+ 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);
+ 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;
+ }
+
+ 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;
+}
+
+static int on_machine_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ PTYForward ** forward = (PTYForward**) userdata;
+ int r;
+
+ assert(bus);
+ assert(m);
+ assert(forward);
+
+ if (*forward) {
+ /* If the forwarder is already initialized, tell it to
+ * exit on the next vhangup(), so that we still flush
+ * out what might be queued and exit then. */
+
+ r = pty_forward_set_ignore_vhangup(*forward, false);
+ if (r >= 0)
+ return 0;
+
+ log_error_errno(r, "Failed to set ignore_vhangup flag: %m");
+ }
+
+ /* On error, or when the forwarder is not initialized yet, quit immediately */
+ sd_event_exit(sd_bus_get_event(bus), EXIT_FAILURE);
+ return 0;
+}
+
+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_slot_unref_ sd_bus_slot *slot = NULL;
+ _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
+ _cleanup_event_unref_ sd_event *event = NULL;
+ int master = -1, r, ret = 0;
+ sd_bus *bus = userdata;
+ const char *pty, *match;
+ sigset_t mask;
+ char last_char = 0;
+ bool machine_died;
+
+ assert(bus);
+
+ if (arg_transport != BUS_TRANSPORT_LOCAL &&
+ arg_transport != BUS_TRANSPORT_MACHINE) {
+ log_error("Login only supported on local machines.");
+ return -ENOTSUP;
+ }
+
+ r = sd_event_default(&event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get event loop: %m");
+
+ r = sd_bus_attach_event(bus, event, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach bus to event loop: %m");
+
+ match = strappenda("type='signal',"
+ "sender='org.freedesktop.machine1',"
+ "path='/org/freedesktop/machine1',",
+ "interface='org.freedesktop.machine1.Manager',"
+ "member='MachineRemoved',"
+ "arg0='",
+ argv[1],
+ "'");
+
+ r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward);
+ 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, true);
+ 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);