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