Subject: Automatic Informix Data Base Backup
From: Sujit Pal <[email-masked]>
Date: Mon, 08 Dec 1997 13:14:36 MST

Sometime ago I released a backup script which does backups through cron, based
on a user-defined backup schedule. The backups are done to the disk and to
preserve space it is piped through a compression utility such as compress or
gzip. In case of errors it sends a mail to one or more people whose email-ids
are stored in an input file.

------------------------------------8<----------------------------------------
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Sujit Pal <spal@scotch> on Mon Dec  8 13:13:10 1997
#
# This archive contains:
#	IDBB.dba	IDBB.lst	IDBB.sh		crontab		
#
# Error checking via sum(1) will be performed.

LANG=""; export LANG
PATH=/bin:/usr/bin:/usr/sbin:/usr/ccs/bin:$PATH; export PATH

if sum -r </dev/null >/dev/null 2>&1
then
	sumopt='-r'
else
	sumopt=''
fi

echo x - IDBB.dba
cat >IDBB.dba <<'@EOF'
your_email_address@your_server_name
@EOF
set `sum $sumopt <IDBB.dba`; if test $1 -ne 43861
then
	echo ERROR: IDBB.dba checksum is $1 should be 43861
fi

chmod 644 IDBB.dba

echo x - IDBB.lst
cat >IDBB.lst <<'@EOF'
# Backup List for Scotch Database Instances 
# ONCONFIG              SCHEDULE
# FILE    	 	SMTWTFS
onconfig_file_name	012012-
# This implies Level 0 backup of the instance pointed to by
# onconfig_file_name on Sunday, Level 1 on Monday, Level 2
# on Tuesday, ... and so on ..., and no backup (indicated
# by -) on Sunday.
@EOF
set `sum $sumopt <IDBB.lst`; if test $1 -ne 57715
then
	echo ERROR: IDBB.lst checksum is $1 should be 57715
fi

chmod 644 IDBB.lst

echo x - IDBB.sh
cat >IDBB.sh <<'@EOF'
#!/bin/ksh
#
# IDBB - Automatic Informix Data Base Backup
#
# Automated backup process. Will read the /infxbkup/IDBB.lst file
# to determine the database instances to back up and the backup
# schedule that needs to be followed. Based on the day of week
# the backup level will be either level 0, 1 or 2. This is a batch
# process which needs to be run by cron.
#
# Author: Sujit Pal
# Date:   12/08/1996
#

#
# Common function to do a level 0, 1 or 2 backup depending on $bklvl
#
backit()
{
#
# Check if enough space available on disk. Heuristic based on 1st run:
#    Level 0 gzipped is 20% of used database space.
#    Level 1 gzipped is  5% of used database space.
#    Level 2 gzipped is  5% of used database space.
#
   case $rbklvl in
      0) reqspace=$(($dataspace/5))
         ;;
      1) reqspace=$(($dataspace/20))
         ;;
      2) reqspace=$(($dataspace/20))
         ;;
   esac
   if [ $reqspace -gt $freespace ]
   then
      echo "IDBB Error: Level $rbklvl backup for ($onconfig_file) failed. No space." \
	| tee -a $DUMPDIR/IDBB.log
   else
      echo "IDBB Log: Level $rbklvl Backup will be done for ($onconfig_file)" \
   	   | tee -a $DUMPDIR/IDBB.log
      echo "IDBB Log: Level $rbklvl Backup started: `date`" | tee -a IDBB.log
#
# Make a copy of the $INFORMIXDIR/etc/$ONCONFIG to a backup file.
# sed the TAPEDEV to $instname.l$bklvl.
# Create a FIFO called $instname.l$bklvl with permissions 0777. Set
# up the file to write to "|gzip - > $instname.l$bklvl.gz". Preserve
# the pid of the process. Run the ontape. At the end of the ontape
# remove the pipe and kill the process. Copy the original ONCONFIG
# file to the temporary one.
#
      mkfifo $DUMPDIR/$bkdev
      chmod 777 $DUMPDIR/$bkdev
      gzip - <$DUMPDIR/$bkdev >$DUMPDIR/$bkdev.gz &
      bgpid=$!
      cp $INFORMIXDIR/etc/$ONCONFIG $INFORMIXDIR/etc/$ONCONFIG.old
      sed -e "s%/dev/null%$DUMPDIR/$bkdev%" $INFORMIXDIR/etc/$ONCONFIG > \
   	   $INFORMIXDIR/etc/$ONCONFIG.new
      mv $INFORMIXDIR/etc/$ONCONFIG.new $INFORMIXDIR/etc/$ONCONFIG
      if [ `echo $onconfig_file | cut -c1-2` = "tb" ]
      then
         tbtape -s -L $rbklvl <<EOF

