Implement a "shares-console" option for non-exclusive console access.
authorDavin McCall <davmac@davmac.org>
Tue, 30 Oct 2018 19:01:02 +0000 (19:01 +0000)
committerDavin McCall <davmac@davmac.org>
Tue, 30 Oct 2018 20:21:56 +0000 (20:21 +0000)
This could be useful for the "single" (single-user) service, so that
runs-on-console services can be started from it.

doc/linux/services/single
doc/manpages/dinit-service.5
src/baseproc-service.cc
src/includes/service.h
src/load-service.cc

index ccb7af5b192cc9d3b5732a676a8b0bc733944332..fa20b8c4fb863482ee709946f61b39583a6a125b 100644 (file)
@@ -1,5 +1,8 @@
+# Single-user mode. This just starts a shell on the console; other services
+# can be started by issuing dinitctl commands. On exit, "boot" resumes.
+
 type = process
 command = /bin/sh
 restart = false
-options = runs-on-console
+options = shares-console
 chain-to = boot
index d50cda99d6b05897e5bd01a5648230fb2de57d02..47a2cd27ceeee90e4267e134e2b9ada93aae0366 100644 (file)
@@ -266,6 +266,18 @@ This setting is not applicable to regular \fBprocess\fR services, but can be
 used for \fBscripted\fR and \fBbgprocess\fR services. It allows for
 interrupting startup via the \fIinterrupt\fR key (normally control-C). This is
 useful to allow filesystem checks to be interrupted/skipped.
+
+This option is implied by \fBruns\-on\-console\fR, and is mutually exclusive
+with \fBshares\-console\fR; setting this option, or setting \fBruns\-on\-console\fR,
+unsets \fBshares\-console\fR.
+.TP
+\fBshares\-console\fR
+Specifies that this service should be given access to the console (input and output
+will be connected to the console), but that it should not exclusively hold the
+console and not delay the start of services with \fBstarts\-on\-console\fR.
+
+This is mutually exclusive with both \fBstarts\-on\-console\fR and \fBruns\-on\-console\fR;
+setting this option unsets both those options.
 .TP
 \fBstarts-rwfs\fR
 This service mounts the root filesystem read/write (or at least mounts the
index 9e9d5c135872921b94cb4ec8af5d0767ed168b12..1a2be988b22ccecbda423dc3cc290e5c4cca5134 100644 (file)
@@ -43,7 +43,8 @@ bool base_process_service::bring_up() noexcept
 
         event_loop.get_time(restart_interval_time, clock_type::MONOTONIC);
         restart_interval_count = 0;
-        if (start_ps_process(exec_arg_parts, onstart_flags.starts_on_console)) {
+        if (start_ps_process(exec_arg_parts,
+                onstart_flags.starts_on_console || onstart_flags.shares_console)) {
             // Note: we don't set a start timeout for PROCESS services.
             if (start_timeout != time_val(0,0) && get_type() != service_type_t::PROCESS) {
                 restart_timer.arm_timer_rel(event_loop, start_timeout);
@@ -203,7 +204,7 @@ void base_process_service::do_restart() noexcept
         }
     }
 
-    if (! start_ps_process(exec_arg_parts, have_console)) {
+    if (! start_ps_process(exec_arg_parts, have_console || onstart_flags.shares_console)) {
         restarting = false;
         if (service_state == service_state_t::STARTING) {
             failed_to_start();
index 91bbcde2d71079f12b5dfd80f0f929c93898a688..4f3f0d6b61b44173d9db0cfbeb4db6ebb542c360 100644 (file)
  * transition stage, at the latest.
  */
 
-struct service_flags_t {
+struct service_flags_t
+{
     // on-start flags:
     bool rw_ready : 1;  // file system should be writable once this service starts
     bool log_ready : 1; // syslog should be available once this service starts
@@ -120,14 +121,15 @@ struct service_flags_t {
     bool no_sigterm : 1;  // do not send SIGTERM
     bool runs_on_console : 1;  // run "in the foreground"
     bool starts_on_console : 1; // starts in the foreground
+    bool shares_console : 1;    // run on console, but not exclusively
     bool pass_cs_fd : 1;  // pass this service a control socket connection via fd
     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
     
     service_flags_t() noexcept : rw_ready(false), log_ready(false), no_sigterm(false),
-            runs_on_console(false), starts_on_console(false), pass_cs_fd(false),
-            start_interruptible(false), skippable(false), signal_process_only(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)
     {
     }
 };
index 675966ebbee2bbfad3698c7613de166cad081eb7..0d66738ad43041e2b449147ec35b9f4b76b74414 100644 (file)
@@ -32,7 +32,8 @@ static int signal_name_to_number(std::string &signame)
     return -1;
 }
 
-static const char * uid_err_msg = "Specified user id contains invalid numeric characters or is outside allowed range.";
+static const char * uid_err_msg = "Specified user id contains invalid numeric characters "
+        "or is outside allowed range.";
 
 // Parse a userid parameter which may be a numeric user ID or a username. If a name, the
 // userid is looked up via the system user database (getpwnam() function). In this case,
@@ -51,7 +52,8 @@ static uid_t parse_uid_param(const std::string &param, const std::string &servic
         static_assert((uintmax_t)std::numeric_limits<uid_t>::max()
                 <= (uintmax_t)std::numeric_limits<unsigned long long>::max(), "uid_t is too large");
         unsigned long long v = std::stoull(param, &ind, 0);
-        if (v > static_cast<unsigned long long>(std::numeric_limits<uid_t>::max()) || ind != param.length()) {
+        if (v > static_cast<unsigned long long>(std::numeric_limits<uid_t>::max())
+                || ind != param.length()) {
             throw service_description_exc(service_name, uid_err_msg);
         }
         return v;
@@ -481,9 +483,16 @@ service_record * dirload_service_set::load_service(const char * name)
                         onstart_flags.runs_on_console = true;
                         // A service that runs on the console necessarily starts on console:
                         onstart_flags.starts_on_console = true;
+                        onstart_flags.shares_console = false;
                     }
                     else if (option_txt == "starts-on-console") {
                         onstart_flags.starts_on_console = true;
+                        onstart_flags.shares_console = false;
+                    }
+                    else if (option_txt == "shares-console") {
+                        onstart_flags.shares_console = true;
+                        onstart_flags.runs_on_console = false;
+                        onstart_flags.starts_on_console = false;
                     }
                     else if (option_txt == "pass-cs-fd") {
                         onstart_flags.pass_cs_fd = true;