From 11c131eef20351d5f6cfaa6bedba3dcb5696cd03 Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Tue, 30 Oct 2018 19:01:02 +0000 Subject: [PATCH] Implement a "shares-console" option for non-exclusive console access. 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 | 5 ++++- doc/manpages/dinit-service.5 | 12 ++++++++++++ src/baseproc-service.cc | 5 +++-- src/includes/service.h | 8 +++++--- src/load-service.cc | 13 +++++++++++-- 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/doc/linux/services/single b/doc/linux/services/single index ccb7af5..fa20b8c 100644 --- a/doc/linux/services/single +++ b/doc/linux/services/single @@ -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 diff --git a/doc/manpages/dinit-service.5 b/doc/manpages/dinit-service.5 index d50cda9..47a2cd2 100644 --- a/doc/manpages/dinit-service.5 +++ b/doc/manpages/dinit-service.5 @@ -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 diff --git a/src/baseproc-service.cc b/src/baseproc-service.cc index 9e9d5c1..1a2be98 100644 --- a/src/baseproc-service.cc +++ b/src/baseproc-service.cc @@ -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(); diff --git a/src/includes/service.h b/src/includes/service.h index 91bbcde..4f3f0d6 100644 --- a/src/includes/service.h +++ b/src/includes/service.h @@ -111,7 +111,8 @@ * 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) { } }; diff --git a/src/load-service.cc b/src/load-service.cc index 675966e..0d66738 100644 --- a/src/load-service.cc +++ b/src/load-service.cc @@ -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 ¶m, const std::string &servic static_assert((uintmax_t)std::numeric_limits::max() <= (uintmax_t)std::numeric_limits::max(), "uid_t is too large"); unsigned long long v = std::stoull(param, &ind, 0); - if (v > static_cast(std::numeric_limits::max()) || ind != param.length()) { + if (v > static_cast(std::numeric_limits::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; -- 2.25.1