3 * (c) Jack lange, Lei Xia, Peter Dinda 2010, 2013
10 #include <sys/ioctl.h>
12 #include <sys/types.h>
18 #include <linux/unistd.h>
25 #define STREAM_NAME_LEN 128
26 /* ^\ is the escape key we're going to use */
31 struct termios ourterm, oldterm;
36 if (tcgetattr(0,&oldterm)) {
37 fprintf(stderr,"Cannot get terminal attributes\n");
41 ourterm = oldterm; // clone existing terminal behavior
42 ourterm.c_lflag &= ~ICANON; // but without buffering
43 ourterm.c_lflag &= ~ECHO; // or echoing
44 ourterm.c_lflag &= ~ISIG; // or interrupt keys
45 ourterm.c_cc[VMIN] = 0; // or weird delays to compose
46 ourterm.c_cc[VTIME] = 0; // function keys (e.g., set raw)
47 //fprintf(stderr, "Calling tcsetattr.\n");
49 if (tcsetattr(0,TCSANOW,&ourterm)) {
50 fprintf(stderr,"Cannot set terminal attributes\n");
53 //fprintf(stderr,"term setup interactive\n");
55 //fprintf(stderr, "term setup noninteractive\n");
64 return -!!tcsetattr(0,TCSANOW,&oldterm);
70 int process_escapes(char in)
72 static int found_esc = 0;
78 fprintf(stderr,"Bye\n");
82 "Control codes: ^-\\ q: quit\n"
84 " ^-\\ ^-\\: send ^-\\;\n");
87 /* Pass the second escape! */
91 fprintf(stderr, "Unknown ESC sequence.\n");
95 } else if (in == ESC_KEY) {
103 int pump(int in, int out)
112 // data from the stream
113 check_esc = interactive && (in == STDIN_FILENO);
114 bytes_read = read(in, buf, check_esc ? 1 : BUF_LEN);
121 ret = process_escapes(buf[0]);
125 //fprintf(stderr,"read %d bytes\n", bytes_read);
129 while (bytes_written<bytes_read) {
130 thiswrite = write(out,&(buf[bytes_written]),bytes_read-bytes_written);
132 if (errno==EWOULDBLOCK) {
135 perror("Cannot write");
139 fprintf(stderr,"Hmm, surprise end-of-file on write\n");
142 bytes_written+=thiswrite;
145 //fprintf(stderr,"wrote %d bytes\n",bytes_written);
152 void signal_handler(int num)
158 fprintf(stderr,"Bye\n");
162 fprintf(stderr,"Unknown signal %d ignored\n",num);
166 int usage(char *argv0)
169 "usage: %s [-i] <vm_device> <stream_name>\n\n"
170 "Connects stdin/stdout to a bidirectional stream on the VM,\n"
171 "for example a serial port.\n\n"
172 "If the [-i] option is given, a terminal is assumed\n"
173 "and it is placed in non-echoing, interactive mode, \n"
174 "which is what you probably want for use as a console.\n",
178 int main(int argc, char* argv[])
183 char * vm_dev = NULL;
184 char stream[STREAM_NAME_LEN];
192 if (!strcasecmp(argv[1],"-i")) {
200 // noninteractive mode
205 vm_dev = argv[argstart];
207 if (strlen(argv[argstart+1]) >= STREAM_NAME_LEN) {
208 fprintf(stderr, "ERROR: Stream name longer than maximum size (%d)\n", STREAM_NAME_LEN);
212 memcpy(stream, argv[argstart+1], strlen(argv[argstart+1]));
214 vm_fd = open(vm_dev, O_RDONLY);
217 fprintf(stderr,"Error opening VM device: %s\n", vm_dev);
221 stream_fd = ioctl(vm_fd, V3_VM_SERIAL_CONNECT, stream);
226 fprintf(stderr,"Error opening VM device: %s\n", vm_dev);
231 fprintf(stderr,"Cannot setup terminal for %s mode\n", interactive ? "interactive" : "noninteraInteractive");
236 signal(SIGINT,signal_handler);
241 FD_SET(stream_fd, &rset);
242 FD_SET(STDIN_FILENO, &rset);
244 // wait for data from stdin or from the stream
245 ret = select(stream_fd + 1, &rset, NULL, NULL, NULL);
247 //fprintf(stderr,"select ret=%d\n", ret);
250 perror("select returned zero without a timer!");
256 perror("select failed");
261 // positive return - we have data on one or both
263 // check data from stream
264 if (FD_ISSET(stream_fd, &rset)) {
265 //fprintf(stderr,"stream is readable\n");
266 if (pump(stream_fd, STDOUT_FILENO)) {
267 //fprintf(stderr,"Cannot transfer all data from stream to stdout...\n");
272 // check data from stdin
274 if (FD_ISSET(STDIN_FILENO, &rset)) {
275 //fprintf(stderr,"stdin is readable\n");
276 if (pump(STDIN_FILENO,stream_fd)) {
277 //fprintf(stderr,"Cannot transfer all data from stdin to stream...\n");