]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: set $SERVICE_RESULT, $EXIT_CODE and $EXIT_STATUS in ExecStop=/ExecStopPost...
authorLennart Poettering <lennart@poettering.net>
Wed, 27 Jul 2016 09:51:11 +0000 (11:51 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 4 Aug 2016 21:08:05 +0000 (23:08 +0200)
This should simplify monitoring tools for services, by passing the most basic
information about service result/exit information via environment variables,
thus making it unnecessary to retrieve them explicitly via the bus.

man/systemd.exec.xml
man/systemd.service.xml
src/core/execute.h
src/core/service.c

index 58ba5829112dfa5e00f2f0cbd633ef8aecdbc0b2..0fc658f18079c2bf64cff5bd54a647cb682fb20e 100644 (file)
         functions) if their standard output or standard error output is connected to the journal anyway, thus enabling
         delivery of structured metadata along with logged messages.</para></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>$SERVICE_RESULT</varname></term>
+
+        <listitem><para>Only defined for the service unit type, this environment variable is passed to all
+        <varname>ExecStop=</varname> and <varname>ExecStopPost=</varname> processes, and encodes the service
+        "result". Currently, the following values are defined: <literal>timeout</literal> (in case of an operation
+        timeout), <literal>exit-code</literal> (if a service process exited with a non-zero exit code; see
+        <varname>$EXIT_STATUS</varname> below for the actual exit status returned), <literal>signal</literal> (if a
+        service process was terminated abnormally by a signal; see <varname>$EXIT_STATUS</varname> below for the actual
+        signal used for the termination), <literal>core-dump</literal> (if a service process terminated abnormally and
+        dumped core), <literal>watchdog</literal> (if the watchdog keep-alive ping was enabled for the service but it
+        missed the deadline), or <literal>resources</literal> (a catch-all condition in case a system operation
+        failed).</para>
+
+        <para>This environment variable is useful to monitor failure or successful termination of a service. Even
+        though this variable is available in both <varname>ExecStop=</varname> and <varname>ExecStopPost=</varname>, it
+        is usually a better choice to place monitoring tools in the latter, as the former is only invoked for services
+        that managed to start up correctly, and the latter covers both services that failed during their start-up and
+        those which failed during their runtime.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>$EXIT_CODE</varname></term>
+        <term><varname>$EXIT_STATUS</varname></term>
+
+        <listitem><para>Only defined for the service unit type, these environment variables are passed to all
+        <varname>ExecStop=</varname>, <varname>ExecStopPost=</varname> processes and contain exit status/code
+        information of the main process of the service. For the precise definition of the exit code and status, see
+        <citerefentry><refentrytitle>wait</refentrytitle><manvolnum>2</manvolnum></citerefentry>. <varname>$EXIT_CODE</varname>
+        is one of <literal>exited</literal>, <literal>killed</literal>,
+        <literal>dumped</literal>. <varname>$EXIT_STATUS</varname> contains the numeric exit code formatted as string
+        if <varname>$EXIT_CODE</varname> is <literal>exited</literal>, and the signal name in all other cases. Note
+        that these environment variables are only set if the service manager succeeded to start and identify the main
+        process of the service.</para></listitem>
+      </varlistentry>
+
     </variablelist>
 
     <para>Additional variables may be configured by the following
index 875d368fcfb78efa53eb1710f9192a0d3957a013..e82edbe93e49d7b03bcdf1d8d3c7a83da05ca112 100644 (file)
         service failed to start up correctly. Commands configured with this setting need to be able to operate even if
         the service failed starting up half-way and left incompletely initialized data around. As the service's
         processes have been terminated already when the commands specified with this setting are executed they should
-        not attempt to communicate with them.</para></listitem>
+        not attempt to communicate with them.</para>
+
+        <para>Note that all commands that are configured with this setting are invoked with the result code of the
+        service, as well as the main process' exit code and status, set in the <varname>$SERVICE_RESULT</varname>,
+        <varname>$EXIT_CODE</varname> and <varname>$EXIT_STATUS</varname> environment variables, see
+        <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+        details.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 8d659ca1783fc9398ab81a6d30b51597ca303383..2b4238ed7e283b7a00e516f97752179e54fde130 100644 (file)
@@ -217,6 +217,7 @@ typedef enum ExecFlags {
         /* The following are not used by execute.c, but by consumers internally */
         EXEC_PASS_FDS          = 1U << 4,
         EXEC_IS_CONTROL        = 1U << 5,
+        EXEC_SETENV_RESULT     = 1U << 6,
 } ExecFlags;
 
 struct ExecParameters {
index 32b8e7d2c536fc60324c71e307c9913a63e9f01c..0cbea522769a6f823c090ee0d5485b7dd37537bf 100644 (file)
@@ -1216,7 +1216,7 @@ static int service_spawn(
         if (r < 0)
                 return r;
 
-        our_env = new0(char*, 6);
+        our_env = new0(char*, 9);
         if (!our_env)
                 return -ENOMEM;
 
@@ -1264,6 +1264,24 @@ static int service_spawn(
                 }
         }
 
+        if (flags & EXEC_SETENV_RESULT) {
+                if (asprintf(our_env + n_env++, "SERVICE_RESULT=%s", service_result_to_string(s->result)) < 0)
+                        return -ENOMEM;
+
+                if (s->main_exec_status.pid > 0 &&
+                    dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) {
+                        if (asprintf(our_env + n_env++, "EXIT_CODE=%s", sigchld_code_to_string(s->main_exec_status.code)) < 0)
+                                return -ENOMEM;
+
+                        if (s->main_exec_status.code == CLD_EXITED)
+                                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;
+                }
+        }
+
         final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
         if (!final_env)
                 return -ENOMEM;
@@ -1467,7 +1485,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
                 r = service_spawn(s,
                                   s->control_command,
                                   s->timeout_stop_usec,
-                                  EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_IS_CONTROL,
+                                  EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
                                   &s->control_pid);
                 if (r < 0)
                         goto fail;
@@ -1578,7 +1596,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
                 r = service_spawn(s,
                                   s->control_command,
                                   s->timeout_stop_usec,
-                                  EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
+                                  EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
                                   &s->control_pid);
                 if (r < 0)
                         goto fail;
@@ -1898,7 +1916,8 @@ static void service_run_next_control(Service *s) {
                           s->control_command,
                           timeout,
                           EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|
-                          (IN_SET(s->control_command_id, SERVICE_EXEC_START_PRE, SERVICE_EXEC_STOP_POST) ? EXEC_APPLY_TTY_STDIN : 0),
+                          (IN_SET(s->control_command_id, SERVICE_EXEC_START_PRE, SERVICE_EXEC_STOP_POST) ? EXEC_APPLY_TTY_STDIN : 0)|
+                          (IN_SET(s->control_command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST) ? EXEC_SETENV_RESULT : 0),
                           &s->control_pid);
         if (r < 0)
                 goto fail;