/* SPDX-License-Identifier: LGPL-2.1+ */
/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2013 Marc-Antoine Perennou
+ Copyright © 2013 Marc-Antoine Perennou
***/
#include <errno.h>
#include "sd-bus.h"
#include "sd-daemon.h"
+#include "sd-event.h"
#include "sd-login.h"
#include "alloc-util.h"
if (!arg_no_legend &&
(streq(u->active_state, "failed") ||
- STR_IN_SET(u->load_state, "error", "not-found", "masked")))
+ STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked")))
circle_len = 2;
}
underline = true;
}
- if (STR_IN_SET(u->load_state, "error", "not-found", "masked") && !arg_plain) {
+ if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) {
on_circle = ansi_highlight_yellow();
off_circle = ansi_normal();
circle = true;
static int output_waiting_jobs(sd_bus *bus, uint32_t id, const char *method, const char *prefix) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- const char *name, *type, *state, *job_path, *unit_path;
+ const char *name, *type;
uint32_t other_id;
int r;
if (r < 0)
return bus_log_parse_error(r);
- while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, &state, &job_path, &unit_path)) > 0)
+ while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, NULL, NULL, NULL)) > 0)
printf("%s %u (%s/%s)\n", prefix, other_id, name, type);
if (r < 0)
return bus_log_parse_error(r);
static int list_jobs(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- const char *name, *type, *state, *job_path, *unit_path;
_cleanup_free_ struct job_info *jobs = NULL;
+ const char *name, *type, *state;
+ bool skipped = false;
size_t size = 0;
unsigned c = 0;
sd_bus *bus;
uint32_t id;
int r;
- bool skipped = false;
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
if (r < 0)
return bus_log_parse_error(r);
- while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) {
+ while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, NULL, NULL)) > 0) {
struct job_info job = { id, name, type, state };
if (!output_show_job(&job, strv_skip(argv, 1))) {
if (r == -ENOMEM)
return log_oom();
if (r < 0)
- return log_error_errno(r, "Failed to access path '%s': %m", path);
+ return log_error_errno(r, "Failed to access path \"%s\": %m", path);
if (unit_path)
*unit_path = TAKE_PTR(lpath);
if (r < 0)
return r;
- if (r > 0)
+ if (r > 0) {
+ if (null_or_empty_path(path))
+ /* The template is masked. Let's cut the process short. */
+ return -ERFKILL;
+
/* We found the unit file. If we followed symlinks, this name might be
* different then the unit_name with started with. Look for dropins matching
* that "final" name. */
r = set_put(names, basename(path));
- else if (!template)
+ } else if (!template)
/* No unit file, let's look for dropins matching the original name.
* systemd has fairly complicated rules (based on unit type and provenience),
* which units are allowed not to have the main unit file. We err on the
return 0;
}
-static int unit_is_masked(sd_bus *bus, const char *name) {
+static int unit_is_masked(sd_bus *bus, LookupPaths *lp, const char *name) {
_cleanup_free_ char *load_state = NULL;
int r;
+ if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
+ _cleanup_free_ char *path = NULL;
+
+ /* A template cannot be loaded, but it can be still masked, so
+ * we need to use a different method. */
+
+ r = unit_file_find_path(lp, name, &path);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return false;
+ return null_or_empty_path(path);
+ }
+
r = unit_load_state(bus, name, &load_state);
if (r < 0)
return r;
static int check_triggering_units(sd_bus *bus, const char *name) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char *n = NULL, *path = NULL;
+ _cleanup_free_ char *n = NULL, *path = NULL, *load_state = NULL;
_cleanup_strv_free_ char **triggered_by = NULL;
bool print_warning_label = true;
UnitActiveState active_state;
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
- r = unit_is_masked(bus, n);
- if (r != 0)
- return r < 0 ? r : 0;
+ r = unit_load_state(bus, name, &load_state);
+ if (r < 0)
+ return r;
+
+ if (streq(load_state, "masked"))
+ return 0;
path = unit_dbus_path_from_name(n);
if (!path)
* another active unit (socket, path, timer) */
if (!arg_quiet && streq(method, "StopUnit"))
STRV_FOREACH(name, names)
- check_triggering_units(bus, *name);
+ (void) check_triggering_units(bus, *name);
}
- if (r >= 0 && arg_wait) {
+ if (r >= 0 && arg_wait && !set_isempty(wait_context.unit_paths)) {
int q;
q = sd_event_loop(wait_context.event);
if (q < 0)
#endif
/* Ask systemd-logind, which might grant access to unprivileged users
- * through PolicyKit */
+ * through polkit */
static int logind_reboot(enum action a) {
#if ENABLE_LOGIND
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
}
static int check_unit_active(int argc, char *argv[], void *userdata) {
- const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING };
+ static const UnitActiveState states[] = {
+ UNIT_ACTIVE,
+ UNIT_RELOADING,
+ };
+
/* According to LSB: 3, "program is not running" */
return check_unit_generic(EXIT_PROGRAM_NOT_RUNNING, states, ELEMENTSOF(states), strv_skip(argv, 1));
}
static int check_unit_failed(int argc, char *argv[], void *userdata) {
- const UnitActiveState states[] = { UNIT_FAILED };
+ static const UnitActiveState states[] = {
+ UNIT_FAILED,
+ };
+
return check_unit_generic(EXIT_PROGRAM_DEAD_AND_PID_EXISTS, states, ELEMENTSOF(states), strv_skip(argv, 1));
}
/* CGroup */
uint64_t memory_current;
+ uint64_t memory_min;
uint64_t memory_low;
uint64_t memory_high;
uint64_t memory_max;
if (i->following)
printf(" Follow: unit currently follows state of %s\n", i->following);
- if (streq_ptr(i->load_state, "error")) {
+ if (STRPTR_IN_SET(i->load_state, "error", "not-found", "bad-setting")) {
on = ansi_highlight_red();
off = ansi_normal();
} else
if (path && terminal_urlify_path(path, NULL, &formatted_path) >= 0)
path = formatted_path;
- if (i->load_error != 0)
+ if (!isempty(i->load_error))
printf(" Loaded: %s%s%s (Reason: %s)\n",
on, strna(i->load_state), off, i->load_error);
else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset) &&
printf("\n");
}
-
LIST_FOREACH(exec, p, i->exec) {
_cleanup_free_ char *argv = NULL;
bool good;
printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
- if (i->memory_low > 0 || i->memory_high != CGROUP_LIMIT_MAX ||
- i->memory_max != CGROUP_LIMIT_MAX || i->memory_swap_max != CGROUP_LIMIT_MAX ||
+ if (i->memory_min > 0 || i->memory_low > 0 ||
+ i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX ||
+ i->memory_swap_max != CGROUP_LIMIT_MAX ||
i->memory_limit != CGROUP_LIMIT_MAX) {
const char *prefix = "";
printf(" (");
+ if (i->memory_min > 0) {
+ printf("%smin: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_min));
+ prefix = " ";
+ }
if (i->memory_low > 0) {
printf("%slow: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_low));
prefix = " ";
}
static int map_load_error(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
- const char *n, *message;
- const char **p = userdata;
+ const char *message, **p = userdata;
int r;
- r = sd_bus_message_read(m, "(ss)", &n, &message);
+ r = sd_bus_message_read(m, "(ss)", NULL, &message);
if (r < 0)
return r;
static int map_exec(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
_cleanup_free_ ExecStatusInfo *info = NULL;
+ ExecStatusInfo *last;
UnitStatusInfo *i = userdata;
int r;
if (!info)
return -ENOMEM;
+ LIST_FIND_TAIL(exec, i->exec, last);
+
while ((r = exec_status_info_deserialize(m, info)) > 0) {
info->name = strdup(member);
if (!info->name)
return -ENOMEM;
- LIST_PREPEND(exec, i->exec, info);
+ LIST_INSERT_AFTER(exec, i->exec, last, info);
+ last = info;
info = new0(ExecStatusInfo, 1);
if (!info)
return 0;
}
-#define print_prop(name, fmt, ...) \
- do { \
- if (arg_value) \
- printf(fmt "\n", __VA_ARGS__); \
- else \
- printf("%s=" fmt "\n", name, __VA_ARGS__); \
- } while (0)
-
-static int print_property(const char *name, sd_bus_message *m, bool value, bool all) {
+static int print_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
char bus_type;
const char *contents;
int r;
return bus_log_parse_error(r);
if (u > 0)
- print_prop(name, "%"PRIu32, u);
+ bus_print_property_value(name, expected_value, value, "%"PRIu32, u);
else if (all)
- print_prop(name, "%s", "");
+ bus_print_property_value(name, expected_value, value, "%s", "");
return 1;
return bus_log_parse_error(r);
if (all || !isempty(s))
- print_prop(name, "%s", s);
+ bus_print_property_value(name, expected_value, value, "%s", s);
return 1;
return bus_log_parse_error(r);
if (all || !isempty(a) || !isempty(b))
- print_prop(name, "%s \"%s\"", strempty(a), strempty(b));
+ bus_print_property_value(name, expected_value, value, "%s \"%s\"", strempty(a), strempty(b));
return 1;
} else if (streq_ptr(name, "SystemCallFilter")) {
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
- print_prop(name, "%s (ignore_errors=%s)", path, yes_no(ignore));
+ bus_print_property_value(name, expected_value, value, "%s (ignore_errors=%s)", path, yes_no(ignore));
if (r < 0)
return bus_log_parse_error(r);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
- print_prop(name, "%s (%s)", path, type);
+ bus_print_property_value(name, expected_value, value, "%s (%s)", path, type);
if (r < 0)
return bus_log_parse_error(r);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
- print_prop(name, "%s (%s)", path, type);
+ bus_print_property_value(name, expected_value, value, "%s (%s)", path, type);
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0) {
char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
- print_prop(name, "{ %s=%s ; next_elapse=%s }", base,
- format_timespan(timespan1, sizeof(timespan1), v, 0),
- format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
+ bus_print_property_value(name, expected_value, value, "{ %s=%s ; next_elapse=%s }", base,
+ format_timespan(timespan1, sizeof(timespan1), v, 0),
+ format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
}
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
char timestamp[FORMAT_TIMESTAMP_MAX];
- print_prop(name, "{ %s=%s ; next_elapse=%s }", base, spec,
- format_timestamp(timestamp, sizeof(timestamp), next_elapse));
+ bus_print_property_value(name, expected_value, value, "{ %s=%s ; next_elapse=%s }", base, spec,
+ format_timestamp(timestamp, sizeof(timestamp), next_elapse));
}
if (r < 0)
return bus_log_parse_error(r);
tt = strv_join(info.argv, " ");
- print_prop(name,
- "{ 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)));
+ bus_print_property_value(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);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
- print_prop(name, "%s %s", strna(path), strna(rwm));
+ bus_print_property_value(name, expected_value, value, "%s %s", strna(path), strna(rwm));
if (r < 0)
return bus_log_parse_error(r);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
- print_prop(name, "%s %"PRIu64, strna(path), weight);
+ bus_print_property_value(name, expected_value, value, "%s %"PRIu64, strna(path), weight);
if (r < 0)
return bus_log_parse_error(r);
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
- print_prop(name, "%s %"PRIu64, strna(path), bandwidth);
+ bus_print_property_value(name, expected_value, value, "%s %"PRIu64, strna(path), bandwidth);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ return 1;
+
+ } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
+ streq(name, "IODeviceLatencyTargetUSec")) {
+ char ts[FORMAT_TIMESPAN_MAX];
+ const char *path;
+ uint64_t target;
+
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_read(m, "(st)", &path, &target)) > 0)
+ bus_print_property_value(name, expected_value, value, "%s %s", strna(path),
+ format_timespan(ts, sizeof(ts), target, 1));
if (r < 0)
return bus_log_parse_error(r);
if (n < 0)
return log_oom();
- print_prop(name, "%s", h);
+ bus_print_property_value(name, expected_value, value, "%s", h);
return 1;
}
_SYSTEMCTL_SHOW_MODE_INVALID = -1,
} SystemctlShowMode;
-static const char* const systemctl_show_mode_table[] = {
+static const char* const systemctl_show_mode_table[_SYSTEMCTL_SHOW_MODE_MAX] = {
[SYSTEMCTL_SHOW_PROPERTIES] = "show",
[SYSTEMCTL_SHOW_STATUS] = "status",
[SYSTEMCTL_SHOW_HELP] = "help",
{ "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) },
_cleanup_strv_free_ char **dropin_paths = NULL;
r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
+ if (r == -ERFKILL) {
+ printf("%s# unit %s is masked%s\n",
+ ansi_highlight_magenta(),
+ *name,
+ ansi_normal());
+ continue;
+ }
if (r < 0)
return r;
else if (r == 0)
if (r < 0)
return r;
if (r == 0)
- log_notice("Unit %s does not exist, proceeding anyway.", *names);
+ log_notice("Unit %s does not exist, proceeding anyway.", *name);
}
}
return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
}
+static int match_startup_finished(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ char **state = userdata;
+ int r;
+
+ assert(state);
+
+ r = sd_bus_get_property_string(
+ sd_bus_message_get_bus(m),
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SystemState",
+ NULL,
+ state);
+
+ sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), r);
+ return 0;
+}
+
static int is_system_running(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot_startup_finished = NULL;
+ _cleanup_(sd_event_unrefp) sd_event* event = NULL;
_cleanup_free_ char *state = NULL;
sd_bus *bus;
int r;
if (r < 0)
return r;
+ if (arg_wait) {
+ r = sd_event_default(&event);
+ if (r >= 0)
+ r = sd_bus_attach_event(bus, event, 0);
+ if (r >= 0)
+ r = sd_bus_match_signal_async(
+ bus,
+ &slot_startup_finished,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartupFinished",
+ match_startup_finished, NULL, &state);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to request match for StartupFinished: %m");
+ arg_wait = false;
+ }
+ }
+
r = sd_bus_get_property_string(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"SystemState",
- NULL,
+ &error,
&state);
if (r < 0) {
+ log_warning_errno(r, "Failed to query system state: %s", bus_error_message(&error, r));
+
if (!arg_quiet)
puts("unknown");
- return 0;
+ return EXIT_FAILURE;
+ }
+
+ if (arg_wait && STR_IN_SET(state, "initializing", "starting")) {
+ r = sd_event_loop(event);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to get property from event loop: %m");
+ if (!arg_quiet)
+ puts("unknown");
+ return EXIT_FAILURE;
+ }
}
if (!arg_quiet)
if (r < 0)
return r;
if (r == 0) {
- const char **args;
- char *editor, **editor_args = NULL;
- char **tmp_path, **original_path, *p;
- size_t n_editor_args = 0, i = 1;
- size_t argc;
+ char **editor_args = NULL, **tmp_path, **original_path, *p;
+ size_t n_editor_args = 0, i = 1, argc;
+ const char **args, *editor;
argc = strv_length(paths)/2 + 1;
}
static int edit(int argc, char *argv[], void *userdata) {
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
_cleanup_strv_free_ char **names = NULL;
_cleanup_strv_free_ char **paths = NULL;
char **original, **tmp;
return -EINVAL;
}
+ r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine unit paths: %m");
+
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(tmp, names) {
- r = unit_is_masked(bus, *tmp);
+ r = unit_is_masked(bus, &lp, *tmp);
if (r < 0)
return r;
return r;
}
-static void systemctl_help(void) {
+static int systemctl_help(void) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
(void) pager_open(arg_no_pager, false);
+ r = terminal_urlify_man("systemctl", "1", &link);
+ if (r < 0)
+ return log_oom();
+
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
"Query or send control commands to the systemd manager.\n\n"
" -h --help Show this help\n"
" --dry-run Only print what would be done\n"
" -q --quiet Suppress output\n"
" --wait For (re)start, wait until service stopped again\n"
+ " For is-system-running, wait until startup is completed\n"
" --no-block Do not wait until operation finished\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n"
" --no-reload Don't reload daemon after en-/dis-abling unit files\n"
" hibernate Hibernate the system\n"
" hybrid-sleep Hibernate and suspend the system\n"
" suspend-then-hibernate Suspend the system, wake after a period of\n"
- " time and put it into hibernate\n",
- program_invocation_short_name);
+ " time and put it into hibernate\n"
+ "\nSee the %s for details.\n"
+ , program_invocation_short_name
+ , link
+ );
+
+ return 0;
}
-static void halt_help(void) {
+static int halt_help(void) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ r = terminal_urlify_man("halt", "8", &link);
+ if (r < 0)
+ return log_oom();
+
printf("%s [OPTIONS...]%s\n\n"
"%s the system.\n\n"
" --help Show this help\n"
" -f --force Force immediate halt/power-off/reboot\n"
" -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
" -d --no-wtmp Don't write wtmp record\n"
- " --no-wall Don't send wall message before halt/power-off/reboot\n",
- program_invocation_short_name,
- arg_action == ACTION_REBOOT ? " [ARG]" : "",
- arg_action == ACTION_REBOOT ? "Reboot" :
- arg_action == ACTION_POWEROFF ? "Power off" :
- "Halt");
+ " --no-wall Don't send wall message before halt/power-off/reboot\n"
+ "\nSee the %s for details.\n"
+ , program_invocation_short_name
+ , arg_action == ACTION_REBOOT ? " [ARG]" : "",
+ arg_action == ACTION_REBOOT ? "Reboot" :
+ arg_action == ACTION_POWEROFF ? "Power off" :
+ "Halt"
+ , link
+ );
+
+ return 0;
}
-static void shutdown_help(void) {
+static int shutdown_help(void) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ r = terminal_urlify_man("shutdown", "8", &link);
+ if (r < 0)
+ return log_oom();
+
printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
"Shut down the system.\n\n"
" --help Show this help\n"
" -h Equivalent to --poweroff, overridden by --halt\n"
" -k Don't halt/power-off/reboot, just send warnings\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n"
- " -c Cancel a pending shutdown\n",
- program_invocation_short_name);
+ " -c Cancel a pending shutdown\n"
+ "\nSee the %s for details.\n"
+ , program_invocation_short_name
+ , link
+ );
+
+ return 0;
}
-static void telinit_help(void) {
+static int telinit_help(void) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ r = terminal_urlify_man("telinit", "8", &link);
+ if (r < 0)
+ return log_oom();
+
printf("%s [OPTIONS...] {COMMAND}\n\n"
"Send control commands to the init daemon.\n\n"
" --help Show this help\n"
" 2, 3, 4, 5 Start runlevelX.target unit\n"
" 1, s, S Enter rescue mode\n"
" q, Q Reload init daemon configuration\n"
- " u, U Reexecute init daemon\n",
- program_invocation_short_name);
+ " u, U Reexecute init daemon\n"
+ "\nSee the %s for details.\n"
+ , program_invocation_short_name
+ , link
+ );
+
+ return 0;
}
-static void runlevel_help(void) {
+static int runlevel_help(void) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ r = terminal_urlify_man("runlevel", "8", &link);
+ if (r < 0)
+ return log_oom();
+
printf("%s [OPTIONS...]\n\n"
"Prints the previous and current runlevel of the init system.\n\n"
- " --help Show this help\n",
- program_invocation_short_name);
+ " --help Show this help\n"
+ "\nSee the %s for details.\n"
+ , program_invocation_short_name
+ , link
+ );
+
+ return 0;
}
static void help_types(void) {
switch (c) {
case 'h':
- systemctl_help();
- return 0;
+ return systemctl_help();
case ARG_VERSION:
return version();
switch (c) {
case ARG_HELP:
- halt_help();
- return 0;
+ return halt_help();
case ARG_HALT:
arg_action = ACTION_HALT;
tm.tm_min = (int) minute;
tm.tm_sec = 0;
- assert_se(s = mktime(&tm));
+ s = mktime(&tm);
+ assert(s >= 0);
*_u = (usec_t) s * USEC_PER_SEC;
switch (c) {
case ARG_HELP:
- shutdown_help();
- return 0;
+ return shutdown_help();
case 'H':
arg_action = ACTION_HALT;
switch (c) {
case ARG_HELP:
- telinit_help();
- return 0;
+ return telinit_help();
case ARG_NO_WALL:
arg_no_wall = true;
switch (c) {
case ARG_HELP:
- runlevel_help();
- return 0;
+ return runlevel_help();
case '?':
return -EINVAL;
if (r < 0)
return r;
- if (arg_when > 0)
- return logind_schedule_shutdown();
+ /* Delayed shutdown requested, and was successful */
+ if (arg_when > 0 && logind_schedule_shutdown() == 0)
+ return 0;
+ /* no delay, or logind failed or is not at all available */
if (geteuid() != 0) {
if (arg_dry_run || arg_force > 0) {
}
/* Try logind if we are a normal user and no special
- * mode applies. Maybe PolicyKit allows us to shutdown
+ * mode applies. Maybe polkit allows us to shutdown
* the machine. */
if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
r = logind_reboot(arg_action);