Лучший способ сценария монтирования USB-устройства в Linux - PullRequest
4 голосов
/ 05 марта 2010

Я пишу модуль Python для устройства, которое взаимодействует с предоставленной пользователем картой памяти USB. Пользователь может вставить карту памяти USB в слот USB устройства, и устройство будет выгружать данные на карту памяти без вмешательства пользователя. Если устройство работает, когда пользователь вставляет USB-флешку, я подключился к D-Bus, и у меня все готово. Новая проблема в том, что если карта памяти вставлена, когда устройство выключено? Я не получаю ни события вставки D-Bus, ни каких-либо связанных частей информации о карте памяти после включения устройства.

Я разработал способ получения узла устройства (/ dev / sd?) Из сканирования устройств USB в / proc, вызвав:

ls /proc/scsi/usb-storage

это дает информацию об устройстве scsi, если вы просматриваете каждый из файлов в этой папке.

Затем я беру поля Vendor, Product и Serial Number из записей usb-storage, генерирую строку идентификатора, которую затем использую в

ll /dev/disc/by-id/usb_[vendor]<code>_[product] _ [serial_number] -0: 0

Так что я могу проанализировать результат, чтобы получить относительный путь

../../sdc

Затем я могу подключить USB-накопитель.

Это громоздкая процедура, в значительной степени основанная на тексте, и готовая к ошибкам, когда кто-то вводит странный символ или нестандартную строку серийного номера. Он работает со всеми 2 USB-накопителями, которые у меня есть. Я пытался отобразить вывод из / var / log / messages, но это также приводит к сопоставлению текста. Вывод lsusb, fdisk, udevinfo, lsmod и других показывает только половину требуемых данных.

Мой вопрос: как определить, при отсутствии сообщения D-Bus, устройство / dev, назначенное карте памяти USB, без вмешательства пользователя или заранее зная особенности вставленного устройства?

Спасибо, извините за роман.

Ответы [ 4 ]

4 голосов
/ 10 марта 2010

Это, кажется, работает, комбинируя /proc/partitions и подход /sys/class/block, который потребовался.

#!/usr/bin/python
import os
partitionsFile = open("/proc/partitions")
lines = partitionsFile.readlines()[2:]#Skips the header lines
for line in lines:
    words = [x.strip() for x in line.split()]
    minorNumber = int(words[1])
    deviceName = words[3]
    if minorNumber % 16 == 0:
        path = "/sys/class/block/" + deviceName
        if os.path.islink(path):
            if os.path.realpath(path).find("/usb") > 0:
                print "/dev/%s" % deviceName

Я не уверен, насколько это портативно или надежно, но это работает для моей флешки. Конечно, find("/usb") можно сделать более строгим регулярным выражением. Выполнение мода 16 также может быть не лучшим подходом для поиска самого диска и фильтрации разделов, но пока это работает для меня.

1 голос
/ 05 марта 2010

Я не совсем уверен, насколько это портативно. Кроме того, эта информация, вероятно, также будет доступна по шине D-Bus из udisks или HAL , но ни одна из них не присутствует в моей системе, поэтому я не могу попробовать. Здесь, кажется, достаточно точно, независимо от:

