要做到这一点就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/Debian\040wheezy\04020140723-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知道卷和挂载点。
当然,连接这三层并不明显(有办法按大小/偏移量匹配分区,但这是疯狂的)。我仍然害怕在我的库中实现它:(
请参阅[这为最近Linuxen上的D-Bus解决方案](http://stackoverflow.com/a/5081937/918959) – 2015-02-10 11:48:52
对不起,udisk已现在不推荐使用[此方法代替](http://stackoverflow.com/q/23244245/918959) – 2015-02-10 11:59:40
请注意,使用udev时,在连接USB设备时自动运行的Linux上运行命令非常简单可以将每个设备安装到不同的路径,甚至可以自动执行复制命令;不需要python也不需要轮询 – 2015-02-10 12:14:59