Better way to script USB device mount in Linux

前端 未结 5 621
鱼传尺愫
鱼传尺愫 2020-12-15 14:26

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

相关标签:
5条回答
  • 2020-12-15 14:31

    I think the easiest way is to use lsblk:

    lsblk -d -o NAME,TRAN | grep usb
    
    0 讨论(0)
  • 2020-12-15 14:39

    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...

    0 讨论(0)
  • 2020-12-15 14:42

    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.

    0 讨论(0)
  • 2020-12-15 14:42

    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()
    
    0 讨论(0)
  • 2020-12-15 14:53

    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
    
    0 讨论(0)
提交回复
热议问题