]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared: split out code to wait for jobs to complet into its own source file
authorLennart Poettering <lennart@poettering.net>
Wed, 6 Mar 2019 18:38:45 +0000 (19:38 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 13 Mar 2019 16:39:24 +0000 (17:39 +0100)
It's complex enough and quite a few functions. Let's hence split this
out.

No code change, just some rearranging of source files.

src/machine/machinectl.c
src/mount/mount-tool.c
src/nspawn/nspawn-register.c
src/run/run.c
src/shared/bus-unit-util.c
src/shared/bus-unit-util.h
src/shared/bus-wait-for-jobs.c [new file with mode: 0644]
src/shared/bus-wait-for-jobs.h [new file with mode: 0644]
src/shared/meson.build
src/systemctl/systemctl.c

index 78f5f2ff3238ae4b719c828dfed3aceefcea5130..c6541aedb0bc009e28aa8f8a6734688c9bd4d9b6 100644 (file)
@@ -20,6 +20,7 @@
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "bus-wait-for-jobs.h"
 #include "cgroup-show.h"
 #include "cgroup-util.h"
 #include "copy.h"
index 1fc8c954d9d2847bd2b90cac3ede4ad2bae158a4..6256920e997db9549a2182699e5af882319f279f 100644 (file)
@@ -8,6 +8,7 @@
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "bus-wait-for-jobs.h"
 #include "device-util.h"
 #include "dirent-util.h"
 #include "escape.h"
index a7cdfc1c7dedfe1b07303980865c0b3e16d9ffb3..4ca5f7998d703cf753387cedd50c9c4fcb85e5ee 100644 (file)
@@ -5,6 +5,7 @@
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "bus-wait-for-jobs.h"
 #include "nspawn-register.h"
 #include "special.h"
 #include "stat-util.h"
index e9e31282b6fc2e8f591f9a3caa27f60e8831c8aa..3f2221f610a1f82c4ddc9c6bbb4d194fce3f1a12 100644 (file)
@@ -10,6 +10,7 @@
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "bus-wait-for-jobs.h"
 #include "calendarspec.h"
 #include "env-util.h"
 #include "fd-util.h"
index a25e82e0176d6191d32745b5c9e90bb43b037dc2..b3d1f51251ca61fb63e7ef2435a0c13f9008840b 100644 (file)
@@ -1,32 +1,29 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "alloc-util.h"
-#include "bus-internal.h"
+#include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
 #include "cap-list.h"
 #include "cgroup-util.h"
 #include "condition.h"
 #include "cpu-set-util.h"
-#include "env-util.h"
-#include "errno-list.h"
 #include "escape.h"
-#include "hashmap.h"
 #include "hexdecoct.h"
 #include "hostname-util.h"
 #include "in-addr-util.h"
 #include "ip-protocol-list.h"
-#include "list.h"
 #include "locale-util.h"
+#include "log.h"
 #include "missing_fs.h"
 #include "mountpoint-util.h"
 #include "nsflags.h"
 #include "parse-util.h"
-#include "path-util.h"
 #include "process-util.h"
 #include "rlimit-util.h"
 #include "securebits-util.h"
 #include "signal-util.h"
+#include "socket-util.h"
 #include "sort-util.h"
 #include "string-util.h"
 #include "syslog-util.h"
@@ -1772,329 +1769,6 @@ int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char
         return 0;
 }
 
