machine: use machine_copy_from_to() in dbus implementation

This commit is contained in:
Ivan Kruglov
2024-12-17 12:53:28 +01:00
parent 9af9d66184
commit 8632e7ae23

View File

@@ -492,15 +492,11 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
}
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);
@@ -549,17 +545,13 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
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) {
@@ -570,83 +562,12 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
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;
}