Makefile.in: Drop dist target
[secnet] / process.c
1 /*
2 * This file is part of secnet.
3 * See README for full list of copyright holders.
4 *
5 * secnet is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * secnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * version 3 along with secnet; if not, see
17 * https://www.gnu.org/licenses/gpl.html.
18 */
19
20 #define _GNU_SOURCE
21 #include "secnet.h"
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <sys/wait.h>
26 #include <string.h>
27 #include "process.h"
28
29 /* Process handling - subprocesses, signals, etc. */
30
31 static bool_t signal_handling=False;
32 static sigset_t emptyset, fullset;
33 static sigset_t registered,pending;
34
35 struct child {
36 pid_t pid;
37 cstring_t desc;
38 process_callback_fn *cb;
39 void *cst;
40 bool_t finished;
41 struct child *next;
42 };
43
44 static struct child *children=NULL;
45
46 struct signotify {
47 int signum;
48 signal_notify_fn *notify;
49 void *cst;
50 struct signotify *next;
51 };
52
53 static struct signotify *sigs=NULL;
54
55 static int spw,spr; /* file descriptors for signal notification pipe */
56
57 /* Long-lived subprocesses can only be started once we've started
58 signal processing so that we can catch SIGCHLD for them and report
59 their exit status using the callback function. We block SIGCHLD
60 until signal processing has begun. */
61 pid_t makesubproc(process_entry_fn *entry, process_callback_fn *cb,
62 void *est, void *cst, cstring_t desc)
63 {
64 struct child *c;
65 pid_t p;
66
67 NEW(c);
68 c->desc=desc;
69 c->cb=cb;
70 c->cst=cst;
71
72 if (!signal_handling) {
73 fatal("makesubproc called before signal handling started");
74 }
75 p=fork();
76 if (p==0) {
77 /* Child process */
78 afterfork();
79 entry(est);
80 abort();
81 } else if (p==-1) {
82 fatal_perror("makesubproc (%s): fork",desc);
83 }
84 c->pid=p;
85 c->finished=False;
86 c->next=children;
87 children=c;
88 return p;
89 }
90
91 static signal_notify_fn sigchld_handler;
92 static void sigchld_handler(void *st, int signum)
93 {
94 struct child *i,*n,**p;
95 struct work {
96 pid_t pid;
97 process_callback_fn *cb;
98 void *cst;
99 int status;
100 struct work *next;
101 };
102 struct work *w=NULL, *nw;
103 pid_t rv;
104 int status;
105
106 for (i=children; i; i=i->next) {
107 rv=waitpid(i->pid,&status,WNOHANG);
108 if (rv==-1) {
109 fatal_perror("sigchld_handler: waitpid");
110 }
111 if (rv==i->pid) {
112 i->finished=True;
113
114 NEW(nw);
115 nw->pid=i->pid;
116 nw->cb=i->cb;
117 nw->cst=i->cst;
118 nw->status=status;
119 nw->next=w;
120 w=nw;
121 }
122 }
123
124 /* Remove all the finished tasks from the list of children */
125 for (i=children, p=&children; i; i=n) {
126 n=i->next;
127 if (i->finished) {
128 free(i);
129 *p=n;
130 } else {
131 p=&i->next;
132 }
133 }
134
135 /* Notify as appropriate, then free the list */
136 while (w) {
137 w->cb(w->cst,w->pid,w->status);
138 nw=w;
139 w=w->next;
140 free(nw);
141 }
142 }
143
144 int sys_cmd(const char *path, const char *arg, ...)
145 {
146 va_list ap;
147 int rv, rc;
148 pid_t c;
149
150 c=fork();
151 if (c) {
152 /* Parent -> wait for child */
153 do {
154 rc = waitpid(c,&rv,0);
155 } while(rc < 0 && errno == EINTR);
156 if (rc < 0)
157 fatal_perror("sys_cmd: waitpid for %s", path);
158 if (rc != c) /* OS has gone mad */
159 fatal("sys_cmd: waitpid for %s returned wrong process ID!",
160 path);
161 if (rv) {
162 /* If the command failed report its exit status */
163 lg_exitstatus(0,"sys_cmd",0,M_ERR,rv,path);
164 }
165 } else if (c==0) {
166 char *args[100];
167 int i;
168 /* Child -> exec command */
169 /* Really we ought to strcpy() the arguments into the args array,
170 since the arguments are const char *. Since we'll exit anyway
171 if the execvp() fails this seems somewhat pointless, and
172 increases the chance of the child process failing before it
173 gets to exec(). */
174 afterfork();
175 va_start(ap,arg);
176 args[0]=(char *)arg; /* program name */
177 i=1;
178 while ((args[i++]=va_arg(ap,char *)));
179 execvp(path,args);
180 fprintf(stderr, "sys_cmd(%s,%s,...): %s\n", path, arg, strerror(errno));
181 _exit(1);
182 } else {
183 /* Error */
184 fatal_perror("sys_cmd(%s,%s,...)", path, arg);
185 }
186
187 return rv;
188 }
189
190 static beforepoll_fn signal_beforepoll;
191 static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io,
192 int *timeout_io)
193 {
194 BEFOREPOLL_WANT_FDS(1);
195 fds[0].fd=spr;
196 fds[0].events=POLLIN;
197 return 0;
198 }
199
200 /* Bodge to work around Ubuntu's strict header files */
201 static void discard(int anything) {}
202
203 static afterpoll_fn signal_afterpoll;
204 static void signal_afterpoll(void *st, struct pollfd *fds, int nfds)
205 {
206 uint8_t buf[16];
207 struct signotify *n;
208 sigset_t todo,old;
209
210 if (nfds && (fds->revents & POLLIN)) {
211 discard(read(spr,buf,16));
212 /* We don't actually care what we read; as
213 long as there was at least one byte
214 (which there was) we'll pick up the
215 signals in the pending set */
216
217 /* We reset 'pending' before processing any of the signals
218 that were pending so that we don't miss any signals that
219 are delivered partway-through processing (all we assume
220 about signal notification routines is that they handle all
221 the work available at their _start_ and only optionally any
222 work that arrives part-way through their execution). */
223 sigprocmask(SIG_SETMASK,&fullset,&old);
224 todo=pending;
225 sigemptyset(&pending);
226 sigprocmask(SIG_SETMASK,&old,NULL);
227
228 for (n=sigs; n; n=n->next)
229 if (sigismember(&todo,n->signum))
230 n->notify(n->cst,n->signum);
231 }
232 }
233
234 void afterfork(void)
235 {
236 struct signotify *n;
237 sigset_t done;
238 struct sigaction sa;
239
240 clear_phase_hooks(PHASE_SHUTDOWN);
241 /* Prevents calls to fatal() etc. in the child from running off
242 and doing a lot of unhelpful things */
243
244 sigemptyset(&done);
245 for (n=sigs; n; n=n->next)
246 if (!sigismember(&done,n->signum)) {
247 sigaddset(&done,n->signum);
248 sa.sa_handler=SIG_DFL;
249 sa.sa_mask=emptyset;
250 sa.sa_flags=0;
251 sigaction(n->signum,&sa,NULL);
252 }
253
254 sigemptyset(&emptyset);
255 sigprocmask(SIG_SETMASK,&emptyset,NULL);
256 }
257
258 void childpersist_closefd_hook(void *fd_vp, uint32_t newphase)
259 {
260 int *fd_p=fd_vp;
261 int fd=*fd_p;
262 if (fd<0) return;
263 *fd_p=-1;
264 setnonblock(fd); /* in case close() might block */
265 close(fd); /* discard errors - we don't care, in the child */
266 }
267
268 static void signal_handler(int signum)
269 {
270 int saved_errno;
271 uint8_t thing=0;
272 sigaddset(&pending,signum);
273 /* XXX the write() may set errno, which can make the main program fail.
274 However, signal handlers aren't allowed to modify anything which
275 is not of type sig_atomic_t. The world is broken. */
276 /* I have decided to save and restore errno anyway; on most
277 architectures on which secnet can run modifications to errno
278 will be atomic, and it seems to be the lesser of the two
279 evils. */
280 saved_errno=errno;
281 discard(write(spw,&thing,1));
282 /* We don't care if this fails (i.e. the pipe
283 is full) because the service routine will
284 spot the pending signal anyway */
285 errno=saved_errno;
286 }
287
288 static void register_signal_handler(struct signotify *s)
289 {
290 struct sigaction sa;
291 int rv;
292
293 if (!signal_handling) return;
294
295 if (sigismember(&registered,s->signum)) return;
296 sigaddset(&registered,s->signum);
297
298 sa.sa_handler=signal_handler;
299 sa.sa_mask=fullset;
300 sa.sa_flags=0;
301 rv=sigaction(s->signum,&sa,NULL);
302 if (rv!=0) {
303 fatal_perror("register_signal_handler: sigaction(%d)",s->signum);
304 }
305 }
306
307 void request_signal_notification(int signum, signal_notify_fn *notify,
308 void *cst)
309 {
310 struct signotify *s;
311 sigset_t old;
312
313 NEW(s);
314 s->signum=signum;
315 s->notify=notify;
316 s->cst=cst;
317 s->next=sigs;
318 sigprocmask(SIG_SETMASK,&fullset,&old);
319 sigs=s;
320 register_signal_handler(s);
321 sigprocmask(SIG_SETMASK,&old,NULL);
322 }
323
324 void start_signal_handling(void)
325 {
326 int p[2];
327 struct signotify *i;
328
329 sigemptyset(&emptyset);
330 sigfillset(&fullset);
331 sigemptyset(&registered);
332 sigemptyset(&pending);
333
334 pipe_cloexec(p);
335 spw=p[1];
336 spr=p[0];
337 setnonblock(spw);
338 setnonblock(spr);
339
340 register_for_poll(NULL,signal_beforepoll,signal_afterpoll,"signal");
341 signal_handling=True;
342
343 /* Register signal handlers for all the signals we're interested in */
344 for (i=sigs; i; i=i->next) {
345 register_signal_handler(i);
346 }
347
348 request_signal_notification(SIGCHLD,sigchld_handler,NULL);
349 }