diff options
Diffstat (limited to 'runit/runsv.c')
-rw-r--r-- | runit/runsv.c | 613 |
1 files changed, 613 insertions, 0 deletions
diff --git a/runit/runsv.c b/runit/runsv.c new file mode 100644 index 000000000..e1b5459fb --- /dev/null +++ b/runit/runsv.c | |||
@@ -0,0 +1,613 @@ | |||
1 | /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */ | ||
2 | /* TODO: depends on runit_lib.c - review and reduce/eliminate */ | ||
3 | |||
4 | #include <sys/poll.h> | ||
5 | #include <sys/file.h> | ||
6 | #include "busybox.h" | ||
7 | #include "runit_lib.h" | ||
8 | |||
9 | static int selfpipe[2]; | ||
10 | |||
11 | /* state */ | ||
12 | #define S_DOWN 0 | ||
13 | #define S_RUN 1 | ||
14 | #define S_FINISH 2 | ||
15 | /* ctrl */ | ||
16 | #define C_NOOP 0 | ||
17 | #define C_TERM 1 | ||
18 | #define C_PAUSE 2 | ||
19 | /* want */ | ||
20 | #define W_UP 0 | ||
21 | #define W_DOWN 1 | ||
22 | #define W_EXIT 2 | ||
23 | |||
24 | struct svdir { | ||
25 | int pid; | ||
26 | int state; | ||
27 | int ctrl; | ||
28 | int want; | ||
29 | struct taia start; | ||
30 | int fdlock; | ||
31 | int fdcontrol; | ||
32 | int fdcontrolwrite; | ||
33 | int islog; | ||
34 | }; | ||
35 | static struct svdir svd[2]; | ||
36 | |||
37 | static int sigterm = 0; | ||
38 | static int haslog = 0; | ||
39 | static int pidchanged = 1; | ||
40 | static int logpipe[2]; | ||
41 | static char *dir; | ||
42 | |||
43 | #define usage() bb_show_usage() | ||
44 | |||
45 | static void fatal2_cannot(char *m1, char *m2) | ||
46 | { | ||
47 | bb_perror_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2); | ||
48 | /* was exiting 111 */ | ||
49 | } | ||
50 | static void fatal_cannot(char *m) | ||
51 | { | ||
52 | fatal2_cannot(m, ""); | ||
53 | /* was exiting 111 */ | ||
54 | } | ||
55 | static void fatal2x_cannot(char *m1, char *m2) | ||
56 | { | ||
57 | bb_error_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2); | ||
58 | /* was exiting 111 */ | ||
59 | } | ||
60 | static void warn_cannot(char *m) | ||
61 | { | ||
62 | bb_perror_msg("%s: warning: cannot %s", dir, m); | ||
63 | } | ||
64 | static void warnx_cannot(char *m) | ||
65 | { | ||
66 | bb_error_msg("%s: warning: cannot %s", dir, m); | ||
67 | } | ||
68 | |||
69 | static void stopservice(struct svdir *); | ||
70 | |||
71 | static void s_child(int sig_no) | ||
72 | { | ||
73 | write(selfpipe[1], "", 1); | ||
74 | } | ||
75 | |||
76 | static void s_term(int sig_no) | ||
77 | { | ||
78 | sigterm = 1; | ||
79 | write(selfpipe[1], "", 1); /* XXX */ | ||
80 | } | ||
81 | |||
82 | static char *add_str(char *p, const char *to_add) | ||
83 | { | ||
84 | while ((*p = *to_add) != '\0') { | ||
85 | p++; | ||
86 | to_add++; | ||
87 | } | ||
88 | return p; | ||
89 | } | ||
90 | |||
91 | static int open_trunc_or_warn(const char *name) | ||
92 | { | ||
93 | int fd = open_trunc(name); | ||
94 | if (fd < 0) | ||
95 | bb_perror_msg("%s: warning: cannot open %s", | ||
96 | dir, name); | ||
97 | return fd; | ||
98 | } | ||
99 | |||
100 | static int rename_or_warn(const char *old, const char *new) | ||
101 | { | ||
102 | if (rename(old, new) == -1) { | ||
103 | bb_perror_msg("%s: warning: cannot rename %s to %s", | ||
104 | dir, old, new); | ||
105 | return -1; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static void update_status(struct svdir *s) | ||
111 | { | ||
112 | unsigned long l; | ||
113 | int fd; | ||
114 | char status[20]; | ||
115 | |||
116 | /* pid */ | ||
117 | if (pidchanged) { | ||
118 | fd = open_trunc_or_warn("supervise/pid.new"); | ||
119 | if (fd < 0) | ||
120 | return; | ||
121 | if (s->pid) { | ||
122 | char spid[sizeof(s->pid)*3 + 2]; | ||
123 | int size = sprintf(spid, "%d\n", s->pid); | ||
124 | write(fd, spid, size); | ||
125 | } | ||
126 | close(fd); | ||
127 | if (s->islog) { | ||
128 | if (rename_or_warn("supervise/pid.new", "log/supervise/pid")) | ||
129 | return; | ||
130 | } else if (rename_or_warn("supervise/pid.new", "supervise/pid")) { | ||
131 | return; | ||
132 | } | ||
133 | pidchanged = 0; | ||
134 | } | ||
135 | |||
136 | /* stat */ | ||
137 | fd = open_trunc_or_warn("supervise/stat.new"); | ||
138 | if (fd < -1) | ||
139 | return; | ||
140 | |||
141 | { | ||
142 | char stat_buf[sizeof("finish, paused, got TERM, want down\n")]; | ||
143 | char *p = stat_buf; | ||
144 | switch (s->state) { | ||
145 | case S_DOWN: | ||
146 | p = add_str(p, "down"); | ||
147 | break; | ||
148 | case S_RUN: | ||
149 | p = add_str(p, "run"); | ||
150 | break; | ||
151 | case S_FINISH: | ||
152 | p = add_str(p, "finish"); | ||
153 | break; | ||
154 | } | ||
155 | if (s->ctrl & C_PAUSE) p = add_str(p, ", paused"); | ||
156 | if (s->ctrl & C_TERM) p = add_str(p, ", got TERM"); | ||
157 | if (s->state != S_DOWN) | ||
158 | switch(s->want) { | ||
159 | case W_DOWN: | ||
160 | p = add_str(p, ", want down"); | ||
161 | break; | ||
162 | case W_EXIT: | ||
163 | p = add_str(p, ", want exit"); | ||
164 | break; | ||
165 | } | ||
166 | *p++ = '\n'; | ||
167 | write(fd, stat_buf, p - stat_buf); | ||
168 | close(fd); | ||
169 | } | ||
170 | |||
171 | if (s->islog) { | ||
172 | rename_or_warn("supervise/stat.new", "log/supervise/stat"); | ||
173 | } else { | ||
174 | rename_or_warn("supervise/stat.new", "log/supervise/stat"+4); | ||
175 | } | ||
176 | |||
177 | /* supervise compatibility */ | ||
178 | taia_pack(status, &s->start); | ||
179 | l = (unsigned long)s->pid; | ||
180 | status[12] = l; l >>=8; | ||
181 | status[13] = l; l >>=8; | ||
182 | status[14] = l; l >>=8; | ||
183 | status[15] = l; | ||
184 | if (s->ctrl & C_PAUSE) | ||
185 | status[16] = 1; | ||
186 | else | ||
187 | status[16] = 0; | ||
188 | if (s->want == W_UP) | ||
189 | status[17] = 'u'; | ||
190 | else | ||
191 | status[17] = 'd'; | ||
192 | if (s->ctrl & C_TERM) | ||
193 | status[18] = 1; | ||
194 | else | ||
195 | status[18] = 0; | ||
196 | status[19] = s->state; | ||
197 | fd = open_trunc_or_warn("supervise/status.new"); | ||
198 | if (fd < 0) | ||
199 | return; | ||
200 | l = write(fd, status, sizeof status); | ||
201 | if (l < 0) { | ||
202 | warn_cannot("write supervise/status.new"); | ||
203 | close(fd); | ||
204 | unlink("supervise/status.new"); | ||
205 | return; | ||
206 | } | ||
207 | close(fd); | ||
208 | if (l < sizeof status) { | ||
209 | warnx_cannot("write supervise/status.new: partial write"); | ||
210 | return; | ||
211 | } | ||
212 | if (s->islog) { | ||
213 | rename_or_warn("supervise/status.new", "log/supervise/status"); | ||
214 | } else { | ||
215 | rename_or_warn("supervise/status.new", "log/supervise/status"+4); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | static unsigned custom(struct svdir *s, char c) | ||
220 | { | ||
221 | int pid; | ||
222 | int w; | ||
223 | char a[10]; | ||
224 | struct stat st; | ||
225 | char *prog[2]; | ||
226 | |||
227 | if (s->islog) return 0; | ||
228 | memcpy(a, "control/?", 10); | ||
229 | a[8] = c; | ||
230 | if (stat(a, &st) == 0) { | ||
231 | if (st.st_mode & S_IXUSR) { | ||
232 | pid = fork(); | ||
233 | if (pid == -1) { | ||
234 | warn_cannot("fork for control/?"); | ||
235 | return 0; | ||
236 | } | ||
237 | if (!pid) { | ||
238 | if (haslog && fd_copy(1, logpipe[1]) == -1) | ||
239 | warn_cannot("setup stdout for control/?"); | ||
240 | prog[0] = a; | ||
241 | prog[1] = 0; | ||
242 | execve(a, prog, environ); | ||
243 | fatal_cannot("run control/?"); | ||
244 | } | ||
245 | while (wait_pid(&w, pid) == -1) { | ||
246 | if (errno == EINTR) continue; | ||
247 | warn_cannot("wait for child control/?"); | ||
248 | return 0; | ||
249 | } | ||
250 | return !wait_exitcode(w); | ||
251 | } | ||
252 | } | ||
253 | else { | ||
254 | if (errno == ENOENT) return 0; | ||
255 | warn_cannot("stat control/?"); | ||
256 | } | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static void stopservice(struct svdir *s) | ||
261 | { | ||
262 | if (s->pid && ! custom(s, 't')) { | ||
263 | kill(s->pid, SIGTERM); | ||
264 | s->ctrl |=C_TERM; | ||
265 | update_status(s); | ||
266 | } | ||
267 | if (s->want == W_DOWN) { | ||
268 | kill(s->pid, SIGCONT); | ||
269 | custom(s, 'd'); return; | ||
270 | } | ||
271 | if (s->want == W_EXIT) { | ||
272 | kill(s->pid, SIGCONT); | ||
273 | custom(s, 'x'); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | static void startservice(struct svdir *s) | ||
278 | { | ||
279 | int p; | ||
280 | char *run[2]; | ||
281 | |||
282 | if (s->state == S_FINISH) | ||
283 | run[0] = "./finish"; | ||
284 | else { | ||
285 | run[0] = "./run"; | ||
286 | custom(s, 'u'); | ||
287 | } | ||
288 | run[1] = 0; | ||
289 | |||
290 | if (s->pid != 0) stopservice(s); /* should never happen */ | ||
291 | while ((p = fork()) == -1) { | ||
292 | warn_cannot("fork, sleeping"); | ||
293 | sleep(5); | ||
294 | } | ||
295 | if (p == 0) { | ||
296 | /* child */ | ||
297 | if (haslog) { | ||
298 | if (s->islog) { | ||
299 | if (fd_copy(0, logpipe[0]) == -1) | ||
300 | fatal_cannot("setup filedescriptor for ./log/run"); | ||
301 | close(logpipe[1]); | ||
302 | if (chdir("./log") == -1) | ||
303 | fatal_cannot("change directory to ./log"); | ||
304 | } else { | ||
305 | if (fd_copy(1, logpipe[1]) == -1) | ||
306 | fatal_cannot("setup filedescriptor for ./run"); | ||
307 | close(logpipe[0]); | ||
308 | } | ||
309 | } | ||
310 | sig_uncatch(sig_child); | ||
311 | sig_unblock(sig_child); | ||
312 | sig_uncatch(sig_term); | ||
313 | sig_unblock(sig_term); | ||
314 | execve(*run, run, environ); | ||
315 | if (s->islog) | ||
316 | fatal2_cannot("start log/", *run); | ||
317 | else | ||
318 | fatal2_cannot("start ", *run); | ||
319 | } | ||
320 | if (s->state != S_FINISH) { | ||
321 | taia_now(&s->start); | ||
322 | s->state = S_RUN; | ||
323 | } | ||
324 | s->pid = p; | ||
325 | pidchanged = 1; | ||
326 | s->ctrl = C_NOOP; | ||
327 | update_status(s); | ||
328 | } | ||
329 | |||
330 | static int ctrl(struct svdir *s, char c) | ||
331 | { | ||
332 | switch(c) { | ||
333 | case 'd': /* down */ | ||
334 | s->want = W_DOWN; | ||
335 | update_status(s); | ||
336 | if (s->pid && s->state != S_FINISH) stopservice(s); | ||
337 | break; | ||
338 | case 'u': /* up */ | ||
339 | s->want = W_UP; | ||
340 | update_status(s); | ||
341 | if (s->pid == 0) startservice(s); | ||
342 | break; | ||
343 | case 'x': /* exit */ | ||
344 | if (s->islog) break; | ||
345 | s->want = W_EXIT; | ||
346 | update_status(s); | ||
347 | if (s->pid && s->state != S_FINISH) stopservice(s); | ||
348 | break; | ||
349 | case 't': /* sig term */ | ||
350 | if (s->pid && s->state != S_FINISH) stopservice(s); | ||
351 | break; | ||
352 | case 'k': /* sig kill */ | ||
353 | if (s->pid && ! custom(s, c)) kill(s->pid, SIGKILL); | ||
354 | s->state = S_DOWN; | ||
355 | break; | ||
356 | case 'p': /* sig pause */ | ||
357 | if (s->pid && ! custom(s, c)) kill(s->pid, SIGSTOP); | ||
358 | s->ctrl |=C_PAUSE; | ||
359 | update_status(s); | ||
360 | break; | ||
361 | case 'c': /* sig cont */ | ||
362 | if (s->pid && ! custom(s, c)) kill(s->pid, SIGCONT); | ||
363 | if (s->ctrl & C_PAUSE) s->ctrl &=~C_PAUSE; | ||
364 | update_status(s); | ||
365 | break; | ||
366 | case 'o': /* once */ | ||
367 | s->want = W_DOWN; | ||
368 | update_status(s); | ||
369 | if (!s->pid) startservice(s); | ||
370 | break; | ||
371 | case 'a': /* sig alarm */ | ||
372 | if (s->pid && ! custom(s, c)) kill(s->pid, SIGALRM); | ||
373 | break; | ||
374 | case 'h': /* sig hup */ | ||
375 | if (s->pid && ! custom(s, c)) kill(s->pid, SIGHUP); | ||
376 | break; | ||
377 | case 'i': /* sig int */ | ||
378 | if (s->pid && ! custom(s, c)) kill(s->pid, SIGINT); | ||
379 | break; | ||
380 | case 'q': /* sig quit */ | ||
381 | if (s->pid && ! custom(s, c)) kill(s->pid, SIGQUIT); | ||
382 | break; | ||
383 | case '1': /* sig usr1 */ | ||
384 | if (s->pid && ! custom(s, c)) kill(s->pid, SIGUSR1); | ||
385 | break; | ||
386 | case '2': /* sig usr2 */ | ||
387 | if (s->pid && ! custom(s, c)) kill(s->pid, SIGUSR2); | ||
388 | break; | ||
389 | } | ||
390 | return 1; | ||
391 | } | ||
392 | |||
393 | int runsv_main(int argc, char **argv) | ||
394 | { | ||
395 | struct stat s; | ||
396 | int fd; | ||
397 | int r; | ||
398 | char buf[256]; | ||
399 | |||
400 | if (!argv[1] || argv[2]) usage(); | ||
401 | dir = argv[1]; | ||
402 | |||
403 | if (pipe(selfpipe) == -1) fatal_cannot("create selfpipe"); | ||
404 | coe(selfpipe[0]); | ||
405 | coe(selfpipe[1]); | ||
406 | ndelay_on(selfpipe[0]); | ||
407 | ndelay_on(selfpipe[1]); | ||
408 | |||
409 | sig_block(sig_child); | ||
410 | sig_catch(sig_child, s_child); | ||
411 | sig_block(sig_term); | ||
412 | sig_catch(sig_term, s_term); | ||
413 | |||
414 | xchdir(dir); | ||
415 | svd[0].pid = 0; | ||
416 | svd[0].state = S_DOWN; | ||
417 | svd[0].ctrl = C_NOOP; | ||
418 | svd[0].want = W_UP; | ||
419 | svd[0].islog = 0; | ||
420 | svd[1].pid = 0; | ||
421 | taia_now(&svd[0].start); | ||
422 | if (stat("down", &s) != -1) svd[0].want = W_DOWN; | ||
423 | |||
424 | if (stat("log", &s) == -1) { | ||
425 | if (errno != ENOENT) | ||
426 | warn_cannot("stat ./log"); | ||
427 | } else { | ||
428 | if (!S_ISDIR(s.st_mode)) | ||
429 | warnx_cannot("stat log/down: log is not a directory"); | ||
430 | else { | ||
431 | haslog = 1; | ||
432 | svd[1].state = S_DOWN; | ||
433 | svd[1].ctrl = C_NOOP; | ||
434 | svd[1].want = W_UP; | ||
435 | svd[1].islog = 1; | ||
436 | taia_now(&svd[1].start); | ||
437 | if (stat("log/down", &s) != -1) | ||
438 | svd[1].want = W_DOWN; | ||
439 | if (pipe(logpipe) == -1) | ||
440 | fatal_cannot("create log pipe"); | ||
441 | coe(logpipe[0]); | ||
442 | coe(logpipe[1]); | ||
443 | } | ||
444 | } | ||
445 | |||
446 | if (mkdir("supervise", 0700) == -1) { | ||
447 | r = readlink("supervise", buf, 256); | ||
448 | if (r != -1) { | ||
449 | if (r == 256) | ||
450 | fatal2x_cannot("readlink ./supervise: ", "name too long"); | ||
451 | buf[r] = 0; | ||
452 | mkdir(buf, 0700); | ||
453 | } else { | ||
454 | if ((errno != ENOENT) && (errno != EINVAL)) | ||
455 | fatal_cannot("readlink ./supervise"); | ||
456 | } | ||
457 | } | ||
458 | svd[0].fdlock = xopen3("log/supervise/lock"+4, | ||
459 | O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); | ||
460 | if (lock_exnb(svd[0].fdlock) == -1) | ||
461 | fatal_cannot("lock supervise/lock"); | ||
462 | coe(svd[0].fdlock); | ||
463 | if (haslog) { | ||
464 | if (mkdir("log/supervise", 0700) == -1) { | ||
465 | r = readlink("log/supervise", buf, 256); | ||
466 | if (r != -1) { | ||
467 | if (r == 256) | ||
468 | fatal2x_cannot("readlink ./log/supervise: ", "name too long"); | ||
469 | buf[r] = 0; | ||
470 | fd = xopen(".", O_RDONLY|O_NDELAY); | ||
471 | xchdir("./log"); | ||
472 | mkdir(buf, 0700); | ||
473 | if (fchdir(fd) == -1) | ||
474 | fatal_cannot("change back to service directory"); | ||
475 | close(fd); | ||
476 | } | ||
477 | else { | ||
478 | if ((errno != ENOENT) && (errno != EINVAL)) | ||
479 | fatal_cannot("readlink ./log/supervise"); | ||
480 | } | ||
481 | } | ||
482 | svd[1].fdlock = xopen3("log/supervise/lock", | ||
483 | O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); | ||
484 | if (lock_ex(svd[1].fdlock) == -1) | ||
485 | fatal_cannot("lock log/supervise/lock"); | ||
486 | coe(svd[1].fdlock); | ||
487 | } | ||
488 | |||
489 | fifo_make("log/supervise/control"+4, 0600); | ||
490 | svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY); | ||
491 | coe(svd[0].fdcontrol); | ||
492 | svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY); | ||
493 | coe(svd[0].fdcontrolwrite); | ||
494 | update_status(&svd[0]); | ||
495 | if (haslog) { | ||
496 | fifo_make("log/supervise/control", 0600); | ||
497 | svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY); | ||
498 | coe(svd[1].fdcontrol); | ||
499 | svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY); | ||
500 | coe(svd[1].fdcontrolwrite); | ||
501 | update_status(&svd[1]); | ||
502 | } | ||
503 | fifo_make("log/supervise/ok"+4, 0600); | ||
504 | fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY); | ||
505 | coe(fd); | ||
506 | if (haslog) { | ||
507 | fifo_make("log/supervise/ok", 0600); | ||
508 | fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY); | ||
509 | coe(fd); | ||
510 | } | ||
511 | for (;;) { | ||
512 | iopause_fd x[3]; | ||
513 | struct taia deadline; | ||
514 | struct taia now; | ||
515 | char ch; | ||
516 | |||
517 | if (haslog) | ||
518 | if (!svd[1].pid && svd[1].want == W_UP) | ||
519 | startservice(&svd[1]); | ||
520 | if (!svd[0].pid) | ||
521 | if (svd[0].want == W_UP || svd[0].state == S_FINISH) | ||
522 | startservice(&svd[0]); | ||
523 | |||
524 | x[0].fd = selfpipe[0]; | ||
525 | x[0].events = IOPAUSE_READ; | ||
526 | x[1].fd = svd[0].fdcontrol; | ||
527 | x[1].events = IOPAUSE_READ; | ||
528 | if (haslog) { | ||
529 | x[2].fd = svd[1].fdcontrol; | ||
530 | x[2].events = IOPAUSE_READ; | ||
531 | } | ||
532 | taia_now(&now); | ||
533 | taia_uint(&deadline, 3600); | ||
534 | taia_add(&deadline, &now, &deadline); | ||
535 | |||
536 | sig_unblock(sig_term); | ||
537 | sig_unblock(sig_child); | ||
538 | iopause(x, 2+haslog, &deadline, &now); | ||
539 | sig_block(sig_term); | ||
540 | sig_block(sig_child); | ||
541 | |||
542 | while (read(selfpipe[0], &ch, 1) == 1) | ||
543 | ; | ||
544 | for (;;) { | ||
545 | int child; | ||
546 | int wstat; | ||
547 | |||
548 | child = wait_nohang(&wstat); | ||
549 | if (!child) break; | ||
550 | if ((child == -1) && (errno != EINTR)) break; | ||
551 | if (child == svd[0].pid) { | ||
552 | svd[0].pid = 0; | ||
553 | pidchanged = 1; | ||
554 | svd[0].ctrl &=~C_TERM; | ||
555 | if (svd[0].state != S_FINISH) | ||
556 | fd = open_read("finish"); | ||
557 | if (fd != -1) { | ||
558 | close(fd); | ||
559 | svd[0].state = S_FINISH; | ||
560 | update_status(&svd[0]); | ||
561 | continue; | ||
562 | } | ||
563 | svd[0].state = S_DOWN; | ||
564 | taia_uint(&deadline, 1); | ||
565 | taia_add(&deadline, &svd[0].start, &deadline); | ||
566 | taia_now(&svd[0].start); | ||
567 | update_status(&svd[0]); | ||
568 | if (taia_less(&svd[0].start, &deadline)) sleep(1); | ||
569 | } | ||
570 | if (haslog) { | ||
571 | if (child == svd[1].pid) { | ||
572 | svd[1].pid = 0; | ||
573 | pidchanged = 1; | ||
574 | svd[1].state = S_DOWN; | ||
575 | svd[1].ctrl &=~C_TERM; | ||
576 | taia_uint(&deadline, 1); | ||
577 | taia_add(&deadline, &svd[1].start, &deadline); | ||
578 | taia_now(&svd[1].start); | ||
579 | update_status(&svd[1]); | ||
580 | if (taia_less(&svd[1].start, &deadline)) sleep(1); | ||
581 | } | ||
582 | } | ||
583 | } | ||
584 | if (read(svd[0].fdcontrol, &ch, 1) == 1) | ||
585 | ctrl(&svd[0], ch); | ||
586 | if (haslog) | ||
587 | if (read(svd[1].fdcontrol, &ch, 1) == 1) | ||
588 | ctrl(&svd[1], ch); | ||
589 | |||
590 | if (sigterm) { | ||
591 | ctrl(&svd[0], 'x'); | ||
592 | sigterm = 0; | ||
593 | } | ||
594 | |||
595 | if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) { | ||
596 | if (svd[1].pid == 0) | ||
597 | _exit(0); | ||
598 | if (svd[1].want != W_EXIT) { | ||
599 | svd[1].want = W_EXIT; | ||
600 | /* stopservice(&svd[1]); */ | ||
601 | update_status(&svd[1]); | ||
602 | close(logpipe[1]); | ||
603 | close(logpipe[0]); | ||
604 | //if (close(logpipe[1]) == -1) | ||
605 | // warn_cannot("close logpipe[1]"); | ||
606 | //if (close(logpipe[0]) == -1) | ||
607 | // warn_cannot("close logpipe[0]"); | ||
608 | } | ||
609 | } | ||
610 | } | ||
611 | /* not reached */ | ||
612 | return 0; | ||
613 | } | ||