.. _usb-backup: Backup beim Anstecken von USB-Storage ##################################### Ziel: Beim Anstecken eines USB-Speichersticks oder einer externen USB-Festplatte sollen wichtige Daten automatisch auf selbigen Gerät gesichert werden. .. warning:: Aktiviertes Festplattenmonitoring führt bereits zum automatischen Mounten des Backup-Datenträgers! So z.B. durch Collectd; bitte ``systemctl stop collectd`` und ``systemctl disable collectd`` ausführen. Um die Daten tatsächlich nur auf die vorgesehene Ablagefläche zu sichern, ziehen wir als Auslöser der Vorgänge zwei Merkmale heran: a) Seriennummer der Major-Devices Zum Beispiel für /dev/sdb (siehe unten bei ``udevadm info ...``), sie ist in der Hardware fest verankert. b) UUID des Dateisystems Für spätere Mount- und Backupvorgänge sind die Partition eindeutig zu identifizieren, hier soll es das erste Minor-Device /dev/sdb1 sein, siehe dazu die Ausgabe der UUID mittels ``blkid /dev/sdb1``. Diese ID wird zumeist beim Aufbringen des Dateisystems generiert, lässt sich aber mit ``tune2fs`` auch auf Gegebenheiten anpassen. Hardwareerkennung ================= Wir gehen von der Annahme aus, dass der angesteckte USB-Stick vom Kernel als 2. Festplatte erkannt wird und zumindest eine Partition aufweist (/dev/sdb1), die wir später für Backupzwecke benutzen wollen. Daher suchen wir nun zur eindeutigen Hardware-Identifizierung die Seriennummer von */dev/sdb* heraus: .. highlight:: shell-session :: root@host $ udevadm info -a /dev/sdb | grep serial ATTRS{serial}=="18030900014548" ATTRS{serial}=="0000:00:1d.0" root@host $ Die erste ATTRS-Zeile beinhaltet die gesuchte Nummer, auf die wir nachher zurückgreifen werden. Dabei spielt die Option ``-a, --attribute-walk`` eine wichtige Rolle, durch welche die Eigenschaften des Geräts entlang des sysfs ausgegeben werden. Diese Werte können dann direkt in den udev-Regeln Verwendung finden. Udev/Mount auf Unix-Art ======================= = Variante ohne den komplexen System-Daemon **Betriebssystem:** Devuan Linux, Artix Linux, PCLinuxOS oder eine andere Distribution **ohne** Systemd-Startverfahren. Wir erstellen eine neue Datei für die Udev-Regeln und nennen sie ``/etc/udev/rules.d/99-mystorage.rules``. Sie bekommt diesen Inhalt: .. highlight:: bash :: SUBSYSTEMS=="usb", ATTRS{serial}=="18030900014548", KERNEL=="sd[b-z]1", \ SYMLINK+="mystorage", RUN+="/usr/local/bin/bkup.sh" Zum eindeutigen Spezifizieren eines bestimmten Geräts muss es hierbei in zwei Punkten Überstimmung geben: 1. Bezüglich der Elterngeräte (eines von SUBSYSTEMS=, ATTRS=, KERNELS=, ... "S" -> Mehrzahl!) In unserem Falle spezifizieren wir die Hardware mittels: ``ATTRS{serial}=="18030900014548"`` 2. In Bezug auf das Gerät selbst (eines von SUBSYSTEM=, ATTR=, KERNEL=, ...) In unserem Falle filtern wir neue Major-Devices mit *sdb* beginnend sowie die 1. Partition mittels: ``KERNEL=="sd[b-z]1"`` heraus. Wichtig ist hier gerade auch der 2. Punkt: existieren z.B. drei Partitionen auf dem Stick, würde udev ohne dieses KERNEL-Filter das Ereignis gleich drei mal hintereinander auslösen! Siehe dazu auch den kurzen Abschnitt unter http://reactivated.net/writing_udev_rules.html#sysfstree Mit der folgenden Zeile lesen wir die Änderungen ein, womit sich meist das komplette Neustarten des udev-Daemons vermeiden lässt: .. highlight:: shell-session :: root@host $ udevadm control --reload-rules && udevadm trigger Backupskript erstellen ---------------------- Nun benötigen wir noch das Shellskript ``/usr/local/bin/bkup.sh``, das hierbei das Volume direkt mounten kann. Zum Backupskript können wir es z.B. mittels 'rsync' machen (Zeile 4), während die Zeilen 5 und 6 nur zu Testzwecken enthalten sind. Insbesondere 'sleep 30', um den erfolgreichen Mountvorgang in der Datei '/proc/self/mounts' bequem kontrollieren zu können: .. highlight:: bash :linenothreshold: 5 :: #!/bin/sh mount /dev/mystorage /mnt logger -t UDEV-TRIGGERED "Ereignis festgestellt: `df -h /mnt`" #rsync -a ~/Dokumente/ /mnt/MyDokumente.synced/ echo "123, fertig ist das Backup!" > /mnt/123.testdatei-$(date +%F-%H-%M) sleep 30 umount /mnt Das Skript müssen wir natürlich noch ausführbar machen: .. highlight:: shell-session :: root@host $ chmod +x /usr/local/bin/bkup.sh .. _systemd-mount: Udev/Mounting mit Systemd ========================= = Variante mit neuem Linux System Daemon **Betriebssystem:** Debian 10 (oder eine vergleichbare Systemd-Distribution) Wir nennen die Datei für die Udev-Regeln ``/etc/udev/rules.d/99-mystorage.rules`` und befüllen sie folgendermaßen (ACHTUNG: dank dem Backlash wurde die lange Zeile zweimal umgebrochen; danach darf kein Leerzeichen etc. folgen, lediglich ein Newline): .. highlight:: bash :: SUBSYSTEMS=="usb", ATTRS{serial}=="18030900014548", KERNEL=="sd[b-z]1", \ ACTION=="add", ENV{SYSTEMD_WANTS}="mybackup.service", \ SYMLINK+="mystorage", RUN+="/usr/bin/logger BACKUP VIA UDEV TRIGGERED" Mit der folgenden Zeile lesen wir die Änderungen ein, womit sich meist das komplette Neustarten des udev-Daemons vermeiden lässt: .. highlight:: shell-session :: root@host $ udevadm control --reload-rules && udevadm trigger Stick mounten - Variante 1: via /etc/fstab - Automount ------------------------------------------------------ Automounter mit Systemd ^^^^^^^^^^^^^^^^^^^^^^^ Am einfachsten ist es, den Stick mittels des neuen Systemd-Automounters selbständig ein- und auch wieder aushängen zu lassen. Dazu muss nur eine Zeile in die Datei /etc/fstab geschrieben werden, der `systemd-fstab-generator `_ erzeugt daraus live eine *.automount*-Unit. Diese Zeile sieht hierbei folgendermaßen aus (die UUID kann mit ``blkid`` ermittelt werden): .. highlight:: bash :: UUID=7C74-7B5A /media/mystick vfat noauto,x-systemd.automount,x-systemd.device-timeout=10,x-systemd.idle-timeout=30 0 2 Nach dem Hinzufügen dieses Eintrags müssen folgende Kommandos ausgeführt werden, um die Änderung einzulesen (wer auf Nummer sicher gehen möchte: ``systemctl reboot``): .. highlight:: shell-session :: root@host $ systemctl daemon-reload root@host $ systemctl restart local-fs.target remote-fs.target Jetzt erst einmal gründlich testen, ob sich der Stick automatsch ein- und aushängen lässt! Dazu einfach mit ``ls -F /media/mystick`` ins Mountverzeichniss hineinschauen, wobei das Mounten geschehen muss. Das kontrollieren wir am besten mit ``df -h | grep mystick``, alternativ lassen sich die letzten Zeilen der /proc/self/mounts heranziehen. Unit-Datei für Backupservice (fstab-automount) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Nun erzeugen wir uns eine eigene Systemd Unit Datei, die später das Backupskript starten wird. Die Datei definiert lediglich, welches Skript auszuführen ist ("ExecStart=") und welches Abhängigkeitsverhältnis beim abschließenden *systemctl enable...* zu beachten ist ("WantedBy="). Wir nennen die Datei ``/etc/systemd/system/mybackup.service`` und geben ihr folgenden Inhalt: .. highlight:: ini :: [Unit] Description=Make Backup via /etc/fstab and Automount [Service] ExecStart=/home/tux/bin/mybackup [Install] WantedBy=media-mystick.automount Abschließend müssen wir noch den Mountpunkt anlegen und den Service aktivieren: .. highlight:: shell-session :: root@host $ mkdir /media/mystick root@host $ systemctl enable mybackup.service Stick mounten - Variante 2: via separater Mount-Units ----------------------------------------------------- Anstelle den einfacheren Weg über den systemd-fstab-generator zu gehen, können wir manuell zwei Dateien anlegen, die das Ganze besser spezifizieren. Prinzipiell muss zuerst einmal eine passende, normale '.mount' Unit-Datei existieren; aus ``man systemd.automount``: *"For each automount unit file a matching mount unit file (see systemd.mount(5) for details) must exist..."* Mount-Unit ^^^^^^^^^^ Zuerst legen wir also eine neue Datei namens ``/etc/systemd/system/media-mystick.mount`` an. Sie bekommt nachfolgenden Inhalt, wobei zu beachten ist, dass der Präfix ('media-mystick') im Dateinamen 'media-mystick.mount' dem späteren Mountpunkt-Pfad '/media/mystick' entsprechen muss. Im Dateinamen ist also der Name des Mountverzeichnisses verankert; das Dateinamenssuffix '.mount' spielt für den Mountpunkt keine Rolle, wohl aber für den Unit-Typ: .. highlight:: ini :: [Unit] Description=Additional drive After=local-fs.target [Mount] What=UUID=7C74-7B5A Where=/media/mystick Type=vfat Options=defaults [Install] WantedBy=multi-user.target Natürlich muss das erwähnte Mountpunktverzeichnis /media/mystick gemäß des Dateinamens 'media-mystick.mount' existieren, außerdem müssen wir diese Unit noch mit ``systemctl enable media-mystick.mount`` aktivieren. Ein manuelles Starten ist nicht notwendig - das Volume wird ja beim udev-Ereignis "USB-Stick wurde angesteckt" automatisch gemountet. Automount-Unit ^^^^^^^^^^^^^^ Nun wollen wir aber auch, dass der Stick nach dem Backup wieder automatisch ausgehängt wird. Das bedeutet, dass Systemd das Gerät überwachen muss, ob es noch in Benutzung ist oder nicht. Falls keine Prozesse mehr vorhanden sind, wird ein "umount" versucht. Dazu benötigen wir aber zusätzlich eine .automount-Unitdatei namens ``/etc/systemd/system/media-mystick.automount``, die wir nun erzeugen und wie folgt befüllen: :: [Unit] Description=Automount additional drive [Automount] Where=/media/mystick TimeoutIdleSec=7s [Install] WantedBy=multi-user.target Diese Datei muss ebenso wie obige Mount-Unitdatei heißen, nur mit dem Unterschied, dass der Dateisuffix nicht ``.mount`` sondern ``.automount`` lautet. Das Präfix "media-mystick" muss mit dem Verzeichnispfad für den Mountpunkt "/media/mystick" korrespondieren, der Pfad wird aber zusätzlich nochmal bei ``Where=/media/mystick`` angegeben. Diese neue Automount-Unit ist ein echter Service und muss nicht nur aktiviert, sondern auch gestartet werden: .. highlight:: shell-session :: root@host $ systemctl enable media-mystick.automount root@host $ systemctl start media-mystick.automount Falls etwas in den Unit-Files geändert werden muss, bitte nicht vergessen ``systemctl daemon-reload`` auszuführen! Dadurch werden die vorherigen Konfigurationen, die von Generatoren stammen, verworfen und neu erzeugt. Nun geht es wieder ans testen, aber VORSICHT: Das Monitoring mit ``watch -n1 -d ls -l /media/mystick/`` hält den Stick im gemounteten Zustand! Besser ist, das Ganze mit ``df -h | grep mystick`` anzugehen. Unit-Datei für Backupservice (mount, automount unit) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Nun erzeugen wir uns eine Systemd Unit Datei, die später das Backupskript starten wird. Dabei muss hier allerdings "Requires" und "After" im Unit-Abschnitt verwendet werden, weil dieser Service auf die funktionierende, separate Mount-Unit angewiesen ist: Der neu anzulegenden Datei ``/etc/systemd/system/mybackup.service`` geben wir folgenden Inhalt: .. highlight:: ini :: [Unit] Description=Make Backup via mount and automount unit files Requires=media-mystick.mount After=media-mystick.mount [Service] ExecStart=/usr/local/bin/bkup-systemd.sh [Install] WantedBy=media-mystick.mount Abschließend müssen wir noch den Mountpunkt anlegen und den Service aktivieren: .. highlight:: shell-session :: root@host $ mkdir /media/mystick root@host $ systemctl enable mybackup.service Backupskript erstellen ^^^^^^^^^^^^^^^^^^^^^^ Zum Schluss benötigen wir wieder ein Backupskript, was jetzt allerdings keine Mountaufgaben mehr wahrnehmen kann. Wir erzeugen dazu eine neue Datei namens ``/usr/local/bin/bkup-systemd.sh`` und befüllen sie folgendermaßen: .. highlight:: bash :linenothreshold: 5 :: #!/bin/sh logger -t UDEV-TRIGGERED "Ereignis festgestellt: `grep '/media/mystick' /proc/self/mounts`" #rsync -a ~/Dokumente/ /media/mystick/MyDokumente.synced/ echo "123, fertig ist das Backup!" > /media/mystick/123.testdatei-$(date +%F-%H-%M) Das Skript müssen wir schließlich wieder ausführbar machen: .. highlight:: shell-session :: root@host $ chmod +x /usr/local/bin/bkup-systemd.sh Inbetriebnahme/Tests ==================== ACHTUNG: Falls collectd mit den Standard Plugins läuft, löst er in einer Endlosschleife immer wieder das das automatische Mounten aus! Genauso kann ein laufender Nagios-Daemon Probleme bereiten! Außerdem ist es ratsam, das Hauptlog im Auge zu behalten, hier einfach mittels ``journalctl -f``. Weitere Tipps: 1) Stets den Stick sauber aus der VM lösen (via VirtualBox unter "Geräte", "USB", ...) 2) Zum Testen/Triggern den Stick einfach wieder per selbigen Menü hineinreichen. 3) Notfalls nach Schritt 1 den USB-Stick richtig herausziehen, danach wieder hineinreichen. 4) Bitte Aufpassen, dass die grafischen Dateimanager nicht schon den Stick mounten, am besten: 'init 3'; wer PCManFM verwendet, kann unter "Bearbeiten", "Einstellungen", "Dateinträgerverwaltung" das automatische Mounten deaktivieren. Halten wir fest: - Es braucht nicht immer den Aufwand mit zwei Dateien: * /etc/systemd/system/media-mystick.mount * /etc/systemd/system/media-mystick.automount - ... alternativ reicht eine Zeile in der /etc/fstab mit ``noauto,x-systemd.automount,...`` - Leider greift in diesem Zusammenhang die Option 'noauto' nicht: Wenn der Stick beim Booten angesteckt ist, wird bereits das Backupskript getriggert (=> "man systemd.automount"). Zusammenfassung =============== Für die Variante mit Systemd und der separaten Mount-Unitdatei hier noch einmal alle beteiligten Dateien und Kommandos im Überblick: 1. Hardwareerkennung durch Udev, getriggert wird aufgrund des USB-Subsystems, der Seriennummer und der 1. Partition des Geräts: :: root@d10:~# cat /etc/udev/rules.d/99-mystorage.rules ### Dies ist Hook number one: ATTRS{serial}=="18030900014548" SUBSYSTEMS=="usb", ATTRS{serial}=="18030900014548", KERNEL=="sd[b-z]1", \ ACTION=="add", ENV{SYSTEMD_WANTS}="mybackup.service", \ SYMLINK+="mystorage", RUN+="/usr/bin/logger BACKUP VIA UDEV TRIGGERED" root@d10:~# 2. Das Backup-Skript (ohne systemd ist dies direkt via Udev's ``RUN+="/usr/local/bin/bkup.sh`` möglich): :: root@d10:~# cat /home/tux/bin/mybackup #!/bin/sh logger -t UDEV-TRIGGERED "Ereignis festgestellt: `grep '/media/mystick' /proc/self/mounts`" #rsync -a ~/Dokumente/ /media/mystick/MyDokumente.synced/ echo "123, fertig ist das Backup!" > /media/mystick/123.testdatei-$(date +%F-%H-%M) 3. Wegen Systemd müssen wir aber in der Udev-Regeldatei ``ENV{SYSTEMD_WANTS}="mybackup.service"`` verwenden und diese Datei erzeugen: :: root@d10:~# cat /etc/systemd/system/mybackup.service [Unit] Description=Make Backup via Mount- und Automount-Units Requires=media-mystick.mount After=media-mystick.mount [Service] ExecStart=/home/tux/bin/mybackup [Install] WantedBy=media-mystick.mount root@d10:~# 4. Die erforderliche Mountunit, was wir soeben unter 3.) gesehen haben (``Requires=media-mystick.mount``): :: root@d10:~# cat /etc/systemd/system/media-mystick.mount [Unit] Description=Additional drive [Mount] What=UUID=7C74-7B5A Where=/media/mystick Type=vfat Options=defaults [Install] WantedBy=multi-user.target root@d10:~# 5. Die Automount-Unit, die wir nur für das automatische Aushängen nach 7 Sekunden benötigen: :: root@d10:~# cat /etc/systemd/system/media-mystick.automount [Unit] Description=Automount additional drive [Automount] Where=/media/mystick TimeoutIdleSec=7s [Install] WantedBy=multi-user.target root@d10:~# Kommandos zum aktivieren, deaktivieren, starten und stoppen: :: systemctl stop collectd systemctl disable collectd udevadm control --reload-rules && udevadm trigger systemctl enable mybackup.service systemctl enable media-mystick.mount systemctl enable media-mystick.automount systemctl start media-mystick.automount Und nicht vergessen, ``systemctl daemon-reload`` auszuführen, falls etwas in den Unit-Files geändert werden musste! Weitere Links ============= - https://www.linux-community.de/ausgaben/linuxuser/2019/05/unsichtbarer-helfer/ - http://reactivated.net/writing_udev_rules.html - https://dev.to/adarshkkumar/mount-a-volume-using-systemd-1h2f - https://coreos.com/os/docs/latest/using-systemd-and-udev-rules.html - http://jasonwryan.com/blog/2014/01/20/udev/