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) {
101 int pump(int in, int out)
110 // data from the stream
111 check_esc = interactive && (in == STDIN_FILENO);
112 bytes_read = read(in, buf, check_esc ? 1 : BUF_LEN);
119 ret = process_escapes(buf[0]);
123 //fprintf(stderr,"read %d bytes\n", bytes_read);
127 while (bytes_written<bytes_read) {
128 thiswrite = write(out,&(buf[bytes_written]),bytes_read-bytes_written);
130 if (errno==EWOULDBLOCK) {
133 perror("Cannot write");
137 fprintf(stderr,"Hmm, surprise end-of-file on write\n");
140 bytes_written+=thiswrite;
143 //fprintf(stderr,"wrote %d bytes\n",bytes_written);
150 void signal_handler(int num)
156 fprintf(stderr,"Bye\n");
160 fprintf(stderr,"Unknown signal %d ignored\n",num);
164 int usage(char *argv0)
167 "usage: %s [-i] <vm_device> <stream_name>\n\n"
168 "Connects stdin/stdout to a bidirectional stream on the VM,\n"
169 "for example a serial port.\n\n"
170 "If the [-i] option is given, a terminal is assumed\n"
171 "and it is placed in non-echoing, interactive mode, \n"
172 "which is what you probably want for use as a console.\n",
176 int main(int argc, char* argv[])
181 char * vm_dev = NULL;
182 char stream[STREAM_NAME_LEN];
190 if (!strcasecmp(argv[1],"-i")) {
198 // noninteractive mode
203 vm_dev = argv[argstart];
205 if (strlen(argv[argstart+1]) >= STREAM_NAME_LEN) {
206 fprintf(stderr, "ERROR: Stream name longer than maximum size (%d)\n", STREAM_NAME_LEN);
210 memcpy(stream, argv[argstart+1], strlen(argv[argstart+1]));
212 vm_fd = open(vm_dev, O_RDONLY);
215 fprintf(stderr,"Error opening VM device: %s\n", vm_dev);
219 stream_fd = ioctl(vm_fd, V3_VM_SERIAL_CONNECT, stream);
224 fprintf(stderr,"Error opening VM device: %s\n", vm_dev);
229 fprintf(stderr,"Cannot setup terminal for %s mode\n", interactive ? "interactive" : "noninteraInteractive");
234 signal(SIGINT,signal_handler);
239 FD_SET(stream_fd, &rset);
240 FD_SET(STDIN_FILENO, &rset);
242 // wait for data from stdin or from the stream
243 ret = select(stream_fd + 1, &rset, NULL, NULL, NULL);
245 //fprintf(stderr,"select ret=%d\n", ret);
248 perror("select returned zero without a timer!");
254 perror("select failed");
259 // positive return - we have data on one or both
261 // check data from stream
262 if (FD_ISSET(stream_fd, &rset)) {
263 //fprintf(stderr,"stream is readable\n");
264 if (pump(stream_fd, STDOUT_FILENO)) {
265 //fprintf(stderr,"Cannot transfer all data from stream to stdout...\n");
270 // check data from stdin
272 if (FD_ISSET(STDIN_FILENO, &rset)) {
273 //fprintf(stderr,"stdin is readable\n");
274 if (pump(STDIN_FILENO,stream_fd)) {
275 //fprintf(stderr,"Cannot transfer all data from stdin to stream...\n");