Several BugFixes (see bug-reports from "accounts")
[vde.git] / vde-2 / src / vdeq.c
blobb76cd78dbfc2000f97b310ba321c824975e4978a
1 /* Copyright 2003 Renzo Davoli
2 * TNX: 2005.11.18 new syntax mgmt patch by Iain McFarlane <imcfarla@tiscali.co.uk>
3 * Licensed under the GPL
4 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <signal.h>
9 #include <errno.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <stdint.h>
13 #include <libgen.h>
14 #include <signal.h>
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
17 #include <sys/un.h>
18 #include <sys/uio.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <pwd.h>
23 #include <config.h>
24 #include <vde.h>
25 #include <vdecommon.h>
27 #include <libvdeplug.h>
29 #define SWITCH_MAGIC 0xfeedface
30 #define BUFSIZE 2048
31 #define ETH_ALEN 6
32 #define MAXDESCR 128
34 int exit_value = 256; /* out of range for exit status possible values */
35 static int nb_nics;
36 VDECONN **conn;
38 unsigned char bufin[BUFSIZE];
40 struct pollfd *pollv;
42 char *filename;
43 char *vdeqname;
44 #define NUMW 10
46 static int countnics(const char *s)
48 register int nics=1;
49 while (*s) {
50 if (*s==',') nics++;
51 s++;
53 return nics;
56 static int countnewnics(int argc,char *argv[])
58 register int nics=0;
59 register int netflag=0;
60 while (argc > 0) {
61 if (strcmp(argv[0],"-net")==0)
62 netflag=1;
63 else {
64 if (netflag && (strncmp(argv[0],"vde",3)==0))
65 nics++;
66 netflag=0;
68 argv++;
69 argc--;
71 return nics;
74 static int isdaemonize(int argc,char *argv[])
76 register int daemonize=0;
77 if(strcmp(filename,"qemu")==0){
78 int daemonadds=0;
79 while (argc > 0) {
80 if (strcmp(argv[0],"-daemonize")==0)
81 daemonize=1;
82 if ((strcmp(argv[0],"-vnc")==0) || (strcmp(argv[0],"-nographic")==0))
83 daemonadds=1;
84 argv++;
85 argc--;
87 if(daemonize && !daemonadds) daemonize = 0;
89 else {
90 while (argc > 0 && !daemonize) {
91 if (strcmp(argv[0],"-daemonize")==0)
92 daemonize=1;
93 else {
94 argv++;
95 argc--;
99 return daemonize;
103 static void usage(void)
105 if (strcmp(vdeqname,"vdeq") != 0 && strncmp(vdeqname,"vde",3)==0) {
106 fprintf(stderr,"Usage: %s [-h]\n"
107 "\t %s ...qemu options... -net vde[,vlan=n][,sock=sock] ... \n"
108 "Old syntax:\n"
109 "\t %s [-sock sock1 [,sock2...]] qemu_options\n"
110 "\t (%s executes a qemu machine named %s, \n\t output of \"%s -h\" follows)\n\n", vdeqname,vdeqname,vdeqname,vdeqname,filename,filename);
111 execlp(filename,filename,"-h",(char *) 0);
112 } else {
113 fprintf(stderr,"Usage: %s [-h]\n"
114 "\t %s qemu_executable ...qemu options... -net vde[,vlan=n][,sock=sock] ... \n"
115 "Old syntax:\n"
116 "\t %s qemu_executable [-sock sock1 [,sock2...]] qemu_options\n", vdeqname,vdeqname, vdeqname);
117 exit(0);
121 static void cleanup()
123 register int i;
124 for (i=0; i<nb_nics; i++) {
125 if (conn[i] != NULL)
126 vde_close(conn[i]);
130 static void sig_handler(int sig)
132 fprintf(stderr,"%s: Caught signal %d, cleaning up and exiting\n", vdeqname, sig);
133 cleanup();
134 signal(sig, SIG_DFL);
135 if (sig == SIGTERM)
136 _exit(0);
137 else
138 kill(getpid(), sig);
141 static void setsighandlers()
143 /* setting signal handlers.
144 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
145 * ignores all the others signals which could cause termination. */
146 struct { int sig; const char *name; int ignore; } signals[] = {
147 { SIGHUP, "SIGHUP", 0 },
148 { SIGINT, "SIGINT", 0 },
149 { SIGPIPE, "SIGPIPE", 1 },
150 { SIGALRM, "SIGALRM", 1 },
151 { SIGTERM, "SIGTERM", 0 },
152 { SIGUSR1, "SIGUSR1", 1 },
153 { SIGUSR2, "SIGUSR2", 1 },
154 { SIGPROF, "SIGPROF", 1 },
155 { SIGVTALRM, "SIGVTALRM", 1 },
156 #ifdef VDE_LINUX
157 { SIGPOLL, "SIGPOLL", 1 },
158 #ifdef SIGSTKFLT
159 { SIGSTKFLT, "SIGSTKFLT", 1 },
160 #endif
161 { SIGIO, "SIGIO", 1 },
162 { SIGPWR, "SIGPWR", 1 },
163 #ifdef SIGUNUSED
164 { SIGUNUSED, "SIGUNUSED", 1 },
165 #endif
166 #endif
167 #ifdef VDE_DARWIN
168 { SIGXCPU, "SIGXCPU", 1 },
169 { SIGXFSZ, "SIGXFSZ", 1 },
170 #endif
171 { 0, NULL, 0 }
174 int i;
175 for(i = 0; signals[i].sig != 0; i++)
176 if(signal(signals[i].sig,
177 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
178 fprintf(stderr,"Setting handler for %s: %s\n", signals[i].name,
179 strerror(errno));
182 static void sigchld_handler(int sig)
184 int ev;
185 wait(&ev);
186 if (WIFEXITED(ev))
187 exit_value=WEXITSTATUS(ev);
188 else
189 exit_value=255;
192 static int checkver(char *prog)
194 char *newargv[3];
195 int fd[2];
196 int f,len,version=0;
197 char buf[257];
198 newargv[0]=prog;
199 newargv[1]="-h";
200 newargv[2]=0;
201 buf[256]=0;
202 if (pipe(fd) < 0) {
203 perror("pipe");
204 exit(1);
206 if ((f=fork()) > 0) {
207 int status;
208 close(fd[1]);
209 len=read(fd[0],buf,256);
210 if (len>0) {
211 int i;
212 for(i=0;i<len && version==0;i++) {
213 if(strncmp(buf+i,"version ",8)==0) {
214 int v1,v2,v3;
215 sscanf(buf+i+8,"%d.%d.%d",&v1,&v2,&v3);
216 version=(v1 << 16) + (v2 << 8) + v3;
220 close(fd[0]);
221 waitpid(f,&status,0);
223 else if (f==0) {
224 close(fd[0]);
225 dup2(fd[1],1);
226 dup2(fd[1],2);
227 close(fd[1]);
228 if (execvp(prog,newargv) < 0) {
229 exit(1);
232 return version;
235 static char *parsevdearg(char *arg,char **sock,int *pport, int fd)
237 char newarg[128];
238 int vlan=0;
239 *sock=NULL;
240 *pport=0;
241 printf("arg %s\n", arg);
242 while(*arg){
243 while (*arg==',') arg++;
244 if (strncmp(arg,"vlan=",5)==0) {
245 vlan=atoi(arg+5);
246 while (*arg != 0 && *arg != ',')
247 arg++;
249 else if (strncmp(arg,"sock=",5)==0) {
250 arg+=5;
251 if (*arg=='\"') {
252 arg++;
253 *sock=arg;
254 while (*arg != 0 && *arg != '\"')
255 arg++;
256 } else {
257 *sock=arg;
258 while (*arg != 0 && *arg != ',')
259 arg++;
261 if (*arg != 0) {
262 *arg=0; arg++;
265 else if (strncmp(arg,"port=",5)==0) {
266 *pport=atoi(arg+5);
267 while (*arg != 0 && *arg != ',')
268 arg++;
270 else {
271 printf("WARNING: unknown parameter in argument %s\n", arg);
272 exit(-1);
276 snprintf(newarg,128,"tap,vlan=%d,fd=%d%s%s",vlan,fd,(*arg == 0)?"":",",arg);
277 return strdup(newarg);
280 int main(int argc, char **argv)
282 char *argsock=NULL,**sockname;
283 int *ports;
284 int result;
285 register ssize_t nx;
286 int newargc;
287 int daemonize;
288 char **newargv;
289 typedef int pair[2];
290 pair *sp;
291 register int i,j;
292 int oldsyntax=0;
293 int newsyntax=0;
294 int ver;
295 mode_t mode = 0700;
296 vdeqname=basename(argv[0]);
298 fprintf(stderr,
299 "NOTE: %s is now DEPRECATED -- both QEMU and KVM have native support for\n"
300 " VDE. This binary will be removed soon from the distribution, consider\n"
301 " stopping using it.\n\n", vdeqname);
303 //callerpwd=getpwuid(getuid());
304 /* OLD SYNTAX MGMT */
305 if (strncmp(vdeqname,"vdeo",4) == 0) {
306 oldsyntax=1;
307 if (strcmp(vdeqname,"vdeoq") != 0) {
308 filename=vdeqname+4;
311 else if (strcmp(vdeqname,"vdeq") != 0 && strncmp(vdeqname,"vde",3)==0) {
312 filename=vdeqname+3;
314 else if (argc > 1) {
315 filename=argv[1];
316 argc--;
317 argv++;
318 } else {
319 usage();
321 daemonize=isdaemonize(argc-1,argv+1);
322 if ((ver=checkver(filename)) < 0x800)
323 oldsyntax=1;
324 if (!oldsyntax) {
325 nb_nics=countnewnics(argc-1,argv+1);
326 if (nb_nics > 0)
327 newsyntax=1;
329 if ((argc > 1 && (
330 strcmp(argv[1],"-h")==0 ||
331 strcmp(argv[1],"-help")==0 ||
332 strcmp(argv[1],"--help")==0
333 )) || (
334 strcmp(filename,"-h")==0 ||
335 strcmp(filename,"-help")==0 ||
336 strcmp(filename,"--help")==0
337 )) {
338 usage();
339 } else if (argc > 2 && (
340 (strcmp(argv[1],"-vdesock")==0) ||
341 (strcmp(argv[1],"-sock")==0) ||
342 (strcmp(argv[1],"-unix")==0))
344 argsock=argv[2];
345 argv+=2;
346 argc-=2;
347 } else
348 argsock=NULL;
350 if (argc > 2 && ((strcmp(argv[1],"--mod")==0))
352 sscanf(argv[2],"%o",(unsigned int *)&mode);
353 argv+=2;
354 argc-=2;
357 if (!newsyntax) {
358 if (argsock == NULL)
359 nb_nics=1;
360 else
361 nb_nics=countnics(argsock);
362 if (!oldsyntax && nb_nics > 1)
363 fprintf(stderr,
364 "Warning: all the vde connections will be connected to one net interface\n"
365 " to configure several interface use the new syntax -net vde\n");
368 if ((sp= (pair *) malloc(nb_nics * 2 * sizeof (int)))<0) {
369 perror("malloc nics");
370 exit(1);
373 if ((conn=(VDECONN **) calloc (nb_nics,sizeof(VDECONN *))) <0) {
374 perror("calloc conn");
375 exit(1);
378 for (i=0; i<nb_nics; i++) {
379 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp[i]) < 0){
380 perror("socketpair");
381 exit(1);
385 if ((sockname= (char **) malloc(sizeof(char *) * nb_nics))<0) {
386 perror("malloc sockname");
387 exit(1);
389 if ((ports= (int *) calloc(nb_nics, sizeof(int)))<0) {
390 perror("malloc ports");
391 exit(1);
394 if (newsyntax)
396 int netflag;
397 int vdeint;
398 newargv=argv;
399 newargc=argc;
400 for (i=1,netflag=0,vdeint=0;i<argc;i++) {
401 if (strcmp(argv[i],"-net")==0)
402 netflag=1;
403 else {
404 if (netflag && strncmp(argv[i],"vde",3) == 0)
406 argv[i]=parsevdearg(argv[i]+3,&sockname[vdeint],&ports[vdeint],sp[vdeint][0]);
407 vdeint++;
409 netflag=0;
412 } else
414 if (argsock==NULL)
415 sockname[0]=NULL;
416 else
418 register char *s=argsock;
419 register char oldch;
420 i=0;
421 do {
422 sockname[i++]=s;
423 while (*s != ',' && *s != '\0')
424 s++;
425 oldch=*s;
426 *s=0;
427 s++;
428 } while (oldch != 0);
431 /* printf("-- %s --\n",numfd);
432 printf("as %s\n",argsock);
433 for (i=0; i<nb_nics; i++)
434 printf("%d -> %s\n",i,sockname[i]); */
435 newargc=argc+2+(2*nb_nics);
436 if ((newargv=(char **) malloc ((newargc+1)* sizeof(char *))) <0) {
437 perror("malloc");
438 exit(1);
441 newargv[0]=filename;
442 if (oldsyntax) {
443 for (i=0; i<nb_nics; i++) {
444 char numfd[10];
445 sprintf(numfd,"%d",sp[i][0]);
446 newargv[2*i+1]="-tun-fd";
447 newargv[2*i+2]=strdup(numfd);
450 char nnics[10];
451 sprintf(nnics,"%d",nb_nics);
452 newargv[2*nb_nics+1]="-nics";
453 newargv[2*nb_nics+2]=strdup(nnics);
455 } else {
456 for (i=0; i<nb_nics; i++) {
457 char numfd[30];
458 sprintf(numfd,"tap,vlan=0,fd=%d",sp[i][0]);
459 newargv[2*i+1]="-net";
460 newargv[2*i+2]=strdup(numfd);
462 newargv[2*nb_nics+1]="-net";
463 newargv[2*nb_nics+2]="nic";
465 for (i=(2*nb_nics)+3,j=1;j<argc;i++,j++) newargv[i]=argv[j];
467 newargv[i]=0;
470 if ((pollv= (struct pollfd *) malloc(sizeof(struct pollfd) * 2 * nb_nics))<0) {
471 perror("malloc pollfd");
472 exit(1);
474 setsighandlers();
475 for (i=0; i<nb_nics; i++) {
476 struct vde_open_args vdearg={ports[i],NULL,mode};
477 conn[i]=vde_open(sockname[i],"vdeqemu",&vdearg);
478 pollv[2*i+1].fd=vde_datafd(conn[i]);
479 pollv[2*i].fd=sp[i][1];
480 pollv[2*i].events= pollv[2*i+1].events=POLLIN|POLLHUP;
483 #if 0
485 int i=0;
486 while(newargv[i])
487 printf("%s ", newargv[i++]);
488 printf("\n");
490 #endif
492 if (fork()) {
493 close(0);
494 signal(SIGCHLD, sigchld_handler);
495 for (i=0; i<nb_nics; i++)
496 close(sp[i][0]);
497 if (daemonize)
498 daemon(1,1);
499 for(;;) {
500 if ((result=poll(pollv,2*nb_nics,-1)) < 0) {
501 if (errno != EINTR) {
502 perror("poll");
503 cleanup();
504 exit(1);
505 } else {
506 if ((exit_value < 256) || !daemonize)
508 cleanup();
509 exit(exit_value);
512 } else {
513 for (i=0; i<nb_nics; i++) {
514 if (pollv[2*i].revents & POLLHUP || pollv[2*i+1].revents & POLLHUP)
515 break;
516 if (pollv[2*i].revents & POLLIN) {
517 if ((nx=read(sp[i][1],bufin,sizeof(bufin))) <= 0) {
518 if (nx < 0)
519 perror("read");
520 cleanup();
521 exit(nx < 0);
523 //fprintf(stderr,"RX from qemu %d\n",nx);
524 if (vde_send(conn[i],bufin,nx,0) < 0) {
525 perror("sendto");
526 cleanup();
527 exit(1);
530 if (pollv[2*i+1].revents & POLLIN) {
531 if ((nx=vde_recv(conn[i],bufin,BUFSIZE,0)) < 0) {
532 perror("recvfrom");
533 cleanup();
534 exit(1);
536 //fprintf(stderr,"TX to qemu %d\n",nx);
537 if (write(sp[i][1],bufin,nx) < 0) {
538 if (errno != ECONNREFUSED)
539 perror("write");
540 cleanup();
541 exit(errno != ECONNREFUSED);
547 } else {
548 for (i=0; i<nb_nics; i++) {
549 close(sp[i][1]);
550 close(vde_datafd(conn[i]));
551 close(vde_ctlfd(conn[i]));
553 execvp(filename,newargv);
555 cleanup();
556 return(0);
559 /* vim: set ts=2 sts=2 sw=2: */