代码之家  ›  专栏  ›  技术社区  ›  Therealstubot

在Linux中编写USB设备安装脚本的更好方法

  •  4
  • Therealstubot  · 技术社区  · 15 年前

    我正在为一个与用户提供的USB记忆棒交互的设备编写一个python模块。用户可以在设备USB插槽中插入USB记忆棒,设备将在不需要用户干预的情况下将数据转储到记忆棒上。如果在用户插入U盘时设备正在运行,我已经挂上了D-Bus,并完成了一个自动安装程序。新的问题是,如果在关闭设备电源的情况下插入斗杆会怎么样?我没有得到任何D总线插入事件,也没有在设备通电后获得有关记忆棒的任何相关信息。

    我已经找到了一种派生设备节点的方法(/dev/sd?)通过在/proc中扫描USB设备,调用:

    ls /proc/scsi/usb-storage

    如果对该文件夹中的每个文件进行分类,则会给出SCSI设备信息。

    然后,我从usb存储记录中获取vendor、product和serial number字段,生成一个标识符字符串,然后在其中使用

    ll /dev/disc/by-id/usb_[vendor] _[product] _[serial_number]-0:0

    所以我可以通过分析结果得到相对路径

    ../../sdc

    然后,我就可以安装U盘了。

    这是一个很麻烦的过程,几乎都是基于文本的,当有人引入一个奇怪的字符或非标准的序列号字符串时,它就准备好了。它与我所有的2个USB记忆棒一起工作。我已经尝试映射/var/log/messages的输出,但最终结果也是文本比较。来自lsusb、fdisk、udevinfo、lsmod等的输出仅显示所需数据的一半。

    我的问题:在没有D总线消息的情况下,如何确定分配给USB记忆棒的/dev设备,而无需用户干预,或者事先知道插入设备的细节?

    谢谢,对不起这部小说。

    4 回复  |  直到 9 年前
        1
  •  4
  •   Peter Lyons    15 年前

    这似乎是有效的结合 /proc/partitions 以及 /sys/class/block 接近ephimient。

    #!/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
    

    我不确定这是多么的便携或可靠,但它适用于我的U盘。当然 find("/usb") 可以做成更严格的正则表达式。执行mod 16也可能不是找到磁盘本身并过滤掉分区的最佳方法,但是到目前为止它对我来说是有效的。

        2
  •  1
  •   ephemient    15 年前

    我不完全确定这个有多便携。此外,这些信息也可能通过D-Bus从 udisks HAL 但我的系统中没有这些,所以我无法尝试。在这里,它似乎是相当准确的,不管:

    $ 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
    
        3
  •  0
  •   Community CDub    7 年前

    looking at this thread 关于如何使用Nautilus,我找到了一些建议,并决定通过shell命令访问udisk。

    大容量存储设备类就是您想要的。把设备文件给它。ie:/dev/sdb 然后,您可以执行d.mount()和d.mount ou point以获得安装位置。

    之后,这也是一个类,用于查找许多相同的USB设备,以控制安装、卸载和弹出所有具有相同标签的设备的大列表。 (如果运行时没有参数,它会将此应用于所有sd设备。对于“自动挂载所有内容”脚本来说可能很方便

    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()
    
        4
  •  0
  •   user4742284    9 年前

    你为什么不简单地用udev规则呢?我必须处理类似的情况,我的解决方案是在/etc/udev/rules.d中创建一个包含以下规则的文件:

    SUBSYSTEMS=="scsi", KERNEL=="sd[b-h]1", RUN+="/bin/mount -o umask=000 /dev/%k /media/usbdrive"
    

    这里的一个假设是,没有人一次插入超过一个U盘。不过,它的优点是,我提前知道木棒将安装在哪里(/media/usbdrive)。

    你可以非常详细地阐述一下,让它更聪明,但就我个人而言,我从未改变过它,它仍然可以在几台电脑上工作。

    不过,据我所知,当插上一根棍子的时候,你一定会被提醒,也许这个策略会给你带来一些麻烦,我不知道,没有调查……