summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Yuan <me@yhndnzj.com>2024-02-24 02:01:22 +0100
committerMike Yuan <me@yhndnzj.com>2024-02-24 05:24:41 +0100
commit716a4cdb0e098ebfed366b59c093d5d29e2f54e0 (patch)
treeb482bae069da8e54cba8b424ec36b00f681dd472
parentsystemctl-util: use strv_free_and_replace at one more place (diff)
downloadsystemd-716a4cdb0e098ebfed366b59c093d5d29e2f54e0.tar.xz
systemd-716a4cdb0e098ebfed366b59c093d5d29e2f54e0.zip
systemctl: generalize GetUnitByPIDFD handling
-rw-r--r--src/systemctl/systemctl-util.c148
-rw-r--r--src/systemctl/systemctl-util.h3
-rw-r--r--src/systemctl/systemctl-whoami.c162
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;
}