X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fmachine%2Fmachinectl.c;h=61183a6bf852701546733ade0d20251235e1e698;hb=113b3fc1a8061f4a24dd0db74e9a3cd0083b2251;hp=5a42f26eaf1f4d584bc0840d445465f42c81ae9c;hpb=6adf7b5e46d32376868feef0197e6ada352aa6f2;p=elogind.git diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 5a42f26ea..61183a6bf 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -24,15 +24,13 @@ #include #include #include -#include #include #include #include #include #include #include -#include -#undef basename + #include "sd-bus.h" #include "log.h" #include "util.h" @@ -896,14 +894,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 +923,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 +933,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", @@ -972,15 +968,13 @@ static int poweroff_machine(int argc, char *argv[], void *userdata) { static int terminate_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); polkit_agent_open_if_enabled(); for (i = 1; i < argc; i++) { - int r; - r = sd_bus_call_method( bus, "org.freedesktop.machine1", @@ -999,326 +993,67 @@ static int terminate_machine(int argc, char *argv[], void *userdata) { return 0; } -static int machine_get_leader(sd_bus *bus, const char *name, pid_t *ret) { +static int copy_files(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL; - const char *object; - uint32_t leader; + sd_bus *bus = userdata; + bool copy_from; int r; assert(bus); - assert(name); - assert(ret); + + polkit_agent_open_if_enabled(); + + copy_from = streq(argv[0], "copy-from"); r = sd_bus_call_method( bus, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", - "GetMachine", + copy_from ? "CopyFromMachine" : "CopyToMachine", &error, - &reply, - "s", name); + NULL, + "sss", + argv[1], + argv[2], + argv[3]); if (r < 0) { - log_error("Could not get path to machine: %s", bus_error_message(&error, -r)); + log_error("Failed to copy: %s", bus_error_message(&error, -r)); return r; } - r = sd_bus_message_read(reply, "o", &object); - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_get_property( - bus, - "org.freedesktop.machine1", - object, - "org.freedesktop.machine1.Machine", - "Leader", - &error, - &reply2, - "u"); - if (r < 0) - return log_error_errno(r, "Failed to retrieve PID of leader: %m"); - - r = sd_bus_message_read(reply2, "u", &leader); - if (r < 0) - return bus_log_parse_error(r); - - *ret = leader; - return 0; -} - -static int copy_files(int argc, char *argv[], void *userdata) { - char *dest, *host_path, *container_path, *host_dirname, *host_basename, *container_dirname, *container_basename, *t; - _cleanup_close_ int hostfd = -1; - sd_bus *bus = userdata; - pid_t child, leader; - bool copy_from; - siginfo_t si; - int r; - - assert(bus); - - copy_from = streq(argv[0], "copy-from"); - dest = argv[3] ?: argv[2]; - host_path = strdupa(copy_from ? dest : argv[2]); - container_path = strdupa(copy_from ? argv[2] : dest); - - if (!path_is_absolute(container_path)) { - log_error("Container path not absolute."); - return -EINVAL; - } - - t = strdupa(host_path); - host_basename = basename(t); - host_dirname = dirname(host_path); - - t = strdupa(container_path); - container_basename = basename(t); - container_dirname = dirname(container_path); - - r = machine_get_leader(bus, argv[1], &leader); - if (r < 0) - return r; - - hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY); - if (r < 0) - return log_error_errno(errno, "Failed to open source directory: %m"); - - child = fork(); - if (child < 0) - return log_error_errno(errno, "Failed to fork(): %m"); - - if (child == 0) { - int containerfd; - const char *q; - int mntfd; - - 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); - } - - containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY); - if (containerfd < 0) { - log_error_errno(errno, "Failed top open destination directory: %m"); - _exit(EXIT_FAILURE); - } - - if (copy_from) - r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true); - else - r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true); - if (r < 0) { - log_error_errno(errno, "Failed to copy tree: %m"); - _exit(EXIT_FAILURE); - } - - _exit(EXIT_SUCCESS); - } - - r = wait_for_terminate(child, &si); - if (r < 0) - return log_error_errno(r, "Failed to wait for client: %m"); - if (si.si_code != CLD_EXITED) { - log_error("Client died abnormally."); - return -EIO; - } - if (si.si_status != EXIT_SUCCESS) - return -EIO; - return 0; } 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); - } + polkit_agent_open_if_enabled(); - 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) { @@ -1348,7 +1083,7 @@ static int on_machine_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd static int login_machine(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; _cleanup_(pty_forward_freep) PTYForward *forward = NULL; _cleanup_event_unref_ sd_event *event = NULL; @@ -1376,7 +1111,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'," @@ -1389,24 +1124,15 @@ static int login_machine(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to add machine removal match: %m"); - r = sd_bus_message_new_method_call(bus, - &m, - "org.freedesktop.machine1", - "/org/freedesktop/machine1", - "org.freedesktop.machine1.Manager", - "OpenMachineLogin"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(m, "s", argv[1]); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_call(bus, m, 0, &error, &reply); + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "OpenMachineLogin", + &error, + &reply, + "s", argv[1]); if (r < 0) { log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r)); return r; @@ -1423,7 +1149,7 @@ static int login_machine(int argc, char *argv[], void *userdata) { sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); - r = pty_forward_new(event, master, true, &forward); + r = pty_forward_new(event, master, true, false, &forward); if (r < 0) return log_error_errno(r, "Failed to create PTY forwarder: %m"); @@ -1571,7 +1297,7 @@ static int start_machine(int argc, char *argv[], void *userdata) { return log_oom(); for (i = 1; i < argc; i++) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_free_ char *e = NULL, *unit = NULL; const char *object; @@ -1588,25 +1314,15 @@ static int start_machine(int argc, char *argv[], void *userdata) { if (!unit) return log_oom(); - r = sd_bus_message_new_method_call( + r = sd_bus_call_method( bus, - &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "StartUnit"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(m, "ss", unit, "fail"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_call(bus, m, 0, &error, &reply); + "StartUnit", + &error, + &reply, + "ss", unit, "fail"); if (r < 0) { log_error("Failed to start unit: %s", bus_error_message(&error, -r)); return r; @@ -1652,10 +1368,6 @@ static int enable_machine(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); - if (r < 0) - return bus_log_create_error(r); - r = sd_bus_message_open_container(m, 'a', "s"); if (r < 0) return bus_log_create_error(r); @@ -1708,23 +1420,15 @@ static int enable_machine(int argc, char *argv[], void *userdata) { if (r < 0) return r; - m = sd_bus_message_unref(m); - - r = sd_bus_message_new_method_call( + r = sd_bus_call_method( bus, - &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "Reload"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_call(bus, m, 0, &error, NULL); + "Reload", + &error, + NULL, + NULL); if (r < 0) { log_error("Failed to reload daemon: %s", bus_error_message(&error, -r)); return r; @@ -1785,7 +1489,7 @@ static int transfer_signal_handler(sd_event_source *s, const struct signalfd_sig assert(si); if (!arg_quiet) - log_info("Continuing download in the background. Use \"machinectl cancel-transfer %" PRIu32 "\" to arbort transfer.", PTR_TO_UINT32(userdata)); + log_info("Continuing download in the background. Use \"machinectl cancel-transfer %" PRIu32 "\" to abort transfer.", PTR_TO_UINT32(userdata)); sd_event_exit(sd_event_source_get_event(s), EINTR); return 0; @@ -1813,10 +1517,6 @@ static int pull_image_common(sd_bus *bus, sd_bus_message *m) { if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop: %m"); - r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); - if (r < 0) - return bus_log_create_error(r); - r = sd_bus_add_match( bus, &slot_job_removed, @@ -1995,12 +1695,11 @@ 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; - if (!streq_ptr(arg_dkr_index_url, "no")) { + if (arg_verify != IMPORT_VERIFY_NO) { log_error("Imports from DKR do not support image verification, please pass --verify=no."); return -EINVAL; } @@ -2071,6 +1770,7 @@ typedef struct TransferInfo { const char *type; const char *remote; const char *local; + double progress; } TransferInfo; static int compare_transfer_info(const void *a, const void *b) { @@ -2088,6 +1788,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) { const char *type, *remote, *local, *object; sd_bus *bus = userdata; uint32_t id, max_id = 0; + double progress; int r; pager_open_if_enabled(); @@ -2106,11 +1807,11 @@ static int list_transfers(int argc, char *argv[], void *userdata) { return r; } - r = sd_bus_message_enter_container(reply, 'a', "(ussso)"); + r = sd_bus_message_enter_container(reply, 'a', "(usssdo)"); if (r < 0) return bus_log_parse_error(r); - while ((r = sd_bus_message_read(reply, "(ussso)", &id, &type, &remote, &local, &object)) > 0) { + while ((r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, &object)) > 0) { size_t l; if (!GREEDY_REALLOC(transfers, n_allocated, n_transfers + 1)) @@ -2120,6 +1821,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) { transfers[n_transfers].type = type; transfers[n_transfers].remote = remote; transfers[n_transfers].local = local; + transfers[n_transfers].progress = progress; l = strlen(type); if (l > max_type) @@ -2148,15 +1850,17 @@ static int list_transfers(int argc, char *argv[], void *userdata) { qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info); if (arg_legend) - printf("%-*s %-*s %-*s %-*s\n", + printf("%-*s %-*s %-*s %-*s %-*s\n", (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID", + (int) 7, "PERCENT", (int) max_type, "TYPE", (int) max_local, "LOCAL", (int) max_remote, "REMOTE"); for (j = 0; j < n_transfers; j++) - printf("%*" PRIu32 " %-*s %-*s %-*s\n", + printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n", (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id, + (int) 6, (unsigned) (transfers[j].progress * 100), (int) max_type, transfers[j].type, (int) max_local, transfers[j].local, (int) max_remote, transfers[j].remote); @@ -2246,7 +1950,7 @@ static int help(int argc, char *argv[], void *userdata) { " copy-from NAME PATH [PATH] Copy files from a container to the host\n" " bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n" "Image Commands:\n" - " list-images Show available container annd VM images\n" + " list-images Show available container and VM images\n" " image-status NAME... Show image details\n" " show-image NAME... Show properties of image\n" " clone NAME NAME Clone an image\n" @@ -2485,6 +2189,8 @@ int main(int argc, char*argv[]) { goto finish; } + sd_bus_set_allow_interactive_authorization(bus, arg_ask_password); + r = machinectl_main(argc, argv, bus); finish: