1#!/bin/sh
2
3TARSNAP_CMD=/usr/local/bin/tarsnap
4
5path2name() {
6    res=$(echo "$1" | sed -E -e 's,/+,/,g' -e 's,/$|^/,,g' -e 's,/,-,g')
7    if [ -z "$res" ]; then
8        res='ROOT'
9    fi
10    echo $res
11}
12
13something_wrong=0
14
15# make the appropriately named backup
16create_backup()
17{
18    path=$1
19    type=$2
20
21    case "$type" in
22        daily)
23        now=$(date +"$type-%Y-%m-%d")
24        ;;
25        weekly)
26        now=$(date +"$type-%Y-%U")
27        ;;
28        monthly)
29        now=$(date +"$type-%Y-%m")
30        ;;
31        yearly)
32        now=$(date +"$type-%Y")
33        ;;
34        *)
35        echo "unknown backup type: $type"
36        exit 1
37    esac
38
39    fullname="$(path2name "$path")-$now"
40    # look for an existing backup with this name
41    if $TARSNAP_CMD --list-archives | grep -q "^${fullname}$"; then
42        echo "* backup $fullname already exists, skipping..."
43    else
44        echo "  * making backup: $fullname"
45        $TARSNAP_CMD -c -f "$fullname" "$path" || something_wrong=1
46    fi
47}
48
49# delete the named backup
50delete_backup()
51{
52    backup=$1
53    echo "  * deleting old backup: $backup"
54    $TARSNAP_CMD -d -f "$backup"
55}
56
57# make a $type backup of path, cleaning up old ones
58do_path()
59{
60    path=$1
61    keep=$2
62    type=$3
63
64    name="$(path2name "$path")"
65
66    # create the regex matching the type of backup we're currently working on
67    case "$type" in
68        daily)
69        # $name-daily-2009-01-01
70        regex="^$name-$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$"
71        ;;
72        weekly)
73        # weekly-2009-01
74        regex="^$name-$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]$"
75        ;;
76        monthly)
77        # monthly-2009-01
78        regex="^$name-$type-[0-9][0-9][0-9][0-9]-[0-9][0-9]$"
79        ;;
80        yearly)
81        # yearly-2009
82        regex="^$name-$type-[0-9][0-9][0-9][0-9]$"
83        ;;
84        *)
85        echo "unknown backup type: $type"
86        exit 1
87    esac
88
89    create_backup "$path" "$type"
90
91    # get a list of all of the backups of this type sorted alpha, which
92    # effectively is increasing date/time
93    backups=$($TARSNAP_CMD --list-archives | grep "$regex" | sort)
94    count=$(echo "$backups" | wc -l)
95    if [ "$count" -ge 0 ]; then
96        # how many items should we delete
97        delete=$((count - keep))
98        count=0
99        # walk through the backups, deleting them until we've trimmed deleted
100        for backup in $backups; do
101            if [ $count -ge $delete ]; then
102                break
103            fi
104            delete_backup "$backup"
105            count=$((count + 1))
106        done
107    fi
108}
109
110# make $type backups, for paths, cleaning up old ones
111do_backups()
112{
113    paths=$1
114    keep=$2
115    type=$3
116
117    echo ""
118    echo "Doing tarsnap $type backups:"
119    for path in $paths; do
120        do_path "$path" "$keep" "$type"
121    done
122    if [ -n "$something_wrong" ]; then
123        exit 3
124    fi
125}
126
127if [ $# -ne 3 ]; then
128    echo "Usage: $0 \"<paths>\" <keep> daily|weekly|monthly|yearly"
129    exit 2
130fi
131
132# FreeBSD 12.0 adds an anticongestion function
133if [ -n "$anticongestion_sleeptime" ]; then
134    anticongestion
135fi
136
137do_backups "$1" "$2" "$3"
138