machine: introduce machine_copy_from_to() helper
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user