diff --git a/init/init.8 b/init/init.8 index 04e9701f..e5d8d7f2 100644 --- a/init/init.8 +++ b/init/init.8 @@ -266,11 +266,14 @@ own log. .Sh ASYNCHRONOUS EVENTS .Bl -tag -width "SIGUSR1" .It Dv SIGTERM -Request system poweroff. +Request system poweroff, normally sent by +.Xr poweroff 8 . .It Dv SIGINT -Request system reboot. +Request system reboot, normally sent by +.Xr reboot 8 . .It Dv SIGQUIT -Request system halt. +Request system halt, normally sent by +.Xr halt 8 . .El .Sh EXIT STATUS .Nm @@ -292,7 +295,10 @@ exits with the same exit status as its target session if it terminates normally. .Xr daemon 7 , .Xr initrd 7 , .Xr kernel 7 , +.Xr halt 8 , .Xr login 8 , +.Xr poweroff 8 , +.Xr reboot 8 , .Xr sysmerge 8 , .Xr update-initrd 8 .Sh SECURITY CONSIDERATIONS diff --git a/login/graphical.c b/login/graphical.c index 94bd9ff8..ed1e5daf 100644 --- a/login/graphical.c +++ b/login/graphical.c @@ -636,6 +636,8 @@ static void keyboard_event(struct glogin* state, uint32_t codepoint) exit(0); if ( !strcmp(textbox_username.text, "reboot") ) exit(1); + if ( !strcmp(textbox_username.text, "halt") ) + exit(2); state->stage = STAGE_PASSWORD; textbox_reset(&textbox_password); break; diff --git a/login/login.8 b/login/login.8 index b52e871f..aa2a776c 100644 --- a/login/login.8 +++ b/login/login.8 @@ -44,6 +44,8 @@ alias for poweroff exit asking for powering off the computer .It reboot exit asking for rebooting the computer +.It halt +exit asking for halting the computer .El .Sh SECURITY There is currently no method to confirm the login screen is in fact real other diff --git a/login/login.c b/login/login.c index 0f085700..c7f294b5 100644 --- a/login/login.c +++ b/login/login.c @@ -349,6 +349,8 @@ int textual(void) exit(0); if ( !strcmp(username, "reboot") ) exit(1); + if ( !strcmp(username, "halt") ) + exit(2); if ( settermmode(0, pw_termmode) < 0 ) err(2, "settermmode"); diff --git a/share/man/man7/installation.7 b/share/man/man7/installation.7 index 1b7d9712..bacc7d66 100644 --- a/share/man/man7/installation.7 +++ b/share/man/man7/installation.7 @@ -357,8 +357,9 @@ if applicable restore boot priorities in your firmware. If you did not accept the bootloader, you will need to manually configure a bootloader to boot the new operating system. .Pp -You will be given the choice between powering off the system, rebooting it, or -directly booting the new system. +You will be given the choice between powering off the system, rebooting it, +halting it, or directly booting the new system. +.Pp The last option will directly boot the new system in a chroot while the live environment remains in the background. If you invoked @@ -369,10 +370,17 @@ Otherwise the computer will power off when the chroot environment terminates. Upon boot of the new system it will be configured in multi-user mode and you will be presented with a login screen. Authenticate as one of the local users and you will be given a shell. +.Pp To power off the computer login as user .Sy poweroff -and to reboot the computer login as user -.Sy reboot . +or run +.Xr poweroff 8 +after logging in. +To reboot the computer login as user +.Sy reboot +or run +.Xr reboot 8 +after logging in. .Pp The .Xr user-guide 7 diff --git a/share/man/man7/user-guide.7 b/share/man/man7/user-guide.7 index e7c5cdbf..6b66818d 100644 --- a/share/man/man7/user-guide.7 +++ b/share/man/man7/user-guide.7 @@ -24,17 +24,16 @@ This is if the system is booted in multi-user mode. This is a root shell if booted in single-user mode. .Pp -To power off from the login screen, login as user -.Sy poweroff . -To reboot, login as user -.Sy reboot . -.Pp -To power off from a single-user boot root shell, run -.Sy exit 0 -in the shell. -To reboot, run -.Sy exit 1 -in the shell. +To power off the computer login as user +.Sy poweroff +or run +.Xr poweroff 8 +after logging in. +To reboot the computer login as user +.Sy reboot +or run +.Xr reboot 8 +after logging in. .Ss Keyboard Layout The kernel has a default US keyboard layout compiled into it. .Pp diff --git a/sysinstall/sysinstall.c b/sysinstall/sysinstall.c index 69f025e5..bf2087c0 100644 --- a/sysinstall/sysinstall.c +++ b/sysinstall/sysinstall.c @@ -828,22 +828,24 @@ int main(void) while ( true ) { prompt(input, sizeof(input), - "Install " BRAND_DISTRIBUTION_NAME "? (yes/no/poweroff/reboot)", - "yes"); + "Install " BRAND_DISTRIBUTION_NAME "? " + "(yes/no/poweroff/reboot/halt)", "yes"); if ( !strcasecmp(input, "yes") ) break; else if ( !strcasecmp(input, "no") ) { text("Answer '!' to get a shell. Type !man to view the " "installation(7) manual page.\n"); - text("Alternatively, you can answer 'poweroff' or 'reboot' to " - "cancel the installation.\n"); + text("Alternatively, you can answer 'poweroff', 'reboot', or " + "'halt' to cancel the installation.\n"); continue; } else if ( !strcasecmp(input, "poweroff") ) exit(0); else if ( !strcasecmp(input, "reboot") ) exit(1); + else if ( !strcasecmp(input, "halt") ) + exit(2); else continue; } @@ -1133,17 +1135,21 @@ int main(void) text("Upon boot, you'll be greeted with a login screen. Enter your " "credentials to get a command line. Login as user 'poweroff' as " - "described in login(8) to power off the machine. After logging in, " - "type 'man user-guide' to view the introductory documentation.\n"); + "described in login(8) to power off the machine or run poweroff(8). " + "After logging in, type 'man user-guide' to view the introductory " + "documentation.\n"); text("\n"); while ( true ) { - prompt(input, sizeof(input), "What now? (poweroff/reboot/boot)", "boot"); + prompt(input, sizeof(input), + "What now? (poweroff/reboot/halt/boot)", "boot"); if ( !strcasecmp(input, "poweroff") ) exit(0); if ( !strcasecmp(input, "reboot") ) exit(1); + if ( !strcasecmp(input, "halt") ) + exit(2); if ( !strcasecmp(input, "boot") ) { unmount_all_but_root(); diff --git a/sysinstall/sysupgrade.c b/sysinstall/sysupgrade.c index 87d55595..fbadb17a 100644 --- a/sysinstall/sysupgrade.c +++ b/sysinstall/sysupgrade.c @@ -775,7 +775,7 @@ int main(void) while ( true ) { promptx(input, sizeof(input), - "Upgrade? (yes/no/poweroff/reboot)", "yes", true); + "Upgrade? (yes/no/poweroff/reboot/halt)", "yes", true); if ( !strcasecmp(input, "yes") ) break; else if ( !strcasecmp(input, "no") ) @@ -784,14 +784,16 @@ int main(void) "upgrade(7) manual page. You can edit the upgrade.conf(5) " "configuration file of the target system to change which " "upgrade operations are performed.\n"); - text("Alternatively, you can answer 'poweroff' or 'reboot' to " - "cancel the upgrade.\n"); + text("Alternatively, you can answer 'poweroff', 'reboot', or " + "'halt' or cancel the upgrade.\n"); continue; } else if ( !strcasecmp(input, "poweroff") ) exit(0); else if ( !strcasecmp(input, "reboot") ) exit(1); + else if ( !strcasecmp(input, "halt") ) + exit(2); else if ( !strcasecmp(input, "!") ) break; else @@ -928,10 +930,13 @@ int main(void) while ( true ) { - prompt(input, sizeof(input), "What now? (poweroff/reboot)", "reboot"); + prompt(input, sizeof(input), + "What now? (poweroff/reboot/halt)", "reboot"); if ( !strcasecmp(input, "poweroff") ) return 0; if ( !strcasecmp(input, "reboot") ) return 1; + if ( !strcasecmp(input, "halt") ) + return 2; } } diff --git a/utils/.gitignore b/utils/.gitignore index f1f0b59f..645b3256 100644 --- a/utils/.gitignore +++ b/utils/.gitignore @@ -20,9 +20,10 @@ env expr false find +halt head -id help +id kernelinfo kill ln @@ -35,11 +36,13 @@ mv nl pager passwd +poweroff ps pstree pwd readlink realpath +reboot rm rmdir sleep diff --git a/utils/Makefile b/utils/Makefile index 275f8a3a..a218a727 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -31,6 +31,7 @@ env \ expr \ false \ find \ +halt \ head \ help \ id \ @@ -71,6 +72,8 @@ uptime \ wc \ which \ yes \ +poweroff \ +reboot \ BINARIES=\ $(BINARIES_EXCEPT_INSTALL) \ @@ -94,6 +97,9 @@ unmount \ MANPAGES8=\ chroot.8 \ +halt.8 \ +poweroff.8 \ +reboot.8 \ unmount.8 \ all: $(BINARIES) $(SBINS) diff --git a/utils/command-not-found.c b/utils/command-not-found.c index 874527e5..510a4563 100644 --- a/utils/command-not-found.c +++ b/utils/command-not-found.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, 2016 Jonas 'Sortie' Termansen. + * Copyright (c) 2013, 2015, 2016, 2021 Jonas 'Sortie' Termansen. * Copyright (c) 2021 Juhani 'nortti' Krekelä. * * Permission to use, copy, modify, and distribute this software for any @@ -27,49 +27,11 @@ #define ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0])) -static const char* tty_name(void) -{ - int tty_fd = open("/dev/tty", O_RDONLY); - const char* result = NULL; - if ( 0 <= tty_fd ) - { - result = ttyname(tty_fd); - close(tty_fd); - } - return result ? result : "/dev/tty"; -} - static void suggest_logout(void) { fprintf(stderr, " Exiting your shell normally to logout.\n"); } -static void suggest_poweroff(void) -{ - if ( strcmp(tty_name(), "/dev/tty1") != 0 ) - fprintf(stderr, " Powering off on /dev/tty1.\n"); - else if ( getenv("LOGIN_PID") ) - { - fprintf(stderr, " Exiting your shell normally to logout.\n"); - fprintf(stderr, " Login as user 'poweroff' to power off computer.\n"); - } - else - fprintf(stderr, " Exiting your shell normally to poweroff.\n"); -} - -static void suggest_reboot(void) -{ - if ( strcmp(tty_name(), "/dev/tty1") != 0 ) - fprintf(stderr, " Rebooting on /dev/tty1.\n"); - else if ( getenv("LOGIN_PID") ) - { - fprintf(stderr, " Exiting your shell normally to logout.\n"); - fprintf(stderr, " Login as user 'reboot' to reboot computer.\n"); - } - else - fprintf(stderr, " Exiting your shell with 'exit 1' to reboot.\n"); -} - enum category { NONE, @@ -79,7 +41,6 @@ enum category MOUNT, PAGER, POWEROFF, - REBOOT, RW, SHELL, UNMOUNT, @@ -122,12 +83,9 @@ struct command commands[] = {PAGER, "more", NULL, NULL}, {PAGER, "pager", "system", NULL}, - {POWEROFF, "halt", NULL, NULL}, - {POWEROFF, "poweroff", NULL, suggest_poweroff}, + {POWEROFF, "poweroff", "system", NULL}, {POWEROFF, "shutdown", NULL, NULL}, - {REBOOT, "reboot", NULL, suggest_reboot}, - {RW, "dd", NULL, NULL}, {RW, "rw", "system", NULL}, diff --git a/utils/halt.8 b/utils/halt.8 new file mode 100644 index 00000000..ccdd9c0b --- /dev/null +++ b/utils/halt.8 @@ -0,0 +1,20 @@ +.Dd December 13, 2021 +.Dt HALT 8 +.Os +.Sh NAME +.Nm halt +.Nd halt the computer +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +gracefully halts the computer by sending a request to the appropriate +.Xr init 8 +process. +.Sh EXIT STATUS +.Nm +will exit 0 on success and non-zero otherwise. +.Sh SEE ALSO +.Xr init 8 , +.Xr poweroff 8 , +.Xr reboot 8 diff --git a/utils/halt.c b/utils/halt.c new file mode 100644 index 00000000..133f8c2b --- /dev/null +++ b/utils/halt.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021, 2022 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * halt.c + * Halts the computer. + */ + +#include + +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + int opt; + while ( (opt = getopt(argc, argv, "")) != -1 ) + { + switch ( opt ) + { + default: return 1; + } + } + + if ( optind < argc ) + errx(1, "extra operand: %s", argv[optind]); + + pid_t init_pid = 1; + // TODO: Use a more reliable getinit() approach that also works in sshd. + if ( getenv("INIT_PID") ) + init_pid = atoll(getenv("INIT_PID")); + + if ( kill(init_pid, SIGQUIT) < 0 ) + err(1, "kill: %" PRIdPID, init_pid); + + return 0; +} diff --git a/utils/poweroff.8 b/utils/poweroff.8 new file mode 100644 index 00000000..1279b01f --- /dev/null +++ b/utils/poweroff.8 @@ -0,0 +1,20 @@ +.Dd December 13, 2021 +.Dt POWEROFF 8 +.Os +.Sh NAME +.Nm poweroff +.Nd power off the computer +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +gracefully powers off the computer by sending a request to the appropriate +.Xr init 8 +process. +.Sh EXIT STATUS +.Nm +will exit 0 on success and non-zero otherwise. +.Sh SEE ALSO +.Xr halt 8 , +.Xr init 8 , +.Xr reboot 8 diff --git a/utils/poweroff.c b/utils/poweroff.c new file mode 100644 index 00000000..9e26762b --- /dev/null +++ b/utils/poweroff.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021, 2022 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * poweroff.c + * Powers off the computer. + */ + +#include + +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + int opt; + while ( (opt = getopt(argc, argv, "")) != -1 ) + { + switch ( opt ) + { + default: return 1; + } + } + + if ( optind < argc ) + errx(1, "extra operand: %s", argv[optind]); + + pid_t init_pid = 1; + // TODO: Use a more reliable getinit() approach that also works in sshd. + if ( getenv("INIT_PID") ) + init_pid = atoll(getenv("INIT_PID")); + + if ( kill(init_pid, SIGTERM) < 0 ) + err(1, "kill: %" PRIdPID, init_pid); + + return 0; +} diff --git a/utils/reboot.8 b/utils/reboot.8 new file mode 100644 index 00000000..942fd553 --- /dev/null +++ b/utils/reboot.8 @@ -0,0 +1,20 @@ +.Dd December 13, 2021 +.Dt REBOOT 8 +.Os +.Sh NAME +.Nm reboot +.Nd reboot the computer +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +gracefully reboots the computer by sending a request to the appropriate +.Xr init 8 +process. +.Sh EXIT STATUS +.Nm +will exit 0 on success and non-zero otherwise. +.Sh SEE ALSO +.Xr halt 8 , +.Xr init 8 , +.Xr poweroff 8 diff --git a/utils/reboot.c b/utils/reboot.c new file mode 100644 index 00000000..ec374026 --- /dev/null +++ b/utils/reboot.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021, 2022 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * reboot.c + * Reboots the computer. + */ + +#include + +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + int opt; + while ( (opt = getopt(argc, argv, "")) != -1 ) + { + switch ( opt ) + { + default: return 1; + } + } + + if ( optind < argc ) + errx(1, "extra operand: %s", argv[optind]); + + pid_t init_pid = 1; + // TODO: Use a more reliable getinit() approach that also works in sshd. + if ( getenv("INIT_PID") ) + init_pid = atoll(getenv("INIT_PID")); + + if ( kill(init_pid, SIGINT) < 0 ) + err(1, "kill: %" PRIdPID, init_pid); + + return 0; +}