Last active
December 11, 2023 16:53
-
-
Save mjf/2134329 to your computer and use it in GitHub Desktop.
lockscript - Shell script locking template
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /bin/sh | |
# lockscript - Shell script locking template | |
# Copyright (C) 2012-2014 Matous J. Fialka, <http://mjf.cz/> | |
# Released under the terms of The MIT License | |
# USAGE | |
# ===== | |
# | |
# Rename, link or source this file to your desired script. | |
# | |
# ENVIRONMENT | |
# =========== | |
# | |
# Name Description | |
# ----------- ----------------------------------------------------- | |
# LOCKTIME Time to stay locked (-1 means to never unlock) | |
# LOCKFILE Path to lockfile | |
# PIDFILE Path to file to write process ID (PID) to | |
# CONFIGFILE List of paths to configuration (separated by collons) | |
# SCRIPTFILE Path to file to include as main script | |
# ------------------------------------------------------------------- | |
# | |
# DESCRIPTION | |
# =========== | |
# | |
# The script first tries to read CONFIGFILE in order, then it writes | |
# PIDFILE and LOCKFILE. If everything went OK it sources SCRIPTFILE. | |
# It also does signal trapping so that you do not have to handle it. | |
# The SCRIPTFILE or main part wouldn't get run again unless LOCKTIME | |
# expires (to reset lock use LOCKTIME=0 which means to ignore lock). | |
# | |
# <<>> BASIC INFORMATION <<>> | |
# | |
PROGRAM=`basename "$0"` | |
if [ "$PROGRAM" = "$__PROGRAM" ] | |
then | |
echo "Source loop detected for $__PROGRAM" 1>&2 | |
exit 1 | |
fi | |
__PROGRAM="$PROGRAM" | |
# | |
# <<>> CONFIGFILE <<>> | |
# | |
if [ "${#CONFIGFILE}" -eq 0 ] | |
then | |
CONFIGFILE="/etc/${PROGRAM}.conf:$HOME/.${PROGRAM}rc":"./.${PROGRAM}rc" | |
else | |
CONFIGFILE="/etc/${PROGRAM}.conf:$HOME/.${PROGRAM}rc":"./.${PROGRAM}rc":"$CONFIGFILE" | |
fi | |
__OFS="$IFS" | |
IFS=: | |
for __CONFIGFILE in $CONFIGFILE | |
do | |
if [ -e "$__CONFIGFILE" ] | |
then | |
if ! [ -r "$__CONFIGFILE" ] | |
then | |
echo "Could not source $__CONFIGFILE" 1>&2 | |
exit 1 | |
fi | |
source "$__CONFIGFILE" | |
fi | |
unset __CONFIGFILE | |
done | |
IFS="$__OFS" | |
# | |
# <<>> PIDFILE <<>> | |
# | |
if [ "${#PIDFILE}" -eq 0 ] | |
then | |
if [ "$USER" = 'root' ] | |
then | |
PIDFILE="/var/run/$PROGRAM.pid" | |
else | |
PIDFILE="/tmp/$PROGRAM.pid" | |
fi | |
fi | |
if [ -e "$PIDFILE" ] | |
then | |
echo "Concurent session is running. PID file is $PIDFILE" 1>&2 | |
exit 1 | |
fi | |
__PIDFILE_DIRNAME=`dirname "$PIDFILE"` | |
if [ -w "$__PIDFILE_DIRNAME" ] | |
then | |
echo "$$" > "$PIDFILE" | |
else | |
echo "Path to write PID file $PIDFILE is not writable" 1>&2 | |
exit 1 | |
fi | |
unset __PIDFILE_DIRNAME | |
# | |
# <<>> SIGNALS <<>> | |
# | |
signal_handler_general() | |
{ | |
EXIT=${EXIT:-$?} | |
if [ -r "$PIDFILE" ] | |
then | |
if [ $(< $PIDFILE) -eq $$ ] | |
then | |
rm -f "$PIDFILE" | |
fi | |
fi | |
trap - 0 1 2 3 13 15 | |
kill -2 $$ | |
} | |
signal_handler_exit() | |
{ | |
EXIT=${EXIT:-$?} | |
if [ $EXIT -eq 0 ] | |
then | |
rm -f "$LOCKFILE" | |
fi | |
signal_handler_general | |
} | |
trap signal_handler_exit 0 | |
trap signal_handler_general 1 2 3 13 15 | |
# | |
# <<>> LOCKFILE <<>> | |
# | |
if [ "${#LOCKFILE}" -eq 0 ] | |
then | |
if [ "$USER" = 'root' ] | |
then | |
LOCKFILE="/var/lock/$PROGRAM.lock" | |
else | |
LOCKFILE="/tmp/$PROGRAM.lock" | |
fi | |
fi | |
__LOCKFILE_DIRNAME=`dirname "$LOCKFILE"` | |
if [ ! -w "$__LOCKFILE_DIRNAME" ] | |
then | |
echo "Path to write lock file $LOCKFILE is not writable" 1>&2 | |
exit 1 | |
fi | |
unset __LOCKFILE_DIRNAME | |
LOCKTIME="${LOCKTIME:--1}" | |
if [ "$LOCKTIME" -lt -1 ] | |
then | |
echo 'Invalid LOCKTIME value (must be in range -1..N)' 1>&2 | |
exit 1 | |
fi | |
if [ -e "$LOCKFILE" ] | |
then | |
if [ "$LOCKTIME" -eq -1 ] | |
then | |
echo "Session is permanently locked. Lockfile is $LOCKFILE" 1>&2 | |
exit 1 | |
fi | |
if ! [ `stat -c %Z "$LOCKFILE"` -lt $((`date +%s` - $LOCKTIME + 1)) ] | |
then | |
echo "Session is temporarily locked. Lockfile is $LOCKFILE" 1>&2 | |
exit 1 | |
fi | |
fi | |
touch "$LOCKFILE" | |
# | |
# <<>> SCRIPTFILE <<>> | |
# | |
if [ "${#SCRIPTFILE}" -ne 0 ] | |
then | |
if [ -e "$SCRIPTFILE" ] | |
then | |
if [ -r "$SCRIPTFILE" ] | |
then | |
source "$SCRIPTFILE" | |
else | |
echo "Unable to read script file $SCRIPTFILE" 1>&2 | |
exit 1 | |
fi | |
else | |
echo "Unable to find script file $SCRIPTFILE" 1>&2 | |
exit 1 | |
fi | |
fi | |
# | |
# <<>> MAIN <<>> | |
# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
USAGE
Create a demo script somewhere in the
$PATH
:Run it via
lockscript
:If the
lockscript-demo
script specified in theSCRIPTFILE
variablefails then it can not be run again using the
lockscript
program forat least 5 seconds specified in then
LOCKTIME
variable.In case you would like to enjoy the
lockscript
configuration fileslink it to you desired name, say
test.sh
:Now you can place your configuration in
CONFIGFILE
paths, in order:/etc/test.conf
$HOME/testrc
./testrc
$CONFIGFILE
And run
lockscript
astest
like this:You can place configuration variables for the
lockscript-demo
in any of theconfiguration files as listed above.
You can also copy the
lockscript
program with another name and use the last MAINpart of the script to either place
SCRIPTFILE
post-run code or you can useit to implement standalone script as well.
Of course, feel free to source this file at the beginning of any script you like.