Add "start-interruptible" service option.
authorDavin McCall <davmac@davmac.org>
Sat, 6 Jan 2018 22:52:08 +0000 (22:52 +0000)
committerDavin McCall <davmac@davmac.org>
Sat, 6 Jan 2018 22:52:08 +0000 (22:52 +0000)
This option allows a service startup to be interrupted if the service
becomes inactive while starting, by sending it the SIGINT signal. This
is useful for file system checks, which can otherwise delay
reboot/shutdown.

README
doc/linux/services/late-filesystems
doc/linux/services/rootfscheck
doc/manpages/dinit.8
src/load_service.cc
src/service.h

diff --git a/README b/README
index 665e5a072983f8cc697eb4fc36ea2e94bd27477f..9420b4655b95a9bee4402f64f5ca972fdde95b19 100644 (file)
--- a/README
+++ b/README
@@ -288,6 +288,12 @@ options = ( runs-on-console | nosigterm | starts-rwfs | starts-log ) ...
               receives the control socket must close it before launching any
               untrusted processes. You should not use this option unless the
               service is designed to receive a Dinit control socket.
+              
+  start-interruptible : this service can have its startup interrupted
+              (cancelled) if it becomes inactive while still starting.
+              The SIGINT signal will be sent to the signal to cancel its
+              startup. This is meaningful only for scripted and bgprocess
+              services. 
 
 logfile = (log file path)
    Specifies the log file for the service. Output from the service process
@@ -355,8 +361,14 @@ The above represents a number of started services and one stopped service
 (mysql). Services transitioning state (starting or stopping) are displayed
 with an arrow indicating the transition direction:
 
-    [   <<{-}] mysql     # starting
-    [{+}>>   ] mysql     # stopping
+    [{ }<<   ] mysql     # starting
+    [   >>{ }] mysql     # stopping
+    
+The curly brackets indicate the desired state, which may not be the state to
+which the service is currently transitioning. For example:
+
+    [   <<{ }] mysql     # starting, but will stop after starting
+    [{ }>>   ] mysql     # stopping, but will restart once stopped
 
 Remember that a "starting" service may be waiting for its dependencies to
 start, and a "stopping" service may be waiting for its dependencies to stop.
index a627583aed9ee9761bcb3741da3a218da32cde00..e5c264aa2537d07a546baadb7370c3b5d22ca5fb 100644 (file)
@@ -4,5 +4,6 @@ type = scripted
 command = /etc/dinit.d/late-filesystems.sh start
 restart = false
 logfile = /var/log/late-filesystems.log
+options = start-interruptible
 
 depends-on = rcboot
index c8e0ef27f43f3579ea091f58833b585d5189dae3..b72480711c5053cda43f9f6cab35deb88ed08b87 100644 (file)
@@ -3,7 +3,7 @@
 type = scripted
 command = /etc/dinit.d/rootfscheck.sh start
 restart = false
-options = starts-on-console pass-cs-fd
+options = starts-on-console pass-cs-fd start-interruptible
 
 depends-on = early-filesystems
 depends-on = udevd
index 21349a540aa284357dfc6405f771e5f2c78dcfd7..93d70d0200588642ad2603f527df1fe0aed13498 100644 (file)
@@ -210,7 +210,7 @@ to terminate (applies to 'process' services only). SIGTERM is always
 sent along with the specified signal, unless the \fBnosigterm\fR option is
 specified via the \fBoptions\fR parameter.
 .TP
-\fBoptions\fR = {runs\-on\-console | nosigterm | starts\-rwfs | starts\-log}...
+\fBoptions\fR = {runs\-on\-console | nosigterm | starts\-rwfs | starts\-log | start\-interruptible}...
 Specifies various options for this service:
 .RS
 .TP
@@ -259,6 +259,11 @@ Using this option has security implications! The service which receives the
 control socket must close it before launching any untrusted processes. You
 should not use this option unless the service is designed to receive a Dinit
 control socket.
+.TP
+\fBstart-interruptible\fR
+this service can have its startup interrupted (cancelled) if it becomes inactive
+while still starting, by sending it the SIGINT signal. This is meaningful only
+for \fBbgprocess\fR and \fBscripted\fR services.
 .RE
 .TP
 \fBlogfile\fR = \fIlog-file-path\fR
