diff options
author | Claes Nästén <pekdon@gmail.com> | 2021-12-09 20:01:19 +0100 |
---|---|---|
committer | Claes Nästén <pekdon@gmail.com> | 2021-12-12 11:29:56 +0000 |
commit | 2c8f4d0912a280ae55d73d96d0ca2ed96b8fde8a (patch) | |
tree | 24d1cdb63fa3fb67c962df055129da4f2b97d751 /src/nvim/os/pty_process_unix.c | |
parent | ac2d140a33dfe88f882218e15a443b8300cca6b2 (diff) | |
download | rneovim-2c8f4d0912a280ae55d73d96d0ca2ed96b8fde8a.tar.gz rneovim-2c8f4d0912a280ae55d73d96d0ca2ed96b8fde8a.tar.bz2 rneovim-2c8f4d0912a280ae55d73d96d0ca2ed96b8fde8a.zip |
fix: add forkpty for SunOS variants
forkpty is missing on Solaris < 11 and Illumos, provide fallback implementation
for non Solaris 11 users.
Diffstat (limited to 'src/nvim/os/pty_process_unix.c')
-rw-r--r-- | src/nvim/os/pty_process_unix.c | 120 |
1 files changed, 119 insertions, 1 deletions
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; |