#! /bin/sh # configure these LOCKDIR=/usr/spool/uucp NOHUP_START_TIME=5 DYING_TIME=60 linestat() { LOCK=$1 [ ! -f $LOCK ] && return 0 [ ! -r $LOCK ] && return 1 PID=`cat $LOCK` PID=`expr $PID + 0` # this line tests if process $PID exists [ ! -d /proc/$PID ] && return 3 # lock exists isn't ll [ ! -f $LOCK.$PROGNAME ] && return 2 # lock exists is ll return 4 } report_line() { LOCK=$1 linestat $LOCK STAT=$? case $STAT in 0) echo "not locked" ;; 1) echo "$PROGNAME: ERROR: can't read $LOCK" ;; 2) echo "locked by another process" ;; 4) echo "locked by $PROGNAME" ;; 3) echo "stale lock" ;; esac exit 0 } unlock_line() { LOCK=$1 linestat $LOCK STAT=$? case $STAT in 0) echo "$PROGNAME: WARNING: already unlocked" [ -f $LOCK.$PROGNAME ] && { echo "$PROGNAME: WARNING: removing stale $PROGNAME lock"; rm -f $LOCK.$PROGNAME; } exit 0 ;; 1) echo "$PROGNAME: ERROR: can't read $LOCK" [ -f $LOCK.$PROGNAME ] && { echo "$PROGNAME: WARNING: removing $PROGNAME lock, hope $PROGNAME was running"; rm -f $LOCK.$PROGNAME; } exit 1 ;; 2) [ $FORCE = false ] && { echo "$PROGNAME: WARNING: lock is not an $PROGNAME lock, not removing"; exit 1; } echo "$PROGNAME: WARNING: killing locking process" PID=`cat $LOCK` PID=`expr $PID + 0` kill -9 $PID ;; 4) rm -f $LOCK.$PROGNAME exit 0 ;; 3) echo "$PROGNAME: WARNING: removing stale lock" rm -f $LOCK [ -f $LOCK.$PROGNAME ] && { echo "$PROGNAME: WARNING: removing stale $PROGNAME lock"; rm -f $LOCK.$PROGNAME; } exit ;; esac } lock_line() { LOCK=$1 linestat $LOCK STAT=$? case $STAT in 0|3) lock_it $LOCK exit $? ;; 1) echo "$PROGNAME: ERROR: can't read $LOCK" exit 1 ;; 2) [ $FORCE = false ] && { echo "$PROGNAME: ERROR: line already locked by another process"; exit 0; } PID=`cat $LOCK` PID=`expr $PID + 0` kill -9 $PID lock_it $LOCK exit $? ;; 4) echo "$PROGNAME: ERROR: line is already locked by $PROGNAME" exit 1 ;; esac } lock_it() { LOCK=$1 [ -f $LOCK ] && rm -f $LOCK [ -f $LOCK ] && { echo "$PROGNAME: ERROR: can't remove old lock"; exit 1; } nohup sh -c " umask 033 # This is a mess. It should be possible to store the return # value in a variable and then just echo that variable on the # second file ... but it doesn't work echo \$\$ | awk '{ printf \"%09d\", \$1 }' > $LOCK cp $LOCK $LOCK.ll while [ -f $LOCK.$PROGNAME ]; do sleep $DYING_TIME done rm -f $LOCK" > /dev/null 2>&1 & # This bit gives the nohup process time to create its locks and then reports sleep $NOHUP_START_TIME [ ! -f $LOCK ] && { echo "$PROGNAME: ERROR: can't create $LOCK"; return 1; } [ ! -f $LOCK.$PROGNAME ] && { rm -f $LOCK; echo "$PROGNAME: ERROR: can't create $LOCK.$PROGNAME"; return 1; } return 0 } main() { # global constants PROGNAME=`basename $0` USAGE="Usage: $PROGNAME [ -f ] [ -d timout ] line [ on | off ]" # default values for options, others may be at the top of this file FORCE=false while :; do case "$1" in -f) FORCE=true ;; -d) [ ! "$2" ] && { echo $USAGE; exit 1; } DYING_TIME=$2 shift ;; *) break ;; esac shift done [ $# -eq 1 -o $# -eq 2 ] || { echo $USAGE; exit 1; } # get lock file name case "$1" in /dev/*) LOCK=$LOCKDIR/LCK..`basename $1` ;; *) LOCK=$LOCKDIR/LCK..$1 ;; esac # process required arguments case "$2" in "") report_line $LOCK ;; on) lock_line $LOCK ;; off) unlock_line $LOCK ;; *) echo $USAGE; exit 1 ;; esac exit 0 } main "$@"