EOF
      else
         ontape -s -L $rbklvl <<EOF

EOF
      fi
      ontape_failed=$?
      if [ $ontape_failed -ne 0 ]
      then
         echo "IDBB Error: Level $rbklvl backup failed on Instance ($onconfig_file)" | \
           tee -a $DUMPDIR/IDBB.log
      fi
      wait $bgpid
      mv $INFORMIXDIR/etc/$ONCONFIG.old $INFORMIXDIR/etc/$ONCONFIG
      rm -f $DUMPDIR/$bkdev
      chmod 0444 $DUMPDIR/$bkdev.gz
      echo "IDBB Log: Level $rbklvl Backup ended: `date`" | tee -a IDBB.log
   fi
}

#
# Main
#

#
# Include constants. DUMPDIR is the directory that is set up for a
# given host and KPERPAGE is the number of KBytes a DB Page has on
# this host. On HP-UX it is 2 and on AIX it is 4.
#
DUMPDIR=/dbdump
KPERPAGE=2
#

PATH=$PATH:/bin:/usr/bin:/usr/local/bin
export PATH
rm -f $DUMPDIR/IDBB.log
#
# Loop through the $DUMPDIR/IDBB.lst file to determine the
# database instance to backup.
#
cat $DUMPDIR/IDBB.lst | while read INST_LIST
do
#
#    Set the environment to access the database. Check to
#    see if instance is online, if not write to error log
#    and loop to the next instance.
#
   if [ `echo $INST_LIST | cut -c1-1` = '#' ]
   then
      continue
   fi
   onconfig_file=`echo $INST_LIST | awk '{print $1}'`
   onconfig_dir=`du -a /usr/informix* | awk '{print $2}' \
	| grep $onconfig_file | uniq`
   INFORMIXDIR=`echo $onconfig_dir | awk -F"/" '{print $2,$3}' | \
	sed -e 's/^/\//' -e 's/ /\//'`
   export INFORMIXDIR
   PATH=$INFORMIXDIR/bin:$PATH
   export INFORMIXDIR
   if [ `echo $onconfig_file | cut -c1-2` = "tb" ]
   then   # This is version 5, use tb commands
      TBCONFIG=$onconfig_file
      export TBCONFIG
   else   # This is version 7, use on commands
      ONCONFIG=$onconfig_file
      export ONCONFIG
      INFORMIXSERVER=`cat $onconfig_dir | grep "^DBSERVERNAME" | \
	uniq | awk '{print $2}`
      export INFORMIXSERVER
   fi
   is_online=`onstat - | grep "On\-Line" | wc -l`
   if [ $is_online -eq 0 ]
   then
      echo "IDBB Error: Instance ($onconfig_file) not online" | \
	tee -a $DUMPDIR/IDBB.log
      continue
   fi
#
#    Determine the backup level to be performed today. The
#    level is indicated for the instance by a 7-char string
#    that gives the backup levels for the week SMTWTFS. 0,
#    1 and 2 represent level 0, 1 and 2 and - indicates no
#    backup needed.
#
   day=`date | cut -f1 -d" "`
   case $day in
      "Sun") dow=1;;
      "Mon") dow=2;;
      "Tue") dow=3;;
      "Wed") dow=4;;
      "Thu") dow=5;;
      "Fri") dow=6;;
      "Sat") dow=7;;
   esac
   bklvl=`echo $INST_LIST | awk '{print $2}' | cut -c$dow-$dow`
   if [ $bklvl = "-" ]
   then
      echo "IDBB Log: No backup needed for ($onconfig_file)" | \
	tee -a $DUMPDIR/IDBB.log
      continue
   fi
