3 * daemon main program, collects request and forks handlers
5 * Copyright (C)1996-1997 Ian Jackson
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with userv; if not, write to the Free Software
19 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include <sys/types.h>
34 #include <sys/socket.h>
44 static pid_t checkpid= -1;
45 static sig_atomic_t needcheck= 1;
47 static void checkstalepipes(void) {
48 /* There is an unimportant race here. If there is a stale pipe but
49 * another pair of processes with the same pids is about to create a
50 * new one we can check that the pipe is stale before they recreate
51 * it but then only remove it afterwards; then we remove the pipe
52 * they're actually using causing that invocation to fail with
53 * ENOENT on the pipe. However, this can only happen if things are
54 * already shafted, because we check for stale pipes at startup
55 * before any children have been started, and then only when a child
56 * dies unhelpfully - and we actually have to have some stale pipes
57 * for the race to exist.
63 unsigned long timediff;
66 if (time(&now) == -1) { syslog(LOG_ERR,"get current time: %m"); return; }
68 if (!dir) { syslog(LOG_ERR,"open directory " VARDIR ": %m"); return; }
69 while ((de= readdir(dir))) {
70 if (fnmatch(PIPEPATTERN,de->d_name,FNM_PATHNAME|FNM_PERIOD)) continue;
71 r= lstat(de->d_name,&stab); if (r && errno==ENOENT) continue;
72 if (r) { syslog(LOG_ERR,"could not stat `" VARDIR "/%s': %m",de->d_name); continue; }
73 timediff= (unsigned long)now - (unsigned long)stab.st_ctime;
74 if (timediff >= (~0UL>>1) || timediff < 3600) continue;
75 if (unlink(de->d_name) && errno!=ENOENT)
76 syslog(LOG_ERR,"could not remove stale pipe `%s': %m",de->d_name);
78 if (closedir(dir)) syslog(LOG_ERR,"close directory " VARDIR ": %m");
81 static void sighandler_chld(int x) {
87 r= waitpid((pid_t)-1,&status,WNOHANG);
88 if (!r || (r==-1 && errno==ECHILD)) break;
89 if (r==-1) { syslog(LOG_ERR,"wait in sigchild handler gave error: %m"); break; }
91 if (WIFEXITED(status)) {
92 if (!WEXITSTATUS(status)) {
93 syslog(LOG_NOTICE,"no longer the uservd - exiting");
95 } else if (WEXITSTATUS(status)!=1) {
96 syslog(LOG_ERR,"check pid %ld exited with status %d",
97 (long)checkpid,WEXITSTATUS(status));
99 } else if (WIFSIGNALED(status)) {
100 if (WTERMSIG(status) == SIGALRM && !WCOREDUMP(status)) {
101 syslog(LOG_NOTICE,"check timed out; no longer the uservd - exiting");
104 syslog(LOG_ERR,"check pid %ld %s due to signal %s",
106 WCOREDUMP(status) ? "dumped core" : "died",
107 strsignal(WTERMSIG(status)));
110 syslog(LOG_ERR,"check pid %ld died due to unknown reason, code %d",
111 (long)checkpid,status);
114 ar= alarm(USERVD_MYSELF_CHECK);
115 if (ar<0) { syslog(LOG_CRIT,"set alarm for next check: %m"); exit(5); }
117 if (WIFSIGNALED(status)) {
118 syslog(LOG_ERR,"call pid %ld %s due to signal %s",
120 WCOREDUMP(status) ? "dumped core" : "died",
121 strsignal(WTERMSIG(status)));
122 } else if (!WIFEXITED(status)) {
123 syslog(LOG_ERR,"call pid %ld died due to unknown reason, code %d",
125 } else if (WEXITSTATUS(status)>12) {
126 if (WEXITSTATUS(status)>24)
127 syslog(LOG_ERR,"call pid %ld exited with status %d >24",
128 (long)r,WEXITSTATUS(status));
137 static void sighandler_alrm(int x) {
141 static void blocksignals(int how) {
146 sigaddset(&set,SIGCHLD);
147 sigaddset(&set,SIGALRM);
148 r= sigprocmask(how,&set,0); assert(!r);
151 static void NONRETURNING docheck(void) {
153 /* This subprocess exits with status 0 if the parent should die,
154 * 1 if it should not, and something else if it fails horribly.
158 struct opening_msg opening_mbuf;
159 struct sigaction sig;
160 struct sockaddr_un ssockname;
162 openlog(USERVDCHECK_LOGIDENT,LOG_NDELAY|LOG_PID,USERVD_LOGFACILITY);
164 sigemptyset(&sig.sa_mask);
166 sig.sa_handler= SIG_IGN;
167 if (sigaction(SIGPIPE,&sig,0)) { syslog(LOG_ERR,"ignore sigpipe"); exit(1); }
169 sig.sa_handler= SIG_DFL;
170 if (sigaction(SIGALRM,&sig,0)) { syslog(LOG_ERR,"default sigalarm"); exit(1); }
172 sfd= socket(AF_UNIX,SOCK_STREAM,0);
173 if (!sfd) { syslog(LOG_ERR,"ignore sigpipe"); exit(1); }
175 assert(sizeof(ssockname.sun_path) > sizeof(RENDEZVOUS));
176 ssockname.sun_family= AF_UNIX;
177 strcpy(ssockname.sun_path,RENDEZVOUS);
179 r= connect(sfd,(struct sockaddr*)&ssockname,sizeof(ssockname));
181 if (errno == ECONNREFUSED || errno == ENOENT)
182 { syslog(LOG_NOTICE,"uservd daemon is not running: %m"); exit(0); }
183 syslog(LOG_ERR,"unable to connect to uservd daemon: %m"); exit(1);
186 r= alarm(USERVD_MYSELF_TIMEOUT);
187 if (r<0) { syslog(LOG_ERR,"set alarm for read: %m"); exit(1); }
188 remain= sizeof(opening_mbuf); p= (unsigned char*)&opening_mbuf;
190 r= read(sfd,p,remain);
191 if (r<0) { syslog(LOG_ERR,"read from server: %m"); exit(1); }
192 if (r==0) { syslog(LOG_ERR,"unexpected EOF from server"); exit(1); }
195 if (opening_mbuf.magic != OPENING_MAGIC) {
196 syslog(LOG_NOTICE,"magic number mismatch");
199 if (memcmp(opening_mbuf.protocolchecksumversion,protocolchecksumversion,PCSUMSIZE)) {
200 syslog(LOG_NOTICE,"protocol checksum mismatch");
203 if (opening_mbuf.overlordpid != overlordpid) {
204 syslog(LOG_NOTICE,"overlord pid mismatch");
207 syslog(LOG_NOTICE,"check - same daemon still running");
212 int main(int argc, char *const *argv) {
213 int mfd, sfd, csocklen, e;
214 struct sigaction sigact;
215 struct sockaddr_un ssockname, csockname;
219 abort(); /* Do not disable assertions in this security-critical code ! */
222 if (argc>1) { fputs("usage: uservd\n",stderr); exit(3); }
224 openlog(USERVD_LOGIDENT,LOG_NDELAY|LOG_PID,USERVD_LOGFACILITY);
226 if (chdir(VARDIR)) { syslog(LOG_CRIT,"cannot change to " VARDIR ": %m"); exit(4); }
229 overlordpid= getpid();
230 if (overlordpid==-1) { syslog(LOG_CRIT,"cannot getpid: %m"); exit(4); }
232 mfd= socket(AF_UNIX,SOCK_STREAM,0);
233 if (mfd<0) { syslog(LOG_CRIT,"cannot create master socket: %m"); exit(4); }
235 assert(sizeof(ssockname.sun_path) > sizeof(RENDEZVOUS));
236 ssockname.sun_family= AF_UNIX;
237 strcpy(ssockname.sun_path,RENDEZVOUS);
239 if (bind(mfd,(struct sockaddr*)&ssockname,sizeof(ssockname)))
240 { syslog(LOG_CRIT,"cannot bind master socket: %m"); exit(4); }
242 { syslog(LOG_CRIT,"cannot listen on master socket: %m"); exit(4); }
244 sigemptyset(&sigact.sa_mask);
245 sigaddset(&sigact.sa_mask,SIGCHLD);
246 sigaddset(&sigact.sa_mask,SIGALRM);
247 sigact.sa_flags= SA_NOCLDSTOP;
249 sigact.sa_handler= sighandler_chld;
250 if (sigaction(SIGCHLD,&sigact,0))
251 { syslog(LOG_CRIT,"cannot setup sigchld handler: %m"); exit(4); }
253 sigact.sa_handler= sighandler_alrm;
254 if (sigaction(SIGALRM,&sigact,0))
255 { syslog(LOG_CRIT,"cannot setup sigalrm handler: %m"); exit(4); }
257 syslog(LOG_NOTICE,"started");
260 assert(checkpid==-1);
262 if (checkpid==-1) { syslog(LOG_CRIT,"fork for check: %m"); exit(5); }
263 if (!checkpid) docheck();
266 csocklen= sizeof(csockname);
267 blocksignals(SIG_UNBLOCK);
268 sfd= accept(mfd,(struct sockaddr*)&csockname,&csocklen);
270 blocksignals(SIG_BLOCK);
273 if (errno == EINTR) continue;
274 if (errno == ENOMEM || errno == EPROTO || errno == EAGAIN) {
275 syslog(LOG_ERR,"unable to accept connection: %m");
278 syslog(LOG_CRIT,"unable to accept new connections: %m");
282 child= nondebug_fork();
283 if (child == (pid_t)-1) {
284 syslog(LOG_ERR,"unable to fork server: %m");
291 blocksignals(SIG_UNBLOCK);