-typedef struct BusWaitForJobs {
-        sd_bus *bus;
-        Set *jobs;
-
-        char *name;
-        char *result;
-
-        sd_bus_slot *slot_job_removed;
-        sd_bus_slot *slot_disconnected;
-} BusWaitForJobs;
-
-static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        assert(m);
-
-        log_error("Warning! D-Bus connection terminated.");
-        sd_bus_close(sd_bus_message_get_bus(m));
-
-        return 0;
-}
-
-static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        const char *path, *unit, *result;
-        BusWaitForJobs *d = userdata;
-        uint32_t id;
-        char *found;
-        int r;
-
-        assert(m);
-        assert(d);
-
-        r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
-        if (r < 0) {
-                bus_log_parse_error(r);
-                return 0;
-        }
-
-        found = set_remove(d->jobs, (char*) path);
-        if (!found)
-                return 0;
-
-        free(found);
-
-        (void) free_and_strdup(&d->result, empty_to_null(result));
-        (void) free_and_strdup(&d->name, empty_to_null(unit));
-
-        return 0;
-}
-
-void bus_wait_for_jobs_free(BusWaitForJobs *d) {
-        if (!d)
-                return;
-
-        set_free_free(d->jobs);
-
-        sd_bus_slot_unref(d->slot_disconnected);
-        sd_bus_slot_unref(d->slot_job_removed);
-
-        sd_bus_unref(d->bus);
-
-        free(d->name);
-        free(d->result);
-
-        free(d);
-}
-
-int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
-        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
-        int r;
-
-        assert(bus);
-        assert(ret);
-
-        d = new(BusWaitForJobs, 1);
-        if (!d)
-                return -ENOMEM;
-
-        *d = (BusWaitForJobs) {
-                .bus = sd_bus_ref(bus),
-        };
-
-        /* When we are a bus client we match by sender. Direct
-         * connections OTOH have no initialized sender field, and
-         * hence we ignore the sender then */
-        r = sd_bus_match_signal_async(
-                        bus,
-                        &d->slot_job_removed,
-                        bus->bus_client ? "org.freedesktop.systemd1" : NULL,
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "JobRemoved",
-                        match_job_removed, NULL, d);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_match_signal_async(
-                        bus,
-                        &d->slot_disconnected,
-                        "org.freedesktop.DBus.Local",
-                        NULL,
-                        "org.freedesktop.DBus.Local",
-                        "Disconnected",
-                        match_disconnected, NULL, d);
-        if (r < 0)
-                return r;
-
-        *ret = TAKE_PTR(d);
-
-        return 0;
-}
-
-static int bus_process_wait(sd_bus *bus) {
-        int r;
-
-        for (;;) {
-                r = sd_bus_process(bus, NULL);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        return 0;
-
-                r = sd_bus_wait(bus, (uint64_t) -1);
-                if (r < 0)
-                        return r;
-        }
-}
-
-static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
-        _cleanup_free_ char *dbus_path = NULL;
-
-        assert(d);
-        assert(d->name);
-        assert(result);
-
-        if (!endswith(d->name, ".service"))
-                return -EINVAL;
-
-        dbus_path = unit_dbus_path_from_name(d->name);
-        if (!dbus_path)
-                return -ENOMEM;
-
-        return sd_bus_get_property_string(d->bus,
-                                          "org.freedesktop.systemd1",
-                                          dbus_path,
-                                          "org.freedesktop.systemd1.Service",
-                                          "Result",
-                                          NULL,
-                                          result);
-}
-
-static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
-        _cleanup_free_ char *service_shell_quoted = NULL;
-        const char *systemctl = "systemctl", *journalctl = "journalctl";
-
-        static const struct {
-                const char *result, *explanation;
-        } explanations[] = {
-                { "resources",   "of unavailable resources or another system error" },
-                { "protocol",    "the service did not take the steps required by its unit configuration" },
-                { "timeout",     "a timeout was exceeded" },
-                { "exit-code",   "the control process exited with error code" },
-                { "signal",      "a fatal signal was delivered to the control process" },
-                { "core-dump",   "a fatal signal was delivered causing the control process to dump core" },
-                { "watchdog",    "the service failed to send watchdog ping" },
-                { "start-limit", "start of the service was attempted too often" }
-        };
-
-        assert(service);
-
-        service_shell_quoted = shell_maybe_quote(service, ESCAPE_BACKSLASH);
-
-        if (!strv_isempty((char**) extra_args)) {
-                _cleanup_free_ char *t;
-
-                t = strv_join((char**) extra_args, " ");
-                systemctl = strjoina("systemctl ", t ? : "<args>");
-                journalctl = strjoina("journalctl ", t ? : "<args>");
-        }
-
-        if (!isempty(result)) {
-                size_t i;
-
-                for (i = 0; i < ELEMENTSOF(explanations); ++i)
-                        if (streq(result, explanations[i].result))
-                                break;
-
-                if (i < ELEMENTSOF(explanations)) {
-                        log_error("Job for %s failed because %s.\n"
-                                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
-                                  service,
-                                  explanations[i].explanation,
-                                  systemctl,
-                                  service_shell_quoted ?: "<service>",
-                                  journalctl);
-                        goto finish;
-                }
-        }
-
-        log_error("Job for %s failed.\n"
-                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
-                  service,
-                  systemctl,
-                  service_shell_quoted ?: "<service>",
-                  journalctl);
-
-finish:
-        /* For some results maybe additional explanation is required */
-        if (streq_ptr(result, "start-limit"))
-                log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
-                         "followed by \"%1$s start %2$s\" again.",
-                         systemctl,
-                         service_shell_quoted ?: "<service>");
-}
-
-static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
-        assert(d);
-        assert(d->name);
-        assert(d->result);
-
-        if (!quiet) {
-                if (streq(d->result, "canceled"))
-                        log_error("Job for %s canceled.", strna(d->name));
-                else if (streq(d->result, "timeout"))
-                        log_error("Job for %s timed out.", strna(d->name));
-                else if (streq(d->result, "dependency"))
-                        log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
-                else if (streq(d->result, "invalid"))
-                        log_error("%s is not active, cannot reload.", strna(d->name));
-                else if (streq(d->result, "assert"))
-                        log_error("Assertion failed on job for %s.", strna(d->name));
-                else if (streq(d->result, "unsupported"))
-                        log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
-                else if (streq(d->result, "collected"))
-                        log_error("Queued job for %s was garbage collected.", strna(d->name));
-                else if (streq(d->result, "once"))
-                        log_error("Unit %s was started already once and can't be started again.", strna(d->name));
-                else if (!STR_IN_SET(d->result, "done", "skipped")) {
-
-                        if (d->name && endswith(d->name, ".service")) {
-                                _cleanup_free_ char *result = NULL;
-                                int q;
-
-                                q = bus_job_get_service_result(d, &result);
-                                if (q < 0)
-                                        log_debug_errno(q, "Failed to get Result property of unit %s: %m", d->name);
-
-                                log_job_error_with_service_result(d->name, result, extra_args);
-                        } else
-                                log_error("Job failed. See \"journalctl -xe\" for details.");
-                }
-        }
-
-        if (STR_IN_SET(d->result, "canceled", "collected"))
-                return -ECANCELED;
-        else if (streq(d->result, "timeout"))
-                return -ETIME;
-        else if (streq(d->result, "dependency"))
-                return -EIO;
-        else if (streq(d->result, "invalid"))
-                return -ENOEXEC;
-        else if (streq(d->result, "assert"))
-                return -EPROTO;
-        else if (streq(d->result, "unsupported"))
-                return -EOPNOTSUPP;
-        else if (streq(d->result, "once"))
-                return -ESTALE;
-        else if (STR_IN_SET(d->result, "done", "skipped"))
-                return 0;
-
-        return log_debug_errno(SYNTHETIC_ERRNO(EIO),
-                               "Unexpected job result, assuming server side newer than us: %s", d->result);
-}
-
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
-        int r = 0;
-
-        assert(d);
-
-        while (!set_isempty(d->jobs)) {
-                int q;
-
-                q = bus_process_wait(d->bus);
-                if (q < 0)
-                        return log_error_errno(q, "Failed to wait for response: %m");
-
-                if (d->name && d->result) {
-                        q = check_wait_response(d, quiet, extra_args);
-                        /* Return the first error as it is most likely to be
-                         * meaningful. */
-                        if (q < 0 && r == 0)
-                                r = q;
-
-                        log_debug_errno(q, "Got result %s/%m for job %s", d->result, d->name);
-                }
-
-                d->name = mfree(d->name);
-                d->result = mfree(d->result);
-        }
-
-        return r;
-}
-
-int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
-        int r;
-
-        assert(d);
-
-        r = set_ensure_allocated(&d->jobs, &string_hash_ops);
-        if (r < 0)
-                return r;
-
-        return set_put_strdup(d->jobs, path);
-}
-
-int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
-        int r;
-
-        r = bus_wait_for_jobs_add(d, path);
-        if (r < 0)
-                return log_oom();
-
-        return bus_wait_for_jobs(d, quiet, NULL);
-}
-
 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
         const char *type, *path, *source;
         int r;
