diff options
Diffstat (limited to 'src/systemctl')
-rw-r--r-- | src/systemctl/systemctl-list-units.c | 81 | ||||
-rw-r--r-- | src/systemctl/systemctl-logind.c | 5 | ||||
-rw-r--r-- | src/systemctl/systemctl-start-special.c | 3 | ||||
-rw-r--r-- | src/systemctl/systemctl-start-unit.c | 3 | ||||
-rw-r--r-- | src/systemctl/systemctl-whoami.c | 164 | ||||
-rw-r--r-- | src/systemctl/systemctl.c | 4 | ||||
-rw-r--r-- | src/systemctl/systemctl.h | 1 |
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, |