- Nota para Ubuntu Server 11.10: este script falla en Ubuntu Server 11.10 debido al
vol_id
comando obsoleto . vol_id
ha sido sustituida por blkid
. Para arreglar el script, reemplace "vol_id" por "blkid -o udev" en el udev-auto-mount.sh
script.
He estado golpeándome la cabeza por un tiempo y creo que he encontrado una solución que funciona. Esto está desarrollado y probado en un sistema basado en Debian, por lo que debería funcionar en Ubuntu. Señalaré los supuestos que hace para que también se pueda adaptar a otros sistemas.
- Montará automáticamente unidades USB en el complemento, y no debería llevar mucho tiempo adaptarse a Firewire.
- Utiliza UDEV, por lo que no es necesario hacer monos con HAL / DeviceKit / GNOME-Anything.
- Automáticamente crea un
/media/LABEL
directorio para montar el dispositivo.
- Sin embargo, puede interferir con otros montadores automáticos; No puedo probar para eso. Espero que, con Gnome-VFS activo, ambos intenten hacer el montaje ... si Gnome-VFS falla el montaje, es posible que no configure un icono de escritorio. Desmontar de Gnome debería ser posible, pero podría requerir
gksudo
o similar.
No he probado esto en el arranque del sistema, pero la única razón por la que puedo ver que podría no funcionar es si intenta montar la unidad USB antes de que el sistema esté listo para montarse. Si ese es el caso, probablemente necesitará un ajuste adicional al script de montaje. (Estoy comprobando con ServerFault para ver si hay algún consejo, pero no hay mucho interés en él allí).
A ello, entonces.
Referencias UDEV:
Fondo (UDEV? Whuzzat?)
UDEV es el sistema de conexión en caliente del núcleo. Es lo que configura automáticamente los dispositivos y enlaces simbólicos del dispositivo (por ejemplo /dev/disk/by-label/<LABEL>
), tanto en el momento del arranque como para los dispositivos agregados mientras el sistema se está ejecutando.
D-Bus y HAL se utilizan para enviar eventos de hardware a oyentes como entornos de escritorio. Entonces, cuando inicia sesión en GNOME e inserta un CD o conecta una unidad USB, ese evento sigue esta cadena:
kernel -> udev -> dbus -> hal -> gnome-vfs/nautilus (mount)
Y listo, su unidad se monta. Pero en un sistema sin cabeza, no queremos tener que iniciar sesión para obtener los beneficios del montaje automático.
Reglas Udev
Dado que UDEV nos permite escribir reglas y ejecutar programas en la inserción del dispositivo, esta es una opción ideal. Vamos a aprovechar las reglas existentes de Debian / Ubuntu, dejar que configuren el /dev/disk/by-label/<LABEL>
enlace simbólico para nosotros y agregar otra regla que montará el dispositivo para nosotros.
Las reglas de UDEV se guardan en /etc/udev/rules.d
(y /lib/udev/rules.d
en Karmic) y se procesan en orden numérico. Cualquier archivo que no comience con un número se procesa después de los archivos numerados. En mi sistema, las reglas de HAL se encuentran en un archivo llamado 90-hal.rules
, así que puse mis reglas 89-local.rules
para que se procesen antes de llegar a HAL. Principalmente, debe asegurarse de que estas reglas sucedan después del 60-persistent-storage.rules
. local.rules
puede ser lo suficientemente bueno
Ponga esto en su nuevo archivo de reglas:
# /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"
Asegúrese de que no haya espacios después del \
, solo un newline
( \n
).
Cambie SUBSYSTEMS=="usb"
a SUBSYSTEMS=="usb|ieee1394"
para soporte Firewire.
Si desea que el dispositivo sea propiedad de un usuario en particular, agregue una OWNER="username"
cláusula. Si solo necesita los archivos de un usuario en particular, modifique el script de montaje.
Leyendo la regla
Esto agrega un programa para ejecutar a la lista de programas para ejecutar del dispositivo. Identifica los dispositivos de partición USB <LABEL>
, luego pasa esta información a un script que realiza el montaje. Específicamente, esta regla es coincidente:
ENV{ID_FS_LABEL_ENC}=="?*"
- una variable de entorno establecida por una regla del sistema anterior. No existe para los sistemas que no son de archivos, por eso lo comprobamos. En realidad, queremos usarlo ID_FS_LABEL
para el punto de montaje, pero no he convencido a UDEV para que escape por mí, así que dejaremos que el script de montaje se encargue de eso.
Udev obtiene esta y otras variables de entorno utilizando el vol_id
comando (en desuso ). Es una herramienta útil para ver detalles rápidos y agradables en una partición:
$ 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"
- solo coincide con add
eventos ...
SUBSYSTEMS=="usb"
- solo coincide con los dispositivos que están en el bus USB. Usamos SUBSYSTEMS
aquí porque esto coincide con los padres de nuestro dispositivo; el dispositivo que nos interesa en realidad será SUBSYSTEM == "scsi". Hacer coincidir un dispositivo USB principal evita agregar nuestro programa a las unidades internas.
RUN+="..."
- no es una coincidencia, sino una acción: agregue este programa a la lista de programas para ejecutar. En los argumentos del programa, %k
se expande al nombre del dispositivo (p sdc1
. Ej. , No /dev/sdc1
) y $env{FOO}
obtiene el contenido de la variable de entorno FOO.
Probar la regla
El primer enlace de referencia (arriba) es un excelente tutorial de UDEV, pero está un poco desactualizado. Los programas que ejecuta para probar sus reglas ( udevtest
en particular) han sido reemplazados por la udevadm
utilidad catch-all .
Después de agregar la regla, conecte su dispositivo. Espere unos segundos, luego verifique a qué dispositivo se le ha asignado:
$ 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 su unidad extraíble contiene label_Baz
, está en el dispositivo sdc1
. Ejecute esto y mire la salida hacia el final:
$ 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'
Busque el nombre del script de nuestra RUN+=
regla en las últimas líneas (tercero en la parte inferior en este ejemplo). Puede ver los argumentos que se usarían para este dispositivo. Puede ejecutar ese comando ahora para verificar que los argumentos son sólidos; si funciona en su línea de comando, debería funcionar automáticamente cuando se inserta un dispositivo.
También puede monitorear los eventos de UDEV en tiempo real: ejecutar sudo udevadm monitor
(consulte los man udevadm
detalles sobre los conmutadores). Luego, simplemente conecte un nuevo dispositivo y vea los eventos desplazarse. (Probablemente exagere a menos que le gusten los detalles de bajo nivel ...)
Recargando las Reglas
Una vez que haya verificado que la regla se está leyendo correctamente, debe decirle a UDEV que vuelva a cargar sus reglas para que la nueva surta efecto. Utilice cualquiera de estos métodos (si el primero no funciona, el segundo debería ... pero pruebe el primero primero):
¡Guión! En realidad, 2 scripts ...
Aquí está el primer guión. Dado que el programa que ejecutamos debe completarse rápidamente, esto simplemente hace girar el segundo script en segundo plano. Pon esto en /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} &
Aquí está el segundo guión. Esto hace un poco más de verificación de entrada. Pon esto en /usr/local/sbin/udev-auto-mount.sh
. Es posible que desee ajustar las opciones de montaje a continuación. Este script ahora maneja la búsqueda de la etiqueta de partición por sí mismo; UDEV solo envía el nombre del DISPOSITIVO.
Si hay un problema al montar unidades en el momento del arranque , puede poner un buen tiempo sleep 60
en este script, para darle tiempo al sistema para que llegue al final antes de que el script intente montar el disco.
He dado una sugerencia en los comentarios sobre cómo verificar (ejecutar ps
para ver si se está ejecutando un servidor web), pero querrá modificar eso para su sistema. Creo que la mayoría de los servidores de red que podría estar utilizando serían suficientes para este propósito: nfsd, smbd, apache, etc. El riesgo, por supuesto, es que el script de montaje fallará si el servicio no se está ejecutando, por lo que tal vez pruebe un la existencia de un archivo en particular sería una mejor solución.
#!/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
¡Súper script de limpieza extra!
Un guion más. Todo lo que hace es desmontar el dispositivo y eliminar los directorios de punto de montaje. Se supone que tiene privilegios para hacer esto, por lo que deberá ejecutarlo sudo
. Este script ahora toma el punto de montaje completo en la línea de comandos, por ejemplo:
$ /usr/local/sbin/udev-unmounter.sh "/media/My Random Disk"
Pon esto en /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