Add reinit support to init(8).

This commit is contained in:
Jonas 'Sortie' Termansen 2023-06-08 01:23:56 +02:00
parent d671516e9c
commit 9d4eec4267
9 changed files with 75 additions and 30 deletions

View File

@ -274,6 +274,8 @@ Request system reboot, normally sent by
.It Dv SIGQUIT .It Dv SIGQUIT
Request system halt, normally sent by Request system halt, normally sent by
.Xr halt 8 . .Xr halt 8 .
.It Dv SIGHUP
Request system reinitialization.
.El .El
.Sh EXIT STATUS .Sh EXIT STATUS
.Nm .Nm

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011-2022 Jonas 'Sortie' Termansen. * Copyright (c) 2011-2023 Jonas 'Sortie' Termansen.
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -322,6 +322,7 @@ static void signal_handler(int signum)
case SIGINT: caught_exit_signal = 1; break; case SIGINT: caught_exit_signal = 1; break;
case SIGTERM: caught_exit_signal = 0; break; case SIGTERM: caught_exit_signal = 0; break;
case SIGQUIT: caught_exit_signal = 2; break; case SIGQUIT: caught_exit_signal = 2; break;
case SIGHUP: caught_exit_signal = 3; break;
} }
} }
@ -331,11 +332,13 @@ static void install_signal_handler(void)
sigaddset(&handled_signals, SIGINT); sigaddset(&handled_signals, SIGINT);
sigaddset(&handled_signals, SIGQUIT); sigaddset(&handled_signals, SIGQUIT);
sigaddset(&handled_signals, SIGTERM); sigaddset(&handled_signals, SIGTERM);
sigaddset(&handled_signals, SIGHUP);
sigprocmask(SIG_BLOCK, &handled_signals, NULL); sigprocmask(SIG_BLOCK, &handled_signals, NULL);
struct sigaction sa = { .sa_handler = signal_handler, .sa_flags = 0 }; struct sigaction sa = { .sa_handler = signal_handler, .sa_flags = 0 };
sigaction(SIGINT, &sa, NULL); sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL); sigaction(SIGTERM, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
} }
static void uninstall_signal_handler(void) static void uninstall_signal_handler(void)
@ -346,6 +349,7 @@ static void uninstall_signal_handler(void)
sigaction(SIGINT, &sa, NULL); sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL); sigaction(SIGTERM, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigprocmask(SIG_UNBLOCK, &handled_signals, NULL); sigprocmask(SIG_UNBLOCK, &handled_signals, NULL);
} }
@ -1596,7 +1600,7 @@ static bool daemon_is_failed(struct daemon* daemon)
WEXITSTATUS(daemon->exit_code) != 0; WEXITSTATUS(daemon->exit_code) != 0;
case EXIT_CODE_MEANING_POWEROFF_REBOOT: case EXIT_CODE_MEANING_POWEROFF_REBOOT:
return !WIFEXITED(daemon->exit_code) || return !WIFEXITED(daemon->exit_code) ||
3 <= WEXITSTATUS(daemon->exit_code); 4 <= WEXITSTATUS(daemon->exit_code);
} }
return true; return true;
} }
@ -2340,6 +2344,8 @@ static void init(void)
log_status("stopped", "Rebooting...\n"); log_status("stopped", "Rebooting...\n");
else if ( caught_exit_signal == 2 ) else if ( caught_exit_signal == 2 )
log_status("stopped", "Halting...\n"); log_status("stopped", "Halting...\n");
else if ( caught_exit_signal == 3 )
log_status("stopped", "Reinitializing...\n");
else else
log_status("stopped", "Exiting %i...\n", caught_exit_signal); log_status("stopped", "Exiting %i...\n", caught_exit_signal);
if ( default_daemon->state != DAEMON_STATE_FINISHING && if ( default_daemon->state != DAEMON_STATE_FINISHING &&
@ -2542,7 +2548,11 @@ static void init(void)
sigprocmask(SIG_SETMASK, &saved_mask, NULL); sigprocmask(SIG_SETMASK, &saved_mask, NULL);
if ( default_daemon_exit_code != -1 ) if ( default_daemon_exit_code != -1 )
daemon_find_by_name("default")->exit_code = default_daemon_exit_code; {
struct daemon* default_daemon = daemon_find_by_name("default");
default_daemon->exit_code = default_daemon_exit_code;
default_daemon->exit_code_meaning = EXIT_CODE_MEANING_POWEROFF_REBOOT;
}
} }
static void write_random_seed(void) static void write_random_seed(void)
@ -3366,6 +3376,14 @@ static void niht(void)
} }
} }
static void reinit(void)
{
niht();
const char* argv[] = { "init", NULL };
execv("/sbin/init", (char* const*) argv);
fatal("Failed to load init during reinit: %s: %m", argv[0]);
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
main_pid = getpid(); main_pid = getpid();
@ -3659,11 +3677,8 @@ int main(int argc, char* argv[])
else if ( !WIFEXITED(status) ) else if ( !WIFEXITED(status) )
fatal("Automatic upgrade failed: Unexpected unusual termination"); fatal("Automatic upgrade failed: Unexpected unusual termination");
// Soft reinit into the freshly upgraded operating system. // Soft reinit into the freshly upgraded operating system.
niht();
// TODO: Use next_argv here. // TODO: Use next_argv here.
const char* argv[] = { "init", NULL }; reinit();
execv("/sbin/init", (char* const*) argv);
fatal("Failed to load init during reinit: %s: %m", argv[0]);
} }
// TODO: Use the arguments to specify additional things the default daemon // TODO: Use the arguments to specify additional things the default daemon
@ -3677,6 +3692,13 @@ int main(int argc, char* argv[])
// Initialize the operating system. // Initialize the operating system.
init(); init();
// Reinitialize the operating system if requested.
if ( default_daemon->exit_code_meaning ==
EXIT_CODE_MEANING_POWEROFF_REBOOT &&
WIFEXITED(default_daemon->exit_code) &&
WEXITSTATUS(default_daemon->exit_code) == 3 )
reinit();
// Finish with the exit code of the default daemon. // Finish with the exit code of the default daemon.
return exit_code_to_exit_status(default_daemon->exit_code); return exit_code_to_exit_status(default_daemon->exit_code);
} }

