| Add comments here | |
|
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
Often, one would like a process to have exclusive
access to a file. By this we mean that only one process can
access the file at any one time. Consider a mail folder: if two
processes were to write to the folder simultaneously it could
become corrupted. We also sometimes want to ensure that a
program can never be run twice at the same time; this
is another use for ``locking''.
|
| |
In the case of a mail folder, if the file is being
written to, then no other process should try read it or
write to it: and we would like to create a write lock on
the file. However if the file is being read from, no other
process should try to write to it: and we would like to create a
read lock on the file. Write locks are sometimes called
exclusive locks, while read locks are sometimes called
shared locks. Often exclusive locks are preferred
for simplicity.
|
| |
Locking can be implemented by simply creating a temporary file
to indicate to other processes to wait before trying some kind of
access. UNIX also has some more sophisticated builtin functions.
|
| |
|
| |
There are currently four methods of file locking23.1
|
| |
- 1.
- ``dot lock'' file locking. Here, a temporary file
is created with the same name as the mail folder and the extension
.lock added. So long as this file exists, no program should
try to access the folder. This is an exclusive lock only. It is
easy to write a shell script to do this kind of file locking.
- 2.
- ``MBX'' file locking. Similar to 1. but a temporary file
is created in
/tmp. This is also an exclusive lock.
- 3.
fcntl locking. Databases require areas of a file
to be locked. fcntl is a system call to be used inside C
programs.
- 4.
flock file locking. Same as fcntl, but locks
whole files.
|
| |
The following shell function does proper mailbox file
locking:
5
10
15
20
25
|
function my_lockfile ()
{
TEMPFILE="$1.$$"
LOCKFILE="$1.lock"
{ echo $$ > $TEMPFILE } >& /dev/null || {
echo "You don't have permission to access `dirname $TEMPFILE`"
return 1
}
ln $TEMPFILE $LOCKFILE >& /dev/null && {
rm -f $TEMPFILE
return 0
}
kill -0 `cat $LOCKFILE` >& /dev/null && {
rm -f $TEMPFILE
return 1
}
echo "Removing stale lock file"
rm -f $LOCKFILE
ln $TEMPFILE $LOCKFILE >& /dev/null && {
rm -f $TEMPFILE
return 0
}
rm -f $TEMPFILE
return 1
}
|
You can include this in scripts that need to lock
any kind file as follows:
5
10
|
# wait for a lock
until my_lockfile /etc/passwd ; do
sleep 1
done
# The body of the program might go here
# [...]
# Then to remove the lock,
rm -f /etc/passwd.lock
|
|
| |
There are a couple of interesting bits in this script: note how
the ln function is used to ensure ``exclusivity''. ln
is one of the few UNIX functions that is atomic,
meaning that only one link of the same name can exist, and its
creation excludes the possibility that another program would
think that it had successfully created the same link. One might
naively expect that the program,
5
|
function my_lockfile ()
{
LOCKFILE="$1.lock"
test -e $LOCKFILE && return 1
touch $LOCKFILE
return 0
}
|
is sufficient for file locking. However consider if two programs
running simultaneously executed line 4 at the same time. Both would
think that the lock did not exist and proceed to line 5. Then both
would successfully create the lockfile -- not what you wanted.
|
| |
The kill command is then useful for checking if
a process is running. Sending the 0 signal does nothing to
the process, but fails if the process does not exist. This can be
used to remove a lock of a process that died before doing so
itself: i.e. a stale lock.
|
| |
|
| |
The above script does not work if your file system is
mounted over NFS (networked file system -- see
Chapter 29). This is obvious because it relies on the
PID of the process, which could clash across different
machines. Not so obvious is that the ln function does not
work exactly right over NFS -- you need to stat the
file and actually check that the link count has increased to 2.
|
| |
There is a program that comes with the
procmail package called lockfile and another that
comes with the mutt email reader called
mutt_dotlock (perhaps not distributed). These do similar
file locking, but do not store the PID in the lock file. Hence it
is not possible to detect a stale lock file. For example to search
your mailbox, you can do:
|
lockfile /var/spool/mail/mary.lock
grep freddy /var/spool/mail/mary
rm -f /var/spool/mail/mary.lock
|
which will ensure that you are searching a clean mailbox
even if /var is a remote NFS share.
|
| |
|
| |
File locking is a headache for the developer. The
problem with UNIX is that whereas we are intuitively thinking
about locking a file, what we really mean is locking a
file name within a directory. File locking
per se should only be used on perpetual files, such as
database files. For mailbox and passwd files we need
directory locking23.2, meaning the
exclusive access of one process to a particular directory entry.
In my opinion, lack of such a feature is a serious deficiency in
UNIX, but because it will require kernel, NFS, and (possibly)
C library extensions, will probably not come into being any
time soon.
|
| |
|
| |
This certainly outside of the scope of this text, except to say
that you should consult the source code of reputed packages
rather than invent your own locking scheme.
|
| |
|