summaryrefslogtreecommitdiff
path: root/src/systemctl/systemctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemctl/systemctl.c')
-rw-r--r--src/systemctl/systemctl.c469
1 files changed, 291 insertions, 178 deletions
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 6db4d6587a..34e4751b94 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -20,59 +20,60 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
#include <getopt.h>
+#include <linux/reboot.h>
#include <locale.h>
#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
+#include <sys/reboot.h>
#include <sys/socket.h>
-#include <stddef.h>
+#include <unistd.h>
+#include "sd-bus.h"
#include "sd-daemon.h"
#include "sd-login.h"
-#include "sd-bus.h"
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "set.h"
-#include "utmp-wtmp.h"
-#include "special.h"
-#include "initreq.h"
-#include "path-util.h"
-#include "strv.h"
+
+#include "build.h"
+#include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-message.h"
+#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
-#include "list.h"
-#include "path-lookup.h"
-#include "exit-status.h"
-#include "build.h"
-#include "unit-name.h"
-#include "pager.h"
-#include "spawn-ask-password-agent.h"
-#include "spawn-polkit-agent.h"
-#include "install.h"
-#include "logs-show.h"
-#include "socket-util.h"
-#include "fileio.h"
#include "copy.h"
-#include "env-util.h"
-#include "bus-util.h"
-#include "bus-message.h"
-#include "bus-error.h"
-#include "bus-common-errors.h"
-#include "mkdir.h"
#include "dropin.h"
#include "efivars.h"
+#include "env-util.h"
+#include "exit-status.h"
+#include "fileio.h"
#include "formats-util.h"
-#include "process-util.h"
-#include "terminal-util.h"
#include "hostname-util.h"
+#include "initreq.h"
+#include "install.h"
+#include "list.h"
+#include "log.h"
+#include "logs-show.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "pager.h"
+#include "path-lookup.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "set.h"
#include "signal-util.h"
+#include "socket-util.h"
+#include "spawn-ask-password-agent.h"
+#include "spawn-polkit-agent.h"
+#include "special.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "unit-name.h"
+#include "util.h"
+#include "utmp-wtmp.h"
static char **arg_types = NULL;
static char **arg_states = NULL;
@@ -100,7 +101,7 @@ static bool arg_quiet = false;
static bool arg_full = false;
static bool arg_recursive = false;
static int arg_force = 0;
-static bool arg_ask_password = true;
+static bool arg_ask_password = false;
static bool arg_runtime = false;
static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
static char **arg_wall = NULL;
@@ -430,11 +431,11 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
if (STR_IN_SET(u->load_state, "error", "not-found", "masked") && !arg_plain) {
on_loaded = ansi_highlight_red();
on_circle = ansi_highlight_yellow();
- off_loaded = off_circle = ansi_highlight_off();
+ off_loaded = off_circle = ansi_normal();
circle = true;
} else if (streq(u->active_state, "failed") && !arg_plain) {
on_circle = on_active = ansi_highlight_red();
- off_circle = off_active = ansi_highlight_off();
+ off_circle = off_active = ansi_normal();
circle = true;
}
@@ -481,10 +482,10 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
"SUB = The low-level unit activation state, values depend on unit type.");
puts(job_count ? "JOB = Pending job for the unit.\n" : "");
on = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
}
if (arg_all)
@@ -535,10 +536,8 @@ static int get_unit_list(
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- log_error("Failed to list units: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
if (r < 0)
@@ -605,7 +604,7 @@ static int get_unit_list_recursive(
r = set_put(replies, reply);
if (r < 0) {
sd_bus_message_unref(reply);
- return r;
+ return log_oom();
}
if (arg_recursive) {
@@ -614,7 +613,7 @@ static int get_unit_list_recursive(
r = sd_get_machine_names(&machines);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to get machine names: %m");
STRV_FOREACH(i, machines) {
_cleanup_bus_flush_close_unref_ sd_bus *container = NULL;
@@ -622,7 +621,7 @@ static int get_unit_list_recursive(
r = sd_bus_open_system_machine(&container, *i);
if (r < 0) {
- log_error_errno(r, "Failed to connect to container %s: %m", *i);
+ log_warning_errno(r, "Failed to connect to container %s, ignoring: %m", *i);
continue;
}
@@ -635,7 +634,7 @@ static int get_unit_list_recursive(
r = set_put(replies, reply);
if (r < 0) {
sd_bus_message_unref(reply);
- return r;
+ return log_oom();
}
}
@@ -837,12 +836,12 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
}
on = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
if (!arg_no_legend)
printf("\n");
} else {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
}
if (!arg_no_legend) {
@@ -1119,12 +1118,12 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
}
on = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
if (!arg_no_legend)
printf("\n");
} else {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
}
if (!arg_no_legend) {
@@ -1301,15 +1300,16 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
const char *on, *off;
const char *id;
- if (u->state == UNIT_FILE_MASKED ||
- u->state == UNIT_FILE_MASKED_RUNTIME ||
- u->state == UNIT_FILE_DISABLED ||
- u->state == UNIT_FILE_INVALID) {
+ if (IN_SET(u->state,
+ UNIT_FILE_MASKED,
+ UNIT_FILE_MASKED_RUNTIME,
+ UNIT_FILE_DISABLED,
+ UNIT_FILE_INVALID)) {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else if (u->state == UNIT_FILE_ENABLED) {
on = ansi_highlight_green();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else
on = off = "";
@@ -1474,9 +1474,12 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
"Requisite\0"
"RequisiteOverridable\0"
"Wants\0"
+ "ConsistsOf\0"
"BindsTo\0",
[DEPENDENCY_REVERSE] = "RequiredBy\0"
"RequiredByOverridable\0"
+ "RequisiteOf\0"
+ "RequisiteOfOverridable\0"
"WantedBy\0"
"PartOf\0"
"BoundBy\0",
@@ -1615,7 +1618,7 @@ static int list_dependencies_one(
state = check_one_unit(bus, *c, "activating\0active\0reloading\0", true);
on = state > 0 ? ansi_highlight_green() : ansi_highlight_red();
- printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_highlight_off());
+ printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_normal());
}
r = list_dependencies_print(*c, level, branches, c[1] == NULL);
@@ -1743,7 +1746,7 @@ static int get_machine_list(
_cleanup_free_ char *hn = NULL;
size_t sz = 0;
char **i;
- int c = 0;
+ int c = 0, r;
hn = gethostname_malloc();
if (!hn)
@@ -1761,7 +1764,10 @@ static int get_machine_list(
c++;
}
- sd_get_machine_names(&m);
+ r = sd_get_machine_names(&m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get machine list: %m");
+
STRV_FOREACH(i, m) {
_cleanup_free_ char *class = NULL;
@@ -1831,17 +1837,17 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n)
if (streq_ptr(m->state, "degraded")) {
on_state = ansi_highlight_red();
- off_state = ansi_highlight_off();
+ off_state = ansi_normal();
circle = true;
} else if (!streq_ptr(m->state, "running")) {
on_state = ansi_highlight_yellow();
- off_state = ansi_highlight_off();
+ off_state = ansi_normal();
circle = true;
}
if (m->n_failed_units > 0) {
on_failed = ansi_highlight_red();
- off_failed = ansi_highlight_off();
+ off_failed = ansi_normal();
} else
on_failed = off_failed = "";
@@ -2014,7 +2020,7 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipp
if (n == 0) {
if (!arg_no_legend) {
on = ansi_highlight_green();
- off = ansi_highlight_off();
+ off = ansi_normal();
printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
}
@@ -2055,7 +2061,7 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipp
if (streq(j->state, "running")) {
on = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else
on = off = "";
@@ -2069,7 +2075,7 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipp
if (!arg_no_legend) {
on = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
printf("\n%s%u jobs listed%s.\n", on, n, off);
}
@@ -2215,7 +2221,7 @@ static int need_daemon_reload(sd_bus *bus, const char *unit) {
static void warn_unit_file_changed(const char *name) {
log_warning("%sWarning:%s %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
ansi_highlight_red(),
- ansi_highlight_off(),
+ ansi_normal(),
name,
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
}
@@ -2760,7 +2766,7 @@ static int start_unit(sd_bus *bus, char **args) {
static int reboot_with_logind(sd_bus *bus, enum action a) {
#ifdef HAVE_LOGIND
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *method;
+ const char *method, *description;
int r;
if (!bus)
@@ -2772,28 +2778,60 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
case ACTION_REBOOT:
method = "Reboot";
+ description = "reboot system";
break;
case ACTION_POWEROFF:
method = "PowerOff";
+ description = "power off 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;
default:
return -EINVAL;
}
+ if (!strv_isempty(arg_wall)) {
+ _cleanup_free_ char *m;
+
+ m = strv_join(arg_wall, " ");
+ if (!m)
+ return log_oom();
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetWallMessage",
+ &error,
+ NULL,
+ "sb",
+ m,
+ !arg_no_wall);
+
+ if (r < 0) {
+ log_warning_errno(r, "Failed to set wall message, ignoring: %s",
+ bus_error_message(&error, r));
+ sd_bus_error_free(&error);
+ }
+ }
+
+
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
@@ -2804,7 +2842,7 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
NULL,
"b", arg_ask_password);
if (r < 0)
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ log_error("Failed to %s via logind: %s", description, bus_error_message(&error, r));
return r;
#else
@@ -2869,10 +2907,11 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
if (!strv_contains(sv,
- a == ACTION_HALT ||
- a == ACTION_POWEROFF ||
- a == ACTION_REBOOT ||
- a == ACTION_KEXEC ? "shutdown" : "sleep"))
+ IN_SET(a,
+ ACTION_HALT,
+ ACTION_POWEROFF,
+ ACTION_REBOOT,
+ ACTION_KEXEC) ? "shutdown" : "sleep"))
continue;
get_process_comm(pid, &comm);
@@ -2966,6 +3005,7 @@ static int prepare_firmware_setup(sd_bus *bus) {
}
static int start_special(sd_bus *bus, char **args) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
enum action a;
int r;
@@ -2990,32 +3030,64 @@ static int start_special(sd_bus *bus, char **args) {
r = update_reboot_param_file(args[1]);
if (r < 0)
return r;
+ } else if (a == ACTION_EXIT && strv_length(args) > 1) {
+ /* If the exit code is not given on the command line, don't
+ * reset it to zero: just keep it as it might have been set
+ * previously. */
+ uint8_t code = 0;
+
+ r = safe_atou8(args[1], &code);
+ if (r < 0) {
+ log_error("Invalid exit code.");
+ return -EINVAL;
+ }
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SetExitCode",
+ &error,
+ NULL,
+ "y", code);
+ if (r < 0) {
+ log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ return r;
+ }
}
if (arg_force >= 2 &&
- (a == ACTION_HALT ||
- a == ACTION_POWEROFF ||
- a == ACTION_REBOOT))
+ IN_SET(a,
+ ACTION_HALT,
+ ACTION_POWEROFF,
+ ACTION_REBOOT))
return halt_now(a);
if (arg_force >= 1 &&
- (a == ACTION_HALT ||
- a == ACTION_POWEROFF ||
- a == ACTION_REBOOT ||
- a == ACTION_KEXEC ||
- a == ACTION_EXIT))
+ IN_SET(a,
+ ACTION_HALT,
+ ACTION_POWEROFF,
+ ACTION_REBOOT,
+ ACTION_KEXEC,
+ ACTION_EXIT))
return daemon_reload(bus, args);
/* first try logind, to allow authentication with polkit */
if (geteuid() != 0 &&
- (a == ACTION_POWEROFF ||
- a == ACTION_REBOOT ||
- a == ACTION_SUSPEND ||
- a == ACTION_HIBERNATE ||
- a == ACTION_HYBRID_SLEEP)) {
+ IN_SET(a,
+ ACTION_POWEROFF,
+ ACTION_REBOOT,
+ ACTION_SUSPEND,
+ ACTION_HIBERNATE,
+ ACTION_HYBRID_SLEEP)) {
r = reboot_with_logind(bus, a);
- if (r >= 0 || IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+ if (r >= 0)
+ return r;
+ if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+ /* requested operation is not supported or already in progress */
return r;
+ /* on all other errors, try low-level operation */
}
r = start_unit(bus, args);
@@ -3061,7 +3133,7 @@ static int check_unit_failed(sd_bus *bus, char **args) {
static int kill_unit(sd_bus *bus, char **args) {
_cleanup_strv_free_ char **names = NULL;
- char **name;
+ char *kill_who = NULL, **name;
int r, q;
assert(bus);
@@ -3072,6 +3144,10 @@ static int kill_unit(sd_bus *bus, char **args) {
if (!arg_kill_who)
arg_kill_who = "all";
+ /* --fail was specified */
+ if (streq(arg_job_mode, "fail"))
+ kill_who = strjoina(arg_kill_who, "-fail", NULL);
+
r = expand_names(bus, args + 1, NULL, &names);
if (r < 0)
log_error_errno(r, "Failed to expand names: %m");
@@ -3087,7 +3163,7 @@ static int kill_unit(sd_bus *bus, char **args) {
"KillUnit",
&error,
NULL,
- "ssi", *names, arg_kill_who, arg_signal);
+ "ssi", *names, kill_who ? kill_who : arg_kill_who, arg_signal);
if (q < 0) {
log_error("Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
if (r == 0)
@@ -3254,6 +3330,8 @@ typedef struct UnitStatusInfo {
uint64_t memory_current;
uint64_t memory_limit;
uint64_t cpu_usage_nsec;
+ uint64_t tasks_current;
+ uint64_t tasks_max;
LIST_HEAD(ExecStatusInfo, exec);
} UnitStatusInfo;
@@ -3277,10 +3355,10 @@ static void print_status_info(
if (streq_ptr(i->active_state, "failed")) {
active_on = ansi_highlight_red();
- active_off = ansi_highlight_off();
+ active_off = ansi_normal();
} else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
active_on = ansi_highlight_green();
- active_off = ansi_highlight_off();
+ active_off = ansi_normal();
} else
active_on = active_off = "";
@@ -3296,7 +3374,7 @@ static void print_status_info(
if (streq_ptr(i->load_state, "error")) {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else
on = off = "";
@@ -3327,8 +3405,7 @@ static void print_status_info(
if (! dir || last) {
printf(dir ? " " : " Drop-In: ");
- free(dir);
- dir = NULL;
+ dir = mfree(dir);
if (path_get_parent(*dropin, &dir) < 0) {
log_oom();
@@ -3378,7 +3455,7 @@ static void print_status_info(
s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
printf("Condition: start %scondition failed%s at %s%s%s\n",
- ansi_highlight_yellow(), ansi_highlight_off(),
+ ansi_highlight_yellow(), ansi_normal(),
s2, s1 ? "; " : "", s1 ? s1 : "");
if (i->failed_condition_trigger)
printf(" none of the trigger conditions were met\n");
@@ -3394,7 +3471,7 @@ static void print_status_info(
s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
printf(" Assert: start %sassertion failed%s at %s%s%s\n",
- ansi_highlight_red(), ansi_highlight_off(),
+ ansi_highlight_red(), ansi_normal(),
s2, s1 ? "; " : "", s1 ? s1 : "");
if (i->failed_assert_trigger)
printf(" none of the trigger assertions were met\n");
@@ -3435,7 +3512,7 @@ static void print_status_info(
good = is_clean_exit_lsb(p->code, p->status, NULL);
if (!good) {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else
on = off = "";
@@ -3513,6 +3590,15 @@ static void print_status_info(
if (i->status_errno > 0)
printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
+ if (i->tasks_current != (uint64_t) -1) {
+ printf(" Tasks: %" PRIu64, i->tasks_current);
+
+ if (i->tasks_max != (uint64_t) -1)
+ printf(" (limit: %" PRIi64 ")\n", i->tasks_max);
+ else
+ printf("\n");
+ }
+
if (i->memory_current != (uint64_t) -1) {
char buf[FORMAT_BYTES_MAX];
@@ -3531,12 +3617,14 @@ static void print_status_info(
if (i->control_group &&
(i->main_pid > 0 || i->control_pid > 0 ||
- ((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0))) {
+ (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group) == 0))) {
unsigned c;
printf(" CGroup: %s\n", i->control_group);
- if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_MACHINE) {
+ if (IN_SET(arg_transport,
+ BUS_TRANSPORT_LOCAL,
+ BUS_TRANSPORT_MACHINE)) {
unsigned k = 0;
pid_t extra[2];
static const char prefix[] = " ";
@@ -3557,7 +3645,7 @@ static void print_status_info(
}
}
- if (i->id && arg_transport == BUS_TRANSPORT_LOCAL) {
+ if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
show_journal_by_unit(
stdout,
i->id,
@@ -3570,7 +3658,6 @@ static void print_status_info(
SD_JOURNAL_LOCAL_ONLY,
arg_scope == UNIT_FILE_SYSTEM,
ellipsized);
- }
if (i->need_daemon_reload)
warn_unit_file_changed(i->id);
@@ -3747,6 +3834,10 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
i->memory_current = u;
else if (streq(name, "MemoryLimit"))
i->memory_limit = u;
+ else if (streq(name, "TasksCurrent"))
+ i->tasks_current = u;
+ else if (streq(name, "TasksMax"))
+ i->tasks_max = u;
else if (streq(name, "CPUUsageNSec"))
i->cpu_usage_nsec = u;
@@ -4223,6 +4314,8 @@ static int show_one(
.memory_current = (uint64_t) -1,
.memory_limit = (uint64_t) -1,
.cpu_usage_nsec = (uint64_t) -1,
+ .tasks_current = (uint64_t) -1,
+ .tasks_max = (uint64_t) -1,
};
ExecStatusInfo *p;
int r;
@@ -4241,10 +4334,8 @@ static int show_one(
&error,
&reply,
"s", "");
- if (r < 0) {
- log_error("Failed to get properties: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
if (r < 0)
@@ -4422,10 +4513,10 @@ static int show_system_status(sd_bus *bus) {
if (streq_ptr(mi.state, "degraded")) {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else if (!streq_ptr(mi.state, "running")) {
on = ansi_highlight_yellow();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else
on = off = "";
@@ -4442,7 +4533,9 @@ static int show_system_status(sd_bus *bus) {
format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
printf(" CGroup: %s\n", mi.control_group ?: "/");
- if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_MACHINE) {
+ if (IN_SET(arg_transport,
+ BUS_TRANSPORT_LOCAL,
+ BUS_TRANSPORT_MACHINE)) {
static const char prefix[] = " ";
unsigned c;
@@ -4595,10 +4688,10 @@ static int cat_file(const char *filename, bool newline) {
newline ? "\n" : "",
ansi_highlight_blue(),
filename,
- ansi_highlight_off());
+ ansi_normal());
fflush(stdout);
- return copy_bytes(fd, STDOUT_FILENO, (off_t) -1, false);
+ return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false);
}
static int cat(sd_bus *bus, char **args) {
@@ -5109,9 +5202,10 @@ static int enable_sysv_units(const char *verb, char **args) {
if (arg_scope != UNIT_FILE_SYSTEM)
return 0;
- if (!streq(verb, "enable") &&
- !streq(verb, "disable") &&
- !streq(verb, "is-enabled"))
+ if (!STR_IN_SET(verb,
+ "enable",
+ "disable",
+ "is-enabled"))
return 0;
/* Processes all SysV units, and reshuffles the array so that
@@ -5611,10 +5705,11 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
if (state < 0)
return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
- if (state == UNIT_FILE_ENABLED ||
- state == UNIT_FILE_ENABLED_RUNTIME ||
- state == UNIT_FILE_STATIC ||
- state == UNIT_FILE_INDIRECT)
+ if (IN_SET(state,
+ UNIT_FILE_ENABLED,
+ UNIT_FILE_ENABLED_RUNTIME,
+ UNIT_FILE_STATIC,
+ UNIT_FILE_INDIRECT))
enabled = true;
if (!arg_quiet)
@@ -6155,7 +6250,7 @@ static void systemctl_help(void) {
" poweroff Shut down and power-off the system\n"
" reboot [ARG] Shut down and reboot the system\n"
" kexec Shut down and reboot the system with kexec\n"
- " exit Request user instance exit\n"
+ " exit [EXIT_CODE] Request user instance or container exit\n"
" switch-root ROOT [INIT] Change to a different root file system\n"
" suspend Suspend the system\n"
" hibernate Hibernate the system\n"
@@ -6261,6 +6356,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_PRESET_MODE,
ARG_FIRMWARE_SETUP,
ARG_NOW,
+ ARG_MESSAGE,
};
static const struct option options[] = {
@@ -6305,6 +6401,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
{ "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
{ "now", no_argument, NULL, ARG_NOW },
+ { "message", required_argument, NULL, ARG_MESSAGE },
{}
};
@@ -6313,6 +6410,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
+ /* 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)
switch (c) {
@@ -6589,6 +6689,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_now = true;
break;
+ case ARG_MESSAGE:
+ if (strv_extend(&arg_wall, optarg) < 0)
+ return log_oom();
+ break;
+
case '?':
return -EINVAL;
@@ -7132,7 +7237,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
{ "default", EQUAL, 1, start_special },
{ "rescue", EQUAL, 1, start_special },
{ "emergency", EQUAL, 1, start_special },
- { "exit", EQUAL, 1, start_special },
+ { "exit", LESS, 2, start_special },
{ "reset-failed", MORE, 1, reset_failed },
{ "enable", MORE, 2, enable_unit, NOBUS },
{ "disable", MORE, 2, enable_unit, NOBUS },
@@ -7293,6 +7398,7 @@ static int halt_now(enum action a) {
reboot(RB_POWER_OFF);
return -errno;
+ case ACTION_KEXEC:
case ACTION_REBOOT: {
_cleanup_free_ char *param = NULL;
@@ -7320,28 +7426,36 @@ static int halt_main(sd_bus *bus) {
return r;
if (geteuid() != 0) {
+ if (arg_when > 0 ||
+ arg_dry ||
+ arg_force > 0) {
+ log_error("Must be root.");
+ return -EPERM;
+ }
+
/* Try logind if we are a normal user and no special
* mode applies. Maybe PolicyKit allows us to shutdown
* the machine. */
-
- if (arg_when <= 0 &&
- !arg_dry &&
- arg_force <= 0 &&
- (arg_action == ACTION_POWEROFF ||
- arg_action == ACTION_REBOOT)) {
+ if (IN_SET(arg_action,
+ ACTION_POWEROFF,
+ ACTION_REBOOT)) {
r = reboot_with_logind(bus, arg_action);
if (r >= 0)
return r;
+ if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+ /* requested operation is not supported or already in progress */
+ return r;
+ /* on all other errors, try low-level operation */
}
-
- log_error("Must be root.");
- return -EPERM;
}
if (arg_when > 0) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
_cleanup_free_ char *m = NULL;
+ const char *action;
+
+ assert(geteuid() == 0);
if (avoid_bus()) {
log_error("Unable to perform operation without bus connection.");
@@ -7356,34 +7470,42 @@ static int halt_main(sd_bus *bus) {
if (!m)
return log_oom();
- r = sd_bus_set_property(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "WallMessage",
- &error,
- "s", m);
+ r = sd_bus_call_method(
+ b,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetWallMessage",
+ &error,
+ NULL,
+ "sb",
+ m,
+ !arg_no_wall);
+
if (r < 0) {
- log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
+ log_warning_errno(r, "Failed to set wall message, ignoring: %s",
bus_error_message(&error, r));
sd_bus_error_free(&error);
}
- r = sd_bus_set_property(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "EnableWallMessages",
- &error,
- "b", !arg_no_wall);
- if (r < 0) {
- log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
+ switch (arg_action) {
+ case ACTION_HALT:
+ action = "halt";
+ break;
+ case ACTION_POWEROFF:
+ action = "poweroff";
+ break;
+ case ACTION_KEXEC:
+ action = "kexec";
+ break;
+ default:
+ action = "reboot";
+ break;
}
+ if (arg_dry)
+ action = strjoina("dry-", action);
+
r = sd_bus_call_method(
b,
"org.freedesktop.login1",
@@ -7393,10 +7515,7 @@ static int halt_main(sd_bus *bus) {
&error,
NULL,
"st",
- arg_action == ACTION_HALT ? "halt" :
- arg_action == ACTION_POWEROFF ? "poweroff" :
- arg_action == ACTION_KEXEC ? "kexec" :
- "reboot",
+ action,
arg_when);
if (r < 0)
log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s",
@@ -7413,6 +7532,8 @@ static int halt_main(sd_bus *bus) {
if (!arg_dry && !arg_force)
return start_with_fallback(bus);
+ assert(geteuid() == 0);
+
if (!arg_no_wtmp) {
if (sd_booted() > 0)
log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
@@ -7537,30 +7658,20 @@ int main(int argc, char*argv[]) {
}
}
- r = sd_bus_set_property(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "WallMessage",
- &error,
- "s", arg_wall);
- if (r < 0) {
- log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
+ r = sd_bus_call_method(
+ b,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetWallMessage",
+ &error,
+ NULL,
+ "sb",
+ m,
+ !arg_no_wall);
- r = sd_bus_set_property(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "EnableWallMessages",
- &error,
- "b", !arg_no_wall);
if (r < 0) {
- log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
+ log_warning_errno(r, "Failed to set wall message, ignoring: %s",
bus_error_message(&error, r));
sd_bus_error_free(&error);
}
@@ -7594,5 +7705,7 @@ finish:
strv_free(arg_states);
strv_free(arg_properties);
+ sd_bus_default_flush_close();
+
return r < 0 ? EXIT_FAILURE : r;
}