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