From 1bd979dddbb6ed3ffe410d78a7ff80cbb1c42a64 Mon Sep 17 00:00:00 2001 From: Ivan Kruglov Date: Mon, 7 Oct 2024 11:22:11 +0200 Subject: [PATCH] machine: io.systemd.Machine.List supports 'pid' filter --- src/machine/machine-varlink.c | 87 +++++++++++++++++++++++++ src/machine/machine-varlink.h | 16 +++++ src/machine/machined-varlink.c | 26 +++++--- src/shared/varlink-io.systemd.Machine.c | 4 +- 4 files changed, 123 insertions(+), 10 deletions(-) diff --git a/src/machine/machine-varlink.c b/src/machine/machine-varlink.c index fb64bde9205..37bcf266f79 100644 --- a/src/machine/machine-varlink.c +++ b/src/machine/machine-varlink.c @@ -188,3 +188,90 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink return sd_varlink_reply(link, NULL); } + +static int lookup_machine_by_name(sd_varlink *link, Manager *manager, const char *machine_name, Machine **ret_machine) { + assert(link); + assert(manager); + assert(ret_machine); + + if (!machine_name) + return -EINVAL; + + if (!hostname_is_valid(machine_name, /* flags= */ VALID_HOSTNAME_DOT_HOST)) + return -EINVAL; + + Machine *machine = hashmap_get(manager->machines, machine_name); + if (!machine) + return -ESRCH; + + *ret_machine = machine; + return 0; +} + +static int lookup_machine_by_pid(sd_varlink *link, Manager *manager, pid_t pid, Machine **ret_machine) { + Machine *machine; + int r; + + assert(link); + assert(manager); + assert(ret_machine); + assert_cc(sizeof(pid_t) == sizeof(uint32_t)); + + if (pid == 0) { + int pidfd = sd_varlink_get_peer_pidfd(link); + if (pidfd < 0) + return log_debug_errno(pidfd, "Failed to get peer pidfd: %m"); + + r = pidfd_get_pid(pidfd, &pid); + if (r < 0) + return log_debug_errno(r, "Failed to get pid from pidfd: %m"); + } + + if (pid <= 0) + return -EINVAL; + + r = manager_get_machine_by_pid(manager, pid, &machine); + if (r < 0) + return r; + if (!machine) + return -ESRCH; + + *ret_machine = machine; + return 0; +} + +int lookup_machine_by_name_or_pid(sd_varlink *link, Manager *manager, const char *machine_name, pid_t pid, Machine **ret_machine) { + Machine *machine = NULL, *pid_machine = NULL; + int r; + + assert(link); + assert(manager); + assert(ret_machine); + + if (machine_name) { + r = lookup_machine_by_name(link, manager, machine_name, &machine); + if (r == -EINVAL) + return sd_varlink_error_invalid_parameter_name(link, "name"); + if (r < 0) + return r; + } + + if (pid >= 0) { + r = lookup_machine_by_pid(link, manager, pid, &pid_machine); + if (r == -EINVAL) + return sd_varlink_error_invalid_parameter_name(link, "pid"); + if (r < 0) + return r; + } + + if (machine && pid_machine && machine != pid_machine) + return log_debug_errno(SYNTHETIC_ERRNO(ESRCH), "Search by machine name '%s' and pid %d resulted in two different machines", machine_name, pid); + else if (machine) + *ret_machine = machine; + else if (pid_machine) + *ret_machine = pid_machine; + else + return -ESRCH; + + return 0; +} diff --git a/src/machine/machine-varlink.h b/src/machine/machine-varlink.h index 3b5eb2c8f72..4ec68d52603 100644 --- a/src/machine/machine-varlink.h +++ b/src/machine/machine-varlink.h @@ -3,4 +3,20 @@ #include "sd-varlink.h" +#include "machine.h" + +#define VARLINK_DISPATCH_MACHINE_LOOKUP_FIELDS(t) { \ + .name = "name", \ + .type = SD_JSON_VARIANT_STRING, \ + .callback = sd_json_dispatch_const_string, \ + .offset = offsetof(t, machine_name) \ + }, { \ + .name = "pid", \ + .type = _SD_JSON_VARIANT_TYPE_INVALID, \ + .callback = sd_json_dispatch_uint32, \ + .offset = offsetof(t, pid) \ + } + +int lookup_machine_by_name_or_pid(sd_varlink *link, Manager *manager, const char *machine_name, pid_t pid, Machine **ret_machine); + int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata); diff --git a/src/machine/machined-varlink.c b/src/machine/machined-varlink.c index 942b0a96b3e..4189ff2cf24 100644 --- a/src/machine/machined-varlink.c +++ b/src/machine/machined-varlink.c @@ -2,6 +2,7 @@ #include "sd-varlink.h" +#include "bus-polkit.h" #include "format-util.h" #include "hostname-util.h" #include "json-util.h" @@ -415,29 +416,36 @@ static int list_machine_one(sd_varlink *link, Machine *m, bool more) { return sd_varlink_reply(link, v); } +typedef struct MachineLookupParameters { + const char *machine_name; + pid_t pid; +} MachineLookupParameters; + static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { static const sd_json_dispatch_field dispatch_table[] = { - { "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, 0 }, + VARLINK_DISPATCH_MACHINE_LOOKUP_FIELDS(MachineLookupParameters), + VARLINK_DISPATCH_POLKIT_FIELD, {} }; Manager *m = ASSERT_PTR(userdata); - const char *mn = NULL; + MachineLookupParameters p = { .pid = -1 }; + Machine *machine; int r; + assert(link); assert(parameters); - r = sd_varlink_dispatch(link, parameters, dispatch_table, &mn); + r = sd_varlink_dispatch(link, parameters, dispatch_table, &p); if (r != 0) return r; - if (mn) { - if (!hostname_is_valid(mn, /* flags= */ VALID_HOSTNAME_DOT_HOST)) - return sd_varlink_error_invalid_parameter_name(link, "name"); - - Machine *machine = hashmap_get(m->machines, mn); - if (!machine) + if (p.machine_name || p.pid >= 0) { + r = lookup_machine_by_name_or_pid(link, m, p.machine_name, p.pid, &machine); + if (r == -ESRCH) return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL); + if (r < 0) + return r; return list_machine_one(link, machine, /* more= */ false); } diff --git a/src/shared/varlink-io.systemd.Machine.c b/src/shared/varlink-io.systemd.Machine.c index 5841bf02ced..334e4c7d938 100644 --- a/src/shared/varlink-io.systemd.Machine.c +++ b/src/shared/varlink-io.systemd.Machine.c @@ -31,8 +31,10 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( static SD_VARLINK_DEFINE_METHOD_FULL( List, SD_VARLINK_SUPPORTS_MORE, - SD_VARLINK_FIELD_COMMENT("If non-null the name of a running machine to report details on. If null/unspecified enumerates all running machines."), + SD_VARLINK_FIELD_COMMENT("If non-null the name of a running machine to report details on. If both 'name' and 'pid' are null/unspecified enumerates all running machines."), SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("If non-null the PID of a running machine to report details on."), + SD_VARLINK_DEFINE_INPUT(pid, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Name of the machine"), SD_VARLINK_DEFINE_OUTPUT(name, SD_VARLINK_STRING, 0), SD_VARLINK_FIELD_COMMENT("128bit ID identifying this machine, formatted in hexadecimal"), -- 2.47.3