]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #25689 from YHNdnzj/systemctl-exit-code
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 14 Dec 2022 07:37:16 +0000 (08:37 +0100)
committerGitHub <noreply@github.com>
Wed, 14 Dec 2022 07:37:16 +0000 (08:37 +0100)
systemctl: make is-* return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN(4) when no unit file is found

src/systemctl/systemctl-is-active.c
src/systemctl/systemctl-is-enabled.c
src/systemctl/systemctl-sysv-compat.c
src/systemctl/systemctl-sysv-compat.h
test/units/testsuite-26.sh

index 7218e900154f78b2edcf7bbda375d2087f6d2056..15e366ccae227bd65259523b3c30b7db1f292df3 100644 (file)
@@ -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) {
index 2d33313eb826aca8d611ba793566dead6cf8d6db..e3bfd62c3f5a76de62f0fa3ae06e51ad797841a2 100644 (file)
@@ -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;
 }
index f6889993ed31276037aa0ca586a8aede8b87ba79..0412b0c62661c5c5b4377fd6ee5f9bb14568f73d 100644 (file)
@@ -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;
 }
index 86fd3ec1861cf3c8ba7056c99309f15c70156538..05db6ec6f2276aca63e941b6f4f964a4c070580b 100644 (file)
@@ -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_;
index 7c7a12b1ae5a683c07b6063bfaba2e97969651fc..70fdc5956e56f4d574dded1e47affdcb4a95810f 100755 (executable)
@@ -9,6 +9,9 @@ at_exit() {
     fi
 }
 
+# shellcheck source=test/units/assert.sh
+. "$(dirname "$0")"/assert.sh
+
 trap at_exit EXIT
 
 # Create a simple unit file for testing
@@ -79,6 +82,16 @@ systemctl list-jobs --before
 systemctl list-jobs --after --before
 systemctl list-jobs "*"
 
+# is-* verbs
+# Should return 4 for a missing unit file
+assert_rc 4 systemctl --quiet is-active not-found.service
+assert_rc 4 systemctl --quiet is-failed not-found.service
+assert_rc 4 systemctl --quiet is-enabled not-found.service
+# is-active: return 3 when the unit exists but inactive
+assert_rc 3 systemctl --quiet is-active "$UNIT_NAME"
+# is-enabled: return 1 when the unit exists but disabled
+assert_rc 1 systemctl --quiet is-enabled "$UNIT_NAME"
+
 # Basic service management
 systemctl start --show-transaction "$UNIT_NAME"
 systemctl status -n 5 "$UNIT_NAME"