The WABAC Machine

parse error

Mise à jour du 14 novembre 2013 :

The WABAC Machine a beaucoup évolué depuis ! Suivez son développement via son dépôt GitHub.

The WABAC Machine dans les années 90

The WABAC Machine est un petit shellscript qui utilise RSync et dont je me sers quotidiennement pour faire une sauvegarde de mon /home.

Son fonctionnement est volontairement proche de celui de la Time Machine d'Apple. La WABAC Machine réalise chaque sauvegarde en 3 étapes :

  1. Elle calcule l'espace nécessaire pour réaliser la sauvegarde et vérifie que celui-ci est bien disponible sur le volume de sauvegarde. Si ce n'est pas le cas, la WABAC Machine supprime automatiquement les plus vieilles sauvegardes pour faire de la place.
  2. Elle réalise une sauvegarde incrémentale et datée, en hard-linkant les fichiers qui n'ont pas changé : l'espace occupé par la sauvegarde est donc le plus petit possible.
  3. Elle supprime les sauvegardes plus vieilles de x jours, x étant paramétrable, bien entendu.

Son efficacité est due à RSync, qui est un outil simplement formidable et aux hardlinks, hérités d'Unix.

Et voilà le script en question :

#!/bin/sh

#
#-------------------------------------------------------------------------------
#
# The WABAC Machine.
#
# This script tries to mimic Apple's TimeMachine, *thanks to rsync* :)
# Copyright François KUBLER, 2009.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#-------------------------------------------------------------------------------
#



# Edit these variables to fit your need ----------------------------------------

# Source :
SRC="/home/"

# Destination :
VOL="/media/HDD"
DST=$VOL"/BACKUP"

# Exclude file :
EXCLUDE_FILE="/home/user/wabac/exclude.txt"

# Remove saves older than (in days) :
REMOVE_OLDER_THAN=60

# Date format :
DATE_FORMAT="+%Y-%m-%d %H:%M:%S"




# Edit with care behind this line ! --------------------------------------------


check_mounted()
{
    cat /etc/mtab | grep $VOL >/dev/null
    if [ "$?" -ne "0" ]; then
        echo -n "    > $VOL is not mounted, trying to mount..."

        mount $VOL

        cat /etc/mtab | grep $VOL >/dev/null
        if [ "$?" -ne "0" ]; then
            echo "failed."
            echo "    > Unable to mount $VOL, aborting !"
            exit 2
        fi
        echo "OK."
    fi
}


needed_space()
{
    NEEDED_SPACE=$(rsync -a --stats --dry-run --exclude-from="$EXCLUDE_FILE" --link-dest="$DST/latest" "$SRC" "$DST/$NOW/" | grep "Total transferred file size" | tr -s " " | cut -d" " -f5)
    NEEDED_SPACE=$((NEEDED_SPACE/(1024*1024)))

    echo "    > Needed space : $NEEDED_SPACE Mo."
}


available_space()
{
    AVAIL_SPACE=$(df -m "$DST" | grep "/dev" | tr -s " " | cut -d" " -f4)

    echo "    > Available space : $AVAIL_SPACE Mo."
}


free_space()
{
    echo "+ PRE-BACKUP THINNING"

    needed_space
    available_space

    while [ $NEEDED_SPACE -gt $AVAIL_SPACE ]
    do
        # Damn, we need to delete the older directory, let's get its name :
        REM=$(find "$DST" -maxdepth 1 -mindepth 1 -type d | sort -f | head -1)
        echo "    > Deleting $REM to get enough free space."
        rm -Rf "$REM"

        available_space
    done
}


purge()
{
    NB_REM=$(find "$DST" -maxdepth 1 -mindepth 1 -type d -mtime +$REMOVE_OLDER_THAN | wc -l)

    if [ $NB_REM -gt 0 ]
        then
            echo "    > $NB_REM expired backup(s) will be removed."
            find "$DST" -maxdepth 1 -mindepth 1 -type d -mtime +$REMOVE_OLDER_THAN -print| while read obj
            do
            rm -Rf "$obj"
            echo "    > $obj has been removed."
            done
        else
            echo "    > OK."
    fi
}


make_link()
{
    rm "$DST/latest"
    N=$(find "$DST" -maxdepth 1 -mindepth 1 -type d | sort -rif | head -1)
    ln -s "$N" "$DST/latest"
}


rotate()
{
    echo "+ POST-BACKUP THINNING"

    purge
    make_link
}


backup()
{
    echo "+ BACKUP"
    echo "    > Backing up to: $DST/$NOW/"

    nice -n 19 rsync -ahS --numeric-ids --stats --exclude-from=$EXCLUDE_FILE --link-dest=$DST/latest $SRC "$DST/$NOW/"
    touch -a -m -c -d "$NOW" "$DST/$NOW"
}


wabac_machine()
{
    echo "+ WABAC MACHINE BACKUP STARTING (${NOW})"

    check_mounted
    free_space
    backup
    rotate

    NOW=$(date "$DATE_FORMAT")
    echo "+ WABAC MACHINE BACKUP DONE (${NOW})"
}



### Allright, let's start :

NOW=$(date "$DATE_FORMAT")

wabac_machine

exit 0



#EOF

Vous pouvez aussi télécharger le script. N'oubliez pas d'enlever le .txt, de lui donner les droits d'exécution (chmod u+x wabac_machine.sh) et de modifier les variables en fonction de vos besoins.