[vte] pty: Split getting PTY peer FD out of child setup
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte] pty: Split getting PTY peer FD out of child setup
- Date: Mon, 27 Apr 2020 18:49:30 +0000 (UTC)
commit c9dc0863888e536f002059550e205cdc1c03d701
Author: Christian Persch <chpe src gnome org>
Date: Mon Apr 27 20:49:04 2020 +0200
pty: Split getting PTY peer FD out of child setup
It will be needed separately when spawning via the portal.
src/pty.cc | 168 +++++++++++++++++++++++++++++++++----------------------------
src/pty.hh | 2 +
2 files changed, 92 insertions(+), 78 deletions(-)
---
diff --git a/src/pty.cc b/src/pty.cc
index 30447215..040a0005 100644
--- a/src/pty.cc
+++ b/src/pty.cc
@@ -104,50 +104,22 @@ Pty::unref() noexcept
delete this;
}
-void
-Pty::child_setup() const noexcept
+vte::libc::FD
+Pty::get_peer() const noexcept
{
- /* Unblock all signals */
- sigset_t set;
- sigemptyset(&set);
- if (pthread_sigmask(SIG_SETMASK, &set, nullptr) == -1) {
- _vte_debug_print(VTE_DEBUG_PTY, "%s failed: %m\n", "pthread_sigmask");
- _exit(127);
- }
-
- /* Reset the handlers for all signals to their defaults. The parent
- * (or one of the libraries it links to) may have changed one to be ignored. */
- for (int n = 1; n < NSIG; n++) {
- if (n == SIGSTOP || n == SIGKILL)
- continue;
-
- signal(n, SIG_DFL);
- }
-
- auto masterfd = fd();
- if (masterfd == -1)
- _exit(127);
+ if (!m_pty_fd)
+ return {};
- if (grantpt(masterfd) != 0) {
+ if (grantpt(m_pty_fd.get()) != 0) {
_vte_debug_print(VTE_DEBUG_PTY, "%s failed: %m\n", "grantpt");
- _exit(127);
+ return {};
}
- if (unlockpt(masterfd) != 0) {
+ if (unlockpt(m_pty_fd.get()) != 0) {
_vte_debug_print(VTE_DEBUG_PTY, "%s failed: %m\n", "unlockpt");
- _exit(127);
+ return {};
}
- if (!(m_flags & VTE_PTY_NO_SESSION)) {
- /* This starts a new session; we become its process-group leader,
- * and lose our controlling TTY.
- */
- _vte_debug_print (VTE_DEBUG_PTY, "Starting new session\n");
- if (setsid() == -1) {
- _vte_debug_print(VTE_DEBUG_PTY, "%s failed: %m\n", "setsid");
- _exit(127);
- }
- }
/* FIXME? else if (m_flags & VTE_PTY_NO_CTTTY)
* No session and no controlling TTY wanted, do we need to lose our controlling TTY,
* perhaps by open("/dev/tty") + ioctl(TIOCNOTTY) ?
@@ -156,44 +128,100 @@ Pty::child_setup() const noexcept
/* Now open the PTY peer. Note that this also makes the PTY our controlling TTY. */
/* Note: *not* O_CLOEXEC! */
auto const fd_flags = int{O_RDWR | ((m_flags & VTE_PTY_NO_CTTY) ? O_NOCTTY : 0)};
- auto fd = int{-1};
+
+ auto peer_fd = vte::libc::FD{};
#ifdef __linux__
- fd = ioctl(masterfd, TIOCGPTPEER, fd_flags);
+ peer_fd = ioctl(m_pty_fd.get(), TIOCGPTPEER, fd_flags);
/* Note: According to the kernel's own tests (tools/testing/selftests/filesystems/devpts_pts.c),
* the error returned when the running kernel does not support this ioctl should be EINVAL.
* However it appears that the actual error returned is ENOTTY. So we check for both of them.
* See issue#182.
*/
- if (fd == -1 &&
+ if (!peer_fd &&
errno != EINVAL &&
errno != ENOTTY) {
- _vte_debug_print(VTE_DEBUG_PTY, "%s failed: %m\n", "ioctl(TIOCGPTPEER)");
- _exit(127);
+ _vte_debug_print(VTE_DEBUG_PTY, "%s failed: %m\n", "ioctl(TIOCGPTPEER)");
+ return {};
}
/* Fall back to ptsname + open */
#endif
- if (fd == -1) {
- auto const name = ptsname(masterfd);
+ if (!peer_fd) {
+ auto const name = ptsname(m_pty_fd.get());
if (name == nullptr) {
_vte_debug_print(VTE_DEBUG_PTY, "%s failed: %m\n", "ptsname");
- _exit(127);
+ return {};
}
_vte_debug_print (VTE_DEBUG_PTY,
"Setting up child pty: master FD = %d name = %s\n",
- masterfd, name);
+ m_pty_fd.get(), name);
- fd = ::open(name, fd_flags);
- if (fd == -1) {
+ peer_fd = ::open(name, fd_flags);
+ if (!peer_fd) {
_vte_debug_print (VTE_DEBUG_PTY, "Failed to open PTY: %m\n");
+ return {};
+ }
+ }
+
+ assert(bool(peer_fd));
+
+#if defined(__sun) && defined(HAVE_STROPTS_H)
+ if (isastream (peer_fd.get()) == 1) {
+ if ((ioctl(peer_fd.get(), I_FIND, "ptem") == 0) &&
+ (ioctl(peer_fd.get(), I_PUSH, "ptem") == -1)) {
+ return {};
+ }
+ if ((ioctl(peer_fd.get(), I_FIND, "ldterm") == 0) &&
+ (ioctl(peer_fd.get(), I_PUSH, "ldterm") == -1)) {
+ return {};
+ }
+ if ((ioctl(peer_fd.get(), I_FIND, "ttcompat") == 0) &&
+ (ioctl(peer_fd.get(), I_PUSH, "ttcompat") == -1)) {
+ return {};
+ }
+ }
+#endif
+
+ return peer_fd;
+}
+
+void
+Pty::child_setup() const noexcept
+{
+ /* Unblock all signals */
+ sigset_t set;
+ sigemptyset(&set);
+ if (pthread_sigmask(SIG_SETMASK, &set, nullptr) == -1) {
+ _vte_debug_print(VTE_DEBUG_PTY, "%s failed: %m\n", "pthread_sigmask");
+ _exit(127);
+ }
+
+ /* Reset the handlers for all signals to their defaults. The parent
+ * (or one of the libraries it links to) may have changed one to be ignored. */
+ for (int n = 1; n < NSIG; n++) {
+ if (n == SIGSTOP || n == SIGKILL)
+ continue;
+
+ signal(n, SIG_DFL);
+ }
+
+ if (!(m_flags & VTE_PTY_NO_SESSION)) {
+ /* This starts a new session; we become its process-group leader,
+ * and lose our controlling TTY.
+ */
+ _vte_debug_print (VTE_DEBUG_PTY, "Starting new session\n");
+ if (setsid() == -1) {
+ _vte_debug_print(VTE_DEBUG_PTY, "%s failed: %m\n", "setsid");
_exit(127);
}
}
- assert(fd != -1);
+ auto peer_fd = get_peer();
+ if (!peer_fd)
+ _exit(127);
#ifdef TIOCSCTTY
/* On linux, opening the PTY peer above already made it our controlling TTY (since
@@ -201,53 +229,37 @@ Pty::child_setup() const noexcept
* on *BSD, that doesn't happen, so we need this explicit ioctl here.
*/
if (!(m_flags & VTE_PTY_NO_CTTY)) {
- if (ioctl(fd, TIOCSCTTY, fd) != 0) {
+ if (ioctl(peer_fd.get(), TIOCSCTTY, peer_fd.get()) != 0) {
_vte_debug_print(VTE_DEBUG_PTY, "%s failed: %m\n", "ioctl(TIOCSCTTY)");
_exit(127);
}
}
#endif
-#if defined(__sun) && defined(HAVE_STROPTS_H)
- if (isastream (fd) == 1) {
- if ((ioctl(fd, I_FIND, "ptem") == 0) &&
- (ioctl(fd, I_PUSH, "ptem") == -1)) {
- _exit (127);
- }
- if ((ioctl(fd, I_FIND, "ldterm") == 0) &&
- (ioctl(fd, I_PUSH, "ldterm") == -1)) {
- _exit (127);
- }
- if ((ioctl(fd, I_FIND, "ttcompat") == 0) &&
- (ioctl(fd, I_PUSH, "ttcompat") == -1)) {
- perror ("ioctl (fd, I_PUSH, \"ttcompat\")");
- _exit (127);
- }
- }
-#endif
-
/* now setup child I/O through the tty */
- if (fd != STDIN_FILENO) {
- if (dup2(fd, STDIN_FILENO) != STDIN_FILENO){
+ if (peer_fd != STDIN_FILENO) {
+ if (dup2(peer_fd.get(), STDIN_FILENO) != STDIN_FILENO){
_exit (127);
}
}
- if (fd != STDOUT_FILENO) {
- if (dup2(fd, STDOUT_FILENO) != STDOUT_FILENO){
+ if (peer_fd != STDOUT_FILENO) {
+ if (dup2(peer_fd.get(), STDOUT_FILENO) != STDOUT_FILENO){
_exit (127);
}
}
- if (fd != STDERR_FILENO) {
- if (dup2(fd, STDERR_FILENO) != STDERR_FILENO){
+ if (peer_fd != STDERR_FILENO) {
+ if (dup2(peer_fd.get(), STDERR_FILENO) != STDERR_FILENO){
_exit (127);
}
}
- /* Close the original FD, unless it's one of the stdio descriptors */
- if (fd != STDIN_FILENO &&
- fd != STDOUT_FILENO &&
- fd != STDERR_FILENO) {
- close(fd);
+ /* If the peer FD has not been consumed above as one of the stdio descriptors,
+ * need to close it now so that it doesn't leak to the child.
+ */
+ if (peer_fd == STDIN_FILENO ||
+ peer_fd == STDOUT_FILENO ||
+ peer_fd == STDERR_FILENO) {
+ (void)peer_fd.release();
}
/* Now set the TERM environment variable */
diff --git a/src/pty.hh b/src/pty.hh
index dea19688..ace59f3d 100644
--- a/src/pty.hh
+++ b/src/pty.hh
@@ -40,6 +40,8 @@ private:
VtePtyFlags m_flags{VTE_PTY_DEFAULT};
+ vte::libc::FD get_peer() const noexcept;
+
public:
constexpr Pty(vte::libc::FD&& fd,
VtePtyFlags flags = VTE_PTY_DEFAULT) noexcept
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]