#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include 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; }