diff options
author | Mike Yuan <me@yhndnzj.com> | 2023-11-25 15:10:16 +0100 |
---|---|---|
committer | Luca Boccassi <luca.boccassi@gmail.com> | 2023-12-06 22:15:38 +0100 |
commit | fb45185d98a7cd559553c35f415d358345a3fd08 (patch) | |
tree | 5c9e4f3f5ff02581200cdeb74d50ef860c1d207e /src/systemctl/systemctl-whoami.c | |
parent | Merge pull request #30101 from poettering/underline-rework (diff) | |
download | systemd-fb45185d98a7cd559553c35f415d358345a3fd08.tar.xz systemd-fb45185d98a7cd559553c35f415d358345a3fd08.zip |
systemctl-whoami: use pidfd to refer to processes
While at it, rephrase the output a bit. Before this commit, if
the pid doesn't exist, we output something hard to interpret -
"Failed to get unit for ourselves".
Diffstat (limited to '')
-rw-r--r-- | src/systemctl/systemctl-whoami.c | 164 |
1 files changed, 134 insertions, 30 deletions
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; } |