View File

@ -49,6 +49,8 @@ exit asking for powering off the computer
exit asking for rebooting the computer exit asking for rebooting the computer
.It halt .It halt
exit asking for halting the computer exit asking for halting the computer
.It reinit
exit asking for reinitializing the system
.El .El
.Sh SECURITY .Sh SECURITY
There is currently no method to confirm the login screen is in fact real other There is currently no method to confirm the login screen is in fact real other
@ -87,7 +89,8 @@ fallback session script run upon login (see
.Sh EXIT STATUS .Sh EXIT STATUS
.Nm login .Nm login
exits 0 if the computer should power off, exits 1 if the computer should exits 0 if the computer should power off, exits 1 if the computer should
reboot, or exits 2 on fatal failure and the boot should halt. reboot, exits 2 on fatal failure and the boot should halt, or exits 3 if the
system should reinitialize.
.Sh SEE ALSO .Sh SEE ALSO
.Xr passwd 1 , .Xr passwd 1 ,
.Xr crypt_checkpass 3 , .Xr crypt_checkpass 3 ,

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2015, 2018, 2022 Jonas 'Sortie' Termansen. * Copyright (c) 2014, 2015, 2018, 2022, 2023 Jonas 'Sortie' Termansen.
* Copyright (c) 2023 dzwdz. * Copyright (c) 2023 dzwdz.
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
@ -341,6 +341,8 @@ bool parse_username(const char* input,
return *action = SPECIAL_ACTION_REBOOT, true; return *action = SPECIAL_ACTION_REBOOT, true;
else if ( !strcmp(input, "halt") ) else if ( !strcmp(input, "halt") )
return *action = SPECIAL_ACTION_HALT, true; return *action = SPECIAL_ACTION_HALT, true;
else if ( !strcmp(input, "reinit") )
return *action = SPECIAL_ACTION_REINIT, true;
// Skip leading spaces to allow logging in as special accounts. // Skip leading spaces to allow logging in as special accounts.
while ( isspace(*input) ) while ( isspace(*input) )
@ -377,6 +379,7 @@ void handle_special(enum special_action action)
case SPECIAL_ACTION_POWEROFF: exit(0); case SPECIAL_ACTION_POWEROFF: exit(0);
case SPECIAL_ACTION_REBOOT: exit(1); case SPECIAL_ACTION_REBOOT: exit(1);
case SPECIAL_ACTION_HALT: exit(2); case SPECIAL_ACTION_HALT: exit(2);
case SPECIAL_ACTION_REINIT: exit(3);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2015 Jonas 'Sortie' Termansen. * Copyright (c) 2014, 2015, 2023 Jonas 'Sortie' Termansen.
* Copyright (c) 2023 dzwdz. * Copyright (c) 2023 dzwdz.
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
@ -42,6 +42,7 @@ enum special_action
SPECIAL_ACTION_POWEROFF, SPECIAL_ACTION_POWEROFF,
SPECIAL_ACTION_REBOOT, SPECIAL_ACTION_REBOOT,
SPECIAL_ACTION_HALT, SPECIAL_ACTION_HALT,
SPECIAL_ACTION_REINIT,
}; };
bool login(const char* username, const char* session); bool login(const char* username, const char* session);

