#!/bin/bash # Path to backuppcfs script BACKUPPCFS_PATH="/usr/local/sbin/backuppcfs" BACKUPPCFS_MNT="/mnt/backuppcfs" MNT_DIR=/mnt/usb LUKS_DM_NAME=bkp-usb LUKS_DM_PATH=/dev/mapper/$LUKS_DM_NAME LUKS_KEY_FILE="/root/.luks.key" # LOCK_FILE LOCK_FILE=/var/lock/bkp-disk.lock MAIL_FROM=root@localhost MAIL_TO=root@localhost function usage() { echo "Usage : backup-usb [-d] [-s|-c|-f|-o] [-l /path/to/log.file] [-u /dev/sdX]" echo " -d Debug mode" echo " -d Status mode : print status mode" echo " -c Clean status mode : try to :" echo " - umount device and BackupPC-FS" echo " - close LUKS device" echo " - remove lock file" echo " -f FSCK mode : Run FSCK on device" echo " -o Open mode : lock, open and mount device" echo " -l Log file path" echo " -u Path of USB disk device" } DEBUG=0 SEND_MAIL=1 STATUS_MODE=0 CLEAN_MODE=0 FSCK_MODE=0 OPEN_MODE=0 LOG="" DEVICE="" while getopts ":dscfol:u:h" opt do case "$opt" in d) DEBUG=1 ;; s) STATUS_MODE=1 SEND_MAIL=0 ;; c) CLEAN_MODE=1 SEND_MAIL=0 ;; f) FSCK_MODE=1 SEND_MAIL=0 ;; o) OPEN_MODE=1 SEND_MAIL=0 ;; l) LOG="$OPTARG" ;; u) DEVICE="$OPTARG" ;; h) usage exit 0 ;; *) echo "Invalid '$opt' parameter" echo usage exit 1 esac done # # Functions # function is_mount () { mount | grep -c "$1 " } function send_mail () { [ $SEND_MAIL -eq 0 ] && return echo -e "$2"|mail -s "$1" -r "$MAIL_FROM" "$MAIL_TO" } REPORT="" function debug () { d=`date "+%Y-%m-%d - %Hh%Mm%Ss"` if [ -z "$LOG" ] then echo -e "$d -- [$1] $2" else echo -e "$d -- [$1] $2" >> $LOG 2>&1 fi REPORT="${REPORT}$d -- [$1] $2\n" if [ "$1" == "HALT" ] then beep -f 300 -l 2000 fi if [ "$3" == "send" -a $SEND_MAIL -ne 0 ] then if [ -z "$LOG" ] then echo "$d -- [INFO] Send mail" else echo "$d -- [INFO] Send mail" >> $LOG 2>&1 fi send_mail "[$1] Export sauvegardes Backup PC" "$2" fi } function send_report () { [ $DEBUG -eq 1 -o $SEND_MAIL -eq 0 ] && return 0 [ -n "$REPORT_DF_START" ] && REPORT="${REPORT}\n\n${REPORT_DF_START}" [ -n "$REPORT_DF_END" ] && REPORT="${REPORT}\n\n${REPORT_DF_END}" if [ "$1" == "error" ] then send_mail "[ERREUR] Export sauvegardes Backup PC : fin de l'export" "/\!\\ Intervention manuelle requise avant de débrancher le disque /\!\\\n\n$REPORT" else send_mail "[INFO] Export sauvegardes Backup PC : fin de l'export" "$REPORT" fi } function disk_info() { VENDOR=$( lsblk -o VENDOR $DEVICE|tail -n1 ) SIZE=$( lsblk -o SIZE $DEVICE|tail -n1 ) UUID=$( lsblk -o UUID $DEVICE|tail -n1 ) echo "$VENDOR $SIZE / UUID : $UUID"|sed 's/ \+/ /g' } function checkAndLock() { if [ -f $LOCK_FILE ] then debug ERREUR "Le fichier de lock est toujours présent ($LOCK_FILE)." send debug HALT exit 1 fi debug INFO "Dépot du fichier de lock." echo $$ > $LOCK_FILE } function unlock() { debug INFO "Suppression du fichier de lock" rm -f $LOCK_FILE } function openDevice() { if [ -e $LUKS_DM_PATH ] then debug ERREUR "Le device $LUKS_DM_NAME existe deja ($LUKS_DM_PATH)." send debug HALT exit 1 fi debug INFO "Ouverture du disque LUKS ..." cryptsetup luksOpen $DEVICE $LUKS_DM_NAME --key-file $LUKS_KEY_FILE RES=$? if [ $RES -ne 0 ] then debug ERREUR "La commande 'cryptsetup luksOpen' n'a pas retourne 0. Code retour : $RES" send debug HALT exit $RES else debug INFO "Fait." fi } function mountDevice() { if [ `is_mount $LUKS_DM_PATH` -eq 1 ] then debug ERREUR "Le disque est déjà monté" send debug HALT exit 1 fi debug INFO "Montage du disque." mount $LUKS_DM_PATH $MNT_DIR if [ `is_mount $LUKS_DM_PATH` -eq 0 ] then debug ERREUR "Problème durant le montage du disque dur." send debug HALT exit 1 fi } function closeDevice() { debug INFO "Fermeture du disque LUKS..." cryptsetup close $LUKS_DM_NAME RES=$? if [ $RES -ne 0 ] then debug ERREUR "Problème durant la fermeture du disque LUKS" send debug HALT send_report error exit 1 fi } function statusMode () { if [ -f $LOCK_FILE ] then debug INFO "Fichier de lock present" if [ $( ps xa|grep rsync|grep -c "$BACKUPPCFS_MNT" ) -gt 0 ] then debug INFO "Un export de sauvegarde est en cours (commande rsync détectée)" else debug ERREUR "Aucun export de sauvegarde détecté (pas de commande rsync détectée).\n\nSi le problème predure depuis plusieurs limite, lancer la commande '$0 -c'" fi else debug INFO "Fichier de lock absent" fi if [ -e $LUKS_DM_PATH ] then debug INFO "Disque LUKS ouvert" if [ `is_mount $LUKS_DM_PATH` -eq 1 ] then debug INFO "Disque LUKS monté" df -h $LUKS_DM_PATH else debug INFO "Disque LUKS non-monté" fi else debug INFO "Disque LUKS non-ouvert" fi if [ `is_mount $BACKUPPCFS_MNT` -eq 1 ] then debug INFO "BackupPC-FS monté" else debug INFO "BackupPC-FS non-monté" fi } function cleanMode () { umount $MNT_DIR cryptsetup close $LUKS_DM_NAME umount $BACKUPPCFS_MNT rm -f $LOCK_FILE } function fsckMode() { debug INFO "Début du test FSCK du disque USB $DEVICE ($( disk_info ))" checkAndLock beep -f 1000 -r 2 -l 100 openDevice fsck $LUKS_DM_PATH RET=$? if [ $RET -eq 0 ] then closeDevice unlock fi exit $RET } function openMode() { debug INFO "Ouverture et montage du disque USB $DEVICE ($( disk_info ))" checkAndLock beep -f 1000 -r 2 -l 100 openDevice mountDevice exit 0 } function exportBackupMode() { debug INFO "Début de l'export des sauvegardes Backup PC sur le disque USB $DEVICE ($( disk_info ))" send checkAndLock beep -f 1000 -r 2 -l 100 openDevice mountDevice debug INFO "Disque monté. Espace sur le disque USB avant l'export :\n\n$( df -hP $MNT_DIR )\n" debug INFO "Montage de BackupPC FS..." $BACKUPPCFS_PATH $BACKUPPCFS_MNT RES=$? if [ $RES -ne 0 ] then debug ERREUR "Problème durant le montage de BackupPC FS. Code retour : $RES" umount $BACKUPPCFS_MNT umount $LUKS_DM_PATH cryptsetup close $LUKS_DM_NAME debug HALT exit 1 else debug INFO "Fait." fi sleep 2 debug INFO "Export des sauvegardes ..." for dir in $BACKUPPCFS_MNT/* do [ ! -d "$dir" -o ! -L "$dir/latest" ] && continue host="$( basename "$dir")" latest=$( readlink -e "$dir/latest" ) [ ! -d "$latest" ] && debug ERREUR "Problème durant la résolution du lien de la dernière sauvegarde du serveur $host" && continue debug INFO "Export de la dernière sauvegarde du serveur $host (sauvegarde n° $( basename $latest )) ..." rsync -a --delete --numeric-ids --exclude='/dev/*' --exclude='/lib/udev/devices/*' --exclude='PaxHeader' --exclude='WinSxS/*' "$latest/" "$MNT_DIR/$host/" RES=$? if [ $RES -ne 0 -a $RES -ne 24 ] then debug ERREUR "Problème durant l'export de la sauvegarde du serveur $host (Code retour : $RES)" send else debug INFO "Fait." fi done debug INFO "Export des sauvegardes terminé. Espace sur le disque USB après l'export :\n\n$( df --sync -hP $MNT_DIR )\n" debug INFO "Démontage de BackupPC FS..." umount $BACKUPPCFS_MNT RES=$? if [ $RES -ne 0 ] then debug ERREUR "Problème durant le démontage de BackupPC FS (Code retour : $RES)" send else debug INFO "Fait." fi debug INFO "Démontage du disque" umount $LUKS_DM_PATH if [ `is_mount $LUKS_DM_PATH` -eq 1 ] then debug ERREUR "Problème durant le démontage du disque dur." send debug HALT send_report error exit 1 else debug INFO "Fait." fi closeDevice unlock debug INFO "Fin de l'export." send_report beep -f 1000 -l 2000 } # Manage status/clean mode if [ "$STATUS_MODE" == "1" ] then statusMode exit 0 elif [ "$CLEAN_MODE" == "1" ] then cleanMode exit 0 fi if [ -z "$DEVICE" ] then debug FATAL "Il faut specifié le disque USB avec le paramètre -u !" usage exit 1 elif [ "$FSCK_MODE" == "1" ] then fsckMode exit $? elif [ "$OPEN_MODE" == "1" ] then openMode exit $? else # Else : we are in backup mode if [ -n "$LOG" ] then # Close STDOUT file descriptor exec 1<&- # Close STDERR FD exec 2<&- # Open STDOUT as $LOG file for read and write. exec 1<>$LOG # Redirect STDERR to STDOUT exec 2>&1 fi exportBackupMode fi