#
#    Calculate the used database space against the available
#    disk space to determine if the backup should continue.
#    Both dataspace and freespace are in 512 K blocks.
#
   dataspace=`onstat -d | sed -e '1,/offset/d' -e '/active/,$d' | \
	awk '{dataspace += $5-$6} END {printf("%d", dataspace*2*KPERPAGE)}'`
   freespace=`df $DUMPDIR | cut -f2 -d":" | awk '{print $1}'`
#
#    If $bklvl = 0, then delete all the backup files. If $bklvl > 0 
#    then look for previous levels. If they dont exist, create them.
#
   instname=`echo $onconfig_file | cut -f2 -d"."`
   case $bklvl in
      0)  if [ -f $DUMPDIR/$instname.l0.gz ]
          then
             if [ -f $DUMPDIR/$instname.l[12].gz ]
             then
                rm -f $DUMPDIR/$instname.l[012].gz
	     else
                echo "IDBB Error: Level 0 backup for $onconfig_file already done" \
		   | tee -a $DUMPDIR/IDBB.log
                continue
             fi
          fi
          bkdev=`echo $instname".l0"`
          rbklvl=0
	  backit
	  ;;
      1)  if [ -f $DUMPDIR/$instname.l1.gz ]
          then
             echo "IDBB Error: Level 1 backup for $onconfig_file already done" \
		| tee -a $DUMPDIR/IDBB.log
             continue
          fi
          if [ -f $DUMPDIR/$instname.l0.gz ]
	  then
             bkdev=`echo $instname".l1"`
             rbklvl=1
	     backit
          else
             bkdev=`echo $instname".l0"`
             rbklvl=0
	     backit
             bkdev=`echo $instname".l1"`
             rbklvl=1
	     backit
	  fi
	  ;;
      2)  if [ -f $DUMPDIR/$instname.l2.gz ]
          then
             echo "IDBB Error: Level 2 backup for $onconfig_file already done" \
		| tee -a $DUMPDIR/IDBB.log
             continue
          fi
          if [ -f $DUMPDIR/$instname.l0.gz ]
	  then
             if [ -f $DUMPDIR/$instname.l1.gz ]
             then
	        bkdev=`echo $instname".l2"`
                rbklvl=2
	        backit
             else
	        bkdev=`echo $instname".l1"`
                rbklvl=1
	        backit
	        bkdev=`echo $instname".l2"`
                rbklvl=2
	        backit
	     fi
          else
	     bkdev=`echo $instname".l0"`
             rbklvl=0
	     backit
	     bkdev=`echo $instname".l1"`
             rbklvl=1
	     backit
	     bkdev=`echo $instname".l2"`
             rbklvl=2
	     backit
	  fi
	  ;;
   esac
done
#
# Mail the error log information to the email addresses in the 
# $DUMPDIR/IDBB.dba files. Better still, grep for "IDBB Error"
# and if found mail the contents to DBAs.
#
if [ `cat $DUMPDIR/IDBB.log | grep "IDBB Error" | wc -l` -gt 0 ]
then
   hostname=`hostname`
   today=`date +%x`
   cat $DUMPDIR/IDBB.dba | while read dba_email
   do
      cat $DUMPDIR/IDBB.log | mailx -s "Backup log for $hostname on $today" \
	   $dba_email
   done
fi
@EOF
set `sum $sumopt <IDBB.sh`; if test $1 -ne 55573
then
	echo ERROR: IDBB.sh checksum is $1 should be 55573
fi

chmod 755 IDBB.sh

echo x - crontab
cat >crontab <<'@EOF'
#
# Informix Crontab
#
# This is a sample crontab file that I used. This says to run the backup
# job /dbdump/IDBB.sh at 6:00 pm every day for the days 1-6 (Monday thru
# Saturday) every day every month.
#
# Format:
# Minute  Hour  Monthday  Month  Weekday  command
# 0-59    0-23  1-31      1-12   0-6 (0=Sunday)
#
0 18 * * 1-6 /dbdump/IDBB.sh
@EOF
set `sum $sumopt <crontab`; if test $1 -ne 51729
then
	echo ERROR: crontab checksum is $1 should be 51729
fi

chmod 644 crontab

exit 0
------------------------------------8<----------------------------------------