Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions src/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,12 @@ static void bypass_shutdown(void *unused)
/*
* Handle switch_root API command.
* Parses data: "newroot\0newinit\0"
* Sends ACK before attempting switch_root since it doesn't return on success.
* Returns: result from switch_root() on failure, doesn't return on success.
* On a precheck failure, sets rq->cmd = INIT_CMD_NACK with a message and returns -1
* Returns: result from switch_root_precheck()/switch_root() on failure, doesn't return on success
*/
static int do_switch_root_api(int sd, struct init_request *rq)
{
char errbuf[sizeof(rq->data)];
char *newroot, *newinit = NULL;
char *ptr;
int result;
Expand All @@ -287,8 +288,14 @@ static int do_switch_root_api(int sd, struct init_request *rq)
newinit = ptr;
}

if (switch_root_precheck(newroot, newinit, errbuf, sizeof(errbuf))) {
rq->cmd = INIT_CMD_NACK;
snprintf(rq->data, sizeof(rq->data), "switch-root: %s", errbuf);
return -1;
}

/*
* Send ACK first, since we won't return from
* Send ACK now, since we won't return from
* switch_root() on success.
*/
rq->cmd = INIT_CMD_ACK;
Expand Down Expand Up @@ -467,6 +474,7 @@ static void api_cb(uev_t *w, void *arg, int events)
case INIT_CMD_SWITCH_ROOT:
if (runlevel != INIT_LEVEL && runlevel != 1) {
warnx("switch-root only allowed in runlevel S or 1");
result = 1;
goto done;
}
break;
Expand Down Expand Up @@ -572,8 +580,10 @@ static void api_cb(uev_t *w, void *arg, int events)
break;

case INIT_CMD_SWITCH_ROOT:
do_switch_root_api(sd, &rq);
goto leave;
result = do_switch_root_api(sd, &rq);
if (result && rq.cmd == INIT_CMD_NACK)
break; /* precheck failed before ACK, done: sends the NACK */
goto leave; /* success, or a post-ACK failure with sd already closed */

case INIT_CMD_ACK:
dbg("Client failed reading ACK");
Expand Down
2 changes: 1 addition & 1 deletion src/finit.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ static void banner(void)
#endif
}

static int sulogin(int do_reboot)
int sulogin(int do_reboot)
{
int rc = EX_OSFILE;
char *cmd[] = {
Expand Down
18 changes: 12 additions & 6 deletions src/initctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -693,10 +693,16 @@ int do_switch_root(int argc, char *argv[])
printf(" ...\n");

/*
* On success, finit exec's new init and we lose connection.
* A "failure" to read reply is actually expected on success.
*/
client_send(&rq, sizeof(rq));
* Nonzero client_send() isn't failure here, unlike do_cmd():
* success execs the new init and drops the connection. Only a real NACK means rejection
*
* Can't distinguish that from finit not running -- dead connect/write also returns nonzero with rq.cmd untouched
* Needs client_request() to signal whether anything was sent; every other caller here treats nonzero as failure
*/
if (client_send(&rq, sizeof(rq)) && rq.cmd == INIT_CMD_NACK) {
puts(rq.data);
return 1;
}

return 0;
}
Expand Down Expand Up @@ -1414,9 +1420,9 @@ static int show_status(char *arg)
snprintf(title, sizeof(title), "%-*s %-*s %-8s %-13s ",
pw, "PID", iw, "IDENT", "STATUS", "RUNLEVELS");
if (!verbose)
strlcat(title, "DESCRIPTION", sizeof(title));
strlcat(title, "DESCRIPTION", sizeof(title));
else
strlcat(title, "COMMAND", sizeof(title));
strlcat(title, "COMMAND", sizeof(title));

print_header("%s", title);
}
Expand Down
Loading