Browse Source

Add always-chain option

Alexander Sherikov 2 years ago
parent
commit
399014aaf5

+ 10 - 4
doc/manpages/dinit-service.5.m4

@@ -243,10 +243,12 @@ a separate filesystem that is mounted during the first stage; such service
 descriptions will not be found at initial start, and so cannot be started
 directly, but can be chained via this directive.
 
-The chain is not executed if the initial service was explicitly stopped, stopped
-due to a dependency stopping (for any reason), if it will restart (including due
-to a dependent restarting), or if its process terminates abnormally or with an
-exit status indicating an error.
+The chain is not executed if the initial service was explicitly stopped,
+stopped due to a dependency stopping (for any reason), if it will restart
+(including due to a dependent restarting), or if its process terminates
+abnormally or with an exit status indicating an error. However, if
+\fBalways-chain\fR option is set the chain is started regardless of the
+reason and the status of this service termination.
 .TP
 \fBsocket\-listen\fR = \fIsocket-path\fR
 Pre-open a socket for the service and pass it to the service using the
@@ -422,6 +424,10 @@ will instead be considered stopped.
 \fBsignal-process-only\fR
 Signal the service process only, rather than its entire process group, whenever
 sending it a signal for any reason.
+.TP
+\fBalways-chain\fR
+Alters behavior of \fBchains-to\fR property forcing the chained service to
+always start on termination of this service.
 .RE
 .LP
 The next section contains example service descriptions including some of the

+ 5 - 0
src/igr-tests/chain-to/record-param.sh

@@ -2,3 +2,8 @@
 # append parameter to file
 
 echo "$1" >> ./recorded-output
+
+if [ "$1" = "part3" ] || [ "$1" = "part4" ]
+then
+    false
+fi

+ 1 - 1
src/igr-tests/chain-to/run-test.sh

@@ -7,7 +7,7 @@ rm -f ./recorded-output
 
 STATUS=FAIL
 if [ -e recorded-output ]; then
-   if [ "$(cat recorded-output)" = "$(echo part1; echo part2; echo part3)" ]; then
+   if [ "$(cat recorded-output)" = "$(echo part1; echo part2; echo part3; echo part4)" ]; then
        STATUS=PASS
    fi
 fi

+ 2 - 0
src/igr-tests/chain-to/sd/part3

@@ -1,2 +1,4 @@
 type = process
+options = always-chain
 command = ./record-param.sh part3
+chain-to = part4

+ 4 - 0
src/igr-tests/chain-to/sd/part4

@@ -0,0 +1,4 @@
+type = process
+#options = always-chain
+command = ./record-param.sh part4
+chain-to = part5

+ 2 - 0
src/igr-tests/chain-to/sd/part5

@@ -0,0 +1,2 @@
+type = process
+command = ./record-param.sh part5

+ 6 - 1
src/includes/load-service.h

@@ -30,10 +30,12 @@ struct service_flags_t
     bool start_interruptible : 1; // the startup of this service process is ok to interrupt with SIGINT
     bool skippable : 1;   // if interrupted the service is skipped (scripted services)
     bool signal_process_only : 1;  // signal the session process, not the whole group
+    bool always_chain : 1; // always start chain-to service on exit
 
     service_flags_t() noexcept : rw_ready(false), log_ready(false),
             runs_on_console(false), starts_on_console(false), shares_console(false),
-            pass_cs_fd(false), start_interruptible(false), skippable(false), signal_process_only(false)
+            pass_cs_fd(false), start_interruptible(false), skippable(false), signal_process_only(false),
+            always_chain(false)
     {
     }
 };
@@ -856,6 +858,9 @@ void process_service_line(settings_wrapper &settings, const char *name, string &
             else if (option_txt == "signal-process-only") {
                 settings.onstart_flags.signal_process_only = true;
             }
+            else if (option_txt == "always-chain") {
+                settings.onstart_flags.always_chain = true;
+            }
             else {
                 throw service_description_exc(name, "Unknown option: " + option_txt);
             }

+ 7 - 7
src/service.cc

@@ -86,7 +86,7 @@ void service_record::stopped() noexcept
     }
     else {
         becoming_inactive();
-        
+
         if (start_explicit) {
             // If we were explicitly started, our required_by count must be at least 1. Use
             // release() to correctly release, mark inactive and release dependencies.
@@ -110,7 +110,7 @@ void service_record::stopped() noexcept
         // - ... successfully (i.e. exit code 0)
         // - this service won't restart, and
         // - a shutdown isn't in progress
-        if (did_finish(stop_reason) && get_exit_status() == 0 && ! will_restart
+        if ((onstart_flags.always_chain || (did_finish(stop_reason) && get_exit_status() == 0 && ! will_restart))
                 && ! start_on_completion.empty() && ! services->is_shutting_down()) {
             try {
                 auto chain_to = services->load_service(start_on_completion.c_str());
@@ -223,18 +223,18 @@ void service_record::do_propagation() noexcept
         }
         prop_require = false;
     }
-    
+
     if (prop_release) {
         release_dependencies();
         prop_release = false;
     }
-    
+
     if (prop_failure) {
         prop_failure = false;
         stop_reason = stopped_reason_t::DEPFAILED;
         failed_to_start(true);
     }
-    
+
     if (prop_start) {
         prop_start = false;
         do_start();
@@ -338,7 +338,7 @@ bool service_record::start_check_dependencies() noexcept
             all_deps_started = false;
         }
     }
-    
+
     return all_deps_started;
 }
 
@@ -359,7 +359,7 @@ void service_record::all_deps_started() noexcept
         queue_for_console();
         return;
     }
-    
+
     waiting_for_deps = false;
 
     if (! can_proceed_to_start()) {