Можно ли получить точку монтирования pendrive, зная его серийный номер, используя python?
У меня есть 2 компьютера (Linux и Windows), подключенных к локальной сети, которая находится на другом этаже. Люди на этом этаже подключают свои USB-накопители к одному из ПК, и я полагаю, что нужно копировать разные конкретные файлы для разных людей.
Ранее,
- то, что я сделал, было очень трудно (добраться до пола и сделать это вручную)
- Позже я написал программу на Python, которая копирует определенный набор файлов конкретному человеку по моему решению через
ssh
, (т.е. я вхожу на конкретную машину черезssh
, попросите пользователей (по телефонному звонку) один за другим вставить свой флеш-накопитель, а затем я выполню программу python, которая приняла аргумент. Этот аргумент - не что иное, как имя, которое я хотел скопировать, и, получив аргумент, программа решает, какие файлы следует скопировать на флешку).
Тем не менее, процесс немного утомителен, потому что можно было подключить только один флеш-накопитель, и мне приходилось делать это неоднократно для каждого пользователя.
Таким образом, чтобы сократить общее время, затрачиваемое на подключение, я подключил USB-концентраторы к обеим системам, чтобы за один раз выполнить несколько вставок флеш-накопителей. И тут возникает проблема, решить, какое устройство кому принадлежало.
Вопрос: Можно ли найти точку монтирования пера-диска из SerialNumber
используя питон? (было бы замечательно, если бы его Python, так как основная программа написана на Python)
Причину, которую я рассматриваю SerialNumber
над,
UUID
- меняется при форматировании устройстваVendor
,ProdID
а такжеManufacturer
- Не уверен, что если они будут другими. (то есть, что если это от того же производителя и той же модели)
Я старался wmi
для Windows.. и получил этот код от SO,(Извините, у меня нет ссылки. Забрал его давно)
import win32com.client
wmi = win32com.client.GetObject ("winmgmts:")
for usb in wmi.InstancesOf ("Win32_USBHub"):
print usb.DeviceID
вывод я получаю
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
Это аналогичный случай в Linux, все, что я смог получить, это серийный номер, используя usb-devices
, Но не может получить соответствующую точку монтирования
Любые идеи, пожалуйста...
2 ответа
Для этого в 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, не связанные с именами томов.
- Существует API в стиле DOS (т.е. работает на уровне A: и C:)
- Существует API в стиле WinNT, который знает о томах и, возможно, точках монтирования.
Конечно, связывание этих трех слоев не является очевидным (существует подход, позволяющий сопоставлять разделы по размеру / смещению, но это безумие). Я все еще боюсь реализовать это в моей библиотеке:(
Вы также можете использовать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)