alpinux.presentations/slides/sauvegardes/script/installer.sh
Cédrix a04a72054a
Ajouter la sauvegarde automatique sur clé USB
Dès qu'on branche la clé déclarée (reconnue par son UUID), udev demande
à systemd de lancer une sauvegarde rsync des dossiers choisis. Ce qui a
disparu de l'ordinateur est retiré de la clé, mais conservé 30 jours dans
une corbeille datée sur la clé. Notifications de bureau, journal systemd,
garde-fous contre une destination erronée. Installateur, tests sans sudo
et mode d'emploi fournis.

Refs #1
2026-11-05 17:44:54 +01:00

208 lines
8.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# =============================================================================
# installer.sh — installe (ou désinstalle) la sauvegarde automatique sur clé
# -----------------------------------------------------------------------------
# Utilisation, depuis ce dossier :
# sudo ./installer.sh installation (questions posées)
# sudo ./installer.sh --uuid E234-70AF --utilisateur marie
# installation sans questions
# sudo ./installer.sh --desinstaller tout retirer (la clé n'est pas touchée)
#
# On peut le relancer autant de fois que l'on veut (changer de clé, mettre
# à jour le script) : les réglages personnels de la configuration existante
# sont conservés, seuls l'UUID et l'utilisateur sont mis à jour.
# =============================================================================
set -euo pipefail
export LC_ALL=C.UTF-8
ICI="$(cd "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT_CIBLE="/usr/local/sbin/sauvegarde-cle-usb"
SERVICE_CIBLE="/etc/systemd/system/sauvegarde-cle-usb.service"
REGLE_CIBLE="/etc/udev/rules.d/99-sauvegarde-cle-usb.rules"
CONF_CIBLE="/etc/sauvegarde-cle-usb.conf"
UUID_CHOISI=""
UTILISATEUR_CHOISI=""
ACTION="installer"
erreur() { printf 'ERREUR : %s\n' "$*" >&2; exit 1; }
titre() { printf '\n== %s ==\n' "$*"; }
aide() {
sed -n '4,13p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
}
while [[ $# -gt 0 ]]; do
case "$1" in
--desinstaller|--désinstaller) ACTION="desinstaller" ;;
--uuid) UUID_CHOISI="${2:-}"; shift ;;
--utilisateur) UTILISATEUR_CHOISI="${2:-}"; shift ;;
--aide|--help|-h) aide; exit 0 ;;
*) aide >&2; erreur "option inconnue : $1" ;;
esac
shift
done
[[ "$(id -u)" -eq 0 ]] || erreur "lancez ce programme avec sudo : sudo $0"
recharger() {
systemctl daemon-reload
udevadm control --reload-rules
}
# -----------------------------------------------------------------------------
# Désinstallation
# -----------------------------------------------------------------------------
if [[ "$ACTION" == "desinstaller" ]]; then
titre "Désinstallation"
systemctl stop sauvegarde-cle-usb.service 2>/dev/null || true
for f in "$REGLE_CIBLE" "$SERVICE_CIBLE" "$SCRIPT_CIBLE" "$CONF_CIBLE"; do
if [[ -e "$f" ]]; then
rm -f -- "$f"
echo "Supprimé : $f"
fi
done
recharger
echo
echo "La sauvegarde automatique est désinstallée."
echo "Les copies déjà présentes sur la clé n'ont pas été touchées."
exit 0
fi
# -----------------------------------------------------------------------------
# Vérifications préalables
# -----------------------------------------------------------------------------
for f in sauvegarde-cle-usb sauvegarde-cle-usb.conf sauvegarde-cle-usb.service 99-sauvegarde-cle-usb.rules.modele; do
[[ -f "$ICI/$f" ]] || erreur "fichier manquant à côté de installer.sh : $f"
done
command -v rsync >/dev/null || erreur "rsync n'est pas installé : sudo apt install rsync"
command -v notify-send >/dev/null || echo "Remarque : notify-send absent (sudo apt install libnotify-bin) : pas de notifications."
# -----------------------------------------------------------------------------
# Choix de la clé
# -----------------------------------------------------------------------------
# Une partition est candidate si elle a un UUID et si elle est (directement ou
# non, ex. clé chiffrée déverrouillée) sur un périphérique USB.
lister_candidats() {
local nom type uuid fstype
while read -r nom type uuid fstype; do
[[ -n "$uuid" && -n "$fstype" ]] || continue
case "$type" in part|disk|crypt) ;; *) continue ;; esac
lsblk -nso TRAN "$nom" 2>/dev/null | grep -qx usb || continue
printf '%s %s %s\n' "$nom" "$uuid" "$fstype"
done < <(lsblk -rnpo NAME,TYPE,UUID,FSTYPE)
}
if [[ -z "$UUID_CHOISI" ]]; then
titre "Choix de la clé de sauvegarde"
echo "Branchez la clé à utiliser (et, si elle est chiffrée, déverrouillez-la"
echo "dans le gestionnaire de fichiers), puis appuyez sur Entrée."
read -r _
mapfile -t CANDIDATS < <(lister_candidats)
[[ "${#CANDIDATS[@]}" -gt 0 ]] || erreur "aucune clé USB trouvée. Est-elle bien branchée ?"
echo "Clés USB trouvées :"
echo
i=0
for c in "${CANDIDATS[@]}"; do
i=$((i + 1))
read -r nom _ _ <<<"$c"
printf ' [%d] ' "$i"
lsblk -dno NAME,LABEL,UUID,FSTYPE,SIZE "$nom" | head -n1
done
echo
echo "(Colonnes : nom, étiquette, UUID, système de fichiers, taille)"
echo "Pour comparer : lsblk -o NAME,LABEL,UUID,FSTYPE,SIZE,TRAN"
read -r -p "Numéro de la clé de sauvegarde : " num
[[ "$num" =~ ^[0-9]+$ && "$num" -ge 1 && "$num" -le "${#CANDIDATS[@]}" ]] || erreur "choix invalide."
read -r _ UUID_CHOISI fstype <<<"${CANDIDATS[$((num - 1))]}"
else
periph="$(blkid -U "$UUID_CHOISI" 2>/dev/null || true)"
if [[ -n "$periph" ]]; then
fstype="$(blkid -o value -s TYPE "$periph" 2>/dev/null || true)"
else
fstype=""
echo "Attention : aucune partition d'UUID $UUID_CHOISI n'est branchée actuellement."
fi
fi
[[ "$UUID_CHOISI" =~ ^[A-Za-z0-9-]+$ ]] || erreur "UUID invalide : $UUID_CHOISI"
periph="$(blkid -U "$UUID_CHOISI" 2>/dev/null || true)"
if [[ -n "$periph" && "$(lsblk -dno TYPE "$periph" 2>/dev/null)" == "crypt" ]]; then
echo "Clé chiffrée : le démarrage automatique n'est pas garanti après le"
echo "déverrouillage. Lancez alors la sauvegarde avec :"
echo " sudo systemctl start sauvegarde-cle-usb"
fi
case "${fstype:-}" in
crypto_LUKS)
erreur "c'est l'enveloppe chiffrée de la clé. Déverrouillez-la dans le gestionnaire de fichiers, relancez l'installateur et choisissez la ligne « crypt » qui apparaît." ;;
ext4|ext3|ext2|btrfs|xfs) echo "Clé au format Linux ($fstype) : droits et propriétaires seront conservés." ;;
vfat) echo "Clé au format FAT32 : ni droits ni liens symboliques, fichiers de 4 Go maximum." ;;
exfat|ntfs) echo "Clé au format $fstype : ni droits ni propriétaires (suffisant pour des documents)." ;;
"") ;;
*) echo "Format $fstype : non testé, copie prudente sans droits." ;;
esac
# -----------------------------------------------------------------------------
# Choix de l'utilisateur
# -----------------------------------------------------------------------------
if [[ -z "$UTILISATEUR_CHOISI" ]]; then
defaut="${SUDO_USER:-}"
[[ "$defaut" == "root" ]] && defaut=""
read -r -p "Utilisateur dont on sauvegarde le dossier personnel [${defaut}] : " UTILISATEUR_CHOISI
UTILISATEUR_CHOISI="${UTILISATEUR_CHOISI:-$defaut}"
fi
[[ -n "$UTILISATEUR_CHOISI" ]] || erreur "aucun utilisateur indiqué."
[[ "$UTILISATEUR_CHOISI" =~ ^[a-z_][a-z0-9_.-]*$ ]] || erreur "nom d'utilisateur invalide : $UTILISATEUR_CHOISI"
id -u "$UTILISATEUR_CHOISI" >/dev/null 2>&1 || erreur "utilisateur inconnu : $UTILISATEUR_CHOISI"
DOSSIER_PERSO="$(getent passwd "$UTILISATEUR_CHOISI" | cut -d: -f6)"
# -----------------------------------------------------------------------------
# Installation des fichiers
# -----------------------------------------------------------------------------
titre "Installation"
install -o root -g root -m 755 "$ICI/sauvegarde-cle-usb" "$SCRIPT_CIBLE"
echo "Script : $SCRIPT_CIBLE"
install -o root -g root -m 644 "$ICI/sauvegarde-cle-usb.service" "$SERVICE_CIBLE"
echo "Service : $SERVICE_CIBLE"
if [[ -f "$CONF_CIBLE" ]]; then
# Configuration existante : on garde les réglages, on met à jour la clé.
sed -i -e "s|^UUID=.*|UUID=\"$UUID_CHOISI\"|" \
-e "s|^UTILISATEUR=.*|UTILISATEUR=\"$UTILISATEUR_CHOISI\"|" "$CONF_CIBLE"
echo "Réglages : $CONF_CIBLE (conservés, clé et utilisateur mis à jour)"
echo " vérifiez la liste SOURCES si l'utilisateur a changé."
else
sed -e "s|^UUID=.*|UUID=\"$UUID_CHOISI\"|" \
-e "s|^UTILISATEUR=.*|UTILISATEUR=\"$UTILISATEUR_CHOISI\"|" \
-e "s|/home/marie|$DOSSIER_PERSO|g" \
"$ICI/sauvegarde-cle-usb.conf" > "$CONF_CIBLE"
echo "Réglages : $CONF_CIBLE"
fi
chown root:root "$CONF_CIBLE"
chmod 644 "$CONF_CIBLE"
sed "s|@UUID@|$UUID_CHOISI|" "$ICI/99-sauvegarde-cle-usb.rules.modele" > "$REGLE_CIBLE"
chmod 644 "$REGLE_CIBLE"
echo "Règle udev : $REGLE_CIBLE"
recharger
titre "C'est prêt"
cat <<FIN
Clé de sauvegarde : UUID $UUID_CHOISI
Utilisateur : $UTILISATEUR_CHOISI
1. Pour tester sans rien modifier : sudo sauvegarde-cle-usb --simulation
2. Débranchez puis rebranchez la clé : la sauvegarde démarre toute seule.
Attendez la notification « Sauvegarde terminée » avant de la retirer.
3. Journal : journalctl -u sauvegarde-cle-usb
Réglages (dossiers, exclusions, corbeille) : sudo xed $CONF_CIBLE
FIN