Unità USB con montaggio automatico con systemd


27

Stiamo aggiornando i nostri server da una distribuzione molto obsoleta a un moderno sistema basato su Debian Jessie, inclusi lightdm / xfce e ovviamente systemd (e udisks2). Un punto critico è il montaggio automatico delle unità USB. Ci riuscivamo con alcune regole udev. Le vecchie regole funzionano quasi ancora: il punto di montaggio viene creato e l'unità viene montata correttamente, ma dopo alcuni secondi systemd sta facendo qualcosa che interrompe il montaggio, quindi i successivi tentativi di accesso provocano errori "L'endpoint di trasporto non è collegato".

Il montaggio manuale dell'unità tramite la riga di comando funziona correttamente. Anche lasciare un file manager (thunar e thunar-volman, che a sua volta usa udisks2). Ma quelle non sono opzioni praticabili: questi sistemi funzionano principalmente senza testa, quindi Thunar non è normalmente in esecuzione. Dobbiamo essere in grado di collegare unità disco per backup cron automatici non presidiati.

Ho pensato che modificare lo script udev per generare un lavoro distaccato che attende alcuni secondi prima di eseguire il mount potrebbe fare il trucco, ma systemd sembra fare di tutto per impedirlo - in qualche modo attende ancora che il lavoro distaccato finisca prima continuando.

Forse avere lo script udev solleticare udisks2 è in qualche modo l'approccio giusto? Sono in perdita, quindi ogni consiglio è molto apprezzato.


1
Correlati solo tangenzialmente, ma ... Stai mettendo xfce su un server?
Parthian Shot

