clockingflock

flock(): is it possible to merely check if the file is already locked, without actually acquiring the lock if not?


My use case is as follows: I have a program that enforces that only one instance of it can be running at any given time, so at startup it always tries to grab hold of a lock file in a standard location, and terminates if the file is already locked. That's all working fine, but now I want to enhance the program with a new command-line option which, when specified, will cause the program to just print out a status report for the program and then terminate (prior to the main lock guard described above), which will include whether the lock file is already locked or not, what the pid of the running process is (if such exists), and some program state queried from a database.

So as you can see, when invoked in this "status report" mode, my program should not actually acquire the lock if it is available. I just want to know if the file is already locked or not, so I can inform the user as part of the status report.

From my searching, there does not appear to be any way of doing this. Rather, the only possible solution seems to be to call flock() with the non-blocking flag, and then, if you actually acquired the lock, you can release it immediately. Something like this:

if (flock(fileno(lockFile), LOCK_EX|LOCK_NB ) == -1) {
    if (errno == EWOULDBLOCK) {
        printf("lock file is locked\n");
    } else {
        // error
    } // end if
} else {
    flock(fileno(lockFile), LOCK_UN );
    printf("lock file is unlocked\n");
} // end if

I suppose it's not such a big deal to acquire the lock and then release it immediately, but I was wondering if there's any better solution out there that doesn't involve a brief and unnecessary acquisition of the lock?

Note: There are already a couple of similar questions whose titles may make it seem like they're identical to this question, but it is clear from the contents of those questions that the OPs are interested in actually writing to the file after acquiring the lock, so this is a distinct question:


Solution

  • You cannot do this reliably. Processes are asynchronous: when you fail to acquire the lock, there is no guarantee that the file will still be locked by the time you print the locked status. Similarly, if you manage to acquire the lock, You then immediately release it, so by the time you print the unlocked status, the file my have been locked by another process. If there are a lot of contenders trying to lock this file, the likelihood of the status message being out of sync is high. Attackers can take advantage of this kind of approximation to penetrate systems.

    If you were to rely on this check in a script to perform any kind of concurrent work, all bets are off. If it is just producing an informative status, you should use the past tense in the status messages:

    if (flock(fileno(lockFile), LOCK_EX|LOCK_NB) == -1) {
        if (errno == EWOULDBLOCK) {
            printf("lock file was locked\n");
        } else {
            // error
        }
    } else {
        flock(fileno(lockFile), LOCK_UN);
        printf("lock file was unlocked\n");
    }