systemctl: make is-* return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN(4) when no unit file is found
_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)
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) {
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);
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,
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)
}
}
- return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
+ return enabled ? EXIT_SUCCESS : not_found ? EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN : EXIT_FAILURE;
}
#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 */
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)
strv_remove(args + f, name);
}
+ if (streq(verb, "is-enabled"))
+ return enable_state;
#endif
return r;
}
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_;
fi
}
+# shellcheck source=test/units/assert.sh
+. "$(dirname "$0")"/assert.sh
+
trap at_exit EXIT
# Create a simple unit file for testing
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"