index 4fc94b0f4e151415cd5598a26357b5f2739ba12e..ba93fae7496000c3d2a4a66776b0a8dafcf859b5 100644 (file)
@@ -25,16 +25,6 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
 int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment);
 int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l);
 
-typedef struct BusWaitForJobs BusWaitForJobs;
-
-int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
-void bus_wait_for_jobs_free(BusWaitForJobs *d);
-int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args);
-int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
-
 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes);
 
 int unit_show_processes(sd_bus *bus, const char *unit, const char *cgroup_path, const char *prefix, unsigned n_columns, OutputFlags flags, sd_bus_error *error);
diff --git a/src/shared/bus-wait-for-jobs.c b/src/shared/bus-wait-for-jobs.c
new file mode 100644 (file)
index 0000000..2f2b0a5
--- /dev/null
@@ -0,0 +1,333 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "bus-wait-for-jobs.h"
+#include "set.h"
+#include "bus-util.h"
+#include "bus-internal.h"
+#include "unit-def.h"
+#include "escape.h"
+#include "strv.h"
+
+typedef struct BusWaitForJobs {
+        sd_bus *bus;
+        Set *jobs;
+
+        char *name;
+        char *result;
+
+        sd_bus_slot *slot_job_removed;
+        sd_bus_slot *slot_disconnected;
+} BusWaitForJobs;
+
+static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        assert(m);
+
+        log_error("Warning! D-Bus connection terminated.");
+        sd_bus_close(sd_bus_message_get_bus(m));
+
+        return 0;
+}
+
+static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        const char *path, *unit, *result;
+        BusWaitForJobs *d = userdata;
+        uint32_t id;
+        char *found;
+        int r;
+
+        assert(m);
+        assert(d);
+
+        r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
+        if (r < 0) {
+                bus_log_parse_error(r);
+                return 0;
+        }
+
+        found = set_remove(d->jobs, (char*) path);
+        if (!found)
+                return 0;
+
+        free(found);
+
+        (void) free_and_strdup(&d->result, empty_to_null(result));
+        (void) free_and_strdup(&d->name, empty_to_null(unit));
+
+        return 0;
+}
+
+void bus_wait_for_jobs_free(BusWaitForJobs *d) {
+        if (!d)
+                return;
+
+        set_free_free(d->jobs);
+
+        sd_bus_slot_unref(d->slot_disconnected);
+        sd_bus_slot_unref(d->slot_job_removed);
+
+        sd_bus_unref(d->bus);
+
+        free(d->name);
+        free(d->result);
+
+        free(d);
+}
+
+int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
+        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
+        int r;
+
+        assert(bus);
+        assert(ret);
+
+        d = new(BusWaitForJobs, 1);
+        if (!d)
+                return -ENOMEM;
+
+        *d = (BusWaitForJobs) {
+                .bus = sd_bus_ref(bus),
+        };
+
+        /* When we are a bus client we match by sender. Direct
+         * connections OTOH have no initialized sender field, and
+         * hence we ignore the sender then */
+        r = sd_bus_match_signal_async(
+                        bus,
+                        &d->slot_job_removed,
+                        bus->bus_client ? "org.freedesktop.systemd1" : NULL,
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "JobRemoved",
+                        match_job_removed, NULL, d);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_match_signal_async(
+                        bus,
+                        &d->slot_disconnected,
+                        "org.freedesktop.DBus.Local",
+                        NULL,
+                        "org.freedesktop.DBus.Local",
+                        "Disconnected",
+                        match_disconnected, NULL, d);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(d);
+
+        return 0;
+}
+
+static int bus_process_wait(sd_bus *bus) {
+        int r;
+
+        for (;;) {
+                r = sd_bus_process(bus, NULL);
+                if (r < 0)
+                        return r;
+                if (r > 0)
+                        return 0;
+
+                r = sd_bus_wait(bus, (uint64_t) -1);
+                if (r < 0)
+                        return r;
+        }
+}
+
+static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
+        _cleanup_free_ char *dbus_path = NULL;
+
+        assert(d);
+        assert(d->name);
+        assert(result);
+
+        if (!endswith(d->name, ".service"))
+                return -EINVAL;
+
+        dbus_path = unit_dbus_path_from_name(d->name);
+        if (!dbus_path)
+                return -ENOMEM;
+
+        return sd_bus_get_property_string(d->bus,
+                                          "org.freedesktop.systemd1",
+                                          dbus_path,
+                                          "org.freedesktop.systemd1.Service",
+                                          "Result",
+                                          NULL,
+                                          result);
+}
+
+static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
+        _cleanup_free_ char *service_shell_quoted = NULL;
+        const char *systemctl = "systemctl", *journalctl = "journalctl";
+
+        static const struct {
+                const char *result, *explanation;
+        } explanations[] = {
+                { "resources",   "of unavailable resources or another system error" },
+                { "protocol",    "the service did not take the steps required by its unit configuration" },
+                { "timeout",     "a timeout was exceeded" },
+                { "exit-code",   "the control process exited with error code" },
+                { "signal",      "a fatal signal was delivered to the control process" },
+                { "core-dump",   "a fatal signal was delivered causing the control process to dump core" },
+                { "watchdog",    "the service failed to send watchdog ping" },
+                { "start-limit", "start of the service was attempted too often" }
+        };
+
+        assert(service);
+
+        service_shell_quoted = shell_maybe_quote(service, ESCAPE_BACKSLASH);
+
+        if (!strv_isempty((char**) extra_args)) {
+                _cleanup_free_ char *t;
+
+                t = strv_join((char**) extra_args, " ");
+                systemctl = strjoina("systemctl ", t ? : "<args>");
+                journalctl = strjoina("journalctl ", t ? : "<args>");
+        }
+
+        if (!isempty(result)) {
+                size_t i;
+
+                for (i = 0; i < ELEMENTSOF(explanations); ++i)
+                        if (streq(result, explanations[i].result))
+                                break;
+
+                if (i < ELEMENTSOF(explanations)) {
+                        log_error("Job for %s failed because %s.\n"
+                                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
+                                  service,
+                                  explanations[i].explanation,
+                                  systemctl,
+                                  service_shell_quoted ?: "<service>",
+                                  journalctl);
+                        goto finish;
+                }
+        }
+
+        log_error("Job for %s failed.\n"
+                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
+                  service,
+                  systemctl,
+                  service_shell_quoted ?: "<service>",
+                  journalctl);
+
+finish:
+        /* For some results maybe additional explanation is required */
+        if (streq_ptr(result, "start-limit"))
+                log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
+                         "followed by \"%1$s start %2$s\" again.",
+                         systemctl,
+                         service_shell_quoted ?: "<service>");
+}
+
+static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
+        assert(d);
+        assert(d->name);
+        assert(d->result);
+
+        if (!quiet) {
+                if (streq(d->result, "canceled"))
+                        log_error("Job for %s canceled.", strna(d->name));
+                else if (streq(d->result, "timeout"))
+                        log_error("Job for %s timed out.", strna(d->name));
+                else if (streq(d->result, "dependency"))
+                        log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
+                else if (streq(d->result, "invalid"))
+                        log_error("%s is not active, cannot reload.", strna(d->name));
+                else if (streq(d->result, "assert"))
+                        log_error("Assertion failed on job for %s.", strna(d->name));
+                else if (streq(d->result, "unsupported"))
+                        log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
+                else if (streq(d->result, "collected"))
+                        log_error("Queued job for %s was garbage collected.", strna(d->name));
+                else if (streq(d->result, "once"))
+                        log_error("Unit %s was started already once and can't be started again.", strna(d->name));
+                else if (!STR_IN_SET(d->result, "done", "skipped")) {
+
+                        if (d->name && endswith(d->name, ".service")) {
+                                _cleanup_free_ char *result = NULL;
+                                int q;
+
+                                q = bus_job_get_service_result(d, &result);
+                                if (q < 0)
+                                        log_debug_errno(q, "Failed to get Result property of unit %s: %m", d->name);
+
+                                log_job_error_with_service_result(d->name, result, extra_args);
+                        } else
+                                log_error("Job failed. See \"journalctl -xe\" for details.");
+                }
+        }
+
+        if (STR_IN_SET(d->result, "canceled", "collected"))
+                return -ECANCELED;
+        else if (streq(d->result, "timeout"))
+                return -ETIME;
+        else if (streq(d->result, "dependency"))
+                return -EIO;
+        else if (streq(d->result, "invalid"))
+                return -ENOEXEC;
+        else if (streq(d->result, "assert"))
+                return -EPROTO;
+        else if (streq(d->result, "unsupported"))
+                return -EOPNOTSUPP;
+        else if (streq(d->result, "once"))
+                return -ESTALE;
+        else if (STR_IN_SET(d->result, "done", "skipped"))
+                return 0;
+
+        return log_debug_errno(SYNTHETIC_ERRNO(EIO),
+                               "Unexpected job result, assuming server side newer than us: %s", d->result);
+}
+
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
+        int r = 0;
+
+        assert(d);
+
+        while (!set_isempty(d->jobs)) {
+                int q;
+
+                q = bus_process_wait(d->bus);
+                if (q < 0)
+                        return log_error_errno(q, "Failed to wait for response: %m");
+
+                if (d->name && d->result) {
+                        q = check_wait_response(d, quiet, extra_args);
+                        /* Return the first error as it is most likely to be
+                         * meaningful. */
+                        if (q < 0 && r == 0)
+                                r = q;
+
+                        log_debug_errno(q, "Got result %s/%m for job %s", d->result, d->name);
+                }
+
+                d->name = mfree(d->name);
+                d->result = mfree(d->result);
+        }
+
+        return r;
+}
+
+int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
+        int r;
+
+        assert(d);
+
+        r = set_ensure_allocated(&d->jobs, &string_hash_ops);
+        if (r < 0)
+                return r;
+
+        return set_put_strdup(d->jobs, path);
+}
+
+int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
+        int r;
+
+        r = bus_wait_for_jobs_add(d, path);
+        if (r < 0)
+                return log_oom();
+
+        return bus_wait_for_jobs(d, quiet, NULL);
+}
diff --git a/src/shared/bus-wait-for-jobs.h b/src/shared/bus-wait-for-jobs.h
new file mode 100644 (file)
index 0000000..8f21eb9
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "sd-bus.h"
+#include "macro.h"
+
+typedef struct BusWaitForJobs BusWaitForJobs;
+
+int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
+void bus_wait_for_jobs_free(BusWaitForJobs *d);
+int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args);
+int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
index 83a9df24cba2e0b4c72197b75d579b8a8324bfc6..ed659f0fbc3464044c4140a44bafbaad01049e32 100644 (file)
@@ -25,6 +25,8 @@ shared_sources = files('''
         bus-unit-util.h
         bus-util.c
         bus-util.h
+        bus-wait-for-jobs.c
+        bus-wait-for-jobs.h
         calendarspec.c
         calendarspec.h
         cgroup-show.c
index e48d34c4d7d776222ef8d9aa2c6174df9959a505..c337da084b05bf418854f9233b5376efd565c607 100644 (file)
@@ -26,6 +26,7 @@
 #include "bus-message.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "bus-wait-for-jobs.h"
 #include "cgroup-show.h"
 #include "cgroup-util.h"
 #include "copy.h"