Avoid boot loop on all-service failure.
authorDavin McCall <davmac@davmac.org>
Wed, 1 May 2019 12:31:59 +0000 (22:31 +1000)
committerDavin McCall <davmac@davmac.org>
Wed, 1 May 2019 12:31:59 +0000 (22:31 +1000)
If no shutdown has been issued but all services stop, prompt user before
re-starting boot sequence.

src/control.cc
src/dinit.cc
src/includes/service-constants.h
src/includes/service.h

index 7933b3271e1fb6b1462e4148655570d03b8873f4..744ead35bbc66e92701351583f4f6a36e5b3ce08 100644 (file)
@@ -64,7 +64,7 @@ bool control_conn_t::process_packet()
             return true;
         }
         
-        if (contains({shutdown_type_t::CONTINUE, shutdown_type_t::HALT,
+        if (contains({shutdown_type_t::REMAIN, shutdown_type_t::HALT,
                shutdown_type_t::POWEROFF, shutdown_type_t::REBOOT}, rbuf[1])) {
             auto sd_type = static_cast<shutdown_type_t>(rbuf[1]);
 
index 191e504417676a95546b25e8312803a63cc0e497..6771bde71d5ac47c8eb392a3b3fc234686a41b96 100644 (file)
@@ -439,6 +439,9 @@ int dinit_main(int argc, char **argv)
     }
 
     shutdown_type_t shutdown_type = services->get_shutdown_type();
+    if (shutdown_type == shutdown_type_t::REMAIN) {
+        goto event_loop;
+    }
     
     if (am_pid_one) {
         log_msg_begin(loglevel_t::INFO, "No more active services.");
@@ -452,9 +455,6 @@ int dinit_main(int argc, char **argv)
         else if (shutdown_type == shutdown_type_t::POWEROFF) {
             log_msg_end(" Will power down.");
         }
-        else {
-            log_msg_end(" Re-initiating boot sequence.");
-        }
     }
     
     log_flush_timer.arm_timer_rel(event_loop, timespec{5,0}); // 5 seconds
@@ -465,10 +465,12 @@ int dinit_main(int argc, char **argv)
     close_control_socket();
     
     if (am_pid_one) {
-        if (shutdown_type == shutdown_type_t::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...
+        if (shutdown_type == shutdown_type_t::NONE) {
+            // Services all stopped but there was no shutdown issued. Inform user, wait for ack, and
+            // re-start boot sequence.
+            std::cout << "No shutdown was requested; boot failure? Will re-run boot sequence." << std::endl;
+            sync(); // Sync to minimise data loss if user elects to power off / hard reset
+            wait_for_user_input();
             try {
                 services->start_service("boot");
                 goto event_loop; // yes, the "evil" goto
@@ -476,7 +478,6 @@ int dinit_main(int argc, char **argv)
             catch (...) {
                 // Now what do we do? try to reboot, but wait for user ack to avoid boot loop.
                 log(loglevel_t::ERROR, "Could not start 'boot' service. Will attempt reboot.");
-                wait_for_user_input();
                 shutdown_type = shutdown_type_t::REBOOT;
             }
         }
index 0e20782aba4e93fc675e36d2be7b2a97aa11d7a2..93d193fe02a08e63ef8e64300105f5dbf83efdcb 100644 (file)
@@ -32,7 +32,8 @@ enum class service_event_t {
 
 /* Shutdown types */
 enum class shutdown_type_t {
-    CONTINUE,          // Continue normal boot sequence (used after single-user shell)
+    NONE,              // No explicit shutdown
+    REMAIN,            // Continue running with no services
     HALT,              // Halt system without powering down
     POWEROFF,          // Power off system
     REBOOT             // Reboot system
index aea9ca13222656a4d924c8b9792b2623684b0555..131c4f8a48666da19157aa7d44d765546e8d39bf 100644 (file)
@@ -725,7 +725,7 @@ class service_set
     std::list<service_record *> records;
     bool restart_enabled; // whether automatic restart is enabled (allowed)
     
-    shutdown_type_t shutdown_type = shutdown_type_t::CONTINUE;  // Shutdown type, if stopping
+    shutdown_type_t shutdown_type = shutdown_type_t::NONE;  // Shutdown type, if stopping
     
     // Services waiting for exclusive access to the console
     dlist<service_record, extract_console_queue> console_queue;
@@ -928,6 +928,13 @@ class service_set
         return shutdown_type;
     }
 
+    // Set the shutdown type to the specified type, without issuing a shutdown order. If all services
+    // stop, the shutdown type determines the action that Dinit will take.
+    void set_shutdown_type(shutdown_type_t new_shutdown_type) noexcept
+    {
+        shutdown_type = new_shutdown_type;
+    }
+
     // Get an identifier for the run-time type of the service set (similar to typeid, but without
     // requiring RTTI to be enabled during compilation).
     virtual int get_set_type_id()