This is an old revision of the document!


Full system rsync

This script will perform a full system backup with rsync, leaving out /dev and /tmp and what not.

There are several configuration parameters:

  • target : system to back up, must be set to output of uname -n. Used as a sanity check.
  • source_dir : source directory. Set to / for full system backup.
  • target_dir : target directory. Set to the mountpoint of an external hard drive. Note: make sure that target_dir or a parent is included in exclude_dir otherwise rsync will recurse and your hard drive will get filled up completely.
  • exclude_dir : excluded directories. Set these to temporary directories and other things you don't want backed up.
  • include_dir : included directories. Subfolders of excluded directories to include.

If you want to use this script with a remote host, change flags to

flags="-avPse ssh --delete --rsync-path=\"rsync --fake-super\""

and use a remote path of the form user@host:path for target_dir

backup-system

#!/bin/bash
set -f
 
hostname=$(uname -n)
target="my-hostname"
 
source_dir="/"
target_dir="/media/external-hard-drive/$target/"
exclude_dir="*/.gvfs /media /run/media /sys /dev /proc /mnt /tmp pagefile.sys hiberfil.sys /home/*/.cache .mozilla/firefox/*/Cache .Trash-1000"
include_dir="/mnt/linux-data/opt /mnt/data"
flags="-avP --delete"
 
if [ -n "$target" ] ; then
  if [ "$hostname" != "$target" ] ; then
    echo Error: must be run on $target
    exit 1
  fi
fi
 
include=""
 
# process include directories
for d in $include_dir
do
  found=0
  dir=""
  exc_dir=""
  shortest_parent=""
 
  # Need to deal with rsync idiosyncracies
  # by including excluded directories
  # but not their contents
  # Removes matches to the include directory
  # and finds the shortest parent path
  for d2 in $exclude_dir
  do
    if [[ $d = $d2* ]]; then
      found=1
 
      if [[ -z "$shortest_parent" ]]; then
        shortest_parent=$d2
      else
        if [ ${#shortest_parent} -gt ${#d2} ]; then
          shortest_parent=$d2
        fi
      fi
 
    else
      exc_dir="$exc_dir $d2"
    fi
  done
 
  if [[ $found ]]; then
    exclude_dir=$exc_dir
    path=`dirname "$d"`
    while [[ "$path" != "/" ]]; do
      exclude_dir="$exclude_dir $path/*"
      #include_dir="$include_dir $path"
      include="$include --include $path"
      path=`dirname "$path"`
    done
  fi
 
  include="$include --include $d"
done
 
exclude=""
 
for d in $exclude_dir
do
  exclude="$exclude --exclude $d"
done
 
sudo -E rsync $flags $include $exclude "$source_dir" "$target_dir"