Script de sauvegarde (perl)

Petit script de sauvegarde en perl utilisé dans le projet d’architecture réseau internet / intranet en environnement GNU / Linux Debian concrétisant la fin de ma formation Administrateur Système et Réseau au GRETA SUD TERTIAIRE 93

Le principe

Désirant faire des sauvegardes régulières de la configuration des serveur du réseau j’ai décider d’écrire un petit script perl pour me facilité la vie. Je suis parti du principe que je ne sauvegardais que les fichiers de configuration, ce qui représente que quelque centaine de ko.

L’organisation

La sauvegarde doit être souple pour juste sélectionner un fichier comme un répertoire en entier. L’archivage ce fait dans le répertoire /var/backups et je garde toujours une trace de la sauvegarde précédente. Enfin j’utilise évidement le cron pour faire une sauvegarde régulières.

Le fichier ini.

Mon script prend la liste des fichiers et répertoires à sauvegardé dans un fichier d’ini. Ce fichier à la syntaxe suivante :
- /etc/network/interface
Pour désigner un fichier a sauvegarder isolément, pas de compression.
- /etc/
Pour désigner un répertoire a sauvegarder en entier au format tar.gz
- /home@
Pour désigner un répertoire racine dont chaque sous répertoire doit être sauvegarder en entier et isolément au format tar.gz.

Voici un exemple de fichier d’ini :


# backlist.ini
#
# Liste des fichiers et rep a sauvegarder

/etc/network/interfaces
/etc/network/options
/home/karles/Desktop/gts93.greta.fr/dev_script/
/tmp@

Le script

A mon humble avis le script est suffisamment bien commenté pour être facile à comprendre :


#!/usr/bin/perl

######################################################################################
## ##
## Name : tovarbackup.pl ##
## Version : 0.1 ##
## Author : Charles Christian CROIX ##
## Thank to : Larry Wall ##
## ##
######################################################################################

#################
# APPEL MODULES #
#################
# use diagnostics;
# use strict;

##################
# VARIABLES PROG #
##################
$backlist="./backuplist.ini"; ## fichier listant les rep et file a sauvegarder
$backlogfile="./tovarbackup.log"; ## fichier log
$backupdir="/var/backups"; ## ou seront stocker les fichiers a sauvegarder /!\ / a la fin
$iWidth=60; ## Largeur de l'affichage fonction sub center

########################
# Sous Prog & Fonction #
########################

sub CENTER($$) {
my ($Temp,$Width) = @_;
my $Len = ($Width - length($Temp)) / 2;
return " " x int($Len), $Temp, " " x (int($Len) + (($Len != int($Len))? 1:0));
}

sub CALDATE() {
# Commande recuperant l'heure et la date systeme
# ATTENTION VARIABLE DATE & TIME DIFF EN Fr et Us
my ($month,$day) = @_;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); ## Commande recuperant l'heure et la date systeme
$month = $mon + 1;
$month = sprintf ("%02d",$month);
$day = sprintf ("%02d",$mday);
$hour = sprintf ("%02d",$hour);
$min = sprintf ("%02d",$min);
$sec = sprintf ("%02d",$sec);
$time = "$hour.$min.$sec";
$year += 1900;
$date = "$day.$month.$year";
$datestamp = "$day/$month/$year";
$timestamp = "$hour.$min.$sec";
}

sub DOLOG($$) {
my ($file,$log)=@_;
# ecriture dans fichier log
# $file : fichier log
# $log : texte
local *LOG;
open (LOG, ">>$file") or warn "\n * Peux pas ouvrir $file \n * $!";
print LOG $log;
close LOG;
}

sub BACKLIST() {
# Appel du fichier INI donnant la liste des fichiers et rep a sauvegarder
open (BACKLIST,$backlist) || die "\U\n HOULA ouverture backlist.ini impossible \n $!";
@backlist = <BACKLIST> ;
close (BACKLIST);
}
sub FIN() {
print "\n\t+", "=" x ($iWidth), "+\n";
print "\t|", CENTER("FIN DU SCRIPT tovarbackup.pl", $iWidth), "|\n";
print "\t+", "=" x ($iWidth), "+\n";
EXIT;
}

sub ENTETE() {
print "\n";
print "\t+", "=" x ($iWidth), "+\n";
print "\t|", CENTER("** PERL tovarbackup.pl **", $iWidth), "|\n";
print "\t|", CENTER("Version 0.1 ", $iWidth), "|\n";
print "\t|", CENTER("(c) Charles Christian CROIX", $iWidth), "|\n";
print "\t|", CENTER("Licence: GPL", $iWidth), "|\n";
print "\t|", CENTER("Syntaxe : tovarbackup.pl ", $iWidth), "|\n";
print "\t|", CENTER( $date , $iWidth), "|\n";
print "\t|", CENTER( $time , $iWidth), "|\n";
print "\t+", "=" x ($iWidth), "+\n"
}

