#!/bin/sh # # Script permettant de sauvegarder des données sur différents médias. # Les éléments à sauvegarder et à exclure sont définis dans des fichiers séparés. # # Michel Grentzinger (c) 2002 # # # Les variables généales : repertoire_sauvegardes=/var/sauve repertoire_listes=/etc/sauve archiveur=/bin/tar ext1=tar # On peut choisir entre gzip, bzip2 et autres... compresseur=bzip2 compresseur=$(which $compresseur) if [ "$compresseur" -a -x $compresseur ] ; then case $compresseur in *bzip2) ext2=bz2 ;; *gzip) ext2=gz ;; esac option_archiveur="--use-compress-program $compresseur" else echo -e "\nAttention, l'archive ne sera pas compressée ! Ceci peut prendre beaucoup d'espace disque...\n" while true ; do echo -en "Voulez-vous continuer [Oui|non] ? " read reponse case $reponse in Oui|oui|"") break ;; non|quitter) quitter="oui" exit 0 ;; *) echo -e "Erreur ! Veuillez répondre correctement à la question, merci !\n" ;; esac done fi nb_erreurs_a=0 nb_erreurs_b=0 function heure() { # Renvoie l'heure au format hh:mm:ss date '+%T' } function datation() { # On met la date dans une variable grace à la fonction datation(): for parametre in $@ ; do case $parametre in heure) # L'heure en heures:minutes: heure=$(date +%H:%M) ;; date|"") # La date en jj-mm-aaaa: date=$(date +%d-%m-%Y) ;; *) echo -e "\nCe paramètre n'est pas accepté..." exit 2 ;; esac done # Si la date et l'heure sont définis : #On met un séparateur entre les deux. if [ -n "$date" -a -n "$heure" ] ; then separateur="_" fi # Enfin, on écrit le contenu de la variable $datation (en une fois !). datation=${date:=}${separateur:=}${heure:=} } function preparer() { # Cette fonction permet de définir des variables # afin de controler le déroulement du script. # La gestion des CD-RW et de leur taille est ainsi assurée. # On veut savoir si le support peut être effacé (cas du CD-RW). echo -e "\nVous pouvez enregistrer sur un support de type suivant:" echo "1) CD enregistrable (CD-R)" echo "2) CD ré-enregistrable (CD-RW)" while true ; do read -p "Entrez le numéro du média correspondant [1|2|quitter] : " reponse case $reponse in 1) media="cdr" ; break ;; 2) media="cdrw" ; break ;; quitter) exit 0 ;; *) echo -e "Erreur ! Veuillez entrer un nombre correct !\n" ;; esac done # La taille du CD echo -e "\n\nQuelle est la capacité du support ?" echo "1) 650Mo soit 74 minutes" echo "2) 700Mo soit 80 minutes" while true ; do read -p "Entrez le numéro de la capacité correspondant [1|2|quitter] : " reponse # Répondre 1 ou 2. case $reponse in 1) capacite="650" ; break ;; 2) capacite="700" ; break ;; quitter) exit 0 ;; *) echo -e "Erreur ! Veuillez entrer un nombre correct !\n" ;; esac done } function purger() { # Cette fonction est instable et n'est pas terminée ! # ATTENTION !! echo -e "\nDébut de la purge..." #echo "Fonction pas encore finie..." echo -e "\nEntrez une date ou une heure (jj-mm-aaaa | hh:mm) : " read supprime_date for partie in contenu erreurs sauvegarde secteur paquets ; do rm -f ${repertoire_sauvegardes}/${partie}_${supprime_date}* done } function selectionner() { # Cette fonction permet d'écrire le contenu # de $inclure et $exclure. echo -e "\nPremière phase : choix du contenu de la sauvegarde. ($(heure))" echo -e "===================================================\n" # Pour déterminer le contenu de $datation : datation date # On crée le répertoire de sauvegarde s'il n'existe pas : test -d $repertoire_sauvegarde || mkdir $repertoire_sauvegarde # On initialise les fichiers : erreurs=${repertoire_sauvegardes}/erreurs_${datation} ; echo -n > $erreurs contenu=${repertoire_sauvegardes}/contenu_${datation} ; echo -n > $contenu secteur=${repertoire_sauvegardes}/secteur_${datation} ; echo -n > $secteur chmod 640 $contenu ; chown root.root $contenu extras="$erreurs $contenu $secteur" echo -e "Erreurs concernant la préparation des fichiers :" >> $erreurs echo -e "================================================\n" >> $erreurs # On définit les éléments à inclure : # ----------------------------------- liste_inclure=${repertoire_listes}/liste-a-inclure inclure=/tmp/inclure_${datation} ; echo -n > $inclure if [ ! -r $liste_inclure ] ; then echo "Erreur ! $liste_inclure n'est pas lisible ou n'est pas un fichier." exit 1 fi echo -ne "\tDéfinition des éléments à sauvegarder..." # On prend en compte toutes les lignes sauf celles contenant des commentaires et des lignes vides : grep '^[^#]' $liste_inclure 1> $inclure && echo "terminé." || { echo "Erreur ! " ; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } # On cherche les répertoires à exclure : # -------------------------------------- liste_exclure=${repertoire_listes}/liste-a-exclure exclure=/tmp/exclure_${datation} ; echo -n > $exclure # On récupère la variable initiale IFS : IFS1=$IFS if [ -r $liste_exclure ] ; then # -> On élimine les lignes de commentaires : # -> On place les champs séparés par les ':' dans $chercher et $chemin : # -> Le reste va dans $autre echo -ne "\tRecherche des fichiers à exclure..." grep '^[^#]' $liste_exclure | while IFS=':' read elements chemins type autre ; do # Pour enlever les espaces dans les variables: elements="`echo $elements`" chemins="`echo $chemins`" type="`echo $type`" # On vérifie que $elements, $chemins soit définis et que $autre soit nul. if [ -n "$elements" -a -n "$chemins" -a -z "$autre" ] ; then # On vérifie que le type d'élément peut être compris par find -type. if [ $(echo "$type" | grep '[bcdpfls]') ] ; then type="-type `echo $type`" else echo "Erreur ! Le champ est incorrect dans $liste_exclure." >> $erreurs type="" fi # IFS est le séparateur de champ. IFS="," unset chercher # On construit la chaine $chercher (ex for element in $elements ; do chercher="${chercher:=}${chercher:+ -o }-name $element" done # On remet le IFS initial : IFS=$IFS1 # On fait la recherche : find $chemins $chercher $type 1>> $exclure 2>> $erreurs || nb_erreurs_b=$(($nb_erreurs_b + 1)) else echo "Erreur ! Le fichier $liste_exclure est mal renseigné." >> $erreurs nb_erreurs_b=$(($nb_erreurs_b + 1)) fi done && echo "terminé." || { echo "ECHEC !" ; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } else echo "Erreur ! $liste_exclure n'est pas lisible ou n'est pas un fichier." >> $erreurs nb_erreurs_b=$(($nb_erreurs_b + 1)) fi } function archiver() { # Cette fonction accepte les paramètres "cdrom" et "disque". # Certains éléments sont communs. echo -e "\nDeuxième phase : enregistrement des données. ($(heure))" echo -e "============================================\n" # On fixe les permissions à rw------- (600) pour que l'archive soit illisible. oldmask=`umask` umask 077 archive=${repertoire_sauvegardes}/sauvegarde_${datation}.${ext1}${ext2:+.}${ext2:=} # Le message en cas d'erreur dans le nom de la fonction : local usage="Utilisation : archiver {disque|cdrom}" # La base de données de dpkg: if [ -x $(which dpkg) ] ; then # On vérifie que dpkg soit exécutable (sinon, c'est pas une Debian) paquets=${repertoire_sauvegardes}/paquets_${datation} extras="$extras $paquets" echo -ne "\tSauvegarde de la base de données des paquets installés..." echo -e "\n\nErreurs concernant la sauvegarde de la base de données des paquets installés :" >> $erreurs echo -e "==============================================================================\n" >> $erreurs dpkg --get-selections 1> $paquets 2>> $erreurs && echo "terminé." || { echo "ECHEC !" ; nb_erreurs_b=$(($nb_erreurs_b + 1)) ; } fi # On sauvegarde le MBR (512 premiers octets du disque): echo -ne "\tSauvegarde du secteur de démarrage..." echo -e "\n\nErreurs concernant la sauvegarde du secteur de démarrage :" >> $erreurs echo -e "========================================================== :\n" >> $erreurs dd if=/dev/hda of=$secteur bs=1 count=512 2>> $erreurs && echo "terminé." || { echo "ECHEC !" ; nb_erreurs_b=$(($nb_erreurs_b + 1)) ; } # On sauvegarde les données : echo -ne "\tSauvegarde des fichiers et des répertoires..." echo -e "\n\nErreurs concernant la sauvegarde des fichiers et des répertoires :" >> $erreurs echo -e "==================================================================\n" >> $erreurs if [ -r $exclure ]; then # On sauvegarde le contenu de $liste_inclure sauf les contenus définis dans $liste_exclure. $archiveur -cvpf $archive $option_archiveur -T $inclure -X $exclure 1> $contenu 2>> $erreurs && echo "terminé." || { echo "ECHEC !" ; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } else # On sauvegarde tous les contenus définis dans $liste_inclure. echo -e "Attention ! $exclure n'est pas lisible ou n'est pas un fichier." >> $erreurs $archiveur -cvpf $archive $option_archiveur -T $inclure 1> $contenu 2>> $erreurs && echo "terminé." || { echo "ECHEC !" ; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } fi && rm -f $inclure $exclure } function calculer_iso() { # Cette fonction calcule la taille de l'image iso à créer en fonction # de la taille des fichiers de méta-informations. # Un découpage et un ré-assemblage est réalisé afin que chaque cédérom soit remplit # au maximun de sa capacité. echo -e "\nTroisième phase : création de(s) cédérom(s). ($(heure))" echo -e "============================================\n" cd $repertoire_sauvegarde # Le périphérique utilisé par le graveur : periph="dev=0,0,0" # On définit et on vide les fichiers journaux : log_mkisofs=${repertoire_sauvegardes}/mkisofs.log ; echo -n > $log_mkisofs log_cdrecord=${repertoire_sauvegardes}/cdrecord.log ; echo -n > $log_cdrecord # On supprime les fichiers déjà existants : rm -f ${archive}_* &> /dev/null # On récupère la première colonne de la dernière ligne du calcul de la place utilisée : taille_extras=$(du -bc $extras | tail -n 1 | awk '{print $1}') taille_archive=$(du -bc $archive | tail -n 1 | awk '{print $1}') # On calcule la taille totale de tous les fichiers. taille_totale=$(($taille_extras + $taille_archive)) # On transforme le taille du CD en octets : taille_cd=$(($capacite * 1024 * 1024)) taille_1=$(($taille_cd - $taille_extras)) taille_2=$(($taille_archive - $taille_1)) # On vérifie si ca peut rentre sur un seul cd : if [ $taille_totale -gt $taille_cd ] ; then echo -e "\n\nErreurs concernant le découpage des fichiers :" >> $erreurs echo -e "==============================================\n" >> $erreurs # On découpe en petites parties pour remplir le cd n°1 echo -ne "\tDécoupage des données pour le premier cédérom..." split -b $taille_1 $archive ${archive}_1_ 2>>$erreurs && echo "terminé." || { echo "ECHEC ! " ; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } # On supprime l'archive qui vient d'être découpée. echo -ne "\tSuppression de l'archive découpée..." rm -f $archive && echo "terminé." || { echo "ECHEC ! " ; nb_erreurs_b=$(($nb_erreurs_b + 1)) ; } # On renomme le premier fichier sans l'extension due à split (aa) : echo -ne "\tRenommage du premier fichier obtenu..." mv ${archive}_1_aa ${archive}_1 2>>$erreurs && echo "terminé." || { echo "ECHEC ! " ; nb_erreurs_b=$(($nb_erreurs_b + 1)) ; } # S'il reste au moins 2 fichiers autres que archive_1_aa, alors, on exécute la suite : if [ $(ls ${archive}_1_?? | wc -l) -ge 2 ] ; then # On rassemble les autres : echo -ne "\tAssemblage des parties restantes..." cat ${archive}_1_?? > ${archive}_2_ 2>> $erreurs && echo "terminé." || { echo "ECHEC ! " ; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } # On sumprime les petites parties echo -ne "\tSuppression des parties restantes..." rm -f ${archive}_1_?? 2>>$erreurs && echo "terminé." || { echo "Erreur ! " ; nb_erreurs_b=$(($nb_erreurs_b + 1)) ; } taille_partie_2=$(du -bc ${archive}_2_ | tail -n 1 | awk '{print $1}') if [ $taille_partie_2 -gt $taille_cd ] ; then # On les redécoupe en fonction de la taille des cd : echo -ne "\tDécoupage des données restantes pour les autres cédéroms..." split -b $taille_cd ${archive}_2_ ${archive}_2_ 2>>$erreurs && echo "terminé." || { echo "ECHEC ! " ; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } # On supprime la partie 2 (qui vient d'être découpée) : echo -ne "\tSuppression du fichier original..." rm -f ${archive}_2_ && echo "terminé." || { echo "Erreur ! " ; nb_erreurs_b=$(($nb_erreurs_b + 1)) ; } else # S'il n'y a pas de _2_ab, alors on renomme en _2 : echo -ne "\tRenommage du fichier unique obtenu après la première partie..." mv ${archive}_2_ ${archive}_2 2>>$erreurs && echo "terminé." || { echo "ECHEC ! " ; nb_erreurs_b=$(($nb_erreurs_b + 1)) ; } fi else mv ${archive}_1_ab ${archive}_2 fi # On compte le nb de lignes que produit la liste des fichiers du jour (ou de l'heure). nombre_cd=$(ls ${archive}_[1-2]* | grep -cv '.*\.iso$' ) else nombre_cd=1 fi echo -e "\nVous aurez besoin de $(echo $nombre_cd) cédérom(s).\n" } function creer_iso() { # Fonction qui réalise des images iso prètes à graver. if [ $nombre_cd -gt 1 ] ; then # Création des images iso : # on regarde combien de fichiers commencent par $prefixe et se terminent pas par iso. numero=0 echo -e "\n\nErreurs concernant la création des images iso :" >> $log_mkisofs echo -e "===============================================\n" >> $log_mkisofs for cd in $(ls ${archive}_[1-2]* | grep -v '.*\.iso$' ) ; do numero=$(($numero + 1)) # Si c'est le premier cd, on ajoute les fichiers d'information : contenu_image="$cd" if [ "$cd" = "${archive}_1" ] ; then contenu_image="$extras $contenu_image" fi echo -ne "\tcréation de l'image iso n°${numero}..." echo -e "\tcréation de l'image iso n°${numero}\n" >> $log_mkisofs # On crée l'image : mkisofs -o ${cd}.iso -R -J -l -L $contenu_image >> $log_mkisofs 2>&1 && echo "terminé à $(heure)." || { echo "ECHEC !"; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } # On supprime la base de l'image iso : rm -f $contenu_image & done else contenu_image="$extras $archive" echo -e "\n\nErreurs concernant la création de l'image iso :" >> $log_mkisofs echo -e "===============================================\n" >> $log_mkisofs echo -ne "\tcréation de l'image iso..." mkisofs -o ${archive}.iso -R -J -l -L $contenu_image >> $log_mkisofs 2>&1 && echo "terminé à $(heure)." || { echo "ECHEC !"; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } rm -f $contenu_image & fi } function graver_iso() { # Cette fonction grave les images iso sur un ou plusieur cédérom. echo # Gravure et effacement éventuel. numero=0 echo -e "\n\nErreurs concernant la gravure des cédérom :" >> $log_cdrecord echo -e "===========================================\n" >> $log_cdrecord for image in $(ls ${archive}*.iso) ; do numero=$(($numero + 1)) # On efface le CD si c'est un CD-RW if [ "$media" = "cdrw" ] ; then while true ; do echo -en "Voulez-vous formatter le CD-RW avant l'écriture (mode fast) [oui|Non|quitter] ? " read reponse #On attend oui, non ou quitter comme réponse. case $reponse in oui) echo -ne "\t\teffacement du CD-RW n°${numero}..." # On efface le CD-RW. cdrecord speed=10 $periph blank=fast >> $log_cdrecord 2>&1 && echo "terminé à $(heure)." || { echo "ECHEC !" ; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } break ;; non|Non|"") break ;; quitter) quitter="oui" # On sort de 2 niveaux pour éviter cdrecord dans for...do...done. break 2 ;; *) echo -e "Erreur ! Veuillez répondre à la question, merci !\n" ;; esac done fi eject while true ; do echo -en "Voulez-vous continuer (insérez un cédérom le cas échéant) [Oui|non|quitter] ? " read reponse # On attend oui ou non comme réponse. case $reponse in oui|"") break ;; non|quitter) quitter="oui" # On sort de 2 niveaux. break 2 ;; *) echo -e "Erreur ! Veuillez répondre à la question, merci !\n" ;; esac done echo -ne "\tgravage de l'image iso n°${numero}..." echo -e "\tgravage de l'image iso n°${numero}\n" >> $erreurs # on grave chaque image à la fin de la boucle. eject cdrecord -v -eject speed=8 $periph -data $image >> $log_cdrecord 2>&1 && echo "terminé à ($(heure))." || { echo "ECHEC !" ; nb_erreurs_a=$(($nb_erreurs_a + 1)) ; } rm -f $image done # On supprime les fichiers temporaires,c'est-à-dire # ceux qui commencent par sauvegarde_jj-mm-aaaa. ou sauvegarde_hh:mm. # On conserve les fichiers-journaux $log_mkisofs $log_cdrecord echo -ne "\nSupression des fichiers temporaires..." supprimer="${archive}* $extras $inclure $exclure" rm -f $supprimer > /dev/null 2>&1 && echo "terminé." || { echo "Erreur !" ; nb_erreurs_b=$(($nb_erreurs_b + 1)) ; } # On rentre le chariot si possible (si le programe eject est dans le PATH) : test -x $(which eject) && eject -t # Si on a répondu quitter à la demande concernant le cdrom, alors on sort : test "$quitter" = "oui" && exit 0 } function terminer() { # On remet l'ancien masque : umask $oldmask # On affiche un petit mot avec l'heure de fin (format hh:mm:ss)... echo -e "\n\nLa sauvegarde s'est terminée à $(heure).\n" echo "Il y a eu ${nb_erreurs_a} erreurs majeures et $nb_erreurs_b erreurs mineures !" } # ------------------------------------- # Début du script. # ================ usage="Utilisation : $0 {auto|disque|cdrom|(purge [N])}" case $1 in auto) selectionner archiver terminer #purger 10 ;; disque) selectionner archiver terminer # purger 10 exit 0 ;; cdrom) repertoire_sauvegardes=/tmp # effacer preparer selectionner archiver calculer_iso creer_iso graver_iso terminer exit 0 #purger 5 ;; purge) echo -e "\nFonction indisponible pour le moment ! Désolé...\n" #nombre=$2 #purger $nombre ;; "") echo -e "\nVeuillez indiquer une action a effectuer..." echo $usage exit 2 ;; *) echo -e "\nDésolé ! Cette action est invalide..." echo $usage exit 2 ;; esac