chiark / gitweb /
prefork-interp: locking: require same inode
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 20 Aug 2022 10:39:52 +0000 (11:39 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 21 Aug 2022 20:21:10 +0000 (21:21 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
cprogs/prefork.c

index 5c1d5bfb0ece8e402a0fa182623c7914a4fa1f35..21c4b7af4e950ea90bcf4a7db00284817f3cdddd 100644 (file)
@@ -187,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; }
 
-  r = flock(lockfd, LOCK_EX);
-  if (r) diee("lock lock (%s)", lock_path);
+    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 = 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;
 }