machine-dbus.c revision d84401767785a8380700d5d9c805c36f5fc63980
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt This file is part of systemd.
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt Copyright 2011 Lennart Poettering
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt systemd is free software; you can redistribute it and/or modify it
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt under the terms of the GNU Lesser General Public License as published by
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt the Free Software Foundation; either version 2.1 of the License, or
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt (at your option) any later version.
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt systemd is distributed in the hope that it will be useful, but
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt WITHOUT ANY WARRANTY; without even the implied warranty of
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt Lesser General Public License for more details.
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt You should have received a copy of the GNU Lesser General Public License
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt along with systemd; If not, see <http://www.gnu.org/licenses/>.
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt/* When we include libgen.h because we need dirname() we immediately
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * undefine basename() since libgen.h defines it as a macro to the POSIX
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * version which is really broken. We prefer GNU basename(). */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_message_append_array(reply, 'y', &m->id, 16);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt state = machine_state_to_string(machine_get_state(m));
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_message_append_basic(reply, 's', state);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtstatic BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtint bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt "org.freedesktop.machine1.manage-machines",
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_reply_method_return(message, NULL);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtint bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_message_read(message, "si", &swho, &signo);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt "org.freedesktop.machine1.manage-machines",
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return sd_bus_reply_method_return(message, NULL);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidtint bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt _cleanup_close_pair_ int pair[2] = { -1, -1 };
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt _cleanup_free_ char *us = NULL, *them = NULL;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt const char *p;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = readlink_malloc("/proc/self/ns/net", &us);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt _cleanup_free_ struct local_address *addresses = NULL;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt for (a = addresses, i = 0; i < n; a++, i++) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt { .iov_base = &a->family, .iov_len = sizeof(a->family) },
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
435fc3176520a58f1c20ccb983c9fb40b30a1471Martin Pitt r = sd_bus_message_new_method_return(message, &reply);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_message_open_container(reply, 'a', "(iay)");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_message_open_container(reply, 'r', "iay");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_message_append(reply, "i", family);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (n != sizeof(struct in_addr) + sizeof(family))
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (n != sizeof(struct in6_addr) + sizeof(family))
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidtint bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt _cleanup_close_ int mntns_fd = -1, root_fd = -1;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt _cleanup_close_pair_ int pair[2] = { -1, -1 };
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt char **k, **v;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = namespace_enter(-1, mntns_fd, -1, root_fd);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = copy_bytes(fd, pair[1], (off_t) -1, false);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_message_new_method_return(message, &reply);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_message_open_container(reply, 'a', "{ss}");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_message_append(reply, "{ss}", *k, *v);
e1323fbfbe8a574f28b704f2df8ce7f99e3a28f5Michal Schmidtint bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
e1323fbfbe8a574f28b704f2df8ce7f99e3a28f5Michal Schmidt _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
e1323fbfbe8a574f28b704f2df8ce7f99e3a28f5Michal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening pseudo TTYs is only supported on container machines.");
e1323fbfbe8a574f28b704f2df8ce7f99e3a28f5Michal Schmidt master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_message_new_method_return(message, &reply);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_message_append(reply, "hs", master, pty_name);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtint bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt _cleanup_free_ char *pty_name = NULL, *getty = NULL;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt _cleanup_bus_unref_ sd_bus *container_bus = NULL;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt const char *p;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening logins is only supported on container machines.");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt "org.freedesktop.machine1.login",
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt# define ADDRESS_FMT "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (asprintf(&address, ADDRESS_FMT, m->leader) < 0)
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt getty = strjoin("container-getty@", p, ".service", NULL);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt "org.freedesktop.systemd1.Manager",
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_message_new_method_return(message, &reply);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_message_append(reply, "hs", master, pty_name);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtint bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt bool mount_slave_created = false, mount_slave_mounted = false,
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt mount_tmp_created = false, mount_tmp_mounted = false,
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt mount_outside_created = false, mount_outside_mounted = false;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (!path_is_absolute(src) || !path_is_safe(src))
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt else if (!path_is_absolute(dest) || !path_is_safe(dest))
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt "org.freedesktop.machine1.manage-machines",
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* One day, when bind mounting /proc/self/fd/n works across
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * namespace boundaries we should rework this logic to make
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * use of it... */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Our goal is to install a new bind mount into the container,
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt possibly read-only. This is irritatingly complex
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt unfortunately, currently.
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt First, we start by creating a private playground in /tmp,
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt that we can mount MS_SLAVE. (Which is necessary, since
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt MS_MOUNT cannot be applied to mounts with MS_SHARED parent
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Second, we mount the source directory to a directory inside
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt of our MS_SLAVE playground. */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_error_set_errnof(error, errno, "Failed to overmount %s: %m", mount_tmp);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Third, we remount the new bind mount read-only if requested. */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Fourth, we move the new bind mount into the propagation
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * directory. This way it will appear there read-only
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * right-away. */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt const char *q;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = log_error_errno(errno, "Failed to join namespace of leader: %m");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* Fifth, move the mount to the right place inside */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = log_error_errno(errno, "Failed to mount: %m");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt (void) write(errno_pipe_fd[1], &r, sizeof(r));
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
ce79279bff6e7a1a17070509a039ab635796f129Michal Schmidt r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client failed.");
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = sd_bus_reply_method_return(message, NULL);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtstatic int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_error_set_errnof(&error, r, "%m");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client failed.");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_reply_method_return(o->message, NULL);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt log_error_errno(r, "Failed to reply to message: %m");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_reply_method_error(o->message, &error);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt log_error_errno(r, "Failed to reply to message: %m");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtint bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (m->n_operations >= MACHINE_OPERATIONS_MAX)
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = sd_bus_message_read(message, "ss", &src, &dest);
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt "org.freedesktop.machine1.manage-machines",
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt container_basename = basename(container_path);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
if (child < 0)
if (child == 0) {
int containerfd;
int mntfd;
if (mntfd < 0) {
goto child_fail;
goto child_fail;
if (containerfd < 0) {
goto child_fail;
if (copy_from)
goto child_fail;
return log_oom();
r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
return log_oom();
m->n_operations++;
o->machine = m;
BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
assert(m);
if (!message)
e = bus_label_unescape(p);
return -ENOMEM;
if (!machine)
assert(m);
return NULL;
int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
Iterator i;
return -ENOMEM;
r = strv_consume(&l, p);
*nodes = l;
l = NULL;
assert(m);
p = machine_bus_path(m);
return -ENOMEM;
return sd_bus_emit_signal(
"/org/freedesktop/machine1",
assert(m);
if (!m->create_message)
c = m->create_message;
if (error)
machine_save(m);
p = machine_bus_path(m);
return -ENOMEM;