}
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *host_basename = NULL, *container_basename = NULL;
const char *src, *dest, *host_path, *container_path;
- _cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS;
- _cleanup_close_ int hostfd = -EBADF;
Machine *m = ASSERT_PTR(userdata);
+ Manager *manager = m->manager;
bool copy_from;
- pid_t child;
- uid_t uid_shift;
int r;
assert(message);
message,
"org.freedesktop.machine1.manage-machines",
details,
- &m->manager->polkit_registry,
+ &manager->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* Will call us back */
- r = machine_get_uid_shift(m, &uid_shift);
- if (r < 0)
- return r;
-
copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
if (copy_from) {
container_path = dest;
}
- r = path_extract_filename(host_path, &host_basename);
+ Operation *op;
+ r = machine_copy_from_to(manager, m, host_path, container_path, copy_from, copy_flags, &op);
if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed to extract file name of '%s' path: %m", host_path);
-
- r = path_extract_filename(container_path, &container_basename);
- if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed to extract file name of '%s' path: %m", container_path);
-
- hostfd = open_parent(host_path, O_CLOEXEC, 0);
- if (hostfd < 0)
- return sd_bus_error_set_errnof(error, hostfd, "Failed to open host directory %s: %m", host_path);
-
- if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
-
- r = safe_fork("(sd-copy)", FORK_RESET_SIGNALS, &child);
- if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
- if (r == 0) {
- int containerfd;
- const char *q;
- int mntfd;
-
- errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
-
- q = procfs_file_alloca(m->leader.pid, "ns/mnt");
- mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
- if (mntfd < 0) {
- r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
- goto child_fail;
- }
-
- if (setns(mntfd, CLONE_NEWNS) < 0) {
- r = log_error_errno(errno, "Failed to join namespace of leader: %m");
- goto child_fail;
- }
-
- containerfd = open_parent(container_path, O_CLOEXEC, 0);
- if (containerfd < 0) {
- r = log_error_errno(containerfd, "Failed to open destination directory: %m");
- goto child_fail;
- }
-
- /* 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)
- r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags, NULL, NULL);
- else
- r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags, NULL, NULL);
-
- hostfd = safe_close(hostfd);
- containerfd = safe_close(containerfd);
-
- if (r < 0) {
- r = log_error_errno(r, "Failed to copy tree: %m");
- goto child_fail;
- }
-
- _exit(EXIT_SUCCESS);
-
- child_fail:
- (void) write(errno_pipe_fd[1], &r, sizeof(r));
- _exit(EXIT_FAILURE);
- }
-
- errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
-
- /* Copying might take a while, hence install a watch on the child, and return */
-
- r = operation_new_with_bus_reply(m->manager, m, child, message, errno_pipe_fd[0], /* ret= */ NULL);
- if (r < 0) {
- (void) sigkill_wait(child);
- return r;
- }
- errno_pipe_fd[0] = -EBADF;
+ return sd_bus_error_set_errnof(error, r, "Failed to copy from/to machine '%s': %m", m->name);
+ operation_attach_bus_reply(op, message);
return 1;
}