#include "cgroup-show.h"
#include "cgroup-util.h"
#include "copy.h"
+#include "cpu-set-util.h"
#include "dropin.h"
#include "efivars.h"
#include "env-util.h"
#include "escape.h"
+#include "exec-util.h"
#include "exit-status.h"
#include "fd-util.h"
#include "format-util.h"
static bool arg_quiet = false;
static bool arg_full = false;
static bool arg_recursive = false;
+static bool arg_show_transaction = false;
static int arg_force = 0;
static bool arg_ask_password = false;
static bool arg_runtime = false;
_BUS_FOCUS_MAX
} BusFocus;
-static sd_bus *busses[_BUS_FOCUS_MAX] = {};
+static sd_bus *buses[_BUS_FOCUS_MAX] = {};
static UnitFileFlags args_to_flags(void) {
return (arg_runtime ? UNIT_FILE_RUNTIME : 0) |
if (getenv_bool("SYSTEMCTL_FORCE_BUS") > 0)
focus = BUS_FULL;
- if (!busses[focus]) {
+ if (!buses[focus]) {
bool user;
user = arg_scope != UNIT_FILE_SYSTEM;
if (focus == BUS_MANAGER)
- r = bus_connect_transport_systemd(arg_transport, arg_host, user, &busses[focus]);
+ r = bus_connect_transport_systemd(arg_transport, arg_host, user, &buses[focus]);
else
- r = bus_connect_transport(arg_transport, arg_host, user, &busses[focus]);
+ r = bus_connect_transport(arg_transport, arg_host, user, &buses[focus]);
if (r < 0)
return log_error_errno(r, "Failed to connect to bus: %m");
- (void) sd_bus_set_allow_interactive_authorization(busses[focus], arg_ask_password);
+ (void) sd_bus_set_allow_interactive_authorization(buses[focus], arg_ask_password);
}
- *ret = busses[focus];
+ *ret = buses[focus];
return 0;
}
BusFocus w;
for (w = 0; w < _BUS_FOCUS_MAX; w++)
- busses[w] = sd_bus_flush_close_unref(busses[w]);
+ buses[w] = sd_bus_flush_close_unref(buses[w]);
}
static void ask_password_agent_open_if_enabled(void) {
*_machines = NULL;
*_unit_infos = TAKE_PTR(unit_infos);
-
*_replies = TAKE_PTR(replies);
return c;
statelen = STRLEN("STATE"),
failedlen = STRLEN("FAILED"),
jobslen = STRLEN("JOBS");
+ bool state_missing = false;
assert(machine_infos || n == 0);
failedlen = MAX(failedlen, DECIMAL_STR_WIDTH(m->n_failed_units));
jobslen = MAX(jobslen, DECIMAL_STR_WIDTH(m->n_jobs));
- if (!arg_plain && !streq_ptr(m->state, "running"))
+ if (!arg_plain && m->state && !streq(m->state, "running"))
circle_len = 2;
}
if (circle_len > 0)
printf("%s%s%s ", on_state, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ", off_state);
+ if (!m->state)
+ state_missing = true;
+
if (m->is_host)
printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
- (int) (namelen - (STRLEN(" (host)"))),
+ (int) (namelen - strlen(" (host)")),
strna(m->name),
on_state, statelen, strna(m->state), off_state,
on_failed, failedlen, m->n_failed_units, off_failed,
jobslen, m->n_jobs);
}
- if (!arg_no_legend)
- printf("\n%u machines listed.\n", n);
+ if (!arg_no_legend) {
+ printf("\n");
+ if (state_missing && geteuid() != 0)
+ printf("Notice: some information only available to privileged users was not shown.\n");
+ printf("%u machines listed.\n", n);
+ }
}
static int list_machines(int argc, char *argv[], void *userdata) {
}
static const struct {
- const char *verb;
- const char *method;
+ const char *verb; /* systemctl verb */
+ const char *method; /* Name of the specific D-Bus method */
+ const char *job_type; /* Job type when passing to the generic EnqueueUnitJob() method */
} unit_actions[] = {
- { "start", "StartUnit" },
- { "stop", "StopUnit" },
- { "condstop", "StopUnit" },
- { "reload", "ReloadUnit" },
- { "restart", "RestartUnit" },
- { "try-restart", "TryRestartUnit" },
- { "condrestart", "TryRestartUnit" },
- { "reload-or-restart", "ReloadOrRestartUnit" },
- { "try-reload-or-restart", "ReloadOrTryRestartUnit" },
- { "reload-or-try-restart", "ReloadOrTryRestartUnit" },
- { "condreload", "ReloadOrTryRestartUnit" },
- { "force-reload", "ReloadOrTryRestartUnit" }
+ { "start", "StartUnit", "start" },
+ { "stop", "StopUnit", "stop" },
+ { "condstop", "StopUnit", "stop" }, /* legacy alias */
+ { "reload", "ReloadUnit", "reload" },
+ { "restart", "RestartUnit", "restart" },
+ { "try-restart", "TryRestartUnit", "try-restart" },
+ { "condrestart", "TryRestartUnit", "try-restart" }, /* legacy alias */
+ { "reload-or-restart", "ReloadOrRestartUnit", "reload-or-restart" },
+ { "try-reload-or-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" },
+ { "reload-or-try-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
+ { "condreload", "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
+ { "force-reload", "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
};
static const char *verb_to_method(const char *verb) {
- uint i;
+ size_t i;
for (i = 0; i < ELEMENTSOF(unit_actions); i++)
if (streq_ptr(unit_actions[i].verb, verb))
return "StartUnit";
}
-static const char *method_to_verb(const char *method) {
- uint i;
+static const char *verb_to_job_type(const char *verb) {
+ size_t i;
for (i = 0; i < ELEMENTSOF(unit_actions); i++)
- if (streq_ptr(unit_actions[i].method, method))
- return unit_actions[i].verb;
+ if (streq_ptr(unit_actions[i].verb, verb))
+ return unit_actions[i].job_type;
- return "n/a";
+ return "start";
}
typedef struct {
static int start_unit_one(
sd_bus *bus,
- const char *method,
+ const char *method, /* When using classic per-job bus methods */
+ const char *job_type, /* When using new-style EnqueueUnitJob() */
const char *name,
const char *mode,
sd_bus_error *error,
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
const char *path;
+ bool done = false;
int r;
assert(method);
log_debug("%s dbus call org.freedesktop.systemd1.Manager %s(%s, %s)",
arg_dry_run ? "Would execute" : "Executing",
method, name, mode);
+
if (arg_dry_run)
return 0;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method,
- error,
- &reply,
- "ss", name, mode);
- if (r < 0) {
- const char *verb;
+ if (arg_show_transaction) {
+ _cleanup_(sd_bus_error_free) sd_bus_error enqueue_error = SD_BUS_ERROR_NULL;
- /* There's always a fallback possible for legacy actions. */
- if (arg_action != ACTION_SYSTEMCTL)
- return r;
+ /* Use the new, fancy EnqueueUnitJob() API if the user wants us to print the transaction */
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "EnqueueUnitJob",
+ &enqueue_error,
+ &reply,
+ "sss",
+ name, job_type, mode);
+ if (r < 0) {
+ if (!sd_bus_error_has_name(&enqueue_error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+ (void) sd_bus_error_move(error, &enqueue_error);
+ goto fail;
+ }
- verb = method_to_verb(method);
+ /* Hmm, the API is not yet available. Let's use the classic API instead (see below). */
+ log_notice("--show-transaction not supported by this service manager, proceeding without.");
+ } else {
+ const char *u, *jt;
+ uint32_t id;
- log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
+ r = sd_bus_message_read(reply, "uosos", &id, &path, &u, NULL, &jt);
+ if (r < 0)
+ return bus_log_parse_error(r);
- if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
- !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) &&
- !sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
- log_error("See %s logs and 'systemctl%s status%s %s' for details.",
- arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
- arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
- name[0] == '-' ? " --" : "",
- name);
+ log_info("Enqueued anchor job %" PRIu32 " %s/%s.", id, u, jt);
- return r;
+ r = sd_bus_message_enter_container(reply, 'a', "(uosos)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+ for (;;) {
+ r = sd_bus_message_read(reply, "(uosos)", &id, NULL, &u, NULL, &jt);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ if (r == 0)
+ break;
+
+ log_info("Enqueued auxiliary job %" PRIu32 " %s/%s.", id, u, jt);
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ done = true;
+ }
}
- r = sd_bus_message_read(reply, "o", &path);
- if (r < 0)
- return bus_log_parse_error(r);
+ if (!done) {
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ method,
+ error,
+ &reply,
+ "ss", name, mode);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_message_read(reply, "o", &path);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ }
if (need_daemon_reload(bus, name) > 0)
warn_unit_file_changed(name);
log_debug("Adding %s to the set", path);
r = bus_wait_for_jobs_add(w, path);
if (r < 0)
- return log_oom();
+ return log_error_errno(r, "Failed to watch job for %s: %m", name);
}
return 0;
+
+fail:
+ /* There's always a fallback possible for legacy actions. */
+ if (arg_action != ACTION_SYSTEMCTL)
+ return r;
+
+ log_error_errno(r, "Failed to %s %s: %s", job_type, name, bus_error_message(error, r));
+
+ if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
+ !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) &&
+ !sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
+ log_error("See %s logs and 'systemctl%s status%s %s' for details.",
+ arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
+ arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
+ name[0] == '-' ? " --" : "",
+ name);
+
+ return r;
}
static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
}
*ret = TAKE_PTR(mangled);
-
return 0;
}
const char *verb;
const char *mode;
} action_table[_ACTION_MAX] = {
- [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
- [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
- [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
- [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
- [ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
- [ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
- [ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
- [ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
- [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
- [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
- [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
- [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
- [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
- [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
- [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
+ [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
+ [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
+ [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
+ [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
+ [ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
+ [ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
+ [ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
+ [ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
+ [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
+ [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
+ [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
+ [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
+ [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
+ [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
+ [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
[ACTION_SUSPEND_THEN_HIBERNATE] = { SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, "suspend-then-hibernate", "replace-irreversibly" },
};
return _ACTION_INVALID;
}
+static const char** make_extra_args(const char *extra_args[static 4]) {
+ size_t n = 0;
+
+ if (arg_scope != UNIT_FILE_SYSTEM)
+ extra_args[n++] = "--user";
+
+ if (arg_transport == BUS_TRANSPORT_REMOTE) {
+ extra_args[n++] = "-H";
+ extra_args[n++] = arg_host;
+ } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
+ extra_args[n++] = "-M";
+ extra_args[n++] = arg_host;
+ } else
+ assert(arg_transport == BUS_TRANSPORT_LOCAL);
+
+ extra_args[n] = NULL;
+ return extra_args;
+}
+
static int start_unit(int argc, char *argv[], void *userdata) {
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
_cleanup_(wait_context_free) WaitContext wait_context = {};
- const char *method, *mode, *one_name, *suffix = NULL;
+ const char *method, *job_type, *mode, *one_name, *suffix = NULL;
_cleanup_free_ char **stopped_units = NULL; /* Do not use _cleanup_strv_free_ */
_cleanup_strv_free_ char **names = NULL;
int r, ret = EXIT_SUCCESS;
action = verb_to_action(argv[0]);
if (action != _ACTION_INVALID) {
+ /* A command in style "systemctl reboot", "systemctl poweroff", … */
method = "StartUnit";
+ job_type = "start";
mode = action_table[action].mode;
one_name = action_table[action].target;
} else {
if (streq(argv[0], "isolate")) {
+ /* A "systemctl isolate <unit1> <unit2> …" command */
method = "StartUnit";
+ job_type = "start";
mode = "isolate";
-
suffix = ".target";
} else {
+ /* A command in style of "systemctl start <unit1> <unit2> …", "sysemctl stop <unit1> <unit2> …" and so on */
method = verb_to_method(argv[0]);
+ job_type = verb_to_job_type(argv[0]);
mode = arg_job_mode;
}
one_name = NULL;
}
} else {
+ /* A SysV legacy command such as "halt", "reboot", "poweroff", … */
assert(arg_action >= 0 && arg_action < _ACTION_MAX);
assert(action_table[arg_action].target);
assert(action_table[arg_action].mode);
method = "StartUnit";
+ job_type = "start";
mode = action_table[arg_action].mode;
one_name = action_table[arg_action].target;
}
NULL);
if (r < 0)
return log_error_errno(r, "Failed to enable subscription: %m");
+
r = sd_event_default(&wait_context.event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
+
r = sd_bus_attach_event(bus, wait_context.event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
STRV_FOREACH(name, names) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- r = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
+ r = start_unit_one(bus, method, job_type, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
if (ret == EXIT_SUCCESS && r < 0)
ret = translate_bus_error_to_exit_status(r, &error);
}
if (!arg_no_block) {
- const char* extra_args[4] = {};
- int arg_count = 0;
-
- if (arg_scope != UNIT_FILE_SYSTEM)
- extra_args[arg_count++] = "--user";
-
- assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE));
- if (arg_transport == BUS_TRANSPORT_REMOTE) {
- extra_args[arg_count++] = "-H";
- extra_args[arg_count++] = arg_host;
- } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
- extra_args[arg_count++] = "-M";
- extra_args[arg_count++] = arg_host;
- }
+ const char* extra_args[4];
- r = bus_wait_for_jobs(w, arg_quiet, extra_args);
+ r = bus_wait_for_jobs(w, arg_quiet, make_extra_args(extra_args));
if (r < 0)
return r;
}
#endif
-/* Ask systemd-logind, which might grant access to unprivileged users
- * through polkit */
+/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
static int logind_reboot(enum action a) {
#if ENABLE_LOGIND
+ static const struct {
+ const char *method;
+ const char *description;
+ } actions[_ACTION_MAX] = {
+ [ACTION_POWEROFF] = { "PowerOff", "power off system" },
+ [ACTION_REBOOT] = { "Reboot", "reboot system" },
+ [ACTION_HALT] = { "Halt", "halt system" },
+ [ACTION_SUSPEND] = { "Suspend", "suspend system" },
+ [ACTION_HIBERNATE] = { "Hibernate", "hibernate system" },
+ [ACTION_HYBRID_SLEEP] = { "HybridSleep", "put system into hybrid sleep" },
+ [ACTION_SUSPEND_THEN_HIBERNATE] = { "SuspendThenHibernate", "suspend system, hibernate later" },
+ };
+
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *method, *description;
sd_bus *bus;
int r;
+ if (a < 0 || a >= _ACTION_MAX || !actions[a].method)
+ return -EINVAL;
+
r = acquire_bus(BUS_FULL, &bus);
if (r < 0)
return r;
- switch (a) {
-
- case ACTION_POWEROFF:
- method = "PowerOff";
- description = "power off system";
- break;
-
- case ACTION_REBOOT:
- method = "Reboot";
- description = "reboot system";
- break;
-
- case ACTION_HALT:
- method = "Halt";
- description = "halt system";
- break;
-
- case ACTION_SUSPEND:
- method = "Suspend";
- description = "suspend system";
- break;
-
- case ACTION_HIBERNATE:
- method = "Hibernate";
- description = "hibernate system";
- break;
-
- case ACTION_HYBRID_SLEEP:
- method = "HybridSleep";
- description = "put system into hybrid sleep";
- break;
-
- case ACTION_SUSPEND_THEN_HIBERNATE:
- method = "SuspendThenHibernate";
- description = "put system into suspend followed by hibernate";
- break;
-
- default:
- return -EINVAL;
- }
-
polkit_agent_open_maybe();
(void) logind_set_wall_message();
- log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", method);
+ log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", actions[a].method);
+
if (arg_dry_run)
return 0;
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
- method,
+ actions[a].method,
&error,
NULL,
"b", arg_ask_password);
if (r < 0)
- return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
return 0;
#else
return 0;
#else
- log_error("Booting into boot loader entry not supported.");
- return -ENOSYS;
+ return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+ "Booting into boot loader entry not supported.");
#endif
}
int code;
int status;
+ ExecCommandFlags flags;
+
LIST_FIELDS(struct ExecStatusInfo, exec);
} ExecStatusInfo;
free(i);
}
-static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) {
+static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i, bool is_ex_prop) {
+ _cleanup_strv_free_ char **ex_opts = NULL;
uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
const char *path;
uint32_t pid;
assert(m);
assert(i);
- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, "sasbttttuii");
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, is_ex_prop ? "sasasttttuii" : "sasbttttuii");
if (r < 0)
return bus_log_parse_error(r);
else if (r == 0)
if (r < 0)
return bus_log_parse_error(r);
+ r = is_ex_prop ? sd_bus_message_read_strv(m, &ex_opts) : sd_bus_message_read(m, "b", &ignore);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
r = sd_bus_message_read(m,
- "bttttuii",
- &ignore,
+ "ttttuii",
&start_timestamp, &start_timestamp_monotonic,
&exit_timestamp, &exit_timestamp_monotonic,
&pid,
if (r < 0)
return bus_log_parse_error(r);
- i->ignore = ignore;
+ if (is_ex_prop) {
+ r = exec_command_flags_from_strv(ex_opts, &i->flags);
+ if (r < 0)
+ return log_error_errno(r, "Failed to convert strv to ExecCommandFlags: %m");
+
+ i->ignore = FLAGS_SET(i->flags, EXEC_COMMAND_IGNORE_FAILURE);
+ } else
+ i->ignore = ignore;
+
i->start_timestamp = (usec_t) start_timestamp;
i->exit_timestamp = (usec_t) exit_timestamp;
i->pid = (pid_t) pid;
uint64_t cpu_usage_nsec;
uint64_t tasks_current;
uint64_t tasks_max;
-
uint64_t ip_ingress_bytes;
uint64_t ip_egress_bytes;
+ uint64_t io_read_bytes;
+ uint64_t io_write_bytes;
+
+ uint64_t default_memory_min;
+ uint64_t default_memory_low;
LIST_HEAD(ExecStatusInfo, exec);
} UnitStatusInfo;
format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
}
+ if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX) {
+ char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
+
+ printf(" IO: %s read, %s written\n",
+ format_bytes(buf_in, sizeof(buf_in), i->io_read_bytes),
+ format_bytes(buf_out, sizeof(buf_out), i->io_write_bytes));
+ }
+
if (i->tasks_current != (uint64_t) -1) {
printf(" Tasks: %" PRIu64, i->tasks_current);
_cleanup_free_ ExecStatusInfo *info = NULL;
ExecStatusInfo *last;
UnitStatusInfo *i = userdata;
+ bool is_ex_prop = endswith(member, "Ex");
int r;
- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, is_ex_prop ? "(sasasttttuii)" : "(sasbttttuii)");
if (r < 0)
return r;
LIST_FIND_TAIL(exec, i->exec, last);
- while ((r = exec_status_info_deserialize(m, info)) > 0) {
+ while ((r = exec_status_info_deserialize(m, info, is_ex_prop)) > 0) {
info->name = strdup(member);
if (!info->name)
} else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
ExecStatusInfo info = {};
+ bool is_ex_prop = endswith(name, "Ex");
- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, is_ex_prop ? "(sasasttttuii)" : "(sasbttttuii)");
if (r < 0)
return bus_log_parse_error(r);
- while ((r = exec_status_info_deserialize(m, &info)) > 0) {
+ while ((r = exec_status_info_deserialize(m, &info, is_ex_prop)) > 0) {
char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
- _cleanup_free_ char *tt;
+ _cleanup_strv_free_ char **optv = NULL;
+ _cleanup_free_ char *tt, *o = NULL;
tt = strv_join(info.argv, " ");
- bus_print_property_valuef(name, expected_value, value,
- "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
- strna(info.path),
- strna(tt),
- yes_no(info.ignore),
- strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
- strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
- info.pid,
- sigchld_code_to_string(info.code),
- info.status,
- info.code == CLD_EXITED ? "" : "/",
- strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
+ if (is_ex_prop) {
+ r = exec_command_flags_to_strv(info.flags, &optv);
+ if (r < 0)
+ return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
+
+ o = strv_join(optv, " ");
+
+ bus_print_property_valuef(name, expected_value, value,
+ "{ path=%s ; argv[]=%s ; flags=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
+ strna(info.path),
+ strna(tt),
+ strna(o),
+ strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
+ strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
+ info.pid,
+ sigchld_code_to_string(info.code),
+ info.status,
+ info.code == CLD_EXITED ? "" : "/",
+ strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
+ } else
+ bus_print_property_valuef(name, expected_value, value,
+ "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
+ strna(info.path),
+ strna(tt),
+ yes_no(info.ignore),
+ strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
+ strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
+ info.pid,
+ sigchld_code_to_string(info.code),
+ info.status,
+ info.code == CLD_EXITED ? "" : "/",
+ strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
free(info.path);
strv_free(info.argv);
if (all || !isempty(fields))
bus_print_property_value(name, expected_value, value, strempty(fields));
+ return 1;
+ } else if (contents[0] == SD_BUS_TYPE_BYTE && streq(name, "CPUAffinity")) {
+ _cleanup_free_ char *affinity = NULL;
+ _cleanup_(cpu_set_reset) CPUSet set = {};
+ const void *a;
+ size_t n;
+
+ r = sd_bus_message_read_array(m, 'y', &a, &n);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = cpu_set_from_dbus(a, n, &set);
+ if (r < 0)
+ return log_error_errno(r, "Failed to deserialize CPUAffinity: %m");
+
+ affinity = cpu_set_to_range_string(&set);
+ if (!affinity)
+ return log_oom();
+
+ bus_print_property_value(name, expected_value, value, affinity);
+
return 1;
}
bool *ellipsized) {
static const struct bus_properties_map property_map[] = {
- { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
- { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
- { "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
+ { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
+ { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
+ { "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
{}
}, status_map[] = {
- { "Id", "s", NULL, offsetof(UnitStatusInfo, id) },
- { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
- { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
- { "SubState", "s", NULL, offsetof(UnitStatusInfo, sub_state) },
- { "UnitFileState", "s", NULL, offsetof(UnitStatusInfo, unit_file_state) },
- { "UnitFilePreset", "s", NULL, offsetof(UnitStatusInfo, unit_file_preset) },
- { "Description", "s", NULL, offsetof(UnitStatusInfo, description) },
- { "Following", "s", NULL, offsetof(UnitStatusInfo, following) },
- { "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
- { "FragmentPath", "s", NULL, offsetof(UnitStatusInfo, fragment_path) },
- { "SourcePath", "s", NULL, offsetof(UnitStatusInfo, source_path) },
- { "ControlGroup", "s", NULL, offsetof(UnitStatusInfo, control_group) },
- { "DropInPaths", "as", NULL, offsetof(UnitStatusInfo, dropin_paths) },
- { "LoadError", "(ss)", map_load_error, offsetof(UnitStatusInfo, load_error) },
- { "Result", "s", NULL, offsetof(UnitStatusInfo, result) },
- { "InactiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp) },
- { "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp_monotonic) },
- { "ActiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_enter_timestamp) },
- { "ActiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_exit_timestamp) },
- { "InactiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_enter_timestamp) },
- { "NeedDaemonReload", "b", NULL, offsetof(UnitStatusInfo, need_daemon_reload) },
- { "Transient", "b", NULL, offsetof(UnitStatusInfo, transient) },
- { "ExecMainPID", "u", NULL, offsetof(UnitStatusInfo, main_pid) },
- { "MainPID", "u", map_main_pid, 0 },
- { "ControlPID", "u", NULL, offsetof(UnitStatusInfo, control_pid) },
- { "StatusText", "s", NULL, offsetof(UnitStatusInfo, status_text) },
- { "PIDFile", "s", NULL, offsetof(UnitStatusInfo, pid_file) },
- { "StatusErrno", "i", NULL, offsetof(UnitStatusInfo, status_errno) },
- { "ExecMainStartTimestamp", "t", NULL, offsetof(UnitStatusInfo, start_timestamp) },
- { "ExecMainExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, exit_timestamp) },
- { "ExecMainCode", "i", NULL, offsetof(UnitStatusInfo, exit_code) },
- { "ExecMainStatus", "i", NULL, offsetof(UnitStatusInfo, exit_status) },
- { "ConditionTimestamp", "t", NULL, offsetof(UnitStatusInfo, condition_timestamp) },
- { "ConditionResult", "b", NULL, offsetof(UnitStatusInfo, condition_result) },
- { "Conditions", "a(sbbsi)", map_conditions, 0 },
- { "AssertTimestamp", "t", NULL, offsetof(UnitStatusInfo, assert_timestamp) },
- { "AssertResult", "b", NULL, offsetof(UnitStatusInfo, assert_result) },
- { "Asserts", "a(sbbsi)", map_asserts, 0 },
- { "NextElapseUSecRealtime", "t", NULL, offsetof(UnitStatusInfo, next_elapse_real) },
- { "NextElapseUSecMonotonic", "t", NULL, offsetof(UnitStatusInfo, next_elapse_monotonic) },
- { "NAccepted", "u", NULL, offsetof(UnitStatusInfo, n_accepted) },
- { "NConnections", "u", NULL, offsetof(UnitStatusInfo, n_connections) },
- { "NRefused", "u", NULL, offsetof(UnitStatusInfo, n_refused) },
- { "Accept", "b", NULL, offsetof(UnitStatusInfo, accept) },
- { "Listen", "a(ss)", map_listen, offsetof(UnitStatusInfo, listen) },
- { "SysFSPath", "s", NULL, offsetof(UnitStatusInfo, sysfs_path) },
- { "Where", "s", NULL, offsetof(UnitStatusInfo, where) },
- { "What", "s", NULL, offsetof(UnitStatusInfo, what) },
- { "MemoryCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_current) },
- { "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) },
- { "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) },
- { "MemoryHigh", "t", NULL, offsetof(UnitStatusInfo, memory_high) },
- { "MemoryMax", "t", NULL, offsetof(UnitStatusInfo, memory_max) },
- { "MemorySwapMax", "t", NULL, offsetof(UnitStatusInfo, memory_swap_max) },
- { "MemoryLimit", "t", NULL, offsetof(UnitStatusInfo, memory_limit) },
- { "CPUUsageNSec", "t", NULL, offsetof(UnitStatusInfo, cpu_usage_nsec) },
- { "TasksCurrent", "t", NULL, offsetof(UnitStatusInfo, tasks_current) },
- { "TasksMax", "t", NULL, offsetof(UnitStatusInfo, tasks_max) },
- { "IPIngressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_ingress_bytes) },
- { "IPEgressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_egress_bytes) },
- { "ExecStartPre", "a(sasbttttuii)", map_exec, 0 },
- { "ExecStart", "a(sasbttttuii)", map_exec, 0 },
- { "ExecStartPost", "a(sasbttttuii)", map_exec, 0 },
- { "ExecReload", "a(sasbttttuii)", map_exec, 0 },
- { "ExecStopPre", "a(sasbttttuii)", map_exec, 0 },
- { "ExecStop", "a(sasbttttuii)", map_exec, 0 },
- { "ExecStopPost", "a(sasbttttuii)", map_exec, 0 },
+ { "Id", "s", NULL, offsetof(UnitStatusInfo, id) },
+ { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
+ { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
+ { "SubState", "s", NULL, offsetof(UnitStatusInfo, sub_state) },
+ { "UnitFileState", "s", NULL, offsetof(UnitStatusInfo, unit_file_state) },
+ { "UnitFilePreset", "s", NULL, offsetof(UnitStatusInfo, unit_file_preset) },
+ { "Description", "s", NULL, offsetof(UnitStatusInfo, description) },
+ { "Following", "s", NULL, offsetof(UnitStatusInfo, following) },
+ { "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
+ { "FragmentPath", "s", NULL, offsetof(UnitStatusInfo, fragment_path) },
+ { "SourcePath", "s", NULL, offsetof(UnitStatusInfo, source_path) },
+ { "ControlGroup", "s", NULL, offsetof(UnitStatusInfo, control_group) },
+ { "DropInPaths", "as", NULL, offsetof(UnitStatusInfo, dropin_paths) },
+ { "LoadError", "(ss)", map_load_error, offsetof(UnitStatusInfo, load_error) },
+ { "Result", "s", NULL, offsetof(UnitStatusInfo, result) },
+ { "InactiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp) },
+ { "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp_monotonic) },
+ { "ActiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_enter_timestamp) },
+ { "ActiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_exit_timestamp) },
+ { "InactiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_enter_timestamp) },
+ { "NeedDaemonReload", "b", NULL, offsetof(UnitStatusInfo, need_daemon_reload) },
+ { "Transient", "b", NULL, offsetof(UnitStatusInfo, transient) },
+ { "ExecMainPID", "u", NULL, offsetof(UnitStatusInfo, main_pid) },
+ { "MainPID", "u", map_main_pid, 0 },
+ { "ControlPID", "u", NULL, offsetof(UnitStatusInfo, control_pid) },
+ { "StatusText", "s", NULL, offsetof(UnitStatusInfo, status_text) },
+ { "PIDFile", "s", NULL, offsetof(UnitStatusInfo, pid_file) },
+ { "StatusErrno", "i", NULL, offsetof(UnitStatusInfo, status_errno) },
+ { "ExecMainStartTimestamp", "t", NULL, offsetof(UnitStatusInfo, start_timestamp) },
+ { "ExecMainExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, exit_timestamp) },
+ { "ExecMainCode", "i", NULL, offsetof(UnitStatusInfo, exit_code) },
+ { "ExecMainStatus", "i", NULL, offsetof(UnitStatusInfo, exit_status) },
+ { "ConditionTimestamp", "t", NULL, offsetof(UnitStatusInfo, condition_timestamp) },
+ { "ConditionResult", "b", NULL, offsetof(UnitStatusInfo, condition_result) },
+ { "Conditions", "a(sbbsi)", map_conditions, 0 },
+ { "AssertTimestamp", "t", NULL, offsetof(UnitStatusInfo, assert_timestamp) },
+ { "AssertResult", "b", NULL, offsetof(UnitStatusInfo, assert_result) },
+ { "Asserts", "a(sbbsi)", map_asserts, 0 },
+ { "NextElapseUSecRealtime", "t", NULL, offsetof(UnitStatusInfo, next_elapse_real) },
+ { "NextElapseUSecMonotonic", "t", NULL, offsetof(UnitStatusInfo, next_elapse_monotonic) },
+ { "NAccepted", "u", NULL, offsetof(UnitStatusInfo, n_accepted) },
+ { "NConnections", "u", NULL, offsetof(UnitStatusInfo, n_connections) },
+ { "NRefused", "u", NULL, offsetof(UnitStatusInfo, n_refused) },
+ { "Accept", "b", NULL, offsetof(UnitStatusInfo, accept) },
+ { "Listen", "a(ss)", map_listen, offsetof(UnitStatusInfo, listen) },
+ { "SysFSPath", "s", NULL, offsetof(UnitStatusInfo, sysfs_path) },
+ { "Where", "s", NULL, offsetof(UnitStatusInfo, where) },
+ { "What", "s", NULL, offsetof(UnitStatusInfo, what) },
+ { "MemoryCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_current) },
+ { "DefaultMemoryMin", "t", NULL, offsetof(UnitStatusInfo, default_memory_min) },
+ { "DefaultMemoryLow", "t", NULL, offsetof(UnitStatusInfo, default_memory_low) },
+ { "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) },
+ { "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) },
+ { "MemoryHigh", "t", NULL, offsetof(UnitStatusInfo, memory_high) },
+ { "MemoryMax", "t", NULL, offsetof(UnitStatusInfo, memory_max) },
+ { "MemorySwapMax", "t", NULL, offsetof(UnitStatusInfo, memory_swap_max) },
+ { "MemoryLimit", "t", NULL, offsetof(UnitStatusInfo, memory_limit) },
+ { "CPUUsageNSec", "t", NULL, offsetof(UnitStatusInfo, cpu_usage_nsec) },
+ { "TasksCurrent", "t", NULL, offsetof(UnitStatusInfo, tasks_current) },
+ { "TasksMax", "t", NULL, offsetof(UnitStatusInfo, tasks_max) },
+ { "IPIngressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_ingress_bytes) },
+ { "IPEgressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_egress_bytes) },
+ { "IOReadBytes", "t", NULL, offsetof(UnitStatusInfo, io_read_bytes) },
+ { "IOWriteBytes", "t", NULL, offsetof(UnitStatusInfo, io_write_bytes) },
+ { "ExecStartPre", "a(sasbttttuii)", map_exec, 0 },
+ { "ExecStartPreEx", "a(sasasttttuii)", map_exec, 0 },
+ { "ExecStart", "a(sasbttttuii)", map_exec, 0 },
+ { "ExecStartEx", "a(sasasttttuii)", map_exec, 0 },
+ { "ExecStartPost", "a(sasbttttuii)", map_exec, 0 },
+ { "ExecStartPostEx", "a(sasasttttuii)", map_exec, 0 },
+ { "ExecReload", "a(sasbttttuii)", map_exec, 0 },
+ { "ExecStopPre", "a(sasbttttuii)", map_exec, 0 },
+ { "ExecStop", "a(sasbttttuii)", map_exec, 0 },
+ { "ExecStopPost", "a(sasbttttuii)", map_exec, 0 },
{}
};
.tasks_max = (uint64_t) -1,
.ip_ingress_bytes = (uint64_t) -1,
.ip_egress_bytes = (uint64_t) -1,
+ .io_read_bytes = UINT64_MAX,
+ .io_write_bytes = UINT64_MAX,
};
char **pp;
int r;
bool first = true;
int r;
+ /* Include all units by default - i.e. continue as if the --all
+ * option was used */
+ if (strv_isempty(arg_states))
+ arg_all = true;
+
if (arg_transport != BUS_TRANSPORT_LOCAL)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot remotely cat units.");
if (r < 0)
return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
- r = copy_file(original_path, t, 0, 0644, 0, COPY_REFLINK);
+ r = copy_file(original_path, t, 0, 0644, 0, 0, COPY_REFLINK);
if (r == -ENOENT) {
r = touch(t);
assert(name);
assert(ret_path);
- path = strjoin(paths->persistent_config, "/", name);
+ path = path_join(paths->persistent_config, name);
if (!path)
return log_oom();
if (arg_runtime) {
- run = strjoin(paths->runtime_config, "/", name);
+ run = path_join(paths->runtime_config, name);
if (!run)
return log_oom();
}
" --reverse Show reverse dependencies with 'list-dependencies'\n"
" --job-mode=MODE Specify how to deal with already queued jobs, when\n"
" queueing a new job\n"
+ " -T --show-transaction\n"
+ " When enqueuing a unit job, show full transaction\n"
" --show-types When showing sockets, explicitly show their type\n"
" --value When showing properties, only print the value\n"
" -i --ignore-inhibitors\n"
{ "boot-loader-entry", required_argument, NULL, ARG_BOOT_LOADER_ENTRY },
{ "now", no_argument, NULL, ARG_NOW },
{ "message", required_argument, NULL, ARG_MESSAGE },
+ { "show-transaction", no_argument, NULL, 'T' },
{}
};
/* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
arg_ask_password = true;
- while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir.::", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:iTr.::", options, NULL)) >= 0)
switch (c) {
return log_oom();
break;
+ case 'T':
+ arg_show_transaction = true;
+ break;
+
case '.':
/* Output an error mimicking getopt, and print a hint afterwards */
log_error("%s: invalid option -- '.'", program_invocation_name);
{ "list-sockets", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, list_sockets },
{ "list-timers", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, list_timers },
{ "list-jobs", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, list_jobs },
- { "list-machines", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY|VERB_MUST_BE_ROOT, list_machines },
+ { "list-machines", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, list_machines },
{ "clear-jobs", VERB_ANY, 1, VERB_ONLINE_ONLY, trivial_method },
{ "cancel", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, cancel_job },
{ "start", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
{ "restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
{ "try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
{ "reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
- { "reload-or-try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatbility with old systemctl <= 228 */
+ { "reload-or-try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with old systemctl <= 228 */
{ "try-reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
{ "force-reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with SysV */
{ "condreload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with ALTLinux */