diff options
Diffstat (limited to 'src/machine')
-rw-r--r-- | src/machine/image-dbus.c | 2 | ||||
-rw-r--r-- | src/machine/machine-dbus.c | 92 | ||||
-rw-r--r-- | src/machine/machine-dbus.h | 1 | ||||
-rw-r--r-- | src/machine/machinectl.c | 66 | ||||
-rw-r--r-- | src/machine/machined-dbus.c | 21 |
5 files changed, 165 insertions, 17 deletions
diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 73f5112c4d..b764bc43a0 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -137,6 +137,8 @@ int bus_image_method_clone( return 1; /* Will call us back */ r = image_clone(image, new_name, read_only); + if (r == -EOPNOTSUPP) + return sd_bus_reply_method_errnof(message, r, "Image cloning is currently only supported on btrfs file systems."); if (r < 0) return r; diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index ab54d9e934..5121bfdd18 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -1274,6 +1274,97 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro return 1; } +int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_close_ int fd = -1; + Machine *m = userdata; + int r; + + assert(message); + assert(m); + + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.machine1.manage-machines", + NULL, + false, + UID_INVALID, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + + switch (m->class) { + + case MACHINE_HOST: + fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY); + if (fd < 0) + return -errno; + + break; + + case MACHINE_CONTAINER: { + _cleanup_close_ int mntns_fd = -1, root_fd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + siginfo_t si; + pid_t child; + + r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m"); + + if (child == 0) { + _cleanup_close_ int dfd = -1; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(-1, mntns_fd, -1, -1, root_fd); + if (r < 0) + _exit(EXIT_FAILURE); + + dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY); + if (dfd < 0) + _exit(EXIT_FAILURE); + + r = send_one_fd(pair[1], dfd, 0); + dfd = safe_close(dfd); + if (r < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + r = wait_for_terminate(child, &si); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally."); + + fd = receive_one_fd(pair[0], MSG_DONTWAIT); + if (fd < 0) + return fd; + + break; + } + + default: + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines."); + } + + return sd_bus_reply_method_return(message, "h", fd); +} + const sd_bus_vtable machine_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1297,6 +1388,7 @@ const sd_bus_vtable machine_vtable[] = { SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("OpenRootDirectory", NULL, "h", bus_machine_method_open_root_directory, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; diff --git a/src/machine/machine-dbus.h b/src/machine/machine-dbus.h index 3a8162b171..241b23c7ec 100644 --- a/src/machine/machine-dbus.h +++ b/src/machine/machine-dbus.h @@ -38,6 +38,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error); int machine_send_signal(Machine *m, bool new_machine); int machine_send_create_reply(Machine *m, sd_bus_error *error); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 35177aa29e..5a68c4ceb2 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -33,6 +33,7 @@ #include "alloc-util.h" #include "bus-error.h" +#include "bus-unit-util.h" #include "bus-util.h" #include "cgroup-show.h" #include "cgroup-util.h" @@ -331,8 +332,8 @@ static int list_images(int argc, char *argv[], void *userdata) { } static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *path = NULL; const char *cgroup; int r; @@ -341,9 +342,6 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { assert(bus); assert(unit); - if (arg_transport == BUS_TRANSPORT_REMOTE) - return 0; - path = unit_dbus_path_from_name(unit); if (!path) return log_oom(); @@ -357,16 +355,14 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { &error, &reply, "s"); - if (r < 0) { - log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r)); r = sd_bus_message_read(reply, "s", &cgroup); if (r < 0) return bus_log_parse_error(r); - if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0) + if (isempty(cgroup)) return 0; c = columns(); @@ -375,7 +371,21 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { else c = 0; - show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags()); + r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error); + if (r == -EBADR) { + + if (arg_transport == BUS_TRANSPORT_REMOTE) + return 0; + + /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */ + + if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0) + return 0; + + show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags()); + } else if (r < 0) + return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r)); + return 0; } @@ -2402,7 +2412,7 @@ static int help(int argc, char *argv[], void *userdata) { " --kill-who=WHO Who to send signal to\n" " -s --signal=SIGNAL Which signal to send\n" " --uid=USER Specify user ID to invoke shell as\n" - " --setenv=VAR=VALUE Add an environment variable for shell\n" + " -E --setenv=VAR=VALUE Add an environment variable for shell\n" " --read-only Create read-only bind mount\n" " --mkdir Create directory before bind mounting, if missing\n" " -n --lines=INTEGER Number of journal entries to show\n" @@ -2439,8 +2449,8 @@ static int help(int argc, char *argv[], void *userdata) { " rename NAME NAME Rename an image\n" " read-only NAME [BOOL] Mark or unmark image read-only\n" " remove NAME... Remove an image\n" - " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n\n" - " clean Remove hidden (or all) images\n" + " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n" + " clean Remove hidden (or all) images\n\n" "Image Transfer Commands:\n" " pull-tar URL [NAME] Download a TAR container image\n" " pull-raw URL [NAME] Download a RAW container or VM image\n" @@ -2470,7 +2480,6 @@ static int parse_argv(int argc, char *argv[]) { ARG_FORCE, ARG_FORMAT, ARG_UID, - ARG_SETENV, }; static const struct option options[] = { @@ -2496,16 +2505,38 @@ static int parse_argv(int argc, char *argv[]) { { "force", no_argument, NULL, ARG_FORCE }, { "format", required_argument, NULL, ARG_FORMAT }, { "uid", required_argument, NULL, ARG_UID }, - { "setenv", required_argument, NULL, ARG_SETENV }, + { "setenv", required_argument, NULL, 'E' }, {} }; + bool reorder = false; int c, r; assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0) + for (;;) { + const char * const option_string = "+hp:als:H:M:qn:o:"; + + c = getopt_long(argc, argv, option_string + reorder, options, NULL); + if (c < 0) { + /* We generally are fine with the fact that getopt_long() reorders the command line, and looks + * for switches after the main verb. However, for "shell" we really don't want that, since we + * want that switches passed after that are passed to the program to execute, and not processed + * by us. To make this possible, we'll first invoke getopt_long() with reordering disabled + * (i.e. with the "+" prefix in the option string), and as soon as we hit the end (i.e. the + * verb) we check if that's "shell". If it is, we exit the loop, since we don't want any + * further options processed. However, if it is anything else, we process the same argument + * again, but this time allow reordering. */ + + if (!reorder && optind < argc && !streq(argv[optind], "shell")) { + reorder = true; + optind--; + continue; + } + + break; + } switch (c) { @@ -2624,7 +2655,7 @@ static int parse_argv(int argc, char *argv[]) { arg_uid = optarg; break; - case ARG_SETENV: + case 'E': if (!env_assignment_is_valid(optarg)) { log_error("Environment assignment invalid: %s", optarg); return -EINVAL; @@ -2641,6 +2672,7 @@ static int parse_argv(int argc, char *argv[]) { default: assert_not_reached("Unhandled option"); } + } return 1; } diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index c9639c3cf2..31efa3695b 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -706,6 +706,26 @@ static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_e return bus_machine_method_copy(message, machine, error); } +static int method_open_machine_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Machine *machine; + const char *name; + int r; + + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + machine = hashmap_get(m->machines, name); + if (!machine) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name); + + return bus_machine_method_open_root_directory(message, machine, error); +} + static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(image_unrefp) Image* i = NULL; const char *name; @@ -1225,6 +1245,7 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED), |