Nous mettons à jour nos serveurs d'une distribution très obsolète à un système moderne basé sur Debian Jessie, y compris lightdm/xfce, et bien sûr systemd (et udisks2). Un point de blocage est le montage automatique de clés USB. Nous avions l'habitude d'accomplir cela avec quelques règles udev. Les anciennes règles fonctionnent presque toujours - le point de montage est créé et le lecteur est monté correctement, mais après quelques secondes, systemd fait quelque chose qui rompt le montage, de sorte que les tentatives d'accès suivantes entraînent des erreurs "Le point d'extrémité de transport n'est pas connecté".
Le montage manuel du lecteur via la ligne de commande fonctionne correctement. Il en va de même pour un gestionnaire de fichiers (thunar et thunar-volman, qui à son tour utilise udisks2). Mais ce ne sont pas des options viables - ces systèmes fonctionnent généralement sans tête, donc thunar ne fonctionne pas normalement. Nous devons être capables de brancher des unités de disque pour des sauvegardes cron sans assistance.
Je pensais que la modification du script udev pour générer un travail détaché qui attend quelques secondes avant d'effectuer le montage pourrait faire l'affaire, mais systemd semble se mettre en quatre pour éviter cela - il attend toujours que le travail détaché se termine avant continue.
Peut-être que le script udev chatouille udisks2 est en quelque sorte la bonne approche? Je suis perdu, donc tout conseil est grandement apprécié.
Après plusieurs faux départs, j'ai compris cela. La clé est d'ajouter un service d'unité systemd entre udev et un script de montage.
(Pour mémoire, je n'ai pas pu faire fonctionner cela en utilisant udisks2 (via quelque chose comme udisksctl mount -b /dev/sdb1
) appelé soit directement à partir d'une règle udev, soit à partir d'un fichier d'unité systemd. Il semble y avoir une condition de concurrence critique et le nœud de périphérique n'est pas tout à fait prêt, ce qui entraîne Error looking up object for device /dev/sdb1
. Malheureusement, car udisks2 pourrait s'occuper de tout le désordre du point de montage ...)
Le gros du travail est effectué par un script Shell, qui prend en charge la création et la suppression de points de montage, ainsi que le montage et le démontage des disques.
/ usr/local/bin/usb-mount.sh
#!/bin/bash
# This script is called from our systemd unit file to mount or unmount
# a USB drive.
usage()
{
echo "Usage: $0 {add|remove} device_name (e.g. sdb1)"
exit 1
}
if [[ $# -ne 2 ]]; then
usage
fi
ACTION=$1
DEVBASE=$2
DEVICE="/dev/${DEVBASE}"
# See if this drive is already mounted, and if so where
MOUNT_POINT=$(/bin/mount | /bin/grep ${DEVICE} | /usr/bin/awk '{ print $3 }')
do_mount()
{
if [[ -n ${MOUNT_POINT} ]]; then
echo "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
exit 1
fi
# Get info for this drive: $ID_FS_LABEL, $ID_FS_UUID, and $ID_FS_TYPE
eval $(/sbin/blkid -o udev ${DEVICE})
# Figure out a mount point to use
LABEL=${ID_FS_LABEL}
if [[ -z "${LABEL}" ]]; then
LABEL=${DEVBASE}
Elif /bin/grep -q " /media/${LABEL} " /etc/mtab; then
# Already in use, make a unique one
LABEL+="-${DEVBASE}"
fi
MOUNT_POINT="/media/${LABEL}"
echo "Mount point: ${MOUNT_POINT}"
/bin/mkdir -p ${MOUNT_POINT}
# Global mount options
OPTS="rw,relatime"
# File system type specific mount options
if [[ ${ID_FS_TYPE} == "vfat" ]]; then
OPTS+=",users,gid=100,umask=000,shortname=mixed,utf8=1,flush"
fi
if ! /bin/mount -o ${OPTS} ${DEVICE} ${MOUNT_POINT}; then
echo "Error mounting ${DEVICE} (status = $?)"
/bin/rmdir ${MOUNT_POINT}
exit 1
fi
echo "**** Mounted ${DEVICE} at ${MOUNT_POINT} ****"
}
do_unmount()
{
if [[ -z ${MOUNT_POINT} ]]; then
echo "Warning: ${DEVICE} is not mounted"
else
/bin/umount -l ${DEVICE}
echo "**** Unmounted ${DEVICE}"
fi
# Delete all empty dirs in /media that aren't being used as mount
# points. This is kind of overkill, but if the drive was unmounted
# prior to removal we no longer know its mount point, and we don't
# want to leave it orphaned...
for f in /media/* ; do
if [[ -n $(/usr/bin/find "$f" -maxdepth 0 -type d -empty) ]]; then
if ! /bin/grep -q " $f " /etc/mtab; then
echo "**** Removing mount point $f"
/bin/rmdir "$f"
fi
fi
done
}
case "${ACTION}" in
add)
do_mount
;;
remove)
do_unmount
;;
*)
usage
;;
esac
Le script, à son tour, est appelé par un fichier d'unité systemd. Nous utilisons la syntaxe de nom de fichier "@" afin de pouvoir passer le nom du périphérique en argument.
/ etc/systemd/system/usb-mount @ .service
[Unit]
Description=Mount USB Drive on %i
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/local/bin/usb-mount.sh add %i
ExecStop=/usr/local/bin/usb-mount.sh remove %i
Enfin, certaines règles udev démarrent et arrêtent le service d'unité systemd sur hotplug/unplug:
/ etc/udev/rules.d/99-local.rules
KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="add", RUN+="/bin/systemctl start usb-mount@%k.service"
KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="remove", RUN+="/bin/systemctl stop usb-mount@%k.service"
Cela semble faire l'affaire! Quelques commandes utiles pour déboguer des trucs comme celui-ci:
udevadm control -l debug
active la journalisation détaillée sur /var/log/syslog
pour voir ce qui se passe.udevadm control --reload-rules
après avoir modifié des fichiers dans le répertoire rules.d (peut ne pas être nécessaire, mais ne peut pas faire de mal ...).systemctl daemon-reload
après avoir modifié les fichiers d'unité systemd.il y a une nouvelle option de montage automatique systemd
succincte qui peut être utilisée avec fstab
qui vous permet d'utiliser toutes les options de permission de montage normalisées, et cela ressemble à ceci:
x-systemd.automount
un exemple de celui-ci dans une ligne fstab
:
/dev/sdd1 /mnt/hitachi-one auto noauto,x-systemd.automount 0 2
l'option noauto
signifie qu'elle ne tentera pas d'être montée au démarrage, comme avec les anciens logiciels autofs
.
après avoir ajouté un nouveau x-systemd.automount
ligne vers fstab
vous devez ensuite exécuter:
Sudo systemctl daemon-reload
puis les deux ou l'un des éléments suivants:
Sudo systemctl restart remote-fs.target
Sudo systemctl restart local-fs.target
pour plus d'informations à ce sujet:
https://wiki.archlinux.org/index.php/Fstab#Automount_with_systemd
J'irais avec la réponse de Warren Young J'ai quelques modifications que j'ai apportées à
J'ai ajouté une protection d'espace car cela donnait des erreurs de l'évaluation de l'environnement pour le lecteur.
J'ai ajouté une section pour chmoder un disque USB afin que tous les utilisateurs aient un accès complet aux disques non ntfs ou vfat.
/usr/local/bin/usb-mount.sh
#!/bin/bash
# This script is called from our systemd unit file to mount or unmount
# a USB drive.
usage()
{
echo "Usage: $0 {add|remove} device_name (e.g. sdb1)"
exit 1
}
if [[ $# -ne 2 ]]; then
usage
fi
ACTION="$1"
DEVBASE="$2"
DEVICE="/dev/${DEVBASE}"
# See if this drive is already mounted, and if so where
MOUNT_POINT=$(/bin/mount | /bin/grep ${DEVICE} | /usr/bin/awk '{ print $3 }')
do_mount()
{
if [[ -n "${MOUNT_POINT}" ]]; then
echo "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
exit 1
fi
# Get info for this drive: $ID_FS_LABEL, $ID_FS_UUID, and $ID_FS_TYPE
# added some sed's to avoid space issues
eval $(/sbin/blkid -o udev ${DEVICE}|sed 's/=/="/'|sed 's/$/"/')
# Figure out a mount point to use
LABEL="${ID_FS_LABEL}"
if [[ -z "${LABEL}" ]]; then
LABEL="${DEVBASE}"
Elif /bin/grep -q " /media/${LABEL} " /etc/mtab; then
# Already in use, make a unique one
LABEL+="-${DEVBASE}"
fi
MOUNT_POINT="/media/${LABEL}"
echo "Mount point: ${MOUNT_POINT}"
/bin/mkdir -p "${MOUNT_POINT}"
# Global mount options
OPTS="rw,relatime"
#added a chmod checker for file systems that don't
#understand allow all to read write
CHMOD=no
# File system type specific mount options
if [[ ${ID_FS_TYPE} == "vfat" ]]; then
OPTS+=",users,gid=100,umask=000,shortname=mixed,utf8=1,flush"
#added options I wanted on ntfs
Elif [[ ${ID_FS_TYPE} == "ntfs" ]]; then
OPTS+=",user,users,umask=000,allow_other"
else
CHMOD=yes
fi
if ! /bin/mount -o "${OPTS}" ${DEVICE} "${MOUNT_POINT}"; then
echo "Error mounting ${DEVICE} (status = $?)"
/bin/rmdir "${MOUNT_POINT}"
exit 1
fi
echo "**** Mounted ${DEVICE} at ${MOUNT_POINT} ****"
if [ "${CHMOD}" = "yes" ];then
/usr/bin/find "${MOUNT_POINT}" -type f -exec chmod 0666 {} \;
/usr/bin/find "${MOUNT_POINT}" -type d -exec chmod 0777 {} \;
fi
}
do_unmount()
{
if [[ -z ${MOUNT_POINT} ]]; then
echo "Warning: ${DEVICE} is not mounted"
else
/bin/umount -l ${DEVICE}
echo "**** Unmounted ${DEVICE}"
fi
# Delete all empty dirs in /media that aren't being used as mount
# points. This is kind of overkill, but if the drive was unmounted
# prior to removal we no longer know its mount point, and we don't
# want to leave it orphaned...
for f in /media/* ; do
if [[ -n $(/usr/bin/find "$f" -maxdepth 0 -type d -empty) ]]; then
if ! /bin/grep -q " $f " /etc/mtab; then
echo "**** Removing mount point $f"
/bin/rmdir "$f"
fi
fi
done
}
case "${ACTION}" in
add)
do_mount
;;
remove)
do_unmount
;;
*)
usage
;;
esac
En utilisant pmount, systemd et l'approche de Mike Blackwell, vous pouvez simplifier le tout:
/ etc/systemd/system/usb-mount @ .service
[Unit]
Description=Mount USB Drive on %i
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/bin/pmount --umask 000 /dev/%i /media/%i
ExecStop=/usr/bin/pumount /dev/%i
/ etc/udev/rules.d/99-usb-mount.rules
ACTION=="add",KERNEL=="sd[a-z][0-9]*",SUBSYSTEMS=="usb",RUN+="/bin/systemctl start usb-mount@%k.service"
ACTION=="remove",KERNEL=="sd[a-z][0-9]*",SUBSYSTEMS=="usb",RUN+="/bin/systemctl stop usb-mount@%k.service"
HTH et merci Mike.
J'ai modifié le script de @MikeBlackwell en:
/dev/sd[a-z]
mais /dev/sd[a-z]*
; souvent le cas avec des serveurs qui ont un plus grand nombre de broches./var/log/usb-mount.track
/var/log/messages
avec tag usb-mount.sh /media/sdd2_usbtest
, /media/sdd2_
Étant donné que @MikeBlackwell a déjà effectué la plupart des travaux lourds, j'ai choisi de ne pas le réécrire; vient de faire les changements nécessaires. J'ai reconnu son travail en voyant son nom et l'URI de la réponse originale.
Trouvez-le sur https://github.com/raamsri/automount-usb