]> git.sesse.net Git - backup.sh/blob - backup.sh
now run backups in parallell again
[backup.sh] / backup.sh
1 #!/bin/sh
2
3 # TODO(sesse, 2007-12-16): 
4 #  * Fiks så parallelliseringen fungerer igjen
5 #  * Bruk tee i stedet for en separat tar ztvf-prosess
6 #  * Sjekk hvorfor .idx-filene til UD er blitt 0 for siste fullbackuper
7
8 # Locking
9 LOCKFILE=/home/backup/backuprun.lockfile
10
11 # Initially, we consider everything to be just fine.
12 R=0
13
14 # Die more or less gracefully (at least notify user)
15 die() {
16         echo `date`": Something nasty happened, and since I fork a lot:"
17         echo `date`": I CANNOT CLEAN UP THE MESS MYSELF."
18         echo `date`": You need to get rid of lost process named stuff like $0, tar and ssh."
19         exit 255
20 }
21
22 # Trap C-c and kill
23 trap die SIGINT SIGTERM
24
25 # Don't start if we're already running
26 if [ -e $LOCKFILE ]; then
27         echo `date`": $LOCKFILE exists, exiting."
28         echo `date`": $LOCKFILE exists, exiting." >&2
29         exit 1
30 fi;
31 touch $LOCKFILE
32
33 #dirs
34 confdir=/home/backup/conf/           #configuration files
35 storagedir=/backup                   #mountpoint of huge disc
36 ###
37
38 #exclude-pattern
39 exclude=$confdir/exclude
40 [ ! -f $exclude ] && printf "tmp\ncore\n" > $exclude
41 ###
42
43 #syntax of remotestat:
44 #hostname:/directory/
45 remotestatf=$confdir/remotestat
46 [ -f $remotestatf ] && remotestat=`cat $remotestatf`
47 ###
48
49 PATH=/local/bin:$PATH:/store/bin
50 export PATH
51
52 #start the logfile
53 echo `date`": Backup run starting" >&2
54
55 umask 027
56
57 # The computers we want to back up
58 unixcomputers=`cat $confdir/computers.unix \
59   | grep -v "^#" \
60   | grep -v "^$" `
61
62 # Backup only one computer, from command line?
63 if [ $1 ] ; then 
64   unixcomputers=$1
65 fi;
66
67 #disse bør kunne varieres fra fs til fs?
68 maksantallfulle=3          #hvor mange fulle vi tar vare på
69 dagermellomfulle=30        #antall dager før det er på tide med ny full
70 logw=40
71 ###
72
73 #lager datovariabeler
74 DATE=`date "+%Y%m%d%H%M"`            #format: touch
75 DATEs=`date "+%Y-%m-%d %H:%M"`       #format: tar
76 ###
77
78 #selve backupen
79 # krever at noen variabler er satt
80 # krever at vi er i rett katalog
81 backup()
82 {
83
84  echo -n `date` >&2
85  printf " $computer: %-${logw}s %s\n" "$computer:$filesystem" "$backuplevel backup" >&2
86
87  if [ "$backuplevel" = "daglig" ] || [ "$backuplevel" = "incremental" ]
88  then
89   lastd=`cat ../.date`
90   lastcmd="--newer='$lastd'"
91  else
92   lastcmd=""
93  fi
94
95  #if this client has a special tar
96  #we need to find a better solution to this conf-issue
97  if [ -f $confdir/tar.$computer ] ; then
98    tar=`cat $confdir/tar.$computer`
99  else 
100    tar=tar
101  fi
102
103  #expand the exclude-path for use with tar
104  exf=`ssh root@$computer "ls ~/.backup/exclude"`
105
106  #We try to run tar on the remote computer
107  #    z gzip it
108  #    c create archive
109  #    C change to directory first
110  #    - output to stdout (we pipe to gzip, then to dd)
111  #    . where to start taring (see C)
112  #    $lastcmd only files newer than this
113  #    --exclude-from file to get exclusion pattern from
114  #    pipe to gzip, which in turn pipes over the ssh-stream
115  #    ..to dd, to output to a file. We surpress messages from dd.
116  #    And at last, redirect stderr to stdout, to get output logged.
117  TARFILE=$DATE.tmp
118  TARCMD="ssh root@$computer \"$tar --one-file-system -zcf - -C $filesystem . $lastcmd \
119         --exclude-from=$exf\" > $TARFILE"
120  echo `date`" $computer: Running $TARCMD" >&2
121  eval $TARCMD;
122  if [ -s $TARFILE ]; then
123   mv $TARFILE $DATE.tgz
124   #make a filelist.
125   #update the datefile if the filelist is ok.
126   tar tvfz $DATE.tgz > $DATE.idx 2>&1 &&
127     echo $DATEs > ../.date            &&
128     touch -t $DATE ../.date
129
130   #make a sortet filelist
131   grep -v ^d $DATE.idx | sort -n -r -k 2 > $DATE.sdx
132
133   #fix perm
134   chmod 600 *tgz                      #only for us
135   chmod 644 *sdx *idx 2>/dev/null     #everyone can read
136
137  else
138   #it did not work
139   rm $TARFILE
140   echo `date`" $computer: $TARFILE empty. $backuplevel backup of $computer:$filesystem failed and deleted"
141
142   # We don't want to return 0
143   R=1
144  fi
145
146 }
147
148 #Løper gjennom listen av unixmaskiner som vi skal ta backup av
149 for computer in $unixcomputers
150 do
151
152  # Check that the target filesystem is mounted 
153  # (actually check that it's not the root filesystem)
154  rootfilesystem=`df -P /`
155  targetfilesystem=`df -P "$storagedir/$computer"`
156  if [ "$rootfilesystem" == "$targetfilesystem" ]; then
157         echo `date`" $computer: Target filesystem ($storagedir/$computer) was mounted on /. Aborting"
158         continue
159  fi
160
161  echo `date`" $computer: Backing up $computer" >&2
162
163  # Try to SSH to the computer without entering a password.
164  if ! `ssh -n -o NumberOfPasswordPrompts=0 root@$computer /bin/true`; then
165   echo `date`" $computer: Could not use passwordless SSH."
166
167   # We don't want to return 0
168   R=1
169   # Do next computer
170   continue;
171  fi
172  
173  #tømmer variabelen for sikkerhets skyld
174  filesystems=""
175
176  #Sjekker nest siste felt i fstab. Om det er 0 tar vi ikke backup
177  filesystems=`ssh -n root@$computer "cat /etc/fstab" \
178   | grep -v nfs \
179   | grep -v "^#" \
180   | grep -v "^$" \
181   | awk '{ if ( $(NF-1) != "0" ) print $2}' `
182
183  #clean up our dir at this client
184  if ! ssh root@$computer "rm -r ~/.backup ; mkdir -m 700 ~/.backup"; then
185   echo `date`" $computer: Could not create backup staging area at $computer:~/.backup - skipping backup of $computer"
186   # We don't want to return 0
187   R=1
188   continue;
189  fi
190
191  #try to copy $exclude to $computer
192  if ! scp $exclude root@$computer:~/.backup/exclude > /dev/null; then
193   echo `date`" $computer: Could not copy exclude.txt to $computer - skipping backup of $computer"
194   # We don't want to return 0
195   R=1
196   continue;
197  fi
198
199  #try to copy preeexec and postexec if they exist
200 # TODO: Gah, clean this mess!
201  [ -f $confdir/preexec.$computer ] && (
202     scp $confdir/preexec.$computer  root@$computer:~/.backup/preexec >&2 ||
203      ( echo `date`" $computer: Could not copy preexec.$computer to $computer:~/.backup/preexec - skipping backup of $computer"
204        R=1
205        continue
206      )
207     )
208  [ -f $confdir/postexec.$computer ] && (
209     scp $confdir/postexec.$computer root@$computer:~/.backup/postexec >&2 ||
210      ( echo `date`" $computer: Could not copy postexec.$computer to $computer:~/.backup/postexec - skipping backup of $computer"
211        R=1
212        continue
213      )
214     )
215
216  #try to run preexec if it exist
217  if ! ssh root@$computer "[ ! -f ~/.backup/preexec ] || /bin/bash -x ~/.backup/preexec" >&2; then
218         echo `date`" $computer: Could not run $computer:~/.backup/preexec - skipping backup of $computer"
219         R=1
220         continue
221  fi
222
223
224  for filesystem in $filesystems
225  do
226   #lager en variant uten tegnet "/" eller $ (gjelder NT)
227   sfilesystem=`echo $filesystem | tr '\/\$' '__'`
228
229   #lager det som trengs av kataloger
230   mkdir -m 755 -p $storagedir/$computer/$sfilesystem/{full,daglig} 2>/dev/null
231
232   echo $filesystem > ${storagedir}/${computer}/.${sfilesystem}.name 
233   chmod 644 ${storagedir}/${computer}/.${sfilesystem}.name
234
235   #set default backuplevel
236   backuplevel=daglig
237
238   if [ ! -f $storagedir/$computer/$sfilesystem/.date ]
239   then
240    #take the first full backup of this filesystem on this computer
241    backuplevel=full
242    echo $DATEs > $storagedir/$computer/$sfilesystem/.date
243   fi
244
245   #sjekker om det er på tide med en full
246   if [ -z "`find $storagedir/$computer/$sfilesystem/full/ -name \*tgz -mtime -$dagermellomfulle`" ]; then
247    backuplevel=full
248   fi
249  
250   #gå ned i rett katalog, eller dø 
251   # TODO bør sende mail om dette skjer!
252   cd $storagedir/$computer/$sfilesystem/$backuplevel || die
253
254   #perform the actual backup
255   backup
256
257   # Sjekk om det skal være et annet antall fulle backuper av en boks
258   if [ -f $confdir/maksfulle.$computer ] ; then
259     mf=$((`cat $confdir/maksfulle.$computer`+1))
260   else
261     mf=$(($maksantallfulle+1))
262   fi
263
264   #delete complete backups
265   for full in `ls -1t $storagedir/$computer/$sfilesystem/full/*tgz | tail -n +$mf`
266   do
267    prefix=`echo $full | sed "s/\.[^.]*$//"`
268    echo `date`": $computer:$filesystem sletter full $prefix (for mange)" >&2
269    rm $prefix*
270   done
271
272   #delete incremental backups older than the oldest complete backup
273   oldf=`ls -t1 $storagedir/$computer/$sfilesystem/full/*tgz | tail -1`
274   find \
275      $storagedir/$computer/$sfilesystem/daglig \
276      -type f \
277      \! -newer $oldf \
278      -exec rm {} \;
279  done
280
281  #try to run postexec if it exist
282  if ! ssh root@$computer "[ ! -f ~/.backup/postexec ] || /bin/bash -x ~/.backup/postexec" >&2; then
283         echo `date`" $computer: Could not run $computer:~/.backup/postexec"
284         R=1
285  fi
286
287 ) &
288 done
289
290 wait
291
292 # Remove lockfile
293 rm $LOCKFILE
294
295 # Did anything go wrong?
296 # (IMPORTANT NOTE: The R-business does not work as expected, since this script
297 # forks itself.
298 if [ $R != 0 ]; then
299         echo `date`": Backup run ended with errors, check logs."
300         exit 1
301 else
302         echo `date`": Backup run ended" >&2
303 fi