I have a Bash script that needs to lock a file for exclusive read/write while it runs. During this time, any other copies of the same script running should hang until the lock is released (which should be pretty quickly).
#!/bin/bash
trap "rm -f /tmp/.lock; exit" 0 1 2 3 15
(
flock -x 100
# Stuff happens here...
) 100>/tmp.lock
This works, somewhat. But not in these conditions:
- Start script copy #1
- Start script copy #2
- End script copy #1 before script copy #2 does
At this point, I get the error:
rm: cannot remove '/tmp/.lock': Text file busy
I assume I'm totally wrong on how I'm cleaning things up with the trap, so any help would be much appreciated. Thanks!
1 Answer 1
DO NOT EVER try to "clean up" flock-style lockfiles whenever it is possible that any program holding that lock could be running or attempting to run.
Keep in mind that locks are held on inodes, not filenames. Deleting a directory entry decouples the inode previously at that location from its name, allowing that name to then refer to a different inode.
Consider the following scenario:
- Program A holds a lock.
- Program B opens the lockfile and tries to grab a lock on it, blocking until Program A is done with the lock.
- Program A finishes; closes the lock; and deletes the lockfile.
- Program B still holds a handle on the deleted lockfile. As Program A closed the lock (or exited, releasing its file handle and thus its lock), Program B is able to continue running, holding that handle as its lock.
- Program C tries to grab the lock. Even though Program B is still running, because the lockfile Program B holds a handle on was deleted by Program A, Program C is allowed to run concurrently.
- Program B exits, deleting the lockfile that Program C created, while Program C is still running.
Flock-file lockfiles should be considered mappings from filesystem namespace into file-locking namespace. These mappings do not need to be, and should not be, "cleaned up". You may wish to consider whether your operating system's filesystem hierarchy standard provides a places for such files to live, such as /var/lock, or somewhere on tmpfs (where "cleanup" will happen implicitly -- and safely -- on reboot).
( flock -x 100; echo lock grabbed; rm /tmp/lol; sleep 60; ) 100> /tmp/lolas you want, and they'll all successfully lock/tmp/lolat the same time because the same filename keeps referring to different files.rm -fto happen without anytext file busyerror, instead silently breaking your locking. Consider yourself lucky that your particular Linux distro provides security hardening that saved you from this bug.0would be sufficient; an EXIT trap covers all cases of exiting due to trappable signals).