- Nota per Ubuntu Server 11.10: questo script ha esito negativo su Ubuntu Server 11.10 a causa del
vol_id
comando obsoleto . vol_id
è stato sostituito da blkid
. Per correggere lo script, sostituire "vol_id" con "blkid -o udev" nello udev-auto-mount.sh
script.
Mi sbatto la testa da un po 'di tempo ormai e penso di aver trovato una soluzione funzionante. Questo è sviluppato e testato su un sistema basato su Debian, quindi dovrebbe funzionare su Ubuntu. Sottolineerò i presupposti che fa in modo che possa essere adattato anche ad altri sistemi.
- Monterà automaticamente le unità USB sul plug-in e non dovrebbe richiedere molto tempo per adattarsi a Firewire.
- Usa UDEV, quindi niente scimmie con HAL / DeviceKit / GNOME-Anything.
- Crea automagicamente una
/media/LABEL
directory su cui montare il dispositivo.
- Tuttavia, potrebbe interferire con altri automounter; Non posso provarlo. Mi aspetto che, con Gnome-VFS attivo, entrambi possano provare a fare il mount ... se Gnome-VFS fallisce il mount, potrebbe non configurare un'icona desktop. Lo smontaggio da Gnome dovrebbe essere possibile, ma potrebbe richiedere
gksudo
o simili.
Non l'ho provato all'avvio del sistema, ma l'unico motivo per cui posso vedere che potrebbe non funzionare è se tenta di montare l'unità USB prima che il sistema sia pronto per il montaggio. In tal caso, probabilmente avrai bisogno di un'ulteriore modifica allo script di mount. (Sto verificando con ServerFault per vedere se c'è qualche consiglio, ma non c'è molto interesse in questo.)
Su di esso, quindi.
Riferimenti UDEV:
Sfondo (UDEV? Whuzzat?)
UDEV è il sistema hotplug del kernel. È ciò che configura automagicamente i dispositivi e i collegamenti simbolici dei dispositivi (ad esempio /dev/disk/by-label/<LABEL>
), sia all'avvio sia per i dispositivi aggiunti mentre il sistema è in esecuzione.
D-Bus e HAL vengono utilizzati per l'invio di eventi hardware a listener come ambienti desktop. Quindi quando si accede a GNOME e si inserisce un CD o si collega un'unità USB, quell'evento segue questa catena:
kernel -> udev -> dbus -> hal -> gnome-vfs/nautilus (mount)
E presto, l'unità viene montata. Ma in un sistema senza testa, non vogliamo accedere per ottenere i vantaggi dell'automontaggio.
Regole Udev
Poiché UDEV ci consente di scrivere regole ed eseguire programmi sull'inserimento del dispositivo, questa è la scelta ideale. Trarremo vantaggio dalle regole esistenti di Debian / Ubuntu, consentiremo loro di impostare il /dev/disk/by-label/<LABEL>
collegamento simbolico per noi e aggiungere un'altra regola che monterà il dispositivo per noi.
Le regole di UDEV sono mantenute in /etc/udev/rules.d
(e /lib/udev/rules.d
su Karmic) e vengono elaborate in ordine numerico. Qualsiasi file che non inizia con un numero viene elaborato dopo i file numerati. Sul mio sistema, le regole HAL sono in un file chiamato 90-hal.rules
, quindi ho inserito le mie regole in 89-local.rules
modo che vengano elaborate prima di arrivare a HAL. In primo luogo, è necessario assicurarsi che queste regole si verifichino dopo il 60-persistent-storage.rules
. local.rules
potrebbe essere abbastanza buono.
Inserisci questo nel tuo nuovo file delle regole:
# /etc/udev/rules.d/local.rules
# /etc/udev/rules.d/89-local.rules
# ADD rule: if we have a valid ID_FS_LABEL_ENC, and it's USB, mkdir and mount
ENV{ID_FS_LABEL_ENC}=="?*", ACTION=="add", SUBSYSTEMS=="usb", \
RUN+="/usr/local/sbin/udev-automounter.sh %k"
Assicurati che non ci siano spazi dopo il \
, solo un newline
( \n
).
Passare SUBSYSTEMS=="usb"
a SUBSYSTEMS=="usb|ieee1394"
per supporto Firewire.
Se desideri che il dispositivo sia sempre di proprietà di un determinato utente, aggiungi una OWNER="username"
clausola. Se hai solo bisogno dei file di proprietà di un determinato utente, modifica invece lo script di mount.
Leggere la regola
Ciò aggiunge un programma da eseguire all'elenco dei programmi del dispositivo da eseguire. Identifica i dispositivi di partizione USB per <LABEL>
, quindi passa queste informazioni a uno script che esegue il montaggio. In particolare, questa regola corrisponde:
ENV{ID_FS_LABEL_ENC}=="?*"
- una variabile di ambiente impostata da una regola di sistema precedente. Non esiste per i non filesystem, quindi è per questo che lo controlliamo. In realtà vogliamo usarlo ID_FS_LABEL
per il mount point, ma non ho convinto UDEV a evitarlo per me, quindi lasceremo che lo script di mount lo gestisca.
Questa e altre variabili d'ambiente sono ottenute da udev usando il vol_id
comando ( obsoleto ). È uno strumento utile per visualizzare dettagli rapidi e piacevoli su una partizione:
$ sudo vol_id /dev/sdc1
ID_FS_TYPE=ext2
ID_FS_UUID=a40d282a-4a24-4593-a0ab-6f2600f920dd
ID_FS_LABEL=Travel Dawgs
ID_FS_LABEL_ENC=Travel\x20Dawgs
ID_FS_LABEL_SAFE=Travel_Dawgs
ACTION=="add"
- abbina solo add
eventi ...
SUBSYSTEMS=="usb"
- abbina solo i dispositivi che si trovano sul bus USB. Usiamo SUBSYSTEMS
qui perché questo corrisponde ai genitori del nostro dispositivo; il dispositivo a cui siamo interessati sarà effettivamente SUBSYSTEM == "scsi". La corrispondenza con un dispositivo USB principale evita di aggiungere il nostro programma alle unità interne.
RUN+="..."
- non una corrispondenza, ma un'azione: aggiungi questo programma all'elenco dei programmi da eseguire. Negli argomenti del programma, %k
viene espanso al nome del dispositivo (ad esempio sdc1
, non /dev/sdc1
) e $env{FOO}
ottiene il contenuto della variabile di ambiente FOO.
Test della regola
Il primo link di riferimento (sopra) è un eccellente tutorial di UDEV, ma è leggermente obsoleto. I programmi che esegue per testare le regole ( udevtest
in particolare) sono stati sostituiti udevadm
dall'utilità catch-all .
Dopo aver aggiunto la regola, collega il dispositivo. Dagli qualche secondo, quindi controlla per vedere a quale dispositivo è stato assegnato:
$ ls -l /dev/disk/by-label/*
lrwxrwxrwx 1 root root 10 2009-10-25 07:27 label_Foo -> ../../sda1
lrwxrwxrwx 1 root root 10 2009-10-25 07:27 label_Bar -> ../../sdb1
lrwxrwxrwx 1 root root 10 2009-10-25 07:27 label_Baz -> ../../sdc1
Se l'unità rimovibile contiene label_Baz
, è sul dispositivo sdc1
. Esegui questo e guarda l'output verso la fine:
$ sudo udevadm test /sys/block/sdc/sdc1
parse_file: reading (...) (many lines about files it reads)
import_uevent_var: import into environment: (...) (many lines about env variables)
(...) (many lines tracing rule matches & programs run)
update_link: found 1 devices with name 'disk/by-label/LABEL_BAZ'
update_link: found '/block/sdc/sdc1' for 'disk/by-label/LABEL_BAZ'
update_link: compare (our own) priority of '/block/sdc/sdc1' 0 >= 0
update_link: 'disk/by-label/LABEL_BAZ' with target 'sdc1' has the highest priority 0, create it
udevtest: run: '/usr/local/sbin/udev-automounter.sh sdc1 LABEL_BAZ'
udevtest: run: 'socket:/org/freedesktop/hal/udev_event'
udevtest: run: 'socket:@/org/kernel/udev/monitor'
Cerca il nome dello script dalla nostra RUN+=
regola nelle ultime righe (3 ° in fondo in questo esempio). Puoi vedere gli argomenti che verrebbero utilizzati per questo dispositivo. È possibile eseguire quel comando ora per verificare che gli argomenti siano validi; se funziona sulla riga di comando, dovrebbe funzionare automaticamente quando viene inserito un dispositivo.
Puoi anche monitorare gli eventi UDEV in tempo reale: esegui sudo udevadm monitor
(vedi man udevadm
per i dettagli sugli switch). Quindi collega un nuovo dispositivo e guarda scorrere gli eventi. (Probabilmente eccessivo a meno che non ti piacciano i dettagli di basso livello ...)
Ricaricare le regole
Dopo aver verificato che la regola viene letta correttamente, devi dire a UDEV di ricaricare le sue regole in modo che la nuova abbia effetto. Usa uno di questi metodi (se il primo non funziona, il secondo dovrebbe ... ma prova il primo primo):
Script! In realtà, 2 script ...
Ecco la prima sceneggiatura. Poiché il programma che eseguiamo deve essere completato rapidamente, questo fa girare il secondo script in background. Metti questo in /usr/local/sbin/udev-automounter.sh
:
#!/bin/sh
#
# USAGE: usb-automounter.sh DEVICE
# DEVICE is the actual device node at /dev/DEVICE
/usr/local/sbin/udev-auto-mount.sh ${1} &
Ecco la seconda sceneggiatura. Questo fa un po 'più controllo di input. Metti questo /usr/local/sbin/udev-auto-mount.sh
. Potresti voler modificare le opzioni di montaggio di seguito. Questo script ora gestisce la ricerca della partizione LABEL da sola; UDEV invia solo il nome del DISPOSITIVO.
Se si verifica un problema con il montaggio delle unità all'avvio , è possibile dedicare molto tempo sleep 60
a questo script, per dare al sistema il tempo di arrivare fino in fondo prima che lo script tenti di montare l'unità.
Ho dato un suggerimento nei commenti su come controllare (esegui ps
per vedere se un server web è in esecuzione), ma ti consigliamo di modificarlo per il tuo sistema. Penso che la maggior parte dei server di rete che potresti utilizzare sarebbe sufficiente per questo scopo - nfsd, smbd, apache, ecc. Il rischio, ovviamente, è che lo script di montaggio fallisca se il servizio non è in esecuzione, quindi forse testare un l'esistenza di un file particolare sarebbe una soluzione migliore.
#!/bin/sh
#
# USAGE: udev-auto-mount.sh DEVICE
# DEVICE is the actual device node at /dev/DEVICE
#
# This script takes a device name, looks up the partition label and
# type, creates /media/LABEL and mounts the partition. Mount options
# are hard-coded below.
DEVICE=$1
# check input
if [ -z "$DEVICE" ]; then
exit 1
fi
# test that this device isn't already mounted
device_is_mounted=`grep ${DEVICE} /etc/mtab`
if [ -n "$device_is_mounted" ]; then
echo "error: seems /dev/${DEVICE} is already mounted"
exit 1
fi
# If there's a problem at boot-time, this is where we'd put
# some test to check that we're booting, and then run
# sleep 60
# so the system is ready for the mount below.
#
# An example to experiment with:
# Assume the system is "booted enough" if the HTTPD server is running.
# If it isn't, sleep for half a minute before checking again.
#
# The risk: if the server fails for some reason, this mount script
# will just keep waiting for it to show up. A better solution would
# be to check for some file that exists after the boot process is complete.
#
# HTTPD_UP=`ps -ax | grep httpd | grep -v grep`
# while [ -z "$HTTPD_UP" ]; do
# sleep 30
# HTTPD_UP=`ps -ax | grep httpd | grep -v grep`
# done
# pull in useful variables from vol_id, quote everything Just In Case
eval `/sbin/vol_id /dev/${DEVICE} | sed 's/^/export /; s/=/="/; s/$/"/'`
if [ -z "$ID_FS_LABEL" ] || [ -z "$ID_FS_TYPE" ]; then
echo "error: ID_FS_LABEL is empty! did vol_id break? tried /dev/${DEVICE}"
exit 1
fi
# test mountpoint - it shouldn't exist
if [ ! -e "/media/${ID_FS_LABEL}" ]; then
# make the mountpoint
mkdir "/media/${ID_FS_LABEL}"
# mount the device
#
# If expecting thumbdrives, you probably want
# mount -t auto -o sync,noatime [...]
#
# If drive is VFAT/NFTS, this mounts the filesystem such that all files
# are owned by a std user instead of by root. Change to your user's UID
# (listed in /etc/passwd). You may also want "gid=1000" and/or "umask=022", eg:
# mount -t auto -o uid=1000,gid=1000 [...]
#
#
case "$ID_FS_TYPE" in
vfat) mount -t vfat -o sync,noatime,uid=1000 /dev/${DEVICE} "/media/${ID_FS_LABEL}"
;;
# I like the locale setting for ntfs
ntfs) mount -t auto -o sync,noatime,uid=1000,locale=en_US.UTF-8 /dev/${DEVICE} "/media/${ID_FS_LABEL}"
;;
# ext2/3/4 don't like uid option
ext*) mount -t auto -o sync,noatime /dev/${DEVICE} "/media/${ID_FS_LABEL}"
;;
esac
# all done here, return successful
exit 0
fi
exit 1
Script di pulizia super bonus!
Un'altra sceneggiatura. Tutto ciò che fa è smontare il dispositivo e rimuovere le directory mountpoint. Presuppone che abbia dei priv per farlo, quindi dovrai eseguirlo sudo
. Questo script ora prende l'intero mountpoint sulla riga di comando, ad esempio:
$ /usr/local/sbin/udev-unmounter.sh "/media/My Random Disk"
Metti questo in /usr/local/sbin/udev-unmounter.sh
:
#!/bin/sh
#
# USAGE: udev-unmounter.sh MOUNTPT
# MOUNTPT is a mountpoint we want to unmount and delete.
MOUNTPT="$1"
if [ -z "$MOUNTPT" ]; then
exit 1
fi
# test mountpoint - it should exist
if [ -e "${MOUNTPT}" ]; then
# very naive; just run and pray
umount -l "${MOUNTPT}" && rmdir "${MOUNTPT}" && exit 0
echo "error: ${MOUNTPT} failed to unmount."
exit 1
fi
echo "error: ${MOUNTPT} does not exist"
exit 1