diff options
author | James McCoy <jamessan@jamessan.com> | 2021-12-16 08:24:29 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-16 08:24:29 -0500 |
commit | 56fa08b458cbf98fa83c21c3e683f8e7e91a334f (patch) | |
tree | 986cb81075e6c91c0454199e533f2181bec6bb1a | |
parent | a402b5e2d58c53f0343e5b01ddf9caca961f30ab (diff) | |
parent | 2c8f4d0912a280ae55d73d96d0ca2ed96b8fde8a (diff) | |
download | rneovim-56fa08b458cbf98fa83c21c3e683f8e7e91a334f.tar.gz rneovim-56fa08b458cbf98fa83c21c3e683f8e7e91a334f.tar.bz2 rneovim-56fa08b458cbf98fa83c21c3e683f8e7e91a334f.zip |
Merge pull request #16617 from pekdon/forkpty
fix: add forkpty for SunOS variants
-rw-r--r-- | config/CMakeLists.txt | 13 | ||||
-rw-r--r-- | config/config.h.in | 1 | ||||
-rw-r--r-- | src/nvim/os/pty_process_unix.c | 120 |
3 files changed, 133 insertions, 1 deletions
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt index 30f08c5297..8f93e1eb27 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -50,6 +50,19 @@ check_function_exists(strcasecmp HAVE_STRCASECMP) check_function_exists(strncasecmp HAVE_STRNCASECMP) check_function_exists(strptime HAVE_STRPTIME) +if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") + check_c_source_compiles(" +#include <termios.h> +int +main(void) +{ + return forkpty(0, NULL, NULL, NULL); +} +" HAVE_FORKPTY) +else() + set(HAVE_FORKPTY 1) +endif() + # Symbols check_symbol_exists(FD_CLOEXEC "fcntl.h" HAVE_FD_CLOEXEC) if(HAVE_LANGINFO_H) diff --git a/config/config.h.in b/config/config.h.in index b0635fb52b..b44b7238d2 100644 --- a/config/config.h.in +++ b/config/config.h.in @@ -50,6 +50,7 @@ # undef HAVE_SYS_UIO_H # endif #endif +#cmakedefine HAVE_FORKPTY #cmakedefine FEAT_TUI diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 450bc75ffb..3459646bad 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -15,7 +15,13 @@ # include <libutil.h> #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) # include <util.h> -#elif !defined(__sun) +#elif defined(__sun) +# include <sys/stream.h> +# include <sys/syscall.h> +# include <fcntl.h> +# include <unistd.h> +# include <signal.h> +#else # include <pty.h> #endif @@ -38,6 +44,118 @@ # include "os/pty_process_unix.c.generated.h" #endif +#if defined(__sun) && !defined(HAVE_FORKPTY) + +// this header defines STR, just as nvim.h, but it is defined as ('S'<<8), +// to avoid #undef STR, #undef STR, #define STR ('S'<<8) just delay the +// inclusion of the header even though it gets include out of order. +#include <sys/stropts.h> + +static int openpty(int *amaster, int *aslave, char *name, + struct termios *termp, struct winsize *winp) +{ + int slave = -1; + int master = open("/dev/ptmx", O_RDWR); + if (master == -1) { + goto error; + } + + // grantpt will invoke a setuid program to change permissions + // and might fail if SIGCHLD handler is set, temporarily reset + // while running + void(*sig_saved)(int) = signal(SIGCHLD, SIG_DFL); + int res = grantpt(master); + signal(SIGCHLD, sig_saved); + + if (res == -1 || unlockpt(master) == -1) { + goto error; + } + + char *slave_name = ptsname(master); + if (slave_name == NULL) { + goto error; + } + + slave = open(slave_name, O_RDWR|O_NOCTTY); + if (slave == -1) { + goto error; + } + + // ptem emulates a terminal when used on a pseudo terminal driver, + // must be pushed before ldterm + ioctl(slave, I_PUSH, "ptem"); + // ldterm provides most of the termio terminal interface + ioctl(slave, I_PUSH, "ldterm"); + // ttcompat compatability with older terminal ioctls + ioctl(slave, I_PUSH, "ttcompat"); + + if (termp) { + tcsetattr(slave, TCSAFLUSH, termp); + } + if (winp) { + ioctl(slave, TIOCSWINSZ, winp); + } + + *amaster = master; + *aslave = slave; + // ignoring name, not passed and size is unknown in the API + + return 0; + +error: + if (slave != -1) { + close(slave); + } + if (master != -1) { + close(master); + } + return -1; +} + +static int login_tty(int fd) +{ + setsid(); + if (ioctl(fd, TIOCSCTTY, NULL) == -1) { + return -1; + } + + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) { + close(fd); + } + + return 0; +} + +static pid_t forkpty(int *amaster, char *name, + struct termios *termp, struct winsize *winp) +{ + int master, slave; + if (openpty(&master, &slave, name, termp, winp) == -1) { + return -1; + } + + pid_t pid = fork(); + switch (pid) { + case -1: + close(master); + close(slave); + return -1; + case 0: + close(master); + login_tty(slave); + return 0; + default: + close(slave); + *amaster = master; + return pid; + } +} + +#endif + /// termios saved at startup (for TUI) or initialized by pty_process_spawn(). static struct termios termios_default; |