int pid;
smallint state;
smallint ctrl;
- smallint want;
+ smallint sd_want;
smallint islog;
struct timespec start;
int fdlock;
int fdcontrol;
int fdcontrolwrite;
+ int wstat;
};
struct globals {
write(selfpipe.wr, "", 1); /* XXX */
}
-static char *add_str(char *p, const char *to_add)
+/* libbb candidate */
+static char *bb_stpcpy(char *p, const char *to_add)
{
while ((*p = *to_add) != '\0') {
p++;
char *p = stat_buf;
switch (s->state) {
case S_DOWN:
- p = add_str(p, "down");
+ p = bb_stpcpy(p, "down");
break;
case S_RUN:
- p = add_str(p, "run");
+ p = bb_stpcpy(p, "run");
break;
case S_FINISH:
- p = add_str(p, "finish");
+ p = bb_stpcpy(p, "finish");
break;
}
- if (s->ctrl & C_PAUSE) p = add_str(p, ", paused");
- if (s->ctrl & C_TERM) p = add_str(p, ", got TERM");
+ if (s->ctrl & C_PAUSE)
+ p = bb_stpcpy(p, ", paused");
+ if (s->ctrl & C_TERM)
+ p = bb_stpcpy(p, ", got TERM");
if (s->state != S_DOWN)
- switch (s->want) {
+ switch (s->sd_want) {
case W_DOWN:
- p = add_str(p, ", want down");
+ p = bb_stpcpy(p, ", want down");
break;
case W_EXIT:
- p = add_str(p, ", want exit");
+ p = bb_stpcpy(p, ", want exit");
break;
}
*p++ = '\n';
status.pid_le32 = SWAP_LE32(s->pid);
if (s->ctrl & C_PAUSE)
status.paused = 1;
- if (s->want == W_UP)
+ if (s->sd_want == W_UP)
status.want = 'u';
else
status.want = 'd';
warn_cannot("vfork for control/?");
return 0;
}
- if (!pid) {
+ if (pid == 0) {
/* child */
if (haslog && dup2(logpipe.wr, 1) == -1)
warn_cannot("setup stdout for control/?");
s->ctrl |= C_TERM;
update_status(s);
}
- if (s->want == W_DOWN) {
+ if (s->sd_want == W_DOWN) {
kill(s->pid, SIGCONT);
custom(s, 'd');
return;
}
- if (s->want == W_EXIT) {
+ if (s->sd_want == W_EXIT) {
kill(s->pid, SIGCONT);
custom(s, 'x');
}
static void startservice(struct svdir *s)
{
int p;
- const char *run;
-
- if (s->state == S_FINISH)
- run = "./finish";
- else {
- run = "./run";
+ const char *arg[4];
+ char exitcode[sizeof(int)*3 + 2];
+ char sigcode[sizeof(int)*3 + 2];
+
+ if (s->state == S_FINISH) {
+/* Two arguments are given to ./finish. The first one is ./run exit code,
+ * or -1 if ./run didnt exit normally. The second one is
+ * the least significant byte of the exit status as determined by waitpid;
+ * for instance it is 0 if ./run exited normally, and the signal number
+ * if ./run was terminated by a signal. If runsv cannot start ./run
+ * for some reason, the exit code is 111 and the status is 0.
+ */
+ arg[0] = "./finish";
+ arg[1] = "-1";
+ if (WIFEXITED(s->wstat)) {
+ sprintf(exitcode, "%u", (int) WEXITSTATUS(s->wstat));
+ arg[1] = exitcode;
+ }
+ //arg[2] = "0";
+ //if (WIFSIGNALED(s->wstat)) {
+ sprintf(sigcode, "%u", (int) WTERMSIG(s->wstat));
+ arg[2] = sigcode;
+ //}
+ arg[3] = NULL;
+ } else {
+ arg[0] = "./run";
+ arg[1] = NULL;
custom(s, 'u');
}
, SIG_DFL);*/
sig_unblock(SIGCHLD);
sig_unblock(SIGTERM);
- execl(run, run, (char *) NULL);
- fatal2_cannot(s->islog ? "start log/" : "start ", run);
+ execv(arg[0], (char**) arg);
+ fatal2_cannot(s->islog ? "start log/" : "start ", arg[0]);
}
/* parent */
if (s->state != S_FINISH) {
switch (c) {
case 'd': /* down */
- s->want = W_DOWN;
+ s->sd_want = W_DOWN;
update_status(s);
if (s->pid && s->state != S_FINISH)
stopservice(s);
break;
case 'u': /* up */
- s->want = W_UP;
+ s->sd_want = W_UP;
update_status(s);
if (s->pid == 0)
startservice(s);
case 'x': /* exit */
if (s->islog)
break;
- s->want = W_EXIT;
+ s->sd_want = W_EXIT;
update_status(s);
/* FALLTHROUGH */
case 't': /* sig term */
update_status(s);
break;
case 'o': /* once */
- s->want = W_DOWN;
+ s->sd_want = W_DOWN;
update_status(s);
if (!s->pid)
startservice(s);
/* bss: svd[0].pid = 0; */
if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */
if (C_NOOP) svd[0].ctrl = C_NOOP;
- if (W_UP) svd[0].want = W_UP;
+ if (W_UP) svd[0].sd_want = W_UP;
/* bss: svd[0].islog = 0; */
/* bss: svd[1].pid = 0; */
gettimeofday_ns(&svd[0].start);
- if (stat("down", &s) != -1) svd[0].want = W_DOWN;
+ if (stat("down", &s) != -1)
+ svd[0].sd_want = W_DOWN;
if (stat("log", &s) == -1) {
if (errno != ENOENT)
haslog = 1;
svd[1].state = S_DOWN;
svd[1].ctrl = C_NOOP;
- svd[1].want = W_UP;
+ svd[1].sd_want = W_UP;
svd[1].islog = 1;
gettimeofday_ns(&svd[1].start);
if (stat("log/down", &s) != -1)
- svd[1].want = W_DOWN;
+ svd[1].sd_want = W_DOWN;
xpiped_pair(logpipe);
close_on_exec_on(logpipe.rd);
close_on_exec_on(logpipe.wr);
char ch;
if (haslog)
- if (!svd[1].pid && svd[1].want == W_UP)
+ if (!svd[1].pid && svd[1].sd_want == W_UP)
startservice(&svd[1]);
if (!svd[0].pid)
- if (svd[0].want == W_UP || svd[0].state == S_FINISH)
+ if (svd[0].sd_want == W_UP || svd[0].state == S_FINISH)
startservice(&svd[0]);
x[0].fd = selfpipe.rd;
if ((child == -1) && (errno != EINTR))
break;
if (child == svd[0].pid) {
+ svd[0].wstat = wstat;
svd[0].pid = 0;
pidchanged = 1;
- svd[0].ctrl &=~ C_TERM;
+ svd[0].ctrl &= ~C_TERM;
if (svd[0].state != S_FINISH) {
fd = open_read("finish");
if (fd != -1) {
}
if (haslog) {
if (child == svd[1].pid) {
+ svd[0].wstat = wstat;
svd[1].pid = 0;
pidchanged = 1;
svd[1].state = S_DOWN;
sigterm = 0;
}
- if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) {
+ if (svd[0].sd_want == W_EXIT && svd[0].state == S_DOWN) {
if (svd[1].pid == 0)
_exit(EXIT_SUCCESS);
- if (svd[1].want != W_EXIT) {
- svd[1].want = W_EXIT;
+ if (svd[1].sd_want != W_EXIT) {
+ svd[1].sd_want = W_EXIT;
/* stopservice(&svd[1]); */
update_status(&svd[1]);
close(logpipe.wr);