Automounting δίσκων με udev και systemd

Τι είναι το automount και γιατί το θέλω;

Το automount είναι ένα σημείο προσάρτησης στην ιεραρχία των δίσκων που υπάρχει μόνο όσο χρειάζεται. Η χρήση του είναι κυρίως για δικτυακούς δίσκους, αλλά είναι χρήσιμο και για στικάκια. Αν τραβάς το δισκάκι χωρίς να το αφαιρέσεις οι πιθανότητες είναι να μην είναι προσαρτημένο οπότε δεν θα γίνει ζημία. Αν μιλάμε για εξωτερικό δίσκο δεν υπάρχει λόγος αυτός να καταναλώνει ρεύμα κάτι που έχει νόημα σε κάποιες περιπτώσεις χρήσης.

Αλλά υπάρχουν και μειονεκτήματα. Το γραφικό περιβάλλον δεν έχει κάποιο τρόπο να ξέρει αν υπάρχει μια συσκευή ή όχι, θα το δει σαν να είναι μέρος του “κανονικού” συστήματος αρχείων.

Υπάρχουν διάφοροι τρόποι να το κάνεις αυτό, αλλά ο ευκολότερος είναι με την βοήθεια του systemd σε συνδυασμό με ένα υποσύστημα του, το udev. Αυτό που μου αρέσει είναι η καθαρότητα και η διαχειρησιμότητα της λύσης, καθώς και ο αυτόματος έλεγχος με το fsck. Ένα σημαντικό bonus για να είναι πάντα εμβολιασμένος ο δίσκος ή το στικάκι :yum:.

Τα συστατικά

  • Το udev περιέχει κανόνες για το τι θα συμβεί όταν μια συσκευή αποσυνδεθεί η αποσυνδεθεί από το σύστημα. Κανονικά αναλαμβάνει το udisks2 που προσαρμόζει το στικάκι κάπου στην διαδρομή /media/$SER.
    H μεγάλη δυσκολία είναι να βρείς τις σωστές προϋποθέσεις για τον κανόνα, αλλά αυτό δεν είναι ένας οδηγός για το udev. Επιλέχθηκε η απλή λύση να βλέπεις το uuid του δίσκου, όπως το βρίσκεις με την εντολή lsblk. Θα δουλέψει έτσι ανεξάρτητα του τρόπου σύνδεσης της συσκευής.

  • Η εντολή systesmd-mount systemd-mount(1). Επιλέχθηκε γιατί φτιάχνει προσωρινά (transient) systemd units που υπάρχουν μόνον όσο η συσκευή παραμένει συνδεμένη. Μπορείς να τα χειριστείς κατά τα άλλα σαν να ήταν μόνιμα. Πλεονέκτημα είναι πως δεν θα κάτσεις να τα γράψεις με το χέρι καθώς και ο αυτόματος έλεγχος ακεραιότητας του συστήματος αρχείων. Αυτό είναι λίγο σπαστικό όταν έχεις btrfs καθώς παίρνει χρόνο, οπότε είναι απαραίτητο να δώσουμε λίγο χρόνο –timeout-idle-sec=10sec αντί για του προκαθορισμένου του μόλις 1sec. Εναλλακτικά μπορούμε να προσθέσουμε --fsck=fasle και να τσεκάρουμε την ακεραιότητα με το χέρι.

  • Μια δικιά μας εντολή για που θα καλεί το udev και που με την σειρά της θα καλεί την systemd-mount. Αυτή θα μπορούσε να λείπει αλλά χρήσιμη για να κάνουμε unmount την συσκευή με το χέρι. Τεχνικά έτσι όπως έχει δομηθεί το unmount θα το κάνει το systemd και όχι το udev (αυτό κάνει το –bind-device) οπότε δεν είναι καθόλου απαραίτητος κάποιος μηχανισμός αποσύνδεσης, αλλά δεν βλάπτει.

  • Ένα αρχείο εγκατάστασης των παραπάνω, που θα βάλει το σωστό uuid και θα μεταφέρει τα πάντα στις σωστές θέσεις. Δεν μπήκα στον κόπο να βάλω μεταβλητό και το σημείο προσάρτησης, αλλάξτε το με το χέρι. Υπάρχουν και κάποια άλλα στην πλήρη λύση που κάνει αυτοματοποιημένο backup, ίσως παρουσιαστούν κάποια άλλην μέρα.

Τα αρχεία

1. 99-backup.rules

# Add action
ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", \
ENV{ID_FS_UUID}=="$UUID”", \
ENV{UDISKS_IGNORE}="1", \
RUN+="/usr/local/bin/backup-mnt-helper ON $devnode"

# Remove action
ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", \
ENV{ID_FS_UUID}=="$UUID”", \
ENV{UDISKS_IGNORE}="1", \
RUN+="/usr/local/bin/backup-mnt-helper OFF $devnode"

2. Install.sh

#! /usr/bin/env bash
export UUID="cdc229cc-37d2-4d77-b3f9-4ca4fa0bab57"
export WHERE="/mnt/backup"


export SYSTEMD_PAGER=
RED="\e[31m"
GREEN="\e[32m"
NC="\e[0m"

if [[ $EUID -ne 0 ]]; then
   echo -e "${RED}This script must be run as root${NC}"
   exit 1
fi

echo -e "\n${GREEN}** Installing udevadm rules${NC}"
# Hack for envsubst
export devnode='$devnode'
envsubst < 99-backup.rules > /etc/udev/rules.d/99-backup.rules 
udevadm control –reload
cat /etc/udev/rules.d/99-backup.rules 

cp backup-mnt-helper /usr/local/bin/backup-mnt-helper
chmod +x /usr/local/bin/backup-mnt-helper

service_prefix="$(/usr/bin/systemd-escape –path "$WHERE")"
systemctl list-units –all -t mount,automount  "${service_prefix}*" | sed '/^$/q'

3. backup-mnt-helper

#! /usr/bin/env bash
action="$1"
device="$2"

WHERE="/mnt/backup"


function do_mount() {
    local devnode="$1"
    /usr/bin/systemd-cat –identifier="backup-mnt-helper" –priority=info echo "Mounting device $devnode => $WHERE"
    /usr/bin/systemd-mount –automount=true  –timeout-idle-sec=10sec –bind-device –description="Backup Disk" "$devnode" "$WHERE"
}

function do_unmount() {
    local devnode=”$1”
    /usr/bin/systemd-cat –identifier="backup-mnt-helper" –priority=info echo "Un-mounting device $devnode from $WHERE"
    /usr/bin/systemd-mount –unmount "$WHERE"
}

case $action in
    ON|on)
        do_mount "$device"
        ;;
    OFF|off) 
        do_unmount "$device"
        ;;
esac