Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


v3_stream fix for escape character handling
[palacios.releases.git] / linux_usr / v3_stream.c
1 /* 
2  * V3 Stream Utility
3  * (c) Jack lange, Lei Xia, Peter Dinda 2010, 2013
4  */
5
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <fcntl.h> 
10 #include <sys/ioctl.h> 
11 #include <sys/stat.h> 
12 #include <sys/types.h> 
13 #include <unistd.h>
14 #include <string.h>
15 #include <fcntl.h>
16 #include <pthread.h>
17 #include <errno.h>
18 #include <linux/unistd.h>
19 #include <termios.h>
20 #include <signal.h>
21
22 #include "v3_ctrl.h"
23
24 #define BUF_LEN  512
25 #define STREAM_NAME_LEN 128
26 /* ^\ is the escape key we're going to use */
27 #define ESC_KEY 0x1c
28
29 int interactive=0;
30 int stream_fd=0;
31 struct termios ourterm, oldterm;
32
33 int setup_term()
34 {
35   if (interactive) { 
36     if (tcgetattr(0,&oldterm)) { 
37       fprintf(stderr,"Cannot get terminal attributes\n");
38       return -1;
39     }
40     
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");
48
49     if (tcsetattr(0,TCSANOW,&ourterm)) { 
50       fprintf(stderr,"Cannot set terminal attributes\n");
51       return -1;
52     }  
53     //fprintf(stderr,"term setup interactive\n");
54   } else {
55     //fprintf(stderr, "term setup noninteractive\n");
56   }
57   
58   return 0;
59 }
60
61 int restore_term()
62 {
63   if (interactive) { 
64     return -!!tcsetattr(0,TCSANOW,&oldterm);
65   } else {
66     return 0;
67   }
68 }
69
70 int process_escapes(char in)
71 {
72   static int found_esc = 0;
73   if (found_esc) {
74     switch(in) {
75       case 'q':
76         close(stream_fd);
77         restore_term();
78         fprintf(stderr,"Bye\n");
79                 exit(0);
80       case 'h':
81         fprintf(stderr, 
82                 "Control codes: ^-\\ q: quit\n"
83                 "               ^-\\ h: help\n"
84                 "               ^-\\ ^-\\: send ^-\\;\n");
85         return 1;
86       case ESC_KEY:
87         /* Pass the second escape! */
88             found_esc = 0;
89         return 0;
90           default:
91         fprintf(stderr, "Unknown ESC sequence.\n");
92             found_esc = 0;
93         return 1;
94         }
95   } else if (in == ESC_KEY)  {
96         found_esc = 1;
97     return 1;
98   }
99
100   return 0;
101 }
102
103 int pump(int in, int out)
104 {
105     int bytes_read;
106     int bytes_written;
107     int thiswrite;
108     int check_esc;
109     int ret;
110     char buf[BUF_LEN];
111     
112     // data from the stream
113     check_esc = interactive && (in == STDIN_FILENO);
114     bytes_read = read(in, buf, check_esc ? 1 : BUF_LEN);
115     
116     if (bytes_read<0) { 
117         return -1;
118     }
119  
120     if (check_esc) {   
121       ret = process_escapes(buf[0]);
122       if (ret) return 0;
123     }
124
125     //fprintf(stderr,"read %d bytes\n", bytes_read);
126
127     bytes_written=0;
128
129     while (bytes_written<bytes_read) { 
130     thiswrite = write(out,&(buf[bytes_written]),bytes_read-bytes_written);
131     if (thiswrite<0) {
132         if (errno==EWOULDBLOCK) {
133                 continue;
134             } else {
135       perror("Cannot write");
136       return -1;
137     }}
138     if (thiswrite==0) {
139       fprintf(stderr,"Hmm, surprise end-of-file on write\n");
140       return -1;
141     }
142     bytes_written+=thiswrite;
143   }
144
145   //fprintf(stderr,"wrote %d bytes\n",bytes_written);
146   
147   return 0;
148 }
149
150
151
152 void signal_handler(int num)
153 {
154   switch (num) { 
155   case SIGINT:
156     close(stream_fd);
157     restore_term();
158     fprintf(stderr,"Bye\n");
159     exit(0);
160     break;
161   default:
162     fprintf(stderr,"Unknown signal %d ignored\n",num);
163   }   
164 }
165
166 int usage(char *argv0)
167 {
168     fprintf(stderr, 
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",
175         argv0);
176 }
177
178 int main(int argc, char* argv[]) 
179 {
180   int ret; 
181   int vm_fd;
182   fd_set rset;
183   char * vm_dev = NULL;
184   char stream[STREAM_NAME_LEN];
185   int argstart;
186   
187   if (argc < 2) {
188     usage(argv[0]);
189     exit(0);
190   }
191   
192   if (!strcasecmp(argv[1],"-i")) { 
193     interactive=1;
194     argstart=2;
195     if (argc < 3) {
196         usage(argv[0]);
197         exit(0);
198     } 
199   } else {
200     // noninteractive mode
201     interactive=0;
202     argstart=1;
203   }
204   
205   vm_dev = argv[argstart];
206   
207   if (strlen(argv[argstart+1]) >= STREAM_NAME_LEN) {
208     fprintf(stderr, "ERROR: Stream name longer than maximum size (%d)\n", STREAM_NAME_LEN);
209     exit(-1);
210   }
211
212   memcpy(stream, argv[argstart+1], strlen(argv[argstart+1]));
213   
214   vm_fd = open(vm_dev, O_RDONLY);
215   
216   if (vm_fd == -1) {
217     fprintf(stderr,"Error opening VM device: %s\n", vm_dev);
218     exit(-1);
219   }
220   
221   stream_fd = ioctl(vm_fd, V3_VM_SERIAL_CONNECT, stream); 
222   
223   close(vm_fd);
224   
225   if (stream_fd<0) { 
226       fprintf(stderr,"Error opening VM device: %s\n", vm_dev);
227       exit(-1);
228   }
229   
230   if (setup_term()) { 
231     fprintf(stderr,"Cannot setup terminal for %s mode\n", interactive ? "interactive" : "noninteraInteractive");
232     close(stream_fd);
233     exit(-1);
234   }
235   
236   signal(SIGINT,signal_handler);
237   
238   while (1) {
239     
240     FD_ZERO(&rset);
241     FD_SET(stream_fd, &rset);
242     FD_SET(STDIN_FILENO, &rset);
243     
244     // wait for data from stdin or from the stream
245     ret = select(stream_fd + 1, &rset, NULL, NULL, NULL);
246   
247     //fprintf(stderr,"select ret=%d\n", ret);
248
249     if (ret==0) {
250       perror("select returned zero without a timer!");
251       goto error;
252     } else if (ret<0) {
253       if (errno==EAGAIN) { 
254         continue;
255       } else {
256         perror("select failed");
257         goto error;
258       }
259     }
260     
261     // positive return - we have data on one or both
262     
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");
268         goto error;
269       }
270     }
271     
272     // check data from stdin
273     
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");
278         goto error;
279       }
280     }
281   } 
282   
283  error:
284   ret = -1;
285   goto out;
286   
287  done:
288   ret = 0;
289   goto out;
290   
291  out:
292   
293   close(stream_fd);
294   restore_term();
295   
296   return ret; 
297   
298
299 }
300
301