O introducere în Udev: Subsistemul Linux pentru gestionarea evenimentelor de dispozitiv

Udev este subsistemul Linux care furnizează computerului dumneavoastră evenimente de dispozitiv. În termeni simpli, asta înseamnă că este codul care detectează când aveți lucruri conectate la calculator, cum ar fi o placă de rețea, hard disk-uri externe (inclusiv stick-uri USB), mouse-uri, tastaturi, joystick-uri și gamepad-uri, unități DVD-ROM și așa mai departe. Acest lucru îl face un utilitar potențial util și este suficient de bine expus pentru ca un utilizator standard să poată face manual un script pentru a face lucruri cum ar fi efectuarea anumitor sarcini atunci când o anumită unitate hard disk este conectată.

Acest articol vă învață cum să creați un script udev declanșat de un anumit eveniment udev, cum ar fi conectarea unei anumite unități thumb. Odată ce ați înțeles procesul de lucru cu udev, îl puteți folosi pentru a face tot felul de lucruri, cum ar fi încărcarea unui driver specific atunci când este conectat un gamepad sau efectuarea unei copii de rezervă automată atunci când conectați unitatea de rezervă.

Un script de bază

Cel mai bun mod de a lucra cu udev este în bucăți mici. Nu scrieți întregul script de la început, dar în schimb începeți cu ceva care să confirme pur și simplu că udev declanșează un anumit eveniment personalizat.

În funcție de scopul pe care îl aveți pentru scriptul dumneavoastră, nu puteți garanta că veți vedea vreodată rezultatele unui script cu ochii voștri, așa că asigurați-vă că scriptul dumneavoastră înregistrează că a fost declanșat cu succes. Locul obișnuit pentru fișierele jurnal este în directorul /var, dar acesta este în mare parte domeniul utilizatorului root. Pentru teste, folosiți /tmp, care este accesibil utilizatorilor normali și care de obicei este curățat la o repornire.

Deschideți editorul de text preferat și introduceți acest script simplu:

#!/usr/bin/bash
/usr/bin/date >> /tmp/udev.log

Puneți-l în /usr/local/bin sau într-un alt loc asemănător din calea executabilă implicită. Numiți-l trigger.sh și, bineînțeles, faceți-l executabil cu chmod +x.

$ sudo mv trigger.sh /usr/local/bin
$ sudo chmod +x /usr/local/bin/trigger.sh

Acest script nu are nimic de-a face cu udev. Când se execută, scriptul plasează un timestamp în fișierul /tmp/udev.log. Testați singur scriptul:

$ /usr/local/bin/trigger.sh
$ cat /tmp/udev.log
Tue Oct 31 01:05:28 NZDT 2035

Postul următor este de a face ca udev să declanșeze scriptul.

Identificare unică a dispozitivului

Pentru ca scriptul dumneavoastră să fie declanșat de un eveniment al dispozitivului, udev trebuie să știe în ce condiții trebuie să apeleze scriptul. În viața reală, puteți identifica o unitate thumb drive după culoarea sa, după producător și după faptul că tocmai ați conectat-o la calculator. Cu toate acestea, computerul dumneavoastră are nevoie de un set diferit de criterii.

Udev identifică dispozitivele după numere de serie, producători și chiar după numerele de identificare a furnizorului și a produsului. Având în vedere că acesta este la începutul vieții scriptului udev, fiți cât mai larg, nespecific și atotcuprinzător posibil. Cu alte cuvinte, doriți mai întâi să prindeți aproape orice eveniment valid udev pentru a vă declanșa scriptul.

Cu comanda udevadm monitor, puteți intra în udev în timp real și să vedeți ce vede atunci când conectați diferite dispozitive. Deveniți root și încercați.

$ su
# udevadm monitor

Funcția monitor tipărește evenimentele primite pentru:

  • UDEV: evenimentul pe care udev îl trimite după procesarea regulilor
  • KERNEL: ueventul kernelului

Cu udevadm monitor în funcțiune, conectați o unitate de memorie și urmăriți cum tot felul de informații sunt expediate pe ecran. Observați că tipul de eveniment este un eveniment ADD. Aceasta este o modalitate bună de a identifica ce tip de eveniment doriți.

