blob: f70b51390f5c79fe893d154c55bfa21e6094d155 [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>
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000033#include "libbb.h"
Denis Vlasenko04c63862006-11-17 18:58:49 +000034#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 Vlasenkoa27a11b2007-08-18 14:16:39 +0000316 xdup2(logpipe[0], 0);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000317 close(logpipe[1]);
Denis Vlasenkoa27a11b2007-08-18 14:16:39 +0000318 xchdir("./log");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000319 } else {
Denis Vlasenkoa27a11b2007-08-18 14:16:39 +0000320 xdup2(logpipe[1], 1);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000321 close(logpipe[0]);
322 }
323 }
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000324 signal(SIGCHLD, SIG_DFL);
325 signal(SIGTERM, SIG_DFL);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000326 sig_unblock(SIGCHLD);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000327 sig_unblock(SIGTERM);
Denis Vlasenko2856dab2007-04-01 01:18:20 +0000328 execvp(*run, run);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000329 fatal2_cannot(s->islog ? "start log/" : "start ", *run);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000330 }
331 if (s->state != S_FINISH) {
332 taia_now(&s->start);
333 s->state = S_RUN;
334 }
335 s->pid = p;
336 pidchanged = 1;
337 s->ctrl = C_NOOP;
338 update_status(s);
339}
340
341static int ctrl(struct svdir *s, char c)
342{
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000343 int sig;
344
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000345 switch (c) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000346 case 'd': /* down */
347 s->want = W_DOWN;
348 update_status(s);
349 if (s->pid && s->state != S_FINISH) stopservice(s);
350 break;
351 case 'u': /* up */
352 s->want = W_UP;
353 update_status(s);
354 if (s->pid == 0) startservice(s);
355 break;
356 case 'x': /* exit */
357 if (s->islog) break;
358 s->want = W_EXIT;
359 update_status(s);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000360 /* FALLTHROUGH */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000361 case 't': /* sig term */
362 if (s->pid && s->state != S_FINISH) stopservice(s);
363 break;
364 case 'k': /* sig kill */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000365 if (s->pid && !custom(s, c)) kill(s->pid, SIGKILL);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000366 s->state = S_DOWN;
367 break;
368 case 'p': /* sig pause */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000369 if (s->pid && !custom(s, c)) kill(s->pid, SIGSTOP);
370 s->ctrl |= C_PAUSE;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000371 update_status(s);
372 break;
373 case 'c': /* sig cont */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000374 if (s->pid && !custom(s, c)) kill(s->pid, SIGCONT);
375 if (s->ctrl & C_PAUSE) s->ctrl &= ~C_PAUSE;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000376 update_status(s);
377 break;
378 case 'o': /* once */
379 s->want = W_DOWN;
380 update_status(s);
381 if (!s->pid) startservice(s);
382 break;
383 case 'a': /* sig alarm */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000384 sig = SIGALRM;
385 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000386 case 'h': /* sig hup */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000387 sig = SIGHUP;
388 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000389 case 'i': /* sig int */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000390 sig = SIGINT;
391 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000392 case 'q': /* sig quit */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000393 sig = SIGQUIT;
394 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000395 case '1': /* sig usr1 */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000396 sig = SIGUSR1;
397 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000398 case '2': /* sig usr2 */
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000399 sig = SIGUSR2;
400 goto sendsig;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000401 }
402 return 1;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000403 sendsig:
404 if (s->pid && !custom(s, c))
405 kill(s->pid, sig);
406 return 1;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000407}
408
Denis Vlasenko06af2162007-02-03 17:28:39 +0000409int runsv_main(int argc, char **argv);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000410int runsv_main(int argc, char **argv)
411{
412 struct stat s;
413 int fd;
414 int r;
415 char buf[256];
416
417 if (!argv[1] || argv[2]) usage();
418 dir = argv[1];
419
Denis Vlasenko5a6aedd2007-05-26 16:44:20 +0000420 xpipe(selfpipe);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000421 coe(selfpipe[0]);
422 coe(selfpipe[1]);
423 ndelay_on(selfpipe[0]);
424 ndelay_on(selfpipe[1]);
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000425
Denis Vlasenko8c783952007-01-27 22:21:52 +0000426 sig_block(SIGCHLD);
427 sig_catch(SIGCHLD, s_child);
428 sig_block(SIGTERM);
429 sig_catch(SIGTERM, s_term);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000430
431 xchdir(dir);
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000432 /* bss: svd[0].pid = 0; */
433 if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */
434 if (C_NOOP) svd[0].ctrl = C_NOOP;
435 if (W_UP) svd[0].want = W_UP;
436 /* bss: svd[0].islog = 0; */
437 /* bss: svd[1].pid = 0; */
Denis Vlasenko04c63862006-11-17 18:58:49 +0000438 taia_now(&svd[0].start);
439 if (stat("down", &s) != -1) svd[0].want = W_DOWN;
440
441 if (stat("log", &s) == -1) {
442 if (errno != ENOENT)
443 warn_cannot("stat ./log");
444 } else {
445 if (!S_ISDIR(s.st_mode))
446 warnx_cannot("stat log/down: log is not a directory");
447 else {
448 haslog = 1;
449 svd[1].state = S_DOWN;
450 svd[1].ctrl = C_NOOP;
451 svd[1].want = W_UP;
452 svd[1].islog = 1;
453 taia_now(&svd[1].start);
454 if (stat("log/down", &s) != -1)
455 svd[1].want = W_DOWN;
Denis Vlasenko5a6aedd2007-05-26 16:44:20 +0000456 xpipe(logpipe);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000457 coe(logpipe[0]);
458 coe(logpipe[1]);
459 }
460 }
461
462 if (mkdir("supervise", 0700) == -1) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000463 r = readlink("supervise", buf, sizeof(buf));
Denis Vlasenko04c63862006-11-17 18:58:49 +0000464 if (r != -1) {
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000465 if (r == sizeof(buf))
466 fatal2x_cannot("readlink ./supervise", ": name too long");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000467 buf[r] = 0;
468 mkdir(buf, 0700);
469 } else {
470 if ((errno != ENOENT) && (errno != EINVAL))
471 fatal_cannot("readlink ./supervise");
472 }
473 }
474 svd[0].fdlock = xopen3("log/supervise/lock"+4,
475 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
476 if (lock_exnb(svd[0].fdlock) == -1)
477 fatal_cannot("lock supervise/lock");
478 coe(svd[0].fdlock);
479 if (haslog) {
480 if (mkdir("log/supervise", 0700) == -1) {
481 r = readlink("log/supervise", buf, 256);
482 if (r != -1) {
483 if (r == 256)
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000484 fatal2x_cannot("readlink ./log/supervise", ": name too long");
Denis Vlasenko04c63862006-11-17 18:58:49 +0000485 buf[r] = 0;
486 fd = xopen(".", O_RDONLY|O_NDELAY);
487 xchdir("./log");
488 mkdir(buf, 0700);
489 if (fchdir(fd) == -1)
490 fatal_cannot("change back to service directory");
491 close(fd);
492 }
493 else {
494 if ((errno != ENOENT) && (errno != EINVAL))
495 fatal_cannot("readlink ./log/supervise");
496 }
497 }
498 svd[1].fdlock = xopen3("log/supervise/lock",
499 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
500 if (lock_ex(svd[1].fdlock) == -1)
501 fatal_cannot("lock log/supervise/lock");
502 coe(svd[1].fdlock);
503 }
504
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000505 mkfifo("log/supervise/control"+4, 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000506 svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
507 coe(svd[0].fdcontrol);
508 svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
509 coe(svd[0].fdcontrolwrite);
510 update_status(&svd[0]);
511 if (haslog) {
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000512 mkfifo("log/supervise/control", 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000513 svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
514 coe(svd[1].fdcontrol);
515 svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
516 coe(svd[1].fdcontrolwrite);
517 update_status(&svd[1]);
518 }
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000519 mkfifo("log/supervise/ok"+4, 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000520 fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
521 coe(fd);
522 if (haslog) {
Denis Vlasenkoe2473f82007-01-27 22:22:17 +0000523 mkfifo("log/supervise/ok", 0600);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000524 fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY);
525 coe(fd);
526 }
527 for (;;) {
528 iopause_fd x[3];
529 struct taia deadline;
530 struct taia now;
531 char ch;
532
533 if (haslog)
534 if (!svd[1].pid && svd[1].want == W_UP)
535 startservice(&svd[1]);
536 if (!svd[0].pid)
537 if (svd[0].want == W_UP || svd[0].state == S_FINISH)
538 startservice(&svd[0]);
539
540 x[0].fd = selfpipe[0];
541 x[0].events = IOPAUSE_READ;
542 x[1].fd = svd[0].fdcontrol;
543 x[1].events = IOPAUSE_READ;
544 if (haslog) {
545 x[2].fd = svd[1].fdcontrol;
546 x[2].events = IOPAUSE_READ;
547 }
548 taia_now(&now);
549 taia_uint(&deadline, 3600);
550 taia_add(&deadline, &now, &deadline);
551
Denis Vlasenko8c783952007-01-27 22:21:52 +0000552 sig_unblock(SIGTERM);
553 sig_unblock(SIGCHLD);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000554 iopause(x, 2+haslog, &deadline, &now);
Denis Vlasenko8c783952007-01-27 22:21:52 +0000555 sig_block(SIGTERM);
556 sig_block(SIGCHLD);
Denis Vlasenko04c63862006-11-17 18:58:49 +0000557
558 while (read(selfpipe[0], &ch, 1) == 1)
559 ;
560 for (;;) {
561 int child;
562 int wstat;
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000563
Denis Vlasenko04c63862006-11-17 18:58:49 +0000564 child = wait_nohang(&wstat);
565 if (!child) break;
566 if ((child == -1) && (errno != EINTR)) break;
567 if (child == svd[0].pid) {
568 svd[0].pid = 0;
569 pidchanged = 1;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000570 svd[0].ctrl &=~ C_TERM;
Denis Vlasenkod0762e32007-02-18 11:07:43 +0000571 if (svd[0].state != S_FINISH) {
Denis Vlasenko04c63862006-11-17 18:58:49 +0000572 fd = open_read("finish");
573 if (fd != -1) {
574 close(fd);
575 svd[0].state = S_FINISH;
576 update_status(&svd[0]);
577 continue;
578 }
Denis Vlasenkod0762e32007-02-18 11:07:43 +0000579 }
Denis Vlasenko04c63862006-11-17 18:58:49 +0000580 svd[0].state = S_DOWN;
581 taia_uint(&deadline, 1);
582 taia_add(&deadline, &svd[0].start, &deadline);
583 taia_now(&svd[0].start);
584 update_status(&svd[0]);
585 if (taia_less(&svd[0].start, &deadline)) sleep(1);
586 }
587 if (haslog) {
588 if (child == svd[1].pid) {
589 svd[1].pid = 0;
590 pidchanged = 1;
591 svd[1].state = S_DOWN;
Denis Vlasenko3aba6662007-03-09 22:46:06 +0000592 svd[1].ctrl &= ~C_TERM;
Denis Vlasenko04c63862006-11-17 18:58:49 +0000593 taia_uint(&deadline, 1);
594 taia_add(&deadline, &svd[1].start, &deadline);
595 taia_now(&svd[1].start);
596 update_status(&svd[1]);
597 if (taia_less(&svd[1].start, &deadline)) sleep(1);
598 }
599 }
600 }
601 if (read(svd[0].fdcontrol, &ch, 1) == 1)
602 ctrl(&svd[0], ch);
603 if (haslog)
604 if (read(svd[1].fdcontrol, &ch, 1) == 1)
605 ctrl(&svd[1], ch);
606
607 if (sigterm) {
608 ctrl(&svd[0], 'x');
609 sigterm = 0;
610 }
611
612 if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) {
613 if (svd[1].pid == 0)
614 _exit(0);
615 if (svd[1].want != W_EXIT) {
616 svd[1].want = W_EXIT;
617 /* stopservice(&svd[1]); */
618 update_status(&svd[1]);
619 close(logpipe[1]);
620 close(logpipe[0]);
621 //if (close(logpipe[1]) == -1)
622 // warn_cannot("close logpipe[1]");
623 //if (close(logpipe[0]) == -1)
624 // warn_cannot("close logpipe[0]");
625 }
626 }
627 }
628 /* not reached */
629 return 0;
630}