| 1 | #!/bin/bash |
|---|
| 2 | # |
|---|
| 3 | # See Usage(). |
|---|
| 4 | # |
|---|
| 5 | # Feel free to copy and modify. |
|---|
| 6 | # --xio |
|---|
| 7 | |
|---|
| 8 | Usage() { |
|---|
| 9 | echo "Usage: $( basename $0 ) {<source_dev_path>} {<target_dir_path>} {<keep_time>} {0|1}" |
|---|
| 10 | echo "Make an incremental backup of a source device to a target directory. Clean increments older than <Keep time>." |
|---|
| 11 | echo " \$1: Source device path." |
|---|
| 12 | echo " \$2: Target backup directory." |
|---|
| 13 | echo " \$3: Time to keep increments." |
|---|
| 14 | echo " \$4: Make a snapshot of the device first (for LVM logical volumes). There should be at least \$snap_size free in LVM logival volume's VG to create the snapshot." |
|---|
| 15 | } |
|---|
| 16 | |
|---|
| 17 | # Check if there are exactly 4 argv[] parameters. |
|---|
| 18 | CkParm() { |
|---|
| 19 | if [ $# -ne 4 ]; then |
|---|
| 20 | echo " ** E: Wrong parameters number: $#. Given \$@: $@" 1>&2 |
|---|
| 21 | Usage |
|---|
| 22 | exit 1 |
|---|
| 23 | fi |
|---|
| 24 | } |
|---|
| 25 | |
|---|
| 26 | # Check UID to be root. |
|---|
| 27 | CkUID() { |
|---|
| 28 | if [ $UID -ne 0 ]; then |
|---|
| 29 | echo " ** E: UID=0 required. Current UID=$UID." 1>&2 |
|---|
| 30 | exit 1 |
|---|
| 31 | fi |
|---|
| 32 | } |
|---|
| 33 | |
|---|
| 34 | # Check if the source device exists and OK. |
|---|
| 35 | CkDev() { |
|---|
| 36 | if [ ! -b "$1" ]; then |
|---|
| 37 | echo " ** E: $1 is not a block special device file." 1>&2 |
|---|
| 38 | Usage |
|---|
| 39 | exit 1 |
|---|
| 40 | fi |
|---|
| 41 | |
|---|
| 42 | if [ "$if_snapshot" -eq 1 ]; then |
|---|
| 43 | if ! lvdisplay "$1" &> /dev/null; then |
|---|
| 44 | echo " ** E: $1 doesn't look like a LVM LV." 1>&2 |
|---|
| 45 | exit 1 |
|---|
| 46 | fi |
|---|
| 47 | fi |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | # Check if snapshot flag is correct (0 or 1). |
|---|
| 51 | CkSnapFlag() { |
|---|
| 52 | if ! echo "$1" | grep '1\|0' &> /dev/null; then |
|---|
| 53 | echo " ** E: Snapshot flag can be either 0 or 1. Given: $1" 1>&2 |
|---|
| 54 | exit 1 |
|---|
| 55 | fi |
|---|
| 56 | } |
|---|
| 57 | |
|---|
| 58 | # Unmount and remove the snapshot. |
|---|
| 59 | CleanUp() { |
|---|
| 60 | echo "Cleaning up..." |
|---|
| 61 | umount -v "$source" |
|---|
| 62 | rmdir "$source" |
|---|
| 63 | if [ "$if_snapshot" -eq 1 ]; then |
|---|
| 64 | echo "Removing LVM snapshot $source_backup_dev_path..." |
|---|
| 65 | lvremove -f "$source_backup_dev_path" |
|---|
| 66 | fi |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | # ------------------------------------------------------------------------------ |
|---|
| 70 | |
|---|
| 71 | # Path to a source device. |
|---|
| 72 | source_dev_path="$1" |
|---|
| 73 | # Path to a target directory on a backup media (possibly remote). |
|---|
| 74 | target="$2" |
|---|
| 75 | # Time period to keep increments. Default to 1 week. |
|---|
| 76 | keep_time="${3:-1W}" |
|---|
| 77 | # Make a LVM snapshot? |
|---|
| 78 | if_snapshot="$4" |
|---|
| 79 | |
|---|
| 80 | # Checks |
|---|
| 81 | CkUID |
|---|
| 82 | CkParm $@ |
|---|
| 83 | CkDev "$source_dev_path" |
|---|
| 84 | CkSnapFlag "$if_snapshot" |
|---|
| 85 | |
|---|
| 86 | echo "Backing up $source_dev_path -> $target..." |
|---|
| 87 | |
|---|
| 88 | # Process variables. |
|---|
| 89 | if [ "$if_snapshot" -eq 1 ]; then |
|---|
| 90 | source_backup_dev_path="${source_dev_path}_backup" |
|---|
| 91 | snap_size="1G" |
|---|
| 92 | else |
|---|
| 93 | source_backup_dev_path="$source_dev_path" |
|---|
| 94 | fi |
|---|
| 95 | source_backup_name="$(basename $source_backup_dev_path)" |
|---|
| 96 | source="/mnt/backup/$source_backup_name" |
|---|
| 97 | |
|---|
| 98 | # Create a snapshot. |
|---|
| 99 | if [ "$if_snapshot" -eq 1 ]; then |
|---|
| 100 | if lvcreate -s -L "$snap_size" -n "$source_backup_name" "$source_dev_path"; then |
|---|
| 101 | echo "Snapshot $source_backup_name created for $source_dev_path." |
|---|
| 102 | else |
|---|
| 103 | echo " ** E: Error creating snapshot." 1>&2 |
|---|
| 104 | CleanUp |
|---|
| 105 | exit 1 |
|---|
| 106 | fi |
|---|
| 107 | fi |
|---|
| 108 | |
|---|
| 109 | # Mount. |
|---|
| 110 | mkdir -p "$source" |
|---|
| 111 | if mount "$source_backup_dev_path" "$source"; then |
|---|
| 112 | echo "Successful mount: $source_backup_dev_path -> $source." |
|---|
| 113 | else |
|---|
| 114 | echo " ** E: Unable to mount $source_backup_dev_path to $source." 1>&2 |
|---|
| 115 | CleanUp |
|---|
| 116 | exit 1 |
|---|
| 117 | fi |
|---|
| 118 | |
|---|
| 119 | #exclude="/dev/* /mnt/* /proc/* /sys/* /tmp/* /srv/backup/*" |
|---|
| 120 | |
|---|
| 121 | # FIXME: Do error processing. Check if a server is reachable in a case of |
|---|
| 122 | # remote backup (--test-server). |
|---|
| 123 | |
|---|
| 124 | # Backup. |
|---|
| 125 | echo "Starting rdiff-backup..." |
|---|
| 126 | rdiff-backup --remote-schema 'ssh -C -o "StrictHostKeyChecking no" %s rdiff-backup --server' \ |
|---|
| 127 | --create-full-path \ |
|---|
| 128 | --print-statistics \ |
|---|
| 129 | "$source" "$target" |
|---|
| 130 | |
|---|
| 131 | # Remove old increments. |
|---|
| 132 | # --force to remove more than two increments a time. |
|---|
| 133 | echo "Removing old increments..." |
|---|
| 134 | rdiff-backup --remote-schema 'ssh -C -o "StrictHostKeyChecking no" %s rdiff-backup --server' \ |
|---|
| 135 | --remove-older-than "$keep_time" \ |
|---|
| 136 | --force \ |
|---|
| 137 | "$target" |
|---|
| 138 | |
|---|
| 139 | CleanUp |
|---|
| 140 | |
|---|
| 141 | echo "Done backing up $source_dev_path." |
|---|