summaryrefslogtreecommitdiffstats
path: root/src/core/service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/service.c')
-rw-r--r--src/core/service.c100
1 files changed, 98 insertions, 2 deletions
diff --git a/src/core/service.c b/src/core/service.c
index 49579f7998..b8430eae96 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1440,6 +1440,93 @@ static bool service_exec_needs_notify_socket(Service *s, ExecFlags flags) {
return s->notify_access != NOTIFY_NONE;
}
+static int service_create_monitor_md_env(Job *j, char **ret) {
+ _cleanup_free_ char *var = NULL;
+ const char *list_delim = ";";
+ bool first = true;
+ Unit *tu;
+
+ assert(j);
+ assert(ret);
+
+ /* Create an environment variable 'MONITOR_METADATA', if creation is successful
+ * a pointer to it is returned via ret.
+ *
+ * This variable contains a space separated set of fields which relate to
+ * the service(s) which triggered job 'j'. Job 'j' is the JOB_START job for
+ * an OnFailure= or OnSuccess= dependency. Format of the MONITOR_METADATA
+ * variable is as follows:
+ *
+ * MONITOR_METADATA="SERVICE_RESULT=<result-string0>,EXIT_CODE=<exit-code0>,EXIT_STATUS=<exit-status0>,
+ * INVOCATION_ID=<id>,UNIT=<triggering-unit0.service>;
+ * SERVICE_RESULT=<result-stringN>,EXIT_CODE=<exit-codeN>,EXIT_STATUS=<exit-statusN>,
+ * INVOCATION_ID=<id>,UNIT=<triggering-unitN.service>"
+ *
+ * Multiple results may be passed as in the above example if jobs are merged, i.e.
+ * some services a and b contain an OnFailure= or OnSuccess= dependency on the same
+ * service.
+ *
+ * For example:
+ *
+ * MONITOR_METADATA="SERVICE_RESULT=exit-code,EXIT_CODE=exited,EXIT_STATUS=1,INVOCATION_ID=02dd868af2f344b18edaf74b618b2f90,UNIT=failer.service;
+ * SERVICE_RESULT=exit-code,EXIT_CODE=exited,EXIT_STATUS=1,INVOCATION_ID=80cb228bd7344f77a090eda603a3cfe2,UNIT=failer2.service"
+ */
+
+ LIST_FOREACH(triggered_by, tu, j->triggered_by) {
+ Service *env_source = SERVICE(tu);
+ int r;
+
+ if (!env_source)
+ continue;
+
+ if (first) {
+ /* Add the environment variable name first. */
+ r = strextendf(&var, "MONITOR_METADATA=");
+ if (r < 0)
+ return r;
+
+ }
+
+ r = strextendf(&var, "%sSERVICE_RESULT=%s",
+ !first ? list_delim : "", service_result_to_string(env_source->result));
+ if (r < 0)
+ return r;
+
+ first = false;
+
+ if (env_source->main_exec_status.pid > 0 &&
+ dual_timestamp_is_set(&env_source->main_exec_status.exit_timestamp)) {
+ r = strextendf(&var, ",EXIT_CODE=%s",
+ sigchld_code_to_string(env_source->main_exec_status.code));
+ if (r < 0)
+ return r;
+
+ if (env_source->main_exec_status.code == CLD_EXITED)
+ r = strextendf(&var, ",EXIT_STATUS=%i",
+ env_source->main_exec_status.status);
+ else
+ r = strextendf(&var, ",EXIT_STATUS=%s",
+ signal_to_string(env_source->main_exec_status.status));
+ if (r < 0)
+ return r;
+ }
+
+ if (!sd_id128_is_null(UNIT(env_source)->invocation_id)) {
+ r = strextendf(&var, ",INVOCATION_ID=" SD_ID128_FORMAT_STR,
+ SD_ID128_FORMAT_VAL(UNIT(env_source)->invocation_id));
+ if (r < 0)
+ return r;
+ }
+
+ r = strextendf(&var, ",UNIT=%s", UNIT(env_source)->id);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = TAKE_PTR(var);
+ return 0;
+}
+
static int service_spawn(
Service *s,
ExecCommand *c,
@@ -1574,9 +1661,18 @@ static int service_spawn(
r = asprintf(our_env + n_env++, "EXIT_STATUS=%i", s->main_exec_status.status);
else
r = asprintf(our_env + n_env++, "EXIT_STATUS=%s", signal_to_string(s->main_exec_status.status));
+
if (r < 0)
return -ENOMEM;
}
+
+ } else if (flags & EXEC_SETENV_MONITOR_RESULT) {
+ Job *j = UNIT(s)->job;
+ if (j) {
+ r = service_create_monitor_md_env(j, our_env + n_env++);
+ if (r < 0)
+ return r;
+ }
}
r = unit_set_exec_params(UNIT(s), &exec_params);
@@ -2164,7 +2260,7 @@ static void service_enter_start(Service *s) {
r = service_spawn(s,
c,
timeout,
- EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_WRITE_CREDENTIALS,
+ EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_WRITE_CREDENTIALS|EXEC_SETENV_MONITOR_RESULT,
&pid);
if (r < 0)
goto fail;
@@ -2222,7 +2318,7 @@ static void service_enter_start_pre(Service *s) {
r = service_spawn(s,
s->control_command,
s->timeout_start_usec,
- EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN,
+ EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN|EXEC_SETENV_MONITOR_RESULT,
&s->control_pid);
if (r < 0)
goto fail;