machine: introduce machine_copy_from_to() helper

This commit is contained in:
Ivan Kruglov
2025-01-06 14:51:57 +01:00
parent 347a1105a4
commit 9af9d66184
2 changed files with 130 additions and 0 deletions
+120
View File
@@ -24,6 +24,7 @@
#include "machine-dbus.h"
#include "machine.h"
#include "mkdir-label.h"
#include "namespace-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
@@ -978,6 +979,125 @@ char** machine_default_shell_args(const char *user) {
return TAKE_PTR(args);
}
int machine_copy_from_to(
Manager *manager,
Machine *machine,
const char *host_path,
const char *container_path,
bool copy_from_container,
CopyFlags copy_flags,
Operation **ret) {
_cleanup_close_ int host_fd = -EBADF, mntns_fd = -EBADF;
_cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
_cleanup_free_ char *host_basename = NULL, *container_basename = NULL;
uid_t uid_shift;
pid_t child;
int r;
assert(manager);
assert(machine);
assert(ret);
if (isempty(host_path) || isempty(container_path))
return -EINVAL;
r = path_extract_filename(host_path, &host_basename);
if (r < 0)
return log_debug_errno(r, "Failed to extract file name of '%s' path: %m", host_path);
r = path_extract_filename(container_path, &container_basename);
if (r < 0)
return log_debug_errno(r, "Failed to extract file name of '%s' path: %m", container_path);
host_fd = open_parent(host_path, O_CLOEXEC, 0);
if (host_fd < 0)
return log_debug_errno(host_fd, "Failed to open host directory '%s': %m", host_path);
r = machine_get_uid_shift(machine, &uid_shift);
if (r < 0)
return log_debug_errno(r, "Failed to get UID shift of machine '%s': %m", machine->name);
r = pidref_namespace_open(&machine->leader,
/* ret_pidns_fd = */ NULL,
&mntns_fd,
/* ret_netns_fd = */ NULL,
/* ret_userns_fd = */ NULL,
/* ret_root_fd = */ NULL);
if (r < 0)
return log_debug_errno(r, "Failed to open mount namespace of machine '%s': %m", machine->name);
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return log_debug_errno(errno, "Failed to create pipe: %m");
r = namespace_fork("(sd-copyns)",
"(sd-copy)",
/* except_fds = */ NULL,
/* n_except_fds = */ 0,
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL,
/* pidns_fd = */ -EBADF,
mntns_fd,
/* netns_fd = */ -EBADF,
/* userns_fd = */ -EBADF,
/* root_fd = */ -EBADF,
&child);
if (r < 0)
return log_debug_errno(r, "Failed to fork into mount namespace of machine '%s': %m", machine->name);
if (r == 0) {
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
_cleanup_close_ int container_fd = -EBADF;
container_fd = open_parent(container_path, O_CLOEXEC, 0);
if (container_fd < 0) {
log_debug_errno(container_fd, "Failed to open destination directory: %m");
report_errno_and_exit(errno_pipe_fd[1], container_fd);
}
/* Run the actual copy operation. Note that when a UID shift is set we'll either clamp the UID/GID to
* 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
* the UID/GIDs as they are. */
if (copy_from_container)
r = copy_tree_at(
container_fd,
container_basename,
host_fd,
host_basename,
uid_shift == 0 ? UID_INVALID : 0,
uid_shift == 0 ? GID_INVALID : 0,
copy_flags,
/* denylist = */ NULL,
/* subvolumes = */ NULL);
else
r = copy_tree_at(
host_fd,
host_basename,
container_fd,
container_basename,
uid_shift == 0 ? UID_INVALID : uid_shift,
uid_shift == 0 ? GID_INVALID : uid_shift,
copy_flags,
/* denylist = */ NULL,
/* subvolumes = */ NULL);
if (r < 0)
log_debug_errno(r, "Failed to copy tree: %m");
report_errno_and_exit(errno_pipe_fd[1], r);
}
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
Operation *operation;
r = operation_new(manager, machine, child, errno_pipe_fd[0], &operation);
if (r < 0) {
sigkill_wait(child);
return r;
}
TAKE_FD(errno_pipe_fd[0]);
*ret = operation;
return 0;
}
void machine_release_unit(Machine *m) {
assert(m);
+10
View File
@@ -4,6 +4,7 @@
typedef struct Machine Machine;
typedef enum KillWhom KillWhom;
#include "copy.h"
#include "list.h"
#include "machined.h"
#include "operation.h"
@@ -107,6 +108,15 @@ int machine_start_shell(Machine *m, int ptmx_fd, const char *ptmx_name, const ch
#define machine_default_shell_path() ("/bin/sh")
char** machine_default_shell_args(const char *user);
int machine_copy_from_to(
Manager *manager,
Machine *machine,
const char *host_path,
const char *container_path,
bool copy_from_container,
CopyFlags copy_flags,
Operation **ret);
int machine_get_uid_shift(Machine *m, uid_t *ret);
int machine_owns_uid(Machine *m, uid_t host_uid, uid_t *ret_internal_uid);