X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=linux_usr%2Fv3_stream.c;h=f3157d7fdbded892ef19684772804ef624ed28de;hb=4e43946f01f687361197dc9571b7df02ae20de30;hp=45d5eb277bae6b61687a7436708f08282a8eb9c1;hpb=035ac752dc4e0eda744205896a9c7c92689bea42;p=palacios.git diff --git a/linux_usr/v3_stream.c b/linux_usr/v3_stream.c index 45d5eb2..f3157d7 100644 --- a/linux_usr/v3_stream.c +++ b/linux_usr/v3_stream.c @@ -1,6 +1,6 @@ /* - * V3 Console utility - * (c) Jack lange & Lei Xia, 2010 + * V3 Stream Utility + * (c) Jack lange, Lei Xia, Peter Dinda 2010, 2013 */ @@ -15,99 +15,287 @@ #include #include #include -#include -#include - +#include +#include +#include #include "v3_ctrl.h" -#define BUF_LEN 1025 +#define BUF_LEN 512 #define STREAM_NAME_LEN 128 +/* ^\ is the escape key we're going to use */ +#define ESC_KEY 0x1c -int main(int argc, char* argv[]) { - int vm_fd; - fd_set rset; - char * vm_dev = NULL; - char stream[STREAM_NAME_LEN]; - char cons_buf[BUF_LEN]; - int stream_fd = 0; - - if (argc < 2) { - printf("usage: v3_stream \n"); - return -1; - } - - vm_dev = argv[1]; +int interactive=0; +int stream_fd=0; +struct termios ourterm, oldterm; - if (strlen(argv[2]) >= STREAM_NAME_LEN) { - printf("ERROR: Stream name longer than maximum size (%d)\n", STREAM_NAME_LEN); - return -1; +int setup_term() +{ + if (interactive) { + if (tcgetattr(0,&oldterm)) { + fprintf(stderr,"Cannot get terminal attributes\n"); + return -1; } + + ourterm = oldterm; // clone existing terminal behavior + ourterm.c_lflag &= ~ICANON; // but without buffering + ourterm.c_lflag &= ~ECHO; // or echoing + ourterm.c_lflag &= ~ISIG; // or interrupt keys + ourterm.c_cc[VMIN] = 0; // or weird delays to compose + ourterm.c_cc[VTIME] = 0; // function keys (e.g., set raw) + //fprintf(stderr, "Calling tcsetattr.\n"); - memcpy(stream, argv[2], strlen(argv[2])); + if (tcsetattr(0,TCSANOW,&ourterm)) { + fprintf(stderr,"Cannot set terminal attributes\n"); + return -1; + } + //fprintf(stderr,"term setup interactive\n"); + } else { + //fprintf(stderr, "term setup noninteractive\n"); + } + + return 0; +} - vm_fd = open(vm_dev, O_RDONLY); - if (vm_fd == -1) { - printf("Error opening VM device: %s\n", vm_dev); - return -1; - } +int restore_term() +{ + if (interactive) { + return -!!tcsetattr(0,TCSANOW,&oldterm); + } else { + return 0; + } +} + +int process_escapes(char in) +{ + static int found_esc = 0; + if (found_esc) { + switch(in) { + case 'q': + close(stream_fd); + restore_term(); + fprintf(stderr,"Bye\n"); + exit(0); + case 'h': + fprintf(stderr, + "Control codes: ^-\\ q: quit\n" + " ^-\\ h: help\n" + " ^-\\ ^-\\: send ^-\\;\n"); + return 1; + case ESC_KEY: + /* Pass the second escape! */ + found_esc = 0; + return 0; + default: + fprintf(stderr, "Unknown ESC sequence.\n"); + found_esc = 0; + return 1; + } + } else if (in == ESC_KEY) { + found_esc = 1; + return 1; + } - stream_fd = ioctl(vm_fd, V3_VM_SERIAL_CONNECT, stream); + return 0; +} - /* Close the file descriptor. */ - close(vm_fd); +int pump(int in, int out) +{ + int bytes_read; + int bytes_written; + int thiswrite; + int check_esc; + int ret; + char buf[BUF_LEN]; + + // data from the stream + check_esc = interactive && (in == STDIN_FILENO); + bytes_read = read(in, buf, check_esc ? 1 : BUF_LEN); + + if (bytes_read<0) { + return -1; + } - if (stream_fd < 0) { - printf("Error opening stream Console\n"); - return -1; + if (check_esc) { + ret = process_escapes(buf[0]); + if (ret) return 0; } - while (1) { - int ret; - int bytes_read = 0; - char in_buf[512]; - - memset(cons_buf, 0, BUF_LEN); + //fprintf(stderr,"read %d bytes\n", bytes_read); + bytes_written=0; - FD_ZERO(&rset); - FD_SET(stream_fd, &rset); - FD_SET(STDIN_FILENO, &rset); - - ret = select(stream_fd + 1, &rset, NULL, NULL, NULL); - - if (ret == 0) { - continue; - } else if (ret == -1) { - perror("Select returned error\n"); - return -1; - } + while (bytes_written \n\n" + "Connects stdin/stdout to a bidirectional stream on the VM,\n" + "for example a serial port.\n\n" + "If the [-i] option is given, a terminal is assumed\n" + "and it is placed in non-echoing, interactive mode, \n" + "which is what you probably want for use as a console.\n", + argv0); +} +int main(int argc, char* argv[]) +{ + int ret; + int vm_fd; + fd_set rset; + char * vm_dev = NULL; + char stream[STREAM_NAME_LEN]; + int argstart; + + if (argc < 3) { + usage(argv[0]); + exit(0); + } + + if (!strcasecmp(argv[1],"-i")) { + interactive=1; + argstart=2; + if (argc < 4) { + usage(argv[0]); + exit(0); } + } else { + // noninteractive mode + interactive=0; + argstart=1; + } + + vm_dev = argv[argstart]; + + if (strlen(argv[argstart+1]) >= STREAM_NAME_LEN) { + fprintf(stderr, "ERROR: Stream name longer than maximum size (%d)\n", STREAM_NAME_LEN); + exit(-1); + } + memcpy(stream, argv[argstart+1], strlen(argv[argstart+1])+1); + + vm_fd = open(vm_dev, O_RDONLY); + + if (vm_fd == -1) { + fprintf(stderr,"Error opening VM device: %s\n", vm_dev); + exit(-1); + } + + stream_fd = ioctl(vm_fd, V3_VM_SERIAL_CONNECT, stream); + + close(vm_fd); + + if (stream_fd<0) { + fprintf(stderr,"Error opening VM device: %s\n", vm_dev); + exit(-1); + } + + if (setup_term()) { + fprintf(stderr,"Cannot setup terminal for %s mode\n", interactive ? "interactive" : "noninteraInteractive"); + close(stream_fd); + exit(-1); + } + + signal(SIGINT,signal_handler); + + while (1) { + + FD_ZERO(&rset); + FD_SET(stream_fd, &rset); + FD_SET(STDIN_FILENO, &rset); + + // wait for data from stdin or from the stream + ret = select(stream_fd + 1, &rset, NULL, NULL, NULL); + + //fprintf(stderr,"select ret=%d\n", ret); + + if (ret==0) { + perror("select returned zero without a timer!"); + goto error; + } else if (ret<0) { + if (errno==EAGAIN) { + continue; + } else { + perror("select failed"); + goto error; + } + } + + // positive return - we have data on one or both + + // check data from stream + if (FD_ISSET(stream_fd, &rset)) { + //fprintf(stderr,"stream is readable\n"); + if (pump(stream_fd, STDOUT_FILENO)) { + //fprintf(stderr,"Cannot transfer all data from stream to stdout...\n"); + goto error; + } + } + + // check data from stdin + + if (FD_ISSET(STDIN_FILENO, &rset)) { + //fprintf(stderr,"stdin is readable\n"); + if (pump(STDIN_FILENO,stream_fd)) { + //fprintf(stderr,"Cannot transfer all data from stdin to stream...\n"); + goto error; + } + } + } + + error: + ret = -1; + goto out; + + done: + ret = 0; + goto out; + + out: + + close(stream_fd); + restore_term(); + + return ret; + - return 0; }