diff --git a/init/init.8 b/init/init.8 index 7f64439d..74efc369 100644 --- a/init/init.8 +++ b/init/init.8 @@ -40,22 +40,32 @@ option if specified or otherwise. Supported targets are: .Pp .Bl -tag -width "single-user" -compact -offset indent -.It chain +.It Sy chain mount real root filesystem and run its -.Nm -.It chain-merge -complete a +.Nm . +.It Sy chain-merge +like +.Sy chain +but run +.Pa /sysmerge/sbin/init +with the +.Sy merge +target. +.It Sy merge +finish a .Xr sysmerge 8 -upgrade during a chain boot -.It multi-user +upgrade and then execute the real +.Nm +with its default target. +.It Sy multi-user boot to -.Xr login 8 -.It single-user -boot to root shell without password (not secure) -.It sysinstall -boot to operating system installer (not secure) -.It sysupgrade -boot to operating system upgrader (not secure) +.Xr login 8 . +.It Sy single-user +boot to root shell without password (not secure). +.It Sy sysinstall +boot to operating system installer (not secure). +.It Sy sysupgrade +boot to operating system upgrader (not secure). .El .Pp It is a full system compromise if unauthenticated users are able to boot the @@ -72,7 +82,9 @@ will scan every block device for valid partition tables and create the corresponding partition devices in .Pa /dev . .Ss Chain Initialization -The chain target mounts the root filesystem as in +The +.Sy chain +target mounts the root filesystem as in .Pa /etc/fstab (see .Xr fstab 5) and runs the next @@ -115,6 +127,20 @@ set graphics resolution (see .Nm mounts all the filesystems according to .Xr fstab 5 . +.Ss Merge +The +.Sy merge +target completes a delayed system upgrade by invoking the +.Xr sysmerge 8 +at +.Pa /sysmerge/sbin/sysmerge +with the +.Ar --booting +option. If the upgrade succeeds, the temporary +.Nm +deinitializes the system and invokes the real (now upgraded) +.Nm +which will restart system initialization in the normal fashion. .Ss Session Finally .Nm diff --git a/init/init.c b/init/init.c index bdd726fc..8db8ca78 100644 --- a/init/init.c +++ b/init/init.c @@ -756,6 +756,33 @@ static int init(const char* target) prepare_block_devices(); load_fstab(); mountpoints_mount(false); + if ( !strcmp(target, "merge") ) + { + pid_t child_pid = fork(); + if ( child_pid < 0 ) + fatal("fork: %m"); + if ( !child_pid ) + { + const char* argv[] = { "sysmerge", "--booting", NULL }; + execv("/sysmerge/sbin/sysmerge", (char* const*) argv); + fatal("Failed to run automatic update: %s: %m", argv[0]); + } + int status; + if ( waitpid(child_pid, &status, 0) < 0 ) + fatal("waitpid"); + if ( WIFEXITED(status) && WEXITSTATUS(status) != 0 ) + fatal("Automatic upgrade failed: Exit status %i", + WEXITSTATUS(status)); + else if ( WIFSIGNALED(status) ) + fatal("Automatic upgrade failed: %s", strsignal(WTERMSIG(status))); + else if ( !WIFEXITED(status) ) + fatal("Automatic upgrade failed: Unexpected unusual termination"); + niht(); + unsetenv("INIT_PID"); + const char* argv[] = { "init", NULL }; + execv("/sbin/init", (char* const*) argv); + fatal("Failed to load chain init: %s: %m", argv[0]); + } sigset_t oldset, sigttou; sigemptyset(&sigttou); sigaddset(&sigttou, SIGTTOU); @@ -891,15 +918,15 @@ static int init_chain(const char* target) fatal("chroot: %s: %m", chain_location); if ( chdir("/") < 0 ) fatal("chdir: %s: %m", chain_location); + unsetenv("INIT_PID"); if ( !strcmp(target, "chain-merge") ) { - const char* argv[] = { "sysmerge", "--booting", NULL }; - execv("/sysmerge/sbin/sysmerge", (char* const*) argv); - fatal("Failed to run automatic update: %s: %m", argv[0]); + const char* argv[] = { "init", "--target=merge", NULL }; + execv("/sysmerge/sbin/init", (char* const*) argv); + fatal("Failed to load automatic update chain init: %s: %m", argv[0]); } else { - unsetenv("INIT_PID"); const char* argv[] = { "init", NULL }; execv("/sbin/init", (char* const*) argv); fatal("Failed to load chain init: %s: %m", argv[0]); @@ -908,23 +935,10 @@ static int init_chain(const char* target) int status; if ( waitpid(child_pid, &status, 0) < 0 ) fatal("waitpid"); - const char* back = ": Trying to bring it back up again"; + // Only run an automatic update once. if ( !strcmp(target, "chain-merge") ) - { - if ( WIFEXITED(status) && WEXITSTATUS(status) == 0 ) - { - target = "chain"; - continue; - } - if ( WIFEXITED(status) ) - fatal("Automatic upgrade failed: Exit status %i", - WEXITSTATUS(status)); - else if ( WIFSIGNALED(status) ) - fatal("Automatic upgrade failed: %s", - strsignal(WTERMSIG(status))); - else - fatal("Automatic upgrade failed: Unexpected unusual termination"); - } + target = "chain"; + const char* back = ": Trying to bring it back up again"; if ( WIFEXITED(status) ) { result = WEXITSTATUS(status); @@ -1019,7 +1033,8 @@ int main(int argc, char* argv[]) if ( !strcmp(target, "single-user") || !strcmp(target, "multi-user") || !strcmp(target, "sysinstall") || - !strcmp(target, "sysupgrade") ) + !strcmp(target, "sysupgrade") || + !strcmp(target, "merge") ) return init(target); if ( !strcmp(target, "chain") || diff --git a/sysinstall/sysmerge.8 b/sysinstall/sysmerge.8 index 9d9c58ea..4e16df71 100644 --- a/sysinstall/sysmerge.8 +++ b/sysinstall/sysmerge.8 @@ -54,7 +54,7 @@ It's boot time, complete the system upgrade that was delayed. This is meant to be used by .Xr init 8 through the -.Sy chain-merge +.Sy merge boot target. This installs the .Pa /sysmerge directory onto the root filesystem and removes the