View File

@ -284,7 +284,7 @@ These are
.Pa /etc/ssh_host_ed25519_key , .Pa /etc/ssh_host_ed25519_key ,
and and
.Pa /etc/ssh_host_rsa_key . .Pa /etc/ssh_host_rsa_key .
.It Sy finally Ns "=" Ns Oo Sy exit "|" Sy poweroff "|" Sy reboot "|" Sy halt "|" Sy boot Oc ( default Sy boot ) .It Sy finally Ns "=" Ns Oo Sy exit "|" Sy poweroff "|" Sy reboot "|" Sy halt "|" Sy boot "|" Sy chroot Oc ( default Sy boot )
What action should be taken when the installation is finished? What action should be taken when the installation is finished?
.Pp .Pp
The The

View File

@ -222,8 +222,9 @@ Any other exit means the daemon failed.
The The
.Sy poweroff-reboot .Sy poweroff-reboot
meaning is that exiting 0 means the system should power off, exiting 1 means the meaning is that exiting 0 means the system should power off, exiting 1 means the
system should reboot, exiting 2 means the system should halt, and any other exit system should reboot, exiting 2 means the system should halt, exit means system
means the daemon failed. should reload its configuration and reinitialize, and any other exit means the
daemon failed.
.Pp .Pp
Daemons are considered successful if they exit by Daemons are considered successful if they exit by
.Sy SIGTERM .Sy SIGTERM

View File

@ -425,19 +425,16 @@ the new installation.
This will complete the operating system installation. This will complete the operating system installation.
Upon reboot, the new system will start normally. Upon reboot, the new system will start normally.
After powering off your system, you need to remove the installation medium and After powering off your system, you need to remove the installation medium and
if applicable restore boot priorities in your firmware. (if applicable) restore boot priorities in your firmware.
If you did not accept the bootloader, you will need to manually configure a If you did not accept the bootloader, you will need to manually configure a
bootloader to boot the new operating system. bootloader to boot the new operating system.
.Pp .Pp
You will be given the choice between powering off the system, rebooting it, You will be given the choice of directly booting into the new system without a
halting it, or directly booting the new system. reboot, powering off the system, rebooting the system, halting the system, or
.Pp chrooting into the new system.
The last option will directly boot the new system in a chroot while the live All of these options (except the
environment remains in the background. .Xr chroot 2 )
If you invoked will destroy the live environment and all files within it will be lost.
.Xr sysinstall 8
yourself, then you will be returned to your live environment shell.
Otherwise the computer will power off when the chroot environment terminates.
.Pp .Pp
This is a last chance to make modifications before the new system boots for the This is a last chance to make modifications before the new system boots for the
first time. first time.

View File

@ -1534,21 +1534,37 @@ int main(void)
while ( true ) while ( true )
{ {
prompt(input, sizeof(input), "finally", prompt(input, sizeof(input), "finally",
"What now? (poweroff/reboot/halt/boot)", "boot"); "What now? (exit/poweroff/reboot/halt/boot/chroot)", "boot");
if ( !strcasecmp(input, "poweroff") ) if ( !strcasecmp(input, "exit") )
exit(0); exit(0);
if ( !strcasecmp(input, "reboot") ) else if ( !strcasecmp(input, "poweroff") )
exit(0);
else if ( !strcasecmp(input, "reboot") )
exit(1); exit(1);
if ( !strcasecmp(input, "halt") ) else if ( !strcasecmp(input, "halt") )
exit(2); exit(2);
if ( !strcasecmp(input, "boot") ) else if ( !strcasecmp(input, "boot") )
{
if ( !access("/etc/fstab", F_OK) )
{
printf("Only a live environment can reinit installations.\n");
continue;
}
execute((const char*[]) {"mkdir", "-p", "/etc/init", NULL }, "ef");
execute((const char*[]) {"cp", "etc/fstab", "/etc/fstab", NULL },
"ef");
execute((const char*[]) {"sh", "-c",
"echo 'require chain exit-code' > "
"/etc/init/default", NULL },
"ef");
exit(3);
}
else if ( !strcasecmp(input, "chroot") )
{ {
unmount_all_but_root(); unmount_all_but_root();
unsetenv("SYSINSTALL_TARGET"); unsetenv("SYSINSTALL_TARGET");
unsetenv("SHLVL"); unsetenv("SHLVL");
unsetenv("INIT_PID"); unsetenv("INIT_PID");
// TODO: If / is a kernel ramfs, and this is a live environment,
// then uninstall the base system to save memory.
exit(execute((const char*[]) { "chroot", "-d", fs, exit(execute((const char*[]) { "chroot", "-d", fs,
"/sbin/init", NULL }, "f")); "/sbin/init", NULL }, "f"));
} }