]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemctl: generalize GetUnitByPIDFD handling
authorMike Yuan <me@yhndnzj.com>
Sat, 24 Feb 2024 01:01:22 +0000 (09:01 +0800)
committerMike Yuan <me@yhndnzj.com>
Sat, 24 Feb 2024 04:24:41 +0000 (12:24 +0800)
src/systemctl/systemctl-util.c
src/systemctl/systemctl-util.h
src/systemctl/systemctl-whoami.c

index 2dc92ce283e08823151a12eaeb1cf0955b34b330..c3da750d641d2aaad48b2ce7ef57ea148da2b620 100644 (file)
@@ -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;
+}
index 17975e110d3adaf0235dd960bc4aa234665914d5..a950dde51552beb3897076f8366db17a92105403 100644 (file)
@@ -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);
index bac72c897397a9900a96949bf413d737fb44703f..607f2db047956710fbe89164248a7db7c875dd03 100644 (file)
 /* 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;
 }