mtimeout.1: Use correct dash for number ranges.
[misc] / locking.c
index 68cbc74..6317b2e 100644 (file)
--- a/locking.c
+++ b/locking.c
@@ -39,6 +39,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
 
 #include <mLib/mdwopt.h>
 #include <mLib/quis.h>
@@ -95,6 +96,7 @@ int main(int argc, char *argv[])
   int t = -1;
   int oflag;
   unsigned int ot = 0;
+  struct stat st, nst;
   time_t nt;
   pid_t kid;
   int rc;
@@ -184,9 +186,25 @@ doneopts:
   ot = alarm(0);
   oalrm = signal(SIGALRM, alrm);
   if (t >= 0) alarm(t);
+again:
   if ((fd = open(file, oflag, 0666)) < 0)
     die(111, "error opening `%s': %s", file, strerror(errno));
+  if (fstat(fd, &st))
+    die(111, "error from fstat on `%s': %s", file, strerror(errno));
   err = fcntl(fd, f & f_wait ? F_SETLKW : F_SETLK, &l) >= 0 ? 0 : errno;
+  /* It's tempting to `optimize' this code by opening a new file descriptor
+   * here so as to elide the additional call to fstat(2) above.  But this
+   * doesn't work: if we successfully acquire the lock, we then have two file
+   * descriptors open on the lock file, so we have to close one -- but, under
+   * the daft fcntl(2) rules, even closing `nfd' will release the lock
+   * immediately.
+   */
+  if (stat(file, &nst)) {
+    if (errno == ENOENT) { close(fd); goto again; }
+    else die(111, "error from stat on `%s': %s", file, strerror(errno));
+  }
+  if (st.st_dev != nst.st_dev || st.st_ino != nst.st_ino)
+    { close(fd); goto again; }
 done:
   signal(SIGALRM, oalrm);
   if (!ot)