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