I can't even imagine how many times I've heard someone complain
about a locked file. Sometimes it's simple - the call goes out
"Who has record 758 open?" or something like that, and sure enough,
Bill forgot he was working on that, closes it out and all is well.
But other times it is not simple, and a system admin has to track
down who is doing what.
Note that in this post we're talking about real locking - not
a volume that can't be ejected (Mac speak) or a file system that
can't be unmounted (the rest of us). For that, just use "lsof"
to find out what process is stopping you.
I had a customer call today with the locking problem: "How can we tell
if a user has a lock on a file in our application?". I immediately
thought of "lsof", because the man page says it should display
locking information. It does so on several Linux systems I tested,
but does not show that on my Mac.
For testing purposes, we'll need something that locks a file. This
very simple C program does that. Note that there is no error checking
at all here; it just assumes success on everything. Be sure to
"touch mylockedfile" before using this.
All that does is apply a lock to a few bytes of "mylocked" file. It
sits and waits for you to press enter, and then teminates. Locks
are removed upon process termination, so pressing enter ends
If you called that program "makelock.c", then "make makelock"
should compile it and "touch mylockedfile;./makelock" should
set it running. You should see this:
If you saw "-1" for either of those, something did not work, and
I'm not going to take the space here to try to help you figure
out what you did wrong - probably permissions.
In another screen, type "lsof mylockedfile". On
a Linux system, you should see something like this:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
makelock 6386 tonyl 3ww REG 3,2 0 2785316 mylockedfile
It's the extra "w" that indicates the lock. If you simply had
the file open, there would only be one "w". OK, that's nice,
and it certainly wouldn't be hard to wrap a shell script around lsof
to find the offending user. But unfortunately, on Mac OS X Leopard,
lsof can't seem to spot the lock:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
makelock 3331 apl 3w REG 14,2 0 9714583 mylockedfile
That doesn't help. And if we don't have root access, "lsof" won't help anyway.
Fortunately it's easy to write a little C program that tests
for other processes locking files. Again, this program has no error checking;
you'd want to dress it up much more for a production tool, but
the raw basics are this:
With "makelock" running, type "make testlock && ./testlock" and
it should return the process id of "makelock".
This "testlock" tries to lock the entire file. If you modified
it so that it had "lock.l_start=3;" and recompiled it, it would
report 0, meaning no lock (because "makelock" only locks the
first two bytes).
So, if you can use "lsof" in a shell script, that's an easy way
to find the responsible PID, but if you can't, something like
this certainly can. By the way,
on Linux, there's also /proc/locks, which does show all file locks,
but you'd need to grep inode numbers from it:
The "6641" after "WRITE is the PID, and the "4014117" is the inode. That's
a bit more difficult than using "lsof" or this program, but everything you
need is there. The "03:02" is the major-device:minor-device of the partition
that has the file (/dev/hda2 in this case), the rest of it has to do with the region locked, which you probably don't care about for this purpose.