Uvodni strana » Linux » HOW-TO jak automaticky připojovat nebo odpojovat USB zařízení

Jak nastavit automatické mountování USB zařízení na Linuxu

Poznámka překladatele a prznitele tohoto dokumentu

Pro větší názornost jsem příklad přepracoval podle své zkušenosti a svého hardware. Smysl a obsah textu jsem poak v podstatě ponechal oproti původnímu textu zachován, což si můžete ověřit při porovnání s obsahem původní stránky na adrese http://resolute.ucsd.edu/diwaker/articles/howtos/howto-usb-automount.html

Komu je určeno toto HOW-TO

Předpoklady

Postup

Automatické připojování/odpojování USB zařízení

V jednom ze svých dřívějších tipů jsem hovořil o použití autofs ke správě přenosných blokových zařízení. Je to opravdu pěkné řešení, až na to že se chová zcela jinak než bych chtěl. Je sice pěkné mít zařízení připojené zrovna když je chci použít a odpojené když je nepoužívám, jenže co když chci aby bylo zařízení připojené už ve chvíli kdy jej zapíchnu do systému a naopak aby se mi odpojilo až ve chvíli kdy ho vytáhnu. Takže jsem se vydal hledat jiné, lepší řešení a díky některým skvělým zdrojům jsem také na jedno takové stabilní, jednoduché a efektivní také přišel.
V následujícím příkladu popisuji jak nastavit automatické mountování/unmoutování pro USB disk - v mém případě to byl USB 2.0 šuplík VIPowER smart se 40GB diskem formátovaným na reiserfs. Podotýkám, že informace níže uvedené nebodou na jiné distribuci, s jiným hardware a na jiném jádře totožné, proto při čtení používejte i to co máte mezi ušima. Dále zdůraz?uji, že je nutné mít systém, který již používá udev a jádro řady 2.6.x

Nastavení přípojného bodu

