10 /* Process handling - subprocesses, signals, etc. */
12 static bool_t signal_handling=False;
13 static sigset_t emptyset, fullset;
14 static sigset_t registered,pending;
19 process_callback_fn *cb;
25 static struct child *children=NULL;
29 signal_notify_fn *notify;
31 struct signotify *next;
34 static struct signotify *sigs=NULL;
36 static int spw,spr; /* file descriptors for signal notification pipe */
38 /* Long-lived subprocesses can only be started once we've started
39 signal processing so that we can catch SIGCHLD for them and report
40 their exit status using the callback function. We block SIGCHLD
41 until signal processing has begun. */
42 pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb,
43 void *est, void *cst, cstring_t desc)
48 c=safe_malloc(sizeof(*c),"makesubproc");
53 if (!signal_handling) {
54 fatal("makesubproc called before signal handling started");
63 fatal_perror("makesubproc (%s): fork",desc);
72 static signal_notify_fn sigchld_handler;
73 static void sigchld_handler(void *st, int signum)
75 struct child *i,*n,**p;
78 process_callback_fn *cb;
83 struct work *w=NULL, *nw;
87 for (i=children; i; i=i->next) {
88 rv=waitpid(i->pid,&status,WNOHANG);
90 fatal_perror("sigchld_handler: waitpid");
95 nw=safe_malloc(sizeof(*nw),"sigchld_handler");
105 /* Remove all the finished tasks from the list of children */
106 for (i=children, p=&children; i; i=n) {
116 /* Notify as appropriate, then free the list */
118 w->cb(w->cst,w->pid,w->status);
125 int sys_cmd(const char *path, const char *arg, ...)
133 /* Parent -> wait for child */
135 rc = waitpid(c,&rv,0);
136 } while(rc < 0 && errno == EINTR);
138 fatal_perror("sys_cmd: waitpid for %s", path);
139 if (rc != c) /* OS has gone mad */
140 fatal("sys_cmd: waitpid for %s returned wrong process ID!",
143 /* If the command failed report its exit status */
144 lg_exitstatus(0,"sys_cmd",0,M_ERR,rv,path);
149 /* Child -> exec command */
150 /* Really we ought to strcpy() the arguments into the args array,
151 since the arguments are const char *. Since we'll exit anyway
152 if the execvp() fails this seems somewhat pointless, and
153 increases the chance of the child process failing before it
157 args[0]=(char *)arg; /* program name */
159 while ((args[i++]=va_arg(ap,char *)));
161 fprintf(stderr, "sys_cmd(%s,%s,...): %s\n", path, arg, strerror(errno));
165 fatal_perror("sys_cmd(%s,%s,...)", path, arg);
171 static beforepoll_fn signal_beforepoll;
172 static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io,
175 BEFOREPOLL_WANT_FDS(1);
177 fds[0].events=POLLIN;
181 /* Bodge to work around Ubuntu's strict header files */
182 static void discard(int anything) {}
184 static afterpoll_fn signal_afterpoll;
185 static void signal_afterpoll(void *st, struct pollfd *fds, int nfds)
191 if (nfds && (fds->revents & POLLIN)) {
192 discard(read(spr,buf,16));
193 /* We don't actually care what we read; as
194 long as there was at least one byte
195 (which there was) we'll pick up the
196 signals in the pending set */
198 /* We reset 'pending' before processing any of the signals
199 that were pending so that we don't miss any signals that
200 are delivered partway-through processing (all we assume
201 about signal notification routines is that they handle all
202 the work available at their _start_ and only optionally any
203 work that arrives part-way through their execution). */
204 sigprocmask(SIG_SETMASK,&fullset,&old);
206 sigemptyset(&pending);
207 sigprocmask(SIG_SETMASK,&old,NULL);
209 for (n=sigs; n; n=n->next)
210 if (sigismember(&todo,n->signum))
211 n->notify(n->cst,n->signum);
222 for (n=sigs; n; n=n->next)
223 if (!sigismember(&done,n->signum)) {
224 sigaddset(&done,n->signum);
225 sa.sa_handler=SIG_DFL;
228 sigaction(n->signum,&sa,NULL);
231 sigemptyset(&emptyset);
232 sigprocmask(SIG_SETMASK,&emptyset,NULL);
235 static void signal_handler(int signum)
239 sigaddset(&pending,signum);
240 /* XXX the write() may set errno, which can make the main program fail.
241 However, signal handlers aren't allowed to modify anything which
242 is not of type sig_atomic_t. The world is broken. */
243 /* I have decided to save and restore errno anyway; on most
244 architectures on which secnet can run modifications to errno
245 will be atomic, and it seems to be the lesser of the two
248 discard(write(spw,&thing,1));
249 /* We don't care if this fails (i.e. the pipe
250 is full) because the service routine will
251 spot the pending signal anyway */
255 static void register_signal_handler(struct signotify *s)
260 if (!signal_handling) return;
262 if (sigismember(®istered,s->signum)) return;
263 sigaddset(®istered,s->signum);
265 sa.sa_handler=signal_handler;
268 rv=sigaction(s->signum,&sa,NULL);
270 fatal_perror("register_signal_handler: sigaction(%d)",s->signum);
274 void request_signal_notification(int signum, signal_notify_fn *notify,
280 s=safe_malloc(sizeof(*s),"request_signal_notification");
285 sigprocmask(SIG_SETMASK,&fullset,&old);
287 register_signal_handler(s);
288 sigprocmask(SIG_SETMASK,&old,NULL);
291 void start_signal_handling(void)
296 sigemptyset(&emptyset);
297 sigfillset(&fullset);
298 sigemptyset(®istered);
299 sigemptyset(&pending);
304 if (fcntl(spw, F_SETFL, fcntl(spw, F_GETFL)|O_NONBLOCK)==-1) {
305 fatal_perror("start_signal_handling: fcntl(O_NONBLOCK)");
308 register_for_poll(NULL,signal_beforepoll,signal_afterpoll,"signal");
309 signal_handling=True;
311 /* Register signal handlers for all the signals we're interested in */
312 for (i=sigs; i; i=i->next) {
313 register_signal_handler(i);
316 request_signal_notification(SIGCHLD,sigchld_handler,NULL);