#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"
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);