]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/unit: make unit_queue_job_check_and_mangle_type() report bus error
authorMike Yuan <me@yhndnzj.com>
Sat, 17 Jan 2026 14:27:24 +0000 (15:27 +0100)
committerMike Yuan <me@yhndnzj.com>
Fri, 23 Jan 2026 23:48:02 +0000 (00:48 +0100)
Our internal logic speaks dbus errors, and that's not changing
anytime soon. Bus errors carried more comprehensive error message
hence let's always return a sd_bus_error on failure, and introduce
varlink_error_id_from_bus_error() for translation.

src/core/dbus-unit.c
src/core/unit.c
src/core/unit.h
src/core/varlink-common.c
src/core/varlink-common.h
src/core/varlink-unit.c

index 18a95955bc9c1bc60ee0cd1b49d22e9053cb825c..2c61ddeb80ce0d222dd44cfc944f1a11cb36ba83 100644 (file)
@@ -1962,19 +1962,11 @@ int bus_unit_queue_job_one(
 
         assert(u);
 
-        r = unit_queue_job_check_and_mangle_type(u, &type, /* reload_if_possible= */ FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE));
-        if (r == -ENOENT)
-                return sd_bus_error_setf(reterr_error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
-        if (r == -ELIBEXEC)
-                return sd_bus_error_setf(reterr_error,
-                                         BUS_ERROR_ONLY_BY_DEPENDENCY,
-                                         "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).",
-                                         u->id);
-        if (r == -ESHUTDOWN)
-                return sd_bus_error_setf(reterr_error,
-                                         BUS_ERROR_SHUTTING_DOWN,
-                                         "Operation for unit %s refused, D-Bus is shutting down.",
-                                         u->id);
+        r = unit_queue_job_check_and_mangle_type(
+                        u,
+                        &type,
+                        /* reload_if_possible= */ FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE),
+                        reterr_error);
         if (r < 0)
                 return r;
 
