blob: cd806851eadbb86028d33ed80f06e14b2abba55e [file] [log] [blame]
Denis Vlasenko8a164052007-03-12 23:34:52 +00001/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
Denis Vlasenko04c63862006-11-17 18:58:49 +000028/* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
29/* TODO: depends on runit_lib.c - review and reduce/eliminate */
30
31#include <sys/poll.h>
32#include <sys/file.h>
33#include "busybox.h"
34#include "runit_lib.h"
35
36static int selfpipe[2];
37
38/* state */
39#define S_DOWN 0
40#define S_RUN 1
41#define S_FINISH 2
42/* ctrl */
43#define C_NOOP 0
44#define C_TERM 1
45#define C_PAUSE 2
46/* want */
47#define W_UP 0
48#define W_DOWN 1
49#define W_EXIT 2
50
51struct svdir {
52 int pid;
Denis Vlasenko3aba6662007-03-09 22:46:06 +000053 smallint state;
54 smallint ctrl;
55 smallint want;
56 smallint islog;
Denis Vlasenko04c63862006-11-17 18:58:49 +000057 struct taia start;
58 int fdlock;
59 int fdcontrol;
60 int fdcontrolwrite;
Denis Vlasenko04c63862006-11-17 18:58:49 +000061};
62static struct svdir svd[2];
63
Denis Vlasenko3aba6662007-03-09 22:46:06 +000064static smallint sigterm;
65static smallint haslog;
66static smallint pidchanged = 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +000067static int logpipe[2];
68static char *dir;
69
70#define usage() bb_show_usage()
71
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000072static void fatal2_cannot(const char *m1, const char *m2)
Denis Vlasenko04c63862006-11-17 18:58:49 +000073{
74 bb_perror_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
75 /* was exiting 111 */
76}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000077static void fatal_cannot(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +000078{
79 fatal2_cannot(m, "");
80 /* was exiting 111 */
81}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000082static void fatal2x_cannot(const char *m1, const char *m2)
Denis Vlasenko04c63862006-11-17 18:58:49 +000083{
84 bb_error_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
85 /* was exiting 111 */
86}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000087static void warn_cannot(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +000088{
89 bb_perror_msg("%s: warning: cannot %s", dir, m);
90}
Denis Vlasenkoab2aea42007-01-29 22:51:58 +000091static void warnx_cannot(const char *m)
Denis Vlasenko04c63862006-11-17 18:58:49 +000092{
93 bb_error_msg("%s: warning: cannot %s", dir, m);
94}
95
Denis Vlasenko04c63862006-11-17 18:58:49 +000096static void s_child(int sig_no)
97{
98 write(selfpipe[1], "", 1);
99}
100
101static void s_term(int sig_no)
102{
103 sigterm = 1;
104 write(selfpipe[1], "", 1); /* XXX */
105}
106
107static char *add_str(char *p, const char *to_add)
108{
109 while ((*p = *to_add) != '\0') {
110 p++;
111 to_add++;
112 }
113 return p;
114}
115
116static int open_trunc_or_warn(const char *name)
117{
118 int fd = open_trunc(name);
119 if (fd < 0)
120 bb_perror_msg("%s: warning: cannot open %s",
121 dir, name);
122 return fd;
123}
124
125static int rename_or_warn(const char *old, const char *new)
126{
127 if (rename(old, new) == -1) {
128 bb_perror_msg("%s: warning: cannot rename %s to %s",
129 dir, old, new);
130 return -1;
131 }
132 return 0;
133}
134
135static void update_status(struct svdir *s)
136{
137 unsigned long l;
138 int fd;
139 char status[20];
140
141 /* pid */
142 if (pidchanged) {
143 fd = open_trunc_or_warn("supervise/pid.new");
144 if (fd < 0)
145 return;
146 if (s->pid) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000147 char spid[sizeof(int)*3 + 2];
148 int size = sprintf(spid, "%u\n", (unsigned)s->pid);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000149 write(fd, spid, size);
150 }
151 close(fd);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000152 if (rename_or_warn("supervise/pid.new",
153 s->islog ? "log/supervise/pid" : "log/supervise/pid"+4))
Denis Vlasenko04c63862006-11-17 18:58:49 +0000154 return;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000155 pidchanged = 0;
156 }
157
158 /* stat */
159 fd = open_trunc_or_warn("supervise/stat.new");
160 if (fd < -1)
161 return;
162
163 {
164 char stat_buf[sizeof("finish, paused, got TERM, want down\n")];
165 char *p = stat_buf;
166 switch (s->state) {
167 case S_DOWN:
168 p = add_str(p, "down");
169 break;
170 case S_RUN:
171 p = add_str(p, "run");
172 break;
173 case S_FINISH:
174 p = add_str(p, "finish");
175 break;
176 }
177 if (s->ctrl & C_PAUSE) p = add_str(p, ", paused");
178 if (s->ctrl & C_TERM) p = add_str(p, ", got TERM");
179 if (s->state != S_DOWN)
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000180 switch (s->want) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000181 case W_DOWN:
182 p = add_str(p, ", want down");
183 break;
184 case W_EXIT:
185 p = add_str(p, ", want exit");
186 break;
187 }
188 *p++ = '\n';
189 write(fd, stat_buf, p - stat_buf);
190 close(fd);
191 }
192
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000193 rename_or_warn("supervise/stat.new",
194 s->islog ? "log/supervise/stat" : "log/supervise/stat"+4);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000195
196 /* supervise compatibility */
197 taia_pack(status, &s->start);
198 l = (unsigned long)s->pid;
199 status[12] = l; l >>=8;
200 status[13] = l; l >>=8;
201 status[14] = l; l >>=8;
202 status[15] = l;
203 if (s->ctrl & C_PAUSE)
204 status[16] = 1;
205 else
206 status[16] = 0;
207 if (s->want == W_UP)
208 status[17] = 'u';
209 else
210 status[17] = 'd';
211 if (s->ctrl & C_TERM)
212 status[18] = 1;
213 else
214 status[18] = 0;
215 status[19] = s->state;
216 fd = open_trunc_or_warn("supervise/status.new");
217 if (fd < 0)
218 return;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000219 l = write(fd, status, sizeof(status));
Denis Vlasenko04c63862006-11-17 18:58:49 +0000220 if (l < 0) {
221 warn_cannot("write supervise/status.new");
222 close(fd);
223 unlink("supervise/status.new");
224 return;
225 }
226 close(fd);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000227 if (l < sizeof(status)) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000228 warnx_cannot("write supervise/status.new: partial write");
229 return;
230 }
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000231 rename_or_warn("supervise/status.new",
232 s->islog ? "log/supervise/status" : "log/supervise/status"+4);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000233}
234
235static unsigned custom(struct svdir *s, char c)
236{
237 int pid;
238 int w;
239 char a[10];
240 struct stat st;
241 char *prog[2];
242
243 if (s->islog) return 0;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000244 strcpy(a, "control/?");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000245 a[8] = c;
246 if (stat(a, &st) == 0) {
247 if (st.st_mode & S_IXUSR) {
248 pid = fork();
249 if (pid == -1) {
250 warn_cannot("fork for control/?");
251 return 0;
252 }
253 if (!pid) {
254 if (haslog && fd_copy(1, logpipe[1]) == -1)
255 warn_cannot("setup stdout for control/?");
256 prog[0] = a;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000257 prog[1] = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000258 execve(a, prog, environ);
259 fatal_cannot("run control/?");
260 }
261 while (wait_pid(&w, pid) == -1) {
262 if (errno == EINTR) continue;
263 warn_cannot("wait for child control/?");
264 return 0;
265 }
266 return !wait_exitcode(w);
267 }
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000268 } else {
269 if (errno != ENOENT)
270 warn_cannot("stat control/?");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000271 }
272 return 0;
273}
274
275static void stopservice(struct svdir *s)
276{
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000277 if (s->pid && !custom(s, 't')) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000278 kill(s->pid, SIGTERM);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000279 s->ctrl |= C_TERM;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000280 update_status(s);
281 }
282 if (s->want == W_DOWN) {
283 kill(s->pid, SIGCONT);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000284 custom(s, 'd');
285 return;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000286 }
287 if (s->want == W_EXIT) {
288 kill(s->pid, SIGCONT);
289 custom(s, 'x');
290 }
291}
292
293static void startservice(struct svdir *s)
294{
295 int p;
296 char *run[2];
297
298 if (s->state == S_FINISH)
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000299 run[0] = (char*)"./finish";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000300 else {
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000301 run[0] = (char*)"./run";
Denis Vlasenko04c63862006-11-17 18:58:49 +0000302 custom(s, 'u');
303 }
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000304 run[1] = NULL;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000305
306 if (s->pid != 0) stopservice(s); /* should never happen */
307 while ((p = fork()) == -1) {
308 warn_cannot("fork, sleeping");
309 sleep(5);
310 }
311 if (p == 0) {
312 /* child */
313 if (haslog) {
314 if (s->islog) {
315 if (fd_copy(0, logpipe[0]) == -1)
316 fatal_cannot("setup filedescriptor for ./log/run");
317 close(logpipe[1]);
318 if (chdir("./log") == -1)
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000319 fatal_cannot("change directory to ./log");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000320 } else {
321 if (fd_copy(1, logpipe[1]) == -1)
322 fatal_cannot("setup filedescriptor for ./run");
323 close(logpipe[0]);
324 }
325 }
Denis Vlasenko8c783952007-01-27 22:21:52 +0000326 sig_uncatch(SIGCHLD);
327 sig_unblock(SIGCHLD);
328 sig_uncatch(SIGTERM);
329 sig_unblock(SIGTERM);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000330 execve(*run, run, environ);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000331 fatal2_cannot(s->islog ? "start log/" : "start ", *run);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000332 }
333 if (s->state != S_FINISH) {
334 taia_now(&s->start);
335 s->state = S_RUN;
336 }
337 s->pid = p;
338 pidchanged = 1;
339 s->ctrl = C_NOOP;
340 update_status(s);
341}
342
343static int ctrl(struct svdir *s, char c)
344{
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000345 int sig;
346
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000347 switch (c) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000348 case 'd': /* down */
349 s->want = W_DOWN;
350 update_status(s);
351 if (s->pid && s->state != S_FINISH) stopservice(s);
352 break;
353 case 'u': /* up */
354 s->want = W_UP;
355 update_status(s);
356 if (s->pid == 0) startservice(s);
357 break;
358 case 'x': /* exit */
359 if (s->islog) break;
360 s->want = W_EXIT;
361 update_status(s);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000362 /* FALLTHROUGH */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000363 case 't': /* sig term */
364 if (s->pid && s->state != S_FINISH) stopservice(s);
365 break;
366 case 'k': /* sig kill */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000367 if (s->pid && !custom(s, c)) kill(s->pid, SIGKILL);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000368 s->state = S_DOWN;
369 break;
370 case 'p': /* sig pause */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000371 if (s->pid && !custom(s, c)) kill(s->pid, SIGSTOP);
372 s->ctrl |= C_PAUSE;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000373 update_status(s);
374 break;
375 case 'c': /* sig cont */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000376 if (s->pid && !custom(s, c)) kill(s->pid, SIGCONT);
377 if (s->ctrl & C_PAUSE) s->ctrl &= ~C_PAUSE;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000378 update_status(s);
379 break;
380 case 'o': /* once */
381 s->want = W_DOWN;
382 update_status(s);
383 if (!s->pid) startservice(s);
384 break;
385 case 'a': /* sig alarm */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000386 sig = SIGALRM;
387 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000388 case 'h': /* sig hup */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000389 sig = SIGHUP;
390 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000391 case 'i': /* sig int */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000392 sig = SIGINT;
393 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000394 case 'q': /* sig quit */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000395 sig = SIGQUIT;
396 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000397 case '1': /* sig usr1 */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000398 sig = SIGUSR1;
399 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000400 case '2': /* sig usr2 */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000401 sig = SIGUSR2;
402 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000403 }
404 return 1;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000405 sendsig:
406 if (s->pid && !custom(s, c))
407 kill(s->pid, sig);
408 return 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000409}
410
Denis Vlasenko06af2162007-02-03 17:28:39 +0000411int runsv_main(int argc, char **argv);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000412int runsv_main(int argc, char **argv)
413{
414 struct stat s;
415 int fd;
416 int r;
417 char buf[256];
418
419 if (!argv[1] || argv[2]) usage();
420 dir = argv[1];
421
422 if (pipe(selfpipe) == -1) fatal_cannot("create selfpipe");
423 coe(selfpipe[0]);
424 coe(selfpipe[1]);
425 ndelay_on(selfpipe[0]);
426 ndelay_on(selfpipe[1]);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000427
Denis Vlasenko8c783952007-01-27 22:21:52 +0000428 sig_block(SIGCHLD);
429 sig_catch(SIGCHLD, s_child);
430 sig_block(SIGTERM);
431 sig_catch(SIGTERM, s_term);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000432
433 xchdir(dir);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000434 /* bss: svd[0].pid = 0; */
435 if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */
436 if (C_NOOP) svd[0].ctrl = C_NOOP;
437 if (W_UP) svd[0].want = W_UP;
438 /* bss: svd[0].islog = 0; */
439 /* bss: svd[1].pid = 0; */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000440 taia_now(&svd[0].start);
441 if (stat("down", &s) != -1) svd[0].want = W_DOWN;
442
443 if (stat("log", &s) == -1) {
444 if (errno != ENOENT)
445 warn_cannot("stat ./log");
446 } else {
447 if (!S_ISDIR(s.st_mode))
448 warnx_cannot("stat log/down: log is not a directory");
449 else {
450 haslog = 1;
451 svd[1].state = S_DOWN;
452 svd[1].ctrl = C_NOOP;
453 svd[1].want = W_UP;
454 svd[1].islog = 1;
455 taia_now(&svd[1].start);
456 if (stat("log/down", &s) != -1)
457 svd[1].want = W_DOWN;
458 if (pipe(logpipe) == -1)
459 fatal_cannot("create log pipe");
460 coe(logpipe[0]);
461 coe(logpipe[1]);
462 }
463 }
464
465 if (mkdir("supervise", 0700) == -1) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000466 r = readlink("supervise", buf, sizeof(buf));
Denis Vlasenko04c63862006-11-17 18:58:49 +0000467 if (r != -1) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000468 if (r == sizeof(buf))
469 fatal2x_cannot("readlink ./supervise", ": name too long");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000470 buf[r] = 0;
471 mkdir(buf, 0700);
472 } else {
473 if ((errno != ENOENT) && (errno != EINVAL))
474 fatal_cannot("readlink ./supervise");
475 }
476 }
477 svd[0].fdlock = xopen3("log/supervise/lock"+4,
478 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
479 if (lock_exnb(svd[0].fdlock) == -1)
480 fatal_cannot("lock supervise/lock");
481 coe(svd[0].fdlock);
482 if (haslog) {
483 if (mkdir("log/supervise", 0700) == -1) {
484 r = readlink("log/supervise", buf, 256);
485 if (r != -1) {
486 if (r == 256)
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000487 fatal2x_cannot("readlink ./log/supervise", ": name too long");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000488 buf[r] = 0;
489 fd = xopen(".", O_RDONLY|O_NDELAY);
490 xchdir("./log");
491 mkdir(buf, 0700);
492 if (fchdir(fd) == -1)
493 fatal_cannot("change back to service directory");
494 close(fd);
495 }
496 else {
497 if ((errno != ENOENT) && (errno != EINVAL))
498 fatal_cannot("readlink ./log/supervise");
499 }
500 }
501 svd[1].fdlock = xopen3("log/supervise/lock",
502 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
503 if (lock_ex(svd[1].fdlock) == -1)
504 fatal_cannot("lock log/supervise/lock");
505 coe(svd[1].fdlock);
506 }
507
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000508 mkfifo("log/supervise/control"+4, 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000509 svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
510 coe(svd[0].fdcontrol);
511 svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
512 coe(svd[0].fdcontrolwrite);
513 update_status(&svd[0]);
514 if (haslog) {
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000515 mkfifo("log/supervise/control", 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000516 svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
517 coe(svd[1].fdcontrol);
518 svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
519 coe(svd[1].fdcontrolwrite);
520 update_status(&svd[1]);
521 }
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000522 mkfifo("log/supervise/ok"+4, 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000523 fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
524 coe(fd);
525 if (haslog) {
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000526 mkfifo("log/supervise/ok", 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000527 fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY);
528 coe(fd);
529 }
530 for (;;) {
531 iopause_fd x[3];
532 struct taia deadline;
533 struct taia now;
534 char ch;
535
536 if (haslog)
537 if (!svd[1].pid && svd[1].want == W_UP)
538 startservice(&svd[1]);
539 if (!svd[0].pid)
540 if (svd[0].want == W_UP || svd[0].state == S_FINISH)
541 startservice(&svd[0]);
542
543 x[0].fd = selfpipe[0];
544 x[0].events = IOPAUSE_READ;
545 x[1].fd = svd[0].fdcontrol;
546 x[1].events = IOPAUSE_READ;
547 if (haslog) {
548 x[2].fd = svd[1].fdcontrol;
549 x[2].events = IOPAUSE_READ;
550 }
551 taia_now(&now);
552 taia_uint(&deadline, 3600);
553 taia_add(&deadline, &now, &deadline);
554
Denis Vlasenko8c783952007-01-27 22:21:52 +0000555 sig_unblock(SIGTERM);
556 sig_unblock(SIGCHLD);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000557 iopause(x, 2+haslog, &deadline, &now);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000558 sig_block(SIGTERM);
559 sig_block(SIGCHLD);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000560
561 while (read(selfpipe[0], &ch, 1) == 1)
562 ;
563 for (;;) {
564 int child;
565 int wstat;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000566
Denis Vlasenko04c63862006-11-17 18:58:49 +0000567 child = wait_nohang(&wstat);
568 if (!child) break;
569 if ((child == -1) && (errno != EINTR)) break;
570 if (child == svd[0].pid) {
571 svd[0].pid = 0;
572 pidchanged = 1;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000573 svd[0].ctrl &=~ C_TERM;
Denis Vlasenkod0762e32007-02-18 11:07:43 +0000574 if (svd[0].state != S_FINISH) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000575 fd = open_read("finish");
576 if (fd != -1) {
577 close(fd);
578 svd[0].state = S_FINISH;
579 update_status(&svd[0]);
580 continue;
581 }
Denis Vlasenkod0762e32007-02-18 11:07:43 +0000582 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000583 svd[0].state = S_DOWN;
584 taia_uint(&deadline, 1);
585 taia_add(&deadline, &svd[0].start, &deadline);
586 taia_now(&svd[0].start);
587 update_status(&svd[0]);
588 if (taia_less(&svd[0].start, &deadline)) sleep(1);
589 }
590 if (haslog) {
591 if (child == svd[1].pid) {
592 svd[1].pid = 0;
593 pidchanged = 1;
594 svd[1].state = S_DOWN;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000595 svd[1].ctrl &= ~C_TERM;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000596 taia_uint(&deadline, 1);
597 taia_add(&deadline, &svd[1].start, &deadline);
598 taia_now(&svd[1].start);
599 update_status(&svd[1]);
600 if (taia_less(&svd[1].start, &deadline)) sleep(1);
601 }
602 }
603 }
604 if (read(svd[0].fdcontrol, &ch, 1) == 1)
605 ctrl(&svd[0], ch);
606 if (haslog)
607 if (read(svd[1].fdcontrol, &ch, 1) == 1)
608 ctrl(&svd[1], ch);
609
610 if (sigterm) {
611 ctrl(&svd[0], 'x');
612 sigterm = 0;
613 }
614
615 if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) {
616 if (svd[1].pid == 0)
617 _exit(0);
618 if (svd[1].want != W_EXIT) {
619 svd[1].want = W_EXIT;
620 /* stopservice(&svd[1]); */
621 update_status(&svd[1]);
622 close(logpipe[1]);
623 close(logpipe[0]);
624 //if (close(logpipe[1]) == -1)
625 // warn_cannot("close logpipe[1]");
626 //if (close(logpipe[0]) == -1)
627 // warn_cannot("close logpipe[0]");
628 }
629 }
630 }
631 /* not reached */
632 return 0;
633}