[systemd-commits] 8 commits - TODO src/core src/libsystemd src/libsystemd-terminal src/machine src/nspawn src/shared units/systemd-nspawn at .service.in

Lennart Poettering lennart at kemper.freedesktop.org
Tue Apr 28 12:34:40 PDT 2015


 TODO                                    |    8 +++-
 src/core/service.c                      |   58 ++++++++++++++++++++++++--------
 src/libsystemd-terminal/idev-keyboard.c |    2 -
 src/libsystemd/sd-bus/bus-util.c        |   44 +++++++++++++-----------
 src/libsystemd/sd-bus/bus-util.h        |   16 +-------
 src/machine/machine.c                   |   20 +++++++----
 src/machine/machine.h                   |    2 +
 src/machine/machined-dbus.c             |   55 +++++++++++++++++++++++++-----
 src/machine/machined.c                  |    3 +
 src/nspawn/nspawn.c                     |    9 ++++
 src/shared/exit-status.c                |   14 +++++++
 src/shared/exit-status.h                |    1 
 units/systemd-nspawn at .service.in        |   14 +++++++
 13 files changed, 182 insertions(+), 64 deletions(-)

New commits:
commit 5c5b7911d34c765f9de5528e1259ea028d5518c1
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Apr 28 21:33:02 2015 +0200

    update TODO

diff --git a/TODO b/TODO
index 4b2feb0..a39ee28 100644
--- a/TODO
+++ b/TODO
@@ -40,8 +40,14 @@ Before 220:
 * timer units triggering services with failing conditions run busy:
   http://lists.freedesktop.org/archives/systemd-devel/2015-April/030095.html
 
+* logind: follow PropertiesChanged state more closely, to deal with quick logouts and relogins
+
 Features:
 
+* networkd: fix ip forwarding boolean
+
+* sd-bus.h: drop bus parameter in message handlers
+
 * journalctl: -m should access container journals directly by enumerating them via machined, and also watch containers coming and going. Benefit: nspawn --ephemeral would start working nicely with the journal.
 
 * nspawn: don't copy /etc/resolv.conf from host into container unless we are in shared-network mode
@@ -66,8 +72,6 @@ Features:
 * rework C11 utf8.[ch] to use char32_t instead of uint32_t when referring
   to unicode chars, to make things more expressive.
 
-* networkd: MTU= switch for .network units needs documentation in systemd.network(5)
-
 * "machinectl migrate" or similar to copy a container from or to a
   difference host, via ssh
 

commit 11b90e69e5620c2483b019340eff121d504db115
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Apr 28 21:32:42 2015 +0200

    machined: make PropertiesChanged match more strict

diff --git a/src/machine/machined.c b/src/machine/machined.c
index 7980293..1e862ad 100644
--- a/src/machine/machined.c
+++ b/src/machine/machined.c
@@ -194,7 +194,8 @@ static int manager_connect_bus(Manager *m) {
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.DBus.Properties',"
-                             "member='PropertiesChanged'",
+                             "member='PropertiesChanged',"
+                             "arg0='org.freedesktop.systemd1.Unit'",
                              match_properties_changed,
                              m);
         if (r < 0)

commit 9b420b3cfb8b93daf50e4cdbc92b05f2209ef893
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Apr 28 21:17:35 2015 +0200

    machined: make sure to track machine unit states properly
    
    If a unit is stopped for a moment, we need to invalidate our knowledge
    of it, otherwise we might be confused by automatic restarts
    
    This makes reboots for nspawn containers run as service work correctly.
    
    https://bugs.freedesktop.org/show_bug.cgi?id=87428

