]> git.sesse.net Git - backup.sh/blob - backup.sh
fikset backupscript til å varsle dersom målfilesystemet tilfeldigvis er rot (/)
[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  # Check that the target filesystem is mounted 
148  # (actually check that it's not the root filesystem)
149  rootfilesystem=`df -P /`
150  targetfilesystem=`df -P "$storagedir/$computer"`
151  if [ "$rootfilesystem" == "$targetfilesystem" ]; then
152         echo `date`" $computer: Target filesystem ($storagedir/$computer) was mounted on /. Aborting"
153         continue
154  fi
155
156  echo `date`" $computer: Backing up $computer" >&2
157
158  # Try to SSH to the computer without entering a password.
159  if ! `ssh -n -o NumberOfPasswordPrompts=0 root@$computer /bin/true`; then
160   echo `date`" $computer: Could not use passwordless SSH."
161
162   # We don't want to return 0
163   R=1
164   # Do next computer
165   continue;
166  fi
167  
168  #tømmer variabelen for sikkerhets skyld
169  filesystems=""
170
171  #Sjekker nest siste felt i fstab. Om det er 0 tar vi ikke backup
172  filesystems=`ssh -n root@$computer "cat /etc/fstab" \
173   | grep -v nfs \
174   | grep -v "^#" \
175   | grep -v "^$" \
176   | awk '{ if ( $(NF-1) != "0" ) print $2}' `
177
178  #clean up our dir at this client
179  if ! ssh root@$computer "rm -r ~/.backup ; mkdir -m 700 ~/.backup"; then
180   echo `date`" $computer: Could not create backup staging area at $computer:~/.backup - skipping backup of $computer"
181   # We don't want to return 0
182   R=1
183   continue;
184  fi
185
186  #try to copy $exclude to $computer
187  if ! scp $exclude root@$computer:~/.backup/exclude > /dev/null; then
188   echo `date`" $computer: Could not copy exclude.txt to $computer - skipping backup of $computer"
189   # We don't want to return 0
190   R=1
191   continue;
192  fi
193
194  #try to copy preeexec and postexec if they exist
195 # TODO: Gah, clean this mess!
196  [ -f $confdir/preexec.$computer ] && (
197     scp $confdir/preexec.$computer  root@$computer:~/.backup/preexec >&2 ||
198      ( echo `date`" $computer: Could not copy preexec.$computer to $computer:~/.backup/preexec - skipping backup of $computer"
199        R=1
200        continue
201      )
202     )
203  [ -f $confdir/postexec.$computer ] && (
204     scp $confdir/postexec.$computer root@$computer:~/.backup/postexec >&2 ||
205      ( echo `date`" $computer: Could not copy postexec.$computer to $computer:~/.backup/postexec - skipping backup of $computer"
206        R=1
207        continue
208      )
209     )
210
211  #try to run preexec if it exist
212  if ! ssh root@$computer "[ ! -f ~/.backup/preexec ] || /bin/bash -x ~/.backup/preexec" >&2; then
213         echo `date`" $computer: Could not run $computer:~/.backup/preexec - skipping backup of $computer"
214         R=1
215         continue
216  fi
217
218
219  for filesystem in $filesystems
220  do
221   #lager en variant uten tegnet "/" eller $ (gjelder NT)
222   sfilesystem=`echo $filesystem | tr '\/\$' '__'`
223
224   #lager det som trengs av kataloger
225   mkdir -m 755 -p $storagedir/$computer/$sfilesystem/{full,daglig} 2>/dev/null
226
227   echo $filesystem > ${storagedir}/${computer}/.${sfilesystem}.name 
228   chmod 644 ${storagedir}/${computer}/.${sfilesystem}.name
229
230   #set default backuplevel
231   backuplevel=daglig
232
233   if [ ! -f $storagedir/$computer/$sfilesystem/.date ]
234   then
235    #take the first full backup of this filesystem on this computer
236    backuplevel=full
237    echo $DATEs > $storagedir/$computer/$sfilesystem/.date
238   fi
239
240   #sjekker om det er på tide med en full
241   if [ -z "`find $storagedir/$computer/$sfilesystem/full/ -name \*tgz -mtime -$dagermellomfulle`" ]; then
242    backuplevel=full
243   fi
244  
245   #gå ned i rett katalog, eller dø 
246   # TODO bør sende mail om dette skjer!
247   cd $storagedir/$computer/$sfilesystem/$backuplevel || die
248
249   #perform the actual backup
250   backup
251
252   # Sjekk om det skal være et annet antall fulle backuper av en boks
253   if [ -f $confdir/maksfulle.$computer ] ; then
254     mf=$((`cat $confdir/maksfulle.$computer`+1))
255   else
256     mf=$(($maksantallfulle+1))
257   fi
258
259   #delete complete backups
260   for full in `ls -1t $storagedir/$computer/$sfilesystem/full/*tgz | tail -n +$mf`
261   do
262    prefix=`echo $full | sed "s/\.[^.]*$//"`
263    echo `date`": $computer:$filesystem sletter full $prefix (for mange)" >&2
264    rm $prefix*
265   done
266
267   #delete incremental backups older than the oldest complete backup
268   oldf=`ls -t1 $storagedir/$computer/$sfilesystem/full/*tgz | tail -1`
269   find \
270      $storagedir/$computer/$sfilesystem/daglig \
271      -type f \
272      \! -newer $oldf \
273      -exec rm {} \;
274  done
275
276  #try to run postexec if it exist
277  if ! ssh root@$computer "[ ! -f ~/.backup/postexec ] || /bin/bash -x ~/.backup/postexec" >&2; then
278         echo `date`" $computer: Could not run $computer:~/.backup/postexec"
279         R=1
280  fi
281
282 )  
283 done &
284
285 wait
286
287 # Remove lockfile
288 rm $LOCKFILE
289
290 # Did anything go wrong?
291 # (IMPORTANT NOTE: The R-business does not work as expected, since this script
292 # forks itself.
293 if [ $R != 0 ]; then
294         echo `date`": Backup run ended with errors, check logs."
295         exit 1
296 else
297         echo `date`": Backup run ended" >&2
298 fi