是否可以使用python获取知道其序列号的pendrive的装入点



我有两台PC(一台Linux和一台Windows)连接到不同楼层的本地网络。那层楼的人把他们的U盘连接到其中一台电脑上,我想我会把不同的特定文件集复制给不同的人。

此前,

  • 我做的太难了(到地板上手动做)
  • 后来,我编写了一个python程序,将特定的文件集复制到具体的人通过ssh对我的决定。(即.我登录通过ssh的特定机器,逐个询问用户(通过电话)插入他们的然后我执行python程序,该程序接受论点这个论点不过是我想复制的一个名字,通过接收自变量,程序决定要创建哪些文件复制到笔驱动器)
    不过这个过程还是有点乏味,。。因为只有一个笔驱动器可以连接,我必须为每个用户重复这样做

因此,为了减少总的时间消耗,我在两个系统上连接了USB集线器,以便在给定的时间内多次插入笔驱动器。问题来了,决定哪个设备属于谁。

问题:是否可以使用python从SerialNumber找到笔驱动器的安装点?(如果是python就太好了,因为主程序是用python编写的)

我考虑SerialNumber的原因是

  • UUID-格式化设备时发生变化
  • VendorProdIDManufacturer-不确定它们是否会不同的(如果是同一家制造商的型号)

我尝试了windows的wmi。。从SO那里得到了这个代码,(对不起,我没有链接。花了很长时间)

import win32com.client
wmi = win32com.client.GetObject ("winmgmts:")
for usb in wmi.InstancesOf ("Win32_USBHub"):
    print usb.DeviceID

我得到的输出是

USBVID_5986&PID_02926&4817B6D&0&6
USBVID_8087&PID_00245&55D1EEC&0&1
USBVID_8087&PID_00245&88B8ABA&0&1
USBROOT_HUB204&11F77F7&0
USBROOT_HUB204&62BF53D&0
USBVID_03F0&PID_3307JN0W5LAB0ZHQ5VK8

在linux中也是类似的情况,我只能使用usb-devices获得序列号。但无法获得相应的挂载点

有什么想法请。。。

要在Linux上执行此操作,您需要解析/proc/mounts以确定设备名称到装入点的映射,即/dev/sdc2->/var/run/media/myaut/hyperx

诀窍是找出哪个设备名称需要序列号。最简单的方法是使用udev——它在/dev/disk/by-id:中生成符号链接时使用串行

/dev/disk/by-id/usb-Generic_Flash_Disk_12345678-0:0 -> ../../sdd

但我们没有寻求最简单的解决方案,是吗?诀窍是udev规则可以更改,而sysfs(来自内核)更可靠。我实现了一个这样做的脚本:

import os
import sys
import glob
SYS_USB_DEVICES = '/sys/bus/usb/devices'
SYS_BLOCK_DEVICES = '/sys/class/block'
try:
    serial = sys.argv[1]
except IndexError:
    print >> sys.stderr, "Usage: findflash.py SERIAL"
    sys.exit(1)
# PASS 1 Find USB node with corresponding to serial
for usbid in os.listdir(SYS_USB_DEVICES):
    usbserpath = os.path.join(SYS_USB_DEVICES, usbid, 'serial')    
    if not os.path.exists(usbserpath):
        continue    
    with open(usbserpath) as f:
        usb_serial = f.read().strip()
    if serial == usb_serial:
        # Found it!
        break
else:
    print >> sys.stderr, "Cannot find usb device with serial {0}".format(serial)
    sys.exit(1)
# Find SCSI ids corresponding to this device
# I didn't check SYSFS documentation, but tested it on openSUSE 13.1
# The form of path is:
#   <SUBDEVICE>/host<SCSI_HOST_ID>/target<SCSI_TARGET_ID>/<CTRL><CHANNEL>:<TGT>:<LUN>
# We need only basename
devs = glob.glob(os.path.join(SYS_USB_DEVICES, usbid, 
                            '*/host*/target*/*:*:*:*'))
devs = map(os.path.basename, devs)
# PASS 2 - find mountpoints for devices with SCSI ids we discover earlier
# Parse mountpoint formatted as "/dev/... /path/to/mntpt ..." 
def parse_mntpt(line):
    dev, mntpt, _ = line.split(None, 2)
    dev = os.path.basename(dev)
    return dev, mntpt
mntpts = {}
with open('/proc/mounts') as f:
    mntpts = dict(map(parse_mntpt, f.readlines()))
# List of ('scsi id', 'dev name', 'mnt pt (if exists)')
devlist = []
def create_dev(scsiid, devname):
    global mntpts
    devlist.append((scsiid, devname, mntpts.get(devname)))
for devname in os.listdir(SYS_BLOCK_DEVICES):
    devpath = os.path.join(SYS_BLOCK_DEVICES, devname)
    devlink = os.path.join(devpath, 'device')
    # Node is "virtual", i.e. partition, ignore it
    if not os.path.islink(devlink):
        continue
    scsiid = os.path.basename(os.readlink(devlink))    
    if scsiid not in devs:
        continue
    create_dev(scsiid, devname)
    # Find partition names
    parts = glob.glob(os.path.join(devpath, '*/partition'))
    for partpath in parts:
        partname = os.path.basename(os.path.dirname(partpath))
        create_dev(scsiid, partname)
# END - print results
fmtstr = '{0:8} {1:5} {2}'
print fmtstr.format('SCSI ID', 'DEV', 'MOUNT POINT')
for scsiid, devname, mntpt in devlist:
    print fmtstr.format(scsiid, devname, mntpt)

以下是示例输出:

$ python findflash.py 12345678
SCSI ID  DEV   MOUNT POINT
8:0:0:0  sdd   None
8:0:0:0  sdd1  /var/run/media/myaut/Debian40wheezy4020140723-17:30
8:0:0:0  sdd2  None
8:0:0:0  sdd5  None
8:0:0:1  sr0   None

我不能说在Windows上那会很容易。我有一个代码(在C/WinAPI中),可以从系统中收集所有磁盘设备,但它的逻辑与文件系统的表示方式相去甚远,所以我仍然没有找到解决方案。

Windows的复杂性来源于:

  • 有一组像SetupDi*这样的函数可以枚举磁盘设备。它们的名称采用PnP样式,与卷名无关
  • 有DOS类型的API(即在A:和C:级别上工作)
  • 有一个WinNT风格的API知道卷,可能还有装载点

当然,将这三层连接起来并不明显(有一种方法可以根据分区的大小/偏移量来匹配分区,但这太疯狂了)。我仍然害怕在我的库中实现它:(

如果您不介意运行外部进程,也可以将lsblk用于linux。请注意,磁盘有序列号,而安装的分区没有。

p_handler = subprocess.run(
    ['lsblk', '-J', '-o', 'PATH,SERIAL,MOUNTPOINT'],
    check=True,
    capture_output=True)
json_output = json.loads(p_handler.stdout.decode("utf-8"))
# (serial, device_path, mount_point)
drives = [(dev['serial'], dev['path'], dev['mountpoint'])
          for dev in json_output['blockdevices']]
print(drives)

最新更新