diff --git a/src/machine/machine.c b/src/machine/machine.c
index dd073ad..05fc4f8 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -80,17 +80,14 @@ void machine_free(Machine *m) {
         if (m->in_gc_queue)
                 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
 
-        if (m->unit) {
-                hashmap_remove(m->manager->machine_units, m->unit);
-                free(m->unit);
-        }
+        machine_release_unit(m);
 
         free(m->scope_job);
 
-        hashmap_remove(m->manager->machines, m->name);
+        (void) hashmap_remove(m->manager->machines, m->name);
 
         if (m->leader > 0)
-                hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
+                (void) hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
 
         sd_bus_message_unref(m->create_message);
 
@@ -526,6 +523,17 @@ MachineOperation *machine_operation_unref(MachineOperation *o) {
         return NULL;
 }
 
+void machine_release_unit(Machine *m) {
+        assert(m);
+
+        if (!m->unit)
+                return;
+
+        (void) hashmap_remove(m->manager->machine_units, m->unit);
+        free(m->unit);
+        m->unit = NULL;
+}
+
 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
         [MACHINE_CONTAINER] = "container",
         [MACHINE_VM] = "vm"
diff --git a/src/machine/machine.h b/src/machine/machine.h
index 7b27aa2..bbe5217 100644
--- a/src/machine/machine.h
+++ b/src/machine/machine.h
@@ -105,6 +105,8 @@ int machine_save(Machine *m);
 int machine_load(Machine *m);
 int machine_kill(Machine *m, KillWho who, int signo);
 
+void machine_release_unit(Machine *m);
+
 MachineState machine_get_state(Machine *u);
 
 MachineOperation *machine_operation_unref(MachineOperation *o);
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 066a8da..7610970 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -24,6 +24,7 @@
 #include <unistd.h>
 
 #include "sd-id128.h"
+#include "strv.h"
 #include "path-util.h"
 #include "unit-name.h"
 #include "bus-util.h"
@@ -923,9 +924,9 @@ int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_b
 
 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *unit = NULL;
+        const char *path, *interface;
         Manager *m = userdata;
         Machine *machine;
-        const char *path;
         int r;
 
         assert(bus);
@@ -939,13 +940,46 @@ int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdat
         r = unit_name_from_dbus_path(path, &unit);
         if (r == -EINVAL) /* not for a unit */
                 return 0;
-        if (r < 0)
-                return r;
+        if (r < 0){
+                log_oom();
+                return 0;
+        }
 
         machine = hashmap_get(m->machine_units, unit);
-        if (machine)
-                machine_add_to_gc_queue(machine);
+        if (!machine)
+                return 0;
+
+        r = sd_bus_message_read(message, "s", &interface);
+        if (r < 0) {
+                bus_log_parse_error(r);
+                return 0;
+        }
+
+        if (streq(interface, "org.freedesktop.systemd1.Unit")) {
+                struct properties {
+                        char *active_state;
+                        char *sub_state;
+                } properties = {};
 
+                const struct bus_properties_map map[] = {
+                        { "ActiveState", "s", NULL, offsetof(struct properties, active_state) },
+                        { "SubState",    "s", NULL, offsetof(struct properties, sub_state)    },
+                        {}
+                };
+
+                r = bus_message_map_properties_changed(message, map, &properties);
+                if (r < 0)
+                        bus_log_parse_error(r);
+                else if (streq_ptr(properties.active_state, "inactive") ||
+                         streq_ptr(properties.active_state, "failed") ||
+                         streq_ptr(properties.sub_state, "auto-restart"))
+                        machine_release_unit(machine);
+
+                free(properties.active_state);
+                free(properties.sub_state);
+        }
+
+        machine_add_to_gc_queue(machine);
         return 0;
 }
 
@@ -962,12 +996,15 @@ int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
         r = sd_bus_message_read(message, "so", &unit, &path);
         if (r < 0) {
                 bus_log_parse_error(r);
-                return r;
+                return 0;
         }
 
         machine = hashmap_get(m->machine_units, unit);
-        if (machine)
-                machine_add_to_gc_queue(machine);
+        if (!machine)
+                return 0;
+
+        machine_release_unit(machine);
+        machine_add_to_gc_queue(machine);
 
         return 0;
 }
@@ -1190,7 +1227,7 @@ int manager_unit_is_active(Manager *manager, const char *unit) {
         if (r < 0)
                 return -EINVAL;
 
-        return !streq(state, "inactive") && !streq(state, "failed");
+        return !STR_IN_SET(state, "inactive", "failed");
 }
 
 int manager_job_is_active(Manager *manager, const char *path) {

commit fe506d569d82467f31862c2ed82ef35f88854149
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Apr 28 20:48:54 2015 +0200

    bus-util: drop redundant bus argument from bus_message_map_all_properties() and related calls

diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c
index 05f5e0c..b5eb737 100644
--- a/src/libsystemd-terminal/idev-keyboard.c
+++ b/src/libsystemd-terminal/idev-keyboard.c
@@ -462,7 +462,7 @@ static int kbdctx_locale_props_changed_fn(sd_bus *bus,
         if (r < 0)
                 goto error;
 
-        r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc);
+        r = bus_message_map_properties_changed(signal, kbdctx_locale_map, kc);
         if (r < 0)
                 goto error;
 
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index 258265d..31bd45c 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -1037,14 +1037,14 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
         return r;
 }
 
