From cb7c0950b3fa93379e3ebdbf756f12f4d723cc5d Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Fri, 9 Jan 2026 19:15:06 +0100 Subject: [PATCH] core: ensure varlink Unit.List() can query inactive units manager_get_unit() only returns loaded units, if a unit is stopped and not referenced by anything it will be GCed, so this method will return nothing. Use manager_load_unit() instead so that a stopped unit gets loaded and we can return its state to the caller, after checking that it actually exists. Follow-up for d2a8dbabf5e2676f436515cc821040bd24eb6003 --- src/core/varlink-unit.c | 40 +++++++++++++++++++++++++--- src/shared/varlink-io.systemd.Unit.c | 6 +++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/core/varlink-unit.c b/src/core/varlink-unit.c index aa9a8fb0ede..71430ca5d38 100644 --- a/src/core/varlink-unit.c +++ b/src/core/varlink-unit.c @@ -361,6 +361,40 @@ static int lookup_unit_by_pidref(sd_varlink *link, Manager *manager, PidRef *pid return 0; } +static int load_unit_and_check(sd_varlink *link, Manager *manager, const char *name, Unit **ret_unit) { + Unit *unit; + int r; + + assert(link); + assert(manager); + assert(name); + assert(ret_unit); + + r = manager_load_unit(manager, name, /* path= */ NULL, /* e= */ NULL, &unit); + if (r < 0) + return r; + + /* manager_load_unit() will create an object regardless of whether the unit actually exists, so + * check the state and refuse if it's not in a good state. */ + if (IN_SET(unit->load_state, UNIT_NOT_FOUND, UNIT_STUB, UNIT_MERGED)) + return sd_varlink_error(link, "io.systemd.Unit.NoSuchUnit", NULL); + if (unit->load_state == UNIT_BAD_SETTING) + return sd_varlink_error(link, "io.systemd.Unit.UnitError", NULL); + if (unit->load_state == UNIT_ERROR) + return sd_varlink_errorbo( + link, + SD_VARLINK_ERROR_SYSTEM, + SD_JSON_BUILD_PAIR_STRING("origin", "linux"), + SD_JSON_BUILD_PAIR_INTEGER("errno", unit->load_error), + JSON_BUILD_PAIR_STRING_NON_EMPTY("errnoName", "io.systemd.Unit.UnitError")); + if (unit->load_state == UNIT_MASKED) + return sd_varlink_error(link, "io.systemd.Unit.UnitMasked", NULL); + assert(UNIT_IS_LOAD_COMPLETE(unit->load_state)); + + *ret_unit = unit; + return 0; +} + typedef struct UnitLookupParameters { const char *name, *cgroup; PidRef pidref; @@ -400,9 +434,9 @@ static int lookup_unit_by_parameters( assert(ret); if (p->name) { - unit = manager_get_unit(manager, p->name); - if (!unit) - return varlink_error_no_such_unit(link, "name"); + r = load_unit_and_check(link, manager, p->name, &unit); + if (r < 0) + return r; } if (pidref_is_set_or_automatic(&p->pidref)) { diff --git a/src/shared/varlink-io.systemd.Unit.c b/src/shared/varlink-io.systemd.Unit.c index 19d384dd913..b9128e78dfe 100644 --- a/src/shared/varlink-io.systemd.Unit.c +++ b/src/shared/varlink-io.systemd.Unit.c @@ -1025,6 +1025,8 @@ static SD_VARLINK_DEFINE_ERROR( static SD_VARLINK_DEFINE_ERROR(OnlyByDependency); static SD_VARLINK_DEFINE_ERROR(DBusShuttingDown); +static SD_VARLINK_DEFINE_ERROR(UnitMasked); +static SD_VARLINK_DEFINE_ERROR(UnitError); SD_VARLINK_DEFINE_INTERFACE( io_systemd_Unit, @@ -1091,6 +1093,10 @@ SD_VARLINK_DEFINE_INTERFACE( /* Errors */ SD_VARLINK_SYMBOL_COMMENT("No matching unit found"), &vl_error_NoSuchUnit, + SD_VARLINK_SYMBOL_COMMENT("The unit is masked"), + &vl_error_UnitMasked, + SD_VARLINK_SYMBOL_COMMENT("Unit is in a fatal error state"), + &vl_error_UnitError, SD_VARLINK_SYMBOL_COMMENT("Job for the unit may only be enqueued by dependencies"), &vl_error_OnlyByDependency, SD_VARLINK_SYMBOL_COMMENT("A unit that requires D-Bus cannot be started as D-Bus is shutting down"), -- 2.47.3