summaryrefslogtreecommitdiffstats
path: root/src/systemctl
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemctl')
-rw-r--r--src/systemctl/systemctl-list-units.c81
-rw-r--r--src/systemctl/systemctl-logind.c5
-rw-r--r--src/systemctl/systemctl-start-special.c3
-rw-r--r--src/systemctl/systemctl-start-unit.c3
-rw-r--r--src/systemctl/systemctl-whoami.c164
-rw-r--r--src/systemctl/systemctl.c4
-rw-r--r--src/systemctl/systemctl.h1
7 files changed, 200 insertions, 61 deletions
diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c
index e48cf45333..a1482d40c2 100644
--- a/src/systemctl/systemctl-list-units.c
+++ b/src/systemctl/systemctl-list-units.c
@@ -127,49 +127,70 @@ static int output_units_list(const UnitInfo *unit_infos, size_t c) {
table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
FOREACH_ARRAY(u, unit_infos, c) {
+ const char *on_loaded = NULL, *on_active = NULL, *on_sub = NULL, *on_circle = NULL;
_cleanup_free_ char *id = NULL;
- const char *on_underline = "", *on_loaded = "", *on_active = "", *on_circle = "";
- bool circle = false, underline = false;
+ bool circle = false, underline;
- if (u + 1 < unit_infos + c &&
- !streq(unit_type_suffix(u->id), unit_type_suffix((u + 1)->id))) {
- on_underline = ansi_underline();
- underline = true;
- }
+ underline = u + 1 < unit_infos + c && !streq(unit_type_suffix(u->id), unit_type_suffix((u + 1)->id));
- if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) {
- on_circle = underline ? ansi_highlight_yellow_underline() : ansi_highlight_yellow();
+ if (streq(u->load_state, "not-found")) {
+ on_circle = on_loaded = ansi_highlight_yellow();
+ on_circle = ansi_highlight_yellow();
circle = true;
- on_loaded = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
- } else if (streq(u->active_state, "failed") && !arg_plain) {
- on_circle = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
+ } else if (STR_IN_SET(u->load_state, "bad-setting", "error", "masked")) {
+ on_loaded = ansi_highlight_red();
+ on_circle = ansi_highlight_yellow();
circle = true;
- on_active = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
- } else {
- on_circle = on_underline;
- on_active = on_underline;
- on_loaded = on_underline;
}
+ if (streq(u->active_state, "failed")) {
+ on_sub = on_active = ansi_highlight_red();
+
+ /* Here override any load_state highlighting */
+ on_circle = ansi_highlight_red();
+ circle = true;
+ } else if (STR_IN_SET(u->active_state, "reloading", "activating", "maintenance", "deactivating")) {
+ on_sub = on_active = ansi_highlight();
+
+ if (!circle) { /* Here we let load_state highlighting win */
+ on_circle = ansi_highlight();
+ circle = true;
+ }
+ } else if (streq(u->active_state, "inactive"))
+ on_sub = on_active = ansi_grey();
+
+ /* As a special case, when this is a service which has not process running, let's grey out
+ * its state, to highlight that a bit */
+ if (!on_sub && endswith(u->id, ".service") && streq(u->sub_state, "exited"))
+ on_sub = ansi_grey();
+
+ if (arg_plain)
+ circle = false;
+
id = format_unit_id(u->id, u->machine);
if (!id)
return log_oom();
r = table_add_many(table,
TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
- TABLE_SET_BOTH_COLORS, on_circle,
+ TABLE_SET_COLOR, on_circle,
+ TABLE_SET_BOTH_UNDERLINES, underline,
TABLE_STRING, id,
- TABLE_SET_BOTH_COLORS, on_active,
+ TABLE_SET_COLOR, on_active,
+ TABLE_SET_BOTH_UNDERLINES, underline,
TABLE_STRING, u->load_state,
- TABLE_SET_BOTH_COLORS, on_loaded,
+ TABLE_SET_COLOR, on_loaded,
+ TABLE_SET_BOTH_UNDERLINES, underline,
TABLE_STRING, u->active_state,
- TABLE_SET_BOTH_COLORS, on_active,
+ TABLE_SET_COLOR, on_active,
+ TABLE_SET_BOTH_UNDERLINES, underline,
TABLE_STRING, u->sub_state,
- TABLE_SET_BOTH_COLORS, on_active,
+ TABLE_SET_COLOR, on_sub,
+ TABLE_SET_BOTH_UNDERLINES, underline,
TABLE_STRING, u->job_id ? u->job_type: "",
- TABLE_SET_BOTH_COLORS, on_underline,
+ TABLE_SET_BOTH_UNDERLINES, underline,
TABLE_STRING, u->description,
- TABLE_SET_BOTH_COLORS, on_underline);
+ TABLE_SET_BOTH_UNDERLINES, underline);
if (r < 0)
return table_log_add_error(r);
@@ -214,12 +235,14 @@ static int output_units_list(const UnitInfo *unit_infos, size_t c) {
if (arg_all || strv_contains(arg_states, "inactive"))
printf("%s%zu loaded units listed.%s\n"
- "To show all installed unit files use 'systemctl list-unit-files'.\n",
- on, records, off);
+ "%sTo show all installed unit files use 'systemctl list-unit-files'.%s\n",
+ on, records, off,
+ ansi_grey(), ansi_normal());
else if (!arg_states)
- printf("%s%zu loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
- "To show all installed unit files use 'systemctl list-unit-files'.\n",
- on, records, off);
+ printf("%s%zu loaded units listed.%s %sPass --all to see loaded but inactive units, too.%s\n"
+ "%sTo show all installed unit files use 'systemctl list-unit-files'.%s\n",
+ on, records, off,
+ ansi_grey(), ansi_normal(), ansi_grey(), ansi_normal());
else
printf("%zu loaded units listed.\n", records);
}
diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c
index 268e528856..2e35413b5f 100644
--- a/src/systemctl/systemctl-logind.c
+++ b/src/systemctl/systemctl-logind.c
@@ -51,6 +51,7 @@ int logind_reboot(enum action a) {
[ACTION_HIBERNATE] = "Hibernate",
[ACTION_HYBRID_SLEEP] = "HybridSleep",
[ACTION_SUSPEND_THEN_HIBERNATE] = "SuspendThenHibernate",
+ [ACTION_SLEEP] = "Sleep",
};
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -71,7 +72,7 @@ int logind_reboot(enum action a) {
polkit_agent_open_maybe();
(void) logind_set_wall_message(bus);
- const char *method_with_flags = strjoina(actions[a], "WithFlags");
+ const char *method_with_flags = a == ACTION_SLEEP ? actions[a] : strjoina(actions[a], "WithFlags");
log_debug("%s org.freedesktop.login1.Manager %s dbus call.",
arg_dry_run ? "Would execute" : "Executing", method_with_flags);
@@ -103,7 +104,7 @@ int logind_reboot(enum action a) {
}
if (r >= 0)
return 0;
- if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
+ if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD) || a == ACTION_SLEEP)
return log_error_errno(r, "Call to %s failed: %s", actions[a], bus_error_message(&error, r));
/* Fall back to original methods in case there is an older version of systemd-logind */
diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c
index d93bffb759..2cf746c5a6 100644
--- a/src/systemctl/systemctl-start-special.c
+++ b/src/systemctl/systemctl-start-special.c
@@ -229,6 +229,9 @@ int verb_start_special(int argc, char *argv[], void *userdata) {
arg_no_block = true;
break;
+ case ACTION_SLEEP:
+ return logind_reboot(a);
+
case ACTION_EXIT:
/* Since exit is so close in behaviour to power-off/reboot, let's also make
* it asynchronous, in order to not confuse the user needlessly with unexpected
diff --git a/src/systemctl/systemctl-start-unit.c b/src/systemctl/systemctl-start-unit.c
index 6927e97747..ae7e25eedb 100644
--- a/src/systemctl/systemctl-start-unit.c
+++ b/src/systemctl/systemctl-start-unit.c
@@ -236,6 +236,7 @@ const struct action_metadata action_table[_ACTION_MAX] = {
[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" },
+ [ACTION_SLEEP] = { NULL, /* handled only by logind */ "sleep", NULL },
};
enum action verb_to_action(const char *verb) {
@@ -294,6 +295,8 @@ int verb_start(int argc, char *argv[], void *userdata) {
action = verb_to_action(argv[0]);
+ assert(action != ACTION_SLEEP);
+
if (action != _ACTION_INVALID) {
/* A command in style "systemctl reboot", "systemctl poweroff", … */
method = "StartUnit";
diff --git a/src/systemctl/systemctl-whoami.c b/src/systemctl/systemctl-whoami.c
index 4ee6592525..bac72c8973 100644
--- a/src/systemctl/systemctl-whoami.c
+++ b/src/systemctl/systemctl-whoami.c
@@ -1,24 +1,39 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-locator.h"
+#include "format-util.h"
+#include "parse-util.h"
+#include "pidref.h"
+#include "process-util.h"
#include "systemctl.h"
#include "systemctl-util.h"
#include "systemctl-whoami.h"
-#include "parse-util.h"
-static int lookup_pid(sd_bus *bus, pid_t pid) {
+static int get_unit_by_pid(sd_bus *bus, pid_t pid, char **ret) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *unit = NULL;
const char *path;
int r;
+ assert(bus);
+ assert(pid >= 0); /* 0 is accepted by GetUnitByPID for querying our own process. */
+ assert(ret);
+
r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", (uint32_t) pid);
- if (r < 0)
- return log_error_errno(r, "Failed to get unit for ourselves: %s", bus_error_message(&error, r));
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_UNIT_FOR_PID))
+ return log_error_errno(r, "%s", bus_error_message(&error, r));
+
+ return log_error_errno(r,
+ "Failed to get unit that PID " PID_FMT " belongs to: %s",
+ pid > 0 ? pid : getpid_cached(),
+ bus_error_message(&error, r));
+ }
- r = sd_bus_message_read(reply, "o", &path);
+ r = sd_bus_message_read_basic(reply, 'o', &path);
if (r < 0)
return bus_log_parse_error(r);
@@ -26,7 +41,103 @@ static int lookup_pid(sd_bus *bus, pid_t pid) {
if (r < 0)
return log_error_errno(r, "Failed to extract unit name from D-Bus object path '%s': %m", path);
- printf("%s\n", unit);
+ *ret = TAKE_PTR(unit);
+ return 0;
+}
+
+static int lookup_pidfd(sd_bus *bus, const PidRef *pid, char **ret) {
+ _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 *unit;
+ int r;
+
+ assert(bus);
+ assert(pidref_is_set(pid));
+ assert(ret);
+
+ if (pid->fd < 0)
+ return -EOPNOTSUPP;
+
+ r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPIDFD", &error, &reply, "h", pid->fd);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
+ return -EOPNOTSUPP;
+
+ if (sd_bus_error_has_names(&error, BUS_ERROR_NO_UNIT_FOR_PID, BUS_ERROR_NO_SUCH_PROCESS))
+ return log_error_errno(r, "%s", bus_error_message(&error, r));
+
+ return log_error_errno(r,
+ "Failed to get unit that PID " PID_FMT " belongs to: %s",
+ pid->pid, bus_error_message(&error, r));
+ }
+
+ r = sd_bus_message_read(reply, "os", NULL, &unit);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ char *u = strdup(unit);
+ if (!u)
+ return log_oom();
+
+ *ret = TAKE_PTR(u);
+
+ return 0;
+}
+
+static int lookup_pid(sd_bus *bus, const char *pidstr) {
+ _cleanup_free_ char *unit = NULL;
+ int r;
+
+ assert(bus);
+ assert(pidstr);
+
+ if (arg_transport == BUS_TRANSPORT_LOCAL) {
+ static bool use_pidfd = true;
+ _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
+
+ r = pidref_set_pidstr(&pid, pidstr);
+ if (r < 0)
+ return log_error_errno(r,
+ r == -ESRCH ?
+ "PID %s doesn't exist or is already gone." :
+ "Failed to create reference to PID %s: %m",
+ pidstr);
+
+ if (use_pidfd) {
+ r = lookup_pidfd(bus, &pid, &unit);
+ if (r == -EOPNOTSUPP) {
+ use_pidfd = false;
+ log_debug_errno(r, "Unable to look up process using pidfd, ignoring.");
+ } else if (r < 0)
+ return r;
+ }
+
+ if (!use_pidfd) {
+ assert(!unit);
+
+ r = get_unit_by_pid(bus, pid.pid, &unit);
+ if (r < 0)
+ return r;
+
+ r = pidref_verify(&pid);
+ if (r < 0)
+ return log_error_errno(r,
+ "Failed to verify our reference to PID " PID_FMT ": %m",
+ pid.pid);
+ }
+ } else {
+ pid_t pid;
+
+ r = parse_pid(pidstr, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse PID %s: %m", pidstr);
+
+ r = get_unit_by_pid(bus, pid, &unit);
+ if (r < 0)
+ return r;
+ }
+
+ puts(unit);
return 0;
}
@@ -38,33 +149,26 @@ int verb_whoami(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- char **pids = strv_skip(argv, 1);
-
- if (strv_isempty(pids)) {
+ if (argc <= 1) {
+ _cleanup_free_ char *unit = NULL;
if (arg_transport != BUS_TRANSPORT_LOCAL)
- return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Refusing to look up local PID on remote host.");
+ return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Refusing to look up our local PID on remote host.");
- return lookup_pid(bus, 0);
- } else {
- int ret = 0;
-
- STRV_FOREACH(p, pids) {
- pid_t pid;
-
- r = parse_pid(*p, &pid);
- if (r < 0) {
- log_error_errno(r, "Failed to parse PID: %s", *p);
- if (ret >= 0)
- ret = r;
- continue;
- }
-
- r = lookup_pid(bus, pid);
- if (r < 0 && ret >= 0)
- ret = r;
- }
+ /* Our own process can never go away while querying, hence no need to open pidfd. */
+
+ r = get_unit_by_pid(bus, 0, &unit);
+ if (r < 0)
+ return r;
- return ret;
+ puts(unit);
+ return 0;
}
+
+ r = 0;
+
+ STRV_FOREACH(pid, strv_skip(argv, 1))
+ RET_GATHER(r, lookup_pid(bus, *pid));
+
+ return r;
}
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 2a1d2d7967..d278d74789 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -250,6 +250,8 @@ static int systemctl_help(void) {
" soft-reboot Shut down and reboot userspace\n"
" exit [EXIT_CODE] Request user instance or container exit\n"
" switch-root [ROOT [INIT]] Change to a different root file system\n"
+ " sleep Put the system to sleep (through one of\n"
+ " the operations below)\n"
" suspend Suspend the system\n"
" hibernate Hibernate the system\n"
" hybrid-sleep Hibernate and suspend the system\n"
@@ -1188,6 +1190,7 @@ static int systemctl_main(int argc, char *argv[]) {
{ "reboot", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
{ "kexec", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
{ "soft-reboot", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
+ { "sleep", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
{ "suspend", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
{ "hibernate", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
{ "hybrid-sleep", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special },
@@ -1332,6 +1335,7 @@ static int run(int argc, char *argv[]) {
break;
case ACTION_EXIT:
+ case ACTION_SLEEP:
case ACTION_SUSPEND:
case ACTION_HIBERNATE:
case ACTION_HYBRID_SLEEP:
diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h
index 9f63443fde..17dcfb4048 100644
--- a/src/systemctl/systemctl.h
+++ b/src/systemctl/systemctl.h
@@ -18,6 +18,7 @@ enum action {
ACTION_KEXEC,
ACTION_SOFT_REBOOT,
ACTION_EXIT,
+ ACTION_SLEEP,
ACTION_SUSPEND,
ACTION_HIBERNATE,
ACTION_HYBRID_SLEEP,