Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -k option to shutdown for kexec functionality #436

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
5 changes: 5 additions & 0 deletions doc/manpages/shutdown.8.m4
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ Display brief help text and then exit.
Request a shutdown followed by restart. This is the default if executed as
\fB$$$SHUTDOWN_PREFIX@@@reboot\fR.
.TP
\fB\-k\fP
Shutdown the system and boot directly into a new kernel loaded via \fBkexec\fR(8),
without firmware reinitialisation. Don't forget to load a kernel image with
\fBkexec\fR(8) first!
.TP
\fB\-s\fP
Restart the service manager and all user-space services without restarting the system.
This is the default if executed as \fB$$$SHUTDOWN_PREFIX@@@soft\-reboot\fR.
Expand Down
3 changes: 2 additions & 1 deletion src/control.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ bool control_conn_t::process_packet()
}

if (contains({shutdown_type_t::REMAIN, shutdown_type_t::HALT,
shutdown_type_t::POWEROFF, shutdown_type_t::REBOOT, shutdown_type_t::SOFTREBOOT}, rbuf[1])) {
shutdown_type_t::POWEROFF, shutdown_type_t::REBOOT,
shutdown_type_t::SOFTREBOOT, shutdown_type_t::KEXEC}, rbuf[1])) {
auto sd_type = static_cast<shutdown_type_t>(rbuf[1]);

services->stop_all_services(sd_type);
Expand Down
6 changes: 6 additions & 0 deletions src/dinit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,9 @@ int dinit_main(int argc, char **argv)
else if (shutdown_type == shutdown_type_t::POWEROFF) {
log_msg_end(" Will power down.");
}
else if (shutdown_type == shutdown_type_t::KEXEC) {
log_msg_end(" Will kexec.");
}
else if (shutdown_type == shutdown_type_t::NONE) {
log_msg_end(" Will handle boot failure.");
}
Expand Down Expand Up @@ -768,6 +771,9 @@ int dinit_main(int argc, char **argv)
else if (shutdown_type == shutdown_type_t::REBOOT) {
cmd_arg = "-r";
}
else if (shutdown_type == shutdown_type_t::KEXEC) {
cmd_arg = "-k";
}
else {
// power off.
cmd_arg = "-p";
Expand Down
5 changes: 3 additions & 2 deletions src/includes/service-constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ enum class service_event_t {
};

/* Shutdown types */
enum class shutdown_type_t {
enum class shutdown_type_t: char {
NONE, // No explicit shutdown
REMAIN, // Continue running with no services
HALT, // Halt system without powering down
POWEROFF, // Power off system
REBOOT, // Reboot system
SOFTREBOOT // Reboot dinit
SOFTREBOOT, // Reboot dinit
KEXEC // Reboot with kexec (without firmware reinitialisation)
};

/* Reasons for why service stopped */
Expand Down
49 changes: 47 additions & 2 deletions src/shutdown.cc
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,24 @@ class subproc_buffer : private cpbuffer<subproc_bufsize>
}
};

static bool
reboot_cmd_unsupported(const shutdown_type_t type)
{
// weed out unsupported values
switch (type) {
#if !defined(RB_HALT_SYSTEM) && !defined(RB_HALT)
case shutdown_type_t::HALT: return true;
#endif
#ifndef RB_POWER_OFF
case shutdown_type_t::POWEROFF: return true;
#endif
#ifndef RB_KEXEC
case shutdown_type_t::KEXEC: return true;
#endif
default: return false;
}
}


int main(int argc, char **argv)
{
Expand Down Expand Up @@ -287,6 +305,9 @@ int main(int argc, char **argv)
else if (strcmp(argv[i], "-s") == 0) {
shutdown_type = shutdown_type_t::SOFTREBOOT;
}
else if (strcmp(argv[i], "-k") == 0) {
shutdown_type = shutdown_type_t::KEXEC;
}
else if (strcmp(argv[i], "--use-passed-cfd") == 0) {
use_passed_cfd = true;
}
Expand All @@ -301,13 +322,25 @@ int main(int argc, char **argv)
}
}

if (reboot_cmd_unsupported(shutdown_type)) {
cerr << "Unsupported shutdown type\n";
return 1;
}

if (show_help) {
cout << execname << " : shutdown the system\n"
" --help : show this help\n"
" -r : reboot\n"
" -s : soft-reboot (restart dinit with same boot-time arguments)\n"
#if defined(RB_HALT_SYSTEM) || defined(RB_HALT)
" -h : halt system\n"
#endif
#ifdef RB_POWER_OFF
" -p : power down (default)\n"
#endif
#ifdef RB_KEXEC
" -k : stop dinit and reboot directly into kernel loaded with kexec\n"
#endif
" --use-passed-cfd : use the socket file descriptor identified by the DINIT_CS_FD\n"
" environment variable to communicate with the init daemon.\n"
" --system : perform shutdown immediately, instead of issuing shutdown\n"
Expand All @@ -318,7 +351,7 @@ int main(int argc, char **argv)

if (sys_shutdown) {
do_system_shutdown(shutdown_type);
return 0;
return 1; // likely to cause panic; the above shouldn't return
}

signal(SIGPIPE, SIG_IGN);
Expand Down Expand Up @@ -421,6 +454,9 @@ void do_system_shutdown(shutdown_type_t shutdown_type)
#elif defined(RB_HALT)
if (shutdown_type == shutdown_type_t::HALT) reboot_type = RB_HALT;
#endif
#if defined(RB_KEXEC)
if (shutdown_type == shutdown_type_t::KEXEC) reboot_type = RB_KEXEC;
#endif

// Write to console rather than any terminal, since we lose the terminal it seems:
int consfd = open("/dev/console", O_WRONLY);
Expand Down Expand Up @@ -496,7 +532,16 @@ void do_system_shutdown(shutdown_type_t shutdown_type)

sub_buf.append("Issuing shutdown via kernel...\n");
loop.poll(); // give message a chance to get to console
reboot(reboot_type);
if (reboot(reboot_type)) {
// we're in trouble now
sub_buf.append("reboot(2): ");
sub_buf.append(strerror(errno));
sub_buf.append(
"\nThis may happen if you try to kexec without loading an image first, or if\n"
"\nsomehow a reboot type unsupported by the kernel is attempted\n"
);
loop.poll();
}
}

// Watcher for subprocess output.
Expand Down