sos-code-article10/extra/termslave.c

131 lines
2.9 KiB
C

/* Unix pty slave program -- David Decotigny 2005
License: GNU GPL version 2
Most of it taken from the GNU C library doc examples */
#include <utmp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
/**
* @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;
}