#326 Le 02/07/2025, à 11:48
- iznobe
Re : script d’automatisation sauvegardes
Salut , c' est plus que de la parano de vouloir sauvegarder en double et des fichiers toutes les heures .
Pour du perso , je n' en vois pas l' interet .
Ca serait une entreprise de dev avec une dizaine d' utilisateurs qui travaillent sur du code , là ok .
Mais ils utilisent des outils appropriés au versionning , ils n' ont donc pas besoin non plus de faire des sauvegardes toutes les heures ( encore moins en double ! ) .
il me semble qu ' il a été dis que reinventé la roue etait une enorme perte de temps :
Bonjour,
je pense le mieux le mieux serais d'utiliser une interfaces web mini-server apache en local ou l'ajouts de nouvelle sauvegardes. Quelques jours je suis dessus bientôt finalisé. Ca evitera de faire des erreurs et de ne plus touché au code principal qui est actuellement fonctionnel.
Mais il y en a que ca amuse à priori .
vincent a deja dis dans tes discussions , je ne sais combien de fois , d' utiliser un logiciel spécialisé , ce qui convient parfaitement une fois que tu as choisi celui qui te convient .
retour COMPLET et utilisable de commande | script montage partitions
MSI Z490A-pro , i7 10700 , 32 GB RAM .
Hors ligne
#327 Le 02/07/2025, à 12:36
- eric63
Re : script d’automatisation sauvegardes
ça me semble pas parano de donner à 2 utilisateurs les mêmes droits de sauvegardes , c’est en plus de la curiosité de voir comment faire cela
et en attendant la proposition de steph810 la solution de rsnapshot -alpha (hourly) me conviendrait à défaut sans casser ce qui existe déjà dans sauvegarde.sh
j’explore cette possibilité
Kubuntu 25.04 wayland Plasma 6.3.4 KDE Qt 6.12.0 noyau 6.14.0-15 Asus B760+D4 i5-12400F 4.4Ghz DDR4 32Go nvidia RTX 3060 12GB
Utilisez les drivers libres avant d’ installer une brother avec le script de demonipuch
J’utilise le clavier french AFNOR
Hors ligne
#328 Le 05/07/2025, à 12:12
- eric63
Re : script d’automatisation sauvegardes
Je vois que steph810 en est à la version 6.5 de son projet Backup Manager Web et qu’il semble fixé depuis 3 jours.
Est ce que je peux essayer à partir de maintenant ?
ou dois je attendre encore quelques temps pour des modifications à venir ?
( je n’ai pas vu de modifications concernant les sauvegardes spéciales mais j’ai parcouru peut être un peu vite les readme et autres explications)
Sacré boulot
Kubuntu 25.04 wayland Plasma 6.3.4 KDE Qt 6.12.0 noyau 6.14.0-15 Asus B760+D4 i5-12400F 4.4Ghz DDR4 32Go nvidia RTX 3060 12GB
Utilisez les drivers libres avant d’ installer une brother avec le script de demonipuch
J’utilise le clavier french AFNOR
Hors ligne
#329 Le 08/07/2025, à 10:29
- eric63
Re : script d’automatisation sauvegardes
bon je m’y suis risqué à la version 6.5
Comme attendu ça marche pô; j’ai lu attentivement pourtant. Les instructions en ligne de commande sont plus précises que le manuel
http://localhost/backup-manager-web/web/ au lieu de http://votre-serveur/backup-manager-web/web/ c’est plus parlant
j’ai fait l’installation rapide recommandée
# Cloner le projet
git clone https://github.com/ps81frt/backup-manager-web.git
cd backup-manager-web
# Installation automatique (détecte votre distribution)
sudo ./setup-web.sh
kubu@kubu-System-Product-Name:~/Documents/ScriptsVMImportants/backup-manager-web$ sudo ./setup-web.sh
[sudo] password for kubu:
Installation de Backup Manager Web...
Détection de la distribution...
Distribution Debian/Ubuntu détectée
Vérification des dépendances...
Toutes les dépendances sont déjà installées.
Configuration du serveur web...
apache2 déjà en cours d'exécution
usermod : aucun changement
Considering dependency mpm_prefork for php8.4:
Considering conflict mpm_event for mpm_prefork:
Considering conflict mpm_worker for mpm_prefork:
Module mpm_prefork already enabled
Considering conflict php5 for php8.4:
Module php8.4 already enabled
Vérification des outils système...
Configuration des permissions...
Génération de la clé SSH...
Clé SSH déjà existante
Vérification finale...
✅ INSTALLATION RÉUSSIE !
=== ÉTAPES SUIVANTES ===
1. Modifiez config.sh avec vos vraies valeurs :
SSH_USER_PHOTOS="votre_utilisateur"
SSH_IP_PHOTOS="192.168.1.100"
donne
SSH_USER_PHOTOS="Multimedias" # Monté sur /home/kubu/VMMultimedias/PhotosVM et Monté à partir de Multimedias@192.168.1.128:/home/Multimedias/PhotosVM "votre_utilisateur_vm_photos"
SSH_IP_PHOTOS="192.168.1.128"
2. Copiez cette clé publique sur vos serveurs distants :
ssh-rsa AAAABxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx= backup-web@kubu-System-Product-Name
là problème pour moi c’est pas clair; sinon je vois pas comment faire exactement autrement:
je suppose qu’il faut exécuter le 3 pour copier au bon endroit ou aux bons endroits cette clé sur les serveurs distants
Multimedias@162.168.1.128
et
fanou@192.168.1.60
????
j’ai donc poursuivis
3. Sur chaque serveur distant, exécutez :
ssh-copy-id -i /var/www/.ssh/backup_key.pub utilisateur@serveur
donne
kubu@kubu-System-Product-Name:~$ ssh-copy-id -i /var/www/.ssh/backup_key.pub Multimedias@192.168.1.128
/usr/bin/ssh-copy-id: ERROR: failed to open ID file '/var/www/.ssh/backup_key': Permission denied
(to install the contents of '/var/www/.ssh/backup_key.pub' anyway, look at the -f option)
kubu@kubu-System-Product-Name:~$
ce qui semble normal vu que ce fichier appartient à www-data
donc j’essai avec un
kubu@kubu-System-Product-Name:~$ sudo ssh-copy-id -i /var/www/.ssh/backup_key.pub Multimedias@192.168.1.128
[sudo] password for kubu:
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/var/www/.ssh/backup_key.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -i /var/www/.ssh/backup_key 'Multimedias@192.168.1.128'"
and check to make sure that only the key(s) you wanted were added.
kubu@kubu-System-Product-Name:~/Documents/ScriptsVMImportants/backup-manager-web$ sudo -u www-data ssh -i /var/www/.ssh/backup_key Multimedias@192.168.1.128
The authenticity of host '192.168.1.128 (192.168.1.128)' can't be established.
ED25519 key fingerprint is SHA256:f5v7hCEMhkmb3eJHG/N60kQ+9G3Kc7pRz6r5fgVXpmQ.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
là je bloque la clé n’est pas la bonne ???
je passe en attendant
5. Le système est maintenant fonctionnel :
- Terminal : ./sauvegarde.sh all
- Web : http://localhost/backup-manager-web/web/
je vois enfin mon dashboard
j’ai aussi modifié dans /var/www/html/backup-manager-web/web/index.php
les lignes
// Sauvegardes par défaut (depuis fichier de config)
$defaultConfig = '../default_backups.conf';
$defaults = ['docs_eric', 'docs_fanou', 'docs_portable_fanou','docs_communs_vm', 'photos_vm', 'images_vm', 'musiques_vm', 'projets_serveur'];
// Vérifier si c'est une sauvegarde par défaut désactivée
$defaultBackups = ['docs_eric', 'docs_fanou', 'docs_portable_fanou','docs_communs_vm', 'photos_vm', 'images_vm', 'musiques_vm', 'projets_serveur'];
if (in_array($selection, $defaultBackups) && !isDefaultBackupEnabled($selection)) {
return "Erreur: La sauvegarde '$selection' est désactivée dans default_backups.conf";
}
// Validation sécurisée - inclure les sauvegardes personnalisées
$allowed = ['docs_eric', 'docs_fanou', 'docs_portable_fanou', 'docs_communs_vm', 'photos_vm', 'images_vm', 'musiques_vm', 'projets_serveur', 'all'];
reste encore à résoudre l’histoire de la clé sur le serveur distant du portable
et les sauvegardes interne des documents de la vm sur la vm avec un crontab horaire
Dernière modification par eric63 (Le 09/07/2025, à 12:40)
Kubuntu 25.04 wayland Plasma 6.3.4 KDE Qt 6.12.0 noyau 6.14.0-15 Asus B760+D4 i5-12400F 4.4Ghz DDR4 32Go nvidia RTX 3060 12GB
Utilisez les drivers libres avant d’ installer une brother avec le script de demonipuch
J’utilise le clavier french AFNOR
Hors ligne
#330 Le 09/07/2025, à 14:53
- eric63
Re : script d’automatisation sauvegardes
essai sauvegardes1
www-data@backup-manager-web:~/backup-manager-web$ ./sauvegarde.sh --dry-run all
tee: /var/log/sauvegardes/sauvegarde_20250709.log: Permission denied
2025-07-09 14:54:39 [INFO] Configuration de l'environnement web détectée...
2025-07-09 11:25:21 [ERREUR] L'exécutable configuré pour MAIL ('/usr/bin/sendmail') n'existe pas ou n'est pas exécutable.
2025-07-09 11:25:21 [ERREUR] Code d'erreur : 127. Certaines dépendances logicielles essentielles sont manquantes ou incorrectement configurées.
2025-07-09 11:25:21 [ERREUR] Action suggérée : Une commande externe requise par le script n'a pas été trouvée dans le PATH. Vérifiez que toutes les dépendances (rsync, ssh, sshfs, mailx/mail, fusermount, etc.) sont installées et accessibles. Ou que leur chemin est correctement configuré dans config.sh.
bon c’est pas gagné
j’ai mis la variable
EMAIL_NOTIFICATION=""
du fichier config.sh mais cela ne fonctionne pas mieux
et les commandes mail ou mailx sont inconnues
kubu@kubu-System-Product-Name:~$ sudo apt install mail
[sudo] password for kubu:
Erreur : Impossible de trouver le paquet mail
kubu@kubu-System-Product-Name:~$ sudo apt install mailx
Le paquet mailx est un paquet virtuel fourni par :
mailutils 1:3.18-1
bsd-mailx 8.1.2-0.20220412cvs-1build1
Vous devez explicitement sélectionner un paquet à installer.
Erreur : Le paquet « mailx » n'a pas de version susceptible d'être installée
kubu@kubu-System-Product-Name:~$
j’ai vidé l’adresse mail
déconnecté les sauvegardes sauf documents_eric
j’ai modifié les chemin de 2 variables pour les rendre accessibles
# Répertoire où les fichiers de log du script seront stockés.
LOG_DIR="/home/kubu/log/sauvegardes/" #"/var/log/sauvegardes"
# Chemin complet du fichier de verrouillage. Doit être accessible en écriture.
PID_FILE="/home/kubu/log/$DEFAULT_NOM_SCRIPT.pid" #"/var/run/$DEFAULT_NOM_SCRIPT.pid"
j’ai démarré la commande sauvegarde.sh dans la konsole
ça a amélioré le départ
kubu@kubu-System-Product-Name:~$ /var/www/html/backup-manager-web/sauvegarde.sh
2025-07-09 19:08:10 [INFO] Fichier de verrouillage créé : 9917
2025-07-09 19:08:10 [INFO] === DÉBUT DES SAUVEGARDES ===
2025-07-09 19:08:10 [INFO] Sélections à traiter : docs_eric docs_fanou docs_portable_fanou docs_communs
2025-07-09 19:08:10 [INFO] Traitement de la sauvegarde 'Docs Eric'...
2025-07-09 19:08:10 [INFO] Démarrage de la sauvegarde locale pour '/home/kubu/Documents' vers '/media/kubu/JEUX8T/SAUVEGARDES/DocumentsEric/'.
2025-07-09 19:08:10 [INFO] Création du répertoire de destination principal : /media/kubu/JEUX8T/SAUVEGARDES/DocumentsEric/
2025-07-09 19:08:10 [INFO] Création du répertoire de base incrémentale : /media/kubu/JEUX8T/SAUVEGARDES/incremental-DocumentsEric/
2025-07-09 19:08:11 [INFO] Espace disque libre sur '/media/kubu/JEUX8T/SAUVEGARDES' : 2730 Go (minimum requis : 5 Go).
2025-07-09 19:08:11 [ERREUR] La variable 'Point de montage SSHFS' ne peut pas être vide.
2025-07-09 19:08:11 [INFO] Fichier de verrouillage supprimé.
kubu@kubu-System-Product-Name:~$
ça m’a créé 2 dossiers vides au bon endroit
essai avec le dashboard
mais le bouton exécuter n’a pas l’air de lancer la sauvegarde
cette ligne m’intrigue
La variable 'Point de montage SSHFS' ne peut pas être vide.
car je n’ai pas besoin de point de montage pour ce dossier local ????
Dans le fichier sauvegarde.sh j’ai 4 occurences pour "montage_sshfs_point"
# shellcheck disable=SC2154 # DEFAULT_TYPE_CONNEXION_DISTANTE est défini dans config.sh
if [[ "$DEFAULT_TYPE_CONNEXION_DISTANTE" -eq 0 ]]; then # Mode SSHFS
local local_source="$source_path" # Pour rsync, la source est le chemin distant MONTÉ localement.
# Vérifie si le point de montage existe et est bien un répertoire
valider_variable "Point de montage SSHFS" "$montage_sshfs_point" "path"
if [[ $? -ne 0 ]]; then diagnostiquer_et_logger_erreur 13 "Point de montage SSHFS invalide: $montage_sshfs_point"; fi
# Montage SSHFS
monter_sshfs "$ssh_user" "$ssh_ip" "$ssh_port" "$source_path" "$montage_sshfs_point"
local_source="$montage_sshfs_point" # La source de rsync devient le point de montage local
# Vérifier si le point de montage est vide ou inaccessible après montage
if ! find "$local_source" -mindepth 1 -print -quit | grep -q .; then
log_warning "Le point de montage SSHFS '$local_source' semble vide ou inaccessible après le montage. La sauvegarde pourrait ne rien transférer."
# Ne pas diagnostiquer comme une erreur fatale ici, car le dossier distant PEUT être vide.
# L'erreur 13 est plus pour "source inexistante avant même de tenter un montage"
fi
Dernière modification par eric63 (Le 09/07/2025, à 21:07)
Kubuntu 25.04 wayland Plasma 6.3.4 KDE Qt 6.12.0 noyau 6.14.0-15 Asus B760+D4 i5-12400F 4.4Ghz DDR4 32Go nvidia RTX 3060 12GB
Utilisez les drivers libres avant d’ installer une brother avec le script de demonipuch
J’utilise le clavier french AFNOR
Hors ligne
#331 Hier à 16:12
- eric63
Re : script d’automatisation sauvegardes
aucune avancée sur le problème
j’ai beau trituré les script je vois rien d’anormal
kubu@kubu-System-Product-Name:/var/www/html/backup-manager-web$ ./sauvegarde.sh docs_eric
2025-07-11 15:50:24 [INFO] Fichier de verrouillage créé : 20984
2025-07-11 15:50:24 [INFO] === DÉBUT DES SAUVEGARDES ===
2025-07-11 15:50:24 [INFO] Sélections à traiter : docs_eric
2025-07-11 15:50:24 [INFO] Traitement de la sauvegarde 'Docs Eric'...
2025-07-11 15:50:24 [INFO] Démarrage de la sauvegarde locale pour '/home/kubu/Documents' vers '/media/kubu/JEUX8T/SAUVEGARDES/DocumentsEric/'.
2025-07-11 15:50:24 [INFO] Espace disque libre sur '/media/kubu/JEUX8T/SAUVEGARDES' : 2730 Go (minimum requis : 5 Go).
2025-07-11 15:50:24 [ERREUR] La variable 'Point de montage SSHFS' ne peut pas être vide.
2025-07-11 15:50:24 [INFO] Fichier de verrouillage supprimé.
kubu@kubu-System-Product-Name:/var/www/html/backup-manager-web$
je donne les 2 scripts config.sh et sauvegarde.sh
#!/bin/bash
#===============================================================
# Fichier de configuration pour sauvegarde.sh
# Auteur : enRIKO (modifié pour production et améliorations)
# Date : 2025-06-24
# Version : 2.5
#
# Changelog :
# - 2.5 (2025-06-24) :
# - Correction majeure : Restauration de TOUS les noms de variables en français comme dans la version originale.
# - Ajout de nouveaux paramètres (également en français) pour une robustesse accrue,
# sans modifier les variables existantes.
# - 2.4 (2025-06-24) :
# - Ajout de RSYNC_DELETE pour contrôler l'option rsync --delete.
# - Clarification des commentaires pour la personnalisation.
#===============================================================
# --- OPTIONS GLOBALES DU SCRIPT ---
# Adresse email pour les rapports de succès/échec. Laissez vide pour désactiver.
EMAIL_NOTIFICATION=""
# Espace disque minimum requis sur la destination (en Go). Le script échouera si l'espace est insuffisant.
ESPACE_DISQUE_MIN_GO=5
# Options rsync par défaut. Utilisez des exclusions pour les fichiers temporaires ou inutiles.
# --archive (-a) : mode archive (récursif, conserve les liens symboliques, permissions, temps, groupe, propriétaire)
# --human-readable (-h) : sorties lisibles par l'humain
# --info=progress2,misc0,name0 : affiche la progression et d'autres infos utiles
# --partial --progress : permet de reprendre les transferts et affiche la progression du fichier courant
DEFAULT_RSYNC_OPTIONS="-avh --partial --progress --info=progress2,misc0,name0"
# Activer (1) ou désactiver (0) l'option --delete de rsync.
# 0: Ne supprime jamais (par défaut et recommandé pour les incrémentales avec --link-dest).
# 1: Supprime les fichiers sur la destination s'ils ont été supprimés sur la source (utiliser avec prudence!).
RSYNC_DELETE=0
# Mode débogage (0=off, 1=on). Active la sortie verbeuse du script pour le diagnostic.
DEFAULT_MODE_DEBOGAGE=1
# Désactiver les journaux (0=actif, 1=désactivé). Les erreurs critiques seront toujours enregistrées dans un fichier temporaire.
DEFAULT_JOURNAUX_DESACTIVES=0
# Nom du script pour le mécanisme de verrouillage (évite les exécutions multiples).
DEFAULT_NOM_SCRIPT="sauvegarde"
# Activer le mécanisme de verrouillage (0=off, 1=on).
ACTIVERLOCK=1
# Type de connexion distante :
# 0 = SSHFS (recommandé pour une intégration transparente des chemins distants)
# 1 = SSH direct (rsync via SSH, plus simple, mais nécessite des chemins distants absolus dans rsync)
DEFAULT_TYPE_CONNEXION_DISTANTE=0
# Sélections de sauvegardes par défaut à exécuter si aucune n'est spécifiée en ligne de commande.
# Séparez les sélections par des espaces (ex: "docs_eric docs_fanou photos_vm").
# Utilisez "all" pour inclure toutes les sauvegardes définies.
DEFAULT_SELECTIONS_SAUVEGARDES="docs_eric docs_fanou docs_portable_fanou docs_communs"
# Mode incrémental par défaut (0=complet, 1=incrémental)
DEFAULT_MODE_INCREMENTAL=1
# --- CHEMINS CRITIQUES ET BINAIRES ---
# Répertoire de base où toutes les sauvegardes seront stockées.
DEST_BASE_SAUVEGARDES="/media/kubu/JEUX8T/SAUVEGARDES"
# Répertoire où les fichiers de log du script seront stockés.
LOG_DIR="/home/kubu/log/sauvegardes/" #"/var/log/sauvegardes"
# Chemin complet du fichier de verrouillage. Doit être accessible en écriture.
PID_FILE="/home/kubu/log/$DEFAULT_NOM_SCRIPT.pid" #"/var/run/$DEFAULT_NOM_SCRIPT.pid"
# Chemin du fichier de clé privée SSH (laissez vide si authentification par agent ou mot de passe).
# Ex: SSH_KEY_PATH="/home/votre_utilisateur/.ssh/id_rsa_backup"
SSH_KEY_PATH="/home/kubu/.ssh/id_ed25519"
# Chemin du socket de l'agent SSH (laissez vide si non utilisé).
# Ex: SSH_AUTH_SOCK_PATH="/tmp/ssh-XXXXXXX/agent.XXXX"
SSH_AUTH_SOCK_PATH=""
# --- NOUVEAUX PARAMÈTRES : CHEMINS EXPLICITES VERS LES EXÉCUTABLES DES OUTILS ---
# Ces variables permettent de spécifier le chemin complet d'un exécutable si celui-ci
# n'est pas dans le PATH standard ou si une version spécifique est requise.
# Laissez vide pour utiliser la version trouvée dans le PATH du système.
CHEMIN_RSYNC="/usr/bin/rsync" # Ex: /usr/bin/rsync
CHEMIN_SSH="/usr/bin/ssh" # Ex: /usr/bin/ssh
CHEMIN_SSHFS="/usr/bin/sshfs" # Ex: /usr/bin/sshfs
CHEMIN_FUSEMOUNT="/usr/bin/fusermount" # Ex: /usr/bin/fusermount
CHEMIN_MOUNTPOINT="/usr/bin/mountpoint" # Ex: /usr/bin/mountpoint
CHEMIN_LSOF="/usr/bin/lsof" # Ex: /usr/bin/lsof
CHEMIN_KILL="/usr/bin/kill" # Ex: /usr/bin/kill
CHEMIN_MKDIR="/usr/bin/mkdir" # Ex: /usr/bin/mkdir
CHEMIN_MAIL="/usr/bin/mail" # Ex: /usr/bin/mailx ou /usr/bin/mail
# --- NOUVEAUX PARAMÈTRES : GESTION AVANCÉE DES JOURNAUX ---
# Taille maximale d'un fichier de log en Mo avant rotation. (0 pour désactiver la rotation par taille)
TAILLE_MAX_LOG_MO=10
# Nombre de jours avant de compresser/purger les anciens logs (0 pour désactiver la rétention basée sur le temps).
JOURS_RETENTION_LOGS=30
# Commande de compression pour les logs archivés (ex: "gzip"). Laissez vide pour ne pas compresser.
# Assurez-vous que la commande est disponible sur le système (e.g., 'gzip', 'bzip2', 'xz').
COMMANDE_COMPRESSION_LOGS="gzip"
# --- NOUVEAUX PARAMÈTRES : OPTIONS DE CONNEXION SSH AVANCÉES ---
# Timeout de connexion SSH en secondes.
DELAI_CONNEXION_SSH_SECONDES=10
# Options SSH communes à toutes les connexions distantes.
# Par défaut, ces options sont sécurisées. Si vous avez besoin de désactiver la vérification des clés
# d'hôte, utilisez StrictHostKeyChecking_SSH (avec prudence !).
OPTIONS_COMMUNES_SSH="-o BatchMode=yes -o ConnectTimeout=${DELAI_CONNEXION_SSH_SECONDES}"
# Activer (yes), désactiver (no) ou demander (ask) StrictHostKeyChecking.
# "no" est risqué en production pour des raisons de sécurité. Laissez vide pour la configuration SSH par défaut.
StrictHostKeyChecking_SSH="" # "yes", "no", "ask" (laisser vide pour la config SSH par défaut)
# --- NOUVEAUX PARAMÈTRES : OPTIONS RSYNC AVANCÉES ---
# Timeout pour l'opération rsync en secondes. (0 = désactivé. Ex: 3600 = 1 heure)
DELAI_OPERATION_RSYNC_SECONDES=0
# Options spécifiques pour la commande rsync incrémentale.
# --link-dest est crucial pour les sauvegardes incrémentales efficaces avec hardlinks.
# Les chemins dans --link-dest sont relatifs à la DEST_INCR_BASE.
# Ne modifiez pas cette option à moins de savoir ce que vous faites.
OPTIONS_RSYNC_INCREMENTALE="--link-dest=../current"
# --- NOUVEAUX PARAMÈTRES : HOOKS PERSONNALISÉS (AVANCÉ) ---
# Vous pouvez définir des chemins vers des scripts personnalisés qui seront exécutés
# à des moments clés du processus de sauvegarde. Exemple de sauvegardes spéciales VM vers 8T.
# Exécuté au début du script sauvegarde.sh, après le chargement de la config et avant le verrouillage.
# SCRIPT_PRE_SAUVEGARDE_GLOBAL="/chemin/vers/votre_script_pre_sauvegarde_global.sh"
SCRIPT_PRE_SAUVEGARDE_GLOBAL=""
# Exécuté à la fin du script sauvegarde.sh, après toutes les sauvegardes et avant le démontage/nettoyage final.
# SCRIPT_POST_SAUVEGARDE_GLOBAL="/chemin/vers/votre_script_post_sauvegarde_global.sh"
SCRIPT_POST_SAUVEGARDE_GLOBAL=""
# --- CONFIGURATIONS DES SAUVEGARDES SPÉCIFIQUES ---
# Définissez ici les paramètres pour chaque sélection de sauvegarde.
# --- Sauvegarde : Docs Eric (Locale) ---
SOURCE_LOCALE_DOCS_ERIC="/home/kubu/Documents"
DEST_MAIN_DOCS_ERIC="$DEST_BASE_SAUVEGARDES/DocumentsEric/"
DEST_INCR_BASE_DOCS_ERIC="$DEST_BASE_SAUVEGARDES/incremental-DocumentsEric/"
# --- Sauvegarde : Docs Fanou (Locale) ---
#SOURCE_LOCALE_DOCS_FANOU="/home/fanou/Documents"
#DEST_MAIN_DOCS_FANOU="$DEST_BASE_SAUVEGARDES/DocumentsFanou/"
#DEST_INCR_BASE_DOCS_FANOU="$DEST_BASE_SAUVEGARDES/incremental-DocumentsFanou/"
# --- Sauvegarde : Docs Portable (Distante via SSHFS) ---
# NOTE: Le nom de la variable MONTAGE_SSHFS_MUSIQUES a été corrigé en MONTAGE_SSHFS_DOCS_PORTABLE pour être cohérent avec le nom de la sauvegarde.
SSH_USER_DOCS_PORTABLE="fanou" # "fanou_portable"
SSH_IP_DOCS_PORTABLE="192.168.1.60"
SSH_PORT_DOCS_PORTABLE=22
SOURCE_DIST_DOCS_PORTABLE="/home/fanou/Documents/" # Chemin ABSOLU sur le portable
MONTAGE_SSHFS_DOCS_PORTABLE="/tmp/sshfs_mounts/docs_portable_fanou"
DEST_MAIN_DOCS_PORTABLE="$DEST_BASE_SAUVEGARDES/DocumentsPortableFanou/"
DEST_INCR_BASE_DOCS_PORTABLE="$DEST_BASE_SAUVEGARDES/incremental-DocumentsPortableFanou/"
SSH_USER_DOCSCOMMUNS="Multimedias" # Monté sur/home/kubu/VMMultimedias/DocumentsCommunsVM et Monté à partir de Multimedias@192.168.1.128:/home/Multimedias/DocumentsCommunsVM "votre_utilisateur_vm_photos"
SSH_IP_DOCSCOMMUNS="192.168.1.128"
SSH_PORT_DOCSCOMMUNS=22
SOURCE_DIST_DOCSCOMMUNS_VM="/home/kubu/Multimedias/DocumentsCommunsVM" # /chemin/sur/vm/DocumentsCommunsVM" # Chemin ABSOLU sur la VM
MONTAGE_SSHFS_DOCSCOMMUNS="/tmp/sshfs_mounts/DocumentsCommuns_vm"
DEST_MAIN_DOCSCOMMUNS="$DEST_BASE_SAUVEGARDES/DocumentsCommunsVM/"
DEST_INCR_BASE_DOCSCOMMUNS="$DEST_BASE_SAUVEGARDES/incremental-DocumentsCommunsVM/"
# --- Sauvegarde : Photos VM (Distante via SSHFS) ---
# Note : Pour DEFAULT_TYPE_CONNEXION_DISTANTE=0 (SSHFS), SOURCE_DIST est le chemin absolu sur le serveur distant.
# MONTAGE_SSHFS_PHOTOS est le point de montage local. DEST_MAIN_PHOTOS et DEST_INCR_BASE_PHOTOS
# sont les destinations finales sur le système de sauvegarde.
SSH_USER_PHOTOS="Multimedias" # Monté sur/home/kubu/VMMultimedias/PhotosVM et Monté à partir de Multimedias@192.168.1.128:/home/Multimedias/PhotosVM "votre_utilisateur_vm_photos"
SSH_IP_PHOTOS="192.168.1.128"
SSH_PORT_PHOTOS=22
SOURCE_DIST_PHOTOS_VM="/home/kubu/Multimedias/PhotosVM" # /chemin/sur/vm/Photos" # Chemin ABSOLU sur la VM
MONTAGE_SSHFS_PHOTOS="/tmp/sshfs_mounts/photos_vm"
DEST_MAIN_PHOTOS="$DEST_BASE_SAUVEGARDES/PhotosVM/"
DEST_INCR_BASE_PHOTOS="$DEST_BASE_SAUVEGARDES/incremental-PhotosVM/"
SSH_USER_IMAGES="Multimedias" # Monté sur/home/kubu/VMMultimedias/ImagesVM et Monté à partir de Multimedias@192.168.1.128:/home/Multimedias/PhotosVM "votre_utilisateur_vm_photos"
SSH_IP_IMAGES="192.168.1.128"
SSH_PORT_IMAGES=22
SOURCE_DIST_IMAGES_VM="/home/kubu/Multimedias/ImagesVM" # /chemin/sur/vm/Images" # Chemin ABSOLU sur la VM
MONTAGE_SSHFS_IMAGES="/tmp/sshfs_mounts/images_vm"
DEST_MAIN_IMAGES="$DEST_BASE_SAUVEGARDES/ImagesVM/"
DEST_INCR_BASE_IMAGES="$DEST_BASE_SAUVEGARDES/incremental-ImagesVM/"
SSH_USER_MUSIQUES="Multimedias" # Monté sur/home/kubu/VMMultimedias/MusiquesVM et Monté à partir de Multimedias@192.168.1.128:/home/Multimedias/ImagesVM "votre_utilisateur_vm_photos"
SSH_IP_MUSIQUES="192.168.1.128"
SSH_PORT_MUSIQUES=22
SOURCE_DIST_MUSIQUES_VM="/home/kubu/Multimedias/MusiquesVM" # /chemin/sur/vm/Musiques" # Chemin ABSOLU sur la VM
MONTAGE_SSHFS_MUSIQUES="/tmp/sshfs_mounts/musiques_vm"
DEST_MAIN_MUSIQUES="$DEST_BASE_SAUVEGARDES/MusiquesVM/"
DEST_INCR_BASE_MUSIQUES="$DEST_BASE_SAUVEGARDES/incremental-MusiquesVM/"
# --- Sauvegarde : Projets Serveur (Distante via SSHFS) ---
# NOTE: Le nom de la variable MONTAGE_SSHFS_IMAGES a été corrigé en MONTAGE_SSHFS_PROJETS pour être cohérent avec le nom de la sauvegarde.
#SSH_USER_PROJETS="votre_utilisateur_serveur_projets"
#SSH_IP_PROJETS="192.168.1.101"
#SSH_PORT_PROJETS=22
#SOURCE_DIST_PROJETS_SERVEUR="/Projets/Serveur/" # Chemin ABSOLU sur le serveur
#MONTAGE_SSHFS_PROJETS="/tmp/sshfs_mounts/projets_serveur"
#DEST_MAIN_PROJETS="$DEST_BASE_SAUVEGARDES/ProjetsServeur/"
#DEST_INCR_BASE_PROJETS="$DEST_BASE_SAUVEGARDES/incremental-ProjetsServeur/"
# --- POLITIQUES DE RÉTENTION ---
# Définissez le nombre de versions quotidiennes, hebdomadaires et mensuelles à conserver.
# Mettez 0 pour désactiver un type de rétention.
# Rétention pour Docs Eric
JOURS_RETENTION_DOCS_ERIC_QUOTIDIEN=7
JOURS_RETENTION_DOCS_ERIC_HEBDO=4 # Nombre de semaines (4 semaines = 1 mois)
JOURS_RETENTION_DOCS_ERIC_MENSUEL=12 # Nombre de mois (12 mois = 1 an)
# Rétention pour Docs Fanou
JOURS_RETENTION_DOCS_FANOU_QUOTIDIEN=7
JOURS_RETENTION_DOCS_FANOU_HEBDO=4
JOURS_RETENTION_DOCS_FANOU_MENSUEL=12
# Rétention pour Docs Portable Fanou
JOURS_RETENTION_DOCS_PORTABLE_FANOU_QUOTIDIEN=7
JOURS_RETENTION_DOCS_PORTABLE_FANOU_HEBDO=4
JOURS_RETENTION_DOCS_PORTABLE_FANOU_MENSUEL=12
# Rétention pour Docs communes
JOURS_RETENTION_DOCS_COMMUNS_QUOTIDIEN=7
JOURS_RETENTION_DOCS_COMMUNS_HEBDO=4
JOURS_RETENTION_DOCS_COMMUNS_MENSUEL=12
# Rétention pour Photos VM
JOURS_RETENTION_PHOTOS_VM_QUOTIDIEN=7
JOURS_RETENTION_PHOTOS_VM_HEBDO=4
JOURS_RETENTION_PHOTOS_VM_MENSUEL=12
# Rétention pour Images VM
JOURS_RETENTION_IMAGES_VM_QUOTIDIEN=7
JOURS_RETENTION_IMAGES_VM_HEBDO=4
JOURS_RETENTION_IMAGES_VM_MENSUEL=12
# Rétention pour Musiques VM
JOURS_RETENTION_MUSIQUES_VM_QUOTIDIEN=7
JOURS_RETENTION_MUSIQUES_VM_HEBDO=4
JOURS_RETENTION_MUSIQUES_VM_MENSUEL=12
# Rétention pour Projets Serveur
JOURS_RETENTION_PROJETS_SERVEUR_QUOTIDIEN=7
JOURS_RETENTION_PROJETS_SERVEUR_HEBDO=4
JOURS_RETENTION_PROJETS_SERVEUR_MENSUEL=12
#!/bin/bash
export LC_ALL=C
#===============================================================
# Sauvegarde des données
# Auteur : enRIKO (modifié par geole, iznobe, Watael, steph810, amélioré pour qualité irréprochable)
# Date : 2025-06-24
# Version : 6.5
# Description : Script de sauvegarde incrémentale avec validation renforcée, mode dry-run, et gestion avancée des erreurs.
#
# Changelog :
# - 6.5 (2025-06-24) :
# - Intégration des fonctions d'erreurs avancées et des codes d'erreur spécifiques.
# - Utilisation des chemins d'exécutables configurables depuis config.sh (CHEMIN_RSYNC, CHEMIN_SSH, etc.).
# - Gestion améliorée de RSYNC_DELETE pour appliquer --delete conditionnellement.
# - Correction des noms de variables de rétention (MONTAGE_SSHFS_MUSIQUES, JOURS_RETENTION_MUSIQUES_...)
# pour correspondre à Docs Portable.
# - Correction du nom de variable de montage pour Projets Serveur (MONTAGE_SSHFS_IMAGES).
# - Validation initiale des chemins et des permissions critiques.
# - Exécution des hooks PRE/POST_SAUVEGARDE_GLOBAL si configurés.
# - Gestion du timeout Rsync.
# - 6.1 Beta (2025-06-24) :
# - Ajout du mode --dry-run pour simuler les sauvegardes sans modification.
# - Ajout de l'option --list pour lister les sauvegardes disponibles.
# - Validation renforcée des variables (UUID, IP, chemins).
# - Option rsync --delete configurable via RSYNC_DELETE.
# - Vérification des chemins distants avant montage SSHFS.
# - Gestion des démontages SSHFS occupés avec retries.
# - Rapport email plus détaillé avec erreurs spécifiques.
# - Journalisation des erreurs critiques même si les logs sont désactivés.
#===============================================================
# --- PARAMÈTRES ET OPTIONS DU SHELL ---
set -o errexit # Quitte si une commande échoue
set -o nounset # Traite les variables non définies comme des erreurs
set -o pipefail # Détecte les erreurs dans les pipelines
# --- VARIABLES GLOBALES DE BASE ---
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
# --- Source des fichiers de configuration et de fonctions ---
# C'est l'ordre crucial : config.sh d'abord pour que ses variables soient disponibles pour fonctions_erreur.sh
source "$SCRIPT_DIR/config.sh"
# Charger les sauvegardes personnalisées si le fichier existe
if [[ -f "$SCRIPT_DIR/sauvegardes_custom.conf" ]]; then
# Filtrer les sauvegardes désactivées
grep -v "# SAUVEGARDE_DISABLED:" "$SCRIPT_DIR/sauvegardes_custom.conf" > "/tmp/sauvegardes_active.conf"
source "/tmp/sauvegardes_active.conf"
rm -f "/tmp/sauvegardes_active.conf"
fi
source "$SCRIPT_DIR/fonctions_erreur.sh"
# --- FONCTION DE VÉRIFICATION DES SAUVEGARDES PAR DÉFAUT ---
# Vérifie si une sauvegarde par défaut est activée dans default_backups.conf
is_default_backup_enabled() {
local backup_name="$1"
local default_config="$SCRIPT_DIR/default_backups.conf"
# Si le fichier n'existe pas, tout est activé par défaut
if [[ ! -f "$default_config" ]]; then
return 0
fi
# Vérifier si la ligne existe et est à 1
if grep -q "^${backup_name}=1" "$default_config"; then
return 0 # Activée
else
return 1 # Désactivée ou commentée
fi
}
# --- VÉRIFICATIONS PRÉ-DÉMARRAGE ---
# Configuration pour exécution web
configure_web_environment() {
if [[ "$(whoami)" == "www-data" ]]; then
log_info "Configuration de l'environnement web détectée..."
# Adapter les répertoires si nécessaire
if [[ ! -w "$LOG_DIR" ]]; then
LOG_DIR="/tmp/backup_logs"
mkdir -p "$LOG_DIR"
LOG_FILE="${LOG_DIR}/sauvegarde_$(date '+%Y%m%d').log"
log_info "Logs redirigés vers: $LOG_FILE"
fi
if [[ ! -w "$DEST_BASE_SAUVEGARDES" ]]; then
DEST_BASE_SAUVEGARDES="/tmp/backups"
mkdir -p "$DEST_BASE_SAUVEGARDES"
log_info "Destination adaptée vers: $DEST_BASE_SAUVEGARDES"
# Recalculer tous les chemins de destination
DEST_MAIN_DOCS_ERIC="$DEST_BASE_SAUVEGARDES/SDocumentsPcEric/"
DEST_INCR_BASE_DOCS_ERIC="$DEST_BASE_SAUVEGARDES/incremental-SDocumentsPcEric/"
DEST_MAIN_DOCS_FANOU="$DEST_BASE_SAUVEGARDES/SDocumentsPcFanou/"
DEST_INCR_BASE_DOCS_FANOU="$DEST_BASE_SAUVEGARDES/incremental-SDocumentsPcFanou/"
DEST_MAIN_DOCS_PORTABLE_FANOU="$DEST_BASE_SAUVEGARDES/SDocumentsPortableFanou/"
DEST_INCR_BASE_DOCS_PORTABLE_FANOU="$DEST_BASE_SAUVEGARDES/incremental-SDocumentsPortableFanou/"
DEST_MAIN_DOCS_COMMUNS="$DEST_BASE_SAUVEGARDES/SvmDocumentsCommunsVM/"
DEST_INCR_BASE_DOCS_COMMUNS="$DEST_BASE_SAUVEGARDES/incremental-SDocumentsCommunsVM/"
DEST_MAIN_PHOTOS="$DEST_BASE_SAUVEGARDES/SPhotosVM/"
DEST_INCR_BASE_PHOTOS="$DEST_BASE_SAUVEGARDES/incremental-SPhotosVM/"
DEST_MAIN_IMAGES="$DEST_BASE_SAUVEGARDES/SImagesVM/"
DEST_INCR_BASE_IMAGES="$DEST_BASE_SAUVEGARDES/incremental-SImagesVM/"
DEST_MAIN_MUSIQUES="$DEST_BASE_SAUVEGARDES/SMusiquesVM/"
DEST_INCR_BASE_MUSIQUES="$DEST_BASE_SAUVEGARDES/incremental-SMusiquesVM/"
DEST_MAIN_PROJETS="$DEST_BASE_SAUVEGARDES/SProjetsServeur/"
DEST_INCR_BASE_PROJETS="$DEST_BASE_SAUVEGARDES/incremental-SProjetsServeur/"
fi
# Créer les points de montage SSHFS
mkdir -p /tmp/sshfs_mounts/{docs_eric,docs_fanou,docs_portable_fanou,docs_communs_vm,photos_vm,images_vm,musiques_vm,projets_serveur}
# Configurer l'environnement SSH
export HOME="/var/www"
fi
}
# Appeler la configuration web
configure_web_environment
# Vérifie que le répertoire de log est bien accessible en écriture
verifier_permissions_log_dir
# Initialisation de LOG_FILE avec le format journalier
# shellcheck disable=SC2154 # LOG_DIR est défini dans config.sh
LOG_FILE="${LOG_DIR}/sauvegarde_$(date '+%Y%m%d').log"
# Vérification initiale des chemins des exécutables critiques
# Ceci complète les vérifications 'command -v' des fonctions_erreur.sh
verifier_chemin_executables() {
local exec_name
local exec_path
local missing_execs=0
# shellcheck disable=SC2154 # Toutes ces variables sont définies dans config.sh
for exec_var in CHEMIN_RSYNC CHEMIN_SSH CHEMIN_SSHFS CHEMIN_FUSEMOUNT CHEMIN_MOUNTPOINT CHEMIN_LSOF CHEMIN_KILL CHEMIN_MKDIR CHEMIN_MAIL; do
eval "exec_path=\"\$$exec_var\"" # Récupère la valeur de la variable
exec_name="${exec_var//CHEMIN_/}" # Extrait le nom de la commande (ex: RSYNC)
if [[ -n "$exec_path" ]]; then # Si un chemin est explicitement défini
if [[ ! -x "$exec_path" ]]; then
log_error "L'exécutable configuré pour $exec_name ('$exec_path') n'existe pas ou n'est pas exécutable."
missing_execs=$((missing_execs + 1))
fi
else # Si aucun chemin n'est défini, vérifie dans le PATH
if ! command -v "$(echo "$exec_name" | tr '[:upper:]' '[:lower:]')" >/dev/null 2>&1; then
log_error "La commande '${exec_name,,}' n'a pas été trouvée dans le PATH."
missing_execs=$((missing_execs + 1))
fi
fi
done
if [[ "$missing_execs" -gt 0 ]]; then
diagnostiquer_et_logger_erreur 127 "Certaines dépendances logicielles essentielles sont manquantes ou incorrectement configurées."
fi
}
verifier_chemin_executables
# --- Initialisation des variables de suivi ---
sauvegardes_reussies=0
sauvegardes_echouees=0
nombre_sauvegardes=0
SAUVEGARDES_A_TRAITER=() # Tableau pour stocker les sélections à traiter
# --- Traitement des arguments de la ligne de commande ---
DRY_RUN=0
LIST_MODE=0
# Fonction d'affichage de l'aide
afficher_aide() {
echo "Utilisation : $0 [--dry-run] [--list] [selection... | all]"
echo ""
echo "Arguments :"
echo " selection : Nom d'une sauvegarde à exécuter (ex: docs_eric photos_vm)."
echo " all : Exécute toutes les sauvegardes définies dans config.sh."
echo ""
echo "Options :"
echo " --dry-run : Simule le processus de sauvegarde sans effectuer de modifications réelles."
echo " --list : Affiche la liste des sélections de sauvegarde disponibles et quitte."
echo " --help, -h : Affiche cette aide."
echo ""
echo "Exemples :"
echo " $0 all"
echo " $0 docs_eric photos_vm"
echo " $0 --dry-run docs_eric"
echo " $0 --list"
exit 0
}
# Analyse les arguments
for arg in "$@"; do
case "$arg" in
--dry-run)
DRY_RUN=1
log_info "Mode 'dry-run' activé : aucune modification ne sera effectuée."
;;
--list)
LIST_MODE=1
;;
--help|-h)
afficher_aide
;;
*)
SAUVEGARDES_A_TRAITER+=("$arg")
;;
esac
done
# Si --list est activé, affiche les sélections et quitte
if [[ "$LIST_MODE" -eq 1 ]]; then
echo "Sélections de sauvegarde disponibles :"
echo ""
echo "Sauvegardes par défaut :"
for backup in docs_eric docs_fanou photos_vm projets_serveur docs_portable; do
if is_default_backup_enabled "$backup"; then
echo " ✅ $backup (activée)"
else
echo " ❌ $backup (désactivée)"
fi
done
echo ""
echo "Sauvegardes personnalisées :"
if [[ -f "$SCRIPT_DIR/sauvegardes_custom.conf" ]]; then
grep "# SAUVEGARDE:" "$SCRIPT_DIR/sauvegardes_custom.conf" | sed 's/# SAUVEGARDE: / ✅ /' | sed 's/$/ (personnalisée)/'
else
echo " Aucune sauvegarde personnalisée configurée"
fi
echo ""
exit 0
fi
# Si aucune sélection n'est spécifiée en ligne de commande, utilise DEFAULT_SELECTIONS_SAUVEGARDES
if [[ ${#SAUVEGARDES_A_TRAITER[@]} -eq 0 ]]; then
# shellcheck disable=SC2154 # DEFAULT_SELECTIONS_SAUVEGARDES est défini dans config.sh
read -r -a SAUVEGARDES_A_TRAITER <<< "$DEFAULT_SELECTIONS_SAUVEGARDES"
fi
# Si "all" est spécifié, liste toutes les sauvegardes connues
if [[ " ${SAUVEGARDES_A_TRAITER[*]} " =~ " all " ]]; then
SAUVEGARDES_A_TRAITER=(
"docs_eric"
"docs_fanou"
"docs_portable_fanou" # Correction du nom de la sélection
"docs_communs_vm"
"photos_vm"
"images_vm"
"musiques_vm"
"projets_serveur" # Correction du nom de la sélection
)
fi
# --- FONCTIONS UTILES ---
# Fonction pour traiter les sauvegardes personnalisées
traiter_sauvegarde_personnalisee() {
local nom_sauvegarde="$1"
local nom_upper=$(echo "$nom_sauvegarde" | tr '[:lower:]' '[:upper:]')
# Vérifier si les variables existent
local source_locale_var="SOURCE_LOCALE_${nom_upper}"
local source_dist_var="SOURCE_DIST_${nom_upper}"
if [[ -n "${!source_locale_var:-}" ]]; then
# Sauvegarde locale personnalisée
log_info "Traitement de la sauvegarde locale personnalisée '$nom_sauvegarde'..."
local dest_main_var="DEST_MAIN_${nom_upper}"
local dest_incr_var="DEST_INCR_BASE_${nom_upper}"
if effectuer_sauvegarde "locale" \
"${!source_locale_var}" \
"${!dest_main_var}" \
"${!dest_incr_var}" \
"" "" "" ""; then
sauvegardes_reussies=$((sauvegardes_reussies + 1))
# Nettoyage si configuré
if [[ "$DRY_RUN" -eq 0 ]]; then
local ret_q_var="JOURS_RETENTION_${nom_upper}_QUOTIDIEN"
local ret_h_var="JOURS_RETENTION_${nom_upper}_HEBDO"
local ret_m_var="JOURS_RETENTION_${nom_upper}_MENSUEL"
if [[ "${!ret_q_var:-0}" -gt 0 || "${!ret_h_var:-0}" -gt 0 || "${!ret_m_var:-0}" -gt 0 ]]; then
nettoyer_anciennes_sauvegardes \
"${!dest_incr_var}" \
"${!ret_q_var:-7}" \
"${!ret_h_var:-4}" \
"${!ret_m_var:-12}"
fi
fi
else
sauvegardes_echouees=$((sauvegardes_echouees + 1))
fi
return 0
elif [[ -n "${!source_dist_var:-}" ]]; then
# Sauvegarde distante personnalisée
log_info "Traitement de la sauvegarde distante personnalisée '$nom_sauvegarde'..."
local ssh_user_var="SSH_USER_${nom_upper}"
local ssh_ip_var="SSH_IP_${nom_upper}"
local ssh_port_var="SSH_PORT_${nom_upper}"
local montage_var="MONTAGE_SSHFS_${nom_upper}"
local dest_main_var="DEST_MAIN_${nom_upper}"
local dest_incr_var="DEST_INCR_BASE_${nom_upper}"
if effectuer_sauvegarde "distante" \
"${!source_dist_var}" \
"${!dest_main_var}" \
"${!dest_incr_var}" \
"${!ssh_user_var}" \
"${!ssh_ip_var}" \
"${!ssh_port_var:-22}" \
"${!montage_var}"; then
sauvegardes_reussies=$((sauvegardes_reussies + 1))
# Nettoyage si configuré
if [[ "$DRY_RUN" -eq 0 ]]; then
local ret_q_var="JOURS_RETENTION_${nom_upper}_QUOTIDIEN"
local ret_h_var="JOURS_RETENTION_${nom_upper}_HEBDO"
local ret_m_var="JOURS_RETENTION_${nom_upper}_MENSUEL"
if [[ "${!ret_q_var:-0}" -gt 0 || "${!ret_h_var:-0}" -gt 0 || "${!ret_m_var:-0}" -gt 0 ]]; then
nettoyer_anciennes_sauvegardes \
"${!dest_incr_var}" \
"${!ret_q_var:-7}" \
"${!ret_h_var:-4}" \
"${!ret_m_var:-12}"
fi
fi
else
sauvegardes_echouees=$((sauvegardes_echouees + 1))
fi
return 0
fi
# Sauvegarde non trouvée
return 1
}
# Fonction pour gérer le verrouillage du script
gerer_verrouillage() {
# shellcheck disable=SC2154 # ACTIVERLOCK, PID_FILE sont définis dans config.sh
if [[ "$ACTIVERLOCK" -eq 1 ]]; then
if [[ -f "$PID_FILE" ]] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
log_error "Le script est déjà en cours d'exécution. PID : $(cat "$PID_FILE")."
diagnostiquer_et_logger_erreur 10 "Script déjà en cours d'exécution."
fi
echo "$$" > "$PID_FILE"
log_info "Fichier de verrouillage créé : $(cat "$PID_FILE")"
trap "rm -f '$PID_FILE'; log_info 'Fichier de verrouillage supprimé.' ; exit" EXIT SIGINT SIGTERM
fi
}
# Fonction pour envoyer le rapport par email
envoyer_rapport_email() {
local sujet="$1"
local corps="$2"
# shellcheck disable=SC2154 # EMAIL_NOTIFICATION, CHEMIN_MAIL sont définis dans config.sh
if [[ -n "$EMAIL_NOTIFICATION" ]]; then
local mail_cmd="${CHEMIN_MAIL:-mailx}" # Utilise CHEMIN_MAIL si défini, sinon 'mailx'
if ! command -v "$mail_cmd" >/dev/null 2>&1; then
log_error "La commande '$mail_cmd' pour envoyer des e-mails n'a pas été trouvée. Impossible d'envoyer le rapport."
diagnostiquer_et_logger_erreur 127 "Dépendance manquante: $mail_cmd (pour envoi d'email)."
return 1 # Ne quitte pas complètement le script, mais signale l'échec d'envoi.
fi
echo "$corps" | "$mail_cmd" -s "$sujet" "$EMAIL_NOTIFICATION"
if [[ $? -ne 0 ]]; then
log_error "Échec de l'envoi de l'e-mail de notification. Vérifiez la configuration du MTA."
diagnostiquer_et_logger_erreur 15 "Échec de l'envoi d'e-mail."
return 1
else
log_info "Rapport envoyé par email à $EMAIL_NOTIFICATION."
return 0
fi
else
log_info "Notification par e-mail désactivée (EMAIL_NOTIFICATION non défini dans config.sh)."
return 0
fi
}
# Fonction pour vérifier l'espace disque
verifier_espace_disque() {
local chemin="$1"
local min_espace="$2" # en Go
if [[ "$min_espace" -eq 0 ]]; then
log_info "Vérification d'espace disque désactivée (ESPACE_DISQUE_MIN_GO=0)."
return 0
fi
local espace_disque_libre
# Utilise 'df -BG' pour obtenir l'espace en GigaBytes et extrait la valeur numérique.
espace_disque_libre=$(df -BG "$chemin" | awk 'NR==2 {print $4}' | sed 's/G//')
if [[ -z "$espace_disque_libre" || ! "$espace_disque_libre" =~ ^[0-9]+$ ]]; then
log_error "Impossible de déterminer l'espace disque libre pour '$chemin'. Vérifiez le chemin ou les permissions."
return 1 # Laisse le script continuer mais log l'erreur
fi
log_info "Espace disque libre sur '$chemin' : ${espace_disque_libre} Go (minimum requis : ${min_espace} Go)."
if (( espace_disque_libre < min_espace )); then
log_error "Espace disque insuffisant sur la destination '$chemin'. Libre: ${espace_disque_libre} Go, Requis: ${min_espace} Go."
diagnostiquer_et_logger_erreur 4 "Espace disque insuffisant sur la destination."
fi
return 0
}
# Fonction pour nettoyer les anciennes sauvegardes
# Note: Cette fonction est un exemple basique et devrait être robuste.
nettoyer_anciennes_sauvegardes() {
local base_chemin_incr="$1"
local retention_quotidien="$2"
local retention_hebdo="$3"
local retention_mensuel="$4"
log_info "Démarrage du nettoyage des anciennes sauvegardes pour $base_chemin_incr..."
# Check if the base incremental path exists
if [[ ! -d "$base_chemin_incr" ]]; then
log_warning "Chemin de base incrémental '$base_chemin_incr' n'existe pas. Pas de nettoyage effectué."
return 0
fi
# Supprimer les liens symboliques brisés dans 'latest' et 'current'
find "$base_chemin_incr" -maxdepth 1 -type l ! -exec test -e {} \; -delete 2>/dev/null
log_info "Nettoyage des liens symboliques brisés dans $base_chemin_incr effectué."
# Suppression des sauvegardes quotidiennes (plus anciennes que $retention_quotidien jours)
if [[ "$retention_quotidien" -gt 0 ]]; then
# Exclure 'current', 'latest', 'weekly', 'monthly' des suppressions quotidiennes
find "$base_chemin_incr" -maxdepth 1 -type d -name "daily-*" -mtime +"$retention_quotidien" \
-not -path "*/current" -not -path "*/latest" \
-exec rm -rf {} + 2>/dev/null
log_info "Suppression des sauvegardes quotidiennes plus anciennes que $retention_quotidien jours."
fi
# Gestion des sauvegardes hebdomadaires
if [[ "$retention_hebdo" -gt 0 ]]; then
local weekly_dir="$base_chemin_incr/weekly"
local weekly_count=$(find "$weekly_dir" -maxdepth 1 -type d -name "weekly-*" | wc -l)
if [[ "$weekly_count" -gt "$retention_hebdo" ]]; then
find "$weekly_dir" -maxdepth 1 -type d -name "weekly-*" | sort | head -n "$((weekly_count - retention_hebdo))" | xargs -r rm -rf 2>/dev/null
log_info "Nettoyage des sauvegardes hebdomadaires: ${weekly_count} -> ${retention_hebdo} versions conservées."
fi
fi
# Gestion des sauvegardes mensuelles
if [[ "$retention_mensuel" -gt 0 ]]; then
local monthly_dir="$base_chemin_incr/monthly"
local monthly_count=$(find "$monthly_dir" -maxdepth 1 -type d -name "monthly-*" | wc -l)
if [[ "$monthly_count" -gt "$retention_mensuel" ]]; then
find "$monthly_dir" -maxdepth 1 -type d -name "monthly-*" | sort | head -n "$((monthly_count - retention_mensuel))" | xargs -r rm -rf 2>/dev/null
log_info "Nettoyage des sauvegardes mensuelles: ${monthly_count} -> ${retention_mensuel} versions conservées."
fi
fi
log_info "Nettoyage des anciennes sauvegardes pour $base_chemin_incr terminé."
return 0
}
# --- FONCTION PRINCIPALE DE SAUVEGARDE ---
effectuer_sauvegarde() {
local type_sauvegarde="$1" # "locale" ou "distante"
local source_path="$2"
local dest_main_path="$3"
local dest_incr_base_path="$4" # Chemin pour les incrémentales (avec daily, weekly, monthly)
local ssh_user="$5"
local ssh_ip="$6"
local ssh_port="$7"
local montage_sshfs_point="$8" # Point de montage local pour SSHFS
local date_courante=$(date '+%Y-%m-%d_%H%M%S')
local dest_courante="$dest_incr_base_path/daily-${date_courante}"
local dest_precedente="$dest_incr_base_path/current"
log_info "Démarrage de la sauvegarde $type_sauvegarde pour '$source_path' vers '$dest_main_path'."
# Vérification de la source
valider_variable "Source de sauvegarde" "$source_path" "path"
if [[ $? -ne 0 ]]; then diagnostiquer_et_logger_erreur 13 "Source invalide: $source_path"; fi
# Vérification et création des répertoires de destination si nécessaire
# shellcheck disable=SC2154 # CHEMIN_MKDIR est défini dans config.sh
local mkdir_cmd="${CHEMIN_MKDIR:-mkdir}"
if [[ ! -d "$dest_main_path" ]]; then
log_info "Création du répertoire de destination principal : $dest_main_path"
if ! "$mkdir_cmd" -p "$dest_main_path"; then
log_error "Impossible de créer le répertoire de destination principal $dest_main_path."
diagnostiquer_et_logger_erreur 12 "Échec de création du répertoire principal."
fi
fi
if [[ ! -d "$dest_incr_base_path" ]]; then
log_info "Création du répertoire de base incrémentale : $dest_incr_base_path"
if ! "$mkdir_cmd" -p "$dest_incr_base_path"; then
log_error "Impossible de créer le répertoire de base incrémentale $dest_incr_base_path."
diagnostiquer_et_logger_erreur 12 "Échec de création du répertoire incrémental."
fi
fi
# Vérifier l'espace disque sur la DEST_BASE_SAUVEGARDES (où sont stockées toutes les sauvegardes)
# shellcheck disable=SC2154 # ESPACE_DISQUE_MIN_GO est défini dans config.sh
verifier_espace_disque "$DEST_BASE_SAUVEGARDES" "$ESPACE_DISQUE_MIN_GO"
local rsync_options="$DEFAULT_RSYNC_OPTIONS"
# shellcheck disable=SC2154 # RSYNC_DELETE est défini dans config.sh
if [[ "$RSYNC_DELETE" -eq 1 ]]; then
rsync_options+=" --delete"
log_info "Option rsync --delete activée."
fi
# Rsync command setup
local rsync_cmd="${CHEMIN_RSYNC:-rsync}" # Utilise CHEMIN_RSYNC si défini, sinon 'rsync'
if ! command -v "$rsync_cmd" >/dev/null 2>&1; then
log_error "La commande 'rsync' (ou chemin configuré: '$CHEMIN_RSYNC') n'a pas été trouvée dans le PATH. Impossible de procéder à la sauvegarde."
diagnostiquer_et_logger_erreur 127 "Dépendance manquante: rsync."
fi
local rsync_full_command=()
local rsync_exit_code=0
# shellcheck disable=SC2154 # DEFAULT_TYPE_CONNEXION_DISTANTE est défini dans config.sh
if [[ "$DEFAULT_TYPE_CONNEXION_DISTANTE" -eq 0 ]]; then # Mode SSHFS
local local_source="$source_path" #local local_source="$source_path" # Pour rsync, la source est le chemin distant MONTÉ localement.
# Vérifie si le point de montage existe et est bien un répertoire
valider_variable "Point de montage SSHFS" "$montage_sshfs_point" "path"
if [[ $? -ne 0 ]]; then diagnostiquer_et_logger_erreur 13 "Point de montage SSHFS invalide: $montage_sshfs_point"; fi
# Montage SSHFS
monter_sshfs "$ssh_user" "$ssh_ip" "$ssh_port" "$source_path" "$montage_sshfs_point"
local_source="$montage_sshfs_point" # La source de rsync devient le point de montage local
# Vérifier si le point de montage est vide ou inaccessible après montage
if ! find "$local_source" -mindepth 1 -print -quit | grep -q .; then
log_warning "Le point de montage SSHFS '$local_source' semble vide ou inaccessible après le montage. La sauvegarde pourrait ne rien transférer."
# Ne pas diagnostiquer comme une erreur fatale ici, car le dossier distant PEUT être vide.
# L'erreur 13 est plus pour "source inexistante avant même de tenter un montage"
fi
rsync_full_command+=("$rsync_cmd")
rsync_full_command+=("-azP") # Forcer le mode archive avec progression pour le montage local
rsync_full_command+=("$rsync_options") # Ajoute les options par défaut, y compris les exclusions si présentes
# shellcheck disable=SC2154 # OPTIONS_RSYNC_INCREMENTALE est défini dans config.sh
if [[ -d "$dest_precedente" ]]; then
rsync_full_command+=("${OPTIONS_RSYNC_INCREMENTALE:-}") # Ajoute --link-dest=../current si 'current' existe
fi
rsync_full_command+=("--exclude='${dest_incr_base_path##*/}/'") # Exclut le dossier incrémental lui-même si il est imbriqué
rsync_full_command+=("$local_source/") # Source avec slash final pour synchroniser le contenu
rsync_full_command+=("$dest_courante")
elif [[ "$DEFAULT_TYPE_CONNEXION_DISTANTE" -eq 1 ]]; then # Mode SSH direct (rsync via SSH)
# Vérifier la connectivité SSH et le chemin distant avant rsync
verifier_connexion_ssh "$ssh_user" "$ssh_ip" "$ssh_port"
verifier_chemin_distant_ssh "$ssh_user" "$ssh_ip" "$ssh_port" "$source_path"
local ssh_cmd="${CHEMIN_SSH:-ssh}" # Utilise CHEMIN_SSH si défini, sinon 'ssh'
# shellcheck disable=SC2154 # OPTIONS_COMMUNES_SSH, StrictHostKeyChecking_SSH sont définis dans config.sh
local ssh_strict_host_key_opt=""
if [[ -n "${StrictHostKeyChecking_SSH}" ]]; then
ssh_strict_host_key_opt="-o StrictHostKeyChecking=${StrictHostKeyChecking_SSH}"
fi
local ssh_command_options="${OPTIONS_COMMUNES_SSH:-} ${ssh_strict_host_key_opt}"
rsync_full_command+=("$rsync_cmd")
rsync_full_command+=("$rsync_options") # Options par défaut
# shellcheck disable=SC2154 # OPTIONS_RSYNC_INCREMENTALE est défini dans config.sh
if [[ -d "$dest_precedente" ]]; then
rsync_full_command+=("${OPTIONS_RSYNC_INCREMENTALE:-}") # Ajoute --link-dest=../current si 'current' existe
fi
rsync_full_command+=(-e "$ssh_cmd -p $ssh_port ${ssh_command_options}") # Spécifie SSH comme transport
rsync_full_command+=("$ssh_user@$ssh_ip:$source_path/") # Source distante avec slash final
rsync_full_command+=("$dest_courante")
else # Mode local
rsync_full_command+=("$rsync_cmd")
rsync_full_command+=("$rsync_options") # Options par défaut
# shellcheck disable=SC2154 # OPTIONS_RSYNC_INCREMENTALE est défini dans config.sh
if [[ -d "$dest_precedente" ]]; then
rsync_full_command+=("${OPTIONS_RSYNC_INCREMENTALE:-}") # Ajoute --link-dest=../current si 'current' existe
fi
rsync_full_command+=("$source_path/") # Source locale avec slash final
rsync_full_command+=("$dest_courante")
fi
log_info "Commande Rsync à exécuter : ${rsync_full_command[*]}"
if [[ "$DRY_RUN" -eq 1 ]]; then
log_info "DRY-RUN: Simulation de rsync. La commande ne sera pas exécutée."
# Simuler un succès pour le dry-run pour que le script puisse continuer et rapporter succès
rsync_exit_code=0
else
# Exécution de la commande rsync avec un timeout si configuré
# shellcheck disable=SC2154 # DELAI_OPERATION_RSYNC_SECONDES est défini dans config.sh
if [[ "$DELAI_OPERATION_RSYNC_SECONDES" -gt 0 ]]; then
log_info "Exécution de rsync avec un timeout de ${DELAI_OPERATION_RSYNC_SECONDES} secondes."
timeout "${DELAI_OPERATION_RSYNC_SECONDES}s" "${rsync_full_command[@]}"
rsync_exit_code=$?
else
log_info "Exécution de rsync (sans timeout)."
"${rsync_full_command[@]}"
rsync_exit_code=$?
fi
fi
if [[ "$rsync_exit_code" -eq 0 ]]; then
log_info "Sauvegarde réussie de '$source_path' vers '$dest_courante'."
if [[ "$DRY_RUN" -eq 0 ]]; then
# Mettre à jour le lien 'current' vers la nouvelle sauvegarde réussie
rm -f "$dest_precedente" # Supprime l'ancien lien
ln -s "${dest_courante##*/}" "$dest_precedente" # Crée le nouveau lien symbolique
log_info "Lien 'current' mis à jour vers '$dest_courante'."
fi
return 0
else
log_error "La sauvegarde de '$source_path' a échoué avec le code de sortie rsync: $rsync_exit_code."
diagnostiquer_et_logger_erreur 9 "Erreur rsync lors de la sauvegarde de '$source_path'. Code: $rsync_exit_code."
return 1
fi
}
# --- DÉBUT DU SCRIPT PRINCIPAL ---
# Gérer le verrouillage du script
gerer_verrouillage
# Exécuter le script PRE_SAUVEGARDE_GLOBAL si défini
# shellcheck disable=SC2154 # SCRIPT_PRE_SAUVEGARDE_GLOBAL est défini dans config.sh
if [[ -n "$SCRIPT_PRE_SAUVEGARDE_GLOBAL" ]]; then
if [[ -x "$SCRIPT_PRE_SAUVEGARDE_GLOBAL" ]]; then
log_info "Exécution du script de pré-sauvegarde global : $SCRIPT_PRE_SAUVEGARDE_GLOBAL"
if ! "$SCRIPT_PRE_SAUVEGARDE_GLOBAL"; then
log_warning "Le script de pré-sauvegarde global a échoué. La sauvegarde continuera."
fi
else
log_warning "Le script de pré-sauvegarde global '$SCRIPT_PRE_SAUVEGARDE_GLOBAL' n'existe pas ou n'est pas exécutable."
fi
fi
# Créer le flag de démarrage
touch /tmp/backup_running.flag
echo "$(date '+%Y-%m-%d %H:%M:%S')" > /tmp/backup_start_time.txt
echo "0" > /tmp/backup_progress.txt
log_info "=== DÉBUT DES SAUVEGARDES ==="
log_info "Sélections à traiter : ${SAUVEGARDES_A_TRAITER[*]}"
nombre_sauvegardes=${#SAUVEGARDES_A_TRAITER[@]}
current_index=0
# Boucle principale de traitement des sélections
for i in "${SAUVEGARDES_A_TRAITER[@]}"; do
# Vérifier si c'est une sauvegarde par défaut désactivée
case "$i" in
docs_eric|docs_fanou|docs_portable_fanou|docs_communs_vm|photos_vm|images_vm|musiques_vm|projets_serveur)
if ! is_default_backup_enabled "$i"; then
log_info "Sauvegarde '$i' désactivée dans default_backups.conf, ignorée"
continue
fi
;;
esac
# Mettre à jour le statut
echo "$i" > /tmp/current_backup.txt
progress=$((current_index * 100 / nombre_sauvegardes))
echo "$progress" > /tmp/backup_progress.txt
current_index=$((current_index + 1))
case "$i" in
docs_eric)
log_info "Traitement de la sauvegarde 'Docs Eric'..."
# shellcheck disable=SC2154 # Variables sont définies dans config.sh
if effectuer_sauvegarde "locale" \
"$SOURCE_LOCALE_DOCS_ERIC" \
"$DEST_MAIN_DOCS_ERIC" \
"$DEST_INCR_BASE_DOCS_ERIC" \
"" "" "" ""; then # Pas de SSH pour une sauvegarde locale
sauvegardes_reussies=$((sauvegardes_reussies + 1))
# shellcheck disable=SC2154 # DEFAULT_MODE_INCREMENTAL n'existe pas, utiliser la présence de DEST_INCR_BASE_DOCS_ERIC
if [[ -n "$DEST_INCR_BASE_DOCS_ERIC" && "$DRY_RUN" -eq 0 ]]; then
# shellcheck disable=SC2154 # Jours de rétention sont définis dans config.sh
if [[ "$JOURS_RETENTION_DOCS_ERIC_QUOTIDIEN" -gt 0 || "$JOURS_RETENTION_DOCS_ERIC_HEBDO" -gt 0 || "$JOURS_RETENTION_DOCS_ERIC_MENSUEL" -gt 0 ]]; then
nettoyer_anciennes_sauvegardes \
"$DEST_INCR_BASE_DOCS_ERIC" \
"$JOURS_RETENTION_DOCS_ERIC_QUOTIDIEN" \
"$JOURS_RETENTION_DOCS_ERIC_HEBDO" \
"$JOURS_RETENTION_DOCS_ERIC_MENSUEL"
fi
fi
else
sauvegardes_echouees=$((sauvegardes_echouees + 1))
fi
;;
docs_fanou)
log_info "Traitement de la sauvegarde 'Docs Fanou'..."
# shellcheck disable=SC2154 # Variables sont définies dans config.sh
if effectuer_sauvegarde "locale" \
"$SOURCE_LOCALE_DOCS_FANOU" \
"$DEST_MAIN_DOCS_FANOU" \
"$DEST_INCR_BASE_DOCS_FANOU" \
"" "" "" ""; then # Pas de SSH pour une sauvegarde locale
sauvegardes_reussies=$((sauvegardes_reussies + 1))
# shellcheck disable=SC2154 # DEFAULT_MODE_INCREMENTAL n'existe pas, utiliser la présence de DEST_INCR_BASE_DOCS_FANOU
if [[ -n "$DEST_INCR_BASE_DOCS_FANOU" && "$DRY_RUN" -eq 0 ]]; then
# shellcheck disable=SC2154 # Jours de rétention sont définis dans config.sh
if [[ "$JOURS_RETENTION_DOCS_FANOU_QUOTIDIEN" -gt 0 || "$JOURS_RETENTION_DOCS_FANOU_HEBDO" -gt 0 || "$JOURS_RETENTION_DOCS_FANOU_MENSUEL" -gt 0 ]]; then
nettoyer_anciennes_sauvegardes \
"$DEST_INCR_BASE_DOCS_FANOU" \
"$JOURS_RETENTION_DOCS_FANOU_QUOTIDIEN" \
"$JOURS_RETENTION_DOCS_FANOU_HEBDO" \
"$JOURS_RETENTION_DOCS_FANOU_MENSUEL"
fi
fi
else
sauvegardes_echouees=$((sauvegardes_echouees + 1))
fi
;;
docs_portable_fanou) # Correction : Anciennement "musiques_portable" ou autre, maintenant "docs_portable"
log_info "Traitement de la sauvegarde 'Docs Portable Fanou'..."
# shellcheck disable=SC2154 # Variables sont définies dans config.sh
if effectuer_sauvegarde "distante" \
"$SOURCE_DIST_DOCS_PORTABLE_FANOU" \
"$DEST_MAIN_DOCS_PORTABLE_FANOU" \
"$DEST_INCR_BASE_DOCS_PORTABLE_FANOU" \
"$SSH_USER_DOCS_PORTABLE_FANOU" \
"$SSH_IP_DOCS_PORTABLE_FANOU" \
"$SSH_PORT_DOCS_PORTABLE_FANOU" \
"$MONTAGE_SSHFS_DOCS_PORTABLE_FANOU"; then # Correction: MONTAGE_SSHFS_MUSIQUES -> MONTAGE_SSHFS_DOCS_PORTABLE
sauvegardes_reussies=$((sauvegardes_reussies + 1))
# shellcheck disable=SC2154 # Utiliser la présence de DEST_INCR_BASE_DOCS_PORTABLE
if [[ -n "$DEST_INCR_BASE_DOCS_PORTABLE_FANOU" ]]; then
if [[ "$DRY_RUN" -eq 0 ]]; then
# shellcheck disable=SC2154 # Jours de rétention sont définis dans config.sh
if [[ "$JOURS_RETENTION_DOCS_PORTABLE_FANOU_QUOTIDIEN" -gt 0 || "$JOURS_RETENTION_DOCS_PORTABLE_FANOU_HEBDO" -gt 0 || "$JOURS_RETENTION_DOCS_PORTABLE_FANOU_MENSUEL" -gt 0 ]]; then
nettoyer_anciennes_sauvegardes \
"$DEST_INCR_BASE_DOCS_PORTABLE_FANOU" \
"$JOURS_RETENTION_DOCS_PORTABLE_FANOU_QUOTIDIEN" \
"$JOURS_RETENTION_DOCS_PORTABLE_FANOU_HEBDO" \
"$JOURS_RETENTION_DOCS_PORTABLE_FANOU_MENSUEL"
fi
fi
fi
else
sauvegardes_echouees=$((sauvegardes_echouees + 1))
fi
;;
*)
# Tentative de traitement d'une sauvegarde personnalisée
if traiter_sauvegarde_personnalisee "$i"; then
log_info "Sauvegarde personnalisée '$i' traitée avec succès."
else
log_warning "Valeur de sélection inconnue ignorée: $i"
diagnostiquer_et_logger_erreur 14 "Sélection de sauvegarde inconnue ou non gérée: $i."
fi
;;
docs_communs_vm) # Correction : Anciennement "musiques_portable" ou autre, maintenant "docs_portable"
log_info "Traitement de la sauvegarde 'Docs Portable Fanou'..."
# shellcheck disable=SC2154 # Variables sont définies dans config.sh
if effectuer_sauvegarde "distante" \
"$SOURCE_DIST_DOCS_COMMUNS" \
"$DEST_MAIN_DOCS_COMMUNS" \
"$DEST_INCR_BASE_DOCS_COMMUNS" \
"$SSH_USER_DOCS_COMMUNS" \
"$SSH_IP_DOCS_COMMUNS" \
"$SSH_PORT_DOCS_COMMUNS" \
"$MONTAGE_SSHFS_DOCS_COMMUNS"; then # Correction: MONTAGE_SSHFS_MUSIQUES -> MONTAGE_SSHFS_DOCS_COMMUNS
sauvegardes_reussies=$((sauvegardes_reussies + 1))
# shellcheck disable=SC2154 # Utiliser la présence de DEST_INCR_BASE_DOCS_COMMUNS
if [[ -n "$DEST_INCR_BASE_DOCS_COMMUNS" ]]; then
if [[ "$DRY_RUN" -eq 0 ]]; then
# shellcheck disable=SC2154 # Jours de rétention sont définis dans config.sh
if [[ "$JOURS_RETENTION_DOCS_COMMUNS_QUOTIDIEN" -gt 0 || "$JOURS_RETENTION_DOCS_COMMUNS_HEBDO" -gt 0 || "$JOURS_RETENTION_DOCS_COMMUNS_MENSUEL" -gt 0 ]]; then
nettoyer_anciennes_sauvegardes \
"$DEST_INCR_BASE_DOCS_COMMUNS" \
"$JOURS_RETENTION_DOCS_COMMUNS_QUOTIDIEN" \
"$JOURS_RETENTION_DOCS_COMMUNS_HEBDO" \
"$JOURS_RETENTION_DOCS_COMMUNS_MENSUEL"
fi
fi
fi
else
sauvegardes_echouees=$((sauvegardes_echouees + 1))
fi
;;
*)
# Tentative de traitement d'une sauvegarde personnalisée
if traiter_sauvegarde_personnalisee "$i"; then
log_info "Sauvegarde personnalisée '$i' traitée avec succès."
else
log_warning "Valeur de sélection inconnue ignorée: $i"
diagnostiquer_et_logger_erreur 14 "Sélection de sauvegarde inconnue ou non gérée: $i."
fi
;;
photos_vm)
log_info "Traitement de la sauvegarde 'Photos VM'..."
# shellcheck disable=SC2154 # Variables sont définies dans config.sh
if effectuer_sauvegarde "distante" \
"$SOURCE_DIST_PHOTOS_VM" \
"$DEST_MAIN_PHOTOS" \
"$DEST_INCR_BASE_PHOTOS" \
"$SSH_USER_PHOTOS" \
"$SSH_IP_PHOTOS" \
"$SSH_PORT_PHOTOS" \
"$MONTAGE_SSHFS_PHOTOS"; then
sauvegardes_reussies=$((sauvegardes_reussies + 1))
# shellcheck disable=SC2154 # DEFAULT_MODE_INCREMENTAL n'existe pas, utiliser la présence de DEST_INCR_BASE_PHOTOS
if [[ -n "$DEST_INCR_BASE_PHOTOS" && "$DRY_RUN" -eq 0 ]]; then
# shellcheck disable=SC2154 # Jours de rétention sont définis dans config.sh
if [[ "$JOURS_RETENTION_PHOTOS_VM_QUOTIDIEN" -gt 0 || "$JOURS_RETENTION_PHOTOS_VM_HEBDO" -gt 0 || "$JOURS_RETENTION_PHOTOS_VM_MENSUEL" -gt 0 ]]; then
nettoyer_anciennes_sauvegardes \
"$DEST_INCR_BASE_PHOTOS" \
"$JOURS_RETENTION_PHOTOS_VM_QUOTIDIEN" \
"$JOURS_RETENTION_PHOTOS_VM_HEBDO" \
"$JOURS_RETENTION_PHOTOS_VM_MENSUEL"
fi
fi
else
sauvegardes_echouees=$((sauvegardes_echouees + 1))
fi
;;
images_vm)
log_info "Traitement de la sauvegarde 'Images VM'..."
# shellcheck disable=SC2154 # Variables sont définies dans config.sh
if effectuer_sauvegarde "distante" \
"$SOURCE_DIST_IMAGES_VM" \
"$DEST_MAIN_IMAGES" \
"$DEST_INCR_BASE_IMAGES" \
"$SSH_USER_IMAGES" \
"$SSH_IP_IMAGES" \
"$SSH_PORT_IMAGES" \
"$MONTAGE_SSHFS_IMAGES"; then
sauvegardes_reussies=$((sauvegardes_reussies + 1))
# shellcheck disable=SC2154 # DEFAULT_MODE_INCREMENTAL n'existe pas, utiliser la présence de DEST_INCR_BASE_IMAGES
if [[ -n "$DEST_INCR_BASE_IMAGES" && "$DRY_RUN" -eq 0 ]]; then
# shellcheck disable=SC2154 # Jours de rétention sont définis dans config.sh
if [[ "$JOURS_RETENTION_IMAGES_VM_QUOTIDIEN" -gt 0 || "$JOURS_RETENTION_IMAGES_VM_HEBDO" -gt 0 || "$JOURS_RETENTION_IMAGES_VM_MENSUEL" -gt 0 ]]; then
nettoyer_anciennes_sauvegardes \
"$DEST_INCR_BASE_IMAGES" \
"$JOURS_RETENTION_IMAGES_VM_QUOTIDIEN" \
"$JOURS_RETENTION_IMAGES_VM_HEBDO" \
"$JOURS_RETENTION_IMAGES_VM_MENSUEL"
fi
fi
else
sauvegardes_echouees=$((sauvegardes_echouees + 1))
fi
;;
musiques_vm)
log_info "Traitement de la sauvegarde 'Photos VM'..."
# shellcheck disable=SC2154 # Variables sont définies dans config.sh
if effectuer_sauvegarde "distante" \
"$SOURCE_DIST_MUSIQUES_VM" \
"$DEST_MAIN_MUSIQUES" \
"$DEST_INCR_BASE_MUSIQUES" \
"$SSH_USER_MUSIQUES" \
"$SSH_IP_MUSIQUES" \
"$SSH_PORT_MUSIQUES" \
"$MONTAGE_SSHFS_MUSIQUES"; then
sauvegardes_reussies=$((sauvegardes_reussies + 1))
# shellcheck disable=SC2154 # DEFAULT_MODE_INCREMENTAL n'existe pas, utiliser la présence de DEST_INCR_BASE_MUSIQUES
if [[ -n "$DEST_INCR_BASE_MUSIQUES" && "$DRY_RUN" -eq 0 ]]; then
# shellcheck disable=SC2154 # Jours de rétention sont définis dans config.sh
if [[ "$JOURS_RETENTION_MUSIQUES_VM_QUOTIDIEN" -gt 0 || "$JOURS_RETENTION_MUSIQUES_VM_HEBDO" -gt 0 || "$JOURS_RETENTION_MUSIQUES_VM_MENSUEL" -gt 0 ]]; then
nettoyer_anciennes_sauvegardes \
"$DEST_INCR_BASE_MUSIQUES" \
"$JOURS_RETENTION_MUSIQUES_VM_QUOTIDIEN" \
"$JOURS_RETENTION_MUSIQUES_VM_HEBDO" \
"$JOURS_RETENTION_MUSIQUES_VM_MENSUEL"
fi
fi
else
sauvegardes_echouees=$((sauvegardes_echouees + 1))
fi
;;
projets_serveur) # Correction : Anciennement "images_serveur" ou autre, maintenant "projets_serveur"
log_info "Traitement de la sauvegarde 'Projets Serveur'..."
# shellcheck disable=SC2154 # Variables sont définies dans config.sh
if effectuer_sauvegarde "distante" \
"$SOURCE_DIST_PROJETS_SERVEUR" \
"$DEST_MAIN_PROJETS" \
"$DEST_INCR_BASE_PROJETS" \
"$SSH_USER_PROJETS" \
"$SSH_IP_PROJETS" \
"$SSH_PORT_PROJETS" \
"$MONTAGE_SSHFS_PROJETS"; then # Correction: MONTAGE_SSHFS_IMAGES -> MONTAGE_SSHFS_PROJETS
sauvegardes_reussies=$((sauvegardes_reussies + 1))
# shellcheck disable=SC2154 # DEFAULT_MODE_INCREMENTAL n'existe pas, utiliser la présence de DEST_INCR_BASE_PROJETS
if [[ -n "$DEST_INCR_BASE_PROJETS" && "$DRY_RUN" -eq 0 ]]; then
# shellcheck disable=SC2154 # Jours de rétention sont définis dans config.sh
if [[ "$JOURS_RETENTION_PROJETS_SERVEUR_QUOTIDIEN" -gt 0 || "$JOURS_RETENTION_PROJETS_SERVEUR_HEBDO" -gt 0 || "$JOURS_RETENTION_PROJETS_SERVEUR_MENSUEL" -gt 0 ]]; then
nettoyer_anciennes_sauvegardes \
"$DEST_INCR_BASE_PROJETS" \
"$JOURS_RETENTION_PROJETS_SERVEUR_QUOTIDIEN" \
"$JOURS_RETENTION_PROJETS_SERVEUR_HEBDO" \
"$JOURS_RETENTION_PROJETS_SERVEUR_MENSUEL"
fi
fi
else
sauvegardes_echouees=$((sauvegardes_echouees + 1))
fi
;;
esac
done
# --- RÉSUMÉ FINAL ---
log_info "=== FIN DES SAUVEGARDES ==="
log_info "Résumé :"
log_info " - Sauvegardes réussies: $sauvegardes_reussies"
log_info " - Sauvegardes échouées: $sauvegardes_echouees"
log_info " - Total des sauvegardes traitées: $nombre_sauvegardes"
local rapport_sujet=""
local rapport_corps=""
if [[ "$sauvegardes_echouees" -eq 0 && "$nombre_sauvegardes" -gt 0 ]]; then
rapport_sujet="[Sauvegarde RÉUSSIE] - Toutes les sauvegardes ont été effectuées."
rapport_corps="Le script de sauvegarde a terminé avec succès.\n"
rapport_corps+="Résumé :\n"
rapport_corps+="- Sauvegardes réussies: $sauvegardes_reussies\n"
rapport_corps+="- Sauvegardes échouées: $sauvegardes_echouees\n"
rapport_corps+="- Total des sauvegardes traitées: $nombre_sauvegardes\n"
log_info "Toutes les sauvegardes ont été effectuées avec succès."
elif [[ "$sauvegardes_echouees" -gt 0 ]]; then
rapport_sujet="[Sauvegarde ÉCHOUÉE] - Des erreurs se sont produites lors de la sauvegarde."
rapport_corps="Le script de sauvegarde a rencontré des erreurs.\n"
rapport_corps+="Veuillez consulter les journaux pour plus de détails sur les erreurs spécifiques.\n"
rapport_corps+="Résumé :\n"
rapport_corps+="- Sauvegardes réussies: $sauvegardes_reussies\n"
rapport_corps+="- Sauvegardes échouées: $sauvegardes_echouees\n"
rapport_corps+="- Total des sauvegardes traitées: $nombre_sauvegardes\n"
log_error "Des erreurs se sont produites lors de la sauvegarde. Veuillez vérifier les logs."
else
rapport_sujet="[Sauvegarde INCOMPLÈTE] - Aucune sauvegarde n'a été traitée."
rapport_corps="Le script de sauvegarde n'a traité aucune sélection.\n"
rapport_corps+="Vérifiez les arguments passés au script ou DEFAULT_SELECTIONS_SAUVEGARDES dans config.sh.\n"
log_warning "Aucune sauvegarde n'a été traitée. Vérifiez la configuration ou les arguments."
fi
# Envoyer le rapport par email
# shellcheck disable=SC2154 # EMAIL_NOTIFICATION est défini dans config.sh
if [[ -n "$EMAIL_NOTIFICATION" ]]; then
envoyer_rapport_email "$rapport_sujet" "$rapport_corps"
fi
# Exécuter le script POST_SAUVEGARDE_GLOBAL si défini
# shellcheck disable=SC2154 # SCRIPT_POST_SAUVEGARDE_GLOBAL est défini dans config.sh
if [[ -n "$SCRIPT_POST_SAUVEGARDE_GLOBAL" ]]; then
if [[ -x "$SCRIPT_POST_SAUVEGARDE_GLOBAL" ]]; then
log_info "Exécution du script de post-sauvegarde global : $SCRIPT_POST_SAUVEGARDE_GLOBAL"
if ! "$SCRIPT_POST_SAUVEGARDE_GLOBAL"; then
log_warning "Le script de post-sauvegarde global a échoué. Le script continuera."
fi
else
log_warning "Le script de post-sauvegarde global '$SCRIPT_POST_SAUVEGARDE_GLOBAL' n'existe pas ou n'est pas exécutable."
fi
fi
# Nettoyer les fichiers de statut
rm -f /tmp/backup_running.flag /tmp/current_backup.txt /tmp/backup_progress.txt /tmp/backup_start_time.txt
# Enregistrer le résultat final
if [[ "$sauvegardes_echouees" -eq 0 ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - Toutes les sauvegardes réussies" > /tmp/last_success.txt
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - $sauvegardes_echouees sauvegarde(s) échouée(s)" > /tmp/last_error.txt
fi
log_info "Script de sauvegarde terminé."
# Si aucune erreur grave n'a été rencontrée, exit 0
if [[ "$sauvegardes_echouees" -eq 0 ]]; then
exit 0
else
# Si des sauvegardes ont échoué, sortir avec un code d'erreur général (par exemple 1)
# Les erreurs spécifiques auront déjà causé un exit plus tôt. Ceci est un fallback.
exit 1
fi
le shellcheck ne me renseigne pas beaucoup plus
$ shellcheck myscript
Line 43:
source "$SCRIPT_DIR/config.sh"
^-- SC1091 (info): Not following: ./config.sh was not specified as input (see shellcheck -x).
Line 49:
source "/tmp/sauvegardes_active.conf"
^-- SC1091 (info): Not following: /tmp/sauvegardes_active.conf was not specified as input (see shellcheck -x).
Line 52:
source "$SCRIPT_DIR/fonctions_erreur.sh"
^-- SC1091 (info): Not following: ./fonctions_erreur.sh was not specified as input (see shellcheck -x).
Line 261:
local nom_upper=$(echo "$nom_sauvegarde" | tr '[:lower:]' '[:upper:]')
^-- SC2155 (warning): Declare and assign separately to avoid masking return values.
Line 353:
trap "rm -f '$PID_FILE'; log_info 'Fichier de verrouillage supprimé.' ; exit" EXIT SIGINT SIGTERM
^-- SC2064 (warning): Use single quotes, otherwise this expands now rather than when signalled.
Line 371:
if [[ $? -ne 0 ]]; then
^-- SC2181 (style): Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?.
Line 445:
local weekly_count=$(find "$weekly_dir" -maxdepth 1 -type d -name "weekly-*" | wc -l)
^-- SC2155 (warning): Declare and assign separately to avoid masking return values.
Line 455:
local monthly_count=$(find "$monthly_dir" -maxdepth 1 -type d -name "monthly-*" | wc -l)
^-- SC2155 (warning): Declare and assign separately to avoid masking return values.
Line 477:
local date_courante=$(date '+%Y-%m-%d_%H%M%S')
^-- SC2155 (warning): Declare and assign separately to avoid masking return values.
Line 485:
if [[ $? -ne 0 ]]; then diagnostiquer_et_logger_erreur 13 "Source invalide: $source_path"; fi
^-- SC2181 (style): Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?.
Line 532:
if [[ $? -ne 0 ]]; then diagnostiquer_et_logger_erreur 13 "Point de montage SSHFS invalide: $montage_sshfs_point"; fi
^-- SC2181 (style): Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?.
Line 646:
echo "$(date '+%Y-%m-%d %H:%M:%S')" > /tmp/backup_start_time.txt
^-- SC2005 (style): Useless echo? Instead of 'echo $(cmd)', just use 'cmd'.
Line 753:
*)
^-- SC2221 (warning): This pattern always overrides a later one on line 763.
Line 763:
docs_communs_vm) # Correction : Anciennement "musiques_portable" ou autre, maintenant "docs_portable"
^-- SC2222 (warning): This pattern never matches because of a previous pattern on line 753.
Line 792:
*)
^-- SC2221 (warning): This pattern always overrides a later one on line 802.
Line 802:
photos_vm)
^-- SC2222 (warning): This pattern never matches because of a previous pattern on line 792.
corrigé
Line 924:
local rapport_sujet=""
^-- SC2168 (error): 'local' is only valid in functions.
Line 925:
local rapport_corps=""
^-- SC2168 (error): 'local' is only valid in functions.
Dernière modification par eric63 (Hier à 16:14)
Kubuntu 25.04 wayland Plasma 6.3.4 KDE Qt 6.12.0 noyau 6.14.0-15 Asus B760+D4 i5-12400F 4.4Ghz DDR4 32Go nvidia RTX 3060 12GB
Utilisez les drivers libres avant d’ installer une brother avec le script de demonipuch
J’utilise le clavier french AFNOR
Hors ligne