78 |
int pid; |
int pid; |
79 |
smallint state; |
smallint state; |
80 |
smallint ctrl; |
smallint ctrl; |
81 |
smallint want; |
smallint sd_want; |
82 |
smallint islog; |
smallint islog; |
83 |
struct timespec start; |
struct timespec start; |
84 |
int fdlock; |
int fdlock; |
85 |
int fdcontrol; |
int fdcontrol; |
86 |
int fdcontrolwrite; |
int fdcontrolwrite; |
87 |
|
int wstat; |
88 |
}; |
}; |
89 |
|
|
90 |
struct globals { |
struct globals { |
139 |
write(selfpipe.wr, "", 1); /* XXX */ |
write(selfpipe.wr, "", 1); /* XXX */ |
140 |
} |
} |
141 |
|
|
142 |
static char *add_str(char *p, const char *to_add) |
/* libbb candidate */ |
143 |
|
static char *bb_stpcpy(char *p, const char *to_add) |
144 |
{ |
{ |
145 |
while ((*p = *to_add) != '\0') { |
while ((*p = *to_add) != '\0') { |
146 |
p++; |
p++; |
191 |
char *p = stat_buf; |
char *p = stat_buf; |
192 |
switch (s->state) { |
switch (s->state) { |
193 |
case S_DOWN: |
case S_DOWN: |
194 |
p = add_str(p, "down"); |
p = bb_stpcpy(p, "down"); |
195 |
break; |
break; |
196 |
case S_RUN: |
case S_RUN: |
197 |
p = add_str(p, "run"); |
p = bb_stpcpy(p, "run"); |
198 |
break; |
break; |
199 |
case S_FINISH: |
case S_FINISH: |
200 |
p = add_str(p, "finish"); |
p = bb_stpcpy(p, "finish"); |
201 |
break; |
break; |
202 |
} |
} |
203 |
if (s->ctrl & C_PAUSE) p = add_str(p, ", paused"); |
if (s->ctrl & C_PAUSE) |
204 |
if (s->ctrl & C_TERM) p = add_str(p, ", got TERM"); |
p = bb_stpcpy(p, ", paused"); |
205 |
|
if (s->ctrl & C_TERM) |
206 |
|
p = bb_stpcpy(p, ", got TERM"); |
207 |
if (s->state != S_DOWN) |
if (s->state != S_DOWN) |
208 |
switch (s->want) { |
switch (s->sd_want) { |
209 |
case W_DOWN: |
case W_DOWN: |
210 |
p = add_str(p, ", want down"); |
p = bb_stpcpy(p, ", want down"); |
211 |
break; |
break; |
212 |
case W_EXIT: |
case W_EXIT: |
213 |
p = add_str(p, ", want exit"); |
p = bb_stpcpy(p, ", want exit"); |
214 |
break; |
break; |
215 |
} |
} |
216 |
*p++ = '\n'; |
*p++ = '\n'; |
228 |
status.pid_le32 = SWAP_LE32(s->pid); |
status.pid_le32 = SWAP_LE32(s->pid); |
229 |
if (s->ctrl & C_PAUSE) |
if (s->ctrl & C_PAUSE) |
230 |
status.paused = 1; |
status.paused = 1; |
231 |
if (s->want == W_UP) |
if (s->sd_want == W_UP) |
232 |
status.want = 'u'; |
status.want = 'u'; |
233 |
else |
else |
234 |
status.want = 'd'; |
status.want = 'd'; |
255 |
int w; |
int w; |
256 |
char a[10]; |
char a[10]; |
257 |
struct stat st; |
struct stat st; |
|
char *prog[2]; |
|
258 |
|
|
259 |
if (s->islog) return 0; |
if (s->islog) |
260 |
|
return 0; |
261 |
strcpy(a, "control/?"); |
strcpy(a, "control/?"); |
262 |
a[8] = c; /* replace '?' */ |
a[8] = c; /* replace '?' */ |
263 |
if (stat(a, &st) == 0) { |
if (stat(a, &st) == 0) { |
267 |
warn_cannot("vfork for control/?"); |
warn_cannot("vfork for control/?"); |
268 |
return 0; |
return 0; |
269 |
} |
} |
270 |
if (!pid) { |
if (pid == 0) { |
271 |
/* child */ |
/* child */ |
272 |
if (haslog && dup2(logpipe.wr, 1) == -1) |
if (haslog && dup2(logpipe.wr, 1) == -1) |
273 |
warn_cannot("setup stdout for control/?"); |
warn_cannot("setup stdout for control/?"); |
274 |
prog[0] = a; |
execl(a, a, (char *) NULL); |
|
prog[1] = NULL; |
|
|
execv(a, prog); |
|
275 |
fatal_cannot("run control/?"); |
fatal_cannot("run control/?"); |
276 |
} |
} |
277 |
/* parent */ |
/* parent */ |
278 |
while (safe_waitpid(pid, &w, 0) == -1) { |
if (safe_waitpid(pid, &w, 0) == -1) { |
279 |
warn_cannot("wait for child control/?"); |
warn_cannot("wait for child control/?"); |
280 |
return 0; |
return 0; |
281 |
} |
} |
282 |
return !wait_exitcode(w); |
return WEXITSTATUS(w) == 0; |
283 |
} |
} |
284 |
} else { |
} else { |
285 |
if (errno != ENOENT) |
if (errno != ENOENT) |
295 |
s->ctrl |= C_TERM; |
s->ctrl |= C_TERM; |
296 |
update_status(s); |
update_status(s); |
297 |
} |
} |
298 |
if (s->want == W_DOWN) { |
if (s->sd_want == W_DOWN) { |
299 |
kill(s->pid, SIGCONT); |
kill(s->pid, SIGCONT); |
300 |
custom(s, 'd'); |
custom(s, 'd'); |
301 |
return; |
return; |
302 |
} |
} |
303 |
if (s->want == W_EXIT) { |
if (s->sd_want == W_EXIT) { |
304 |
kill(s->pid, SIGCONT); |
kill(s->pid, SIGCONT); |
305 |
custom(s, 'x'); |
custom(s, 'x'); |
306 |
} |
} |
309 |
static void startservice(struct svdir *s) |
static void startservice(struct svdir *s) |
310 |
{ |
{ |
311 |
int p; |
int p; |
312 |
char *run[2]; |
const char *arg[4]; |
313 |
|
char exitcode[sizeof(int)*3 + 2]; |
314 |
|
|
315 |
if (s->state == S_FINISH) |
if (s->state == S_FINISH) { |
316 |
run[0] = (char*)"./finish"; |
/* Two arguments are given to ./finish. The first one is ./run exit code, |
317 |
else { |
* or -1 if ./run didnt exit normally. The second one is |
318 |
run[0] = (char*)"./run"; |
* the least significant byte of the exit status as determined by waitpid; |
319 |
|
* for instance it is 0 if ./run exited normally, and the signal number |
320 |
|
* if ./run was terminated by a signal. If runsv cannot start ./run |
321 |
|
* for some reason, the exit code is 111 and the status is 0. |
322 |
|
*/ |
323 |
|
arg[0] = "./finish"; |
324 |
|
arg[1] = "-1"; |
325 |
|
if (WIFEXITED(s->wstat)) { |
326 |
|
*utoa_to_buf(WEXITSTATUS(s->wstat), exitcode, sizeof(exitcode)) = '\0'; |
327 |
|
arg[1] = exitcode; |
328 |
|
} |
329 |
|
//arg[2] = "0"; |
330 |
|
//if (WIFSIGNALED(s->wstat)) { |
331 |
|
arg[2] = utoa(WTERMSIG(s->wstat)); |
332 |
|
//} |
333 |
|
arg[3] = NULL; |
334 |
|
} else { |
335 |
|
arg[0] = "./run"; |
336 |
|
arg[1] = NULL; |
337 |
custom(s, 'u'); |
custom(s, 'u'); |
338 |
} |
} |
|
run[1] = NULL; |
|
339 |
|
|
340 |
if (s->pid != 0) |
if (s->pid != 0) |
341 |
stopservice(s); /* should never happen */ |
stopservice(s); /* should never happen */ |
363 |
, SIG_DFL);*/ |
, SIG_DFL);*/ |
364 |
sig_unblock(SIGCHLD); |
sig_unblock(SIGCHLD); |
365 |
sig_unblock(SIGTERM); |
sig_unblock(SIGTERM); |
366 |
execvp(*run, run); |
execv(arg[0], (char**) arg); |
367 |
fatal2_cannot(s->islog ? "start log/" : "start ", *run); |
fatal2_cannot(s->islog ? "start log/" : "start ", arg[0]); |
368 |
} |
} |
369 |
/* parent */ |
/* parent */ |
370 |
if (s->state != S_FINISH) { |
if (s->state != S_FINISH) { |
383 |
|
|
384 |
switch (c) { |
switch (c) { |
385 |
case 'd': /* down */ |
case 'd': /* down */ |
386 |
s->want = W_DOWN; |
s->sd_want = W_DOWN; |
387 |
update_status(s); |
update_status(s); |
388 |
if (s->pid && s->state != S_FINISH) |
if (s->pid && s->state != S_FINISH) |
389 |
stopservice(s); |
stopservice(s); |
390 |
break; |
break; |
391 |
case 'u': /* up */ |
case 'u': /* up */ |
392 |
s->want = W_UP; |
s->sd_want = W_UP; |
393 |
update_status(s); |
update_status(s); |
394 |
if (s->pid == 0) |
if (s->pid == 0) |
395 |
startservice(s); |
startservice(s); |
397 |
case 'x': /* exit */ |
case 'x': /* exit */ |
398 |
if (s->islog) |
if (s->islog) |
399 |
break; |
break; |
400 |
s->want = W_EXIT; |
s->sd_want = W_EXIT; |
401 |
update_status(s); |
update_status(s); |
402 |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
403 |
case 't': /* sig term */ |
case 't': /* sig term */ |
418 |
case 'c': /* sig cont */ |
case 'c': /* sig cont */ |
419 |
if (s->pid && !custom(s, c)) |
if (s->pid && !custom(s, c)) |
420 |
kill(s->pid, SIGCONT); |
kill(s->pid, SIGCONT); |
421 |
if (s->ctrl & C_PAUSE) |
s->ctrl &= ~C_PAUSE; |
|
s->ctrl &= ~C_PAUSE; |
|
422 |
update_status(s); |
update_status(s); |
423 |
break; |
break; |
424 |
case 'o': /* once */ |
case 'o': /* once */ |
425 |
s->want = W_DOWN; |
s->sd_want = W_DOWN; |
426 |
update_status(s); |
update_status(s); |
427 |
if (!s->pid) |
if (!s->pid) |
428 |
startservice(s); |
startservice(s); |
463 |
|
|
464 |
INIT_G(); |
INIT_G(); |
465 |
|
|
466 |
if (!argv[1] || argv[2]) |
dir = single_argv(argv); |
|
bb_show_usage(); |
|
|
dir = argv[1]; |
|
467 |
|
|
468 |
xpiped_pair(selfpipe); |
xpiped_pair(selfpipe); |
469 |
close_on_exec_on(selfpipe.rd); |
close_on_exec_on(selfpipe.rd); |
472 |
ndelay_on(selfpipe.wr); |
ndelay_on(selfpipe.wr); |
473 |
|
|
474 |
sig_block(SIGCHLD); |
sig_block(SIGCHLD); |
475 |
bb_signals_recursive(1 << SIGCHLD, s_child); |
bb_signals_recursive_norestart(1 << SIGCHLD, s_child); |
476 |
sig_block(SIGTERM); |
sig_block(SIGTERM); |
477 |
bb_signals_recursive(1 << SIGTERM, s_term); |
bb_signals_recursive_norestart(1 << SIGTERM, s_term); |
478 |
|
|
479 |
xchdir(dir); |
xchdir(dir); |
480 |
/* bss: svd[0].pid = 0; */ |
/* bss: svd[0].pid = 0; */ |
481 |
if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */ |
if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */ |
482 |
if (C_NOOP) svd[0].ctrl = C_NOOP; |
if (C_NOOP) svd[0].ctrl = C_NOOP; |
483 |
if (W_UP) svd[0].want = W_UP; |
if (W_UP) svd[0].sd_want = W_UP; |
484 |
/* bss: svd[0].islog = 0; */ |
/* bss: svd[0].islog = 0; */ |
485 |
/* bss: svd[1].pid = 0; */ |
/* bss: svd[1].pid = 0; */ |
486 |
gettimeofday_ns(&svd[0].start); |
gettimeofday_ns(&svd[0].start); |
487 |
if (stat("down", &s) != -1) svd[0].want = W_DOWN; |
if (stat("down", &s) != -1) |
488 |
|
svd[0].sd_want = W_DOWN; |
489 |
|
|
490 |
if (stat("log", &s) == -1) { |
if (stat("log", &s) == -1) { |
491 |
if (errno != ENOENT) |
if (errno != ENOENT) |
498 |
haslog = 1; |
haslog = 1; |
499 |
svd[1].state = S_DOWN; |
svd[1].state = S_DOWN; |
500 |
svd[1].ctrl = C_NOOP; |
svd[1].ctrl = C_NOOP; |
501 |
svd[1].want = W_UP; |
svd[1].sd_want = W_UP; |
502 |
svd[1].islog = 1; |
svd[1].islog = 1; |
503 |
gettimeofday_ns(&svd[1].start); |
gettimeofday_ns(&svd[1].start); |
504 |
if (stat("log/down", &s) != -1) |
if (stat("log/down", &s) != -1) |
505 |
svd[1].want = W_DOWN; |
svd[1].sd_want = W_DOWN; |
506 |
xpiped_pair(logpipe); |
xpiped_pair(logpipe); |
507 |
close_on_exec_on(logpipe.rd); |
close_on_exec_on(logpipe.rd); |
508 |
close_on_exec_on(logpipe.wr); |
close_on_exec_on(logpipe.wr); |
580 |
char ch; |
char ch; |
581 |
|
|
582 |
if (haslog) |
if (haslog) |
583 |
if (!svd[1].pid && svd[1].want == W_UP) |
if (!svd[1].pid && svd[1].sd_want == W_UP) |
584 |
startservice(&svd[1]); |
startservice(&svd[1]); |
585 |
if (!svd[0].pid) |
if (!svd[0].pid) |
586 |
if (svd[0].want == W_UP || svd[0].state == S_FINISH) |
if (svd[0].sd_want == W_UP || svd[0].state == S_FINISH) |
587 |
startservice(&svd[0]); |
startservice(&svd[0]); |
588 |
|
|
589 |
x[0].fd = selfpipe.rd; |
x[0].fd = selfpipe.rd; |
612 |
if ((child == -1) && (errno != EINTR)) |
if ((child == -1) && (errno != EINTR)) |
613 |
break; |
break; |
614 |
if (child == svd[0].pid) { |
if (child == svd[0].pid) { |
615 |
|
svd[0].wstat = wstat; |
616 |
svd[0].pid = 0; |
svd[0].pid = 0; |
617 |
pidchanged = 1; |
pidchanged = 1; |
618 |
svd[0].ctrl &=~ C_TERM; |
svd[0].ctrl &= ~C_TERM; |
619 |
if (svd[0].state != S_FINISH) { |
if (svd[0].state != S_FINISH) { |
620 |
fd = open_read("finish"); |
fd = open_read("finish"); |
621 |
if (fd != -1) { |
if (fd != -1) { |
634 |
} |
} |
635 |
if (haslog) { |
if (haslog) { |
636 |
if (child == svd[1].pid) { |
if (child == svd[1].pid) { |
637 |
|
svd[0].wstat = wstat; |
638 |
svd[1].pid = 0; |
svd[1].pid = 0; |
639 |
pidchanged = 1; |
pidchanged = 1; |
640 |
svd[1].state = S_DOWN; |
svd[1].state = S_DOWN; |
658 |
sigterm = 0; |
sigterm = 0; |
659 |
} |
} |
660 |
|
|
661 |
if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) { |
if (svd[0].sd_want == W_EXIT && svd[0].state == S_DOWN) { |
662 |
if (svd[1].pid == 0) |
if (svd[1].pid == 0) |
663 |
_exit(EXIT_SUCCESS); |
_exit(EXIT_SUCCESS); |
664 |
if (svd[1].want != W_EXIT) { |
if (svd[1].sd_want != W_EXIT) { |
665 |
svd[1].want = W_EXIT; |
svd[1].sd_want = W_EXIT; |
666 |
/* stopservice(&svd[1]); */ |
/* stopservice(&svd[1]); */ |
667 |
update_status(&svd[1]); |
update_status(&svd[1]); |
668 |
close(logpipe.wr); |
close(logpipe.wr); |