chiark / gitweb /
prefork-interp: locking: require same inode
[chiark-utils.git] / cprogs / prefork.c
index 095dd44e89d2778c5241568e1cd5bfff0f565cc8..21c4b7af4e950ea90bcf4a7db00284817f3cdddd 100644 (file)
@@ -2,14 +2,13 @@
 
 #include "prefork.h"
 
-const char *interp, *ident;
-
+const char *interp, *ident, *script, *socket_path, *lock_path;
+bool logging;
 struct sha256_ctx identsc;
 
-uid_t us;
-const char *run_base, *script, *socket_path, *lock_path;
-const char *run_base_mkdir_p;
-bool logging;
+static uid_t us;
+static const char *run_base;
+static const char *run_base_mkdir_p;
 
 void common_diee(const char *m) { diee("%s", m); }
 void common_die (const char *m) { die ("%s", m); }
@@ -20,7 +19,7 @@ void vmsgcore(int estatus, int errnoval, const char *fmt, va_list al) {
   if (logging) {
     const char *fmt_use = fmt;
     char *fmt_free = 0;
-    if (errnoval) {
+    if (errnoval!=-1) {
       r = asprintf(&fmt_free, "%s: %%m", fmt);
       if (r) {
        fmt_free = 0;
@@ -72,6 +71,11 @@ void off_ident_addenv(const struct cmdinfo *ci, const char *name) {
   }
 }
 
+bool stabs_same_inode(struct stat *a, struct stat *b) {
+  return (a->st_dev == b->st_dev &&
+         a->st_ino == b->st_ino);
+}
+
 bool find_run_base_var_run(void) {
   struct stat stab;
   char *try;
@@ -149,7 +153,8 @@ void find_socket_path(void) {
     int i;
 
     ident_addstring(0,interp);
-    ident_addstring(0,script);
+    if (script)
+      ident_addstring(0,script);
     sha256_digest(&identsc,sizeof(bbuf),bbuf);
 
     for (i=0; i<identlen; i += 2)
@@ -182,14 +187,31 @@ void find_socket_path(void) {
 int acquire_lock(void) {
   int r;
   int lockfd = -1;
+  struct stat stab_fd;
+  struct stat stab_path;
 
   lock_path = m_asprintf("%s/l%s",run_base,ident);
 
-  lockfd = open(lock_path, O_CREAT|O_RDWR, 0600);
-  if (lockfd<0) diee("create lock (%s)", lock_path);
+  for (;;) {
+    if (lockfd >= 0) { close(lockfd); lockfd = -1; }
+
+    lockfd = open(lock_path, O_CREAT|O_RDWR, 0600);
+    if (lockfd<0) diee("create lock (%s)", lock_path);
 
-  r = flock(lockfd, LOCK_EX);
-  if (r) diee("lock lock (%s)", lock_path);
+    r = flock(lockfd, LOCK_EX);
+    if (r && errno == EINTR) continue;
+    if (r) diee("lock lock (%s)", lock_path);
+
+    r = fstat(lockfd, &stab_fd);
+    if (r) diee("fstat locked lock");
+
+    r = stat(lock_path, &stab_path);
+    if (!r) {
+      if (stabs_same_inode(&stab_path, &stab_fd)) break;
+    } else {
+      if (!(errno == ENOENT)) diee("re-stat locked lock (%s)", lock_path);
+    }
+  }
 
   return lockfd;
 }
@@ -206,6 +228,7 @@ void process_opts(const char *const **argv_io) {
   const char *smashedopt;
 
   sha256_init(&identsc);
+  ident_addinit();
 
   if ((*argv_io)[0] &&
       (smashedopt = (*argv_io)[1]) &&
@@ -234,6 +257,9 @@ void process_opts(const char *const **argv_io) {
 
     shbang_opts(&split_argv, cmdinfos);
     /* sets interp */
+
+    if (!**argv_io)
+      badusage("no script argument (expected after combined #! options)");
   } else {
     shbang_opts(argv_io, cmdinfos);
   }