- Remarque pour Ubuntu Server 11.10: Ce script échoue sous Ubuntu Server 11.10 en raison de la
vol_id
commande obsolète . vol_id
a été remplacé par blkid
. Pour corriger le script, remplacez "vol_id" par "blkid -o udev" dans le udev-auto-mount.sh
script.
Cela fait un moment que je me cogne la tête et je pense avoir trouvé une solution efficace. Ceci est développé et testé sur un système basé sur Debian, il devrait donc fonctionner sur Ubuntu. Je ferai remarquer les hypothèses sur lesquelles il repose afin que celui-ci puisse également être adapté à d'autres systèmes.
- Il montera automatiquement les clés USB sur le plug-in et ne devrait pas demander beaucoup d'efforts pour s'adapter à Firewire.
- Il utilise UDEV, donc pas de singe avec HAL / DeviceKit / GNOME-Anything.
- Il crée automatiquement un
/media/LABEL
répertoire sur lequel monter le périphérique.
- Cependant, il peut interférer avec d’autres montages automatiques; Je ne peux pas tester pour ça. J'imagine que, lorsque Gnome-VFS est actif, les deux peuvent essayer de faire le montage ... Si Gnome-VFS échoue, il risque de ne pas configurer d'icône de bureau. Démonter de Gnome devrait être possible, mais peut nécessiter
gksudo
ou similaire.
Je n'ai pas testé cela au démarrage du système, mais la seule raison pour laquelle je vois que cela pourrait ne pas fonctionner est si le système essaie de monter le lecteur USB avant que le système ne soit prêt pour le montage. Si tel est le cas, vous aurez probablement besoin d'un ajustement supplémentaire pour le script de montage. (Je vérifie avec ServerFault pour voir s'il y a un conseil, mais cela ne suscite pas beaucoup d'intérêt.)
Sur, alors.
Références UDEV:
Contexte (UDEV? Whuzzat?)
UDEV est le système hotplug du noyau. C'est ce qui configure automatiquement les périphériques et les liens symboliques de périphérique appropriés (par exemple /dev/disk/by-label/<LABEL>
), à la fois au moment du démarrage et pour les périphériques ajoutés lorsque le système est en cours d'exécution.
D-Bus et HAL sont utilisés pour envoyer des événements matériels à des écouteurs tels que Desktop Environments. 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 hop, votre disque est monté. Mais dans un système sans tête, nous ne voulons pas avoir à nous connecter pour profiter des avantages du montage automatique.
Règles d'Udev
Puisque UDEV nous permet d’écrire des règles et d’exécuter des programmes lors de l’insertion de périphériques, c’est un choix idéal. Nous allons tirer parti des règles existantes de Debian / Ubuntu, leur laisser configurer le /dev/disk/by-label/<LABEL>
lien symbolique pour nous et ajouter une autre règle qui montera le périphérique pour nous.
Les règles de UDEV sont conservées dans /etc/udev/rules.d
(et /lib/udev/rules.d
sur le karmique) et sont traitées dans l'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 HAL se trouvent dans un fichier appelé 90-hal.rules
. J'ai donc inséré mes règles 89-local.rules
pour qu'elles soient traitées avant d'arriver à HAL. Avant tout, vous devez vous assurer que ces règles se produisent après la 60-persistent-storage.rules
. local.rules
peut être assez bon.
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
).
Passez SUBSYSTEMS=="usb"
à l' SUBSYSTEMS=="usb|ieee1394"
assistance Firewire.
Si vous souhaitez que le périphérique appartienne toujours à un utilisateur particulier, ajoutez une OWNER="username"
clause. Si vous avez juste besoin des fichiers appartenant à un utilisateur particulier, modifiez le script de montage à la place.
Lire la règle
Cela 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. N'existe pas pour les systèmes non-fichiers, c'est pourquoi nous le vérifions. Nous voulons en fait utiliser ID_FS_LABEL
le point de montage, mais je n’ai pas convaincu UDEV de le lui échapper, nous allons donc laisser le script de montage le gérer.
Cette variable, ainsi que d’autres, est obtenue par udev à l’aide de la vol_id
commande ( obsolète ). C’est un outil pratique pour voir de jolis détails rapides sur 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"
- seulement les add
événements de match ...
SUBSYSTEMS=="usb"
- correspond uniquement aux périphériques présents sur le bus USB. Nous utilisons SUBSYSTEMS
ici parce que cela correspond aux parents de notre appareil; le dispositif qui nous intéresse sera en réalité SOUS-SYSTÈME == "scsi". La correspondance avec un périphérique USB parent évite d’ajouter notre programme aux lecteurs internes.
RUN+="..."
- pas une correspondance, mais une action: ajoutez ce programme à la liste des programmes à exécuter. Dans les arguments du programme, %k
est étendu au nom de périphérique (par exemple sdc1
, not /dev/sdc1
) et $env{FOO}
obtient 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 l' udevadm
utilitaire catch-all .
Après avoir ajouté la règle, branchez votre appareil. Donnez-lui quelques secondes, puis vérifiez le périphérique auquel il est affecté:
$ 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 le périphérique sdc1
. Exécutez ceci et regardez le résultat 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'
Recherchez le nom de script de notre RUN+=
règle dans les dernières lignes (3ème à partir du bas dans cet exemple). Vous pouvez voir les arguments qui seraient utilisés pour ce périphérique. Vous pouvez exécuter cette commande maintenant pour vérifier que les arguments sont corrects. si cela fonctionne sur votre ligne de commande, il 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
(voir man udevadm
pour plus de détails sur les commutateurs). Ensuite, branchez simplement un nouvel appareil et regardez les événements défiler. (Probablement exagéré sauf si vous êtes dans les détails vraiment bas ...)
Recharger les règles
Une fois que vous avez vérifié que la règle est lue correctement, vous devez dire à UDEV de recharger ses règles pour que la nouvelle prenne effet. Utilisez l’une de ces méthodes (si la première ne fonctionne pas, la seconde devrait ... mais essayez la première):
Scénario! En fait, 2 scripts ...
Voici le premier script. Comme le programme que nous exécutons doit être terminé rapidement, le second script est alors lancé en arrière-plan. Mettez ceci 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 fait un peu plus de vérification d'entrée. Mettez ceci dans /usr/local/sbin/udev-auto-mount.sh
. Vous voudrez peut-être modifier les options de montage ci-dessous. Ce script gère maintenant la recherche de la partition LABEL par elle-même; UDEV n'envoie que le nom DEVICE.
En cas de problème lors du montage des lecteurs au démarrage , vous pouvez en ajouter un long sleep 60
dans ce script, afin de laisser le temps système de se dérouler avant que le script ne tente de monter le lecteur.
J'ai donné dans les commentaires une suggestion sur la façon de vérifier (exécuter ps
pour voir si un serveur Web est en cours d'exécution), mais vous voudrez modifier cela pour votre système. Je pense que la plupart des serveurs de réseau que vous utiliseriez suffiraient - nfsd, smbd, apache, etc. Le risque, bien sûr, est que le script de montage échoue si le service ne fonctionne pas 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
Script de nettoyage super bonus!
Un autre script. Tout cela consiste à démonter le périphérique et à supprimer les répertoires du point de montage. Il suppose qu'il a des privilèges pour le faire, vous devrez donc l'exécuter avec 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 ceci 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