From a47321a2286259bf90b707edc8c45c3bb2ddaa84 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 22 Sep 2023 23:02:33 +0200 Subject: [PATCH] libc: Implement openpty() --- libc/CMakeLists.txt | 1 + libc/include/pty.h | 21 +++++++++++++++++ libc/src/pty.cpp | 47 +++++++++++++++++++++++++++++++++++++ terminal/TerminalWidget.cpp | 27 +++++++++++---------- 4 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 libc/include/pty.h create mode 100644 libc/src/pty.cpp diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index e2eaceea..47d8c8d6 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -25,6 +25,7 @@ set(SOURCES src/utime.cpp src/strtod.cpp src/math.cpp + src/pty.cpp src/sys/stat.cpp src/sys/mman.cpp src/sys/wait.cpp diff --git a/libc/include/pty.h b/libc/include/pty.h new file mode 100644 index 00000000..22afbb97 --- /dev/null +++ b/libc/include/pty.h @@ -0,0 +1,21 @@ +/* pty.h: Pseudoterminal handling functions. */ + +#ifndef _PTY_H +#define _PTY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Find an available pseudoterminal pair and initialize it, returning file descriptors for both sides. */ + int openpty(int* master, int* slave, char* name, const struct termios* term, const struct winsize* win); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/src/pty.cpp b/libc/src/pty.cpp new file mode 100644 index 00000000..879a772b --- /dev/null +++ b/libc/src/pty.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +extern "C" +{ + int openpty(int* master, int* slave, char* name, const struct termios* term, const struct winsize* win) + { + *master = posix_openpt(O_RDWR); + if (*master < 0) return -1; + + // No-ops on Luna, and since this is the Luna libc, we can skip error handling. + grantpt(*master); + unlockpt(*master); + + char* pname = ptsname(*master); + if (!pname) + { + close(*master); + return -1; + } + + if (name) + { + fputs("warning: openpty() called with non-null name, this is insecure\n", stderr); + strcpy(name, pname); + } + + *slave = open(pname, O_RDWR); + if (*slave < 0) + { + close(*master); + return -1; + } + + if (term) tcsetattr(*slave, TCSANOW, term); + if (win) fputs("warning: openpty() called with non-null window size, this is not supported yet\n", stderr); + + return 0; + } +} diff --git a/terminal/TerminalWidget.cpp b/terminal/TerminalWidget.cpp index 703ecbf2..76e93262 100644 --- a/terminal/TerminalWidget.cpp +++ b/terminal/TerminalWidget.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -51,33 +52,35 @@ Result TerminalWidget::init(char* const* args) signal(SIGCHLD, sigchld_handler); - int fd = posix_openpt(O_RDWR | O_CLOEXEC); - if (fd < 0) return err(errno); + int master; + int slave; - grantpt(fd); - unlockpt(fd); + int result = openpty(&master, &slave, nullptr, nullptr, nullptr); + if (result < 0) return err(errno); pid_t child = TRY(os::Process::fork()); if (child == 0) { - int ptsfd = open(ptsname(fd), O_RDWR); + close(master); - dup2(ptsfd, STDIN_FILENO); - dup2(ptsfd, STDOUT_FILENO); - dup2(ptsfd, STDERR_FILENO); + dup2(slave, STDIN_FILENO); + dup2(slave, STDOUT_FILENO); + dup2(slave, STDERR_FILENO); setpgid(0, 0); - tcsetpgrp(ptsfd, getpid()); + tcsetpgrp(slave, getpid()); - close(ptsfd); + close(slave); execv(args[0], args); _exit(127); } - m_pty = fd; + close(slave); - fcntl(fd, F_SETFL, O_NONBLOCK); + m_pty = master; + + fcntl(master, F_SETFL, O_NONBLOCK); m_child_pid = child;