blob: bd4a81eeeafb646d36d3f21299fd33fbc5e61eed [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) {
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000254 if (haslog && dup2(logpipe[1], 1) == -1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000255 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
Denis Vlasenkoff131b92007-04-10 15:42:06 +0000306 if (s->pid != 0)
307 stopservice(s); /* should never happen */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000308 while ((p = fork()) == -1) {
309 warn_cannot("fork, sleeping");
310 sleep(5);
311 }
312 if (p == 0) {
313 /* child */
314 if (haslog) {
315 if (s->islog) {
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000316 if (dup2(logpipe[0], 0) == -1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000317 fatal_cannot("setup filedescriptor for ./log/run");
318 close(logpipe[1]);
319 if (chdir("./log") == -1)
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000320 fatal_cannot("change directory to ./log");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000321 } else {
Denis Vlasenkocad04ef2007-03-25 23:21:05 +0000322 if (dup2(logpipe[1], 1) == -1)
Denis Vlasenko04c63862006-11-17 18:58:49 +0000323 fatal_cannot("setup filedescriptor for ./run");
324 close(logpipe[0]);
325 }
326 }
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000327 signal(SIGCHLD, SIG_DFL);
328 signal(SIGTERM, SIG_DFL);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000329 sig_unblock(SIGCHLD);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000330 sig_unblock(SIGTERM);
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000331 execvp(*run, run);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000332 fatal2_cannot(s->islog ? "start log/" : "start ", *run);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000333 }
334 if (s->state != S_FINISH) {
335 taia_now(&s->start);
336 s->state = S_RUN;
337 }
338 s->pid = p;
339 pidchanged = 1;
340 s->ctrl = C_NOOP;
341 update_status(s);
342}
343
344static int ctrl(struct svdir *s, char c)
345{
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000346 int sig;
347
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000348 switch (c) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000349 case 'd': /* down */
350 s->want = W_DOWN;
351 update_status(s);
352 if (s->pid && s->state != S_FINISH) stopservice(s);
353 break;
354 case 'u': /* up */
355 s->want = W_UP;
356 update_status(s);
357 if (s->pid == 0) startservice(s);
358 break;
359 case 'x': /* exit */
360 if (s->islog) break;
361 s->want = W_EXIT;
362 update_status(s);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000363 /* FALLTHROUGH */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000364 case 't': /* sig term */
365 if (s->pid && s->state != S_FINISH) stopservice(s);
366 break;
367 case 'k': /* sig kill */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000368 if (s->pid && !custom(s, c)) kill(s->pid, SIGKILL);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000369 s->state = S_DOWN;
370 break;
371 case 'p': /* sig pause */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000372 if (s->pid && !custom(s, c)) kill(s->pid, SIGSTOP);
373 s->ctrl |= C_PAUSE;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000374 update_status(s);
375 break;
376 case 'c': /* sig cont */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000377 if (s->pid && !custom(s, c)) kill(s->pid, SIGCONT);
378 if (s->ctrl & C_PAUSE) s->ctrl &= ~C_PAUSE;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000379 update_status(s);
380 break;
381 case 'o': /* once */
382 s->want = W_DOWN;
383 update_status(s);
384 if (!s->pid) startservice(s);
385 break;
386 case 'a': /* sig alarm */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000387 sig = SIGALRM;
388 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000389 case 'h': /* sig hup */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000390 sig = SIGHUP;
391 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000392 case 'i': /* sig int */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000393 sig = SIGINT;
394 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000395 case 'q': /* sig quit */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000396 sig = SIGQUIT;
397 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000398 case '1': /* sig usr1 */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000399 sig = SIGUSR1;
400 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000401 case '2': /* sig usr2 */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000402 sig = SIGUSR2;
403 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000404 }
405 return 1;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000406 sendsig:
407 if (s->pid && !custom(s, c))
408 kill(s->pid, sig);
409 return 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000410}
411
Denis Vlasenko06af2162007-02-03 17:28:39 +0000412int runsv_main(int argc, char **argv);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000413int runsv_main(int argc, char **argv)
414{
415 struct stat s;
416 int fd;
417 int r;
418 char buf[256];
419
420 if (!argv[1] || argv[2]) usage();
421 dir = argv[1];
422
423 if (pipe(selfpipe) == -1) fatal_cannot("create selfpipe");
424 coe(selfpipe[0]);
425 coe(selfpipe[1]);
426 ndelay_on(selfpipe[0]);
427 ndelay_on(selfpipe[1]);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000428
Denis Vlasenko8c783952007-01-27 22:21:52 +0000429 sig_block(SIGCHLD);
430 sig_catch(SIGCHLD, s_child);
431 sig_block(SIGTERM);
432 sig_catch(SIGTERM, s_term);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000433
434 xchdir(dir);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000435 /* bss: svd[0].pid = 0; */
436 if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */
437 if (C_NOOP) svd[0].ctrl = C_NOOP;
438 if (W_UP) svd[0].want = W_UP;
439 /* bss: svd[0].islog = 0; */
440 /* bss: svd[1].pid = 0; */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000441 taia_now(&svd[0].start);
442 if (stat("down", &s) != -1) svd[0].want = W_DOWN;
443
444 if (stat("log", &s) == -1) {
445 if (errno != ENOENT)
446 warn_cannot("stat ./log");
447 } else {
448 if (!S_ISDIR(s.st_mode))
449 warnx_cannot("stat log/down: log is not a directory");
450 else {
451 haslog = 1;
452 svd[1].state = S_DOWN;
453 svd[1].ctrl = C_NOOP;
454 svd[1].want = W_UP;
455 svd[1].islog = 1;
456 taia_now(&svd[1].start);
457 if (stat("log/down", &s) != -1)
458 svd[1].want = W_DOWN;
459 if (pipe(logpipe) == -1)
460 fatal_cannot("create log pipe");
461 coe(logpipe[0]);
462 coe(logpipe[1]);
463 }
464 }
465
466 if (mkdir("supervise", 0700) == -1) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000467 r = readlink("supervise", buf, sizeof(buf));
Denis Vlasenko04c63862006-11-17 18:58:49 +0000468 if (r != -1) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000469 if (r == sizeof(buf))
470 fatal2x_cannot("readlink ./supervise", ": name too long");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000471 buf[r] = 0;
472 mkdir(buf, 0700);
473 } else {
474 if ((errno != ENOENT) && (errno != EINVAL))
475 fatal_cannot("readlink ./supervise");
476 }
477 }
478 svd[0].fdlock = xopen3("log/supervise/lock"+4,
479 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
480 if (lock_exnb(svd[0].fdlock) == -1)
481 fatal_cannot("lock supervise/lock");
482 coe(svd[0].fdlock);
483 if (haslog) {
484 if (mkdir("log/supervise", 0700) == -1) {
485 r = readlink("log/supervise", buf, 256);
486 if (r != -1) {
487 if (r == 256)
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000488 fatal2x_cannot("readlink ./log/supervise", ": name too long");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000489 buf[r] = 0;
490 fd = xopen(".", O_RDONLY|O_NDELAY);
491 xchdir("./log");
492 mkdir(buf, 0700);
493 if (fchdir(fd) == -1)
494 fatal_cannot("change back to service directory");
495 close(fd);
496 }
497 else {
498 if ((errno != ENOENT) && (errno != EINVAL))
499 fatal_cannot("readlink ./log/supervise");
500 }
501 }
502 svd[1].fdlock = xopen3("log/supervise/lock",
503 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
504 if (lock_ex(svd[1].fdlock) == -1)
505 fatal_cannot("lock log/supervise/lock");
506 coe(svd[1].fdlock);
507 }
508
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000509 mkfifo("log/supervise/control"+4, 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000510 svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
511 coe(svd[0].fdcontrol);
512 svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
513 coe(svd[0].fdcontrolwrite);
514 update_status(&svd[0]);
515 if (haslog) {
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000516 mkfifo("log/supervise/control", 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000517 svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
518 coe(svd[1].fdcontrol);
519 svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
520 coe(svd[1].fdcontrolwrite);
521 update_status(&svd[1]);
522 }
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000523 mkfifo("log/supervise/ok"+4, 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000524 fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
525 coe(fd);
526 if (haslog) {
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000527 mkfifo("log/supervise/ok", 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000528 fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY);
529 coe(fd);
530 }
531 for (;;) {
532 iopause_fd x[3];
533 struct taia deadline;
534 struct taia now;
535 char ch;
536
537 if (haslog)
538 if (!svd[1].pid && svd[1].want == W_UP)
539 startservice(&svd[1]);
540 if (!svd[0].pid)
541 if (svd[0].want == W_UP || svd[0].state == S_FINISH)
542 startservice(&svd[0]);
543
544 x[0].fd = selfpipe[0];
545 x[0].events = IOPAUSE_READ;
546 x[1].fd = svd[0].fdcontrol;
547 x[1].events = IOPAUSE_READ;
548 if (haslog) {
549 x[2].fd = svd[1].fdcontrol;
550 x[2].events = IOPAUSE_READ;
551 }
552 taia_now(&now);
553 taia_uint(&deadline, 3600);
554 taia_add(&deadline, &now, &deadline);
555
Denis Vlasenko8c783952007-01-27 22:21:52 +0000556 sig_unblock(SIGTERM);
557 sig_unblock(SIGCHLD);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000558 iopause(x, 2+haslog, &deadline, &now);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000559 sig_block(SIGTERM);
560 sig_block(SIGCHLD);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000561
562 while (read(selfpipe[0], &ch, 1) == 1)
563 ;
564 for (;;) {
565 int child;
566 int wstat;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000567
Denis Vlasenko04c63862006-11-17 18:58:49 +0000568 child = wait_nohang(&wstat);
569 if (!child) break;
570 if ((child == -1) && (errno != EINTR)) break;
571 if (child == svd[0].pid) {
572 svd[0].pid = 0;
573 pidchanged = 1;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000574 svd[0].ctrl &=~ C_TERM;
Denis Vlasenkod0762e32007-02-18 11:07:43 +0000575 if (svd[0].state != S_FINISH) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000576 fd = open_read("finish");
577 if (fd != -1) {
578 close(fd);
579 svd[0].state = S_FINISH;
580 update_status(&svd[0]);
581 continue;
582 }
Denis Vlasenkod0762e32007-02-18 11:07:43 +0000583 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000584 svd[0].state = S_DOWN;
585 taia_uint(&deadline, 1);
586 taia_add(&deadline, &svd[0].start, &deadline);
587 taia_now(&svd[0].start);
588 update_status(&svd[0]);
589 if (taia_less(&svd[0].start, &deadline)) sleep(1);
590 }
591 if (haslog) {
592 if (child == svd[1].pid) {
593 svd[1].pid = 0;
594 pidchanged = 1;
595 svd[1].state = S_DOWN;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000596 svd[1].ctrl &= ~C_TERM;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000597 taia_uint(&deadline, 1);
598 taia_add(&deadline, &svd[1].start, &deadline);
599 taia_now(&svd[1].start);
600 update_status(&svd[1]);
601 if (taia_less(&svd[1].start, &deadline)) sleep(1);
602 }
603 }
604 }
605 if (read(svd[0].fdcontrol, &ch, 1) == 1)
606 ctrl(&svd[0], ch);
607 if (haslog)
608 if (read(svd[1].fdcontrol, &ch, 1) == 1)
609 ctrl(&svd[1], ch);
610
611 if (sigterm) {
612 ctrl(&svd[0], 'x');
613 sigterm = 0;
614 }
615
616 if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) {
617 if (svd[1].pid == 0)
618 _exit(0);
619 if (svd[1].want != W_EXIT) {
620 svd[1].want = W_EXIT;
621 /* stopservice(&svd[1]); */
622 update_status(&svd[1]);
623 close(logpipe[1]);
624 close(logpipe[0]);
625 //if (close(logpipe[1]) == -1)
626 // warn_cannot("close logpipe[1]");
627 //if (close(logpipe[0]) == -1)
628 // warn_cannot("close logpipe[0]");
629 }
630 }
631 }
632 /* not reached */
633 return 0;
634}