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
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
19 #include <sys/types.h>
25 #include <vdecommon.h>
27 #include <libvdeplug.h>
29 #define SWITCH_MAGIC 0xfeedface
34 int exit_value
= 256; /* out of range for exit status possible values */
38 unsigned char bufin
[BUFSIZE
];
46 static int countnics(const char *s
)
56 static int countnewnics(int argc
,char *argv
[])
59 register int netflag
=0;
61 if (strcmp(argv
[0],"-net")==0)
64 if (netflag
&& (strncmp(argv
[0],"vde",3)==0))
74 static int isdaemonize(int argc
,char *argv
[])
76 register int daemonize
=0;
77 if(strcmp(filename
,"qemu")==0){
80 if (strcmp(argv
[0],"-daemonize")==0)
82 if ((strcmp(argv
[0],"-vnc")==0) || (strcmp(argv
[0],"-nographic")==0))
87 if(daemonize
&& !daemonadds
) daemonize
= 0;
90 while (argc
> 0 && !daemonize
) {
91 if (strcmp(argv
[0],"-daemonize")==0)
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"
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);
113 fprintf(stderr
,"Usage: %s [-h]\n"
114 "\t %s qemu_executable ...qemu options... -net vde[,vlan=n][,sock=sock] ... \n"
116 "\t %s qemu_executable [-sock sock1 [,sock2...]] qemu_options\n", vdeqname
,vdeqname
, vdeqname
);
121 static void cleanup()
124 for (i
=0; i
<nb_nics
; i
++) {
130 static void sig_handler(int sig
)
132 fprintf(stderr
,"%s: Caught signal %d, cleaning up and exiting\n", vdeqname
, sig
);
134 signal(sig
, SIG_DFL
);
138 static void setsighandlers()
140 /* setting signal handlers.
141 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
142 * ignores all the others signals which could cause termination. */
143 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
144 { SIGHUP
, "SIGHUP", 0 },
145 { SIGINT
, "SIGINT", 0 },
146 { SIGPIPE
, "SIGPIPE", 1 },
147 { SIGALRM
, "SIGALRM", 1 },
148 { SIGTERM
, "SIGTERM", 0 },
149 { SIGUSR1
, "SIGUSR1", 1 },
150 { SIGUSR2
, "SIGUSR2", 1 },
151 { SIGPROF
, "SIGPROF", 1 },
152 { SIGVTALRM
, "SIGVTALRM", 1 },
154 { SIGPOLL
, "SIGPOLL", 1 },
156 { SIGSTKFLT
, "SIGSTKFLT", 1 },
158 { SIGIO
, "SIGIO", 1 },
159 { SIGPWR
, "SIGPWR", 1 },
161 { SIGUNUSED
, "SIGUNUSED", 1 },
165 { SIGXCPU
, "SIGXCPU", 1 },
166 { SIGXFSZ
, "SIGXFSZ", 1 },
172 for(i
= 0; signals
[i
].sig
!= 0; i
++)
173 if(signal(signals
[i
].sig
,
174 signals
[i
].ignore
? SIG_IGN
: sig_handler
) < 0)
175 fprintf(stderr
,"Setting handler for %s: %s\n", signals
[i
].name
,
179 static void sigchld_handler(int sig
)
184 exit_value
=WEXITSTATUS(ev
);
189 static int checkver(char *prog
)
203 if ((f
=fork()) > 0) {
206 len
=read(fd
[0],buf
,256);
209 for(i
=0;i
<len
&& version
==0;i
++) {
210 if(strncmp(buf
+i
,"version ",8)==0) {
212 sscanf(buf
+i
+8,"%d.%d.%d",&v1
,&v2
,&v3
);
213 version
=(v1
<< 16) + (v2
<< 8) + v3
;
218 waitpid(f
,&status
,0);
225 if (execvp(prog
,newargv
) < 0) {
232 static char *parsevdearg(char *arg
,char **sock
,int *pport
, int fd
)
238 printf("arg %s\n", arg
);
240 while (*arg
==',') arg
++;
241 if (strncmp(arg
,"vlan=",5)==0) {
243 while (*arg
!= 0 && *arg
!= ',')
246 else if (strncmp(arg
,"sock=",5)==0) {
251 while (*arg
!= 0 && *arg
!= '\"')
255 while (*arg
!= 0 && *arg
!= ',')
262 else if (strncmp(arg
,"port=",5)==0) {
264 while (*arg
!= 0 && *arg
!= ',')
269 snprintf(newarg
,128,"tap,vlan=%d,fd=%d%s%s",vlan
,fd
,(*arg
== 0)?"":",",arg
);
270 return strdup(newarg
);
273 int main(int argc
, char **argv
)
275 char *argsock
=NULL
,**sockname
;
290 vdeqname
=basename(argv
[0]);
291 //callerpwd=getpwuid(getuid());
292 /* OLD SYNTAX MGMT */
293 if (strncmp(vdeqname
,"vdeo",4) == 0) {
295 if (strcmp(vdeqname
,"vdeoq") != 0) {
299 else if (strcmp(vdeqname
,"vdeq") != 0 && strncmp(vdeqname
,"vde",3)==0) {
309 daemonize
=isdaemonize(argc
-1,argv
+1);
310 if ((ver
=checkver(filename
)) < 0x800)
313 nb_nics
=countnewnics(argc
-1,argv
+1);
318 strcmp(argv
[1],"-h")==0 ||
319 strcmp(argv
[1],"-help")==0 ||
320 strcmp(argv
[1],"--help")==0
322 strcmp(filename
,"-h")==0 ||
323 strcmp(filename
,"-help")==0 ||
324 strcmp(filename
,"--help")==0
327 } else if (argc
> 2 && (
328 (strcmp(argv
[1],"-vdesock")==0) ||
329 (strcmp(argv
[1],"-sock")==0) ||
330 (strcmp(argv
[1],"-unix")==0))
338 if (argc
> 2 && ((strcmp(argv
[1],"--mod")==0))
340 sscanf(argv
[2],"%o",&mode
);
349 nb_nics
=countnics(argsock
);
350 if (!oldsyntax
&& nb_nics
> 1)
352 "Warning: all the vde connections will be connected to one net interface\n"
353 " to configure several interface use the new syntax -net vde\n");
356 if ((sp
= (pair
*) malloc(nb_nics
* 2 * sizeof (int)))<0) {
357 perror("malloc nics");
361 if ((conn
=(VDECONN
**) calloc (nb_nics
,sizeof(VDECONN
*))) <0) {
362 perror("calloc conn");
366 for (i
=0; i
<nb_nics
; i
++) {
367 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, sp
[i
]) < 0){
368 perror("socketpair");
373 if ((sockname
= (char **) malloc(sizeof(char *) * nb_nics
))<0) {
374 perror("malloc sockname");
377 if ((ports
= (int *) calloc(nb_nics
, sizeof(int)))<0) {
378 perror("malloc ports");
388 for (i
=1,netflag
=0,vdeint
=0;i
<argc
;i
++) {
389 if (strcmp(argv
[i
],"-net")==0)
392 if (netflag
&& strncmp(argv
[i
],"vde",3) == 0)
394 argv
[i
]=parsevdearg(argv
[i
]+3,&sockname
[vdeint
],&ports
[vdeint
],sp
[vdeint
][0]);
403 sockname
[0]=VDESTDSOCK
;
406 register char *s
=argsock
;
411 while (*s
!= ',' && *s
!= '\0')
416 } while (oldch
!= 0);
419 /* printf("-- %s --\n",numfd);
420 printf("as %s\n",argsock);
421 for (i=0; i<nb_nics; i++)
422 printf("%d -> %s\n",i,sockname[i]); */
423 newargc
=argc
+2+(2*nb_nics
);
424 if ((newargv
=(char **) malloc ((newargc
+1)* sizeof(char *))) <0) {
431 for (i
=0; i
<nb_nics
; i
++) {
433 sprintf(numfd
,"%d",sp
[i
][0]);
434 newargv
[2*i
+1]="-tun-fd";
435 newargv
[2*i
+2]=strdup(numfd
);
439 sprintf(nnics
,"%d",nb_nics
);
440 newargv
[2*nb_nics
+1]="-nics";
441 newargv
[2*nb_nics
+2]=strdup(nnics
);
444 for (i
=0; i
<nb_nics
; i
++) {
446 sprintf(numfd
,"tap,vlan=0,fd=%d",sp
[i
][0]);
447 newargv
[2*i
+1]="-net";
448 newargv
[2*i
+2]=strdup(numfd
);
450 newargv
[2*nb_nics
+1]="-net";
451 newargv
[2*nb_nics
+2]="nic";
453 for (i
=(2*nb_nics
)+3,j
=1;j
<argc
;i
++,j
++) newargv
[i
]=argv
[j
];
458 if ((pollv
= (struct pollfd
*) malloc(sizeof(struct pollfd
) * 2 * nb_nics
))<0) {
459 perror("malloc pollfd");
463 for (i
=0; i
<nb_nics
; i
++) {
464 struct vde_open_args vdearg
={ports
[i
],NULL
,mode
};
465 conn
[i
]=vde_open(sockname
[i
],"vdeqemu",&vdearg
);
466 pollv
[2*i
+1].fd
=vde_datafd(conn
[i
]);
467 pollv
[2*i
].fd
=sp
[i
][1];
468 pollv
[2*i
].events
= pollv
[2*i
+1].events
=POLLIN
|POLLHUP
;
475 printf("%s ", newargv
[i
++]);
482 signal(SIGCHLD
, sigchld_handler
);
483 for (i
=0; i
<nb_nics
; i
++)
488 if ((result
=poll(pollv
,2*nb_nics
,-1)) < 0) {
489 if (errno
!= EINTR
) {
494 if ((exit_value
< 256) || !daemonize
)
498 for (i
=0; i
<nb_nics
; i
++) {
499 if (pollv
[2*i
].revents
& POLLHUP
|| pollv
[2*i
+1].revents
& POLLHUP
)
501 if (pollv
[2*i
].revents
& POLLIN
) {
502 if ((nx
=read(sp
[i
][1],bufin
,sizeof(bufin
))) <= 0) {
508 //fprintf(stderr,"RX from qemu %d\n",nx);
509 if (vde_send(conn
[i
],bufin
,nx
,0) < 0) {
515 if (pollv
[2*i
+1].revents
& POLLIN
) {
516 if ((nx
=vde_recv(conn
[i
],bufin
,BUFSIZE
,0)) < 0) {
521 //fprintf(stderr,"TX to qemu %d\n",nx);
522 if (write(sp
[i
][1],bufin
,nx
) < 0) {
523 if (errno
!= ECONNREFUSED
)
526 exit(errno
!= ECONNREFUSED
);
533 for (i
=0; i
<nb_nics
; i
++) {
535 close(vde_datafd(conn
[i
]));
536 close(vde_ctlfd(conn
[i
]));
538 execvp(filename
,newargv
);