#!/usr/bin/ksh ############################################################################### # # # DON'T HANG UP YET! # # ############################################################################### ############################################################################### # # Things you should know about this script: # # It is stored under RCS! Keep it that way! If you want a history of # changes made to this script then refer to rlog(1) - don't look here! # ############################################################################### ############################################################################### # # USER CONFIGURABLE STUFF STARTS HERE # ############################################################################### ############################################################################### # # USER CONFIGURABLE STUFF ENDS HERE # ############################################################################### ############################################################################### # # PACKAGE INDEPENDENT VARIABLE SETTINGS # ############################################################################### PATH=/bin:/usr/bin PROGNAME=`basename $0` VERSION="MARKER_PATCHLEVEL" #UMASK=022 #LOCK_DIR=/var/run #ERRORS_CAUSE_EXITS=true # $Header: /home/ahuxley/dev/arc/ppplc/bin/RCS/dhuy.shpp,v 1.7 1999/04/28 09:44:31 alexis Exp $ ############################################################################### # # PACKAGE SPECIFIC VARIABLE SETTINGS # ############################################################################### SNDMSG=MARKER_LCLBINDIR/sndmsg ############################################################################### # # MAIN FUNCTION (called from very bottom of script) # ############################################################################### main() { ########################################################################### # # PROCESS OPTIONS # ########################################################################### # default values for things changable by command line options MODE=dhuy while [ "X$1" != X ]; do case "$1" in -V) echo "$PROGNAME version $VERSION" exit 0 ;; -d) [ "X$2" = X ] && usage VERBOSE_LEVEL=$2 shift ;; -v) VERBOSE_LEVEL=3 ;; -c) MODE=cancel ;; -*) usage ;; *) break ;; esac shift done # Are locks required? Nah. # Are you going to register temporary files? No. #trap sighandler 1 2 15 ########################################################################## # # SCRIPT GUTS STARTS HERE # ########################################################################## # clear pending announcements $SNDMSG 1 1026 # clear pending hangups $SNDMSG 1 1005 # announce 'pending hangups cancelled' now $SNDMSG 1026 9 if [ $MODE = dhuy ]; then # announce 'going down in 5 minutes' in 15 minutes $SNDMSG -q 900 1026 7 # queue a hangup for 20 minutes $SNDMSG -q 1200 1005 # announce 'going down in 20 minutes' now $SNDMSG 1026 8 fi } usage() { { echo "Usage: $PROGNAME [ -d | -v ] [ -c ]" echo " $PROGNAME -V" } >&2 exit 2 } ############################################################################## # # SHELL LIBRARY OF HANDY FUNCTIONS # ############################################################################### ############################################################################### # # IMPORTANT NOTES # # 1. Any calls to 'error' made *inside* this file, *must* be supplied with # -e or -ne options. This is because we have no way of knowing the # value of ERRORS_CAUSE_EXITS. # ############################################################################### # $Header: /home/ahuxley/dev/supported/support/lib/RCS/utils.sh.shpp,v 1.25 2000/11/06 14:31:32 ahuxley Exp $ if [ "X$UTILS_SH_LOADING_IN_THIS_PROCESS_DONE" != Xtrue ]; then ############################################################################### # # RESILIANT MESSAGING FUNCTIONS # ############################################################################### # Mon Jan 3 19:36:50 GMT 2000 Alexis # # All message functions use 'sed' and 'date', which in Debian can, on a # partially configured system, choke on a timezone containing slashes. # Moral: configure your system! if [ "X$DEBUG_LITE" = Xfalse ]; then internal() { # Safest to put these *in* all functions - if they're outside then # there is a chance a function can get called by *other* extra-function # code with the vars still unset. Better yet ... define it in both # places so that main() can test it without having to set it first. VERBOSE_LEVEL=${VERBOSE_LEVEL:-2} FACILITY=${FACILITY:-local0} I_AM_A_DAEMON=${I_AM_A_DAEMON:-false} MSG="INTERNAL ERROR: $*" # 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 if we're a daemon (previously logger was called in # all cases - regardless of setting of I_AM_A_DAEMON, but this can # result in development versions generating critical error messages in # syslog files, which can be a bit confusing.) [ $I_AM_A_DAEMON = true ] && logger -i -p $FACILITY.alert -t $PROGNAME "$MSG" # try to log it on the console [ -w /dev/console ] && { echo "`date`: \ $PROGNAME: \ $MSG" > /dev/console; } exit 2 } error() { typeset FILE MODE MAX_MSG_LINES USE_LOG_FILE_IF_DEFINED LOCAL_ERRORS_CAUSE typeset USE_STDERR USE_STDERR_EVEN_IF_REDIRECTED typeset TMP_FILE_EXISTS TMP_FILE_EXISTS=false # Safest to put these *in* all functions - if they're outside then # there is a chance a function can get called by *other* extra-function # code with the vars still unset. Better yet ... define it in both # places so that main() can test it without having to set it first. # This is here just for backwards compatibility case $ERRORS_CAUSE_EXITS in true) warning "use 'ERRORS_CAUSE=exit' instead of 'ERRORS_CAUSE_EXITS=true'" ERRORS_CAUSE=exit ;; false) warning "use 'ERRORS_CAUSE=return' instead of 'ERRORS_CAUSE_EXITS=false'" ERRORS_CAUSE=return ;; *) : ;; # undefined - good! esac ERRORS_CAUSE=${ERRORS_CAUSE:-exit} VERBOSE_LEVEL=${VERBOSE_LEVEL:-2} FACILITY=${FACILITY:-local0} I_AM_A_DAEMON=${I_AM_A_DAEMON:-false} USE_STDERR=true USE_STDERR_EVEN_IF_REDIRECTED=true LOCAL_ERRORS_CAUSE=$ERRORS_CAUSE USE_LOG_FILE_IF_DEFINED=true MODE=line while :; do case "$1" in -) internal "change '-' to '-f file' in message calls" ;; -m) MAX_MSG_LINES=$2 shift ;; -f) MODE=file FILE=$2 shift ;; -e) warning "option '-e' on 'error() calls is obsolete, use '-d exit'" LOCAL_ERRORS_CAUSE=exit ;; -ne) warning "option '-ne' on 'error() calls is obsolete, use '-d return'" LOCAL_ERRORS_CAUSE=return ;; -d) LOCAL_ERRORS_CAUSE=$2 shift ;; -nl) USE_LOG_FILE_IF_DEFINED=false ;; -ns) USE_STDERR=false ;; -nr) USE_STDERR_EVEN_IF_REDIRECTED=false ;; --) shift break ;; -*) internal "invalid option to error() '$1' (pars: $*)" ;; *) break ;; esac shift done case $LOCAL_ERRORS_CAUSE in exit|return) : ;; *) internal "error() called with option '-d $LOCAL_ERRORS_CAUSE" ;; esac if [ $MODE = file -a "X$FILE" = X- ]; then TMP_FILE_EXISTS=true delonexit /tmp/$PROGNAME.$$.error cat > /tmp/$PROGNAME.$$.error FILE=/tmp/$PROGNAME.$$.error fi if [ ${VERBOSE_LEVEL:-2} -ge 1 ]; then if [ "X$I_AM_A_DAEMON" = Xtrue ]; then { { [ $MODE = line ] && echo "$@"; } || sed "${MAX_MSG_LINES:-10}{ a\\ long output suppressed! q }" $FILE; } | while read LINE; do logger -i -p $FACILITY.err -t $PROGNAME "$LINE" done elif [ $USE_STDERR = true -a \( -t 2 -o $USE_STDERR_EVEN_IF_REDIRECTED \ = true \) ]; then { { [ $MODE = line ] && echo "$@"; } || sed "${MAX_MSG_LINES:-10}{ a\\ long output suppressed! q }" $FILE; } | sed "s/^/$PROGNAME: ERROR: /" >&2 fi if [ $USE_LOG_FILE_IF_DEFINED = true -a "X$LOG_FILE" != X ]; then { { [ $MODE = line ] && echo "$@"; } || cat $FILE; } | ( sed "s/^/`date`: ERROR: /" >> $LOG_FILE ) 2>/dev/null || error -d exit -nl "log file $LOG_FILE not writable!" fi fi if [ $TMP_FILE_EXISTS = true ]; then rm -f /tmp/$PROGNAME.$$.error dontdelonexit /tmp/$PROGNAME.$$.error fi [ $LOCAL_ERRORS_CAUSE = return ] && return 1 exitdel exit 1 } warning() { typeset FILE MODE MAX_MSG_LINES USE_LOG_FILE_IF_DEFINED typeset USE_STDERR USE_STDERR_EVEN_IF_REDIRECTED typeset TMP_FILE_EXISTS TMP_FILE_EXISTS=false # Safest to put these *in* all functions - if they're outside then # there is a chance a function can get called by *other* extra-function # code with the vars still unset. Better yet ... define it in both # places so that main() can test it without having to set it first. VERBOSE_LEVEL=${VERBOSE_LEVEL:-2} FACILITY=${FACILITY:-local0} I_AM_A_DAEMON=${I_AM_A_DAEMON:-false} USE_STDERR=true USE_STDERR_EVEN_IF_REDIRECTED=true MODE=line USE_LOG_FILE_IF_DEFINED=true while :; do case "$1" in -) internal "change '-' to '-f file' in message calls" ;; -m) MAX_MSG_LINES=$2 shift ;; -f) MODE=file FILE=$2 shift ;; -nl) USE_LOG_FILE_IF_DEFINED=false ;; -ns) USE_STDERR=false ;; -nr) USE_STDERR_EVEN_IF_REDIRECTED=false ;; --) shift break ;; -*) internal "invalid option to error() '$1'" ;; *) break ;; esac shift done if [ $MODE = file -a "X$FILE" = X- ]; then TMP_FILE_EXISTS=true delonexit /tmp/$PROGNAME.$$.warning cat > /tmp/$PROGNAME.$$.warning FILE=/tmp/$PROGNAME.$$.warning fi if [ ${VERBOSE_LEVEL:-2} -ge 2 ]; then if [ "X$I_AM_A_DAEMON" = Xtrue ]; then { { [ $MODE = line ] && echo "$@"; } || sed "${MAX_MSG_LINES:-10}{ a\\ long output suppressed! q }" $FILE; } | while read LINE; do logger -i -p $FACILITY.warning -t $PROGNAME "$LINE" done elif [ $USE_STDERR = true -a \( -t 2 -o $USE_STDERR_EVEN_IF_REDIRECTED \ = true \) ]; then { { [ $MODE = line ] && echo "$@"; } || sed "${MAX_MSG_LINES:-10}{ a\\ long output suppressed! q }" $FILE; } | sed "s/^/$PROGNAME: WARNING: /" >&2 fi if [ $USE_LOG_FILE_IF_DEFINED = true -a "X$LOG_FILE" != X ]; then { { [ $MODE = line ] && echo "$@"; } || cat $FILE; } | ( sed "s/^/`date`: WARNING: /" >> $LOG_FILE ) 2>/dev/null || error -d exit -nl "log file $LOG_FILE not writable!" fi fi if [ $TMP_FILE_EXISTS = true ]; then rm -f /tmp/$PROGNAME.$$.warning dontdelonexit /tmp/$PROGNAME.$$.warning fi return 0 } debug() { typeset FILE MODE MAX_MSG_LINES USE_LOG_FILE_IF_DEFINED typeset USE_STDERR USE_STDERR_EVEN_IF_REDIRECTED typeset TMP_FILE_EXISTS TMP_FILE_EXISTS=false # Safest to put these *in* all functions - if they're outside then # there is a chance a function can get called by *other* extra-function # code with the vars still unset. Better yet ... define it in both # places so that main() can test it without having to set it first. VERBOSE_LEVEL=${VERBOSE_LEVEL:-2} FACILITY=${FACILITY:-local0} I_AM_A_DAEMON=${I_AM_A_DAEMON:-false} USE_STDERR=true USE_STDERR_EVEN_IF_REDIRECTED=true MODE=line USE_LOG_FILE_IF_DEFINED=true while :; do case "$1" in -) internal "change '-' to '-f file' in message calls" ;; -m) MAX_MSG_LINES=$2 shift ;; -f) MODE=file FILE=$2 shift ;; -nl) USE_LOG_FILE_IF_DEFINED=false ;; -ns) USE_STDERR=false ;; -nr) USE_STDERR_EVEN_IF_REDIRECTED=false ;; --) shift break ;; -*) internal "invalid option to debug() '$1'" ;; *) break ;; esac shift done LEVEL=$1 shift if [ $MODE = file -a "X$FILE" = X- ]; then TMP_FILE_EXISTS=true delonexit /tmp/$PROGNAME.$$.debug cat > /tmp/$PROGNAME.$$.debug FILE=/tmp/$PROGNAME.$$.debug fi if [ ${VERBOSE_LEVEL:-2} -ge $LEVEL ]; then if [ "X$I_AM_A_DAEMON" = Xtrue ]; then { { [ $MODE = line ] && echo "$@"; } || sed "${MAX_MSG_LINES:-10}{ a\\ long output suppressed! q }" $FILE; } | while read LINE; do logger -i -p $FACILITY.debug -t $PROGNAME "$LINE" done elif [ $USE_STDERR = true -a \( -t 2 -o $USE_STDERR_EVEN_IF_REDIRECTED \ = true \) ]; then { { [ $MODE = line ] && echo "$@"; } || sed "${MAX_MSG_LINES:-10}{ a\\ long output suppressed! q }" $FILE; } | sed "s/^/$PROGNAME: DEBUG[$LEVEL]: /" >&2 fi if [ $USE_LOG_FILE_IF_DEFINED = true -a "X$LOG_FILE" != X ]; then { { [ $MODE = line ] && echo "$@"; } || cat $FILE; } | ( sed "s/^/`date`: DEBUG[$LEVEL]: /" >> $LOG_FILE ) 2>/dev/null || error -d exit -nl "log file $LOG_FILE not writable!" fi fi if [ $TMP_FILE_EXISTS = true ]; then rm -f /tmp/$PROGNAME.$$.debug dontdelonexit /tmp/$PROGNAME.$$.debug fi return 0 } info() { typeset FILE MODE MAX_MSG_LINES USE_LOG_FILE_IF_DEFINED typeset USE_STDERR USE_STDERR_EVEN_IF_REDIRECTED typeset TMP_FILE_EXISTS TMP_FILE_EXISTS=false # Safest to put these *in* all functions - if they're outside then # there is a chance a function can get called by *other* extra-function # code with the vars still unset. Better yet ... define it in both # places so that main() can test it without having to set it first. VERBOSE_LEVEL=${VERBOSE_LEVEL:-2} FACILITY=${FACILITY:-local0} I_AM_A_DAEMON=${I_AM_A_DAEMON:-false} USE_STDERR=true USE_STDERR_EVEN_IF_REDIRECTED=true MODE=line USE_LOG_FILE_IF_DEFINED=true while :; do case "$1" in -) internal "change '-' to '-f file' in message calls" ;; -m) MAX_MSG_LINES=$2 shift ;; -f) MODE=file FILE=$2 shift ;; -nl) USE_LOG_FILE_IF_DEFINED=false ;; -ns) USE_STDERR=false ;; -nr) USE_STDERR_EVEN_IF_REDIRECTED=false ;; --) shift break ;; -*) internal "invalid option to error() '$1'" ;; *) break ;; esac shift done if [ $MODE = file -a "X$FILE" = X- ]; then TMP_FILE_EXISTS=true delonexit /tmp/$PROGNAME.$$.info cat > /tmp/$PROGNAME.$$.info FILE=/tmp/$PROGNAME.$$.info fi if [ ${VERBOSE_LEVEL:-2} -ge 3 ]; then if [ "X$I_AM_A_DAEMON" = Xtrue ]; then { { [ $MODE = line ] && echo "$@"; } || sed "${MAX_MSG_LINES:-10}{ a\\ long output suppressed! q }" $FILE; } | while read LINE; do logger -i -p $FACILITY.info -t $PROGNAME "$LINE" done elif [ $USE_STDERR = true -a \( -t 2 -o $USE_STDERR_EVEN_IF_REDIRECTED \ = true \) ]; then { { [ $MODE = line ] && echo "$@"; } || sed "${MAX_MSG_LINES:-10}{ a\\ long output suppressed! q }" $FILE; } | sed "s/^/$PROGNAME: INFO: /" >&2 fi if [ $USE_LOG_FILE_IF_DEFINED = true -a "X$LOG_FILE" != X ]; then { { [ $MODE = line ] && echo "$@"; } || cat $FILE; } | ( sed "s/^/`date`: INFO: /" >> $LOG_FILE ) 2>/dev/null || error -d exit -nl "log file $LOG_FILE not writable!" fi fi if [ $TMP_FILE_EXISTS = true ]; then rm -f /tmp/$PROGNAME.$$.info dontdelonexit /tmp/$PROGNAME.$$.info fi return 0 } # DEBUG_LITE else internal() { echo "$PROGNAME: INTERNAL ERROR: $1" >&2 [ "X$LOG_FILE" != X ] && { echo "$PROGNAME: INTERNAL ERROR: $1" >> $LOG_FILE; } [ -w /dev/console ] && { echo "`date`: $PROGNAME: INTERNAL ERROR: $1" > /dev/console; } exit 2 } error() { echo "$PROGNAME: ERROR: $1" >&2 [ "X$LOG_FILE" != X ] && { echo "$PROGNAME: ERROR: $1" >> $LOG_FILE; } exit 1 } debug() { if [ $1 -le ${VERBOSE_LEVEL:-2} ]; then echo "$PROGNAME: DEBUG[$1]: $2" >&2 [ "X$LOG_FILE" != X ] && { echo "$PROGNAME: DEBUG[$1]: $2" >> $LOG_FILE; } fi } info() { if [ 3 -le ${VERBOSE_LEVEL:-2} ]; then echo "$PROGNAME: INFO: $1" >&2 [ "X$LOG_FILE" != X ] && { echo "$PROGNAME: INFO: $1" >> $LOG_FILE; } fi } warning() { if [ 2 -le ${VERBOSE_LEVEL:-2} ]; then echo "$PROGNAME: WARNING: $1" >&2 [ "X$LOG_FILE" != X ] && { echo "$PROGNAME: WARNING: $1" >> $LOG_FILE; } fi } # DEBUG_LITE fi display() { typeset FILE MODE MAX_MSG_LINES USE_LOG_FILE_IF_DEFINED typeset USE_STDOUT USE_STDOUT_EVEN_IF_REDIRECTED typeset TMP_FILE_EXISTS TMP_FILE_EXISTS=false USE_LOG_FILE_IF_DEFINED=true USE_STDOUT=true USE_STDOUT_EVEN_IF_REDIRECTED=true MODE=line while :; do case "$1" in -) internal "change '-' to '-f file' in message calls" ;; -m) MAX_MSG_LINES=$2 shift ;; -f) MODE=file FILE=$2 shift ;; -nl) USE_LOG_FILE_IF_DEFINED=false ;; -ns) USE_STDOUT=false ;; -nr) USE_STDOUT_EVEN_IF_REDIRECTED=false ;; --) shift break ;; -*) internal "invalid option to error() '$1' (pars: $*)" ;; *) break ;; esac shift done if [ $MODE = file -a "X$FILE" = X- ]; then TMP_FILE_EXISTS=true delonexit /tmp/$PROGNAME.$$.display cat > /tmp/$PROGNAME.$$.display FILE=/tmp/$PROGNAME.$$.display fi if [ $USE_STDOUT = true -a \( -t 1 -o $USE_STDOUT_EVEN_IF_REDIRECTED = \ true \) ]; then { { [ $MODE = line ] && echo "$@"; } || sed "${MAX_MSG_LINES:-10}{ a\\ long output suppressed! q }" $FILE; } fi if [ $USE_LOG_FILE_IF_DEFINED = true -a "X$LOG_FILE" != X ]; then { { [ $MODE = line ] && echo "$@"; } || cat $FILE; } | ( cat >> $LOG_FILE ) 2>/dev/null || error -d exit -nl "log file $LOG_FILE not writable!" fi if [ $TMP_FILE_EXISTS = true ]; then rm -f /tmp/$PROGNAME.$$.display dontdelonexit /tmp/$PROGNAME.$$.display fi } ############################################################################### # # INTERACTIVE MESSAGING FUNCTIONS # ############################################################################### ### echo loading interactive messaging functions pause() { necho "Press ENTER to continue " read RESPONSE return 0 } proceed() { typeset PROMPT DEFAULT RESPONSE PROMPT="do you wish to proceed" while [ "X$1" != X ]; do case "$1" in -d) DEFAULT="$2" shift ;; -p) PROMPT="$2" shift ;; -*) internal "proceed: invalid option '$1'" ;; *) break ;; esac shift done while :; do question "${PROMPT:-proceed}? [${DEFAULT:-n}]" > /dev/tty read RESPONSE < /dev/tty [ "X$RESPONSE" = X ] && RESPONSE=${DEFAULT:-n} case "$RESPONSE" in [Yy]*) return 0 ;; [Nn]*) return 1 ;; *) echo "Eh? Try again" > /dev/tty ;; esac done } question() { necho "$PROGNAME: \ QUESTION: $*: " return 0 } ############################################################################### # # MISCELLANEOUS INTERACTIVE FUNCTIONS # ############################################################################### ### echo loading miscellaneous interactive functions do_a_shell() { OLD_PS1="$PS1" export PS1 while :; do case "$1" in -p) PS1="$2" shift ;; -*) internal "invalid option '$1' to do_a_shell() (001)" ;; *) break ;; esac shift done COMMAND="$*" debug 60 "command to run is $COMMAND, SHELL is $SHELL" case "$COMMAND" in "") info "starting sub-shell, type 'exit' to resume" ${SHELL:-/bin/sh} ;; *) ${SHELL:-/bin/sh} -c "$COMMAND" ;; esac PS1="$OLD_PS1" return 0 } ############################################################################### # # GENERIC SUPPORT FUNCTIONS # ############################################################################### path_from() { # Usage: path_from # Desc: calculates a relative path from to typeset SRC_DIR DST_DIR SRC_LIST DIR REL_PATH SRC_DIR=$1 DST_DIR=$2 debug 60 "path_from: original paths $SRC_DIR and $DST_DIR" expr $SRC_DIR : '\/' > /dev/null || internal "path_from: src_dir not absolute"; expr $DST_DIR : '\/' > /dev/null || internal "path_from: dst_dir not absolute"; SRC_DIR=`echo $SRC_DIR | sed 's/^\///'` DST_DIR=`echo $DST_DIR | sed 's/^\///'` debug 60 "path_from: leading slash removed paths $SRC_DIR and $DST_DIR" SRC_LIST=`echo $SRC_DIR | sed 's/\// /g'` for DIR in $SRC_LIST; do debug 60 "checking if paths start with $DIR ..." expr $DST_DIR : "$DIR/" > /dev/null || break SRC_DIR=`echo $SRC_DIR | sed "s/^$DIR\///"` DST_DIR=`echo $DST_DIR | sed "s/^$DIR\///"` done debug 60 "path_from: reduced paths are $SRC_DIR and $DST_DIR" REL_PATH=`echo $SRC_DIR | sed 's/[^/][^/]*/../g'`/$DST_DIR debug 60 "path_from: returning $REL_PATH" echo $REL_PATH exit 2 } rcf() { # Usage: rcf > # Note that although GNU sed (on Linux) is happy with a single long # line, Solaris's sed isn't, producing the following error: # Label too long: /^#/d;/^$/d;:b;/\\$/{N;s/\\\n[ ]*//;bb;} # so we span it over a few lines, it's more readable too! sed '/^#/d /^$/d :b /\\$/{ N s/\\\n[ ]*// bb }' "$@" } os_config2() { # usage: os_config2 [ ... ] [ ] typeset OS CMD UNAMES=${UNAMES:-`uname -s`} while [ "X$1" != X ]; do OS="$1" CMD="$2" [ "X$CMD" = X -o "X$UNAMES" = "X$OS" ] && { [ "X$CMD" = X ] && CMD="$OS" locatecmd -q $CMD && echo $CMD; return $? } shift; shift done return 1 } choosecmd() { for POSSCMD in "$@"; do [ X`locatecmd $POSSCMD` != X ] && { echo $POSSCMD; return 0; } done return 1 } locatecmd() { typeset PATH_DIR L_QUIET L_QUIET=false while [ "X$1" != X ]; do case "$1" in -q) L_QUIET=true ;; -*) internal "locatecmd: called with invalid option: $1" ;; *) break ;; esac shift done debug 60 "locatecmd: searching for $1 ..." if expr $1 : '.*/.*$' > /dev/null; then debug 60 "locatecmd: absolute" [ -x $1 ] && { [ $L_QUIET = false ] && echo $1; return 0; } return 1 elif type $1 2>/dev/null | grep 'is a function' > /dev/null; then debug 60 "locatecmd: function" [ $L_QUIET = false ] && echo $1; return 0 else debug 60 "locatecmd: possibly external command" for PATH_DIR in `echo $PATH | sed 's/:/ /g'`; do [ -x $PATH_DIR/$1 ] && { [ $L_QUIET = false ] && echo $PATH_DIR/$1; return 0; } done return 1 fi } myxargs() { debug 60 "myxargs: sof" # This is a function equivalent to GNU FindUtils's "xargs -r" - i.e. # it doesn't call the command if there is no input. while [ "X$1" = X ]; do case "$1" in -*) internal "myxargs supports no options" ;; *) break ;; esac shift done sed '/^[ ]*$/d' | while read LINE; do debug 60 "myxargs: calling $@ $LINE" "$@" $LINE done } necho() { debug 60 "necho: sof (ECHO_MODE is $ECHO_MODE)" if [ "X$ECHO_MODE" = X ]; then if [ `echo -n | wc -c` -eq 0 ]; then ECHO_MODE=mn elif [ `echo "\\c" | wc -c` -eq 0 ]; then ECHO_MODE=bsc else internal "don't know how to suppress newlines in echos" fi fi debug 60 "necho: after echo mode calculation (ECHO_MODE is $ECHO_MODE)" if [ $ECHO_MODE = mn ]; then echo -n "$@" elif [ $ECHO_MODE = bsc ]; then echo "$@""\\c" fi return 0 } am_i_root() { [ ! -w / ] && return 1 return 0 } who_am_i() { echo ${USER:-${LOGNAME:-`id | sed -n 's/^[^(][^(]*(\([^)][^)]*\)).*$/\1/p'`}} } ############################################################################### # # TEMPORARY FILE MANAGEMENT FUNCTIONS # ############################################################################### ## echo "loading temporary file management functions (1)" delonexit() { typeset LIST FILE LIST=DELONEXIT while [ "X$1" != X ]; do case $1 in -l) LIST=$2 shift ;; -*) internal "delonexit: usage error" ;; *) break ;; esac shift done # add the list to the list of lists [ $LIST != TMP_FILE_LOL ] && delonexit -l TMP_FILE_LOL $LIST # add the specified files to the specified list for FILE in $*; do debug 60 "delonexit: adding $FILE to $LIST ..." eval LIST_CONTENTS=\"\$$LIST\" if expr "$LIST_CONTENTS" : ".* $FILE .*\$" > /dev/null || \ expr "$LIST_CONTENTS" : "$FILE .*\$" > /dev/null || \ expr "$LIST_CONTENTS" : ".* $FILE\$" > /dev/null; then debug 60 "delonexit: $FILE is already on $LIST" else eval $LIST=\"\$$LIST $FILE\" fi done eval debug 60 "delonexit: list name is $LIST, list contains [\$$LIST]" } ## echo "loading temporary file management functions (2)" dontdelonexitall() { typeset LIST LIST=DELONEXIT while [ "X$1" != X ]; do case $1 in -l) LIST=$2 shift ;; -*) internal "delonexit: usage error" ;; *) break ;; esac shift done # purge the list eval $LIST= # remove the list from the list of lists [ $LIST != TMP_FILE_LOL ] && dontdelonexit -l TMP_FILE_LOL $LIST eval debug 60 "dontdelonexitall: list name is $LIST, list contains [\$$LIST]" >&2 } dontdelonexit() { typeset LIST LIST=DELONEXIT while [ "X$1" != X ]; do case $1 in -l) LIST=$2 shift ;; -*) internal "delonexit: usage error" ;; *) break ;; esac shift done # remove the specifified files from the specified list for FILE in $*; do #eval "$LIST=\`echo \$$LIST | sed \"s@$FILE@@g\"\`" eval "$LIST=\`echo \$$LIST | sed -e \"s@^$FILE\\\\\$@@g\" \ -e \"s@ $FILE\\\\\$@@g\" \ -e \"s@^$FILE @@g\" \ -e \"s@ $FILE @ $FILE@g\"\`" done # we could check to see if the list is no empty and then remove the # list from the list of lists, but it's not worth it. ## eval echo "ECHO_DEBUG: dontdelonexit: list name is $LIST, list contains [\$$LIST]" } generic_exitdel() { # this function cannot do any message function - if it does, then # possibly removed log files are recreated. if [ $ON_EXIT_ONLY_DELETE_FILES_FROM_LIST_DELONEXIT = true ]; then #echo "ECHO_DEBUG: exitdel: delonexit contains $DELONEXIT" >&2 rm -f $DELONEXIT DELONEXIT= else for LIST in $TMP_FILE_LOL; do eval rm -f \$$LIST # next line just so any echos in here display the right info eval $LIST= # having emptied the list we could now remove the list name from # the list of lists, but it's not worth the trouble of # deregistering the names of lists. #eval echo "ECHO_DEBUG: exitdel: list name is $LIST, list contains [\$$LIST]" done fi } exitdel() { [ "X$EXITDEL_FUNCS" != X ] && { for EXITDEL_FUNC in $EXITDEL_FUNCS; do eval $EXITDEL_FUNC done } generic_exitdel } genericsighandler() { warning "signal recieved, clearing up and exiting" exitdel exit 3 } sighandler() { internal "this program called sighandler(), which is obsolete; use genericsighandler()" } ############################################################################### # # LOCKING ROUTINES # ############################################################################### ## echo loading locking routines # It would be nice to return minus numbers on errors, positive ones on # discovering locks held be another process (the return value being the # holding pid). But 'return' won't accept minus numbers (Solaris breaks, # Linux adds 256 to them). So we use 1 to represent an error (since no # locking process should use pid 1). lock() { typeset LOCK_FILE MODE LOCK_TEXT LOCK_WHAT GEN_LOCK_FILE_NAME TMP_LOCK_FILE MODE=system while [ "X$1" != X ]; do case "$1" in -n) MODE=network ;; -s) MODE=system ;; -*) internal "lock: called with bad option: $1" ;; *) break ;; esac shift done LOCK_WHAT="$1" GEN_LOCK_FILE_NAME_FNC="$2" debug 90 "lock: LOCK_WHAT=$LOCK_WHAT, GEN_LOCK_FILE_NAME_FNC=$GEN_LOCK_FILE_NAME_FNC" LOCK_FILE=`eval $GEN_LOCK_FILE_NAME_FNC "$LOCK_WHAT"` TMP_LOCK_FILE=$LOCK_FILE.$$ debug 90 "lock: LOCK_FILE=$LOCK_FILE" case $MODE in system) LOCK_TEXT="$$" ;; network) LOCK_TEXT="$$ `uname -n`" ;; esac # create temporary lock (world readable) debug 90 "lock: creating temporary lock ..." delonexit $TMP_LOCK_FILE { echo $LOCK_TEXT > $TMP_LOCK_FILE; } 2>/dev/null || { error -d return "can't create temporary lock" return 1 } chmod a+r $TMP_LOCK_FILE # Slide the temporary lockfile into place debug 90 "lock: sliding temporary lock in place ..." delonexit $LOCK_FILE LN_CMD=`os_config2 SunOS /usr/xpg4/bin/ln ln` || internal "cannot determine ln command" $LN_CMD $TMP_LOCK_FILE $LOCK_FILE 2>/dev/null && { rm -f $TMP_LOCK_FILE dontdelonexit $TMP_LOCK_FILE return 0 } # AH - Sat Jan 15 15:49:44 MET 2000 # The next line used to be in, why I have no idea! ##dontdelonexit $LOCK_FILE # It failed. Check who is locking us out. debug 90 "lock: sliding temporary lock failed, checking existing lock ..." HOLDING_LOCK_TEXT=`cat $LOCK_FILE` HOLDING_PID=`echo $HOLDING_LOCK_TEXT | cut -f1 -d' '` case $MODE in system) HOLDING_HOST=`uname -n` ;; network) HOLDING_HOST=`echo $HOLDING_LOCK_TEXT | cut -f2 -d' '` ;; esac # validate lock [ "X$HOLDING_PID" = X -o "X$HOLDING_HOST" = X ] && { rm -f $TMP_LOCK_FILE dontdelonexit $TMP_LOCK_FILE error -d return "corrupt lockfile: $LOCK_FILE" return 1 } # if locking host is remote then there's not much we can do to verify it # though we should really return a positive (made up) pid or something [ $HOLDING_HOST != `uname -n` ] && { error -d return "locking host is remote, cannot verify if lock is stale" return 1 } # if the locking host is local (it must be if we get here) if running # abandon lock attempt and return locking pid debug 90 "lock: lock is local lock, checking if pid running ..." pid_running $HOLDING_PID && { rm -f $TMP_LOCK_FILE dontdelonexit $TMP_LOCK_FILE return $HOLDING_PID } # if the lock is local and stale (it must be if we get here) remove lock info "removing stale lock (pid=$HOLDING_PID)" rm -f $LOCK_FILE # try locking again debug 90 "lock: sliding temporary lock into place - second try ..." delonexit $LOCK_FILE $LN_CMD $TMP_LOCK_FILE $LOCK_FILE 2>/dev/null && { rm -f $TMP_LOCK_FILE dontdelonexit $TMP_LOCK_FILE return 0 } # if we still haven't successfully locked by now then there is something # seriously wrong rm -f $TMP_LOCK_FILE dontdelonexit $TMP_LOCK_FILE internal "couldn't lock even after removing stale lockfile" } gen_lock_file_name() { echo "/tmp/$PROGNAME" } pid_running() { # for Linux and Solaris 2 [ -d /proc ] && { [ -d /proc/$1 -o -f /proc/`printf "%05d" $1` ]; return $?; } # The chosen ps command must return a list of all pids in the first # (possible space-led) column. PS_CMD=`os_config2 Linux "ps ax" SunOS "ps -ae" HP-UX "ps -e"` || internal "cannot determine if pid $1 is running (recode pid_running())" # note \$1 is quote-escaped awk variable, $1 is shell function arg [ X`$PS_CMD | awk "{ if (\\$1 == $1) print \$1 }"` != X ] } unlock() { typeset LOCK_FILE LOCK_WHAT GEN_LOCK_FILE_NAME_FNC LOCK_WHAT="$1" GEN_LOCK_FILE_NAME_FNC="$2" LOCK_FILE=`eval $GEN_LOCK_FILE_NAME_FNC "$LOCK_WHAT"` rm -f $LOCK_FILE } hpux_ksh_read_bug() { debug 5 "hpux_ksh_read_bug: exiting quietly" exit 1 } set_determinant_variables() { if [ "X$DETERMINANT_VARIABLES_LOADED" != Xtrue ]; then UNAMEN=`uname -n` UNAMES=`uname -s` UNAMER=`uname -r` UNAMEM=`uname -m` # Don't differentiate Intel processors expr $UNAMEM : 'i[3456]86$' > /dev/null && UNAMEM=i386 # OSID is the absolute OS reference. It has no spaces or slashes in # it for safer use later on. Linux requires some massaging here, # since revision comes from the kernel version and this is not # really terribly useful. if [ $UNAMES != Linux ]; then OSID=`uname -sr | sed 's/[ \/]/_/g'` elif [ -f /etc/redhat-release ]; then OSID="Linux_Redhat_`sed -n 's/.*release \([^ ][^ ]*\) .*/\1/p' /etc/redhat-release`_$UNAMEM" elif [ -f /etc/debian_version ]; then OSID="Linux_Debian_`cat /etc/debian_version`_$UNAMEM" else OSID="Linux_Unknown_$UNAMEM" fi case $OSID in Linux_Redhat_6.1_i*86) OSID=Linux_Redhat_6.1_i386 ;; Linux_Debian_2.2_i*86) OSID=Linux_Debian_2.2_i386 ;; HP-UX_B.11.00) OSID="${OSID}_`/usr/bin/getconf KERNEL_BITS`" ;; esac export OSID UNAMEN UNAMES UNAMER UNAMEM DETERMINANT_VARIABLES_LOADED=true export DETERMINANT_VARIABLES_LOADED fi } case $ERRORS_CAUSE_EXITS in true) warning "use 'ERRORS_CAUSE=exit' instead of 'ERRORS_CAUSE_EXITS=true'" ERRORS_CAUSE=exit ;; false) warning "use 'ERRORS_CAUSE=return' instead of 'ERRORS_CAUSE_EXITS=false'" ERRORS_CAUSE=return ;; *) : ;; # undefined - good! esac ERRORS_CAUSE=${ERRORS_CAUSE:-exit} VERBOSE_LEVEL=${VERBOSE_LEVEL:-2} FACILITY=${FACILITY:-local0} I_AM_A_DAEMON=${I_AM_A_DAEMON:-false} ON_EXIT_ONLY_DELETE_FILES_FROM_LIST_DELONEXIT=${ON_EXIT_ONLY_DELETE_FILES_FROM_LIST_DELONEXIT:-true} # # The following might one day be moved to 'patches.sh.shpp'. # # This is a sanity check that the date command doesn't have # a slash in it - a misconfigured Linux system can have! expr "`date`" : '.*/' > /dev/null && error "the 'date' command on this system" fi UTILS_SH_LOADING_IN_THIS_PROCESS_DONE=true # don't export UTILS_SH_LOADING_IN_THIS_PROCESS_DONE! ############################################################################### # # GENERIC ENTRY POINT # ############################################################################### # $Header: /home/ahuxley/dev/supported/support/lib/RCS/gep.sh.shpp,v 1.6 2000/11/06 14:33:34 ahuxley Exp $ [ "X$VERSION_SCHEME" = X ] && VERSION_SCHEME=rcs [ $VERSION_SCHEME != rcs ] && VERSION="MARKER_PATCHLEVEL" [ $VERSION_SCHEME != rcs ] && expr "$VERSION" : 'MARKE._PATCH.EVEL' > /dev/null && { [ "X$IGNORE_WARNING_UNSUBBED_RELEASE_MARKER" != Xtrue ] && warning "version scheme is 'release', but marker has not been replaced, falling back to 'rcs' scheme (set IGNORE_WARNING_UNSUBBED_RELEASE_MARKER=true to suppress this message)" } # this is always a fatal error regardless of whether we use 'rcs' or 'release' # versioning scheme [ "X$RCS_ID" = X ] && internal "RCS_ID undefined" [ $VERSION_SCHEME = rcs ] && { VERSION=`echo $RCS_ID | cut -d' ' -f3` [ `echo $RCS_ID | cut -d' ' -f8` != '$' ] && VERSION="$VERSION (not checked in)" } EXIT_AT_END=${EXIT_AT_END:-true} [ "X$UMASK" != X ] && umask $UMASK main "$@" MAIN_RC=$? [ $EXIT_AT_END = true ] && exit $MAIN_RC