8 /* Advice about children from Peter:
9 Better way: before the fork, make a pipe. In the child close the
10 +reading end. Make the writing end close-on-exec. If the dup2 or exec fails,
11 +write the errno value. In the parent, close the writing end. Now you can read
12 +from it. If you get an errno value from the pipe, the process failed and you
13 +know why. If you get EOF, the exec succeeded.
15 <Senji> So, close on exec only closes if exec isn't going to return then?
16 <Diziet> qu: I wouldn't bother with all that with pipes. Remember that the
17 +runtime system can still make exec fail when it's `too late'.
18 <Senji> Diz - I would rather have a coherant error message than 'child failed'
19 <Diziet> The child, if it fails to exec, should print a message to stderr
20 +(giving errno and what it was trying to execute, most likely), and exit
22 <Diziet> It should exit calling _exit.
25 /* Process handling - subprocesses, signals, etc. */
27 static bool_t signal_handling=False;
28 static sigset_t emptyset, fullset;
29 static sigset_t registered,pending;
34 process_callback_fn *cb;
40 static struct child *children=NULL;
44 signal_notify_fn *notify;
46 struct signotify *next;
49 static struct signotify *sigs=NULL;
51 static int spw,spr; /* file descriptors for signal notification pipe */
53 static void set_default_signals(void);
55 /* Long-lived subprocesses can only be started once we've started
56 signal processing so that we can catch SIGCHLD for them and report
57 their exit status using the callback function. We block SIGCHLD
58 until signal processing has begun. */
59 pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb,
60 void *est, void *cst, cstring_t desc)
65 c=safe_malloc(sizeof(*c),"makesubproc");
70 if (!signal_handling) {
71 fatal("makesubproc called before signal handling started");
76 set_default_signals();
77 sigprocmask(SIG_SETMASK,&emptyset,NULL);
81 fatal_perror("makesubproc (%s): fork",desc);
90 static signal_notify_fn sigchld_handler;
91 static void sigchld_handler(void *st, int signum)
93 struct child *i,*n,**p;
96 process_callback_fn *cb;
101 struct work *w=NULL, *nw;
105 for (i=children; i; i=i->next) {
106 rv=waitpid(i->pid,&status,WNOHANG);
108 fatal_perror("sigchld_handler: waitpid");
113 nw=safe_malloc(sizeof(*nw),"sigchld_handler");
123 /* Remove all the finished tasks from the list of children */
124 for (i=children, p=&children; i; i=n) {
134 /* Notify as appropriate, then free the list */
136 w->cb(w->cst,w->pid,w->status);
143 int sys_cmd(const char *path, const char *arg, ...)
152 /* Parent -> wait for child */
157 /* Child -> exec command */
158 /* Really we ought to strcpy() the arguments into the args array,
159 since the arguments are const char *. Since we'll exit anyway
160 if the execvp() fails this seems somewhat pointless, and
161 increases the chance of the child process failing before it
165 while ((args[i++]=va_arg(ap,char *)));
170 fatal_perror("sys_cmd(%s,%s,...)");
177 static beforepoll_fn signal_beforepoll;
178 static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io,
179 int *timeout_io, const struct timeval *tv_now,
188 fds[0].events=POLLIN;
192 /* Bodge to work around Ubuntu's strict header files */
193 static void discard(int anything) {}
195 static afterpoll_fn signal_afterpoll;
196 static void signal_afterpoll(void *st, struct pollfd *fds, int nfds,
197 const struct timeval *tv, uint64_t *now)
203 if (nfds && (fds->revents & POLLIN)) {
204 discard(read(spr,buf,16));
205 /* We don't actually care what we read; as
206 long as there was at least one byte
207 (which there was) we'll pick up the
208 signals in the pending set */
210 /* We reset 'pending' before processing any of the signals
211 that were pending so that we don't miss any signals that
212 are delivered partway-through processing (all we assume
213 about signal notification routines is that they handle all
214 the work available at their _start_ and only optionally any
215 work that arrives part-way through their execution). */
216 sigprocmask(SIG_SETMASK,&fullset,&old);
218 sigemptyset(&pending);
219 sigprocmask(SIG_SETMASK,&old,NULL);
221 for (n=sigs; n; n=n->next)
222 if (sigismember(&todo,n->signum))
223 n->notify(n->cst,n->signum);
227 static void set_default_signals(void)
234 for (n=sigs; n; n=n->next)
235 if (!sigismember(&done,n->signum)) {
236 sigaddset(&done,n->signum);
237 sa.sa_handler=SIG_DFL;
240 sigaction(n->signum,&sa,NULL);
244 static void signal_handler(int signum)
248 sigaddset(&pending,signum);
249 /* XXX the write() may set errno, which can make the main program fail.
250 However, signal handlers aren't allowed to modify anything which
251 is not of type sig_atomic_t. The world is broken. */
252 /* I have decided to save and restore errno anyway; on most
253 architectures on which secnet can run modifications to errno
254 will be atomic, and it seems to be the lesser of the two
257 discard(write(spw,&thing,1));
258 /* We don't care if this fails (i.e. the pipe
259 is full) because the service routine will
260 spot the pending signal anyway */
264 static void register_signal_handler(struct signotify *s)
269 if (!signal_handling) return;
271 if (sigismember(®istered,s->signum)) return;
272 sigaddset(®istered,s->signum);
274 sa.sa_handler=signal_handler;
277 rv=sigaction(s->signum,&sa,NULL);
279 fatal_perror("register_signal_handler: sigaction(%d)",s->signum);
283 void request_signal_notification(int signum, signal_notify_fn *notify,
289 s=safe_malloc(sizeof(*s),"request_signal_notification");
294 sigprocmask(SIG_SETMASK,&fullset,&old);
296 register_signal_handler(s);
297 sigprocmask(SIG_SETMASK,&old,NULL);
300 void start_signal_handling(void)
305 sigemptyset(&emptyset);
306 sigfillset(&fullset);
307 sigemptyset(®istered);
308 sigemptyset(&pending);
311 fatal_perror("start_signal_handling: pipe");
315 if (fcntl(spw, F_SETFL, fcntl(spw, F_GETFL)|O_NONBLOCK)==-1) {
316 fatal_perror("start_signal_handling: fcntl(O_NONBLOCK)");
319 register_for_poll(NULL,signal_beforepoll,signal_afterpoll,1,"signal");
320 signal_handling=True;
322 /* Register signal handlers for all the signals we're interested in */
323 for (i=sigs; i; i=i->next) {
324 register_signal_handler(i);
327 request_signal_notification(SIGCHLD,sigchld_handler,NULL);