]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machined: when opening a shell via machined, pass tty fds in
authorLennart Poettering <lennart@poettering.net>
Wed, 7 Oct 2015 21:38:20 +0000 (23:38 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 8 Oct 2015 13:03:31 +0000 (15:03 +0200)
With this change we'll open the shell's tty right from machined and then
pass it to the transient unit we create. This way we make sure the pty
is opened exactly as long as the transient service is around, and no
longer, and vice versa. This way pty forwarders do not have to deal with
EIO problems due to vhangup, as the pty is open all the time from the
point we set things up to the point where the service goes away.

src/basic/terminal-util.c
src/basic/terminal-util.h
src/machine/machine-dbus.c
src/machine/machine.c
src/machine/machine.h
src/machine/machinectl.c

index 50a86a331c4bd24c5db6ab775a77f04af0a3318e..e9097d8ae52be67156bcad478a657d5c5706c0c9 100644 (file)
@@ -1152,3 +1152,51 @@ int openpt_in_namespace(pid_t pid, int flags) {
 
         return receive_one_fd(pair[0], 0);
 }
+
+int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
+        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
+        _cleanup_close_pair_ int pair[2] = { -1, -1 };
+        siginfo_t si;
+        pid_t child;
+        int r;
+
+        r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+        if (r < 0)
+                return r;
+
+        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+                return -errno;
+
+        child = fork();
+        if (child < 0)
+                return -errno;
+
+        if (child == 0) {
+                int master;
+
+                pair[0] = safe_close(pair[0]);
+
+                r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
+                if (r < 0)
+                        _exit(EXIT_FAILURE);
+
+                master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC);
+                if (master < 0)
+                        _exit(EXIT_FAILURE);
+
+                if (send_one_fd(pair[1], master, 0) < 0)
+                        _exit(EXIT_FAILURE);
+
+                _exit(EXIT_SUCCESS);
+        }
+
+        pair[1] = safe_close(pair[1]);
+
+        r = wait_for_terminate(child, &si);
+        if (r < 0)
+                return r;
+        if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
+                return -EIO;
+
+        return receive_one_fd(pair[0], 0);
+}
index 050d0524a560eb3c4e6cf2300b9226d26bef5d92..ee0b68b433abd4428d995b77d730bbf1c43f0d84 100644 (file)
@@ -124,3 +124,4 @@ int ptsname_malloc(int fd, char **ret);
 int ptsname_namespace(int pty, char **ret);
 
 int openpt_in_namespace(pid_t pid, int flags);
+int open_terminal_in_namespace(pid_t pid, const char *name, int mode);
index 21026829a9ff087591343caf089b210a32b39f4b..6e41e929621c74111f369d216e57484c558d1476 100644 (file)
@@ -639,7 +639,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
         _cleanup_free_ char *pty_name = NULL;
         _cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL;
         sd_bus *container_bus = NULL;
-        _cleanup_close_ int master = -1;
+        _cleanup_close_ int master = -1, slave = -1;
         _cleanup_strv_free_ char **env = NULL, **args = NULL;
         Machine *m = userdata;
         const char *p, *unit, *user, *path, *description, *utmp_id;
@@ -700,8 +700,11 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
                 return r;
 
         p = path_startswith(pty_name, "/dev/pts/");
-        if (!p)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
+        assert(p);
+
+        slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (slave < 0)
+                return slave;
 
         utmp_id = path_startswith(pty_name, "/dev/");
         assert(utmp_id);
@@ -735,16 +738,14 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
 
         description = strjoina("Shell for User ", isempty(user) ? "root" : user);
         r = sd_bus_message_append(tm,
-                                  "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
+                                  "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
                                   "Description", "s", description,
-                                  "StandardInput", "s", "tty",
-                                  "StandardOutput", "s", "tty",
-                                  "StandardError", "s", "tty",
-                                  "TTYPath", "s", pty_name,
+                                  "StandardInputFileDescriptor", "h", slave,
+                                  "StandardOutputFileDescriptor", "h", slave,
+                                  "StandardErrorFileDescriptor", "h", slave,
                                   "SendSIGHUP", "b", true,
                                   "IgnoreSIGPIPE", "b", false,
                                   "KillMode", "s", "mixed",
-                                  "TTYVHangup", "b", true,
                                   "TTYReset", "b", true,
                                   "UtmpIdentifier", "s", utmp_id,
                                   "UtmpMode", "s", "user",
@@ -845,6 +846,8 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
         if (r < 0)
                 return r;
 
+        slave = safe_close(slave);
+
         r = sd_bus_message_new_method_return(message, &reply);
         if (r < 0)
                 return r;
index 0f1942d1f4671dbe96b96eb4cc5ff4729739844e..7ab84607fbc39d236e5c8c81d5a8a9bc5eec5023 100644 (file)
@@ -572,6 +572,25 @@ int machine_openpt(Machine *m, int flags) {
         }
 }
 
+int machine_open_terminal(Machine *m, const char *path, int mode) {
+        assert(m);
+
+        switch (m->class) {
+
+        case MACHINE_HOST:
+                return open_terminal(path, mode);
+
+        case MACHINE_CONTAINER:
+                if (m->leader <= 0)
+                        return -EINVAL;
+
+                return open_terminal_in_namespace(m->leader, path, mode);
+
+        default:
+                return -EOPNOTSUPP;
+        }
+}
+
 MachineOperation *machine_operation_unref(MachineOperation *o) {
         if (!o)
                 return NULL;
index 5f978289f29a31c1a0385b557c43588c40adfa52..ad7f2a162f594e258152afd5cc992b8eca270bcd 100644 (file)
@@ -123,3 +123,4 @@ const char *kill_who_to_string(KillWho k) _const_;
 KillWho kill_who_from_string(const char *s) _pure_;
 
 int machine_openpt(Machine *m, int flags);
+int machine_open_terminal(Machine *m, const char *path, int mode);
index e75b1833283bacd1c6d2feb7a1b075890e7666c2..0a21ab4415b7a92ef307af2fba0a8dcf24cf69ce 100644 (file)
@@ -1390,7 +1390,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, machine);
+        return process_forward(event, &forward, master, 0, machine);
 }
 
 static int remove_image(int argc, char *argv[], void *userdata) {