diff options
Diffstat (limited to 'taketty.c')
| -rw-r--r-- | taketty.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/taketty.c b/taketty.c new file mode 100644 index 0000000..31fb25e --- /dev/null +++ b/taketty.c @@ -0,0 +1,119 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <termios.h> +#include <sys/select.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <string.h> + +static void set_raw_mode(int fd) { + struct termios tios; + + if (tcgetattr(fd, &tios) < 0) { + perror("tcgetattr"); + exit(1); + } + + tios.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO); + tios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + tios.c_cflag &= ~(CSIZE | PARENB); + tios.c_cflag |= CS8; + tios.c_oflag &= ~(OPOST); + + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; + + if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { + perror("tcsetattr"); + exit(1); + } +} + +static void forward_io(int master_fd) { + fd_set rfds; + char buf[4096]; + ssize_t n; + + while (1) { + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + FD_SET(master_fd, &rfds); + + int maxfd = (master_fd > STDIN_FILENO) ? master_fd : STDIN_FILENO; + + if (select(maxfd + 1, &rfds, NULL, NULL, NULL) < 0) { + if (errno == EINTR) continue; + perror("select"); + exit(1); + } + + if (FD_ISSET(STDIN_FILENO, &rfds)) { + n = read(STDIN_FILENO, buf, sizeof(buf)); + if (n <= 0) { + if (n < 0) perror("read stdin"); + break; + } + if (write(master_fd, buf, n) != n) { + perror("write to master"); + exit(1); + } + } + + if (FD_ISSET(master_fd, &rfds)) { + n = read(master_fd, buf, sizeof(buf)); + if (n <= 0) { + if (n < 0 && errno != EIO) perror("read master"); + break; + } + if (write(STDOUT_FILENO, buf, n) != n) { + perror("write to stdout"); + exit(1); + } + } + } +} + +int main(int argc, char *argv[]) { + int master_fd; + char *slave_name; + struct winsize ws; + + master_fd = posix_openpt(O_RDWR | O_NOCTTY); + if (master_fd < 0) { + perror("posix_openpt"); + exit(1); + } + + if (grantpt(master_fd) < 0) { + perror("grantpt"); + exit(1); + } + + if (unlockpt(master_fd) < 0) { + perror("unlockpt"); + exit(1); + } + + slave_name = ptsname(master_fd); + if (!slave_name) { + perror("ptsname"); + exit(1); + } + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) { + ioctl(master_fd, TIOCSWINSZ, &ws); + } + + fprintf(stderr, "TAKETTY_PTY=%s\n", slave_name); + fflush(stderr); + + set_raw_mode(STDIN_FILENO); + + forward_io(master_fd); + + close(master_fd); + return 0; +} |
