event loop: remove now and tv_now from before/afterpoll API
[secnet] / process.c
1 #include "secnet.h"
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <errno.h>
5 #include <sys/wait.h>
6 #include "process.h"
7
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.
14
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
21 +nonzero.
22 <Diziet> It should exit calling _exit.
23 */
24
25 /* Process handling - subprocesses, signals, etc. */
26
27 static bool_t signal_handling=False;
28 static sigset_t emptyset, fullset;
29 static sigset_t registered,pending;
30
31 struct child {
32 pid_t pid;
33 cstring_t desc;
34 process_callback_fn *cb;
35 void *cst;
36 bool_t finished;
37 struct child *next;
38 };
39
40 static struct child *children=NULL;
41
42 struct signotify {
43 int signum;
44 signal_notify_fn *notify;
45 void *cst;
46 struct signotify *next;
47 };
48
49 static struct signotify *sigs=NULL;
50
51 static int spw,spr; /* file descriptors for signal notification pipe */
52
53 static void set_default_signals(void);
54
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)
61 {
62 struct child *c;
63 pid_t p;
64
65 c=safe_malloc(sizeof(*c),"makesubproc");
66 c->desc=desc;
67 c->cb=cb;
68 c->cst=cst;
69
70 if (!signal_handling) {
71 fatal("makesubproc called before signal handling started");
72 }
73 p=fork();
74 if (p==0) {
75 /* Child process */
76 set_default_signals();
77 sigprocmask(SIG_SETMASK,&emptyset,NULL);
78 entry(est);
79 abort();
80 } else if (p==-1) {
81 fatal_perror("makesubproc (%s): fork",desc);
82 }
83 c->pid=p;
84 c->finished=False;
85 c->next=children;
86 children=c;
87 return p;
88 }
89
90 static signal_notify_fn sigchld_handler;
91 static void sigchld_handler(void *st, int signum)
92 {
93 struct child *i,*n,**p;
94 struct work {
95 pid_t pid;
96 process_callback_fn *cb;
97 void *cst;
98 int status;
99 struct work *next;
100 };
101 struct work *w=NULL, *nw;
102 pid_t rv;
103 int status;
104
105 for (i=children; i; i=i->next) {
106 rv=waitpid(i->pid,&status,WNOHANG);
107 if (rv==-1) {
108 fatal_perror("sigchld_handler: waitpid");
109 }
110 if (rv==i->pid) {
111 i->finished=True;
112
113 nw=safe_malloc(sizeof(*nw),"sigchld_handler");
114 nw->pid=i->pid;
115 nw->cb=i->cb;
116 nw->cst=i->cst;
117 nw->status=status;
118 nw->next=w;
119 w=nw;
120 }
121 }
122
123 /* Remove all the finished tasks from the list of children */
124 for (i=children, p=&children; i; i=n) {
125 n=i->next;
126 if (i->finished) {
127 free(i);
128 *p=n;
129 } else {
130 p=&i->next;
131 }
132 }
133
134 /* Notify as appropriate, then free the list */
135 while (w) {
136 w->cb(w->cst,w->pid,w->status);
137 nw=w;
138 w=w->next;
139 free(nw);
140 }
141 }
142
143 int sys_cmd(const char *path, const char *arg, ...)
144 {
145 va_list ap;
146 int rv;
147 pid_t c;
148
149 va_start(ap,arg);
150 c=fork();
151 if (c) {
152 /* Parent -> wait for child */
153 waitpid(c,&rv,0);
154 } else if (c==0) {
155 char *args[100];
156 int i;
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
162 gets to exec(). */
163 args[0]=(char *)arg;
164 i=1;
165 while ((args[i++]=va_arg(ap,char *)));
166 execvp(path,args);
167 exit(1);
168 } else {
169 /* Error */
170 fatal_perror("sys_cmd(%s,%s,...)");
171 }
172
173 va_end(ap);
174 return rv;
175 }
176
177 static beforepoll_fn signal_beforepoll;
178 static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io,
179 int *timeout_io)
180 {
181 if (*nfds_io<1) {
182 *nfds_io=1;
183 return ERANGE;
184 }
185 *nfds_io=1;
186 fds[0].fd=spr;
187 fds[0].events=POLLIN;
188 return 0;
189 }
190
191 static afterpoll_fn signal_afterpoll;
192 static void signal_afterpoll(void *st, struct pollfd *fds, int nfds)
193 {
194 uint8_t buf[16];
195 struct signotify *n;
196 sigset_t todo,old;
197
198 if (nfds && (fds->revents & POLLIN)) {
199 read(spr,buf,16); /* We don't actually care what we read; as
200 long as there was at least one byte
201 (which there was) we'll pick up the
202 signals in the pending set */
203
204 /* We reset 'pending' before processing any of the signals
205 that were pending so that we don't miss any signals that
206 are delivered partway-through processing (all we assume
207 about signal notification routines is that they handle all
208 the work available at their _start_ and only optionally any
209 work that arrives part-way through their execution). */
210 sigprocmask(SIG_SETMASK,&fullset,&old);
211 todo=pending;
212 sigemptyset(&pending);
213 sigprocmask(SIG_SETMASK,&old,NULL);
214
215 for (n=sigs; n; n=n->next)
216 if (sigismember(&todo,n->signum))
217 n->notify(n->cst,n->signum);
218 }
219 }
220
221 static void set_default_signals(void)
222 {
223 struct signotify *n;
224 sigset_t done;
225 struct sigaction sa;
226
227 sigemptyset(&done);
228 for (n=sigs; n; n=n->next)
229 if (!sigismember(&done,n->signum)) {
230 sigaddset(&done,n->signum);
231 sa.sa_handler=SIG_DFL;
232 sa.sa_mask=emptyset;
233 sa.sa_flags=0;
234 sigaction(n->signum,&sa,NULL);
235 }
236 }
237
238 static void signal_handler(int signum)
239 {
240 int saved_errno;
241 uint8_t thing=0;
242 sigaddset(&pending,signum);
243 /* XXX the write() may set errno, which can make the main program fail.
244 However, signal handlers aren't allowed to modify anything which
245 is not of type sig_atomic_t. The world is broken. */
246 /* I have decided to save and restore errno anyway; on most
247 architectures on which secnet can run modifications to errno
248 will be atomic, and it seems to be the lesser of the two
249 evils. */
250 saved_errno=errno;
251 write(spw,&thing,1); /* We don't care if this fails (i.e. the pipe
252 is full) because the service routine will
253 spot the pending signal anyway */
254 errno=saved_errno;
255 }
256
257 static void register_signal_handler(struct signotify *s)
258 {
259 struct sigaction sa;
260 int rv;
261
262 if (!signal_handling) return;
263
264 if (sigismember(&registered,s->signum)) return;
265 sigaddset(&registered,s->signum);
266
267 sa.sa_handler=signal_handler;
268 sa.sa_mask=fullset;
269 sa.sa_flags=0;
270 rv=sigaction(s->signum,&sa,NULL);
271 if (rv!=0) {
272 fatal_perror("register_signal_handler: sigaction(%d)",s->signum);
273 }
274 }
275
276 void request_signal_notification(int signum, signal_notify_fn *notify,
277 void *cst)
278 {
279 struct signotify *s;
280 sigset_t old;
281
282 s=safe_malloc(sizeof(*s),"request_signal_notification");
283 s->signum=signum;
284 s->notify=notify;
285 s->cst=cst;
286 s->next=sigs;
287 sigprocmask(SIG_SETMASK,&fullset,&old);
288 sigs=s;
289 register_signal_handler(s);
290 sigprocmask(SIG_SETMASK,&old,NULL);
291 }
292
293 void start_signal_handling(void)
294 {
295 int p[2];
296 struct signotify *i;
297
298 sigemptyset(&emptyset);
299 sigfillset(&fullset);
300 sigemptyset(&registered);
301 sigemptyset(&pending);
302
303 if (pipe(p)!=0) {
304 fatal_perror("start_signal_handling: pipe");
305 }
306 spw=p[1];
307 spr=p[0];
308 if (fcntl(spw, F_SETFL, fcntl(spw, F_GETFL)|O_NONBLOCK)==-1) {
309 fatal_perror("start_signal_handling: fcntl(O_NONBLOCK)");
310 }
311
312 register_for_poll(NULL,signal_beforepoll,signal_afterpoll,1,"signal");
313 signal_handling=True;
314
315 /* Register signal handlers for all the signals we're interested in */
316 for (i=sigs; i; i=i->next) {
317 register_signal_handler(i);
318 }
319
320 request_signal_notification(SIGCHLD,sigchld_handler,NULL);
321 }