You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

81 lines
3.0 KiB
Python

# Copyright 2015 Adafruit Industries.
# Author: Tony DiCola
# License: GNU GPLv2, see LICENSE.txt
import glob
import subprocess
import time
import pyudev
class USBDriveMounter(object):
"""Service for automatically mounting attached USB drives."""
def __init__(self, root='/mnt/usbdrive', readonly=False):
"""Create an instance of the USB drive mounter service. Root is an
optional parameter which specifies the location and file name prefix for
mounted drives (a number will be appended to each mounted drive file
name). Readonly is a boolean that indicates if the drives should be
mounted as read-only or not (default false, writable).
"""
self._root = root
self._readonly = readonly
self._context = pyudev.Context()
def remove_all(self):
"""Unmount and remove mount points for all mounted drives."""
for path in glob.glob(self._root + '*'):
subprocess.call(['umount', '-l', path])
subprocess.call(['rm', '-r', path])
def mount_all(self):
"""Mount all attached USB drives. Readonly is a boolean that specifies
if the drives should be mounted read only (defaults to false).
"""
self.remove_all()
# Enumerate USB drive partitions by path like /dev/sda1, etc.
nodes = [x.device_node for x in self._context.list_devices(subsystem='block',
DEVTYPE='partition') \
if 'ID_BUS' in x and x['ID_BUS'] == 'usb']
# Mount each drive under the mount root.
for i, node in enumerate(nodes):
path = self._root + str(i)
subprocess.call(['mkdir', path])
args = ['mount']
if self._readonly:
args.append('-r')
args.extend([node, path])
subprocess.check_call(args)
def start_monitor(self):
"""Initialize monitoring of USB drive changes."""
self._monitor = pyudev.Monitor.from_netlink(self._context)
self._monitor.filter_by('block', 'partition')
self._monitor.start()
def poll_changes(self):
"""Check for changes to USB drives. Returns true if there was a USB
drive change, otherwise false.
"""
# Look for a drive change.
device = self._monitor.poll(0)
# If a USB drive changed (added/remove) remount all drives.
if device is not None and device['ID_BUS'] == 'usb':
return True
# Else nothing changed.
return False
if __name__ == '__main__':
# Run as a service that mounts all USB drives as read-only under the default
# path of /mnt/usbdrive*.
drive_mounter = USBDriveMounter(readonly=True)
drive_mounter.mount_all()
drive_mounter.start_monitor()
print 'Listening for USB drive changes (press Ctrl-C to quite)...'
while True:
if drive_mounter.poll_changes():
print 'USB drives changed!'
drive_mounter.mount_all()
time.sleep(0)