Skip to content

Instantly share code, notes, and snippets.

@jesboat
Created December 26, 2015 21:14
Show Gist options
  • Save jesboat/14e32d63dee5a01d81ee to your computer and use it in GitHub Desktop.
Save jesboat/14e32d63dee5a01d81ee to your computer and use it in GitHub Desktop.
Check whether there are outstanding POSIX fcntl or flock locks on files. Written after a stray lock broke my mbox, to see if there were any others hiding around. Does not check for dotlocks (just use ls).
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
/* Compile with any c99 compiler:
*
* cc -o confirm-lock confirm-lock.c
*
* Tested with:
*
* gcc --std=c99 --pedantic -Wall -Wextra -o confirm-lock confirm-lock.c
*
*/
static int failed_to_lock = 0;
static int other_failure = 0;
static
void
confirm_lock(const char* path)
{
int fd, err;
fd = open(path, O_RDWR | O_APPEND);
if (fd < 0) {
fprintf(stderr, "open %s: %s\n", path, strerror(errno));
other_failure = 1;
return;
}
struct flock lock = {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
.l_start = 0, /* beginning of file */
.l_len = 0, /* special meaning: full file */
};
err = fcntl(fd, F_SETLK, &lock);
if (err < 0) {
fprintf(stderr, "fcntl F_SETLK: %s: %s\n", path, strerror(errno));
if (errno == EAGAIN || errno == EACCES) {
failed_to_lock = 1;
} else {
other_failure = 1;
}
} else {
lock.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &lock);
}
err = flock(fd, LOCK_EX | LOCK_NB);
if (err < 0) {
fprintf(stderr, "flock %s: %s\n", path, strerror(errno));
if (errno == EWOULDBLOCK) {
failed_to_lock = 1;
} else {
other_failure = 1;
}
} else {
flock(fd, LOCK_UN);
}
close(fd);
}
/**
* Checks whether one or more files have outstanding kernel locks.
* One example use might be to confirm that nothing has any of
* a user's mailboxes locked: `cd ~/mail && confirm-lock *`
*
* Arguments: one or more paths to existing files
*
* Exit codes:
* 0: no errors and no outstanding locks
* 1: usage error
* 2: at least one outstanding lock found (see stderr for details)
* 3: other error (see stderr for details)
*/
int
main(int argc, char **argv)
{
int i;
if (argc < 2) {
fprintf(stderr, "Usage: %s file ...\n", argv[0]);
return 1;
}
for (i=1; i<argc; i++) {
confirm_lock(argv[i]);
}
if (other_failure) {
return 3;
} else if (failed_to_lock) {
return 2;
} else {
return 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment