#!/usr/bin/ksh PROGNAME=`basename $0` ############################################################################### # # FLAT FILE DATABASE # ############################################################################### ############################################################################### # # CONFIGURABLE STUFF # ############################################################################### ############################################################################### # # CONFIGURABLE STUFF ENDS HERE # ############################################################################### # Set a load of important variables PATH=/bin:/sbin:/usr/bin:/usr/sbin:/etc:/usr/etc:/usr/local/bin:/usr/local/sbin VERBOSE_LEVEL=5 # verbosity level:3=info,warnings,errors TMP_DIR=/var/tmp # where to stash temporary files ERRORS_CAUSE_EXITS=true # error() calls without options do exits # $Id: dailybackup-hpux10.in,v 1.1 1998/05/05 16:29:06 alexis Exp $ VERSION="PATCHLEVEL_MARKER" # version id ############################################################################### # # MAIN FUNCTION (called from very bottom of script) # ############################################################################### main() { ########################################################################### # # PROCESS OPTIONS # ########################################################################### # default values for things modified by options MODE=unset # process command line REAL options while [ "X$1" != X ]; do case $1 in -V) if expr "$VERSION" : 'P.*R$' > /dev/null; then warning "this is development version; use 'ident'" exit 1 else echo "$PROGNAME version $VERSION" exit 0 fi ;; -[cisdu]) break ;; -*) usage ;; esac shift done case $1 in -c) MODE=create ;; -i) MODE=insert ;; -s) MODE=select ;; -d) MODE=delete ;; -u) MODE=update ;; *) usage ;; esac shift case $MODE in create) create_table "$@" ;; insert) insert_record_in_table "$@" ;; delete) delete_record_in_table "$@" ;; select) select_record_in_table "$@" ;; update) update_record_in_table "$@" ;; unset) usage ;; esac } usage_create_table() { { echo "Usage: $PROGNAME -c " } >&2 exit 1 } create_table() { [ "X$1" = X -o "X$2" != X ] && usage_create_table TABLE=$1 shift [ -f $TABLE ] && error -e "table '$TABLE' exists!" touch $TABLE 2>/dev/null || error -e "unable to create $TABLE" } usage_select_record_in_table() { { echo "Usage: $PROGNAME -s [ -c ]
[ ]" } >&2 exit 1 } select_record_in_table() { COLUMN_EXTRACTION_CMD=cat while [ "X$1" != X ]; do case $1 in -[cf]) COLUMN_EXTRACTION_CMD="cut -f$2 -d:" shift ;; -*) usage_select_record_in_table ;; *) break ;; esac shift done [ "X$1" = X ] && usage_select_record_in_table TABLE=$1 shift if [ "X$1" != X ]; then ROW_EXTRACTION_CMD="egrep \"$1\" $TABLE" shift else ROW_EXTRACTION_CMD="cat $TABLE" fi [ ! -r $TABLE ] && error -e "table '$TABLE' not accessible" lock $TABLE debug 5 "shell command: $ROW_EXTRACTION_CMD | $COLUMN_EXTRACTION_CMD" eval $ROW_EXTRACTION_CMD | $COLUMN_EXTRACTION_CMD unlock $TABLE } usage_update_record_in_table() { { echo "Usage: $PROGNAME -u
[ .... ]" } >&2 exit 1 } update_record_in_table() { debug 5 "update_record_in_table: sof" [ "X$2" = X ] && usage_update_record_in_table TABLE=$1 PRIKEY=$2 shift shift debug 5 "update_record_in_table: calling delete_record_in_table" delete_record_in_table $TABLE $PRIKEY debug 5 "update_record_in_table: calling insert_record_in_table" insert_record_in_table $TABLE $PRIKEY "$@" } usage_insert_record_in_table() { { echo "Usage: $PROGNAME -i
[ .... ]" } >&2 exit 1 } insert_record_in_table() { [ "X$2" = X ] && usage_insert_record_in_table TABLE=$1 shift PRIKEY=$1 shift [ ! -r $TABLE ] && error -e "table '$TABLE' not accessible" lock $TABLE egrep -q "^$PRIKEY:" $TABLE && { unlock $TABLE; error -e "key '$PRIKEY' already exists in table '$TABLE'"; } RECORD="$PRIKEY" for FIELD in "$@"; do RECORD="$RECORD:$FIELD" done echo $RECORD >> $TABLE unlock $TABLE } usage_delete_record_in_table() { { echo "Usage: $PROGNAME -d
" } >&2 exit 1 } delete_record_in_table() { [ "X$2" = X -o "X$3" != X ] && usage_delete_record_in_table TABLE=$1 PRIKEY=$2 shift shift [ ! -r $TABLE ] && error -e "table '$TABLE' not accessible" lock $TABLE egrep -q "^$PRIKEY:" $TABLE || { unlock $TABLE; error -e "can't locate primary key '$PRIKEY' in table '$TABLE'"; } cp $TABLE $TMP_DIR/$PROGNAME.$$.tmptbl egrep -v "^$PRIKEY:" $TMP_DIR/$PROGNAME.$$.tmptbl > $TABLE unlock $TABLE } ############################################################################### # # RESILIANT MESSAGING FUNCTIONS # ############################################################################### usage() { { echo "Usage: $PROGNAME { -c | -i | -d | -s | -u } [ ]" echo " $PROGNAME -V" } >&2 exit 1 } internal() { MSG="INTERNAL ERROR: $*" DATE=`date` # echo it so that the user can see it or cron can trap it (split line # to avoid confusing 'ident') echo "$PROGNAME: \ $MSG" >&2 # try to write it into $LOG_FILE if that's defined - other message types # treat unwritable but defined LOG_FILE as an error ( echo "$DATE: \ $MSG" >> ${LOG_FILE:-/dev/null} ) 2>/dev/null # try to syslog it - other message types are only syslog'ed if there is # no controlling terminal (as when run from 'at' or 'cron') logger -i -p local0.alert -t $PROGNAME "$MSG" # try to log it on the console echo "$DATE: \ $MSG" > /dev/console exit 2 } error() { DO_EXIT=${ERRORS_CAUSE_EXITS:-true} STDIN=false while :; do case "$1" in -) STDIN=true ;; -e) DO_EXIT=true ;; -ne) DO_EXIT=false ;; -*) internal "invalid option to error() '$1'" ;; *) break ;; esac shift done if [ ${VERBOSE_LEVEL:-2} -ge 1 ]; then DATE=`date` { { [ $STDIN = false ] && echo "$@"; } || cat; } | while read LINE; do MSG="ERROR: $LINE" ( echo "$DATE: \ $MSG" >> ${LOG_FILE:-/dev/null} ) 2>/dev/null || internal "log file $LOG_FILE not writable!" { [ -t 2 ] && echo "$PROGNAME: \ $MSG" >&2; } || logger -i -p $FACILITY.err -t $PROGNAME "$MSG" done fi [ $DO_EXIT = false ] && return 1 exitdel exit 1 } warning() { STDIN=false while :; do case "$1" in -) STDIN=true ;; -*) internal "invalid option to error() '$1'" ;; *) break ;; esac shift done if [ ${VERBOSE_LEVEL:-2} -ge 2 ]; then DATE=`date` { { [ $STDIN = false ] && echo "$@"; } || cat; } | while read LINE; do MSG="WARNING: $LINE" ( echo "$DATE: \ $MSG" >> ${LOG_FILE:-/dev/null} ) 2>/dev/null || internal "log file $LOG_FILE not writable!" { [ -t 2 ] && echo "$PROGNAME: \ $MSG" >&2; } || logger -i -p $FACILITY.warning -t $PROGNAME "$MSG" done fi return 0 } debug() { STDIN=false while :; do case "$1" in -) STDIN=true ;; -*) internal "invalid option to error() '$1'" ;; *) break ;; esac shift done LEVEL=$1 shift if [ ${VERBOSE_LEVEL:-2} -ge $LEVEL ]; then DATE=`date` { { [ $STDIN = false ] && echo "$@"; } || cat; } | while read LINE; do MSG="DEBUG[$LEVEL]: $LINE" ( echo "$DATE: \ $MSG" >> ${LOG_FILE:-/dev/null} ) 2>/dev/null || internal "log file $LOG_FILE not writable!" { [ -t 2 ] && echo "$PROGNAME: \ $MSG" >&2; } || logger -i -p $FACILITY.debug -t $PROGNAME "$MSG" done fi return 0 } info() { STDIN=false while :; do case "$1" in -) STDIN=true ;; -*) internal "invalid option to error() '$1'" ;; *) break ;; esac shift done if [ ${VERBOSE_LEVEL:-2} -ge 3 ]; then DATE=`date` { { [ $STDIN = false ] && echo "$@"; } || cat; } | while read LINE; do MSG="INFO: $LINE" ( echo "$DATE: \ $MSG" >> ${LOG_FILE:-/dev/null} ) 2>/dev/null || internal "log file $LOG_FILE not writable!" { [ -t 2 ] && echo "$PROGNAME: \ $MSG" >&2; } || logger -i -p $FACILITY.info -t $PROGNAME "$MSG" done fi return 0 } ############################################################################### # # GENERIC SUPPORT FUNCTIONS (not specifically related to backup task) # ############################################################################### locatecmd() { for POSSCMD in $*; do [ X`whichcmd $POSSCMD` != X ] && { echo $POSSCMD; return 0; } done return 1 } whichcmd() { for DIR in `echo $PATH | sed 's/:/ /g'`; do [ -x $DIR/$1 ] && { echo $DIR/$1; return 0; } done return 1 } ############################################################################### # # TEMPORARY FILE MANAGEMENT FUNCTIONS # ############################################################################### delonexit() { DELONEXIT="$DELONEXIT $*" } dontdelonexit() { for FILE in $*; do DELONEXIT=`echo $DELONEXIT | sed "s@$FILE@@g"` done } exitdel() { debug 50 "cleaning up" rm -f $DELONEXIT } sighandler() { warning "signal recieved, clearing up and exiting" exitdel exit 3 } ############################################################################## # # LOCK FUNCTIONS # ############################################################################## gen_lock_file_name() { TABLE=$1 shift echo .$TABLE.lock } lock() { debug 5 "lock: locking $1" LOCKFILE=`gen_lock_file_name $1` { echo $$ > $LOCKFILE.$$; } 2>/dev/null || error -e "can't create lock" ln $LOCKFILE.$$ $LOCKFILE 2>/dev/null && { rm $LOCKFILE.$$; return 0; } HOLDING_PID=`cat $LOCKFILE` [ "X$HOLDING_PID" = X ] && { rm $LOCKFILE.$$; error -e "empty lockfile: $LOCKFILE"; } [ -d /proc/$HOLDING_PID ] && { rm $LOCKFILE.$$; error -e "program running already! (pid=$HOLDING_PID)"; } info "removing stale lock (pid=$HOLDING_PID)" rm -f $LOCKFILE ln $LOCKFILE.$$ $LOCKFILE 2>/dev/null && { rm $LOCKFILE.$$; return 0; } rm $LOCKFILE.$$ error -e "couldn't lock after removing stale lockfile" } unlock() { debug 5 "unlock: unlocking $1" LOCKFILE=`gen_lock_file_name $1` rm -f $LOCKFILE } ############################################################################### # # ENTRY POINT # ############################################################################### # ensure temporary files are private umask 077 # ensure temporary files are deleted if we get interrupted trap sighandler 1 2 15 # do the main thing! main "$@" # yes, i know, this would be the default, but just for clarity exit $?