Ah, ho usato il termine "server" piuttosto vagamente ... Tutte le interazioni dell'utente con il sistema avvengono tramite un'app Web, in genere accessibile tramite un browser in rete. Ma alcuni clienti preferiscono una soluzione non di rete, quindi eseguiamo Chrome sulla console in una sorta di modalità kiosk. (Questo è utile anche per il debug dei problemi di configurazione della rete, è possibile collegare un monitor / mouse / tastiera e accedere agli strumenti diagnostici di base nell'app Web senza bisogno di credenziali di accesso a Linux). Probabilmente esiste una soluzione più leggera rispetto a lightdm / xfce, ma questa è stata la più semplice da configurare ...
Mike Blackwell

Per chiunque desideri regole di systemd-udevd che eseguono direttamente uno script: ho avuto questo; ha funzionato per un po ', ma a un certo punto ha smesso di eseguire lo script se udevd era stato avviato automaticamente. Stop e riavvio dalla riga di comando, e andrebbe bene. Inoltre, non ha mai funzionato bene con NTFS + FUSE perché udev ha rilevato un processo figlio di lunga durata (ntfs-3g) e lo ha ucciso dopo gli anni '60. In conclusione: le regole di udev che eseguono direttamente uno script sono una perdita di tempo. Utilizza invece le regole udev e un servizio systemd, come indicato nelle risposte. Quindi non devi nemmeno occuparti degli spazi dei nomi (MountFlags = slave).
Segna il

Ho avuto un problema simile con uno script avviato da udev che non era in grado di stabilire connessioni di rete. La soluzione di seguito dell'utilizzo di systemd ha funzionato anche per questo - grazie!
Quentin Stafford-Fraser,

Risposte:


28

Dopo diverse false partenze l'ho capito. La chiave è aggiungere un servizio di unità di sistema tra udev e uno script di montaggio.

(Per la cronaca, non sono stato in grado di farlo funzionare usando udisks2 (tramite qualcosa di simile udisksctl mount -b /dev/sdb1) chiamato direttamente da una regola udev o da un file di unità di sistema. Sembra che ci sia una condizione di competizione e il nodo del dispositivo non è del tutto pronto , risultante Error looking up object for device /dev/sdb1. Sfortunato, poiché udisks2 potrebbe occuparsi di tutto il disordine dei mount point ...)

Il pesante sollevamento viene eseguito da uno script della shell, che si occupa della creazione e rimozione dei punti di montaggio, nonché del montaggio e dello smontaggio delle unità.

/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

Lo script, a sua volta, viene chiamato da un file di unità systemd. Usiamo la sintassi del nome file "@" in modo da poter passare il nome del dispositivo come argomento.

/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

Infine, alcune regole udev avviano e interrompono il servizio dell'unità systemd su 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"

Questo sembra fare il trucco! Un paio di comandi utili per il debug di cose come questa:

  • udevadm control -l debugattiva la registrazione dettagliata in /var/log/syslogmodo da poter vedere cosa sta succedendo.
  • udevadm control --reload-rules dopo aver modificato i file nella directory rules.d (potrebbe non essere necessario, ma non può far male ...).
  • systemctl daemon-reload dopo aver modificato i file di unità di sistema.

4
Wow. Questo e spettacolare. Vorrei poter dare più voti! L'unica cosa che ho dovuto modificare era che sul mio sistema, blkidnon sembra estrarre un ID_FS_LABEL, quindi ho usato solo DEVBASEinvece di LABELcostruire MOUNT_POINTinvece.
Travis Griggs,

Questa configurazione può essere modificata per funzionare con dispositivi ATA / SCSI? Vedi: serverfault.com/q/825779/297059
user339676

@Travis - Puoi usare udevadminvece di blkid. Fornisce molti più dettagli e informazioni aggiuntive. (ad es. udevadm info --query=property --name=sda1)
user339676

questo non funziona bene all'avvio, se un dispositivo USB è già collegato. Qualche idea?
Michal Artazov,

Quando nullglobs non sono impostati, allo smontaggio, la pulizia può generare un errore simile /usr/bin/find: '/media/*': No such file or directory. La pulizia può utilizzare un controllo aggiuntivo come if [ "$f" != "/media/*" ]; thenprima di eseguire find.
Pro Backup il

12

esiste una nuova systemdopzione di montaggio automatico concisa che può essere utilizzata con la fstabquale consente di utilizzare tutte le opzioni di autorizzazione per il montaggio standardizzate e si presenta così:

  x-systemd.automount

un esempio in una fstabriga:

  /dev/sdd1   /mnt/hitachi-one     auto     noauto,x-systemd.automount     0 2

l' noautoopzione significherà che non tenterà di essere montata all'avvio, come con un software precedente autofs.

dopo aver aggiunto una nuova x-systemd.automountriga a fstabte, devi eseguire:

  sudo systemctl daemon-reload

e poi entrambi, o uno dei seguenti:

  sudo systemctl restart remote-fs.target
  sudo systemctl restart local-fs.target

per maggiori informazioni a riguardo:

https://wiki.archlinux.org/index.php/Fstab#Automount_with_systemd


sudo systemctl restart local-fs.targetha fatto il trucco per me
Philippe Gachoud il

2

Ho modificato lo script da @MikeBlackwell a:

  • riconoscere i nomi dei dispositivi che si estendono su più caratteri, non solo /dev/sd[a-z]ma /dev/sd[a-z]*; spesso nel caso di server con un numero maggiore di mandrini.
  • traccia l'elenco delle unità montate automaticamente su /var/log/usb-mount.track
  • registra le azioni /var/log/messagescon il tag usb-mount.sh
  • prefisso del nome del dispositivo con l'etichetta del dispositivo per il punto di non correre in problemi con unità che non sono stati assegnati un'etichetta montare (vuoto?): /media/sdd2_usbtest,/media/sdd2_
  • script wrapper inclusi per posizionare i file in modo appropriato e, se necessario, annullarli

Poiché @MikeBlackwell ha già eseguito la maggior parte del sollevamento pesante, ho scelto di non riscriverlo; appena apportato le modifiche necessarie. Ho riconosciuto il suo lavoro avvistando il suo nome e URI della risposta originale.

Lo trovi su https://github.com/raamsri/automount-usb


2

Utilizzando l' approccio di pmount , systemd e Mike Blackwell, puoi semplificare il tutto:

/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 e grazie Mike.


0

Andrei con la risposta di Warren Young. Ho apportato alcune modifiche

Ho aggiunto un po 'di protezione dello spazio in quanto stava dando errori dal valutazione dell'ambiente per l'unità.

Ho aggiunto una sezione per chmod un disco USB in modo che tutti gli utenti abbiano pieno accesso ai dischi non ntfs o 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

Potresti descrivere in poche parole ciò che è diverso tra la risposta originale e la tua, per renderla più utile. PS: nessuna risposta da parte di Warren Young; forse intendevi la risposta di Mike Blackwell che è stata modificata?
Amir
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.