9.11. Varm tilkobling: hotplug
Kjerne-delsystemet hotplug håndterer å legge til og fjerne enheter ved å laste de riktige driverne, og ved å lage passende enhetsfiler (med hjelp av udevd
). Med moderne maskinvare og visualisering, kan nesten alt bli varmtilkoblet (hotplugged): fra den vanlige USB/PCMCIA/IEEE 1394 enheter til SATA-harddisker, men også CPU-en og minnet.
Kjernen har en database som knytter hver enhets-ID med den nødvendige driveren. Denne databasen brukes under oppstart for å laste alle driverne til eksterne enheter som oppdages på forskjellige busser, men også når en ekstra varmtilkoblingsenhet blir koblet til. Når enheten er klar til bruk, sendes en melding til udevd
slik at den kan lage den tilsvarende oppføringen i /dev/
.
Før varm-tilkoblingene, var det enkelt å tilordne et fast navn til en enhet. Det var enkelt basert på enhetenes posisjonen på sine respektive busser. Men dette er ikke mulig når slike enheter kan komme og gå på bussen. Det typiske tilfellet er bruk av et digitalt kamera og en USB-minnepenn, som begge for datamaskinen ser ut som harddisker. Den første tilkoblede kan være /dev/sdb
og den andre /dev/sdc
(med /dev/sda
som representerer datamaskinens egen harddisk). Enhetsnavnet er ikke fast; det er avhengig av rekkefølgen enheter er koblet til.
I tillegg bruker flere og flere drivere dynamiske verdier for enhetenes store/små nummer, noe som gjør det umulig å ha statiske oppføringer for de gitte enhetene, siden deres grunnleggende egenskaper kan variere etter en omstart.
udev ble laget nettopp for å løse dette problemet.
9.11.3. Hvordan udev virker
Når udev varsles av kjernen når en ny enhet dukker opp, samler den ulike opplysninger om den gitte enheten ved å konsultere de tilsvarende oppføringene i /sys/
, spesielt de som klart identifiserer den (MAC-adressen til et nettverkskort, serienummer for enkelte USB-enheter, etc.).
Bevæpnet med all denne informasjonen, udev konsulterer så alle reglene som ligger i /etc/udev/rules.d/
og /lib/udev/rules.d/
. I denne prosessen bestemmer den hvordan enheten skal navnes, hvilke symbolske lenker som skal lages (for å gi den alternative navn), og hvilke kommandoer som skal kjøres. Alle disse filene er konsultert , og reglene er alle vurdert sekvensielt (bortsett fra når en fil bruker «GOTO»-direktiver). Således kan det være flere regler som svarer til en gitt hendelse.
Regelfilenes syntaks er ganske enkel: Hver rad inneholder utvalgskriterier og variable oppdrag. Den første er brukt til å velge hendelser der det er behov for å reagere, og sistnevnte definerer handlingen som skal utføres. De er alle enkelt atskilt med komma, og operatøren skiller implisitt mellom et utvalgskriterium (med sammenligningsoperatorer, for eksempel ==
, eller !=
), eller et oppdragsdirektiv (med operatorer som =
, +=
eller :=
).
Sammenligningsoperatorer brukes på følgende variabler:
KJERNE
: navnet som kjernen tilordner til enheten;
ACTION
: handlingen som tilsvarer hendelsen («add» når en enhet er lagt til, «remove» når den er fjernet);
DEVPATH
: Stien til enhetens /sys/
inngang;
SUBSYSTEM
: kjerne-delsystemet som genererer forespørselen (det er mange, men noen eksempler er «usb»,«ide», «net», «firmware», etc.);
ATTR{attributt (egenskap)}
: filinnholdet til attributt-filen i /sys/$devpath/
-mappen til enheten. Det er her du finner MAC-adressen og andre buss-spesifikke identifikatorer;
KERNELS
, SUBSYSTEMS
og ATTRS{attributter}
er variasjoner som vil prøve å treffe de ulike valgene hos en av de overordnede enhetene til den aktuelle enheten;
PROGRAM
: delegerer testen til det angitte programmet (sant hvis den returnerer 0, falsk hvis ikke). Innholdet av programmmets standard resultat blir lagret slik at det kan brukes om igjen av RESULT
-testen;
RESULT
: utfører tester på standardresultatet lagret under siste kontakt til PROGRAM
.
De riktige operander kan bruke mønsteruttrykk for å finne flere verdier som passer samtidig. For eksempel, *
matcher alle strenger (selv en tom en); ?
treffer hvilken som helst tegn, og []
matcher settet med tegn som er listet mellom hakeparenteser (eller det motsatte hvis det første tegnet er et utropstegn, og sammenhengende rekker med tegn er angitt som a-z
).
Når det gjelder tildelingsoperatørene, =
tildeler en verdi (og erstatter gjeldende verdi); i tilfelle av en liste, blir den tømt, og inneholder bare den tildelte verdien. :=
gjør det samme, men hindrer senere endringer i samme variabel. Når det gjelder +=
, legger den til et element i en liste. Følgende variabler kan endres:
NAME
: filnavnet til enheten som skal opprettes i /dev/
. Bare den første oppgaven teller; de andre blir ignorert;
SYMLINK
: listen med symbolske lenker som vil peke til den samme enheten;
OWNER
, GROUP
og MODE
definerer brukeren og gruppen som eier enheten, samt tilhørende tillatelse;
RUN
: listen over programmer som må kjøres som reaksjon på denne hendelsen.
Verdiene tilordnet disse variablene kan bruke en rekke erstatninger:
$kernel
eller %k
: som tilsvarer KERNEL
;
$number
eller %n
: rekkefølgenummeret til enheten, for eksempel for sda3
, ville det være «3»;
$devpath
eller %p
: som tilsvarerer DEVPATH
;
$attr{attributt}
eller %s{attributt}
: som tilsvarer ATTRS{attributt}
;
$major
eller %M
: hovednummeret for enheten i kjernen
$minor
eller %m
: undernummer for enheten i kjernen
$result
eller %c
: resultatstrengen fra det siste programmet aktivert av PROGRAM
;
og, til slutt, %%
og $$
for henholdsvis prosent og dollartegnet.
De ovennevnte listene er ikke komplette (de inneholder kun de viktigste parametrene), men manualside udev(7) skulle være uttømmende.
9.11.4. Et konkret eksempel
La oss vurdere tillfellet med en enkel USB-minnepenn, og prøve å tilordne et fast navn til den. Først må du finne de elementene som unikt vil identifisere den. For å få til dette plugg den inn og kjør udevadm info -a -n /dev/sdc
(for å erstatte /dev/sdc med det faktiske navnet minnepennen har).
#
udevadm info -a -n /dev/sdc
[...]
looking at device '/devices/pci0000:00/0000:00:10.3/usb1/1-2/1-2.2/1-2.2:1.0/host9/target9:0:0/9:0:0:0/block/sdc':
KERNEL=="sdc"
SUBSYSTEM=="block"
DRIVER==""
ATTR{range}=="16"
ATTR{ext_range}=="256"
ATTR{removable}=="1"
ATTR{ro}=="0"
ATTR{size}=="126976"
ATTR{alignment_offset}=="0"
ATTR{capability}=="53"
ATTR{stat}==" 51 100 1208 256 0 0 0 0 0 192 25 6"
ATTR{inflight}==" 0 0"
[...]
looking at parent device '/devices/pci0000:00/0000:00:10.3/usb1/1-2/1-2.2/1-2.2:1.0/host9/target9:0:0/9:0:0:0':
KERNELS=="9:0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{device_blocked}=="0"
ATTRS{type}=="0"
ATTRS{scsi_level}=="3"
ATTRS{vendor}=="I0MEGA "
ATTRS{model}=="UMni64MB*IOM2C4 "
ATTRS{rev}==" "
ATTRS{state}=="running"
[...]
ATTRS{max_sectors}=="240"
[...]
looking at parent device '/devices/pci0000:00/0000:00:10.3/usb1/1-2/1-2.2':
KERNELS=="9:0:0:0"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{configuration}=="iCfg"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bmAttributes}=="80"
ATTRS{bMaxPower}=="100mA"
ATTRS{urbnum}=="398"
ATTRS{idVendor}=="4146"
ATTRS{idProduct}=="4146"
ATTRS{bcdDevice}=="0100"
[...]
ATTRS{manufacturer}=="USB Disk"
ATTRS{product}=="USB Mass Storage Device"
ATTRS{serial}=="M004021000001"
[...]
For å opprette en ny regel kan du bruke tester på enhetens variabler, så vel som de fra en av de overordnede enhetene. Det ovennevnte tilfellet tillater oss å lage to regler som disse:
KERNEL=="sd?", SUBSYSTEM=="block", ATTRS{serial}=="M004021000001", SYMLINK+="usb_key/disk"
KERNEL=="sd?[0-9]", SUBSYSTEM=="block", ATTRS{serial}=="M004021000001", SYMLINK+="usb_key/part%n"
Når disse reglene er satt i en fil, som for eksempel er døpt /etc/udev/rules.d/010_local.rules
, kan du enkelt fjerne og koble til USB-minnepennen. Deretter kan du se at /dev/usb_key/disk
representerer disken knyttet til USB-minnepennen, og /dev/usb_key/part1
er dens første partisjon.