[Chapter 45] 45.36 Shell Lockfile
Author: Jerry Peek, Tim O'Reilly & Mike Loukides
Date: 1998-08-04T21:55:24Z

#

| Chapter 45 Shell Programming for the Initiated |

## 45.36 Shell Lockfile

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

- JP

45.35 Using a Control Character in a Script |  | 46. Shell Script Debugging and Gotchas