/* Unix pty slave program -- David Decotigny 2005 License: GNU GPL version 2 Most of it taken from the GNU C library doc examples */ #include #include #include #include #include #include #include #include /** * @file termslave.c * * Linux pseudo-TTY slave program. To be used with "qemu -monitor pty" * to access qemu's monitor from any linux terminal. To use it, launch * a "qemu -monitor pty" in one terminal, take a look at the first * line stating "char device redirected to /dev/pts/4" for example, * and lauch the termslave program as "./termslave /dev/pts/4" in * another terminal. * * To make this correctly work, one has to apply the * patch-qemu-pty.diff patch to qemu < 0.8.0 (qemu 0.8.0 and beyond * already includes this patch). * * This program also works with the "-serial pty" flag of qemu. It can * be used to send commands to the SOS serial-line shell (article 9). */ /* Use this variable to remember original terminal attributes. */ struct termios saved_attributes; static void reset_input_mode (void) { tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes); } static void set_input_mode (void) { struct termios tattr; /* Make sure stdin is a terminal. */ if (!isatty (STDIN_FILENO)) { fprintf (stderr, "Not a terminal.\n"); exit (EXIT_FAILURE); } /* Save the terminal attributes so we can restore them later. */ tcgetattr (STDIN_FILENO, &saved_attributes); atexit (reset_input_mode); /* Set the funny terminal modes. */ tcgetattr (STDIN_FILENO, &tattr); tattr.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); tattr.c_lflag &= ~(ICANON|ECHO); tattr.c_cflag |= CLOCAL; tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr); } int main (int argc, char *argv[]) { int term; if (argc < 2) { fprintf(stderr, "Usage: %s /dev/pts/number\n", argv[0]); return -1; } term = open(argv[1], O_RDWR); if (term < 0) { perror("open"); return -1; } if (! isatty(term)) { fprintf(stderr, "%s is not a valid terminal\n", argv[1]); return -1; } set_input_mode(); while (1) { fd_set cur_set; FD_ZERO(& cur_set); FD_SET(STDIN_FILENO, & cur_set); FD_SET(term, & cur_set); if (select(FD_SETSIZE, & cur_set, NULL, NULL, NULL) < 1) continue; if (FD_ISSET(term, & cur_set)) { char buf[1024]; int len = read(term, buf, sizeof(buf)); if (len >= 1) write(STDOUT_FILENO, buf, len); else { fprintf(stderr, "Master exitted\n"); break; } } if (FD_ISSET(STDIN_FILENO, & cur_set)) { char c; if (read(STDIN_FILENO, &c, 1) == 1) { if (c == 0x4) /* ctrl-D */ break; write(term, &c, 1); } else break; } } return 0; }