$ for i in /sys/class/block/*; do
>     /sbin/udevadm info -a -p $i | grep -qx '    SUBSYSTEMS=="usb"' &&
>     echo ${i##*/}
> done
sde
sdf
sdg
sdh
sdi
sdj
sdj1
$ cd /sys/class/block/
$ for i in *; do [[ $(cd $i; pwd -P) = */usb*/* ]] && echo $i; done
sde
sdf
sdg
sdh
sdi
sdj
sdj1
0 голосов
/ 02 апреля 2015

почему бы вам просто не использовать правило udev? Мне пришлось столкнуться с подобной ситуацией, и я решил создать файл в /etc/udev/rules.d, содержащий следующее правило:

SUBSYSTEMS=="scsi", KERNEL=="sd[b-h]1", RUN+="/bin/mount -o umask=000 /dev/%k /media/usbdrive"

Одно из предположений здесь состоит в том, что никто никогда не вставляет более одной флешки одновременно. однако у него есть то преимущество, что я заранее знаю, где будет монтироваться флешка (/ media / usbdrive).

Вы можете совершенно точно разработать его, чтобы сделать его умнее, но лично мне никогда не приходилось его менять, и он все еще работает на нескольких компьютерах.

однако, как я понимаю, вы хотите как-то быть предупреждены, когда вставлена ​​флешка, и, возможно, эта стратегия доставляет вам некоторые проблемы на этой стороне, я не знаю, не расследовала ...

0 голосов
/ 17 марта 2014

После просмотра этой темы о том, что ubuntu делает с nautilus, я нашел несколько рекомендаций и решил заняться доступом к udisks с помощью команд оболочки.

Класс запоминающих устройств - это то, что вам нужно. Просто дайте ему файл устройства. то есть: / dev / sdb затем вы можете выполнить d.mount () и d.mount_point, чтобы узнать, где он был смонтирован.

После этого это также класс для поиска множества идентичных USB-устройств для управления подключением, демонтажем и извлечением большого списка устройств, которые имеют одинаковую метку. (если вы запускаете без аргументов, это применимо ко всем SD-устройствам. Может быть полезно для сценария «просто автоматически смонтировать все»

import re
import subprocess

#used as a quick way to handle shell commands
def getFromShell_raw(command):
    p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    return p.stdout.readlines()

def getFromShell(command):
    result = getFromShell_raw(command)
    for i in range(len(result)):       
        result[i] = result[i].strip() # strip out white space
    return result



class Mass_storage_device(object):
    def __init__(self, device_file):
       self.device_file = device_file
       self.mount_point = None

    def as_string(self):
        return "%s -> %s" % (self.device_file, self.mount_point)

    """ check if we are already mounted"""
    def is_mounted(self):
        result = getFromShell('mount | grep %s' % self.device_file)
        if result:
            dev, on, self.mount_point, null = result[0].split(' ', 3)
            return True
        return False

    """ If not mounted, attempt to mount """
    def mount(self):
        if not self.is_mounted():
            result = getFromShell('udisks --mount %s' % self.device_file)[0] #print result
            if re.match('^Mounted',result): 
                mounted, dev, at, self.mount_point = result.split(' ')

        return self.mount_point

    def unmount(self):
        if self.is_mounted():
            result = getFromShell('udisks --unmount %s' % self.device_file) #print result
            self.mount_point=None

    def eject(self):
        if self.is_mounted():
            self.unmount()
        result = getFromShell('udisks --eject %s' % self.device_file) #print result
        self.mount_point=None


class Mass_storage_management(object):
    def __init__(self, label=None):
        self.label = label
        self.devices = [] 
        self.devices_with_label(label=label)

    def refresh(self):
        self.devices_with_label(self.label)

    """ Uses udisks to retrieve a raw list of all the /dev/sd* devices """
    def get_sd_list(self):
        devices = []
        for d in getFromShell('udisks --enumerate-device-files'):
            if re.match('^/dev/sd.$',d): 
                devices.append(Mass_storage_device(device_file=d))
        return devices


    """ takes a list of devices and uses udisks --show-info 
    to find their labels, then returns a filtered list"""
    def devices_with_label(self, label=None):
        self.devices = []
        for d in self.get_sd_list():
            if label is None:
                self.devices.append(d)
            else:
                match_string = 'label:\s+%s' % (label)
                for info in getFromShell('udisks --show-info %s' % d.device_file):
                    if re.match(match_string,info): self.devices.append(d)
        return self

    def as_string(self):
        string = ""
        for d in self.devices:
            string+=d.as_string()+'\n'
        return string

    def mount_all(self): 
        for d in self.devices: d.mount()

    def unmount_all(self): 
        for d in self.devices: d.unmount()

    def eject_all(self): 
        for d in self.devices: d.eject()
        self.devices = []



if __name__ == '__main__':
    name = 'my devices'
    m = Mass_storage_management(name)
    print m.as_string()

    print "mounting"
    m.mount_all()
    print m.as_string()

    print "un mounting"
    m.unmount_all()
    print m.as_string()

    print "ejecting"
    m.eject_all()
    print m.as_string()
...