From cd3bec398808df31042f12daebeff32a8584c519 Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Sat, 17 Nov 2018 00:35:13 +0000 Subject: [PATCH] Add "ready-notification" service option. This allows either of the two notification methods - write to a specific fd or to an fd identified by an environment variable. --- doc/manpages/dinit-service.5 | 15 +++++++++++++++ src/load-service.cc | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/doc/manpages/dinit-service.5 b/doc/manpages/dinit-service.5 index c594194..34428eb 100644 --- a/doc/manpages/dinit-service.5 +++ b/doc/manpages/dinit-service.5 @@ -220,6 +220,21 @@ 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 +\fBready-notification\fR = {\fBpipefd:\fR\fIfd-number\fR | \fBpipevar:\fR\fIenv-var-name\fR} +Specifies the mechanism, if any, by which a process service will notify that it is ready +(successfully started). If not specified, a process service is considered started as soon as it +has begun execution. The two options are: +.RS +.IP \(bu +\fBpipefd:\fR\fIfd-number\fR \(em the service will write a message to the specified file descriptor, +which \fBdinit\fR sets up as the write end of a pipe before execution. This mechanism is compatible +with the S6 supervision suite. +.IP \(bu +\fBpipevar:\fR\fIenv-var-name\fR \(em the service will write a message to file descriptor identified +using the contents of the specified environment variable, which will be set by \fBdinit\fR before +execution to a file descriptor (chosen arbitrarily) attached to the write end of a pipe. +.RE +.TP \fBlogfile\fR = \fIlog-file-path\fR Specifies the log file for the service. Output from the service process will go this file. diff --git a/src/load-service.cc b/src/load-service.cc index 0d66738..318e7b4 100644 --- a/src/load-service.cc +++ b/src/load-service.cc @@ -283,6 +283,17 @@ static void process_dep_dir(dirload_service_set &sset, } } +// Check if one string starts with another +static bool starts_with(string s, const char *prefix) +{ + const char * sp = s.c_str(); + while (*sp != 0 && *prefix != 0) { + if (*sp != *prefix) return false; + sp++; prefix++; + } + return *prefix == 0; +} + // Find a service record, or load it from file. If the service has // dependencies, load those also. // @@ -361,6 +372,9 @@ service_record * dirload_service_set::load_service(const char * name) timespec stop_timeout = { .tv_sec = 10, .tv_nsec = 0 }; timespec start_timeout = { .tv_sec = 60, .tv_nsec = 0 }; + int readiness_fd = -1; // readiness fd in service process + std::string readiness_var; // environment var to hold readiness fd + uid_t run_as_uid = -1; gid_t run_as_gid = -1; @@ -567,6 +581,24 @@ service_record * dirload_service_set::load_service(const char * name) else if (setting == "chain-to") { chain_to_name = read_setting_value(i, end, nullptr); } + else if (setting == "ready-notification") { + string notify_setting = read_setting_value(i, end, nullptr); + if (starts_with(notify_setting, "pipefd:")) { + readiness_fd = parse_unum_param(notify_setting.substr(7 /* len 'pipefd:' */), + name, std::numeric_limits::max()); + } + else if (starts_with(notify_setting, "pipevar:")) { + readiness_var = notify_setting.substr(8 /* len 'pipevar:' */); + if (readiness_var.empty()) { + throw service_description_exc(name, "Invalid pipevar variable name " + "in ready-notification"); + } + } + else { + throw service_description_exc(name, "Unknown ready-notification setting: " + + notify_setting); + } + } else { throw service_description_exc(name, "Unknown setting: " + setting); } @@ -598,6 +630,8 @@ service_record * dirload_service_set::load_service(const char * name) rvalps->set_extra_termination_signal(term_signal); rvalps->set_run_as_uid_gid(run_as_uid, run_as_gid); rvalps->set_workding_dir(working_dir); + rvalps->set_notification_fd(readiness_fd); + rvalps->set_notification_var(std::move(readiness_var)); // process service start / run on console must be the same: onstart_flags.starts_on_console = onstart_flags.runs_on_console; rval = rvalps; -- 2.25.1