Comanda udevadm monitor oferă o mulțime de informații bune, dar le puteți vedea cu o formatare mai drăguță cu comanda udevadm info, presupunând că știți unde se află în prezent unitatea thumb în arborele /dev. Dacă nu, deconectați și conectați din nou unitatea thumb, apoi emiteți imediat această comandă:

$ su -c 'dmesg | tail | fgrep -i sd*'

Dacă această comandă a returnat sdb: sdb1, de exemplu, știți că kernelul a atribuit unității dvs. thumb eticheta sdb.

Alternativ, puteți folosi comanda lsblk pentru a vedea toate unitățile atașate la sistemul dumneavoastră, inclusiv dimensiunile și partițiile acestora.

Acum că ați stabilit unde se află unitatea dumneavoastră în sistemul de fișiere, puteți vizualiza informațiile udev despre acel dispozitiv cu această comandă:

# udevadm info -a -n /dev/sdb | less

Aceasta returnează o mulțime de informații. Concentrează-te deocamdată pe primul bloc de informații.

Lucrarea ta este de a alege părțile din raportul udev despre un dispozitiv care sunt cele mai unice pentru acel dispozitiv, apoi spune-i lui udev să declanșeze scriptul tău atunci când sunt detectate acele atribute unice.

Procesul udevadm info raportează despre un dispozitiv (specificat de calea dispozitivului), apoi „merge” în susul lanțului de dispozitive părinte. Pentru fiecare dispozitiv găsit, acesta tipărește toate atributele posibile folosind un format cheie-valoare. Puteți compune o regulă pentru a se potrivi în funcție de atributele unui dispozitiv plus atributele de la un singur dispozitiv părinte.

looking at device '/devices/000:000/blah/blah//block/sdb':
KERNEL=="sdb"
SUBSYSTEM=="block"
DRIVER==""
ATTR{ro}=="0"
ATTR{size}=="125722368"
ATTR{stat}==" 2765 1537 5393"
ATTR{range}=="16"
ATTR{discard\_alignment}=="0"
ATTR{removable}=="1"
ATTR{blah}=="blah"

O regulă udev trebuie să conțină un atribut de la un singur dispozitiv părinte.

Atributele părintești sunt lucruri care descriu un dispozitiv de la cel mai de bază nivel, cum ar fi că este ceva care a fost conectat într-un port fizic sau că este ceva cu o dimensiune sau că acesta este un dispozitiv detașabil.

Din moment ce eticheta KERNEL a lui sdb se poate schimba în funcție de câte alte unități au fost conectate înainte de a conecta acea unitate thumb, acesta nu este atributul părinte optim pentru o regulă udev. Cu toate acestea, funcționează pentru o dovadă de concept, așa că îl puteți folosi. Un candidat și mai bun este atributul SUBSYSTEM, care identifică faptul că acesta este un dispozitiv de sistem „bloc” (acesta este motivul pentru care comanda lsblk listează dispozitivul).

Deschideți un fișier numit 80-local.rules în /etc/udev/rules.d și introduceți acest cod:

SUBSYSTEM=="block", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

Salvați fișierul, scoateți din priză stick-ul de test și reporniți.

Așteptați, reporniți pe o mașină Linux?

Teoretic, puteți emite pur și simplu udevadm control –reload, care ar trebui să încarce toate regulile, dar în acest stadiu al jocului, este mai bine să eliminați toate variabilele. Udev este destul de complex și nu vreți să stați toată noaptea în pat întrebându-vă dacă acea regulă nu a funcționat din cauza unei erori de sintaxă sau dacă ar fi trebuit să reporniți. Așadar, reporniți indiferent de ceea ce vă spune mândria POSIX.

Când sistemul este din nou online, treceți la o consolă de text (cu Ctl+Alt+F3 sau similar) și conectați unitatea USB. Dacă executați un kernel recent, probabil că veți vedea o mulțime de ieșiri în consolă atunci când conectați unitatea. Dacă vedeți un mesaj de eroare de tipul Could not execute /usr/local/bin/trigger.sh, probabil că ați uitat să faceți scriptul executabil. În caz contrar, să sperăm că tot ce vedeți este că un dispozitiv a fost conectat, a primit un fel de alocare de dispozitiv din kernel și așa mai departe.

