簡體   English   中英

是否可以使用 python 獲取知道其序列號的 pendrive 的安裝點?

[英]Is it possible to get the mountpoint of a pendrive knowing its serialnumber using python?

我有 2 台 PC(Linux 和 Windows)連接到位於不同樓層的 local.network。 那個樓層的人將他們的 USB 筆式驅動器連接到其中一台 PC,我想將不同的特定文件集復制給不同的人。

之前,

  • 我做的太難了(到地板上手動做)
  • 后來我寫了一個 python 程序,根據我的決定通過ssh將特定的文件集復制給特定的人。 (即,我通過ssh登錄到特定機器,要求用戶(通過電話)一個接一個地插入他們的筆式驅動器,然后我執行接受參數的 python 程序。這個參數只是一個名稱我想復制誰,並通過接收參數,程序決定將哪些文件復制到筆式驅動器)。
    這個過程仍然有點乏味,.. 因為只能連接一個筆式驅動器,我不得不為每個用戶重復執行此操作。

因此,為了減少消耗的總時間,我在兩個系統上連接了 USB 個集線器,以便在給定時間內多次插入筆式驅動器。 問題來了,決定哪個設備屬於誰。

問題:是否可以使用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

我得到的 output 是

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獲得序列號。 但無法獲取其對應的掛載點

任何想法請...

要在Linux上執行此操作,您需要解析/proc/mounts以確定設備名稱到掛載點的映射,即/dev/sdc2 - > /var/run/media/myaut/hyperx

訣竅是找出所需的設備名稱序列號。 最簡單的方法是使用udev - 它在/dev/disk/by-id生成符號鏈接時使用serial:

/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了解卷,可能還有掛載點。

當然,鏈接這三個層並不明顯(有通過它們的大小/偏移來匹配分區的方法,但這很瘋狂)。 我仍然害怕在我的庫中實現它:(

如果您不介意運行外部進程,也可以將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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM