chiark / gitweb /
prefork-interp: locking: require same inode
[chiark-utils.git] / cprogs / prefork.c
index aaac059e1bb3a739d64957ebdf5bf9b3fa9ae4c6..21c4b7af4e950ea90bcf4a7db00284817f3cdddd 100644 (file)
@@ -71,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;
@@ -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 && errno == EINTR) continue;
+    if (r) diee("lock lock (%s)", lock_path);
 
-  r = flock(lockfd, LOCK_EX);
-  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]) &&