##############################
# #
# TRAITEMENT PRINCIPALE #
# #
##############################

CALDATE();
ENTETE();
BACKLIST();

DOLOG $backlogfile,"\n[$datestamp] [$timestamp] --";
DOLOG $backlogfile,"\n[$datestamp] [$timestamp] LANCEMENT ET INIT de tovarbackup";

# pour chaque ligne du ficier ini
foreach $line (@backlist) {
chomp $line;
@mots = split(/\s+/,$line);
next if (@mots[0] eq "#");
next if (@mots[0] eq "");

# recup du caractere de fin de ligne
$dirornot = substr (@mots[0],-1,1);

# recupe du nom de ficher / rep en fin de path
@filename = split(/\//,$mots[0]);
$nb_element_filename = @filename;
$nb_element_filename--;

###############################
# test si c'est un repertoire #
###############################
if ($dirornot eq "/") {
print "\n\t $mots[0] est un repertoire";
# on garde tjrs la version precedente
if (-e "$backupdir/$filename[$nb_element_filename].tar.gz") {
if (-e "$backupdir/$filename[$nb_element_filename].old.tar.gz") {
unlink ("$backupdir/$filename[$nb_element_filename].old.tar.gz")
}
system("mv $backupdir/$filename[$nb_element_filename].tar.gz $backupdir/$filename[$nb_element_filename].old.tar.gz ");
}
# appel systeme pour le tar
system("tar cvfz $backupdir/$filename[$nb_element_filename].tar.gz $mots[0] 2>&-, >&-");
DOLOG $backlogfile,"\n[$datestamp] [$timestamp] TAR REPERTOIRE $mots[0]";
}

######################################
# test si c'est un repertoire racine #
######################################
elsif ($dirornot eq "@") {
print "\n\t $mots[0] est un repertoire racine";
# suppression du carractere @
$mots[0]=substr($mots[0], 0, -1);
print "\n\t $backupdir$mots[0]";
# creation du rep racine dans le rep de backup
unless (-e "$backupdir$mots[0]") {
mkdir "$backupdir$mots[0]";
DOLOG $backlogfile,"\n[$datestamp] [$timestamp] CREATION de $backupdir$mots[0]";
}
# recup de la liste des fichier dans le rep racine
@list_sousrep = glob ("$mots[0]/*");
DOLOG $backlogfile,"\n[$datestamp] [$timestamp] TAR.GZ des sous repertoire de $mots[0] ";
foreach $sousrep (@list_sousrep) {
#si c'est un rep on le tar
if (-d $sousrep) {
# on garde tjrs la version precedente
if (-e "$backupdir$sousrep.tar.gz") {
if (-e "$backupdir$sousrep.old.tar.gz") {
unlink ("$backupdir$sousrep.old.tar.gz");
DOLOG $backlogfile,"\n[$datestamp] [$timestamp] SUPPRESSION de $backupdir$sousrep.old.tar.gz";
}
system("mv $backupdir$sousrep.tar.gz $backupdir$sousrep.old.tar.gz ");
DOLOG $backlogfile,"\n[$datestamp] [$timestamp] DEPLACEMENT de $backupdir$sousrep.tar.gz vers $backupdir$sousrep.old.tar.gz ";
}
print "\n\t - $sousrep";
system("tar cvfz $backupdir/$sousrep.tar.gz $sousrep 2>&-, >&-");
DOLOG $backlogfile,"\n[$datestamp] [$timestamp]\t TAR.GZ de $sousrep";
}
}
}

############################################
# et bien c'est ni un rep ni un rep racine #
# donc c'est un fichier #
############################################
else {
print "\n\t $mots[0] est un fichier ";
# on garde tjrs la version precedente
if (-e "$backupdir/$filename[$nb_element_filename]") {
if (-e "$backupdir/$filename[$nb_element_filename].old") {
unlink ("$backupdir/$filename[$nb_element_filename].old");
DOLOG $backlogfile,"\n[$datestamp] [$timestamp] SUPPRESSION DU FICHIER $backupdir/$filename[$nb_element_filename].old";
}
system("mv $backupdir/$filename[$nb_element_filename] $backupdir/$filename[$nb_element_filename].old ");
DOLOG $backlogfile,"\n[$datestamp] [$timestamp] DEPLACEMENT DU FICHER $backupdir/$filename[$nb_element_filename] vers $backupdir/$filename[$nb_element_filename].old ";
}
else {
}
# copie simple
system("cp $mots[0] $backupdir ");
DOLOG $backlogfile,"\n[$datestamp] [$timestamp] COPIE DU FICHER $mots[0]";
}
print "\n";
}

FIN();

Pour faire mieux

Pour faire mieux je prendrais soins de prévoir la possibilité de choisir entre la compression d’un répertoire ou sa simple copie. J’inclurais également la gestion des fichiers présent dans un répertoire racine car pour le moment seul les sous répertoires sont pris en compte. Les messages sur STDOUT devrait également être optionnel.