Acum, momentul adevărului:

$ cat /tmp/udev.log
Tue Oct 31 01:35:28 NZDT 2035

Dacă vedeți o dată și o oră foarte recente returnate din /tmp/udev.log, udev a declanșat cu succes scriptul dumneavoastră.

Refining the rule into something useful

Problema cu această regulă este că este foarte generică. Conectarea unui mouse, a unei unități thumb sau a unității thumb a altcuiva va declanșa fără discriminare scriptul dumneavoastră. Acum este momentul să începeți să vă concentrați asupra unității thumb drive exacte pe care doriți să vă declanșeze scriptul.

Un mod de a face acest lucru este cu ID-ul furnizorului și ID-ul produsului. Pentru a obține aceste numere, puteți utiliza comanda lsusb.

$ lsusb
Bus 001 Device 002: ID 8087:0024 Slacker Corp. Hub
Bus 002 Device 002: ID 8087:0024 Slacker Corp. Hub
Bus 003 Device 005: ID 03f0:3307 TyCoon Corp.
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 hub
Bus 001 Device 003: ID 13d3:5165 SBo Networks

În acest exemplu, 03f0:3307 înaintea TyCoon Corp. denotă atributele idVendor și idProduct. Puteți, de asemenea, să vedeți aceste numere în ieșirea din udevadm info -a -n /dev/sdb | grep vendor, dar găsesc ieșirea din lsusb un pic mai ușoară pentru ochi.

Acum puteți include aceste atribute în regula dumneavoastră.

SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/thumb.sh"

Testați acest lucru (da, ar trebui să reporniți în continuare, doar pentru a vă asigura că primiți reacții proaspete de la udev), și ar trebui să funcționeze la fel ca înainte, doar că acum, dacă conectați, să zicem, o unitate thumb fabricată de o altă companie (prin urmare, cu un idVendor diferit) sau un mouse sau o imprimantă, scriptul nu va fi declanșat.

Continuați să adăugați noi atribute pentru a vă concentra și mai mult pe acea unitate thumb unică pe care doriți să vă declanșeze scriptul. Folosind udevadm info -a -n /dev/sdb, puteți afla lucruri cum ar fi numele vânzătorului, uneori un număr de serie, sau numele produsului și așa mai departe.

Pentru sănătatea dumneavoastră mintală, asigurați-vă că adăugați doar un singur atribut nou la un moment dat. Cele mai multe greșeli pe care le-am făcut (și am văzut și alți oameni online să le facă) este să arunce o grămadă de atribute în regula lor udev și să se întrebe de ce chestia nu mai funcționează. A testa atributele unul câte unul este cel mai sigur mod de a vă asigura că udev vă poate identifica dispozitivul cu succes.

Securitate

Aceasta aduce în discuție problemele de securitate legate de scrierea regulilor udev pentru a face automat ceva atunci când o unitate este conectată. Pe mașinile mele, nici măcar nu am activată funcția de montare automată, și totuși acest articol propune scripturi și reguli care execută comenzi doar pentru că este conectat ceva.

Două lucruri de care trebuie să țineți cont aici.

  1. Concentrați-vă regulile udev odată ce le-ați pus în funcțiune, astfel încât să declanșeze scripturile doar atunci când doriți cu adevărat să o facă. Executarea unui script care copiază orbește date către sau de pe calculatorul dumneavoastră este o idee proastă în cazul în care oricine care se întâmplă să aibă la el aceeași marcă de unitate thumb drive o conectează în cutia dumneavoastră.
  2. Nu vă scrieți regulile și scripturile udev și nu uitați de ele. Știu ce computere au regulile mele udev pe ele, iar acele cutii sunt cel mai adesea computerele mele personale, nu cele pe care le iau cu mine la conferințe sau pe care le am în biroul meu de la serviciu. Cu cât un calculator este mai „social”, cu atât este mai puțin probabil să primească o regulă udev pe el care ar putea avea ca rezultat potențial ca datele mele să ajungă pe dispozitivul altcuiva sau ca datele sau programele malware ale altcuiva să ajungă pe dispozitivul meu.

