【问题标题】:Better way to script USB device mount in Linux在 Linux 中编写 USB 设备挂载脚本的更好方法
【发布时间】:2011-01-23 23:11:27
【问题描述】:

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

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

ls /proc/scsi/usb-storage

如果您对该文件夹中的每个文件进行分类,这将提供 scsi 设备信息。

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

中使用

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

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

../../sdc

然后,我可以挂载 U 盘了。

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

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

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

【问题讨论】:

    标签: python linux usb


    【解决方案1】:

    这似乎可以将/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
    

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

    【讨论】:

    • 我其实采用了一种更简单的方法。我查看 /dev/disk/by-id/usb--part 中的每个条目都指向 /dev 设备的链接。快速调用 os.path.realpath 获取链接设备。
    【解决方案2】:

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

    $ for i in /sys/class/block/*;做 > /sbin/udevadm 信息-a -p $i | grep -qx ' SUBSYSTEMS=="usb"' && > 回声 ${i##*/} > 完成 sde 自卫队 可持续发展目标 sdh sdi sdj sdj1 $ cd /sys/类/块/ $ for i in *;做 [[ $(cd $i; pwd -P) = */usb*/* ]] && echo $i;完毕 sde 自卫队 可持续发展目标 sdh sdi sdj sdj1

    【讨论】:

      【解决方案3】:

      looking at this thread 谈到 ubuntu 对 nautilus 所做的事情之后,我找到了一些建议,并决定通过 shell 命令访问 udisk。

      大容量存储设备类是您想要的。只需给它设备文件。即:/dev/sdb 然后,您可以执行 d.mount() 和 d.mount_point 来获取它的安装位置。

      这也是一个类,用于查找许多相同的 USB 设备以控制安装、卸载和弹出大量具有相同标签的设备。 (如果您运行 is 没有参数,它将将此应用于所有 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】:

        为什么不简单地使用 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)。

        您可以肯定地对其进行详细说明以使其更智能,但我个人从未需要更改它,它仍然可以在多台计算机上运行。

        但是,据我了解,您希望在插入一根棍子时以某种方式收到警报,也许这种策略在这方面给您带来了一些麻烦,我不知道,没有调查...

        【讨论】:

          【解决方案5】:

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

          lsblk -d -o NAME,TRAN | grep usb
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-07-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-12-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多