I have 2 PC's(a Linux and a Windows) connected to a local network which is on a different floor. People on that floor connect their USB Pen-drives to either one of the PC and I am suppose to copy different specific set of files to different people.
Previously,
ssh
. (ie,. I log in to the
specific machine through ssh
, ask users (over a phone call) one by one to insert their
pen-drive and then i execute the python program which accepted an
argument. This argument is nothing but a name whom i wanted to copy,
and by receiving the argument the program decides which files to be
copied to the pen-drive).So to reduce the total time consumed, i connected USB hubs on both the systems to make multiple insert of pen-drive's in a given time. And here comes the problem, decide which device belonged to whom.
Question : Is it possible to find the mount point of a pen-drive from the SerialNumber
using python ? (it would be great if its python, since the main program is written in python)
The reason i am considering SerialNumber
over,
UUID
- It changes when the device is formattedVendor
, ProdID
and Manufacturer
- Not sure that if they will be
different. (ie,. what if its from the same manufacturer and a same
model)I tried wmi
for windows.. and got this code from SO,(Sorry i don't have the link. Took it long back)
import win32com.client
wmi = win32com.client.GetObject ("winmgmts:")
for usb in wmi.InstancesOf ("Win32_USBHub"):
print usb.DeviceID
the output i get is
USB\VID_5986&PID_0292\6&4817B6D&0&6
USB\VID_8087&PID_0024\5&55D1EEC&0&1
USB\VID_8087&PID_0024\5&88B8ABA&0&1
USB\ROOT_HUB20\4&11F77F7&0
USB\ROOT_HUB20\4&62BF53D&0
USB\VID_03F0&PID_3307\JN0W5LAB0ZHQ5VK8
its the similar case in linux, all i able to get is serialnumber, using usb-devices
. But unable to get its corresponding mount-point
Any Ideas please...
To do that on Linux you will need to parse /proc/mounts
to determine mapping of device names to mountpoints, i.e. /dev/sdc2
-> /var/run/media/myaut/hyperx
.
The trick is to find out what device name has required serial number. Easiest approach to do so is to use udev
- it uses serial when generates symlinks in /dev/disk/by-id
:
/dev/disk/by-id/usb-Generic_Flash_Disk_12345678-0:0 -> ../../sdd
But we didn't seek for easiest solutions, are we? The trick is that udev
rules may be altered, and sysfs
(which come from kernel) is more reliable. I implemented a script that does that:
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)
Here is example output:
$ 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
I can't say that on Windows that would be easy. I have a code (in C/WinAPI) that able to collect all disk devices from system, but it's logic is far away from filesystems representation, so I still didn't find a solution for that.
Complexity of Windows come from that:
Of course linking that three layers is not obvious (there is approach to match partitions by their size/offset, but that is crazy). I'm still scared to implement it in my library :(