#!SCRIPTSHELLCMD_MARKER
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 $?