X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fmachine%2Fmachinectl.c;h=c1cc5e7eb53029e1f5eb738b792c23ececa42ae3;hp=071b2b9ebf59cd5a6bae5923e62cfa7424dff3e0;hb=90adaa25e894a580930ef2c3e65ab8db8295515a;hpb=cc98b3025eeb89addb76a27390cb2baca4eab8b9 diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 071b2b9eb..c1cc5e7eb 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -31,8 +31,13 @@ #include #include #include + +/* When we include libgen.h because we need dirname() we immediately + * undefine basename() since libgen.h defines it as a macro to the XDG + * version which is really broken. */ #include #undef basename + #include "sd-bus.h" #include "log.h" #include "util.h" @@ -896,14 +901,14 @@ static int show_image(int argc, char *argv[], void *userdata) { const char *path = NULL; r = sd_bus_call_method( - bus, - "org.freedesktop.machine1", - "/org/freedesktop/machine1", - "org.freedesktop.machine1.Manager", - "GetImage", - &error, - &reply, - "s", argv[i]); + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "GetImage", + &error, + &reply, + "s", argv[i]); if (r < 0) { log_error("Could not get path to image: %s", bus_error_message(&error, -r)); return r; @@ -925,7 +930,7 @@ static int show_image(int argc, char *argv[], void *userdata) { static int kill_machine(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; - int i; + int r, i; assert(bus); @@ -935,8 +940,6 @@ static int kill_machine(int argc, char *argv[], void *userdata) { arg_kill_who = "all"; for (i = 1; i < argc; i++) { - int r; - r = sd_bus_call_method( bus, "org.freedesktop.machine1", @@ -1138,187 +1141,32 @@ static int copy_files(int argc, char *argv[], void *userdata) { } static int bind_mount(int argc, char *argv[], void *userdata) { - char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; - pid_t child, leader; - const char *dest; - siginfo_t si; - bool mount_slave_created = false, mount_slave_mounted = false, - mount_tmp_created = false, mount_tmp_mounted = false, - mount_outside_created = false, mount_outside_mounted = false; int r; assert(bus); - /* One day, when bind mounting /proc/self/fd/n works across - * namespace boundaries we should rework this logic to make - * use of it... */ - - dest = argv[3] ?: argv[2]; - if (!path_is_absolute(dest)) { - log_error("Destination path not absolute."); - return -EINVAL; - } - - p = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/"); - if (access(p, F_OK) < 0) { - log_error("Container does not allow propagation of mount points."); - return -ENOTSUP; - } - - r = machine_get_leader(bus, argv[1], &leader); - if (r < 0) - return r; - - /* Our goal is to install a new bind mount into the container, - possibly read-only. This is irritatingly complex - unfortunately, currently. - - First, we start by creating a private playground in /tmp, - that we can mount MS_SLAVE. (Which is necessary, since - MS_MOUNT cannot be applied to mounts with MS_SHARED parent - mounts.) */ - - if (!mkdtemp(mount_slave)) - return log_error_errno(errno, "Failed to create playground: %m"); - - mount_slave_created = true; - - if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) { - r = log_error_errno(errno, "Failed to make bind mount: %m"); - goto finish; - } - - mount_slave_mounted = true; - - if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) { - r = log_error_errno(errno, "Failed to remount slave: %m"); - goto finish; - } - - /* Second, we mount the source directory to a directory inside - of our MS_SLAVE playground. */ - mount_tmp = strappenda(mount_slave, "/mount"); - if (mkdir(mount_tmp, 0700) < 0) { - r = log_error_errno(errno, "Failed to create temporary mount: %m"); - goto finish; - } - - mount_tmp_created = true; - - if (mount(argv[2], mount_tmp, NULL, MS_BIND, NULL) < 0) { - r = log_error_errno(errno, "Failed to overmount: %m"); - goto finish; - } - - mount_tmp_mounted = true; - - /* Third, we remount the new bind mount read-only if requested. */ - if (arg_read_only) - if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) { - r = log_error_errno(errno, "Failed to mark read-only: %m"); - goto finish; - } - - /* Fourth, we move the new bind mount into the propagation - * directory. This way it will appear there read-only - * right-away. */ - - mount_outside = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/XXXXXX"); - if (!mkdtemp(mount_outside)) { - r = log_error_errno(errno, "Cannot create propagation directory: %m"); - goto finish; - } - - mount_outside_created = true; - - if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) { - r = log_error_errno(errno, "Failed to move: %m"); - goto finish; - } - - mount_outside_mounted = true; - mount_tmp_mounted = false; - - (void) rmdir(mount_tmp); - mount_tmp_created = false; - - (void) umount(mount_slave); - mount_slave_mounted = false; - - (void) rmdir(mount_slave); - mount_slave_created = false; - - child = fork(); - if (child < 0) { - r = log_error_errno(errno, "Failed to fork(): %m"); - goto finish; - } - - if (child == 0) { - const char *mount_inside; - int mntfd; - const char *q; - - q = procfs_file_alloca(leader, "ns/mnt"); - mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (mntfd < 0) { - log_error_errno(errno, "Failed to open mount namespace of leader: %m"); - _exit(EXIT_FAILURE); - } - - if (setns(mntfd, CLONE_NEWNS) < 0) { - log_error_errno(errno, "Failed to join namespace of leader: %m"); - _exit(EXIT_FAILURE); - } - - if (arg_mkdir) - mkdir_p(dest, 0755); - - /* Fifth, move the mount to the right place inside */ - mount_inside = strappenda("/run/systemd/nspawn/incoming/", basename(mount_outside)); - if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) { - log_error_errno(errno, "Failed to mount: %m"); - _exit(EXIT_FAILURE); - } - - _exit(EXIT_SUCCESS); - } - - r = wait_for_terminate(child, &si); + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "BindMountMachine", + &error, + NULL, + "sssbb", + argv[1], + argv[2], + argv[3], + arg_read_only, + arg_mkdir); if (r < 0) { - log_error_errno(r, "Failed to wait for client: %m"); - goto finish; - } - if (si.si_code != CLD_EXITED) { - log_error("Client died abnormally."); - r = -EIO; - goto finish; - } - if (si.si_status != EXIT_SUCCESS) { - r = -EIO; - goto finish; + log_error("Failed to bind mount: %s", bus_error_message(&error, -r)); + return r; } - r = 0; - -finish: - if (mount_outside_mounted) - umount(mount_outside); - if (mount_outside_created) - rmdir(mount_outside); - - if (mount_tmp_mounted) - umount(mount_tmp); - if (mount_tmp_created) - umount(mount_tmp); - - if (mount_slave_mounted) - umount(mount_slave); - if (mount_slave_created) - umount(mount_slave); - - return r; + return 0; } static int on_machine_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { @@ -1376,7 +1224,7 @@ static int login_machine(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop: %m"); - match = strappenda("type='signal'," + match = strjoina("type='signal'," "sender='org.freedesktop.machine1'," "path='/org/freedesktop/machine1',", "interface='org.freedesktop.machine1.Manager'," @@ -1995,7 +1843,6 @@ static int pull_raw(int argc, char *argv[], void *userdata) { static int pull_dkr(int argc, char *argv[], void *userdata) { _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_free_ char *l = NULL, *ll = NULL; const char *local, *remote, *tag; sd_bus *bus = userdata; int r;