|
@@ -12,6 +12,7 @@
|
|
|
#include <unistd.h>
|
|
|
#include <fcntl.h>
|
|
|
#include <pwd.h>
|
|
|
+
|
|
|
#include "service.h"
|
|
|
#include "ev++.h"
|
|
|
#include "control.h"
|
|
@@ -19,6 +20,7 @@
|
|
|
|
|
|
#ifdef __linux__
|
|
|
#include <sys/klog.h>
|
|
|
+#include <sys/reboot.h>
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
@@ -69,12 +71,9 @@ struct ev_io control_socket_io;
|
|
|
|
|
|
// Variables
|
|
|
|
|
|
-static bool got_sigterm = false;
|
|
|
-
|
|
|
static ServiceSet *service_set;
|
|
|
|
|
|
static bool am_system_init = false; // true if we are the system init process
|
|
|
-static bool do_reboot = false; // whether to reboot (instead of halting)
|
|
|
|
|
|
static bool control_socket_open = false;
|
|
|
int active_control_conns = 0;
|
|
@@ -212,6 +211,8 @@ int main(int argc, char **argv)
|
|
|
if (am_system_init) {
|
|
|
// Disable non-critical kernel output to console
|
|
|
klogctl(6 /* SYSLOG_ACTION_CONSOLE_OFF */, nullptr, 0);
|
|
|
+ // Make ctrl+alt+del combination send SIGINT to PID 1 (this process)
|
|
|
+ reboot(RB_DISABLE_CAD);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -237,18 +238,24 @@ int main(int argc, char **argv)
|
|
|
event_loop:
|
|
|
|
|
|
// Process events until all services have terminated.
|
|
|
- while (service_set->count_active_services() != 0 || active_control_conns != 0) {
|
|
|
+ while (service_set->count_active_services() != 0) {
|
|
|
ev_loop(loop, EVLOOP_ONESHOT);
|
|
|
}
|
|
|
+
|
|
|
+ ShutdownType shutdown_type = service_set->getShutdownType();
|
|
|
|
|
|
if (am_system_init) {
|
|
|
logMsgBegin(LogLevel::INFO, "No more active services.");
|
|
|
- if (do_reboot) {
|
|
|
+
|
|
|
+ if (shutdown_type == ShutdownType::REBOOT) {
|
|
|
logMsgEnd(" Will reboot.");
|
|
|
}
|
|
|
- else if (got_sigterm) {
|
|
|
+ else if (shutdown_type == ShutdownType::HALT) {
|
|
|
logMsgEnd(" Will halt.");
|
|
|
}
|
|
|
+ else if (shutdown_type == ShutdownType::POWEROFF) {
|
|
|
+ logMsgEnd(" Will power down.");
|
|
|
+ }
|
|
|
else {
|
|
|
logMsgEnd(" Re-initiating boot sequence.");
|
|
|
}
|
|
@@ -257,28 +264,7 @@ int main(int argc, char **argv)
|
|
|
close_control_socket(ev_default_loop(EVFLAG_AUTO));
|
|
|
|
|
|
if (am_system_init) {
|
|
|
- if (do_reboot) {
|
|
|
- // Fork and execute /sbin/reboot
|
|
|
- int fres = fork();
|
|
|
- if (fres == 0) {
|
|
|
- execl("/sbin/reboot", "/sbin/reboot", (char *) 0);
|
|
|
- }
|
|
|
- else if (fres == -1) {
|
|
|
- log(LogLevel::ERROR, "Could not fork for reboot: ", strerror(errno));
|
|
|
- }
|
|
|
- }
|
|
|
- else if (got_sigterm) {
|
|
|
- // Fork and execute /sbin/halt
|
|
|
- int fres = fork();
|
|
|
- if (fres == 0) {
|
|
|
- execl("/sbin/halt", "/sbin/halt", (char *) 0);
|
|
|
- }
|
|
|
- else if (fres == -1) {
|
|
|
- log(LogLevel::ERROR, "Could not fork for halt: ", strerror(errno));
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- // Hmmmmmm.
|
|
|
+ if (shutdown_type == ShutdownType::CONTINUE) {
|
|
|
// It could be that we started in single user mode, and the
|
|
|
// user has now exited the shell. We'll try and re-start the
|
|
|
// boot process...
|
|
@@ -289,15 +275,29 @@ int main(int argc, char **argv)
|
|
|
catch (...) {
|
|
|
// Now WTF do we do? try to reboot
|
|
|
log(LogLevel::ERROR, "Could not start 'boot' service; rebooting.");
|
|
|
- if (fork() == 0) {
|
|
|
- execl("/sbin/reboot", "/sbin/reboot", (char *) 0);
|
|
|
- }
|
|
|
+ shutdown_type = ShutdownType::REBOOT;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // PID 1 should never exit:
|
|
|
+ const char * cmd_arg;
|
|
|
+ if (shutdown_type == ShutdownType::HALT) {
|
|
|
+ cmd_arg = "-h";
|
|
|
+ }
|
|
|
+ else if (shutdown_type == ShutdownType::REBOOT) {
|
|
|
+ cmd_arg = "-r";
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // power off.
|
|
|
+ cmd_arg = "-p";
|
|
|
+ }
|
|
|
+
|
|
|
+ // Fork and execute dinit-reboot.
|
|
|
+ execl("/usr/libexec/dinit-reboot", "/usr/libexec/dinit-reboot", cmd_arg, nullptr);
|
|
|
+ log(LogLevel::ERROR, "Could not execl() for reboot: ", strerror(errno));
|
|
|
+
|
|
|
+ // PID 1 must not actually exit, although we should never reach this point:
|
|
|
while (true) {
|
|
|
- pause();
|
|
|
+ ev_loop(loop, EVLOOP_ONESHOT);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -399,9 +399,8 @@ void close_control_socket(struct ev_loop *loop) noexcept
|
|
|
/* handle SIGINT signal (generated by kernel when ctrl+alt+del pressed) */
|
|
|
static void sigint_reboot_cb(struct ev_loop *loop, ev_signal *w, int revents)
|
|
|
{
|
|
|
- do_reboot = true;
|
|
|
log_to_console = true;
|
|
|
- service_set->stop_all_services();
|
|
|
+ service_set->stop_all_services(ShutdownType::REBOOT);
|
|
|
}
|
|
|
|
|
|
/* handle SIGQUIT (if we are system init) */
|
|
@@ -410,14 +409,14 @@ static void sigquit_cb(struct ev_loop *loop, ev_signal *w, int revents)
|
|
|
// This allows remounting the filesystem read-only if the dinit binary has been
|
|
|
// unlinked. In that case the kernel holds the binary open, so that it can't be
|
|
|
// properly removed.
|
|
|
+ close_control_socket(ev_default_loop(EVFLAG_AUTO));
|
|
|
execl("/sbin/shutdown", "/sbin/shutdown", (char *) 0);
|
|
|
log(LogLevel::ERROR, "Error executing /sbin/shutdown: ", strerror(errno));
|
|
|
}
|
|
|
|
|
|
-/* handle SIGTERM - stop all services */
|
|
|
+/* handle SIGTERM/SIGQUIT - stop all services (not used for system daemon) */
|
|
|
static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents)
|
|
|
{
|
|
|
- got_sigterm = true;
|
|
|
log_to_console = true;
|
|
|
service_set->stop_all_services();
|
|
|
}
|