: ########################################################################## # Title : mklock - aquire/release advisory lock # Date : 2001-04-10 # Category : System Utilities # Requires : - # SCCS-Id. : @(#) mklock 1.2 04/06/09 ########################################################################## # Description # This program can be used for advisory locking, e.g. to ensure that # only one instance of a program is running at a time. # # o It creates or removes a lock of a specified name # o The exit code of the script can be checked to find out # if a lock was aquired successfully, e.g. # # if mklock backup # then # # successfully aquired the lock # echo "creating backup..." # tar cf .... # mkunlock backup # else # # lock is already held by some other process # echo "backup is already running" # fi # # o The script checks its own name to find out if it should aquire or # release a lock. It should be installed using name ending with "lock" # and "unlock", e.g. "mklock" and "mkunlock": # $ ln -s mklock mkunlock # # Notes # o The process holding a lock should take care to release it # before it terminates, e.g. by using a trap (signal) handler: # trap "mkunlock mylock" 0 # release lock # trap "exit 2" 1 2 3 15 # catch signals # # Caveats # o could provide a way to test if a lock is held (without blocking) ########################################################################## PN=`basename "$0"` # Program name VER='1.2' : ${LOCKDIR:=${TMPDIR:-/tmp}} # Directory a lock will be created in LOCKNAME=lock # default lock name # Maximum time to wait for a lock to be released (in seconds) MAXTIME=10 naptime=2 usage () { echo >&2 "$PN - aquire/release advisory lock, $VER usage: $PN [-v] [-t maxtime] [lockname] -t: maximum time to wait for the lock (in seconds, default: $MAXTIME) -v: verbose operation" exit 1 } msg () { echo >&2 "$PN:" "$@" } fatal () { msg "$@"; exit 1; } # Note that "getopt" removes whitespace from the command line arguments. # If you do not like that, put the the following two lines in comments: set -- `getopt ht:v "$@"` || usage [ $# -lt 1 ] && usage # "getopt" detected an error Verbose=false while [ $# -gt 0 ] do case "$1" in -t) MaxTime=$2; shift case "$MaxTime" in *[!0-9]*) fatal "invalid number of seconds: $MaxTime";; esac [ "$MaxTime" -lt $naptime ] && MaxTime=$naptime ;; -v) Verbose=true;; --) shift; break;; -h) usage;; -*) usage;; *) break;; # First file name esac shift done maxtime=${MaxTime:-$MAXTIME} case "$PN" in *unlock) Action=unlock;; *lock) Action=lock;; *) fatal "ERROR: program name does neither end in \"lock\" nor" \ "\"unlock\": $PN";; esac [ $# -lt 1 ] && set -- "$LOCKNAME" lockname=$1; shift lockpath=$LOCKDIR/$lockname case "$Action" in lock) timetowait=$maxtime until mkdir "$lockpath" >/dev/null 2>&1 do if [ $timetowait -lt $naptime ] then if $Verbose then msg "could not aquire lock: $lockname" [ -s "$lockpath/owner" ] && msg "owner:" `cat "$lockpath/owner"` fi exit 1 fi $Verbose && msg "lock \"$lockname\" is held, waiting max. $timetowait seconds" sleep $naptime timetowait=`expr $timetowait - $naptime` done $Verbose && msg "$$: aquired lock $lockname" date >> "$lockpath/owner" id >> "$lockpath/owner" ;; unlock) $Verbose && msg "$$: releasing lock $lockname" rm -rf "$lockpath" || fatal "cannot unlock $lockname" ;; *) fatal "INTERNAL ERROR: unknown action: <$Action>" ;; esac exit 0