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>
42 static void checkstalepipes(void) {
43 /* There is an unimportant race here. If there is a stale pipe but
44 * another pair of processes with the same pids is about to create a
45 * new one we can check that the pipe is stale before they recreate
46 * it but then only remove it afterwards; then we remove the pipe
47 * they're actually using causing that invocation to fail with
48 * ENOENT on the pipe. However, this can only happen if things are
49 * already shafted, because we check for stale pipes at startup
50 * before any children have been started, and then only when a child
51 * dies unhelpfully - and we actually have to have some stale pipes
52 * for the race to exist.
58 unsigned long timediff;
61 if (time(&now) == -1) { syslog(LOG_ERR,"get current time: %m"); return; }
63 if (!dir) { syslog(LOG_ERR,"open directory " VARDIR ": %m"); return; }
64 while ((de= readdir(dir))) {
65 if (fnmatch(PIPEPATTERN,de->d_name,FNM_PATHNAME|FNM_PERIOD)) continue;
66 r= lstat(de->d_name,&stab); if (r && errno==ENOENT) continue;
67 if (r) { syslog(LOG_ERR,"could not stat `" VARDIR "/%s': %m",de->d_name); continue; }
68 timediff= (unsigned long)now - (unsigned long)stab.st_ctime;
69 if (timediff >= (~0UL>>1) || timediff < 3600) continue;
70 if (unlink(de->d_name) && errno!=ENOENT)
71 syslog(LOG_ERR,"could not remove stale pipe `%s': %m",de->d_name);
73 if (closedir(dir)) syslog(LOG_ERR,"close directory " VARDIR ": %m");
76 static void sighandler_chld(int x) {
82 r= waitpid((pid_t)-1,&status,WNOHANG);
83 if (!r || (r==-1 && errno==ECHILD)) break;
84 if (r==-1) { syslog(LOG_ERR,"wait in sigchild handler gave error: %m"); break; }
85 if (WIFSIGNALED(status)) {
86 if (WCOREDUMP(status))
87 syslog(LOG_ERR,"call pid %ld dumped core due to signal %s",(long)r,
88 strsignal(WTERMSIG(status)));
90 syslog(LOG_ERR,"call pid %ld died due to signal %s",
91 (long)r,strsignal(WTERMSIG(status)));
92 } else if (!WIFEXITED(status)) {
93 syslog(LOG_ERR,"call pid %ld died due to unknown reason, code %ld",
95 } else if (WEXITSTATUS(status)>12) {
96 if (WEXITSTATUS(status)>24)
97 syslog(LOG_ERR,"call pid %ld exited with status %ld >24",
98 (long)r,WEXITSTATUS(status));
106 static void blocksignals(int how) {
111 sigaddset(&set,SIGCHLD);
112 r= sigprocmask(how,&set,0); assert(!r);
115 int main(int argc, char *const *argv) {
116 int mfd, sfd, csocklen, e;
117 struct sigaction childact;
118 struct sockaddr_un ssockname, csockname;
122 abort(); /* Do not disable assertions in this security-critical code ! */
125 if (argc>1) { fputs("usage: uservd\n",stderr); exit(3); }
127 openlog(USERVD_LOGIDENT,LOG_NDELAY,USERVD_LOGFACILITY);
129 if (chdir(VARDIR)) { syslog(LOG_CRIT,"cannot change to " VARDIR ": %m"); exit(4); }
132 mfd= socket(AF_UNIX,SOCK_STREAM,0);
133 if (mfd<0) { syslog(LOG_CRIT,"cannot create master socket: %m"); exit(4); }
135 assert(sizeof(ssockname.sun_path) > sizeof(RENDEZVOUS));
136 ssockname.sun_family= AF_UNIX;
137 strcpy(ssockname.sun_path,RENDEZVOUS);
139 if (bind(mfd,(struct sockaddr*)&ssockname,sizeof(ssockname)))
140 { syslog(LOG_CRIT,"cannot bind master socket: %m"); exit(4); }
142 { syslog(LOG_CRIT,"cannot listen on master socket: %m"); exit(4); }
144 childact.sa_handler= sighandler_chld;
145 sigemptyset(&childact.sa_mask);
146 childact.sa_flags= SA_NOCLDSTOP;
147 if (sigaction(SIGCHLD,&childact,0))
148 { syslog(LOG_CRIT,"cannot setup sigchld handler: %m"); exit(4); }
149 syslog(LOG_NOTICE,"started");
151 csocklen= sizeof(csockname);
152 blocksignals(SIG_UNBLOCK);
153 sfd= accept(mfd,(struct sockaddr*)&csockname,&csocklen);
155 blocksignals(SIG_BLOCK);
158 if (errno == EINTR) continue;
159 if (errno == ENOMEM || errno == EPROTO || errno == EAGAIN) {
160 syslog(LOG_ERR,"unable to accept connection: %m");
163 syslog(LOG_CRIT,"unable to accept new connections: %m");
167 child= nondebug_fork();
168 if (child == (pid_t)-1) {
169 syslog(LOG_ERR,"unable to fork server: %m");
176 blocksignals(SIG_UNBLOCK);