Added rhatto's rub handler, a second try at a rsync snapshot
[matthijs/upstream/backupninja.git] / handlers / rub
1 #
2 # backupninja handler to do incremental backups using
3 # rsync and hardlinks, based on
4 #
5 #   http://www.mikerubel.org/computers/rsync_snapshots/
6 #
7 # feedback: rhatto at riseup.net | gpl
8 #
9 # config file options
10 # -------------------
11 #
12 #   [general]
13 #   log = rsync log file
14 #   partition = partition where the backup lives
15 #   fsck = set to 1 if fsck should run on $partition after the backup is made
16 #   read_only = set to 1 if $partition is mounted read-only
17 #   mountpoint = backup partition mountpoint or backup main folder
18 #   backupdir = folder relative do $mountpoint where the backup should be stored
19 #   days = number of backup increments (min = 5)
20 #   lockfile = lockfile to be kept during backup execution
21 #
22 #   [source]
23 #   include = include folder on backup
24 #   exclude = exclude folder on backup
25 #   from = local or remote
26 #   ssh = ssh command line (remote only)
27 #   rsync = rsync command line
28 #   exclude_vserver = vserver-name (valid only if vservers = yes on backupninja.conf)
29 #
30 #   [services]
31 #   initscripts = absolute path where scripts are located
32 #   service = script name to be stoped at the begining of the backup and started at its end
33 #
34 # You dont need to manually specify vservers using "include = /vservers".
35 # They are automatically backed-up if vserver is set to "yes" on your backupninja.conf.
36 #
37
38 setsection general
39 getconf log /var/log/backupninja-rub.log
40 getconf partition
41 getconf fsck
42 getconf read_only
43 getconf mountpoint
44 getconf backupdir
45 getconf rotate
46 getconf days
47 getconf lockfile
48
49 setsection source
50 getconf from local
51 getconf rsync "rsync -av --delete"
52 getconf ssh ssh
53 getconf user
54 getconf host
55 getconf include
56 getconf exclude
57 getconf exclude_vserver
58
59 setsection services
60 getconf initscripts
61 getconf service
62
63 backupdir="$mountpoint/$backupdir"
64
65 if [ ! -d "$backupdir" ]; then 
66   error "Backupdir $backupdir does not exist"
67   exit 1
68 fi
69
70 if [ -z "$days" ]; then
71   keep="4"
72 else
73   keep="`echo $days - 1 | bc -l`"
74 fi
75
76 if [ ! -z "$lockfile" ]; then
77   touch $lockfile || warning "Could not create lockfile $lockfile"
78 fi
79
80 for path in $exclude; do
81   EXCLUDES="$EXCLUDES --exclude=$path"
82 done
83
84 if [ ! -z "$service" ]; then
85   for daemon in $service; do
86     info "Stopping service $daemon..."
87     $initscripts/$daemon stop
88   done
89 fi
90
91 function rotate {
92
93   # please use an absolute path
94
95   if [[ "$2" < 4 ]]; then
96     error "Rotate: minimum of 4 rotations"
97     exit 1
98   fi
99
100   if [ -d $1.$2 ]; then
101     mv $1.$2 $1.tmp
102   fi
103
104   for ((n=`echo "$2 - 1" | bc`; n >= 0; n--)); do
105     if [ -d $1.$n ]; then
106       dest=`echo "$n + 1" | bc`
107       mv $1.$n $1.$dest
108       touch $1.$dest
109     fi
110   done
111
112   if [ -d $1.tmp ]; then
113     mv $1.tmp $1.0
114   fi
115
116   if [ -d $1.1 ]; then
117     cp -alf $1.1/. $1.0
118   fi
119
120 }
121
122 echo "Starting backup at `date`" >> $log
123
124 if [ "$read_only" == "1" ] || [ "$read_only" == "yes" ]; then
125   if [ -d "$mountpoint" ]; then
126     mount -o remount,rw $mountpoint
127     if (($?)); then
128       error "Could not mount $mountpoint"
129       exit 1
130     fi
131   fi
132 fi
133
134 if [ "$vservers_are_available" == "yes" ]; then
135
136   # sane permission on backup
137   mkdir -p $backupdir/$VROOTDIR
138   chmod 000 $backupdir/$VROOTDIR
139
140   for candidate in `ls $VROOTDIR`; do
141     found_excluded_vserver="0"
142     if [ "$candidate" != "lost+found" ]; then
143       for excluded_vserver in $exclude_vserver; do
144         if [ "$excluded_vserver" == "$candidate" ]; then
145           found_excluded_vserver="1"
146           break
147         fi
148       done
149       if [ "$found_excluded_vserver" == "0" ]; then
150         include="$include $VROOTDIR/$candidate"
151       fi
152     fi
153   done
154 fi
155
156 for SECTION in $include; do
157
158   section="`basename $SECTION`"
159
160   if [ ! -d "$backupdir/$SECTION/$section.0" ]; then
161     mkdir -p $backupdir/$SECTION/$section.0
162   fi
163  
164   info "Rotating $backupdir/$SECTION/$section..."
165   echo "Rotating $backupdir/$SECTION/$section..." >> $log
166   rotate $backupdir/$SECTION/$section $keep
167   info "Syncing $SECTION on $backupdir/$SECTION/$section.0..."
168
169   if [ "$from" == "local" ]; then
170     debug $rsync $EXCLUDES /$SECTION/ $backupdir/$SECTION/$section.0/ 
171     $rsync $EXCLUDES /$SECTION/ $backupdir/$SECTION/$section.0/ >> $log
172     if [ "$?" != "0" ]; then
173       warning "Rsync error when trying to transfer $SECTION"
174     fi
175   elif [ "$from" == "remote" ]; then
176     if [ -z "$user" ] || [ -z "$host" ]; then
177       error "Config file error: either user or host was not specified"
178       exit 1
179     else
180       debug $rsync $EXCLUDES -e "$ssh" $user@$host:/$SECTION/ $backupdir/$SECTION/$section.0
181       $rsync $EXCLUDES -e "$ssh" $user@$host:/$SECTION/ $backupdir/$SECTION/$section.0 >> $log
182       if [ "$?" != "0" ]; then
183         warning "Rsync error when trying to transfer $SECTION"
184       fi
185     fi
186   else
187     error "Invalid source $from"
188     exit 1
189   fi
190
191   touch $backupdir/$SECTION/$section.0
192
193 done
194
195 if [ "$read_only" == "1" ] || [ "$read_only" == "yes" ]; then
196   mount -o remount,ro $mountpoint
197 fi
198
199 if [ "$fsck" == "1" ] || [ "$fsck" == "yes" ]; then
200   umount $mountpoint
201   if (($?)); then
202     warning "Could not umount $mountpoint to run fsck"
203   else
204     fsck -v -y $partition >> $log
205     mount $mountpoint
206   fi
207 fi
208
209 if [ ! -z "$service" ]; then
210   for daemon in $service; do
211     info "Starting service $daemon..."
212     $initscripts/$daemon start
213   done
214 fi
215
216 if [ ! -z "$lockfile" ]; then
217   rm $lockfile || warning "Could not remove lockfile $lockfile"
218 fi
219
220 echo "Finnishing backup at `date`" >> $log
221