chiark / gitweb /
prefork-interp: add copyright licences
[chiark-utils.git] / cprogs / prefork.c
index 909d0658ebf7f407f317f32164299b8306ff7101..b8f4c8a2b1834d8eeca8405eb56da798f4d39524 100644 (file)
@@ -1,13 +1,18 @@
 /* common stuff for cgi-fcgi-interp and prefork-interp */
+/*
+ * Copyright 2016-2022 Ian Jackson and contributors to chiark-utils
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * There is NO WARRANTY.
+ */
 
 #include "prefork.h"
 
 const char *interp, *ident, *script, *socket_path, *lock_path;
 bool logging;
 struct sha256_ctx identsc;
+const char *run_base;
 
 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); }
@@ -55,22 +60,34 @@ void of_iassign(const struct cmdinfo *ci, const char *val) {
   *ci->iassignto = v;
 }
 
-void ident_addstring(const struct cmdinfo *ci, const char *string) {
-  /* ci may be 0 and is provided so this can be .call */
+void ident_add_key_byte(char key) {
+  sha256_update(&identsc,1,&key);
+}
+
+void ident_addstring(char key, const char *string) {
+  ident_add_key_byte(key);
   sha256_update(&identsc,strlen(string)+1,string);
 }
 
+void off_ident_addstring(const struct cmdinfo *ci, const char *string) {
+  ident_addstring('G', string);
+}
+
 void off_ident_addenv(const struct cmdinfo *ci, const char *name) {
+  ident_addstring('E', name);
   const char *val = getenv(name);
   if (val) {
-    sha256_update(&identsc,strlen(name),name); /* no nul */
-    sha256_update(&identsc,1,"=");
-    ident_addstring(0,val);
+    ident_addstring('v', val);
   } else {
-    ident_addstring(0,name);
+    ident_add_key_byte(0);
   }
 }
 
+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;
@@ -147,9 +164,9 @@ void find_socket_path(void) {
     unsigned char bbuf[32];
     int i;
 
-    ident_addstring(0,interp);
+    ident_addstring('i', interp);
     if (script)
-      ident_addstring(0,script);
+      ident_addstring('s', script);
     sha256_digest(&identsc,sizeof(bbuf),bbuf);
 
     for (i=0; i<identlen; i += 2)
@@ -179,21 +196,42 @@ void find_socket_path(void) {
 }  
 
 // Returns fd
-int acquire_lock(void) {
+int flock_file(const char *lock_path) {
   int r;
   int lockfd = -1;
+  struct stat stab_fd;
+  struct stat stab_path;
 
-  lock_path = m_asprintf("%s/l%s",run_base,ident);
+  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);
 
-  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;
 }
 
+// Returns fd
+int acquire_lock(void) {
+  lock_path = m_asprintf("%s/l%s",run_base,ident);
+  return flock_file(lock_path);
+}
+
 static void shbang_opts(const char *const **argv_io,
                        const struct cmdinfo *cmdinfos) {
   myopt(argv_io, cmdinfos);