From: ian Date: Sat, 11 Oct 1997 12:46:26 +0000 (+0000) Subject: Server checks itself every hour, and logs with pid. X-Git-Tag: release-0-56~1 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=userv.git;a=commitdiff_plain;h=2c8651e76d5629948778fb1b3d15ccc591d14da0 Server checks itself every hour, and logs with pid. --- diff --git a/Changelog b/Changelog index 71a09a4..7e9b975 100644 --- 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 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. diff --git a/common.h b/common.h index f73ea4d..ee243b1 100644 --- 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 { diff --git a/daemon.h b/daemon.h index 710d854..9efd982 100644 --- 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 @@ -102,6 +103,8 @@ 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 */ diff --git a/overlord.c b/overlord.c index 241bb0d..e32c9a1 100644 --- a/overlord.c +++ b/overlord.c @@ -39,6 +39,11 @@ #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); diff --git a/process.c b/process.c index c88c3c9..98bbeec 100644 --- 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);