]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/service: store BUSERROR= & VARLINKERROR= received through notification
authorMike Yuan <me@yhndnzj.com>
Thu, 9 May 2024 14:05:22 +0000 (22:05 +0800)
committerMike Yuan <me@yhndnzj.com>
Thu, 20 Jun 2024 17:03:44 +0000 (19:03 +0200)
Closes #6073

TODO
man/org.freedesktop.systemd1.xml
man/sd_notify.xml
src/core/dbus-service.c
src/core/service.c
src/core/service.h

diff --git a/TODO b/TODO
index 534463cd73178831de6b9c4794cc68e108f77546..92169dea0bf4e4cbd5b205197a7f0e45f1d27d5a 100644 (file)
--- a/TODO
+++ b/TODO
@@ -478,10 +478,6 @@ Features:
   - kernel-install
   - systemd-mount (with PK so that desktop environments could use it to mount disks)
 
-* in the service manager, pick up ERRNO= + BUSERROR= + VARLINKERROR= error
-  identifiers, and store them along with the exit status of a server and report
-  via "systemctl status".
-
 * enumerate virtiofs devices during boot-up in a generator, and synthesize
   mounts for rootfs, /usr/, /home/, /srv/ and some others from it, depending on
   the "tag". (waits for: https://gitlab.com/virtio-fs/virtiofsd/-/issues/128)
index b0b45097e30a31bf04767e188cb21ed092246ce3..7ab560a65484962968de95d16a1ebff87966215d 100644 (file)
@@ -2745,6 +2745,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       readonly s FileDescriptorStorePreserve = '...';
       readonly s StatusText = '...';
       readonly i StatusErrno = ...;
+      readonly s StatusBusError = '...';
+      readonly s StatusVarlinkError = '...';
       readonly s Result = '...';
       readonly s ReloadResult = '...';
       readonly s CleanResult = '...';
@@ -3404,8 +3406,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property FileDescriptorStorePreserve is not documented!-->
 
-    <!--property StatusErrno is not documented!-->
-
     <!--property ReloadResult is not documented!-->
 
     <!--property CleanResult is not documented!-->
@@ -4026,6 +4026,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="StatusErrno"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="StatusBusError"/>
+
+    <variablelist class="dbus-property" generated="True" extra-ref="StatusVarlinkError"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Result"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="ReloadResult"/>
@@ -4732,11 +4736,11 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       process is currently running while the latter possible contains information collected from the last run
       even if the process is no longer around.</para>
 
-      <para><varname>StatusText</varname> contains the status text passed to the service manager via a call
-      to
-      <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
-      This may be used by services to inform the service manager about its internal state with a nice
-      explanatory string.</para>
+      <para><varname>StatusText</varname>, <varname>StatusErrno</varname>, <varname>StatusBusError</varname>,
+      and <varname>StatusVarlinkError</varname> contain the status text, the error number,
+      and the D-Bus/Varlink error name passed to the service manager via
+      <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      respectively. They may be used by services to inform the service manager about its internal state.</para>
 
       <para><varname>Result</varname> encodes the execution result of the last run of the service. It is
       useful to determine the reason a service failed if it is in the <literal>failed</literal> state (see
@@ -12221,6 +12225,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
       <varname>EffectiveMemoryMax</varname>,
       <varname>EffectiveTasksMax</varname>, and
       <varname>MemoryZSwapWriteback</varname> were added in version 256.</para>
+      <para><varname>StatusBusError</varname>
+      and <varname>StatusVarlinkError</varname> were added in version 257.</para>
     </refsect2>
     <refsect2>
       <title>Job Objects</title>
index 35c450b12815f6fbcb4b7b40dedc2ba8f677b20e..f04251bd197e583aeccd44f7776073e55400fc41 100644 (file)
         <term>BUSERROR=…</term>
 
         <listitem><para>If a service fails, the D-Bus error-style error code. Example:
-        <literal>BUSERROR=org.freedesktop.DBus.Error.TimedOut</literal>. Note that this assignment is
-        currently not used by <command>systemd</command>.</para>
+        <literal>BUSERROR=org.freedesktop.DBus.Error.TimedOut</literal>.</para>
 
         <xi:include href="version-info.xml" xpointer="v233"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term>VARLINKERROR=…</term>
+
+        <listitem><para>If a service fails, the Varlink error-style error code. Example:
+        <literal>VARLINKERROR=org.varlink.service.InvalidParameter</literal>.</para>
+
+        <xi:include href="version-info.xml" xpointer="v257"/></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term>EXIT_STATUS=…</term>
 
index ff970df957485a3a6b47ecb8c05743397103927a..cf7e2fe0eb83aad7ed31fc2f2c4bfd34d3292a27 100644 (file)
@@ -351,6 +351,8 @@ const sd_bus_vtable bus_service_vtable[] = {
         SD_BUS_PROPERTY("FileDescriptorStorePreserve", "s", bus_property_get_exec_preserve_mode, offsetof(Service, fd_store_preserve_mode), 0),
         SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("StatusErrno", "i", bus_property_get_int, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("StatusBusError", "s", NULL, offsetof(Service, status_bus_error), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("StatusVarlinkError", "s", NULL, offsetof(Service, status_varlink_error), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("ReloadResult", "s", property_get_result, offsetof(Service, reload_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("CleanResult", "s", property_get_result, offsetof(Service, clean_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
index f37a941a6d4323bdfcbfd25ffb8b2a2de5af7201..937729cd068740bc99201f749af5f08b433937a9 100644 (file)
@@ -468,6 +468,8 @@ static void service_done(Unit *u) {
 
         s->pid_file = mfree(s->pid_file);
         s->status_text = mfree(s->status_text);
+        s->status_bus_error = mfree(s->status_bus_error);
+        s->status_varlink_error = mfree(s->status_varlink_error);
 
         s->exec_runtime = exec_runtime_free(s->exec_runtime);
 
@@ -1045,6 +1047,14 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
                 fprintf(f, "%sStatus Errno: %s\n",
                         prefix, STRERROR(s->status_errno));
 
+        if (s->status_bus_error)
+                fprintf(f, "%sStatus Bus Error: %s\n",
+                        prefix, s->status_bus_error);
+
+        if (s->status_varlink_error)
+                fprintf(f, "%sStatus Varlink Error: %s\n",
+                        prefix, s->status_varlink_error);
+
         if (s->n_fd_store_max > 0)
                 fprintf(f,
                         "%sFile Descriptor Store Max: %u\n"
@@ -2765,6 +2775,8 @@ static int service_start(Unit *u) {
 
         s->status_text = mfree(s->status_text);
         s->status_errno = 0;
+        s->status_bus_error = mfree(s->status_bus_error);
+        s->status_varlink_error = mfree(s->status_varlink_error);
 
         s->notify_access_override = _NOTIFY_ACCESS_INVALID;
         s->notify_state = NOTIFY_UNKNOWN;
@@ -3036,6 +3048,8 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
                 return r;
 
         (void) serialize_item_format(f, "status-errno", "%d", s->status_errno);
+        (void) serialize_item(f, "status-bus-error", s->status_bus_error);
+        (void) serialize_item(f, "status-varlink-error", s->status_varlink_error);
 
         (void) serialize_dual_timestamp(f, "watchdog-timestamp", &s->watchdog_timestamp);
 
@@ -3370,6 +3384,14 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
                 else
                         s->status_errno = i;
 
+        } else if (streq(key, "status-bus-error")) {
+                if (free_and_strdup(&s->status_bus_error, value) < 0)
+                        log_oom_debug();
+
+        } else if (streq(key, "status-varlink-error")) {
+                if (free_and_strdup(&s->status_varlink_error, value) < 0)
+                        log_oom_debug();
+
         } else if (streq(key, "watchdog-timestamp"))
                 (void) deserialize_dual_timestamp(value, &s->watchdog_timestamp);
         else if (streq(key, "watchdog-original-usec"))
@@ -4353,7 +4375,7 @@ static void service_notify_message(
 
         if (DEBUG_LOGGING) {
                 _cleanup_free_ char *cc = strv_join(tags, ", ");
-                log_unit_debug(u, "Got notification message from PID "PID_FMT" (%s)", ucred->pid, empty_to_na(cc));
+                log_unit_debug(u, "Got notification message from PID "PID_FMT": %s", ucred->pid, empty_to_na(cc));
         }
 
         usec_t monotonic_usec = USEC_INFINITY;
@@ -4479,7 +4501,7 @@ static void service_notify_message(
                         else {
                                 t = strdup(e);
                                 if (!t)
-                                        log_oom();
+                                        log_oom_warning();
                         }
                 }
 
@@ -4523,10 +4545,35 @@ static void service_notify_message(
                 }
         }
 
+        static const struct {
+                const char *tag;
+                size_t status_offset;
+        } status_errors[] = {
+                { "BUSERROR=",     offsetof(Service, status_bus_error)     },
+                { "VARLINKERROR=", offsetof(Service, status_varlink_error) },
+        };
+
+        FOREACH_ELEMENT(i, status_errors) {
+                e = strv_find_startswith(tags, i->tag);
+                if (!e)
+                        continue;
+
+                char **status_error = (char**) ((uint8_t*) s + i->status_offset);
+
+                e = empty_to_null(e);
+
+                if (e && !string_is_safe_ascii(e)) {
+                        _cleanup_free_ char *escaped = cescape(e);
+                        log_unit_warning(u, "Got invalid %s string, ignoring: %s", i->tag, strna(escaped));
+                } else if (free_and_strdup_warn(status_error, e) > 0)
+                        notify_dbus = true;
+        }
+
         /* Interpret EXTEND_TIMEOUT= */
         e = strv_find_startswith(tags, "EXTEND_TIMEOUT_USEC=");
         if (e) {
                 usec_t extend_timeout_usec;
+
                 if (safe_atou64(e, &extend_timeout_usec) < 0)
                         log_unit_warning(u, "Failed to parse EXTEND_TIMEOUT_USEC=%s", e);
                 else
index 55ea413f40a30ff719e6c6e8d52a67a69a9e9d88..1d67d13fda4cfbd7fefcfe6e102f2a3129529b9a 100644 (file)
@@ -198,6 +198,8 @@ struct Service {
         char *bus_name;
 
         char *status_text;
+        char *status_bus_error;
+        char *status_varlink_error;
         int status_errno;
 
         sd_event_source *timer_event_source;