-
Note pour Ubuntu Server 11.10 : Ce script échoue sur Ubuntu Server 11.10 à cause de l'obsolète
vol_id
commandement. vol_id
a été remplacée par blkid
. Pour corriger le script, remplacez "vol_id" par "blkid -o udev" dans le fichier udev-auto-mount.sh
script.
Je me suis creusé la tête à ce sujet pendant un certain temps et je pense avoir trouvé une solution efficace. Celle-ci est développée et testée sur un système basé sur Debian, elle devrait donc fonctionner sur Ubuntu. Je vais indiquer les hypothèses qu'il fait pour qu'il puisse être adapté à d'autres systèmes.
-
Il montera automatiquement les disques USB sur le plugin, et ne devrait pas prendre beaucoup de temps pour s'adapter au Firewire.
-
Il utilise UDEV, donc pas de manipulation avec HAL/DeviceKit/GNOME-quelque chose.
-
Il crée automatiquement un /media/LABEL
le répertoire dans lequel monter le périphérique.
-
Cependant, il puede interférer avec d'autres compteurs automatiques ; je ne peux pas le tester. Je m'attends à ce que, avec Gnome-VFS actif, les deux tentent d'effectuer le montage... si Gnome-VFS échoue le montage, il se peut qu'il ne configure pas d'icône de bureau. Le démontage à partir de Gnome devrait être possible, mais pourrait nécessiter gksudo
ou similaire.
Je n'ai pas testé cela au démarrage du système, mais la seule raison que je vois pour laquelle cela pourrait ne pas fonctionner est qu'il essaie de monter la clé USB avant que le système ne soit prêt pour les montages. Si c'est le cas, vous aurez probablement besoin d'une modification supplémentaire du script de montage. (Je suis vérification avec ServerFault pour voir s'il y a des conseils, mais il n'y a pas beaucoup d'intérêt pour ça là-bas).
On y va, alors.
Références UDEV :
Contexte (UDEV ? Qu'est-ce que c'est ?)
UDEV est le système hotplug du noyau. C'est ce qui configure automatiquement les périphériques appropriés et les liens symboliques de périphériques (par ex. /dev/disk/by-label/<LABEL>
), à la fois au moment du démarrage et pour les périphériques ajoutés pendant l'exécution du système.
D-Bus et HAL sont utilisés pour envoyer des événements matériels aux auditeurs tels que les environnements de bureau. Ainsi, lorsque vous vous connectez à GNOME et insérez un CD ou branchez une clé USB, cet événement suit cette chaîne :
kernel -> udev -> dbus -> hal -> gnome-vfs/nautilus (mount)
Et presto, votre disque est monté. Mais dans un système sans tête, nous ne voulons pas avoir à nous connecter pour bénéficier des avantages du montage automatique.
Règles Udev
Comme UDEV nous permet d'écrire des règles et d'exécuter des programmes lors de l'insertion du périphérique, c'est un choix idéal. Nous allons tirer parti des règles existantes de Debian/Ubuntu, les laisser configurer le programme /dev/disk/by-label/<LABEL>
symlink pour nous, et ajouter une autre règle qui montera le périphérique pour nous.
Les règles d'UDEV sont conservées dans /etc/udev/rules.d
(et /lib/udev/rules.d
sur Karmic), et sont traitées par ordre numérique. Tout fichier ne commençant pas par un numéro est traité après les fichiers numérotés. Sur mon système, les règles de HAL sont dans un fichier appelé 90-hal.rules
donc j'ai mis mes règles dans 89-local.rules
pour qu'ils soient traités avant d'arriver à HAL. Principalement, vous devez vous assurer que ces règles se produisent après que les 60-persistent-storage.rules
. local.rules
peut être suffisant.
Mettez ceci dans votre nouveau fichier de règles :
# /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"
-
Assurez-vous qu'il n'y a pas d'espace après le \
juste un newline
( \n
).
-
Changement SUBSYSTEMS=="usb"
a SUBSYSTEMS=="usb|ieee1394"
pour le support Firewire.
-
Si vous voulez que le périphérique soit toujours la propriété d'un utilisateur particulier, ajoutez une balise OWNER="username"
clause. Si vous n'avez besoin que des fichiers appartenant à un utilisateur particulier, modifiez plutôt le script mount script.
Lecture de la règle
Il ajoute un programme à exécuter à la liste des programmes à exécuter du périphérique. Il identifie les périphériques de partition USB par <LABEL>
puis transmet ces informations à un script qui effectue le montage. Plus précisément, cette règle correspond :
-
*`ENV{ID_FS_LABEL_ENC}=="?"** -- une variable d'environnement définie par une règle système antérieure. Elle n'existe pas pour les systèmes autres que les systèmes de fichiers, c'est pourquoi nous la vérifions. Nous voulons en fait utiliser
ID_FS_LABEL` pour le point de montage, mais je n'ai pas convaincu UDEV de l'échapper pour moi, donc nous laisserons le script de montage gérer cela.
Cette variable et d'autres variables d'environnement sont obtenues par udev en utilisant la commande vol_id
( déprécié ). C'est un outil pratique pour voir rapidement les détails d'une partition :
$ 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"
-- ne correspond qu'à add
des événements...
-
SUBSYSTEMS=="usb"
-- ne correspondent qu'aux dispositifs qui se trouvent sur le bus USB. Nous utilisons SUBSYSTEMS
ici parce que cela correspond aux parents de notre périphérique ; le périphérique qui nous intéresse sera en fait SUBSYSTEM=="scsi". La correspondance avec un périphérique USB parent évite d'ajouter notre programme aux disques internes.
-
RUN+="..."
-- pas une correspondance, mais une action : ajouter ce programme à la liste des programmes à exécuter. Dans les arguments du programme, %k
est étendu au nom du dispositif (par exemple sdc1
pas /dev/sdc1
) et $env{FOO}
récupère le contenu de la variable d'environnement FOO.
Tester la règle
Le premier lien de référence (ci-dessus) est un excellent tutoriel UDEV, mais il est légèrement obsolète. Les programmes qu'il exécute pour tester vos règles ( udevtest
en particulier) ont été remplacés par le fourre-tout udevadm
utilitaire.
Après avoir ajouté la règle, branchez votre appareil. Laissez-lui quelques secondes, puis vérifiez avec quel appareil il a été assigné :
$ 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
Si votre lecteur amovible contient label_Baz
c'est sur l'appareil sdc1
. Exécutez ceci et regardez la sortie vers la fin :
$ 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'
Cherchez le nom du script de notre RUN+=
dans les dernières lignes (3e en partant du bas dans cet exemple). Vous pouvez voir les arguments qui seraient utilisés pour ce dispositif. Vous pouvez exécuter cette commande maintenant pour vérifier que les arguments sont corrects ; si elle fonctionne sur votre ligne de commande, elle devrait fonctionner automatiquement lorsqu'un périphérique est inséré.
Vous pouvez également surveiller les événements UDEV en temps réel : exécutez sudo udevadm monitor
(ver man udevadm
pour plus de détails sur les commutateurs). Il suffit ensuite de brancher un nouveau périphérique et de regarder les événements défiler. (Probablement exagéré, sauf si vous êtes dans les détails de très bas niveau...)
Recharger les règles
Une fois que vous avez vérifié que la règle est lue correctement, vous devez demander à UDEV de recharger ses règles pour que la nouvelle règle prenne effet. Utilisez l'une de ces méthodes (si la première ne fonctionne pas, la seconde devrait... mais essayez d'abord la première) :
script ! En fait, 2 script...
Voici le premier script. Comme le programme que nous exécutons doit se terminer rapidement, cela fait tourner le second script en arrière-plan. Mettez ça dans /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} &
Voici le deuxième script. Cela permet de vérifier un peu plus les entrées. Mettez ceci dans /usr/local/sbin/udev-auto-mount.sh
. Vous pouvez vouloir modifier les options de montage ci-dessous. Ce script s'occupe maintenant de trouver le LABEL de la partition par lui-même ; UDEV envoie seulement le nom du DEVICE.
S'il y a un problème de montage des lecteurs au démarrage vous pouvez mettre une belle et longue sleep 60
dans ce script, pour donner au système le temps de monter complètement avant que le script tente de monter le lecteur.
J'ai donné une suggestion dans les commentaires pour savoir comment vérifier (exécuter ps
pour voir si un serveur web est en cours d'exécution), mais vous devrez adapter cela à votre système. Je pense que la plupart des serveurs réseau que vous pourriez utiliser suffiraient à cet effet -- nfsd, smbd, apache, etc. Le risque, bien sûr, est que le mount script échoue si le service n'est pas en cours d'exécution, alors peut-être que tester l'existence d'un fichier particulier serait une meilleure solution.
#!/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 de nettoyage script !
Encore un script. Tout ce qu'il fait est de démonter le périphérique et de supprimer les répertoires du point de montage. Il suppose qu'il a des privilèges pour le faire, donc vous devrez l'exécuter avec le code suivant sudo
. Ce script prend maintenant le point de montage complet sur la ligne de commande, par exemple :
$ /usr/local/sbin/udev-unmounter.sh "/media/My Random Disk"
Mettez ça dans /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