Import release 0.1.14
[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 string_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, string_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, 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 args[0]=arg;
159 i=1;
160 while ((args[i++]=va_arg(ap,char *)));
161 execvp(path,args);
162 exit(1);
163 } else {
164 /* Error */
165 fatal_perror("sys_cmd(%s,%s,...)");
166 }
167
168 va_end(ap);
169 return rv;
170 }
171
172 static beforepoll_fn signal_beforepoll;
173 static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io,
174 int *timeout_io, const struct timeval *tv_now,
175 uint64_t *now)
176 {
177 if (*nfds_io<1) {
178 *nfds_io=1;
179 return ERANGE;
180 }
181 *nfds_io=1;
182 fds[0].fd=spr;
183 fds[0].events=POLLIN;
184 return 0;
185 }
186
187 static afterpoll_fn signal_afterpoll;
188 static void signal_afterpoll(void *st, struct pollfd *fds, int nfds,
189 const struct timeval *tv, uint64_t *now)
190 {
191 uint8_t buf[16];
192 struct signotify *n;
193 sigset_t todo,old;
194
195 if (nfds && (fds->revents & POLLIN)) {
196 read(spr,buf,16); /* We don't actually care what we read; as
197 long as there was at least one byte
198 (which there was) we'll pick up the
199 signals in the pending set */
200
201 /* We reset 'pending' before processing any of the signals
202 that were pending so that we don't miss any signals that
203 are delivered partway-through processing (all we assume
204 about signal notification routines is that they handle all
205 the work available at their _start_ and only optionally any
206 work that arrives part-way through their execution). */
207 sigprocmask(SIG_SETMASK,&fullset,&old);
208 todo=pending;
209 sigemptyset(&pending);
210 sigprocmask(SIG_SETMASK,&old,NULL);
211
212 for (n=sigs; n; n=n->next)
213 if (sigismember(&todo,n->signum))
214 n->notify(n->cst,n->signum);
215 }
216 }
217
218 static void set_default_signals(void)
219 {
220 struct signotify *n;
221 sigset_t done;
222 struct sigaction sa;
223
224 sigemptyset(&done);
225 for (n=sigs; n; n=n->next)
226 if (!sigismember(&done,n->signum)) {
227 sigaddset(&done,n->signum);
228 sa.sa_handler=SIG_DFL;
229 sa.sa_mask=emptyset;
230 sa.sa_flags=0;
231 sigaction(n->signum,&sa,NULL);
232 }
233 }
234
235 static void signal_handler(int signum)
236 {
237 int saved_errno;
238 uint8_t thing=0;
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
246 evils. */
247 saved_errno=errno;
248 write(spw,&thing,1); /* We don't care if this fails (i.e. the pipe
249 is full) because the service routine will
250 spot the pending signal anyway */
251 errno=saved_errno;
252 }
253
254 static void register_signal_handler(struct signotify *s)
255 {
256 struct sigaction sa;
257 int rv;
258
259 if (!signal_handling) return;
260
261 if (sigismember(&registered,s->signum)) return;
262 sigaddset(&registered,s->signum);
263
264 sa.sa_handler=signal_handler;
265 sa.sa_mask=fullset;
266 sa.sa_flags=0;
267 rv=sigaction(s->signum,&sa,NULL);
268 if (rv!=0) {
269 fatal_perror("register_signal_handler: sigaction(%d)",s->signum);
270 }
271 }
272
273 void request_signal_notification(int signum, signal_notify_fn *notify,
274 void *cst)
275 {
276 struct signotify *s;
277 sigset_t old;
278
279 s=safe_malloc(sizeof(*s),"request_signal_notification");
280 s->signum=signum;
281 s->notify=notify;
282 s->cst=cst;
283 s->next=sigs;
284 sigprocmask(SIG_SETMASK,&fullset,&old);
285 sigs=s;
286 register_signal_handler(s);
287 sigprocmask(SIG_SETMASK,&old,NULL);
288 }
289
290 void start_signal_handling(void)
291 {
292 int p[2];
293 struct signotify *i;
294
295 sigemptyset(&emptyset);
296 sigfillset(&fullset);
297 sigemptyset(&registered);
298 sigemptyset(&pending);
299
300 if (pipe(p)!=0) {
301 fatal_perror("start_signal_handling: pipe");
302 }
303 spw=p[1];
304 spr=p[0];
305 if (fcntl(spw, F_SETFL, fcntl(spw, F_GETFL)|O_NONBLOCK)==-1) {
306 fatal_perror("start_signal_handling: fcntl(O_NONBLOCK)");
307 }
308
309 register_for_poll(NULL,signal_beforepoll,signal_afterpoll,1,"signal");
310 signal_handling=True;
311
312 /* Register signal handlers for all the signals we're interested in */
313 for (i=sigs; i; i=i->next) {
314 register_signal_handler(i);
315 }
316
317 request_signal_notification(SIGCHLD,sigchld_handler,NULL);
318 }