Here's an efficient and portable way to create a lockfile from a shell script. [6] It's also an interesting demonstration of the way that UNIX umasks ( 22.4 ) and file permissions ( 22.2 ) are handled.
[6] Greg Ubben sent this idea.
A lockfile can be used if a particular program might be run more than once at the same time - and you need to be sure that only one instance of the program can do something (like modify some file, access a printer, etc.). Let's say you have a script called edmaster ; it edits a master configuration file named config . To be sure that two users can't modify the config file at the same time, the first edmaster would check whether the lockfile exists. If the lockfile doesn't exist, edmaster will create it and modify the config file. When it's done editing, it removes the lockfile. If someone tries to run a second edmaster process, it will see the lockfile from the first edmaster , wait and check every few seconds to see if the lockfile is gone. Once the first edmaster removes the lockfile, the second edmaster can create the lockfile and do its editing of config .
Here are pieces of a script that check the lock, create it, and (later) remove it:
2> /dev/null set |
# set name of this program's lockfile: myname=`basename $0` LOCKFILE=/tmp/lock.$myname ... # Loop until we get a lock: until (umask 222; echo $$ >$LOCKFILE) 2>/dev/null # test & set do # Optional message - show lockfile owner and creation time: set x `ls -l $LOCKFILE` echo "Waiting for user $4 (working since $7 $8 $9)..." sleep 5 done # Do whatever we need exclusive access to do... ... rm -f $LOCKFILE # unlock |
---|
So if another user tried to run edconfig , and jpeek had run edconfig first, she might see:
%edconfig
Waiting for user jpeek (working since Aug 23 14:05)... ...a 5-second pause Waiting for user jpeek (working since Aug 23 14:05)... another 5-second pause... ...then jpeek finishes and she can edit the file.
How does it work? Almost all of the action is in the first line of the loop. A umask of 222 creates files that are read-only (mode
r--r--r--
). Because the
umask 222
command is run in a
subshell (
38.4
)
, it only affects the lockfile that's created in the subshell at the top of the loop. The rest of the shell script keeps its normal umask.
If the lockfile already exists (because another process has created it), the loop executes
sleep 5
; five seconds later, it tries to create the lock. If the lockfile exists, it will be read-only - so, the command
echo $$ >$LOCKFILE
will return a nonzero status. A nonzero status is what keeps an
until
loop (
44.10
)
running. Once the other process (which has the lock) removes the lockfile, the
echo
command in the subshell will write the shell's process ID number into the lockfile and the
until
loop will terminate.
But, if the lockfile is read-only, how can it ever be created? That's the other interesting part of this technique. The umask only applies to the file as it's created; if the file doesn't exist, the umask doesn't apply to it (yet) and the file can be created. In fact, you can create a file with mode 000 by typing:
$(umask 666; echo hi > afile)
$ls -l afile
---------- 1 jpeek wheel 3 Aug 23 14:08 afile
-