chiark / gitweb /
Server checks itself every hour, and logs with pid.
authorian <ian>
Sat, 11 Oct 1997 12:46:26 +0000 (12:46 +0000)
committerian <ian>
Sat, 11 Oct 1997 12:46:26 +0000 (12:46 +0000)
Changelog
common.h
daemon.h
overlord.c
process.c

index 71a09a4e2640574c2692e612bbe31190e31b0900..7e9b9753570e11f7a9445a0c000fe76c4a17202a 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,12 @@
+userv (0.56); urgency=medium
+
+  * Server now checks itself every hour to see if its socket has been
+    stolen, and exits if it has.
+  * Client only retries connect(2) on EINTR (and does so silently).
+  * All of even master server's syslog messages have pid.
+
+ -- Ian Jackson <ian@davenant.greenend.org.uk>  Sat, 11 Oct 1997 13:45:38 +0100
+
 userv (0.55.2); urgency=low
 
   * Added info about WWW page, mailing lists and bug reporting to README.  
index f73ea4d876c73da5780310d1369ba3f3152cfe32..ee243b1ac3aeb7ba0f358b056da48987c4e57b87 100644 (file)
--- a/common.h
+++ b/common.h
@@ -77,7 +77,7 @@ enum {
 struct opening_msg {
   unsigned long magic;
   unsigned char protocolchecksumversion[PCSUMSIZE];
-  pid_t serverpid;
+  pid_t overlordpid, serverpid;
 };
 
 struct request_msg {
index 710d854a173f5aa87c5be21bffa836ede22295ee..9efd98271b221293aaf63bd41544703fccf8f603 100644 (file)
--- a/daemon.h
+++ b/daemon.h
@@ -75,6 +75,7 @@
 #define SETENVIRONMENTPATH          SYSTEMCONFIGDIR "/" SETENVIRONMENT
 
 #define USERVD_LOGIDENT "uservd"
+#define USERVDCHECK_LOGIDENT "uservd/check"
 #define USERVD_LOGFACILITY LOG_DAEMON
 #define DEFUSERLOGFACILITY LOG_DAEMON
 #define DEFUSERLOGLEVEL LOG_ERR
   quit                                             \n\
 "
 
+#define USERVD_MYSELF_CHECK 3600
+#define USERVD_MYSELF_TIMEOUT 60
 #define MAX_INCLUDE_NEST 40
 #define MAX_ERRMSG_LEN (MAX_ERRMSG_STRING-1024)
 #define ERRMSG_RESERVE_ERRNO 128
@@ -145,6 +148,7 @@ struct fdstate {
 
 struct keyvaluepair { char *key, *value; };
 
+extern pid_t overlordpid;
 extern struct request_msg request_mbuf;
 extern struct keyvaluepair *defvararray;
 extern struct fdstate *fdarray; /* indexed by nominal fd */
index 241bb0de60d00a2d1fc19b85e6cff15cc57e5739..e32c9a10db0e2757cef1891af07a76dc1b21b81d 100644 (file)
 #include "common.h"
 #include "daemon.h"
 
+pid_t overlordpid;
+
+static pid_t checkpid= -1;
+static sig_atomic_t needcheck= 1;
+
 static void checkstalepipes(void) {
   /* There is an unimportant race here.  If there is a stale pipe but
    * another pair of processes with the same pids is about to create a
@@ -75,46 +80,138 @@ static void checkstalepipes(void) {
 
 static void sighandler_chld(int x) {
   pid_t r;
-  int status, es;
+  int status, es, ar;
 
   es= errno;
   for (;;) {
     r= waitpid((pid_t)-1,&status,WNOHANG);
     if (!r || (r==-1 && errno==ECHILD)) break;
     if (r==-1) { syslog(LOG_ERR,"wait in sigchild handler gave error: %m"); break; }
-    if (WIFSIGNALED(status)) {
-      if (WCOREDUMP(status))
-       syslog(LOG_ERR,"call pid %ld dumped core due to signal %s",(long)r,
+    if (r==checkpid) {
+      if (WIFEXITED(status)) {
+       if (!WEXITSTATUS(status)) {
+         syslog(LOG_NOTICE,"no longer the uservd - exiting");
+         _exit(0);
+       } else if (WEXITSTATUS(status)!=1) {
+         syslog(LOG_ERR,"check pid %ld exited with status %d",
+                (long)checkpid,WEXITSTATUS(status));
+       }
+      } else if (WIFSIGNALED(status)) {
+       if (WTERMSIG(status) == SIGALRM && !WCOREDUMP(status)) {
+         syslog(LOG_NOTICE,"check timed out; no longer the uservd - exiting");
+         _exit(0);
+       } else {
+         syslog(LOG_ERR,"check pid %ld %s due to signal %s",
+                (long)checkpid,
+                WCOREDUMP(status) ? "dumped core" : "died",
+                strsignal(WTERMSIG(status)));
+       }
+      } else {
+       syslog(LOG_ERR,"check pid %ld died due to unknown reason, code %d",
+              (long)checkpid,status);
+      }
+      checkpid= -1;
+      ar= alarm(USERVD_MYSELF_CHECK);
+      if (ar<0) { syslog(LOG_CRIT,"set alarm for next check: %m"); exit(5); }
+    } else {
+      if (WIFSIGNALED(status)) {
+       syslog(LOG_ERR,"call pid %ld %s due to signal %s",
+              (long)r,
+              WCOREDUMP(status) ? "dumped core" : "died",
               strsignal(WTERMSIG(status)));
-      else
-       syslog(LOG_ERR,"call pid %ld died due to signal %s",
-              (long)r,strsignal(WTERMSIG(status)));
-    } else if (!WIFEXITED(status)) {
-      syslog(LOG_ERR,"call pid %ld died due to unknown reason, code %ld",
-            (long)r,status);
-    } else if (WEXITSTATUS(status)>12) {
-      if (WEXITSTATUS(status)>24)
-       syslog(LOG_ERR,"call pid %ld exited with status %d >24",
-              (long)r,WEXITSTATUS(status));
-      checkstalepipes();
+      } else if (!WIFEXITED(status)) {
+       syslog(LOG_ERR,"call pid %ld died due to unknown reason, code %d",
+              (long)r,status);
+      } else if (WEXITSTATUS(status)>12) {
+       if (WEXITSTATUS(status)>24)
+         syslog(LOG_ERR,"call pid %ld exited with status %d >24",
+                (long)r,WEXITSTATUS(status));
+       checkstalepipes();
+      }
     }
   }
   errno= es;
   return;
 }
 
+static void sighandler_alrm(int x) {
+  needcheck= 1;
+}
+
 static void blocksignals(int how) {
   int r;
   sigset_t set;
 
   sigemptyset(&set);
   sigaddset(&set,SIGCHLD);
+  sigaddset(&set,SIGALRM);
   r= sigprocmask(how,&set,0); assert(!r);
 }
 
+static void NONRETURNING docheck(void) {
+#ifndef DEBUG
+  /* This subprocess exits with status 0 if the parent should die,
+   * 1 if it should not, and something else if it fails horribly.
+   */
+  int sfd, r, remain;
+  unsigned char *p;
+  struct opening_msg opening_mbuf;
+  struct sigaction sig;
+  struct sockaddr_un ssockname;
+
+  openlog(USERVDCHECK_LOGIDENT,LOG_NDELAY|LOG_PID,USERVD_LOGFACILITY);
+
+  sigemptyset(&sig.sa_mask);
+  sig.sa_flags= 0;
+  sig.sa_handler= SIG_IGN;
+  if (sigaction(SIGPIPE,&sig,0)) { syslog(LOG_ERR,"ignore sigpipe"); exit(1); }
+
+  sig.sa_handler= SIG_DFL;
+  if (sigaction(SIGALRM,&sig,0)) { syslog(LOG_ERR,"default sigalarm"); exit(1); }
+
+  sfd= socket(AF_UNIX,SOCK_STREAM,0);
+  if (!sfd) { syslog(LOG_ERR,"ignore sigpipe"); exit(1); }
+
+  assert(sizeof(ssockname.sun_path) > sizeof(RENDEZVOUS));
+  ssockname.sun_family= AF_UNIX;
+  strcpy(ssockname.sun_path,RENDEZVOUS);
+
+  r= connect(sfd,(struct sockaddr*)&ssockname,sizeof(ssockname));
+  if (r) {
+    if (errno == ECONNREFUSED || errno == ENOENT)
+      { syslog(LOG_NOTICE,"uservd daemon is not running: %m"); exit(0); }
+    syslog(LOG_ERR,"unable to connect to uservd daemon: %m"); exit(1);
+  }
+
+  r= alarm(USERVD_MYSELF_TIMEOUT);
+  if (r<0) { syslog(LOG_ERR,"set alarm for read: %m"); exit(1); }
+  remain= sizeof(opening_mbuf); p= (unsigned char*)&opening_mbuf;
+  while (remain) {
+    r= read(sfd,p,remain);
+    if (r<0) { syslog(LOG_ERR,"read from server: %m"); exit(1); }
+    if (r==0) { syslog(LOG_ERR,"unexpected EOF from server"); exit(1); }
+    remain-= r; p+= r;
+  }
+  if (opening_mbuf.magic != OPENING_MAGIC) {
+    syslog(LOG_NOTICE,"magic number mismatch");
+    exit(0);
+  }
+  if (memcmp(opening_mbuf.protocolchecksumversion,protocolchecksumversion,PCSUMSIZE)) {
+    syslog(LOG_NOTICE,"protocol checksum mismatch");
+    exit(0);
+  }
+  if (opening_mbuf.overlordpid != overlordpid) {
+    syslog(LOG_NOTICE,"overlord pid mismatch");
+    exit(0);
+  }
+  syslog(LOG_NOTICE,"check - same daemon still running");
+#endif
+  exit(1);
+}
+
 int main(int argc, char *const *argv) {
   int mfd, sfd, csocklen, e;
-  struct sigaction childact;
+  struct sigaction sigact;
   struct sockaddr_un ssockname, csockname;
   pid_t child;
 
@@ -124,11 +221,14 @@ int main(int argc, char *const *argv) {
 
   if (argc>1) { fputs("usage: uservd\n",stderr); exit(3); }
 
-  openlog(USERVD_LOGIDENT,LOG_NDELAY,USERVD_LOGFACILITY);
+  openlog(USERVD_LOGIDENT,LOG_NDELAY|LOG_PID,USERVD_LOGFACILITY);
 
   if (chdir(VARDIR)) { syslog(LOG_CRIT,"cannot change to " VARDIR ": %m"); exit(4); }
   checkstalepipes();
 
+  overlordpid= getpid();
+  if (overlordpid==-1) { syslog(LOG_CRIT,"cannot getpid: %m"); exit(4); }
+
   mfd= socket(AF_UNIX,SOCK_STREAM,0);
   if (mfd<0) { syslog(LOG_CRIT,"cannot create master socket: %m"); exit(4); }
 
@@ -141,13 +241,28 @@ int main(int argc, char *const *argv) {
   if (listen(mfd,5))
     { syslog(LOG_CRIT,"cannot listen on master socket: %m"); exit(4); }
 
-  childact.sa_handler= sighandler_chld;
-  sigemptyset(&childact.sa_mask);
-  childact.sa_flags= SA_NOCLDSTOP;
-  if (sigaction(SIGCHLD,&childact,0))
+  sigemptyset(&sigact.sa_mask);
+  sigaddset(&sigact.sa_mask,SIGCHLD);
+  sigaddset(&sigact.sa_mask,SIGALRM);
+  sigact.sa_flags= SA_NOCLDSTOP;
+
+  sigact.sa_handler= sighandler_chld;
+  if (sigaction(SIGCHLD,&sigact,0))
     { syslog(LOG_CRIT,"cannot setup sigchld handler: %m"); exit(4); }
+
+  sigact.sa_handler= sighandler_alrm;
+  if (sigaction(SIGALRM,&sigact,0))
+    { syslog(LOG_CRIT,"cannot setup sigalrm handler: %m"); exit(4); }
+
   syslog(LOG_NOTICE,"started");
   for (;;) {
+    if (needcheck) {
+      assert(checkpid==-1);
+      checkpid= fork();
+      if (checkpid==-1) { syslog(LOG_CRIT,"fork for check: %m"); exit(5); }
+      if (!checkpid) docheck();
+      needcheck= 0;
+    }
     csocklen= sizeof(csockname);
     blocksignals(SIG_UNBLOCK);
     sfd= accept(mfd,(struct sockaddr*)&csockname,&csocklen);
index c88c3c9bee277d2551f446f2fe7ad22889e2ab38..98bbeec6523bd73ffc966057b2f3e296e1a5dab8 100644 (file)
--- a/process.c
+++ b/process.c
@@ -399,6 +399,7 @@ static void send_opening(void) {
   memset(&opening_mbuf,0,sizeof(opening_mbuf));
   opening_mbuf.magic= OPENING_MAGIC;
   memcpy(opening_mbuf.protocolchecksumversion,protocolchecksumversion,PCSUMSIZE);
+  opening_mbuf.overlordpid= overlordpid;
   opening_mbuf.serverpid= mypid;
   xfwrite(&opening_mbuf,sizeof(opening_mbuf),swfile);
   xfflush(swfile);