- Hinweis für Ubuntu Server 11.10: Dieses Skript schlägt unter Ubuntu Server 11.10 aufgrund des veralteten
vol_id
Befehls fehl . vol_id
wurde ersetzt durch blkid
. Um das Skript zu reparieren, ersetzen Sie "vol_id" durch "blkid -o udev" im udev-auto-mount.sh
Skript.
Ich habe mich schon eine Weile damit beschäftigt und ich denke, ich habe eine funktionierende Lösung gefunden. Dies wurde auf einem Debian-basierten System entwickelt und getestet, daher sollte es auf Ubuntu funktionieren. Ich werde auf die Annahmen hinweisen, die es macht, damit es auch an andere Systeme angepasst werden kann.
- Es wird automatisch USB-Laufwerke beim Plugin einbinden und sollte nicht viel Zeit in Anspruch nehmen, um sich an Firewire anzupassen.
- Es verwendet UDEV, also kein Affe mit HAL / DeviceKit / GNOME-Anything.
- Es erstellt automatisch ein
/media/LABEL
Verzeichnis, in das das Gerät eingehängt werden soll.
- Es kann jedoch zu Interferenzen mit anderen Automountern kommen. Das kann ich nicht testen. Ich gehe davon aus, dass beide bei aktivem Gnome-VFS versuchen können, den Mount durchzuführen. Wenn Gnome-VFS den Mount nicht erfolgreich durchführt, wird möglicherweise kein Desktopsymbol konfiguriert. Das Abmelden von Gnome sollte möglich sein, erfordert aber möglicherweise etwas
gksudo
Ähnliches.
Ich habe dies nicht beim Systemstart getestet, aber der einzige Grund, warum ich feststellen kann, dass es möglicherweise nicht funktioniert, ist der Versuch, das USB-Laufwerk zu mounten, bevor das System zum Mounten bereit ist. Wenn dies der Fall ist, benötigen Sie wahrscheinlich eine zusätzliche Optimierung des Mount-Skripts. (Ich wende mich an ServerFault, um zu sehen, ob es Ratschläge gibt, aber nicht viel Interesse daran.)
Also weiter so.
UDEV Referenzen:
Hintergrund (UDEV? Whuzzat?)
UDEV ist das Hotplug-System des Kernels. Dies konfiguriert automatisch die richtigen Geräte und Geräte-Symlinks (z. B. /dev/disk/by-label/<LABEL>
), sowohl beim Booten als auch für Geräte, die hinzugefügt werden, während das System ausgeführt wird.
D-Bus und HAL werden zum Senden von Hardware-Ereignissen an Listener wie Desktop-Umgebungen verwendet. Wenn Sie sich bei GNOME anmelden und eine CD einlegen oder ein USB-Laufwerk anschließen, folgt dieses Ereignis dieser Kette:
kernel -> udev -> dbus -> hal -> gnome-vfs/nautilus (mount)
Und schon wird Ihr Laufwerk montiert. In einem kopflosen System müssen wir uns jedoch nicht anmelden, um die Vorteile des automatischen Einbaus nutzen zu können.
Udev-Regeln
Da wir mit UDEV Regeln schreiben und Programme beim Einfügen von Geräten ausführen können, ist dies eine ideale Wahl. Wir werden die vorhandenen Regeln von Debian / Ubuntu nutzen, sie den /dev/disk/by-label/<LABEL>
Symlink für uns einrichten lassen und eine weitere Regel hinzufügen, die das Gerät für uns bereitstellt.
Die UDEV-Regeln werden in /etc/udev/rules.d
(und /lib/udev/rules.d
auf Karmic) aufbewahrt und in numerischer Reihenfolge verarbeitet. Jede Datei, die nicht mit einer Nummer beginnt, wird nach den nummerierten Dateien verarbeitet. Auf meinem System befinden sich HAL-Regeln in einer Datei mit dem Namen 90-hal.rules
. Ich habe meine Regeln 89-local.rules
so eingefügt, dass sie verarbeitet werden, bevor sie zu HAL gelangen. In erster Linie müssen Sie sicherstellen, dass diese Regeln nach dem auftreten 60-persistent-storage.rules
. local.rules
kann gut genug sein.
Fügen Sie dies in Ihre neue Regeldatei ein:
# /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"
Stellen Sie sicher, dass nach \
, nur ein newline
( \n
) keine Leerzeichen stehen .
Wechseln Sie SUBSYSTEMS=="usb"
zu SUBSYSTEMS=="usb|ieee1394"
für die Firewire-Unterstützung.
Wenn das Gerät immer einem bestimmten Benutzer gehören soll, fügen Sie eine OWNER="username"
Klausel hinzu. Wenn Sie nur die Dateien eines bestimmten Benutzers benötigen, optimieren Sie stattdessen das Mount-Skript.
Die Regel lesen
Dadurch wird ein auszuführendes Programm zur Liste der auszuführenden Programme des Geräts hinzugefügt. Es identifiziert USB-Partitionsgeräte anhand von <LABEL>
und leitet diese Informationen an ein Skript weiter, das die Bereitstellung durchführt. Im Einzelnen entspricht diese Regel:
ENV{ID_FS_LABEL_ENC}=="?*"
- eine Umgebungsvariable, die von einer früheren Systemregel festgelegt wurde. Existiert nicht für Nicht-Dateisysteme, deshalb suchen wir danach. Eigentlich möchten wir ID_FS_LABEL
den Mount-Punkt verwenden, aber ich habe UDEV nicht davon überzeugt, ihn für mich zu entziehen. Deshalb lassen wir das Mount-Skript damit umgehen.
Diese und andere Umgebungsvariablen werden von udev mit dem vol_id
Befehl ( veraltet ) abgerufen . Es ist ein praktisches Tool, mit dem Sie schnell Details zu einer Partition anzeigen können:
$ 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"
- nur Spielereignisse add
...
SUBSYSTEMS=="usb"
- stimmen Sie nur mit Geräten überein, die sich am USB-Bus befinden. Wir verwenden SUBSYSTEMS
hier, weil dies mit den Eltern unseres Geräts übereinstimmt. Das Gerät, an dem wir interessiert sind, wird tatsächlich SUBSYSTEM == "scsi" sein. Durch die Zuordnung zu einem übergeordneten USB-Gerät wird vermieden, dass unser Programm den internen Laufwerken hinzugefügt wird.
RUN+="..."
- Keine Übereinstimmung, sondern eine Aktion: Fügen Sie dieses Programm zur Liste der auszuführenden Programme hinzu. Wird in den Programmargumenten %k
auf den Gerätenamen erweitert (z. B. sdc1
nicht /dev/sdc1
) und $env{FOO}
ruft den Inhalt der Umgebungsvariablen FOO ab.
Regel testen
Der erste Referenzlink (oben) ist ein exzellentes UDEV-Tutorial, aber etwas veraltet. Die Programme, die ( udevtest
insbesondere) zum Testen Ihrer Regeln ausgeführt werden, wurden durch das udevadm
Dienstprogramm catch-all ersetzt .
Nachdem Sie die Regel hinzugefügt haben, schließen Sie Ihr Gerät an. Nehmen Sie sich ein paar Sekunden Zeit und überprüfen Sie, welchem Gerät es zugewiesen wurde:
$ 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
Wenn Ihr Wechsellaufwerk enthält label_Baz
, befindet es sich auf dem Gerät sdc1
. Führen Sie dies aus und schauen Sie sich die Ausgabe gegen Ende an:
$ 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'
Suchen Sie RUN+=
in den letzten Zeilen nach dem Skriptnamen aus unserer Regel (in diesem Beispiel der dritte von unten). Sie können die Argumente sehen, die für dieses Gerät verwendet werden würden. Sie können diesen Befehl jetzt ausführen, um zu überprüfen, ob die Argumente korrekt sind. Wenn es in Ihrer Befehlszeile funktioniert, sollte es automatisch funktionieren, wenn ein Gerät eingefügt wird.
Sie können UDEV-Ereignisse auch in Echtzeit überwachen: ausführen sudo udevadm monitor
( man udevadm
Einzelheiten zu den Schaltern siehe ). Dann schließen Sie einfach ein neues Gerät an und schauen Sie sich die Ereignisse an. (Wahrscheinlich übertrieben, es sei denn, Sie interessieren sich für wirklich einfache Details ...)
Regeln neu laden
Sobald Sie überprüft haben, dass die Regel richtig gelesen wird, müssen Sie UDEV anweisen, die Regeln neu zu laden, damit die neue wirksam wird. Wenden Sie eine der folgenden Methoden an (wenn die erste nicht funktioniert, sollte die zweite ... aber versuchen Sie die erste zuerst):
Skript! Eigentlich 2 Skripte ...
Hier ist das erste Skript. Da das von uns ausgeführte Programm schnell ausgeführt werden muss, wird das zweite Skript nur im Hintergrund ausgeführt. Setzen Sie dies 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} &
Hier ist das zweite Skript. Dies führt zu einer etwas stärkeren Eingabeprüfung. Setzen Sie dies in /usr/local/sbin/udev-auto-mount.sh
. Möglicherweise möchten Sie die folgenden Mount-Optionen optimieren. Dieses Skript kann jetzt die Partition LABEL selbstständig finden. UDEV sendet nur den DEVICE-Namen.
Wenn beim Hochfahren Probleme beim Mounten von Laufwerken auftreten , können Sie sleep 60
in dieses Skript einen langen Zeitraum einfügen, damit das System Zeit hat, bis das Skript versucht, das Laufwerk zu mounten.
Ich habe in den Kommentaren einen Vorschlag zur Überprüfung (Ausführen ps
, um festzustellen, ob ein Webserver ausgeführt wird) gemacht, aber Sie sollten diesen Vorschlag für Ihr System anpassen. Ich denke, die meisten Netzwerkserver, die Sie möglicherweise verwenden, würden für diesen Zweck ausreichen - nfsd, smbd, apache usw. Das Risiko besteht natürlich darin, dass das Mount-Skript fehlschlägt, wenn der Dienst nicht ausgeführt wird Die Existenz einer bestimmten Datei wäre eine bessere Lösung.
#!/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
Super Bonus Cleanup Script!
Noch ein Drehbuch. Dazu müssen Sie nur das Gerät aushängen und die Mountpoint-Verzeichnisse entfernen. Es wird davon ausgegangen, dass es über Privilegien verfügt, mit denen Sie es ausführen müssen sudo
. Dieses Skript übernimmt jetzt den vollständigen Mountpunkt in der Befehlszeile, z. B .:
$ /usr/local/sbin/udev-unmounter.sh "/media/My Random Disk"
Setzen Sie dies 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