hard link instead of cp -r
[outofuni/backup.git] / bin / backup
1 #!/bin/bash
2
3 function log {
4         conf=`basename $config | sed 's/\.conf$//'`
5         [ "$dolog" = "1" ] && echo "`date` - $@" >> $logdir/${conf}.log
6 }
7
8 if [ -z "$1" ]; then
9         echo usage: $0 configfile
10         exit -1
11 fi
12
13 if [ ! -f $1 ]; then
14         echo configfile $1 is not a file
15         exit -2
16 fi
17
18 config=$1
19
20 host=`grep ^host $config | cut -s -d ' ' -f 2`
21 aliases="`grep ^aliases $config | cut -s -d ' ' -f 2-`"
22 user=`grep ^user $config | cut -s -d ' ' -f 2`
23 homedirs="` grep ^homedirs $config | cut -s -d ' ' -f 2-`"
24 extradirs="`grep ^extradirs $config | cut -s -d ' ' -f 2-`" 
25 replicas=`grep ^replicas $config | cut -s -d ' ' -f 2`
26 oldest=`grep ^oldest $config | cut -s -d ' ' -f 2`
27 data=`grep ^data $config | cut -s -d ' ' -f 2`
28 bandwidth=`grep ^bandwidth $config | cut -s -d ' ' -f 2`
29 bwconn="`grep ^bandwidth $config | cut -s -d ' ' -f 3-`"
30 compression=`grep ^compression $config | cut -s -d ' ' -f 2`
31 compconn="`grep ^compression $config | cut -s -d ' ' -f 3-`"
32 cipher=`grep ^cipher $config | cut -s -d ' ' -f 2`
33 ciconn=`grep ^cipher $config | cut -s -d ' ' -f 3-`
34 logdir=`grep ^logdir $config | cut -s -d ' ' -f 2`
35
36 dolog=0
37 if [ ! -z "$logdir" ]; then
38         mkdir -p $logdir
39         [ -d $logdir ] && dolog=1
40 fi
41
42 hit=0
43 for conn in $host $aliases; do
44         ping -c1 $conn > /dev/null 2>&1
45         ret=$?
46         if [ "$ret" = "0" ]; then
47                 remote=$conn
48                 break
49         fi
50 done
51 if [ -z "$remote" ]; then
52         log "host $host ($aliases) unreachable ..."
53         exit -3
54 else
55         log "host $host (via $remote) is online ..."
56 fi
57
58 if [ ! -z "`ssh $user@$remote 'cat ~/.backup | grep ^off'`" ]; then
59         log "backup rejected by client ..."
60         exit 0
61 fi
62
63 comp=6
64 if [ ! -z "$compression" ]; then
65         comp=$compression
66         for cpair in "$compconn"; do
67                 ch=`echo $cpair | cut -s -d ':' -f 1`
68                 if [[ "$remote" == "$ch"* ]]; then
69                         cl=`echo $cpair | cut -s -d ':' -f 2`
70                         [[ "$cl" == [0-9] ]] && comp=$cl
71                 fi
72         done
73 fi
74 rcomp="-z --compress-level $comp"
75 log using compression level $comp ...
76
77 bw=0
78 if [ ! -z "$bandwidth" ]; then
79         bw=$bandwidth
80         for bwpair in "$bwconn"; do
81                 ch=`echo $bwpair | cut -s -d ':' -f 1`
82                 if [[ "$remote" == "$ch"* ]]; then
83                         bwl=`echo $cpair | cut -s -d ':' -f 2`
84                         [ ! -z "$bwl" ] && bw=$bwl
85                 fi
86         done
87 fi
88 rbw="--bwlimit=$bw"
89 log applying bandwidth of $bw ...
90
91 ciph=""
92 if [ ! -z "$cipher" ]; then
93         ciph=$cipher
94         for cipair in "$ciconn"; do
95                 ch=`echo $cipair | cut -s -d ':' -f 1`
96                 if [[ "$remote" == "$ch"* ]]; then
97                         cl=`echo $cipair | cut -s -d ':' -f 2`
98                         [ ! -z "$cl" ] && ciph=$cl
99                 fi
100         done
101 fi
102 if [ ! -z "$ciph" ]; then
103         log using cipher $ciph ...
104 fi
105
106 if [ ! -d $data ]; then
107         log no data directory ...
108         exit -4
109 fi
110 log backing up to $data ...
111
112 today=`date -I`
113 backupdir=$data/${user}_at_${host}
114 cbd=$backupdir/$today
115
116 ob=""
117 lpb=""
118 for pb in $backupdir/[0-9]*; do
119         [ ! -d $pb ] && continue
120         bdd=`basename $pb`
121         if [ ! -f $backupdir/.$bdd ]; then
122                 if [ "$pb" != "$cbd" ]; then
123                         rm -rf $cbd
124                         mv $pb $cbd
125                         log continuing $pb as $cbd ...
126                 fi
127         else
128                 lpb=$pb
129                 ob="$ob $pb"
130         fi
131 done
132
133
134 if [ ! -d $cbd ]; then
135         if [ ! -z "$lpb" ]; then
136                 cp -al $lpb $cbd
137                 log starting backup $today from $lpb ...
138         else
139                 mkdir -p $cbd
140                 log starting backup $today from scratch ...
141         fi
142 fi
143
144 if [ ! -f $backupdir/.$today ]; then
145         rsrc=""
146         for dir in $homedirs; do
147                 rsrc="$rsrc :/home/$user/$dir"
148         done
149         rsrc="`echo $rsrc | sed 's/^\ //'`"
150         for dir in $extradirs; do
151                 rsrc="$rsrc :$dir"
152         done
153         [ ! -z "$homedirs" ] && \
154                 log backing up home directories $homedirs ...
155         [ ! -z "$extradirs" ] && \
156                 log backing up directories $extradirs ...
157
158         if [ -z "$ciph" ]; then
159                 rsync=(rsync -aR $rcomp --delete $rbw $user@$remote$rsrc $cbd)
160         else
161                 rsync=(rsync -aR -e "ssh -c $ciph" $rcomp --delete)
162                 rsync+=($rbw $user@$remote$rsrc $cbd)
163         fi
164         res=`"${rsync[@]}" 2>&1`
165
166         ret=$?
167         if [ "$ret" != "0" ]; then
168                 log backup terminated before completion ...
169                 log reason:
170                 log $res
171                 exit -50
172         fi
173         
174         touch $backupdir/.$today
175         log "backup $today completed :)"
176 else
177         log backup $bdd found completed ...
178 fi
179
180 [ -z "$replicas" ] && replicas=3
181 [ -z "$oldest" ] && oldest=0
182
183 cob=`echo $ob | wc -w`
184 if [ $cob -gt $replicas ]; then
185         ((numdel=cob-replicas))
186         todel="`echo $ob | cut -s -d ' ' -f 1-${numdel}`"
187         for dirdel in $todel; do
188                 past=`basename $dirdel`
189                 ns=`date --date="$today" +%s`
190                 ps=`date --date="$past" +%s`
191                 ((delta=(ns-ps)/86400))
192                 if [ $delta -gt $oldest ]; then
193                         log "deleting $dirdel ($delta days old) ..."
194                         bdd=`basename $dirdel`
195                         rm -r $dirdel
196                         rm $backupdir/.$bdd
197                 else
198                         log "keeping $dirdel ($delta days old) ..."
199                 fi
200         done
201 fi
202
203 exit 0