diff options
author | Ivan Kruglov <mail@ikruglov.com> | 2024-09-25 14:17:38 +0200 |
---|---|---|
committer | Ivan Kruglov <mail@ikruglov.com> | 2024-10-01 19:00:25 +0200 |
commit | 31f9f589a83508b576412eb32dfeacfe224ab573 (patch) | |
tree | f2b31fc33eea9995bdc81e9bbc27fe3e1fcab39e /src | |
parent | machine: generalise logic GetMachineAddresses to later use it in varlink inte... (diff) | |
download | systemd-31f9f589a83508b576412eb32dfeacfe224ab573.tar.xz systemd-31f9f589a83508b576412eb32dfeacfe224ab573.zip |
machine: generalise logic GetOSRelease to later use it in varlink interface
Diffstat (limited to 'src')
-rw-r--r-- | src/machine/machine-dbus.c | 81 | ||||
-rw-r--r-- | src/machine/machined-core.c | 104 | ||||
-rw-r--r-- | src/machine/machined.h | 1 |
3 files changed, 111 insertions, 75 deletions
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index a8c376dee9..85cb00a8a6 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -236,8 +236,6 @@ int bus_machine_method_get_ssh_info(sd_bus_message *message, void *userdata, sd_ return sd_bus_send(NULL, reply, NULL); } -#define EXIT_NOT_FOUND 2 - int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_strv_free_ char **l = NULL; Machine *m = ASSERT_PTR(userdata); @@ -245,80 +243,13 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s assert(message); - switch (m->class) { - - case MACHINE_HOST: - r = load_os_release_pairs(NULL, &l); - if (r < 0) - return r; - - break; - - case MACHINE_CONTAINER: { - _cleanup_close_ int mntns_fd = -EBADF, root_fd = -EBADF, pidns_fd = -EBADF; - _cleanup_close_pair_ int pair[2] = EBADF_PAIR; - _cleanup_fclose_ FILE *f = NULL; - pid_t child; - - r = pidref_namespace_open(&m->leader, - &pidns_fd, - &mntns_fd, - /* ret_netns_fd = */ NULL, - /* ret_userns_fd = */ NULL, - &root_fd); - if (r < 0) - return r; - - if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) - return -errno; - - r = namespace_fork("(sd-osrelns)", "(sd-osrel)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, - pidns_fd, mntns_fd, -1, -1, root_fd, - &child); - if (r < 0) - return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); - if (r == 0) { - int fd = -EBADF; - - pair[0] = safe_close(pair[0]); - - r = open_os_release(NULL, NULL, &fd); - if (r == -ENOENT) - _exit(EXIT_NOT_FOUND); - if (r < 0) - _exit(EXIT_FAILURE); - - r = copy_bytes(fd, pair[1], UINT64_MAX, 0); - if (r < 0) - _exit(EXIT_FAILURE); - - _exit(EXIT_SUCCESS); - } - - pair[1] = safe_close(pair[1]); - - f = take_fdopen(&pair[0], "r"); - if (!f) - return -errno; - - r = load_env_file_pairs(f, "/etc/os-release", &l); - if (r < 0) - return r; - - r = wait_for_terminate_and_check("(sd-osrelns)", child, 0); - if (r < 0) - return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); - if (r == EXIT_NOT_FOUND) - return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Machine does not contain OS release information"); - if (r != EXIT_SUCCESS) - return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Child died abnormally."); - - break; - } - - default: + r = machine_get_os_release(m, &l); + if (r == -ENONET) + return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Machine does not contain OS release information."); + if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines."); - } + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to get OS release: %m"); return bus_reply_pair_array(message, l); } diff --git a/src/machine/machined-core.c b/src/machine/machined-core.c index df6e437835..0045f75b0c 100644 --- a/src/machine/machined-core.c +++ b/src/machine/machined-core.c @@ -1,7 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "cgroup-util.h" +#include "copy.h" +#include "env-file.h" #include "fd-util.h" +#include "fileio.h" #include "iovec-util.h" #include "machined.h" #include "process-util.h" @@ -299,3 +302,104 @@ int machine_get_addresses(Machine* machine, struct local_address **ret_addresses return -EOPNOTSUPP; } } + +#define EXIT_NOT_FOUND 2 + +int machine_get_os_release(Machine *machine, char ***ret_os_release) { + _cleanup_strv_free_ char **l = NULL; + int r; + + assert(machine); + assert(ret_os_release); + + switch (machine->class) { + + case MACHINE_HOST: + r = load_os_release_pairs(/* root = */ NULL, &l); + if (r < 0) + return log_debug_errno(r, "Failed to load OS release information: %m"); + + break; + + case MACHINE_CONTAINER: { + _cleanup_close_ int mntns_fd = -EBADF, root_fd = -EBADF, pidns_fd = -EBADF; + _cleanup_close_pair_ int pair[2] = EBADF_PAIR; + _cleanup_fclose_ FILE *f = NULL; + pid_t child; + + r = pidref_namespace_open(&machine->leader, + &pidns_fd, + &mntns_fd, + /* ret_netns_fd = */ NULL, + /* ret_userns_fd = */ NULL, + &root_fd); + if (r < 0) + return log_debug_errno(r, "Failed to open namespace: %m"); + + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) + return log_debug_errno(errno, "Failed to call socketpair(): %m"); + + r = namespace_fork("(sd-osrelns)", + "(sd-osrel)", + /* except_fds = */ NULL, + /* n_except_fds = */ 0, + FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, + pidns_fd, + mntns_fd, + /* netns_fd = */ -1, + /* userns_fd = */ -1, + root_fd, + &child); + if (r < 0) + return log_debug_errno(r, "Failed to fork(): %m"); + if (r == 0) { + _cleanup_close_ int fd = -EBADF; + + pair[0] = safe_close(pair[0]); + + r = open_os_release(/* root = */ NULL, /* ret_path = */ NULL, &fd); + if (r == -ENOENT) + _exit(EXIT_NOT_FOUND); + if (r < 0) { + log_debug_errno(r, "Failed to read OS release: %m"); + _exit(EXIT_FAILURE); + } + + r = copy_bytes(fd, pair[1], UINT64_MAX, /* copy_flags = */ 0); + if (r < 0) { + log_debug_errno(r, "Failed to write to fd: %m"); + _exit(EXIT_FAILURE); + } + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + f = take_fdopen(&pair[0], "r"); + if (!f) + return log_debug_errno(errno, "Failed to fdopen(): %m"); + + r = load_env_file_pairs(f, "/etc/os-release", &l); + if (r < 0) + return log_debug_errno(r, "Failed to load OS release information: %m"); + + r = wait_for_terminate_and_check("(sd-osrelns)", child, /* flags = */ 0); + if (r < 0) + return log_debug_errno(r, "Failed to wait for child: %m"); + if (r == EXIT_NOT_FOUND) + return -ENOENT; + if (r != EXIT_SUCCESS) + return log_debug_errno(SYNTHETIC_ERRNO(ESHUTDOWN), "Child died abnormally"); + + break; + } + + default: + return -EOPNOTSUPP; + } + + + *ret_os_release = TAKE_PTR(l); + return 0; +} diff --git a/src/machine/machined.h b/src/machine/machined.h index f1d0d157c8..4a718f9462 100644 --- a/src/machine/machined.h +++ b/src/machine/machined.h @@ -66,3 +66,4 @@ void manager_gc(Manager *m, bool drop_not_started); void manager_enqueue_gc(Manager *m); int machine_get_addresses(Machine* machine, struct local_address **ret_addresses); +int machine_get_os_release(Machine *machine, char ***ret_os_release); |