-int bus_message_map_all_properties(sd_bus *bus,
-                                   sd_bus_message *m,
-                                   const struct bus_properties_map *map,
-                                   void *userdata) {
+int bus_message_map_all_properties(
+                sd_bus_message *m,
+                const struct bus_properties_map *map,
+                void *userdata) {
+
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
 
-        assert(bus);
         assert(m);
         assert(map);
 
@@ -1080,9 +1080,9 @@ int bus_message_map_all_properties(sd_bus *bus,
 
                         v = (uint8_t *)userdata + prop->offset;
                         if (map[i].set)
-                                r = prop->set(bus, member, m, &error, v);
+                                r = prop->set(sd_bus_message_get_bus(m), member, m, &error, v);
                         else
-                                r = map_basic(bus, member, m, &error, v);
+                                r = map_basic(sd_bus_message_get_bus(m), member, m, &error, v);
                         if (r < 0)
                                 return r;
 
@@ -1099,22 +1099,24 @@ int bus_message_map_all_properties(sd_bus *bus,
                 if (r < 0)
                         return r;
         }
+        if (r < 0)
+                return r;
 
         return sd_bus_message_exit_container(m);
 }
 
-int bus_message_map_properties_changed(sd_bus *bus,
-                                       sd_bus_message *m,
-                                       const struct bus_properties_map *map,
-                                       void *userdata) {
+int bus_message_map_properties_changed(
+                sd_bus_message *m,
+                const struct bus_properties_map *map,
+                void *userdata) {
+
         const char *member;
         int r, invalidated, i;
 
-        assert(bus);
         assert(m);
         assert(map);
 
-        r = bus_message_map_all_properties(bus, m, map, userdata);
+        r = bus_message_map_all_properties(m, map, userdata);
         if (r < 0)
                 return r;
 
@@ -1129,6 +1131,8 @@ int bus_message_map_properties_changed(sd_bus *bus,
                                 ++invalidated;
                                 break;
                         }
+        if (r < 0)
+                return r;
 
         r = sd_bus_message_exit_container(m);
         if (r < 0)
@@ -1137,11 +1141,13 @@ int bus_message_map_properties_changed(sd_bus *bus,
         return invalidated;
 }
 
-int bus_map_all_properties(sd_bus *bus,
-                           const char *destination,
-                           const char *path,
-                           const struct bus_properties_map *map,
-                           void *userdata) {
+int bus_map_all_properties(
+                sd_bus *bus,
+                const char *destination,
+                const char *path,
+                const struct bus_properties_map *map,
+                void *userdata) {
+
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
@@ -1163,7 +1169,7 @@ int bus_map_all_properties(sd_bus *bus,
         if (r < 0)
                 return r;
 
-        return bus_message_map_all_properties(bus, m, map, userdata);
+        return bus_message_map_all_properties(m, map, userdata);
 }
 
 int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h
index 0f7a3b2..d3a18e2 100644
--- a/src/libsystemd/sd-bus/bus-util.h
+++ b/src/libsystemd/sd-bus/bus-util.h
@@ -45,19 +45,9 @@ struct bus_properties_map {
 
 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
 
-int bus_message_map_all_properties(sd_bus *bus,
-                                   sd_bus_message *m,
-                                   const struct bus_properties_map *map,
-                                   void *userdata);
-int bus_message_map_properties_changed(sd_bus *bus,
-                                       sd_bus_message *m,
-                                       const struct bus_properties_map *map,
-                                       void *userdata);
-int bus_map_all_properties(sd_bus *bus,
-                           const char *destination,
-                           const char *path,
-                           const struct bus_properties_map *map,
-                           void *userdata);
+int bus_message_map_all_properties(sd_bus_message *m, const struct bus_properties_map *map,  void *userdata);
+int bus_message_map_properties_changed(sd_bus_message *m, const struct bus_properties_map *map, void *userdata);
+int bus_map_all_properties(sd_bus *bus, const char *destination, const char *path, const struct bus_properties_map *map, void *userdata);
 
 int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name);
 

commit 1a2399e57d9f5943a508720aaddc87512a972378
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Apr 28 20:46:33 2015 +0200

    nspawn: when run as a service, don't ask machined for terminatin of ourselves

diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 29652e0..05d2c71 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2081,6 +2081,11 @@ static int terminate_machine(pid_t pid) {
         if (!arg_register)
                 return 0;
 
+        /* If we are reusing the unit, then just exit, systemd will do
+         * the right thing when we exit. */
+        if (arg_keep_unit)
+                return 0;
+
         r = sd_bus_default_system(&bus);
         if (r < 0)
                 return log_error_errno(r, "Failed to open system bus: %m");

commit 773ce3d89c25aa51b0fe9085bd0eb7ba5e50508b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Apr 28 20:46:03 2015 +0200

    nspawn: make sure we install the device policy if nspawn is run as unit as on the command line

diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index f43ffd9..29652e0 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2014,6 +2014,10 @@ static int register_machine(pid_t pid, int local_ifindex) {
                 if (r < 0)
                         return bus_log_create_error(r);
 
+                /* If you make changes here, also make sure to update
+                 * systemd-nspawn at .service, to keep the device
+                 * policies in sync regardless if we are run with or
+                 * without the --keep-unit switch. */
                 r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 9,
                                           /* Allow the container to
                                            * access and create the API
diff --git a/units/systemd-nspawn at .service.in b/units/systemd-nspawn at .service.in
index 3e26b53..6bfa55a 100644
--- a/units/systemd-nspawn at .service.in
+++ b/units/systemd-nspawn at .service.in
@@ -19,5 +19,19 @@ RestartForceExitStatus=133
 SuccessExitStatus=133
 Delegate=yes
 
+# Enforce a strict device policy, similar to the one nspawn configures
+# when it allocates its own scope unit. Make sure to keep these
+# policies in sync if you change them!
+DevicePolicy=strict
+DeviceAllow=/dev/null rwm
+DeviceAllow=/dev/zero rwm
+DeviceAllow=/dev/full rwm
+DeviceAllow=/dev/random rwm
+DeviceAllow=/dev/urandom rwm
+DeviceAllow=/dev/tty rwm
+DeviceAllow=/dev/net/tun rwm
+DeviceAllow=/dev/pts/ptmx rw
+DeviceAllow=char-pts rw
+
 [Install]
 WantedBy=machines.target

commit a509f0e631b12cfec6aafe4d152532109082efc9
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Apr 28 20:45:25 2015 +0200

    service: make restart logic a bit easier to understand

diff --git a/src/core/service.c b/src/core/service.c
index d004728..3a614b1 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1268,6 +1268,49 @@ static int cgroup_good(Service *s) {
         return !r;
 }
 
+static bool service_shall_restart(Service *s) {
+        assert(s);
+
+        /* Don't restart after manual stops */
+        if (s->forbid_restart)
+                return false;
+
+        /* Never restart if this is configured as special exception */
+        if (exit_status_set_test(&s->restart_prevent_status, s->main_exec_status.code, s->main_exec_status.status))
+                return false;
+
+        /* Restart if the exit code/status are configured as restart triggers */
+        if (exit_status_set_test(&s->restart_force_status,  s->main_exec_status.code, s->main_exec_status.status))
+                return true;
+
+        switch (s->restart) {
+
+        case SERVICE_RESTART_NO:
+                return false;
+
+        case SERVICE_RESTART_ALWAYS:
+                return true;
+
+        case SERVICE_RESTART_ON_SUCCESS:
+                return s->result == SERVICE_SUCCESS;
+
+        case SERVICE_RESTART_ON_FAILURE:
+                return s->result != SERVICE_SUCCESS;
+
+        case SERVICE_RESTART_ON_ABNORMAL:
+                return !IN_SET(s->result, SERVICE_SUCCESS, SERVICE_FAILURE_EXIT_CODE);
+
+        case SERVICE_RESTART_ON_WATCHDOG:
+                return s->result == SERVICE_FAILURE_WATCHDOG;
+
+        case SERVICE_RESTART_ON_ABORT:
+                return IN_SET(s->result, SERVICE_FAILURE_SIGNAL, SERVICE_FAILURE_CORE_DUMP);
+
+        default:
+                assert_not_reached("unknown restart setting");
+        }
+}
+
 static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
         int r;
         assert(s);
@@ -1282,16 +1325,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
                 failure_action(UNIT(s)->manager, s->failure_action, s->reboot_arg);
         }
 
-        if (allow_restart &&
-            !s->forbid_restart &&
-            (s->restart == SERVICE_RESTART_ALWAYS ||
-             (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) ||
-             (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) ||
-             (s->restart == SERVICE_RESTART_ON_ABNORMAL && !IN_SET(s->result, SERVICE_SUCCESS, SERVICE_FAILURE_EXIT_CODE)) ||
-             (s->restart == SERVICE_RESTART_ON_WATCHDOG && s->result == SERVICE_FAILURE_WATCHDOG) ||
-             (s->restart == SERVICE_RESTART_ON_ABORT && IN_SET(s->result, SERVICE_FAILURE_SIGNAL, SERVICE_FAILURE_CORE_DUMP)) ||
-             exit_status_set_test(&s->restart_force_status,  s->main_exec_status.code, s->main_exec_status.status)) &&
-            !exit_status_set_test(&s->restart_prevent_status, s->main_exec_status.code, s->main_exec_status.status)) {
+        if (allow_restart && service_shall_restart(s)) {
 
                 r = service_arm_timer(s, s->restart_usec);
                 if (r < 0)
@@ -1896,7 +1930,7 @@ static int service_stop(Unit *u) {
 
         assert(s);
 
-        /* Don't create restart jobs from here. */
+        /* Don't create restart jobs from manual stops. */
         s->forbid_restart = true;
 
         /* Already on it */

commit 597466f49752a52e85ea04051d020f97e8739f72
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Apr 28 18:24:20 2015 +0200

    exit-status: introduce common exit_status_set_test() call for testing exit status set membership

diff --git a/src/core/service.c b/src/core/service.c
index 9104347..d004728 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1290,10 +1290,8 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
              (s->restart == SERVICE_RESTART_ON_ABNORMAL && !IN_SET(s->result, SERVICE_SUCCESS, SERVICE_FAILURE_EXIT_CODE)) ||
              (s->restart == SERVICE_RESTART_ON_WATCHDOG && s->result == SERVICE_FAILURE_WATCHDOG) ||
              (s->restart == SERVICE_RESTART_ON_ABORT && IN_SET(s->result, SERVICE_FAILURE_SIGNAL, SERVICE_FAILURE_CORE_DUMP)) ||
-             (s->main_exec_status.code == CLD_EXITED && set_contains(s->restart_force_status.status, INT_TO_PTR(s->main_exec_status.status))) ||
-             (IN_SET(s->main_exec_status.code, CLD_KILLED, CLD_DUMPED) && set_contains(s->restart_force_status.signal, INT_TO_PTR(s->main_exec_status.status)))) &&
-            (s->main_exec_status.code != CLD_EXITED || !set_contains(s->restart_prevent_status.status, INT_TO_PTR(s->main_exec_status.status))) &&
-            (!IN_SET(s->main_exec_status.code, CLD_KILLED, CLD_DUMPED) || !set_contains(s->restart_prevent_status.signal, INT_TO_PTR(s->main_exec_status.status)))) {
+             exit_status_set_test(&s->restart_force_status,  s->main_exec_status.code, s->main_exec_status.status)) &&
+            !exit_status_set_test(&s->restart_prevent_status, s->main_exec_status.code, s->main_exec_status.status)) {
 
                 r = service_arm_timer(s, s->restart_usec);
                 if (r < 0)
diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c
index 9e14eb8..c09efdd 100644
--- a/src/shared/exit-status.c
+++ b/src/shared/exit-status.c
@@ -225,3 +225,17 @@ bool exit_status_set_is_empty(ExitStatusSet *x) {
 
         return set_isempty(x->status) && set_isempty(x->signal);
 }
+
+bool exit_status_set_test(ExitStatusSet *x, int code, int status) {
+
+        if (exit_status_set_is_empty(x))
+                return false;
+
+        if (code == CLD_EXITED && set_contains(x->status, INT_TO_PTR(status)))
+                return true;
+
+        if (IN_SET(code, CLD_KILLED, CLD_DUMPED) && set_contains(x->signal, INT_TO_PTR(status)))
+                return true;
+
+        return false;
+}
diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h
index 1d774f2..7259cd1 100644
--- a/src/shared/exit-status.h
+++ b/src/shared/exit-status.h
@@ -100,3 +100,4 @@ bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status);
 
 void exit_status_set_free(ExitStatusSet *x);
 bool exit_status_set_is_empty(ExitStatusSet *x);
+bool exit_status_set_test(ExitStatusSet *x, int code, int status);



More information about the systemd-commits mailing list