diff options
author | Mike Yuan <me@yhndnzj.com> | 2024-02-24 02:01:22 +0100 |
---|---|---|
committer | Mike Yuan <me@yhndnzj.com> | 2024-02-24 05:24:41 +0100 |
commit | 716a4cdb0e098ebfed366b59c093d5d29e2f54e0 (patch) | |
tree | b482bae069da8e54cba8b424ec36b00f681dd472 | |
parent | systemctl-util: use strv_free_and_replace at one more place (diff) | |
download | systemd-716a4cdb0e098ebfed366b59c093d5d29e2f54e0.tar.xz systemd-716a4cdb0e098ebfed366b59c093d5d29e2f54e0.zip |
systemctl: generalize GetUnitByPIDFD handling
-rw-r--r-- | src/systemctl/systemctl-util.c | 148 | ||||
-rw-r--r-- | src/systemctl/systemctl-util.h | 3 | ||||
-rw-r--r-- | src/systemctl/systemctl-whoami.c | 162 |
3 files changed, 170 insertions, 143 deletions
diff --git a/src/systemctl/systemctl-util.c b/src/systemctl/systemctl-util.c index 2dc92ce283..c3da750d64 100644 --- a/src/systemctl/systemctl-util.c +++ b/src/systemctl/systemctl-util.c @@ -18,6 +18,8 @@ #include "glob-util.h" #include "macro.h" #include "path-util.h" +#include "pidref.h" +#include "process-util.h" #include "reboot-util.h" #include "set.h" #include "spawn-ask-password-agent.h" @@ -985,3 +987,149 @@ int halt_now(enum action a) { assert_not_reached(); } } + +int get_unit_by_pid(sd_bus *bus, pid_t pid, char **ret_unit, char **ret_path) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + int r; + + assert(bus); + assert(pid >= 0); /* 0 is accepted by GetUnitByPID for querying our own process. */ + + r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", (uint32_t) pid); + 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)); + } + + _cleanup_free_ char *u = NULL, *p = NULL; + const char *path; + + r = sd_bus_message_read_basic(reply, 'o', &path); + if (r < 0) + return bus_log_parse_error(r); + + if (ret_unit) { + r = unit_name_from_dbus_path(path, &u); + if (r < 0) + return log_error_errno(r, + "Failed to extract unit name from D-Bus object path '%s': %m", + path); + } + + if (ret_path) { + p = strdup(path); + if (!p) + return log_oom(); + } + + if (ret_unit) + *ret_unit = TAKE_PTR(u); + if (ret_path) + *ret_path = TAKE_PTR(p); + + return 0; +} + +static int get_unit_by_pidfd(sd_bus *bus, const PidRef *pid, char **ret_unit, char **ret_path) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + int r; + + assert(bus); + assert(pidref_is_set(pid)); + + 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)); + } + + _cleanup_free_ char *u = NULL, *p = NULL; + const char *path, *unit; + + r = sd_bus_message_read(reply, "os", &path, &unit); + if (r < 0) + return bus_log_parse_error(r); + + if (ret_unit) { + u = strdup(unit); + if (!u) + return log_oom(); + } + + if (ret_path) { + p = strdup(path); + if (!p) + return log_oom(); + } + + if (ret_unit) + *ret_unit = TAKE_PTR(u); + if (ret_path) + *ret_path = TAKE_PTR(p); + + return 0; +} + +int lookup_unit_by_pidref(sd_bus *bus, pid_t pid, char **ret_unit, char **ret_path) { + int r; + + assert(bus); + assert(pid >= 0); /* 0 means our own process */ + + if (arg_transport != BUS_TRANSPORT_LOCAL) + return get_unit_by_pid(bus, pid, ret_unit, ret_path); + + static bool use_pidfd = true; + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + + r = pidref_set_pid(&pidref, pid); + if (r < 0) + return log_error_errno(r, + r == -ESRCH ? + "PID " PID_FMT " doesn't exist or is already gone." : + "Failed to create reference to PID " PID_FMT ": %m", + pid); + + if (use_pidfd) { + r = get_unit_by_pidfd(bus, &pidref, ret_unit, ret_path); + if (r != -EOPNOTSUPP) + return r; + + use_pidfd = false; + log_debug_errno(r, "Unable to look up process using pidfd, falling back to pid."); + } + + _cleanup_free_ char *u = NULL, *p = NULL; + + r = get_unit_by_pid(bus, pidref.pid, ret_unit ? &u : NULL, ret_path ? &p : NULL); + if (r < 0) + return r; + + r = pidref_verify(&pidref); + if (r < 0) + return log_error_errno(r, "Failed to verify our reference to PID " PID_FMT ": %m", pidref.pid); + + if (ret_unit) + *ret_unit = TAKE_PTR(u); + if (ret_path) + *ret_path = TAKE_PTR(p); + + return 0; +} diff --git a/src/systemctl/systemctl-util.h b/src/systemctl/systemctl-util.h index 17975e110d..a950dde515 100644 --- a/src/systemctl/systemctl-util.h +++ b/src/systemctl/systemctl-util.h @@ -58,3 +58,6 @@ int mangle_names(const char *operation, char * const *original_names, char ***re UnitFileFlags unit_file_flags_from_args(void); int halt_now(enum action a); + +int get_unit_by_pid(sd_bus *bus, pid_t pid, char **ret_unit, char **ret_path); +int lookup_unit_by_pidref(sd_bus *bus, pid_t pid, char **ret_unit, char **ret_path); diff --git a/src/systemctl/systemctl-whoami.c b/src/systemctl/systemctl-whoami.c index bac72c8973..607f2db047 100644 --- a/src/systemctl/systemctl-whoami.c +++ b/src/systemctl/systemctl-whoami.c @@ -1,149 +1,14 @@ /* 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" -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) { - 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_basic(reply, 'o', &path); - if (r < 0) - return bus_log_parse_error(r); - - r = unit_name_from_dbus_path(path, &unit); - if (r < 0) - return log_error_errno(r, "Failed to extract unit name from D-Bus object path '%s': %m", path); - - *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; -} - int verb_whoami(int argc, char *argv[], void *userdata) { sd_bus *bus; - int r; + int r, ret = 0; r = acquire_bus(BUS_FULL, &bus); if (r < 0) @@ -153,11 +18,12 @@ int verb_whoami(int argc, char *argv[], void *userdata) { _cleanup_free_ char *unit = NULL; if (arg_transport != BUS_TRANSPORT_LOCAL) - return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Refusing to look up our local PID on remote host."); + return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), + "Refusing to look up our local PID on remote host."); - /* Our own process can never go away while querying, hence no need to open pidfd. */ + /* Our own process can never go away while querying, hence no need to go through pidfd. */ - r = get_unit_by_pid(bus, 0, &unit); + r = get_unit_by_pid(bus, 0, &unit, /* ret_path = */ NULL); if (r < 0) return r; @@ -165,10 +31,20 @@ int verb_whoami(int argc, char *argv[], void *userdata) { return 0; } - r = 0; + STRV_FOREACH(pidstr, strv_skip(argv, 1)) { + _cleanup_free_ char *unit = NULL; + pid_t pid; + + r = parse_pid(*pidstr, &pid); + if (r < 0) + return log_error_errno(r, "Invalid PID specified: %s", *pidstr); - STRV_FOREACH(pid, strv_skip(argv, 1)) - RET_GATHER(r, lookup_pid(bus, *pid)); + r = lookup_unit_by_pidref(bus, pid, &unit, /* ret_path = */ NULL); + if (r < 0) + RET_GATHER(ret, r); + else + puts(unit); + } - return r; + return ret; } |