index 96f56a28e043763695354dc8542f2315ac5b3bcb..e172a9e38c087fc6396b55d501ea019b7fd68190 100644 (file)
@@ -7005,13 +7005,8 @@ UnitDependency unit_mount_dependency_type_to_dependency_type(UnitMountDependency
 int unit_queue_job_check_and_mangle_type(
                 Unit *u,
                 JobType *type, /* input and output */
-                bool reload_if_possible) {
-
-        /* Returns:
-         *
-         * -ENOENT    → Unit not loaded
-         * -ELIBEXEC  → Unit can only be activated via dependency, not directly
-         * -ESHUTDOWN → System bus is shutting down */
+                bool reload_if_possible,
+                sd_bus_error *reterr_error) {
 
         JobType t;
 
@@ -7030,13 +7025,16 @@ int unit_queue_job_check_and_mangle_type(
         /* Our transaction logic allows units not properly loaded to be stopped. But if already dead
          * let's return clear error to caller. */
         if (t == JOB_STOP && UNIT_IS_LOAD_ERROR(u->load_state) && unit_active_state(u) == UNIT_INACTIVE)
-                return -ENOENT;
+                return sd_bus_error_setf(reterr_error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
 
         if ((t == JOB_START && u->refuse_manual_start) ||
             (t == JOB_STOP && u->refuse_manual_stop) ||
             (IN_SET(t, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
             (t == JOB_RELOAD_OR_START && job_type_collapse(t, u) == JOB_START && u->refuse_manual_start))
-                return -ELIBEXEC;
+                return sd_bus_error_setf(reterr_error,
+                                         BUS_ERROR_ONLY_BY_DEPENDENCY,
+                                         "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).",
+                                         u->id);
 
         /* dbus-broker issues StartUnit for activation requests, and Type=dbus services automatically
          * gain dependency on dbus.socket. Therefore, if dbus has a pending stop job, the new start
@@ -7050,7 +7048,10 @@ int unit_queue_job_check_and_mangle_type(
                 FOREACH_STRING(dbus_unit, SPECIAL_DBUS_SOCKET, SPECIAL_DBUS_SERVICE) {
                         Unit *dbus = manager_get_unit(u->manager, dbus_unit);
                         if (dbus && unit_stop_pending(dbus))
-                                return -ESHUTDOWN;
+                                return sd_bus_error_setf(reterr_error,
+                                                         BUS_ERROR_SHUTTING_DOWN,
+                                                         "Operation for unit %s refused, D-Bus is shutting down.",
+                                                         u->id);
                 }
 
         *type = t;
index feaed9125adf3b19a2204f6775a8219f6dbcf219..55a51a6f0e0569543597a3e851c4347a7406428a 100644 (file)
@@ -1092,7 +1092,7 @@ UnitDependency unit_mount_dependency_type_to_dependency_type(UnitMountDependency
 
 DECLARE_STRING_TABLE_LOOKUP(oom_policy, OOMPolicy);
 
-int unit_queue_job_check_and_mangle_type(Unit *u, JobType *type, bool reload_if_possible);
+int unit_queue_job_check_and_mangle_type(Unit *u, JobType *type, bool reload_if_possible, sd_bus_error *reterr_error);
 
 /* Macros which append UNIT= or USER_UNIT= to the message */
 
index babed68378fa602a16ff8c79359d5fc75768e709..e388b1633929d54d452d31de53dd355e5238d9c5 100644 (file)
@@ -1,9 +1,33 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include "sd-bus.h"
+
+#include "bus-common-errors.h"
 #include "cpu-set-util.h"
 #include "json-util.h"
 #include "rlimit-util.h"
 #include "varlink-common.h"
+#include "varlink-unit.h"
+
+const char* varlink_error_id_from_bus_error(const sd_bus_error *e) {
+        static const struct {
+                const char *bus_error;
+                const char *varlink_error;
+        } map[] = {
+                { BUS_ERROR_NO_SUCH_UNIT,       VARLINK_ERROR_UNIT_NO_SUCH_UNIT       },
+                { BUS_ERROR_ONLY_BY_DEPENDENCY, VARLINK_ERROR_UNIT_ONLY_BY_DEPENDENCY },
+                { BUS_ERROR_SHUTTING_DOWN,      VARLINK_ERROR_UNIT_DBUS_SHUTTING_DOWN },
+        };
+
+        if (!sd_bus_error_is_set(e))
+                return NULL;
+
+        FOREACH_ELEMENT(i, map)
+                if (sd_bus_error_has_name(e, i->bus_error))
+                        return i->varlink_error;
+
+        return NULL;
+}
 
 int rlimit_build_json(sd_json_variant **ret, const char *name, void *userdata) {
         const struct rlimit *rl = userdata;
index 5918f9ac68fd3ad1abb29607f6a0e31d7f288f16..82d1458dd9609d8f8ee5666e05b5fffe58661d74 100644 (file)
@@ -6,3 +6,5 @@
 int rlimit_build_json(sd_json_variant **ret, const char *name, void *userdata);
 int rlimit_table_build_json(sd_json_variant **ret, const char *name, void *userdata);
 int cpuset_build_json(sd_json_variant **ret, const char *name, void *userdata);
+
+const char* varlink_error_id_from_bus_error(const sd_bus_error *e);
index 210added6035f2d16815950d55a8d8f71b9517ab..8e061c0d50f4fbf6df445f12988f36eb9de77a07 100644 (file)
@@ -514,19 +514,19 @@ int varlink_unit_queue_job_one(
                 bool reload_if_possible,
                 uint32_t *ret_job_id) {
 
+        _cleanup_(sd_bus_error_free) sd_bus_error bus_error = SD_BUS_ERROR_NULL;
         int r;
 
         assert(u);
 
-        r = unit_queue_job_check_and_mangle_type(u, &type, reload_if_possible);
-        if (r == -ENOENT)
-                return varlink_error_no_such_unit(link, "name");
-        if (r == -ELIBEXEC)
-                return sd_varlink_error(link, VARLINK_ERROR_UNIT_ONLY_BY_DEPENDENCY);
-        if (r == -ESHUTDOWN)
-                return sd_varlink_error(link, VARLINK_ERROR_UNIT_DBUS_SHUTTING_DOWN);
-        if (r < 0)
+        r = unit_queue_job_check_and_mangle_type(u, &type, reload_if_possible, &bus_error);
+        if (r < 0) {
+                const char *error_id = varlink_error_id_from_bus_error(&bus_error);
+                if (error_id)
+                        return sd_varlink_error(link, error_id);
+
                 return r;
+        }
 
         Job *j;
         r = manager_add_job(u->manager, type, u, mode, /* reterr_error= */ NULL, &j);