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.


e54d196566b82f84f47fc7ad71721a469420337b
[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 #define ESC_KEY '~'
27
28 int interactive=0;
29 int found_esc=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 pump(int in, int out)
71 {
72     int bytes_read;
73     int bytes_written;
74     int thiswrite;
75     int check_esc;
76     char buf[BUF_LEN];
77
78     // data from the stream
79     check_esc = interactive && (in == STDIN_FILENO);
80     bytes_read = read(in, buf, check_esc ? 1 : BUF_LEN);
81     
82     if (bytes_read<0) { 
83         return -1;
84     }
85     
86     if (check_esc) {
87           if (found_esc) {
88             switch(buf[0]) {
89                   case '.':
90             close(stream_fd);
91             restore_term();
92             fprintf(stderr,"Bye\n");
93                     exit(0);
94           case ESC_KEY:
95             /* Pass the second escape! */
96             break;
97                   default:
98             fprintf(stderr, "Unknown ESC sequence.\n");
99                     found_esc = 0;
100             return;
101         }
102           } else if (buf[0] == ESC_KEY)  {
103             found_esc = 1;
104         return;
105           }
106     }
107
108     fprintf(stderr,"read %d bytes\n", bytes_read);
109
110     bytes_written=0;
111
112     while (bytes_written<bytes_read) { 
113     thiswrite = write(out,&(buf[bytes_written]),bytes_read-bytes_written);
114     if (thiswrite<0) {
115         if (errno==EWOULDBLOCK) {
116                 continue;
117             } else {
118       perror("Cannot write");
119       return -1;
120     }}
121     if (thiswrite==0) {
122       fprintf(stderr,"Hmm, surprise end-of-file on write\n");
123       return -1;
124     }
125     bytes_written+=thiswrite;
126   }
127
128   fprintf(stderr,"wrote %d bytes\n",bytes_written);
129   
130   return 0;
131 }
132
133
134
135 void signal_handler(int num)
136 {
137   switch (num) { 
138   case SIGINT:
139     close(stream_fd);
140     restore_term();
141     fprintf(stderr,"Bye\n");
142     exit(0);
143     break;
144   default:
145     fprintf(stderr,"Unknown signal %d ignored\n",num);
146   }   
147 }
148
149 int main(int argc, char* argv[]) 
150 {
151   int ret; 
152   int vm_fd;
153   fd_set rset;
154   char * vm_dev = NULL;
155   char stream[STREAM_NAME_LEN];
156   int argstart;
157   
158   if (argc < 2) {
159     fprintf(stderr, 
160             "usage: v3_stream [-i] <vm_device> <stream_name>\n\n"
161             "Connects stdin/stdout to a bidirectional stream on the VM,\n"
162             "for example a serial port.\n\n"
163             "If the [-i] option is given, a terminal is assumed\n"
164             "and it is placed in non-echoing, interactive mode, \n"
165             "which is what you probably want for use as a console.\n");
166     exit(0);
167   }
168   
169   if (!strcasecmp(argv[1],"-i")) { 
170     interactive=1;
171     argstart=2;
172   } else {
173     // noninteractive mode
174     interactive=0;
175     argstart=1;
176   }
177   
178   vm_dev = argv[argstart];
179   
180   if (strlen(argv[argstart+1]) >= STREAM_NAME_LEN) {
181     fprintf(stderr, "ERROR: Stream name longer than maximum size (%d)\n", STREAM_NAME_LEN);
182     exit(-1);
183   }
184
185   memcpy(stream, argv[argstart+1], strlen(argv[argstart+1]));
186   
187   vm_fd = open(vm_dev, O_RDONLY);
188   
189   if (vm_fd == -1) {
190     fprintf(stderr,"Error opening VM device: %s\n", vm_dev);
191     exit(-1);
192   }
193   
194   stream_fd = ioctl(vm_fd, V3_VM_SERIAL_CONNECT, stream); 
195   
196   close(vm_fd);
197   
198   if (stream_fd<0) { 
199       fprintf(stderr,"Error opening VM device: %s\n", vm_dev);
200       exit(-1);
201   }
202   
203   if (setup_term()) { 
204     fprintf(stderr,"Cannot setup terminal for %s mode\n", interactive ? "interactive" : "noninteraInteractive");
205     close(stream_fd);
206     exit(-1);
207   }
208   
209   signal(SIGINT,signal_handler);
210   
211   while (1) {
212     
213     FD_ZERO(&rset);
214     FD_SET(stream_fd, &rset);
215     FD_SET(STDIN_FILENO, &rset);
216     
217     // wait for data from stdin or from the stream
218     ret = select(stream_fd + 1, &rset, NULL, NULL, NULL);
219   
220     fprintf(stderr,"select ret=%d\n", ret);
221
222     if (ret==0) {
223       perror("select returned zero without a timer!");
224       goto error;
225     } else if (ret<0) {
226       if (errno==EAGAIN) { 
227         continue;
228       } else {
229         perror("select failed");
230         goto error;
231       }
232     }
233     
234     // positive return - we have data on one or both
235     
236     // check data from stream
237     if (FD_ISSET(stream_fd, &rset)) {
238       fprintf(stderr,"stream is readable\n");
239       if (pump(stream_fd, STDOUT_FILENO)) { 
240         fprintf(stderr,"Cannot transfer all data from stream to stdout...\n");
241         goto error;
242       }
243     }
244     
245     // check data from stdin
246     
247     if (FD_ISSET(STDIN_FILENO, &rset)) {
248       fprintf(stderr,"stdin is readable\n");
249       if (pump(STDIN_FILENO,stream_fd)) { 
250         fprintf(stderr,"Cannot transfer all data from stdin to stream...\n");
251         goto error;
252       }
253     }
254   } 
255   
256  error:
257   ret = -1;
258   goto out;
259   
260  done:
261   ret = 0;
262   goto out;
263   
264  out:
265   
266   close(stream_fd);
267   restore_term();
268   
269   return ret; 
270   
271
272 }
273
274