Cu alte cuvinte, ca și cu o mare parte din puterea oferită de un sistem GNU, este de datoria dumneavoastră să fiți atenți la modul în care manevrați această putere. Dacă abuzați de ea sau nu reușiți să o tratați cu respect, ar putea foarte bine să meargă groaznic de rău.

Udev în lumea reală

Acum că puteți confirma că scriptul dvs. este declanșat de udev, vă puteți îndrepta atenția către funcția scriptului. În momentul de față, acesta este inutil, nu face nimic mai mult decât să înregistreze faptul că a fost executat.

Utilizez udev pentru a declanșa backup-uri automate ale unităților mele de memorie. Ideea este că copiile master ale documentelor mele active se află pe unitatea de degetar (deoarece merge peste tot unde mă duc și ar putea fi lucrat în orice moment), iar aceste documente master sunt copiate de rezervă pe computerul meu de fiecare dată când conectez unitatea la acea mașină. Cu alte cuvinte, calculatorul meu este unitatea de rezervă, iar datele mele de producție sunt mobile. Codul sursă este disponibil, așa că nu ezitați să vă uitați la codul lui attachup pentru alte exemple de constrângere a testelor udev.

Din moment ce pentru asta folosesc udev cel mai mult, acesta este exemplul pe care îl voi folosi aici, dar udev poate prelua o mulțime de alte lucruri, cum ar fi gamepad-uri (acest lucru este util pe sistemele care nu sunt setate să încarce modulul xboxdrv atunci când un gamepad este atașat) și camere și microfoane (util pentru a seta intrările atunci când un anumit microfon este atașat), așa că realizați că este bun pentru mult mai mult decât acest exemplu.

O versiune simplă a sistemului meu de backup este un proces cu două comenzi:

SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", SYMLINK+="safety%n"
SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

Prima linie detectează unitatea mea thumb cu atributele deja discutate, apoi atribuie unității thumb un symlink în cadrul arborelui de dispozitive. Legătura simbolică pe care o atribuie este safety%n. %n este un macro udev care se rezolvă cu orice număr pe care kernelul îl dă dispozitivului, cum ar fi sdb1, sdb2, sdb3 și așa mai departe. Deci %n ar fi 1 sau 2 sau 3.

Aceasta creează un symlink în arborele dev, astfel încât nu interferează cu procesul normal de conectare a unui dispozitiv. Acest lucru înseamnă că dacă folosiți un mediu desktop căruia îi place să monteze automat dispozitivele, nu îi veți cauza probleme.

A doua linie rulează scriptul.

Scriptul meu de backup arată astfel:

#!/usr/bin/bash
mount /dev/safety1 /mnt/hd
sleep 2
rsync -az /mnt/hd/ /home/seth/backups/ && umount /dev/safety1

Scriptul folosește legătura simbolică, ceea ce evită posibilitatea ca udev să numească unitatea cu ceva neașteptat (de exemplu, dacă am deja o unitate numită DISK conectată la computerul meu și conectez cealaltă unitate numită tot DISK, cea de-a doua unitate va fi etichetată DISK_, ceea ce ar da peste cap scriptul meu). Acesta montează safety1 (prima partiție a unității) la punctul de montare preferat de mine, /mnt/hd.

După ce a fost montat în siguranță, folosește rsync pentru a face o copie de rezervă a unității în dosarul meu de rezervă (scriptul meu actual folosește rdiff-backup, iar al dumneavoastră poate folosi orice soluție de rezervă automată pe care o preferați).

Udev este dev-ul dumneavoastră

Udev este un sistem foarte flexibil și vă permite să definiți reguli și funcții în moduri pe care puține alte sisteme îndrăznesc să le ofere utilizatorilor. Învățați-l și folosiți-l, și bucurați-vă de puterea POSIX.

Acest articol se bazează pe conținutul din Manualul Slackermedia, care este licențiat sub licența GNU Free Documentation License 1.3.

.

Lasă un răspuns

Adresa ta de email nu va fi publicată.