@@ -320,7 +325,7 @@ More examples are provided with the Dinit distribution.
 When run as a system process, SIGINT stops all services and performs a reboot (on Linux, this signal can be
 generated using the control-alt-delete key combination); SIGTERM stops services and halts the system; and
 SIGQUIT performs an immediate shutdown with no service rollback.
-LP
+.LP
 When run as a user process, SIGINT and SIGTERM both stop services and exit Dinit; SIGQUIT exits Dinit
 immediately.
 .\"
index 5c211b1920f1522a1315e874b38f4eff8c1a5807..d1d827d8157964f171ddf94e8379f694d9b228a7 100644 (file)
@@ -309,6 +309,7 @@ static gid_t parse_gid_param(const std::string &param, const std::string &servic
 
 // Parse a time, specified as a decimal number of seconds (with optional fractional component after decimal
 // point or decimal comma).
+//
 static void parse_timespec(const std::string &paramval, const std::string &servicename,
         const char * paramname, timespec &ts)
 {
@@ -352,6 +353,7 @@ static void parse_timespec(const std::string &paramval, const std::string &servi
 // Might throw a ServiceLoadExc exception if a dependency cycle is found or if another
 // problem occurs (I/O error, service description not found etc). Throws std::bad_alloc
 // if a memory allocation failure occurs.
+//
 service_record * dirload_service_set::load_service(const char * name)
 {
     using std::string;
@@ -393,6 +395,7 @@ service_record * dirload_service_set::load_service(const char * name)
     int term_signal = -1;  // additional termination signal
     bool auto_restart = false;
     bool smooth_recovery = false;
+    bool start_is_interruptible = false;
     string socket_path;
     int socket_perms = 0666;
     // Note: Posix allows that uid_t and gid_t may be unsigned types, but eg chown uses -1 as an
@@ -416,7 +419,8 @@ service_record * dirload_service_set::load_service(const char * name)
         throw service_not_found(name);
     }
     
-    // Add a dummy service record now to prevent infinite recursion in case of cyclic dependency
+    // Add a dummy service record now to prevent infinite recursion in case of cyclic dependency.
+    // We replace this with the real service later (or remove it if we find a configuration error).
     rval = new service_record(this, string(name));
     add_service(rval);
     
@@ -541,6 +545,9 @@ service_record * dirload_service_set::load_service(const char * name)
                         else if (option_txt == "pass-cs-fd") {
                             onstart_flags.pass_cs_fd = true;
                         }
+                        else if (option_txt == "start-interruptible") {
+                            start_is_interruptible = true;
+                        }
                         else {
                             throw service_description_exc(name, "Unknown option: " + option_txt);
                         }
@@ -597,6 +604,7 @@ service_record * dirload_service_set::load_service(const char * name)
                     rvalps->set_restart_interval(restart_interval, max_restarts);
                     rvalps->set_restart_delay(restart_delay);
                     rvalps->set_stop_timeout(stop_timeout);
+                    rvalps->set_start_interruptible(start_is_interruptible);
                     rval = rvalps;
                 }
                 else if (service_type == service_type::BGPROCESS) {
@@ -606,6 +614,7 @@ service_record * dirload_service_set::load_service(const char * name)
                     rvalps->set_restart_interval(restart_interval, max_restarts);
                     rvalps->set_restart_delay(restart_delay);
                     rvalps->set_stop_timeout(stop_timeout);
+                    rvalps->set_start_interruptible(start_is_interruptible);
                     rval = rvalps;
                 }
                 else if (service_type == service_type::SCRIPTED) {
@@ -613,6 +622,7 @@ service_record * dirload_service_set::load_service(const char * name)
                             command_offsets, depends);
                     rvalps->set_stop_command(stop_command, stop_command_offsets);
                     rvalps->set_stop_timeout(stop_timeout);
+                    rvalps->set_start_interruptible(start_is_interruptible);
                     rval = rvalps;
                 }
                 else {
index f6bfed1c3bf001fc89b5c79a7aabf6c956c272f8..0c8e20859303509a6c84a596678e0fb4a70faed7 100644 (file)
@@ -718,6 +718,11 @@ class base_process_service : public service_record
     {
         stop_timeout = timeout;
     }
+
+    void set_start_interruptible(bool value) noexcept
+    {
+        start_is_interruptible = value;
+    }
 };
 
 class process_service : public base_process_service