From: Davin McCall Date: Sat, 6 Jan 2018 22:52:08 +0000 (+0000) Subject: Add "start-interruptible" service option. X-Git-Tag: v0.07~4 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=5b6fc34c8642b93901d39df07888d25cef6bf322;p=oweals%2Fdinit.git Add "start-interruptible" service option. 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. --- diff --git a/README b/README index 665e5a0..9420b46 100644 --- 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. diff --git a/doc/linux/services/late-filesystems b/doc/linux/services/late-filesystems index a627583..e5c264a 100644 --- a/doc/linux/services/late-filesystems +++ b/doc/linux/services/late-filesystems @@ -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 diff --git a/doc/linux/services/rootfscheck b/doc/linux/services/rootfscheck index c8e0ef2..b724807 100644 --- a/doc/linux/services/rootfscheck +++ b/doc/linux/services/rootfscheck @@ -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 diff --git a/doc/manpages/dinit.8 b/doc/manpages/dinit.8 index 21349a5..93d70d0 100644 --- a/doc/manpages/dinit.8 +++ b/doc/manpages/dinit.8 @@ -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. .\" diff --git a/src/load_service.cc b/src/load_service.cc index 5c211b1..d1d827d 100644 --- a/src/load_service.cc +++ b/src/load_service.cc @@ -309,6 +309,7 @@ static gid_t parse_gid_param(const std::string ¶m, 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 ¶mval, const std::string &servicename, const char * paramname, timespec &ts) { @@ -352,6 +353,7 @@ static void parse_timespec(const std::string ¶mval, 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 { diff --git a/src/service.h b/src/service.h index f6bfed1..0c8e208 100644 --- a/src/service.h +++ b/src/service.h @@ -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