From: Mike Yuan Date: Sat, 10 Dec 2022 12:55:42 +0000 (+0800) Subject: systemctl: is-*: return correct code when no unit is found X-Git-Tag: v253-rc1~297^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=43e48a47383e05914b4a96c31d356ea8aa9f98f5;p=thirdparty%2Fsystemd.git systemctl: is-*: return correct code when no unit is found According to systemctl(1), we should use LSB return code 4 (EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN) when the state is "no such unit" for is-{active,failed,enabled} verbs. Fixes #25680 --- diff --git a/src/systemctl/systemctl-is-active.c b/src/systemctl/systemctl-is-active.c index 7218e900154..15e366ccae2 100644 --- a/src/systemctl/systemctl-is-active.c +++ b/src/systemctl/systemctl-is-active.c @@ -13,8 +13,8 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int _cleanup_strv_free_ char **names = NULL; UnitActiveState active_state; sd_bus *bus; + bool not_found = true, ok = false; int r; - bool found = false; r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -25,21 +25,32 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { + _cleanup_free_ char *load_state = NULL; + r = get_state_one_unit(bus, *name, &active_state); if (r < 0) return r; + r = unit_load_state(bus, *name, &load_state); + if (r < 0) + return r; + if (!arg_quiet) puts(unit_active_state_to_string(active_state)); for (int i = 0; i < nb_states; ++i) - if (good_states[i] == active_state) - found = true; + if (good_states[i] == active_state) { + ok = true; + break; + } + + if (!streq(load_state, "not-found")) + not_found = false; } - /* use the given return code for the case that we won't find - * any unit which matches the list */ - return found ? 0 : code; + /* We use LSB code 4 ("program or service status is unknown") + * when the corresponding unit file doesn't exist. */ + return ok ? EXIT_SUCCESS : not_found ? EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN : code; } int verb_is_active(int argc, char *argv[], void *userdata) { diff --git a/src/systemctl/systemctl-is-enabled.c b/src/systemctl/systemctl-is-enabled.c index 2d33313eb82..e3bfd62c3f5 100644 --- a/src/systemctl/systemctl-is-enabled.c +++ b/src/systemctl/systemctl-is-enabled.c @@ -58,7 +58,7 @@ static int show_installation_targets(sd_bus *bus, const char *name) { int verb_is_enabled(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; - bool enabled; + bool not_found, enabled; int r; r = mangle_names("to check", strv_skip(argv, 1), &names); @@ -69,15 +69,22 @@ int verb_is_enabled(int argc, char *argv[], void *userdata) { if (r < 0) return r; - enabled = r > 0; + not_found = r == 0; /* Doesn't have SysV support or SYSV_UNIT_NOT_FOUND */ + enabled = r == SYSV_UNIT_ENABLED; if (install_client_side()) { STRV_FOREACH(name, names) { UnitFileState state; r = unit_file_get_state(arg_scope, arg_root, *name, &state); - if (r < 0) + if (r == -ENOENT) { + if (!arg_quiet) + puts("not-found"); + continue; + } else if (r < 0) return log_error_errno(r, "Failed to get unit file state for %s: %m", *name); + else + not_found = false; if (IN_SET(state, UNIT_FILE_ENABLED, @@ -112,8 +119,19 @@ int verb_is_enabled(int argc, char *argv[], void *userdata) { const char *s; r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileState", &error, &reply, "s", *name); - if (r < 0) - return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r)); + if (r == -ENOENT) { + sd_bus_error_free(&error); + + if (!arg_quiet) + puts("not-found"); + continue; + } else if (r < 0) + return log_error_errno(r, + "Failed to get unit file state for %s: %s", + *name, + bus_error_message(&error, r)); + else + not_found = false; r = sd_bus_message_read(reply, "s", &s); if (r < 0) @@ -133,5 +151,5 @@ int verb_is_enabled(int argc, char *argv[], void *userdata) { } } - return enabled ? EXIT_SUCCESS : EXIT_FAILURE; + return enabled ? EXIT_SUCCESS : not_found ? EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN : EXIT_FAILURE; } diff --git a/src/systemctl/systemctl-sysv-compat.c b/src/systemctl/systemctl-sysv-compat.c index f6889993ed3..0412b0c6266 100644 --- a/src/systemctl/systemctl-sysv-compat.c +++ b/src/systemctl/systemctl-sysv-compat.c @@ -113,6 +113,7 @@ int enable_sysv_units(const char *verb, char **args) { #if HAVE_SYSV_COMPAT _cleanup_(lookup_paths_free) LookupPaths paths = {}; unsigned f = 0; + SysVUnitEnableState enable_state = SYSV_UNIT_NOT_FOUND; /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */ @@ -226,10 +227,12 @@ int enable_sysv_units(const char *verb, char **args) { if (j == EXIT_SUCCESS) { if (!arg_quiet) puts("enabled"); - r = 1; + enable_state = SYSV_UNIT_ENABLED; } else { if (!arg_quiet) puts("disabled"); + if (enable_state != SYSV_UNIT_ENABLED) + enable_state = SYSV_UNIT_DISABLED; } } else if (j != EXIT_SUCCESS) @@ -245,6 +248,8 @@ int enable_sysv_units(const char *verb, char **args) { strv_remove(args + f, name); } + if (streq(verb, "is-enabled")) + return enable_state; #endif return r; } diff --git a/src/systemctl/systemctl-sysv-compat.h b/src/systemctl/systemctl-sysv-compat.h index 86fd3ec1861..05db6ec6f22 100644 --- a/src/systemctl/systemctl-sysv-compat.h +++ b/src/systemctl/systemctl-sysv-compat.h @@ -30,6 +30,12 @@ enum { EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN = 4, }; +typedef enum SysVUnitEnableState { + SYSV_UNIT_NOT_FOUND = 0, + SYSV_UNIT_DISABLED, + SYSV_UNIT_ENABLED, +} SysVUnitEnableState; + int enable_sysv_units(const char *verb, char **args); int action_to_runlevel(void) _pure_;