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.


8a3733aa2b1b0040286ce59312e49ee3c2f0d83b
[palacios.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
101 int pump(int in, int out)
102 {
103     int bytes_read;
104     int bytes_written;
105     int thiswrite;
106     int check_esc;
107     int ret;
108     char buf[BUF_LEN];
109     
110     // data from the stream
111     check_esc = interactive && (in == STDIN_FILENO);
112     bytes_read = read(in, buf, check_esc ? 1 : BUF_LEN);
113     
114     if (bytes_read<0) { 
115         return -1;
116     }
117  
118     if (check_esc) {   
119       ret = process_escapes(buf[0]);
120       if (ret) return 0;
121     }
122
123     //fprintf(stderr,"read %d bytes\n", bytes_read);
124
125     bytes_written=0;
126
127     while (bytes_written<bytes_read) { 
128     thiswrite = write(out,&(buf[bytes_written]),bytes_read-bytes_written);
129     if (thiswrite<0) {
130         if (errno==EWOULDBLOCK) {
131                 continue;
132             } else {
133       perror("Cannot write");
134       return -1;
135     }}
136     if (thiswrite==0) {
137       fprintf(stderr,"Hmm, surprise end-of-file on write\n");
138       return -1;
139     }
140     bytes_written+=thiswrite;
141   }
142
143   //fprintf(stderr,"wrote %d bytes\n",bytes_written);
144   
145   return 0;
146 }
147
148
149
150 void signal_handler(int num)
151 {
152   switch (num) { 
153   case SIGINT:
154     close(stream_fd);
155     restore_term();
156     fprintf(stderr,"Bye\n");
157     exit(0);
158     break;
159   default:
160     fprintf(stderr,"Unknown signal %d ignored\n",num);
161   }   
162 }
163
164 int usage(char *argv0)
165 {
166     fprintf(stderr, 
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",
173         argv0);
174 }
175
176 int main(int argc, char* argv[]) 
177 {
178   int ret; 
179   int vm_fd;
180   fd_set rset;
181   char * vm_dev = NULL;
182   char stream[STREAM_NAME_LEN];
183   int argstart;
184   
185   if (argc < 2) {
186     usage(argv[0]);
187     exit(0);
188   }
189   
190   if (!strcasecmp(argv[1],"-i")) { 
191     interactive=1;
192     argstart=2;
193     if (argc < 3) {
194         usage(argv[0]);
195         exit(0);
196     } 
197   } else {
198     // noninteractive mode
199     interactive=0;
200     argstart=1;
201   }
202   
203   vm_dev = argv[argstart];
204   
205   if (strlen(argv[argstart+1]) >= STREAM_NAME_LEN) {
206     fprintf(stderr, "ERROR: Stream name longer than maximum size (%d)\n", STREAM_NAME_LEN);
207     exit(-1);
208   }
209
210   memcpy(stream, argv[argstart+1], strlen(argv[argstart+1]));
211   
212   vm_fd = open(vm_dev, O_RDONLY);
213   
214   if (vm_fd == -1) {
215     fprintf(stderr,"Error opening VM device: %s\n", vm_dev);
216     exit(-1);
217   }
218   
219   stream_fd = ioctl(vm_fd, V3_VM_SERIAL_CONNECT, stream); 
220   
221   close(vm_fd);
222   
223   if (stream_fd<0) { 
224       fprintf(stderr,"Error opening VM device: %s\n", vm_dev);
225       exit(-1);
226   }
227   
228   if (setup_term()) { 
229     fprintf(stderr,"Cannot setup terminal for %s mode\n", interactive ? "interactive" : "noninteraInteractive");
230     close(stream_fd);
231     exit(-1);
232   }
233   
234   signal(SIGINT,signal_handler);
235   
236   while (1) {
237     
238     FD_ZERO(&rset);
239     FD_SET(stream_fd, &rset);
240     FD_SET(STDIN_FILENO, &rset);
241     
242     // wait for data from stdin or from the stream
243     ret = select(stream_fd + 1, &rset, NULL, NULL, NULL);
244   
245     //fprintf(stderr,"select ret=%d\n", ret);
246
247     if (ret==0) {
248       perror("select returned zero without a timer!");
249       goto error;
250     } else if (ret<0) {
251       if (errno==EAGAIN) { 
252         continue;
253       } else {
254         perror("select failed");
255         goto error;
256       }
257     }
258     
259     // positive return - we have data on one or both
260     
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");
266         goto error;
267       }
268     }
269     
270     // check data from stdin
271     
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");
276         goto error;
277       }
278     }
279   } 
280   
281  error:
282   ret = -1;
283   goto out;
284   
285  done:
286   ret = 0;
287   goto out;
288   
289  out:
290   
291   close(stream_fd);
292   restore_term();
293   
294   return ret; 
295   
296
297 }
298
299