I\'m writing a python module for a device that interacts with a user supplied USB memory stick. The user can insert a USB memory stick in the device USB slot, and the device
I think the easiest way is to use lsblk:
lsblk -d -o NAME,TRAN | grep usb
why don't you simply use an udev rule? i had to deal with a similar situation, and my solution was to create a file in /etc/udev/rules.d containing following rule:
SUBSYSTEMS=="scsi", KERNEL=="sd[b-h]1", RUN+="/bin/mount -o umask=000 /dev/%k /media/usbdrive"
one assumption here is that nobody ever inserts more than one usb stick at time. it has however the advantage that i know in advance where the stick will be mounted (/media/usbdrive).
you can quite surely elaborate it a bit to make it smarter, but personally i never had to change it and it still works on several computers.
however, as i understand, you want to be alerted somehow when a stick is inserted, and perhaps this strategy gives you some trouble on that side, i don't know, didn't investigate...
This seems to work combining /proc/partitions
and the /sys/class/block
approach ephimient took.
#!/usr/bin/python
import os
partitionsFile = open("/proc/partitions")
lines = partitionsFile.readlines()[2:]#Skips the header lines
for line in lines:
words = [x.strip() for x in line.split()]
minorNumber = int(words[1])
deviceName = words[3]
if minorNumber % 16 == 0:
path = "/sys/class/block/" + deviceName
if os.path.islink(path):
if os.path.realpath(path).find("/usb") > 0:
print "/dev/%s" % deviceName
I'm not sure how portable or reliable this is, but it works for my USB stick. Of course find("/usb")
could be made into a more rigorous regular expression. Doing mod 16 may also not be the best approach to find the disk itself and filter out the partitions, but it works for me so far.
After looking at this thread about doing what ubuntu does with nautilus, i found a few recommendations and decided to go with accessing udisks through shell commands.
The Mass storage device class is what you want. Just give it the device file. ie: /dev/sdb you can then do d.mount() and d.mount_point to get where it has been mounted.
After that is also a class for finding many identical USB devices to control mounting, un-mounting and ejecting a large list of devices that all have the same label. (if you run is with no argument, it will apply this to all SD devices. Could be handy for a "just auto mount everything" script
import re
import subprocess
#used as a quick way to handle shell commands
def getFromShell_raw(command):
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
return p.stdout.readlines()
def getFromShell(command):
result = getFromShell_raw(command)
for i in range(len(result)):
result[i] = result[i].strip() # strip out white space
return result
class Mass_storage_device(object):
def __init__(self, device_file):
self.device_file = device_file
self.mount_point = None
def as_string(self):
return "%s -> %s" % (self.device_file, self.mount_point)
""" check if we are already mounted"""
def is_mounted(self):
result = getFromShell('mount | grep %s' % self.device_file)
if result:
dev, on, self.mount_point, null = result[0].split(' ', 3)
return True
return False
""" If not mounted, attempt to mount """
def mount(self):
if not self.is_mounted():
result = getFromShell('udisks --mount %s' % self.device_file)[0] #print result
if re.match('^Mounted',result):
mounted, dev, at, self.mount_point = result.split(' ')
return self.mount_point
def unmount(self):
if self.is_mounted():
result = getFromShell('udisks --unmount %s' % self.device_file) #print result
self.mount_point=None
def eject(self):
if self.is_mounted():
self.unmount()
result = getFromShell('udisks --eject %s' % self.device_file) #print result
self.mount_point=None
class Mass_storage_management(object):
def __init__(self, label=None):
self.label = label
self.devices = []
self.devices_with_label(label=label)
def refresh(self):
self.devices_with_label(self.label)
""" Uses udisks to retrieve a raw list of all the /dev/sd* devices """
def get_sd_list(self):
devices = []
for d in getFromShell('udisks --enumerate-device-files'):
if re.match('^/dev/sd.$',d):
devices.append(Mass_storage_device(device_file=d))
return devices
""" takes a list of devices and uses udisks --show-info
to find their labels, then returns a filtered list"""
def devices_with_label(self, label=None):
self.devices = []
for d in self.get_sd_list():
if label is None:
self.devices.append(d)
else:
match_string = 'label:\s+%s' % (label)
for info in getFromShell('udisks --show-info %s' % d.device_file):
if re.match(match_string,info): self.devices.append(d)
return self
def as_string(self):
string = ""
for d in self.devices:
string+=d.as_string()+'\n'
return string
def mount_all(self):
for d in self.devices: d.mount()
def unmount_all(self):
for d in self.devices: d.unmount()
def eject_all(self):
for d in self.devices: d.eject()
self.devices = []
if __name__ == '__main__':
name = 'my devices'
m = Mass_storage_management(name)
print m.as_string()
print "mounting"
m.mount_all()
print m.as_string()
print "un mounting"
m.unmount_all()
print m.as_string()
print "ejecting"
m.eject_all()
print m.as_string()
I'm not entirely certain how portable this is. Also, this information would presumably also be available over D-Bus from udisks or HAL but neither of those is present on my system so I can't try. It seems to be reasonably accurate here regardless:
$ for i in /sys/class/block/*; do > /sbin/udevadm info -a -p $i | grep -qx ' SUBSYSTEMS=="usb"' && > echo ${i##*/} > done sde sdf sdg sdh sdi sdj sdj1 $ cd /sys/class/block/ $ for i in *; do [[ $(cd $i; pwd -P) = */usb*/* ]] && echo $i; done sde sdf sdg sdh sdi sdj sdj1