I'm new with fcntl locking and following this example to create a sample lock in linux using c code: http://www.informit.com/articles/article.aspx?p=23618&seqNum=4
I wonder how can we can print out which process hold the lock file and which process is waiting for lock. I consider using l_pid to figure out the process id which is holding the lock but i'm not sure the right way to do it. What is the best way to print out which process is holding the lock?
As the man 2 fcntl
page describes, you can use the F_GETLK
to obtain the process ID that has the conflicting lock (if the conflicting lock is a process-associated one). So, for example,
/* Return 0 if descriptor locked exclusively, positive PID if
a known process holds a conflicting lock, or -1 if the
descriptor cannot be locked (and errno has the reason).
*/
static pid_t lock_exclusively(const int fd)
{
struct flock lock;
int err = 0;
if (fd == -1) {
errno = EINVAL;
return -1;
}
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (!fcntl(fd, F_SETLK, &lock))
return 0;
/* Remember the cause of the failure */
err = errno;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_pid = 0;
if (fcntl(fd, F_GETLK, &lock) == 0 && lock.l_pid > 0)
return lock.l_pid;
errno = err;
return -1;
}
Do note that fd
must be open for reading and writing. I recommend using open(path, O_RDWR | O_NOCTTY)
or open(path, O_WRONLY | O_NOCTTY)
. Closing any file descriptor to the same file will release the lock.
Some may say that re-setting the lock
memebers before the second fcntl()
call is unnecessary, but I'd rather err on the side of caution here.
As to how to report it, I would simply use
int fd;
pid_t p;
fd = open(path, O_RDWR | O_NOCTTY);
if (fd == -1) {
fprintf(stderr, "%s: Cannot open file: %s.\n",
path, strerror(errno));
exit(EXIT_FAILURE);
}
p = lock_exclusively(fd);
if (p < 0) {
fprintf(stderr, "%s: Cannot lock file: %s.\n",
path, strerror(errno));
exit(EXIT_FAILURE);
} else
if (p > 0) {
fprintf(stderr, "%s: File is already locked by process %ld.\n",
path, (long)p);
exit(EXIT_FAILURE);
}
/* fd is now open and exclusive-locked. */
The user can always run e.g. ps -o cmd= -p PID
to see what command that is (or you can try reading /proc/PID/cmdline
in Linux).