Dobrá, takže prvním krokem bylo zjistit zda udev vůbec vytváří pro mé zařízení přípojný bod. Dejme tomu, že do té doby jsem neměl potuchy o tom, kam vlastně udev přípojný bod pro mé zařízení strká. Dále jsem chtěl, aby mi zárove? na tento přípojný bod odkazoval symbolickým linkem /dev/usbdisk. Tak vzhůru na věc.
  1. První krok. Zasunul jsem své USB zařízení a spustil dmesg,  Ve výpisu si můžete sami zjistit kde udev mé zařízení našel:
    [17193225.576000] usb 4-5: new high speed USB device
    using ehci_hcd and address 3
    [17193225.668000] kobject 4-5: registering. parent: usb4, set: devices
    [17193225.668000] kobject_hotplug
    [17193225.668000] fill_kobj_path: path = '/devices/pci0000:00/0000:00:10.3/usb4/4-5'
    [17193225.668000] kobject_hotplug: /sbin/udevsend usb seq=1009 HOME=/ PATH=/sbin:/bin:/usr/sbin:/usr/bin ACTION=add DEVPATH=/devices/pci0000:00/0000:00:10.3/usb4/4-5 SUBSYSTEM=usb
    [17193225.676000] kobject 4-5:1.0: registering. parent: 4-5, set: devices
    [17193225.676000] kobject_hotplug
    [17193225.676000] fill_kobj_path: path = '/devices/pci0000:00/0000:00:10.3/usb4/4-5/4-5:1.0'
    [17193225.676000] kobject_hotplug: /sbin/udevsend usb seq=1010 HOME=/ PATH=/sbin:/bin:/usr/sbin:/usr/bin ACTION=add DEVPATH=/devices/pci0000:00/0000:00:10.3/usb4/4-5/4-5:1.0 SUBSYSTEM=usb
    [17193226.604000] kobject ub: registering. parent: , set: module
    [17193226.604000] kobject_hotplug
    [17193226.604000] fill_kobj_path: path = '/module/ub'
    [17193226.604000] kobject_hotplug: /sbin/udevsend module seq=1011 HOME=/ PATH=/sbin:/bin:/usr/sbin:/usr/bin ACTION=add DEVPATH=/module/ub SUBSYSTEM=module
    [17193226.636000] ub: sizeof ub_scsi_cmd 68 ub_dev 2384 ub_lun 140
    [17193226.636000] kobject ub: registering. parent: , set: drivers
    [17193226.636000] kobject_hotplug
    [17193226.636000] fill_kobj_path: path = '/bus/usb/drivers/ub'
    [17193226.636000] kobject_hotplug: /sbin/udevsend drivers seq=1012 HOME=/ PATH=/sbin:/bin:/usr/sbin:/usr/bin ACTION=add DEVPATH=/bus/usb/drivers/ub SUBSYSTEM=drivers
    [17193226.668000] ub(4.3): GetMaxLUN returned 0 bytes
    [17193226.772000] ub(4.3): GetMaxLUN returned 0 bytes
    [17193226.872000] ub(4.3): GetMaxLUN returned 0 bytes
    [17193226.976000] kobject uba: registering. parent: , set: block
    [17193226.976000] kobject_hotplug
    [17193226.976000] fill_kobj_path: path = '/block/uba'
    [17193226.976000] fill_kobj_path: path = '/devices/pci0000:00/0000:00:10.3/usb4/4-5/4-5:1.0'
    [17193226.976000] kobject_hotplug: /sbin/udevsend block seq=1013 HOME=/ PATH=/sbin:/bin:/usr/sbin:/usr/bin ACTION=add DEVPATH=/block/uba SUBSYSTEM=block
    [17193226.980000] uba: uba1
    [17193227.000000] kobject uba1: registering. parent: uba, set:
    [17193227.000000] kobject_hotplug
    [17193227.000000] fill_kobj_path: path = '/block/uba/uba1'
    [17193227.000000] fill_kobj_path: path = '/devices/pci0000:00/0000:00:10.3/usb4/4-5/4-5:1.0'
    [17193227.000000] kobject_hotplug: /sbin/udevsend block seq=1014 HOME=/ PATH=/sbin:/bin:/usr/sbin:/usr/bin ACTION=add DEVPATH=/block/uba/uba1 SUBSYSTEM=block
    [17193227.004000] kobject queue: registering. parent: uba, set:
    [17193227.004000] kobject iosched: registering. parent: queue, set:
    [17193227.004000] usbcore: registered new driver ub
    [17193227.080000] kobject usb_storage: registering. parent: , set: module
    [17193227.084000] kobject_hotplug
    [17193227.084000] fill_kobj_path: path = '/module/usb_storage'
    [17193227.084000] kobject_hotplug: /sbin/udevsend module seq=1015 HOME=/ PATH=/sbin:/bin:/usr/sbin:/usr/bin ACTION=add DEVPATH=/module/usb_storage SUBSYSTEM=module
    [17193227.112000] Initializing USB Mass Storage driver...
    [17193227.112000] kobject usb-storage: registering. parent: , set: drivers
    [17193227.112000] kobject_hotplug
    [17193227.112000] fill_kobj_path: path = '/bus/usb/drivers/usb-storage'
    [17193227.112000] kobject_hotplug: /sbin/udevsend drivers seq=1016 HOME=/ PATH=/sbin:/bin:/usr/sbin:/usr/bin ACTION=add DEVPATH=/bus/usb/drivers/usb-storage SUBSYSTEM=drivers
    [17193227.140000] usbcore: registered new driver usb-storage
    [17193227.140000] USB Mass Storage support registered.
    Moc přehledné to není což? Pro větší názornost jsem některé části výpisu obarvil. Mimo to jsem si již dříve napsal jednoduchý skript kterým si z adresáře /sys vytáhnu vše potřebné. Jeho výpis vypadá takto:
    ========= Zařízení č. 1 ==============
    cesta k zařízení : /sys/devices/pci0000:00/0000:00:10.2/usb3/3-2/3-2:1.0
    modalias: usb:v055Fp0219d0100dc00dsc00dp00icFFiscFFipFF
    product : USB Scanner
    idProduct : 0219
    serial : Hodnota není uvedena
    idVendor : 055f
    manufacturer : Hodnota není uvedena
    speed : 12
    devnum : 3
    bcdDevice : 0100
    bMaxPower : 500mA
    bmAttributes : a0
    bConfigurationValue : 1
    bDeviceClass : 00
    bNumConfigurations : 1
    bDeviceProtocol : 00
    bNumInterfaces : 1
    bDeviceSubClass : 00
    detach_state : Hodnota není uvedena
    maxchild : 0
    version : 1.10

    Pro výpis z udevinfo použijte následující příkaz:

    udevinfo -a -p /sys/devices/pci0000:00/0000:00:10.2/usb3/3-2/3-2:1.0

    ========= Zařízení č. 2 ==============
    cesta k zařízení :/sys/devices/pci0000:00/0000:00:10.3/usb4/4-5/4-5:1.0
    modalias: usb:v0F2Dp9308d0001dc00dsc00dp00ic08isc06ip50
    product : ViPowER USB2.0 SmartCable
    idProduct : 9308
    serial : DEF107C55F6B
    idVendor : 0f2d
    manufacturer : ViPowER,Inc
    speed : 480
    devnum : 6
    bcdDevice : 0001
    bMaxPower : 0mA
    bmAttributes : c0
    bConfigurationValue : 1
    bDeviceClass : 00
    bNumConfigurations : 1
    bDeviceProtocol : 00
    bNumInterfaces : 1
    bDeviceSubClass : 00
    detach_state : Hodnota není uvedena
    maxchild : 0
    version : 2.00


    Pro výpis z udevinfo použijte následující příkaz:

    udevinfo -a -p /sys/devices/pci0000:00/0000:00:10.3/usb4/4-5/4-5:1.0
    Jak vidno údajů, kterých se lze chytit, je trochu více, není-liž pravda? Takže pokud vás zaujal, tak si jej můžete přepsat:
    #! /bin/bash
    # ===== Začátek výpisu ======
        ZARIZENI=($(ls -1 /sys/devices/pci0000:00/[0-9]*/usb[0-9]/[0-9]-[0-9]/product))
       index=0
        while [ $index -lt ${#ZARIZENI[*]} ]; do
        # Vypíše elementy v poli
         pokus=${ZARIZENI[$index]}
         device=${pokus%product}
         cesta=$(find $device -name modalias)
    echo "========= Zařízení č. $(($index + 1)) =============="
    echo "cesta k zařízení:      "${cesta%/modalias}
    echo "modalias :       "     $(cat $cesta 2>/dev/null || echo "hodnota není uvedena")
    echo"product :         "    $(cat $device"product" 2>/dev/null          || echo "Hodnota není uvedena")
    echo "idProduct :       "      $(cat $device"idProduct" 2>/dev/null     || echo "Hodnota není uvedena")
    echo "serial :        "         $(cat $device"serial" 2>/dev/null     || echo "Hodnota není uvedena")
    echo "idVendor :        "       $(cat $device"idVendor" 2>/dev/null     || echo "Hodnota není uvedena")
    echo "manufacturer :        "   $(cat $device"manufacturer" 2>/dev/null || echo "Hodnota není uvedena")
    echo "speed :            "      $(cat $device"speed" 2>/dev/null || echo "Hodnota není uvedena")
    echo "devnum :        "         $(cat $device"devnum" 2>/dev/null     || echo "Hodnota není uvedena")
    echo "bcdDevice :        "      $(cat $device"bcdDevice" 2>/dev/null      || echo "Hodnota není uvedena")
    echo "bMaxPower :        "      $(cat $device"bMaxPower" 2>/dev/null      || echo "Hodnota není uvedena")
    echo "bmAttributes :        "   $(cat $device"bmAttributes" 2>/dev/null || echo "Hodnota není uvedena")
    echo "bConfigurationValue :    "$(cat $device"bConfigurationValue" 2>/dev/null || echo "Hodnota není uvedena")
    echo "bDeviceClass :        "   $(cat $device"bDeviceClass" 2>/dev/null || echo "Hodnota není uvedena")
    echo "bNumConfigurations :    " $(cat $device"bNumConfigurations" 2>/dev/null  || echo "Hodnota není uvedena")
    echo "bDeviceProtocol :    "    $(cat $device"bDeviceProtocol" 2>/dev/null     || echo "Hodnota není uvedena")
    echo "bNumInterfaces :    "     $(cat $device"bNumInterfaces" 2>/dev/null     || echo "Hodnota není uvedena")
    echo "bDeviceSubClass :    "    $(cat $device"bDeviceSubClass" 2>/dev/null     || echo "Hodnota není uvedena")
    echo "detach_state :        "   $(cat $device"detach_state" 2>/dev/null || echo "Hodnota není uvedena")
    echo "maxchild :        "       $(cat $device"maxchild" 2>/dev/null     || echo "Hodnota není uvedena")
    echo "version :        "        $(cat $device"version" 2>/dev/null         || echo "Hodnota není uvedena")
    echo ""echo $"\
    Pro výpis z udevinfo použijte následující příkaz:       udevinfo -a -p ${cesta%/modalias}"      let "index = $index + 1"
        done
        exit 0
    # ===== Konec výpisu ======

  2. Druhým bylo sepsání pravidla pro udev. Při svých dřívějších pokusech jsem se v tomto bodě na dlouhou dobu zasekl, než jsem zjistil, že mi udev nefunguje kvůli tomu, že udevinfo nevrací proměnné, které byly uváděny v nejrůznějších příkladech na netu. Ale ať hovořím konkrétně. V původním příkladu k této stránce bylo např.:
    BUS="usb", SYSFS{manufacturer}="SanDisk Corporation",
    SYSFS{serial}="SNDK3EE59429F8301101", NAME="%k",
    SYMLINK="usbkey"
    Ovšem červeně označené klíče mi udevinfo nevrací, resp. nepracuje s nimi. Místo toho mi však vracelo jiný jednoznačný identifikátor: SYSFS{modalias}="usb:v0F2Dp9308d0001dc00dsc00dp00ic08isc06ip50". Tak jsem ho použil i ve svém pravidle:
    BUS="usb",
    SYSFS{modalias}="usb:v0F2Dp9308d0001dc00dsc00dp00ic08isc06ip50",
    SYMLINK="usbdisk"
    Pak již vše fungovalo tak jak má
  3. Toto pravidlo jsem napsal do souboru /etc/udev/early.rules který jsem symbolickým linkem nalinkoval do adresáře /etc/udev/rules.d/010_local.rules
    Symbilcký link začíná 010 proto, aby jej udev zpracoval dříve než výchozí soubor pravidel (viz Psaní pravidel pro udev)
  4. Po zapsání pravidla  jsem  je nechal načíst spuštěním příkazu udevstart.

Automatický mount/umount USB zařízení

Před sepsáním skriptu pro automatický mount/umount jsem se přes příkaz "ls -al /dev/usbdisk" přesvědčil zda udev při připojení a odpojení opravdu vytváří a ruší přípojný bod /dev/usbdisk. Pak jsem si vytvořil adresář /mnt/disk do kterého chci tento disk mountovat a přikročil k sepsání vlastního mountovacího skriptu:

  1. Ten musí být umístěn v adresáři block, jako podadresář /etc/dev.d Pokud neexistuje tak si ho vytvořte.
  2. Do tohoto adresáře nakopírujte, nebo přilinkujte spustitelný skript (podmínkou je aby link, nebo soubor byl spustitelný a měl příponu .dev) s  následujícím obsahem:
    #!/bin/bash
    if [ $ACTION = add ]; then
    if [ -e /dev/usbdisk ]; then
    mount /dev/usbdisk /mnt/disk
    exit 0
    fi
    elif [ $ACTION = remove ]; then
    if [ $(mount | grep /mnt/disk | awk '{print $1}') ]; then
    umount /mnt/disk
    exit 0
    fi
    fi
  3. A to je vše. Co vlastně skript dělá?
    Vyskytne-li se v systémových proměnných jako hodnota proměnné ACTION "add", pak zkontroluj zda nebyl vytvořený přípojný bod /dev/usbdisk; pokud ano, tak ho připoj do adresáře /mnt/disk. Je-li hodnota vyvolané ACTION "remove", tak se koukni do výpisu příkazu mount zda náhodou nezmizelo zařízení připojené do adresáře /mnt/disk. Pokud je pryč, tak vyhoď tenhle záznam přes umount pryč.

    Jak vidíte, skript je velmi jednoduchý a lze jej snadno modifikovat. Nicméně zběhlejší uživatelé, co si potykali s programováním v shellu mohou mít skript komplexnější, který před připojením zařízení vytvoří příslušný cílový adresář, ošetří všechny případné diskové oddíly, zjistí jejich filesystém, připojí a po vypíchnutí odpojí, a smaže cílový adresář.
    Možná vám vrtá hlavou proč by to měl takhle komplikovat? Nemusíte s mým názorem souhlasit, ale pokud neproběhne z nějakého důvodu připojení zařízení a adresář stále existuje, tak se může snadno stát, že odejdete od stroje v domění že máte všechny soubory na svém disku a přitom tomu tak nebude.
Poznámka: Skript na původní stránce mi jednak připadal složitý jak žebř a navíc na mém stroji stejně nefungoval, takže je tady můj vlastní co funguje

A to je vše. Jakže to funguje?

Po zasunutí USB zařízení udev vytvoří příslušné zařízení v /dev a nastaví symbolický link. Poté zavolá váš skript který zařízení připojí. Když USB zařízení vytáhnete, tak udev smaže zařízení z adresáře /dev a skript vyhodí záznam o připojeném systému

Jak jdou na to jiní?

Např suse používá o balík submount, který obsahuje skript subfs.dev který pro každé připojené usb zařízení vytvoří v adresáři /media vlastní adresář, kam ho pak připojuje. Tento adresář pak zůstává stále přítomen.
Co používá Mandrake a další zatím nevím (nemám možnost otestovat a zjistit) ale zjistím a doplním.

Keny Otter

Nahoru
Vložil(a): Aleš Kapica dne 2005-06-10 12:47:49
Poslední změna: Aleš Kapica dne 2005-06-10 12:55:31
Schválil(a): Aleš Kapica