Можно ли получить точку монтирования 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)
Другие вопросы по тегам