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

时间:2010-03-05 03:00:02

标签: python linux usb

我正在为一个与用户提供的USB记忆棒交互的设备编写python模块。用户可以在设备USB插槽中插入USB记忆棒,设备将数据转储到记忆棒上,无需用户干预。如果设备在用户插入USB记忆棒时正在运行,我已经连接到D-Bus并且已经完成了自动安装程序。新问题是,如果在设备断电时插入插杆怎么办?在设备开机后,我没有得到任何D-Bus插入事件或任何关于记忆棒的相关信息。

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

ls /proc/scsi/usb-storage

如果您捕获该文件夹中的每个文件,则会提供scsi设备信息。

然后我从usb-storage记录中获取供应商,产品和序列号字段,生成一个标识符字符串,然后我在

中使用

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

所以我可以解析结果以获得相对路径

_[product]

然后,我可以安装USB记忆棒。

这是一个繁琐的过程,基本上都是基于文本的,并且当有人引入奇怪的字符或非标准的序列号字符串时就准备好了。它适用于我拥有的所有2个USB记忆棒。我试图映射/ var / log / messages的输出,但最终也是文本比较。 lsusb,fdisk,udevinfo,lsmod等的输出仅显示所需数据的一半。

我的问题:在没有D-Bus消息的情况下,如何在没有用户干预的情况下确定分配给USB记忆棒的/ dev设备,或者事先知道所插入设备的具体情况?

谢谢,对这部小说感到抱歉。

5 个答案:

答案 0 :(得分:4)

这似乎可以将/proc/partitions/sys/class/block方法相结合。

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

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

答案 1 :(得分:1)

我不完全确定这是多么便携。此外,这些信息可能也可以通过D-Bus从udisksHAL获得,但我的系统上都没有这些信息,因此我无法尝试。无论如何,这里似乎相当准确:

$ 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

答案 2 :(得分:0)

looking at this thread关于做ubuntu对nautilus的处理之后,我找到了一些建议并决定通过shell命令访问udisks。

大容量存储设备类是您想要的。只需给它设备文件。即:/ dev / sdb 然后你可以执行d.mount()和d.mount_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()

答案 3 :(得分:0)

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

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

这里的一个假设是,没有人会及时插入多个usb棒。然而,它有一个优点,我事先知道将安装杆(/ media / usbdrive)。

你可以肯定地说明它有点聪明,但我个人从来没有改变它,它仍然适用于几台电脑。

然而,据我所知,你想在插入一根棍子时以某种方式收到警报,也许这个策略会给你带来一些麻烦,我不知道,没有调查......

答案 4 :(得分:0)

我认为最简单的方法是使用lsblk:

lsblk -d -o NAME,TRAN | grep usb