Backup bei Anschluss des USB-Laufwerks

von Markus Berger am Mittwoch, 23. August 2023

Einleitung

Da moderne Laptops oft keine Netzwerk-Buchse mehr haben und die WLAN Verbindung meist langsamer als einen Kabelverbindung ist, man aber doch ein Backup zügig durch führen möchte, bietet es sich an hierfür eine Wechseldatenträger via USB zu verwenden. Weiterhin wäre es natürlich sehr schön wenn man dies nicht noch explizit anstoßen muss. Mit ein wenig Skripting und der passenden udev-Regel ist das einfach möglich.

Vorbereitung

Um den Vorgang nur bei den richtigen Datenträger auszulösen kann man die idVendor und idProduct Nummern des Backuplaufwerks nutzen. Ein Eintrag in /etc/udev/rules.d/test_backup.rules mit folgendem Inhalt:

ATTRS{idVendor}=="152d", ATTRS{idProduct}=="3234", KERNEL=="sd*", RUN+="/usr/local/bin/bktest.sh"

wobei die Werte z.B. mit lsusb ermittelt werden können, ein dazu passendes Skript aus. Das Skript selbst schreibt das neue Gerät in eine FiFo-Datei, so das andere ohne zu pollen davon erfahren können.

Hier ein Beispiel:

#!/bin/sh

if [ "${ACTION}" = add -a -d "/sys${DEVPATH}" ]; then
    date > /tmp/usbdev.log
    if [ -p "/tmp/usbdev" ]; then
        echo "${DEVPATH}" | awk -F'block' '{print $2}' | awk -F'/' '{print "connected /dev/"$3}' >> /tmp/usbdev
    else
        echo "pipe not found" > /tmp/usbdev.log
    fi
    echo "${DEVPATH}" | awk -F'block' '{print $2}' | awk -F'/' '{print "connected /dev/"$3}' >> /tmp/usbdev.log
fi

Dabei muss die FiFo-Datei dem lesenden Nutzer gehören.

Das Script was dann das eigentliche Backup durchführt erstellt die FiFo-Datei und wartet dort auf Nachrichten.

Hier ein Beispiel mit restic als normaler Nutzer.

#!/bin/bash

backup()
{
    REPO="$1/rbk"
    export RESTIC_REPOSITORY="$REPO"
    if [ ! -d "$REPO" ]; then
        echo "$REPO not found" >&2
        return 1
    else
        echo mkdir -p "$REPO"
        # restic init
    fi
    restic forget --keep-last 365 --prune
    restic -q backup --exclude={$HOME/.cache} --one-file-system $HOME
    restic stats
    echo "done"
    logger "backup for $USER done"
}

trap "rm -f /tmp/usbdev" EXIT


if [ ! -p /tmp/usbdev ]; then
     mkfifo /tmp/usbdev
fi

echo "start waching"
if [ -z "$RESTIC_PASSWORD" ]; then
    RESTIC_PASSWORD=$(pass path/to/your/password)
    export RESTIC_PASSWORD
fi

while true; do
    if read -r line < /tmp/usbdev; then
        if echo "$line" | grep "connected" | grep "sd" > /dev/null; then
            USB="${line//connected /}"
            M="${USB//\/dev/\/media/}"
            if [ -f "$M" ] && echo "$USB" | grep -v "1" > /dev/null; then
                echo "ignore $USB" >&2
            else
                pmount "$USB"
                backup "$M" || echo "please check your setup"
                pumount "$USB"
            fi
        fi
    fi
done

Durch ausführen dies Skripts im Hintergrund, z.B. beim starten der grafischen Oberfläche, wird ein Backup durchgeführt, sobald der passende Datenträger verfügbar ist.

Anmerkung

Die externe Platten muss nicht wie sonst üblich verschlüsselt sein, denn die Daten werden durch restic selbst verschlüsselt.

Anmerkung 2

Bei USB-Adaptern wird nur der Adapter selbst eindeutig erkannt, nicht aber die die daran angeschlossene Platte. Durch einen Test z.B. auf eine bestimmte Datei und/oder deren Inhalt kann die notwendige Aktion darüber gesteuert werden.

Anmerkung 3

Um ein Sytem-Backup als normaler Nutzer durchführen zu können, gibt es unter systembackup eine Anleitung.

Der entscheidende Punkt ist hier die Anwendung vom setcap cap_dac_read_search=+ep, dabei ist aber zu beachten, das die erzeugten Dateien im Backup-Repo dem normalen User gehören.