chiark / gitweb /
Found with-lock-ex.c on jura.
authorian <ian>
Thu, 19 Jul 2001 20:23:26 +0000 (20:23 +0000)
committerian <ian>
Thu, 19 Jul 2001 20:23:26 +0000 (20:23 +0000)
misc/with-lock-ex.c [new file with mode: 0644]

diff --git a/misc/with-lock-ex.c b/misc/with-lock-ex.c
new file mode 100644 (file)
index 0000000..1850d1f
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * File locker
+ *
+ * Usage: with-lock-ex -<mode> <lockfile> <command> <args>...
+ *
+ * modes are
+ *  w    wait for the lock
+ *  f    fail if the lock cannot be acquired
+ *  q    silently do nothing if the lock cannot be acquired
+ *
+ * with-lock-ex will open and lock the lockfile for writing and
+ * then feed the remainder of its arguments to exec(2); when
+ * that process terminates the fd will be closed and the file
+ * unlocked automatically by the kernel.
+ *
+ * If invoked as with-lock, behaves like with-lock-ex -f (for backward
+ * compatibility with an earlier version).
+ *
+ * This file written by me, Ian Jackson, in 1993, 1994, 1995, 1996,
+ * 1998, 1999.  I hereby place it in the public domain.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+static const char *cmd;
+
+static void fail(const char *why) __attribute__((noreturn));
+
+static void fail(const char *why) {
+  fprintf(stderr,"with-lock-ex %s: %s: %s\n",cmd,why,strerror(errno));
+  exit(255);
+}
+
+int main(int argc, char **argv) {
+  int fd, mode, um;
+  struct stat stab, fstab;
+  long cloexec;
+  struct flock fl;
+  const char *p;
+
+  if (argc >= 3 && !strcmp((p= strrchr(argv[0],'/')) ? ++p : argv[0], "with-lock")) {
+    mode= 'f';
+  } else if (argc < 4 || argv[1][0] != '-' || argv[1][2] ||
+            ((mode= argv[1][1]) != 'w' && mode != 'q' && mode != 'f')) {
+    fputs("usage: with-lock-ex -w|-q|-f <lockfile> <command> <args>...\n"
+         "       with-lock             <lockfile> <command> <args>...\n",
+         stderr);
+    exit(255);
+  } else {
+    argv++; argc--;
+  }
+  cmd= argv[2];
+  um= umask(0777); if (um==-1) fail("find umask");
+  if (umask(um)==-1) fail("reset umask");
+
+  for (;;) {
+  
+    fd= open(argv[1],O_RDWR|O_CREAT,0666&~(um|((um&0222)<<1)));
+    if (fd<0) fail(argv[1]);
+  
+    for (;;) {
+      fl.l_type= F_WRLCK;
+      fl.l_whence= SEEK_SET;
+      fl.l_start= 0;
+      fl.l_len= 1;
+      if (fcntl(fd, mode=='w' ? F_SETLKW : F_SETLK, &fl) != -1) break;
+      if (mode=='q' &&
+         (errno == EAGAIN || errno == EWOULDBLOCK || errno == EBUSY))
+       exit(0);
+      if (errno != EINTR) fail("could not acquire lock");
+    }
+
+    if (fstat(fd, &fstab)) fail("could not fstat lock fd");
+    if (stat(argv[1], &stab)) {
+      if (errno != ENOENT) fail("could not stat lockfile");
+    } else {
+      if (stab.st_dev == fstab.st_dev &&
+         stab.st_ino == fstab.st_ino) break;
+    }
+    close(fd);
+  }
+
+  cloexec= fcntl(fd, F_GETFD); if (cloexec==-1) fail("fcntl F_GETFD");
+  cloexec &= ~1;
+  if (fcntl(fd, F_SETFD, cloexec)==-1) fail("fcntl F_SETFD");
+
+  execvp(cmd,argv+2);
+  fail("unable to execute command");
+}