mirror of
https://github.com/systemd/systemd.git
synced 2025-03-19 22:50:17 +03:00
systemctl: generalize GetUnitByPIDFD handling
This commit is contained in:
parent
d9219935ab
commit
716a4cdb0e
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
STRV_FOREACH(pid, strv_skip(argv, 1))
|
||||
RET_GATHER(r, lookup_pid(bus, *pid));
|
||||
r = parse_pid(*pidstr, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Invalid PID specified: %s", *pidstr);
|
||||
|
||||
return r;
|
||||
r = lookup_unit_by_pidref(bus, pid, &unit, /* ret_path = */ NULL);
|
||||
if (r < 0)
|
||||
RET_GATHER(ret, r);
|
||||
else
|
||||
puts(unit);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user