X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fnspawn%2Fnspawn.c;h=6aaceac30b97a7321d9068688a600369340d8d3d;hb=814a3fdfdc8cd94797eff5f3e1d9a3cc032d880a;hp=651a45126b8585b7e0037e76a53c553318b2fdf5;hpb=c4e34a612c81266773cf8358cb38a43d2e43474e;p=elogind.git diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 651a45126..6aaceac30 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -90,8 +89,10 @@ #include "base-filesystem.h" #include "barrier.h" #include "event-util.h" +#include "capability.h" #include "cap-list.h" #include "btrfs-util.h" +#include "machine-image.h" #ifdef HAVE_SECCOMP #include "seccomp-util.h" @@ -2082,6 +2083,27 @@ finish: } +static int setup_propagate(const char *root) { + const char *p, *q; + + (void) mkdir_p("/run/systemd/nspawn/", 0755); + (void) mkdir_p("/run/systemd/nspawn/propagate", 0600); + p = strappenda("/run/systemd/nspawn/propagate/", arg_machine); + (void) mkdir_p(p, 0600); + + q = strappenda(root, "/run/systemd/nspawn/incoming"); + mkdir_parents(q, 0755); + mkdir_p(q, 0600); + + if (mount(p, q, NULL, MS_BIND, NULL) < 0) + return log_error_errno(errno, "Failed to install propagation bind mount."); + + if (mount(NULL, q, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) + return log_error_errno(errno, "Failed to make propagation mount read-only"); + + return 0; +} + static int setup_image(char **device_path, int *loop_nr) { struct loop_info64 info = { .lo_flags = LO_FLAGS_AUTOCLEAR|LO_FLAGS_PARTSCAN @@ -2861,21 +2883,43 @@ static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo } static int determine_names(void) { + int r; if (!arg_image && !arg_directory) { - if (arg_machine) - arg_directory = strappend("/var/lib/container/", arg_machine); - else + if (arg_machine) { + _cleanup_(image_unrefp) Image *i = NULL; + + r = image_find(arg_machine, &i); + if (r < 0) + return log_error_errno(r, "Failed to find image for machine '%s': %m", arg_machine); + else if (r == 0) { + log_error("No image for machine '%s': %m", arg_machine); + return -ENOENT; + } + + if (i->type == IMAGE_GPT) + r = set_sanitized_path(&arg_image, i->path); + else + r = set_sanitized_path(&arg_directory, i->path); + if (r < 0) + return log_error_errno(r, "Invalid image directory: %m"); + + arg_read_only = arg_read_only || i->read_only; + } else arg_directory = get_current_dir_name(); - if (!arg_directory) { - log_error("Failed to determine path, please use -D."); + if (!arg_directory && !arg_machine) { + log_error("Failed to determine path, please use -D or -i."); return -EINVAL; } } if (!arg_machine) { - arg_machine = strdup(basename(arg_image ?: arg_directory)); + if (arg_directory && path_equal(arg_directory, "/")) + arg_machine = gethostname_malloc(); + else + arg_machine = strdup(basename(arg_image ?: arg_directory)); + if (!arg_machine) return log_oom(); @@ -2884,6 +2928,21 @@ static int determine_names(void) { log_error("Failed to determine machine name automatically, please use -M."); return -EINVAL; } + + if (arg_ephemeral) { + char *b; + + /* Add a random suffix when this is an + * ephemeral machine, so that we can run many + * instances at once without manually having + * to specify -M each time. */ + + if (asprintf(&b, "%s-%016" PRIx64, arg_machine, random_u64()) < 0) + return log_oom(); + + free(arg_machine); + arg_machine = b; + } } return 0; @@ -2891,13 +2950,12 @@ static int determine_names(void) { int main(int argc, char *argv[]) { - _cleanup_free_ char *device_path = NULL, *root_device = NULL, *home_device = NULL, *srv_device = NULL; + _cleanup_free_ char *device_path = NULL, *root_device = NULL, *home_device = NULL, *srv_device = NULL, *console = NULL; bool root_device_rw = true, home_device_rw = true, srv_device_rw = true; _cleanup_close_ int master = -1, image_fd = -1; _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }; _cleanup_fdset_free_ FDSet *fds = NULL; int r, n_fd_passed, loop_nr = -1; - const char *console = NULL; char veth_name[IFNAMSIZ]; bool secondary = false, remove_subvol = false; sigset_t mask, mask_chld; @@ -3054,9 +3112,9 @@ int main(int argc, char *argv[]) { goto finish; } - console = ptsname(master); - if (!console) { - r = log_error_errno(errno, "Failed to determine tty name: %m"); + r = ptsname_malloc(master, &console); + if (r < 0) { + r = log_error_errno(r, "Failed to determine tty name: %m"); goto finish; } @@ -3074,10 +3132,6 @@ int main(int argc, char *argv[]) { goto finish; } - sd_notify(false, - "READY=1\n" - "STATUS=Container running."); - assert_se(sigemptyset(&mask) == 0); sigset_add_many(&mask, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1); assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0); @@ -3114,9 +3168,9 @@ int main(int argc, char *argv[]) { goto finish; } - pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWNS| - (arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS)| - (arg_private_network ? CLONE_NEWNET : 0), NULL); + pid = raw_clone(SIGCHLD|CLONE_NEWNS| + (arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS)| + (arg_private_network ? CLONE_NEWNET : 0), NULL); if (pid < 0) { if (errno == EINVAL) r = log_error_errno(errno, "clone() failed, do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in): %m"); @@ -3241,6 +3295,9 @@ int main(int argc, char *argv[]) { dev_setup(arg_directory); + if (setup_propagate(arg_directory) < 0) + _exit(EXIT_FAILURE); + if (setup_seccomp() < 0) _exit(EXIT_FAILURE); @@ -3419,6 +3476,7 @@ int main(int argc, char *argv[]) { if (barrier_place_and_sync(&barrier)) { _cleanup_event_unref_ sd_event *event = NULL; _cleanup_(pty_forward_freep) PTYForward *forward = NULL; + char last_char = 0; int ifi = 0; r = move_network_interfaces(pid); @@ -3455,7 +3513,11 @@ int main(int argc, char *argv[]) { /* Notify the child that the parent is ready with all * its setup, and that the child can now hand over * control to the code to run inside the container. */ - (void)barrier_place(&barrier); + (void) barrier_place(&barrier); + + sd_notify(false, + "READY=1\n" + "STATUS=Container running."); r = sd_event_new(&event); if (r < 0) { @@ -3476,7 +3538,7 @@ int main(int argc, char *argv[]) { /* simply exit on sigchld */ sd_event_add_signal(event, NULL, SIGCHLD, NULL, NULL); - r = pty_forward_new(event, master, &forward); + r = pty_forward_new(event, master, true, &forward); if (r < 0) { log_error_errno(r, "Failed to create PTY forwarder: %m"); goto finish; @@ -3488,9 +3550,11 @@ int main(int argc, char *argv[]) { goto finish; } + pty_forward_last_char(forward, &last_char); + forward = pty_forward_free(forward); - if (!arg_quiet) + if (!arg_quiet && last_char != '\n') putc('\n', stdout); /* Kill if it is not dead yet anyway */ @@ -3552,6 +3616,13 @@ finish: log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory); } + if (arg_machine) { + const char *p; + + p = strappenda("/run/systemd/nspawn/propagate", arg_machine); + (void) rm_rf(p, false, true, false); + } + free(arg_directory); free(arg_template); free(arg_image);