]> git.treefish.org Git - backmeupscotty.git/blob - backmeupscotty
Add functionality to list existing backups
[backmeupscotty.git] / backmeupscotty
1 #!/bin/bash
2
3 REMOTE_HOST=localhost
4 REMOTE_DIR=/tmp/backmeupscotty/test
5 ARCHIVE_KEEPNBACKUPS=30
6 ARCHIVE_KEEPNDAYS=30
7 BACKUP_RUNEVERYNTHDAY=1
8 BWLIMIT=500KiB
9 BACKUP_FORCE=0
10
11 _ERROR_ENCOUNTERED=0
12
13 function timestamp {
14     date +'[%y-%m-%d|%H:%M:%S]'
15 }
16
17 function scottyline {
18     echo $(timestamp) $@
19 }
20
21 function scottyinfo {
22     if [ $_ERROR_ENCOUNTERED -eq 0 ]; then
23         scottyline $@
24     else
25         scottyline $@ >&2
26     fi
27 }
28
29 function scottyerror {
30     scottyline $@ >&2
31     if [ $_ERROR_ENCOUNTERED -eq 0 ]; then
32         _ERROR_ENCOUNTERED=1
33         scottyline "Going into verbose mode after error encounter." >&2
34     fi
35 }
36
37 function ssh255 {
38     ssh $@
39     sshret=$?
40
41     if [ $sshret -eq 255 ]; then
42         scottyerror "SSH connection failed!"
43         exit 1
44     else
45         return $sshret
46     fi
47 }
48
49 function grepbackups {
50     ssh255 $REMOTE_HOST "ls $REMOTE_DIR" | grep -E '[0-9]+-[0-9]+'
51 }
52
53 function isIncomplete {
54     if ( ssh255 $REMOTE_HOST '[ -d '$REMOTE_DIR/incomplete' ]' ); then
55         return 0
56     else
57         return 1
58     fi
59 }
60
61 function isNthDay {
62     if [ $(( ( $(date +%s) / (60*60*24) ) % $BACKUP_RUNEVERYNTHDAY )) -eq 0 ];
63     then
64         return 0
65     else
66         return 1
67     fi
68 }
69
70 function latestTooOld {
71     for oldbackup in $(grepbackups); do
72         tstamp=$(echo $oldbackup | cut -d'-' -f1)
73
74         if [ $(( $(date +%s) - $tstamp )) -lt $(( ($BACKUP_RUNEVERYNTHDAY*24+12)*60*60 )) ]
75         then
76             return 1
77         fi
78     done
79
80     return 0
81 }
82
83 function scottysync {
84     timestamp=$(date +%s)
85
86     scottyinfo "Syncing $SYNC_SRC to $REMOTE_HOST:$REMOTE_DIR @$timestamp."
87
88     if [ ! -d "$SYNC_SRC" ]; then
89         scottyerror "Source dir $SYNC_SRC does not exist. Not syncing!"
90         return 1
91     fi
92
93     if [ $(ls -A "$SYNC_SRC" | wc -l) -eq 0 ]; then
94         scottyerror "Source dir $SYNC_SRC is empty. Not syncing!"
95         return 1
96     fi
97
98     dir_current=$REMOTE_DIR/current
99     dir_incomplete=$REMOTE_DIR/incomplete
100     dir_timestamped=$REMOTE_DIR/$timestamp-$(date -d @$timestamp +%Y%m%d%H%M%S)
101
102     if [ -z $SYNC_EXC ]; then
103         rsync_exclude=""
104     else
105         rsync_exclude=$(eval echo --exclude={$SYNC_EXC} | tr -d {})
106     fi
107
108     if (ssh255 $REMOTE_HOST '[ ! -d '$REMOTE_DIR' ]'); then
109         scottyinfo "Creating destination directory $REMOTE_HOST:$REMOTE_DIR."
110         ssh255 $REMOTE_HOST "mkdir $REMOTE_DIR"
111     fi
112
113     if isIncomplete; then
114         scottyerror "Continuing old incomplete backup."
115     fi
116
117     scottyinfo "Starting rsync."
118     rsync -e ssh --bwlimit=$BWLIMIT \
119           -v -aHAX --numeric-ids --delete --delete-excluded \
120           --link-dest=$dir_current \
121           $rsync_exclude \
122           $SYNC_SRC/ $REMOTE_HOST:$dir_incomplete/
123
124     if [ $? -eq 0 ]; then
125         scottyinfo "Timestamping completed backup and linking to current backup."
126         ssh255 $REMOTE_HOST \
127                "mv $dir_incomplete $dir_timestamped && rm -f $dir_current && \
128                ln -s $(basename $dir_timestamped) $dir_current"
129     else
130         scottyerror "Rsync failed."
131     fi
132
133     while [ $(grepbackups | wc -l) -gt $ARCHIVE_KEEPNBACKUPS ]; do
134         oldestbackup=$(grepbackups | head -1)
135         oldestbackuptstamp=$(echo $oldestbackup | cut -d'-' -f1)
136
137         if [ $oldestbackuptstamp -lt $(( $(date +%s) - $ARCHIVE_KEEPNDAYS*60*60*24 )) ]; then
138             scottyinfo "Removing old backup $oldestbackup."
139             ssh255 $REMOTE_HOST rm -r "$REMOTE_DIR/$oldestbackup"
140         else
141             break
142         fi
143     done
144 }
145
146 function deleteLock {
147     if ! rmdir /var/lock/$(basename $0); then
148         scottyerror "Could not delete lockfile /tmp/$(basename $0).lock!"
149     fi
150 }
151
152 function cleanup_abort {
153     scottyerror "Caught exit signal! Cleaning up."
154
155     cleanup ABORT
156
157     if [ $(jobs -p) ]; then
158         scottyerror "TERMinating remaining child processes."
159         kill $(jobs -p)
160     fi
161
162     deleteLock
163
164     exit
165 }
166
167 function cleanup {
168     scottyinfo "No cleanup function was defined."
169 }
170
171 function prepare {
172     scottyinfo "No prepare function was defined."
173 }
174
175 function cleanup_normal {
176     cleanup
177     deleteLock
178 }
179
180 function printhelp {
181     cat <<EOF
182 Usage: $(basename $0) [OPTION]...
183
184 Recognized options:
185   -q   Only output errors
186   -n   Run only on nth day
187   -f   Force backup
188   -l   List existing backups
189   -h   Print out this help
190 EOF
191 }
192
193 function backmeupscotty {
194     while getopts "qn:flh" opt; do
195         case $opt in
196             q)
197                 exec > /dev/null
198                 ;;
199             n)
200                 BACKUP_RUNEVERYNTHDAY=$OPTARG
201                 ;;
202             f)
203                 BACKUP_FORCE=1
204                 ;;
205             l)
206                 LIST_BACKUPS=1
207                 ;;
208             h)
209                 printhelp
210                 exit 0
211                 ;;
212         esac
213     done
214
215     ssh255 $REMOTE_HOST exit
216
217     if [ $LIST_BACKUPS ]; then
218         for backup in $(grepbackups); do
219             echo $backup
220         done
221         exit 0
222     fi
223
224     if [ $BACKUP_FORCE -eq 1 ]; then
225         scottyinfo "Backup was enforced."
226     elif latestTooOld; then
227         scottyerror "The latest backup is too old."
228     elif isNthDay; then
229         scottyinfo "This is the nth day."
230     else
231         scottyinfo "No backup has to be done. Exiting."
232         exit 0
233     fi
234
235     scottyinfo "Performing backup."
236
237     trap cleanup_abort EXIT
238
239     prepare
240     scottysync
241
242     trap cleanup_normal EXIT
243
244     exit 0
245 }
246
247 if ! mkdir /var/lock/$(basename $0); then
248     scottyerror "Another instance of $(basename $0) is still running!"
249     exit 1
250 else
251     trap deleteLock EXIT
252 fi