tagging vde-2 version 2.3.2
[vde.git] / 2.3.2 / src / vde_switch / consmgmt.c
blob09545f7654ec7364ce0233f68f64f9a22067423e
1 /* Copyright 2005,2006,2007 Renzo Davoli - VDE-2
2 * 2007 co-authors Ludovico Gardenghi, Filippo Giunchedi, Luca Bigliardi
3 * --pidfile/-p and cleanup management by Mattia Belletti (C) 2004.
4 * Licensed under the GPLv2
5 */
7 #define _GNU_SOURCE
8 #include <stdio.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <syslog.h>
14 #include <stdlib.h>
15 #include <signal.h>
16 #include <grp.h>
17 #include <libgen.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <sys/uio.h>
24 #include <net/if.h>
25 #include <stdarg.h>
26 #include <getopt.h>
27 #include <dlfcn.h>
28 #include <limits.h>
30 #include <config.h>
31 #include <vde.h>
32 #include <vdecommon.h>
34 #include "port.h"
35 #include "switch.h"
36 #include "sockutils.h"
37 #include "consmgmt.h"
38 #include "qtimer.h"
39 #include "packetq.h"
41 #define MAXCMD 128
43 static struct swmodule swmi;
45 static int logok=0;
46 static char *rcfile;
47 static char *pidfile = NULL;
48 static char pidfile_path[PATH_MAX];
49 static int daemonize = 0;
50 static unsigned int console_type=-1;
51 static unsigned int mgmt_ctl=-1;
52 static unsigned int mgmt_data=-1;
53 static int mgmt_mode = 0600;
54 static gid_t mgmt_group = -1;
56 static char *mgmt_socket = NULL;
57 static char header[]="VDE switch V.%s\n(C) Virtual Square Team (coord. R. Davoli) 2005,2006,2007 - GPLv2\n";
58 static char prompt[]="\nvde$ ";
60 static struct comlist *clh=NULL;
61 static struct comlist **clt=&clh;
62 #ifdef DEBUGOPT
63 #define DBGCLSTEP 8
64 static struct dbgcl *dbgclh=NULL;
65 static struct dbgcl **dbgclt=&dbgclh;
66 #define MGMTPORTNEW (dl)
67 #define MGMTPORTDEL (dl+1)
68 #define MGMTSIGHUP (dl+2)
69 static struct dbgcl dl[]= {
70 {"mgmt/+",NULL,D_MGMT|D_PLUS},
71 {"mgmt/-",NULL,D_MGMT|D_MINUS},
72 {"sig/hup",NULL,D_SIG|D_HUP}
74 #endif
75 #ifdef VDEPLUGIN
76 static struct plugin *pluginh=NULL;
77 static struct plugin **plugint=&pluginh;
78 #endif
80 void addcl(int ncl,struct comlist *cl)
82 register int i;
83 for (i=0;i<ncl;i++,cl++) {
84 cl->next=NULL;
85 (*clt)=cl;
86 clt=(&cl->next);
90 void delcl(int ncl,struct comlist *cl)
92 register int i;
93 for (i=0;i<ncl;i++,cl++) {
94 register struct comlist **p=&clh;
95 while (*p != NULL) {
96 if (*p == cl)
97 *p=cl->next;
98 else {
99 p=&(*p)->next;
100 clt=p;
106 #ifdef DEBUGOPT
107 void adddbgcl(int ncl,struct dbgcl *cl)
109 int i;
110 for (i=0;i<ncl;i++,cl++) {
111 cl->next=NULL;
112 (*dbgclt)=cl;
113 dbgclt=(&cl->next);
117 void deldbgcl(int ncl,struct dbgcl *cl)
119 register int i;
120 for (i=0;i<ncl;i++,cl++) {
121 register struct dbgcl **p=&dbgclh;
122 while (*p != NULL) {
123 if (*p == cl) {
124 if (cl->fds) free(cl->fds);
125 if (cl->fun) free(cl->fun);
126 *p=cl->next;
127 } else {
128 p=&(*p)->next;
129 dbgclt=p;
134 #endif
136 #ifdef VDEPLUGIN
137 void addplugin(struct plugin *cl)
139 cl->next=NULL;
140 (*plugint)=cl;
141 plugint=(&cl->next);
144 void delplugin(struct plugin *cl)
146 register struct plugin **p=plugint=&pluginh;
147 while (*p != NULL) {
148 if (*p == cl)
149 *p=cl->next;
150 else {
151 p=&(*p)->next;
152 plugint=p;
156 #endif
158 void printlog(int priority, const char *format, ...)
160 va_list arg;
162 va_start (arg, format);
164 if (logok)
165 vsyslog(priority,format,arg);
166 else {
167 fprintf(stderr,"%s: ",prog);
168 vfprintf(stderr,format,arg);
169 fprintf(stderr,"\n");
171 va_end (arg);
174 void printoutc(FILE *f, const char *format, ...)
176 va_list arg;
178 va_start (arg, format);
179 if (f) {
180 vfprintf(f,format,arg);
181 fprintf(f,"\n");
182 } else
183 printlog(LOG_INFO,format,arg);
184 va_end(arg);
187 #ifdef DEBUGOPT
188 static char _dbgnl='\n';
189 void debugout(struct dbgcl* cl, const char *format, ...)
191 va_list arg;
192 char *msg;
193 int i;
194 char *header;
195 struct iovec iov[]={{NULL,0},{NULL,0},{&_dbgnl,1}};
197 va_start (arg, format);
198 iov[0].iov_len=asprintf(&header,"3%03o %s ",cl->tag & 0777,cl->path);
199 iov[0].iov_base=header;
200 iov[1].iov_len=vasprintf(&msg,format,arg);
201 iov[1].iov_base=msg;
202 va_end (arg);
204 for (i=0; i<cl->nfds; i++)
205 writev(cl->fds[i],iov,3);
206 free(header);
207 free(msg);
210 void eventout(struct dbgcl* cl, ...)
212 int i;
213 va_list arg;
214 for (i=0; i<cl->nfun; i++) {
215 va_start (arg, cl);
216 (cl->fun[i])(cl,cl->funarg[i],arg);
217 va_end(arg);
221 int packetfilter(struct dbgcl* cl, ...)
223 int i;
224 va_list arg;
225 int len;
226 va_start (arg, cl);
227 (void) va_arg(arg,int); /*port*/
228 (void) va_arg(arg,char *); /*buf*/
229 len=va_arg(arg,int);
230 va_end(arg);
231 for (i=0; i<cl->nfun && len>0; i++) {
232 va_start (arg, cl);
233 int rv=(cl->fun[i])(cl,cl->funarg[i],arg);
234 va_end (arg);
235 if (rv!=0)
236 len=rv;
238 if (len < 0)
239 return 0;
240 else
241 return len;
243 #endif
245 void setmgmtperm(char *path)
247 chmod(path,mgmt_mode);
248 chown(path, -1, mgmt_group);
251 static int help(FILE *fd,char *arg)
253 struct comlist *p;
254 int n=strlen(arg);
255 printoutc(fd,"%-18s %-15s %s","COMMAND PATH","SYNTAX","HELP");
256 printoutc(fd,"%-18s %-15s %s","------------","--------------","------------");
257 for (p=clh;p!=NULL;p=p->next)
258 if (strncmp(p->path,arg,n) == 0)
259 printoutc(fd,"%-18s %-15s %s",p->path,p->syntax,p->help);
260 return 0;
263 static int handle_cmd(int type,int fd,char *inbuf)
265 struct comlist *p;
266 int rv=ENOSYS;
267 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
268 if (*inbuf != '\0' && *inbuf != '#') {
269 char *outbuf;
270 size_t outbufsize;
271 FILE *f=open_memstream(&outbuf,&outbufsize);
272 for (p=clh;p!=NULL && (p->doit==NULL || strncmp(p->path,inbuf,strlen(p->path))!=0); p=p->next)
274 if (p!=NULL)
276 inbuf += strlen(p->path);
277 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
278 if (p->type & WITHFD) {
279 if (fd >= 0) {
280 if (p->type & WITHFILE) {
281 printoutc(f,"0000 DATA END WITH '.'");
282 switch(p->type & ~(WITHFILE | WITHFD)){
283 case NOARG: rv=p->doit(f,fd); break;
284 case INTARG: rv=p->doit(f,fd,atoi(inbuf)); break;
285 case STRARG: rv=p->doit(f,fd,inbuf); break;
287 printoutc(f,".");
288 } else {
289 switch(p->type & ~WITHFD){
290 case NOARG: rv=p->doit(fd); break;
291 case INTARG: rv=p->doit(fd,atoi(inbuf)); break;
292 case STRARG: rv=p->doit(fd,inbuf); break;
295 } else
296 rv = EBADF;
297 } else if (p->type & WITHFILE) {
298 printoutc(f,"0000 DATA END WITH '.'");
299 switch(p->type & ~WITHFILE){
300 case NOARG: rv=p->doit(f); break;
301 case INTARG: rv=p->doit(f,atoi(inbuf)); break;
302 case STRARG: rv=p->doit(f,inbuf); break;
304 printoutc(f,".");
305 } else {
306 switch(p->type){
307 case NOARG: rv=p->doit(); break;
308 case INTARG: rv=p->doit(atoi(inbuf)); break;
309 case STRARG: rv=p->doit(inbuf); break;
313 if (rv == 0) {
314 printoutc(f,"1000 Success");
315 } else if (rv > 0) {
316 printoutc(f,"1%03d %s",rv,strerror(rv));
318 fclose(f);
319 if (fd >= 0)
320 write(fd,outbuf,outbufsize);
321 free(outbuf);
323 return rv;
326 static int runscript(int fd,char *path)
328 FILE *f=fopen(path,"r");
329 char buf[MAXCMD];
330 if (f==NULL)
331 return errno;
332 else {
333 while (fgets(buf,MAXCMD,f) != NULL) {
334 if (strlen(buf) > 1 && buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]= '\0';
335 if (fd >= 0) {
336 char *scriptprompt=NULL;
337 asprintf(&scriptprompt,"vde[%s]: %s\n",path,buf);
338 write(fd,scriptprompt,strlen(scriptprompt));
339 free(scriptprompt);
341 handle_cmd(mgmt_data, fd, buf);
343 fclose(f);
344 return 0;
348 void loadrcfile(void)
350 if (rcfile != NULL)
351 runscript(-1,rcfile);
352 else {
353 char path[PATH_MAX];
354 snprintf(path,PATH_MAX,"%s/.vde2/vde_switch.rc",getenv("HOME"));
355 if (access(path,R_OK) == 0)
356 runscript(-1,path);
357 else {
358 if (access(STDRCFILE,R_OK) == 0)
359 runscript(-1,STDRCFILE);
364 void mgmtnewfd(int new)
366 char buf[MAXCMD];
367 if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
368 printlog(LOG_WARNING,"mgmt fcntl - setting O_NONBLOCK %s",strerror(errno));
369 close(new);
370 return;
373 add_fd(new,mgmt_data,NULL);
374 EVENTOUT(MGMTPORTNEW,new);
375 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
376 write(new,buf,strlen(buf));
377 write(new,prompt,strlen(prompt));
380 #ifdef DEBUGOPT
381 static int debugdel(int fd,char *arg);
382 #endif
383 static char *EOS="9999 END OF SESSION";
384 static void handle_io(unsigned char type,int fd,int revents,void *private_data)
386 char buf[MAXCMD];
387 if (type != mgmt_ctl) {
388 int n=0;
390 if (revents & POLLIN) {
391 n = read(fd, buf, sizeof(buf));
392 if(n < 0){
393 printlog(LOG_WARNING,"Reading from mgmt %s",strerror(errno));
394 return;
397 if (n==0) { /*EOF || POLLHUP*/
398 if (type == console_type) {
399 printlog(LOG_WARNING,"EOF on stdin, cleaning up and exiting");
400 exit(0);
401 } else {
402 #ifdef DEBUGOPT
403 debugdel(fd,"");
404 #endif
405 remove_fd(fd);
407 } else {
408 int cmdout;
409 buf[n]=0;
410 if (n>0 && buf[n-1] == '\n') buf[n-1] = 0;
411 cmdout=handle_cmd(type,(type==console_type)?STDOUT_FILENO:fd,buf);
412 if (cmdout >= 0)
413 write(fd,prompt,strlen(prompt));
414 else {
415 if(type==mgmt_data) {
416 write(fd,EOS,strlen(EOS));
417 #ifdef DEBUGOPT
418 EVENTOUT(MGMTPORTDEL,fd);
419 debugdel(fd,"");
420 #endif
421 remove_fd(fd);
423 if (cmdout == -2)
424 exit(0);
427 } else {/* mgmt ctl */
428 struct sockaddr addr;
429 int new;
430 socklen_t len;
432 len = sizeof(addr);
433 new = accept(fd, &addr, &len);
434 if(new < 0){
435 printlog(LOG_WARNING,"mgmt accept %s",strerror(errno));
436 return;
438 if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
439 printlog(LOG_WARNING,"mgmt fcntl - setting O_NONBLOCK %s",strerror(errno));
440 close(new);
441 return;
444 add_fd(new,mgmt_data,NULL);
445 EVENTOUT(MGMTPORTNEW,new);
446 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
447 write(new,buf,strlen(buf));
448 write(new,prompt,strlen(prompt));
452 static void save_pidfile()
454 if(pidfile[0] != '/')
455 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
456 else
457 strcpy(pidfile_path, pidfile);
459 int fd = open(pidfile_path,
460 O_WRONLY | O_CREAT | O_EXCL,
461 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
462 FILE *f;
464 if(fd == -1) {
465 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
466 exit(1);
469 if((f = fdopen(fd, "w")) == NULL) {
470 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
471 exit(1);
474 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
475 printlog(LOG_ERR, "Error in writing pidfile");
476 exit(1);
479 fclose(f);
482 static void cleanup(unsigned char type,int fd,void *private_data)
484 if (fd < 0) {
485 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
486 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
488 } else {
489 close(fd);
490 if (type == mgmt_ctl && mgmt_socket != NULL) {
491 unlink(mgmt_socket);
496 #define MGMTMODEARG 0x100
497 #define MGMTGROUPARG 0x101
499 static struct option long_options[] = {
500 {"daemon", 0, 0, 'd'},
501 {"pidfile", 1, 0, 'p'},
502 {"rcfile", 1, 0, 'f'},
503 {"mgmt", 1, 0, 'M'},
504 {"mgmtmode", 1, 0, MGMTMODEARG},
505 {"mgmtgroup", 1, 0, MGMTGROUPARG},
506 #ifdef DEBUGOPT
507 {"debugclients",1,0,'D'},
508 #endif
511 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
513 static void usage(void)
515 printf(
516 "(opts from consmgmt module)\n"
517 " -d, --daemon Daemonize vde_switch once run\n"
518 " -p, --pidfile PIDFILE Write pid of daemon to PIDFILE\n"
519 " -f, --rcfile Configuration file (overrides %s and ~/.vderc)\n"
520 " -M, --mgmt SOCK path of the management UNIX socket\n"
521 " --mgmtmode MODE management UNIX socket access mode (octal)\n"
522 " --mgmtgroup GROUP management UNIX socket group name\n"
523 #ifdef DEBUGOPT
524 " -D, --debugclients # number of debug clients allowed\n"
525 #endif
526 ,STDRCFILE);
529 static int parseopt(int c, char *optarg)
531 int outc=0;
532 struct group *grp;
533 switch (c) {
534 case 'd':
535 daemonize=1;
536 break;
537 case 'p':
538 pidfile=strdup(optarg);
539 break;
540 case 'f':
541 rcfile=strdup(optarg);
542 break;
543 case 'M':
544 mgmt_socket=strdup(optarg);
545 break;
546 case MGMTMODEARG:
547 sscanf(optarg,"%o",&mgmt_mode);
548 break;
549 case MGMTGROUPARG:
550 if (!(grp = getgrnam(optarg)))
552 fprintf(stderr, "No such group '%s'\n", optarg);
553 exit(1);
555 mgmt_group = grp->gr_gid;
556 break;
558 default:
559 outc=c;
561 return outc;
564 static void init(void)
566 if (daemonize) {
567 openlog(basename(prog), LOG_PID, 0);
568 logok=1;
569 syslog(LOG_INFO,"VDE_SWITCH started");
571 /* add stdin (if tty), connect and data fds to the set of fds we wait for
572 * * input */
573 if(isatty(0) && !daemonize)
575 console_type=add_type(&swmi,0);
576 add_fd(0,console_type,NULL);
579 /* saves current path in pidfile_path, because otherwise with daemonize() we
580 * * forget it */
581 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
582 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
583 exit(1);
585 strcat(pidfile_path, "/");
586 if (daemonize && daemon(0, 0)) {
587 printlog(LOG_ERR,"daemon: %s",strerror(errno));
588 exit(1);
591 /* once here, we're sure we're the true process which will continue as a
592 * * server: save PID file if needed */
593 if(pidfile) save_pidfile();
595 if(mgmt_socket != NULL) {
596 int mgmtconnfd;
597 struct sockaddr_un sun;
598 int one = 1;
600 if((mgmtconnfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
601 printlog(LOG_ERR,"mgmt socket: %s",strerror(errno));
602 return;
604 if(setsockopt(mgmtconnfd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
605 sizeof(one)) < 0){
606 printlog(LOG_ERR,"mgmt setsockopt: %s",strerror(errno));
607 return;
609 if(fcntl(mgmtconnfd, F_SETFL, O_NONBLOCK) < 0){
610 printlog(LOG_ERR,"Setting O_NONBLOCK on mgmt fd: %s",strerror(errno));
611 return;
613 sun.sun_family = PF_UNIX;
614 snprintf(sun.sun_path,sizeof(sun.sun_path),"%s",mgmt_socket);
615 if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
616 if((errno == EADDRINUSE) && still_used(&sun)) return;
617 else if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
618 printlog(LOG_ERR,"mgmt bind %s",strerror(errno));
619 return;
622 setmgmtperm(sun.sun_path);
623 if(listen(mgmtconnfd, 15) < 0){
624 printlog(LOG_ERR,"mgmt listen: %s",strerror(errno));
625 return;
627 mgmt_ctl=add_type(&swmi,0);
628 mgmt_data=add_type(&swmi,0);
629 add_fd(mgmtconnfd,mgmt_ctl,NULL);
633 static int vde_logout()
635 return -1;
638 static int vde_shutdown()
640 printlog(LOG_WARNING,"Shutdown from mgmt command");
641 return -2;
644 static int showinfo(FILE *fd)
646 printoutc(fd,header,PACKAGE_VERSION);
647 printoutc(fd,"pid %d MAC %02x:%02x:%02x:%02x:%02x:%02x uptime %d",getpid(),
648 switchmac[0], switchmac[1], switchmac[2], switchmac[3], switchmac[4], switchmac[5],
649 qtime());
650 if (mgmt_socket)
651 printoutc(fd,"mgmt %s perm 0%03o",mgmt_socket,mgmt_mode);
652 return 0;
655 #ifdef DEBUGOPT
656 static int debuglist(FILE *f,int fd,char *path)
658 #define DEBUGFORMAT1 "%-22s %-3s %-6s %s"
659 #define DEBUGFORMAT2 "%-22s %03o %-6s %s"
660 struct dbgcl *p;
661 int i;
662 int rv=ENOENT;
663 printoutc(f,DEBUGFORMAT1,"CATEGORY", "TAG", "STATUS", "HELP");
664 printoutc(f,DEBUGFORMAT1,"------------","---","------", "----");
665 for (p=dbgclh; p!=NULL; p=p->next){
666 if (p->help && strncmp(p->path, path, strlen(path)) == 0) {
667 for (i=0; i<p->nfds && p->fds[i] != fd; i++)
669 rv=0;
670 printoutc(f, DEBUGFORMAT2, p->path, p->tag &0777, i<p->nfds ? "ON" : "OFF", p->help);
673 return rv;
676 /* EINVAL -> no matches
677 * EEXIST -> all the matches already include fd
678 * ENOMEM -> fd buffer realloc failed
679 * 0 otherwise */
680 static int debugadd(int fd,char *path) {
681 struct dbgcl *p;
682 int rv=EINVAL;
683 for (p=dbgclh; p!=NULL; p=p->next) {
684 if (p->help && strncmp(p->path, path, strlen(path)) == 0) {
685 int i;
686 if (rv==EINVAL) rv=EEXIST;
687 for(i=0;i<p->nfds && (p->fds[i] != fd); i++)
689 if (i>=p->nfds) {
690 if (i>=p->maxfds) {
691 int newsize=p->maxfds+DBGCLSTEP;
692 p->fds=realloc(p->fds,newsize*sizeof(int));
693 if (p->fds) {
694 p->maxfds=newsize;
695 p->fds[i]=fd;
696 p->nfds++;
697 if (rv != ENOMEM) rv=0;
698 } else
699 rv=ENOMEM;
700 } else {
701 p->fds[i]=fd;
702 p->nfds++;
703 if (rv != ENOMEM) rv=0;
708 return rv;
711 /* EINVAL -> no matches
712 * ENOENT -> all the matches do not include fd
713 * 0 otherwise */
714 static int debugdel(int fd,char *path) {
715 struct dbgcl *p;
716 int rv=EINVAL;
717 for (p=dbgclh; p!=NULL; p=p->next){
718 if (strncmp(p->path, path, strlen(path)) == 0) {
719 int i;
720 if (rv==EINVAL) rv=ENOENT;
721 for(i=0;i<p->nfds && (p->fds[i] != fd); i++)
723 if (i<p->nfds) {
724 p->nfds--; /* the last one */
725 p->fds[i]=p->fds[p->nfds]; /* swap it with the deleted element*/
726 rv=0;
730 return rv;
733 int eventadd(int (*fun)(),char *path,void *arg) {
734 struct dbgcl *p;
735 int rv=EINVAL;
736 for (p=dbgclh; p!=NULL; p=p->next) {
737 if (strncmp(p->path, path, strlen(path)) == 0) {
738 int i;
739 if (rv==EINVAL) rv=EEXIST;
740 for(i=0;i<p->nfun && (p->fun[i] != fun); i++)
742 if (i>=p->nfun) {
743 if (i>=p->maxfun) {
744 int newsize=p->maxfun+DBGCLSTEP;
745 p->fun=realloc(p->fun,newsize*sizeof(int));
746 p->funarg=realloc(p->funarg,newsize*sizeof(void *));
747 if (p->fun && p->funarg) {
748 p->maxfun=newsize;
749 p->fun[i]=fun;
750 p->funarg[i]=arg;
751 p->nfun++;
752 if (rv != ENOMEM) rv=0;
753 } else
754 rv=ENOMEM;
755 } else {
756 p->fun[i]=fun;
757 p->nfun++;
758 if (rv != ENOMEM) rv=0;
763 return rv;
766 /* EINVAL -> no matches
767 * ENOENT -> all the matches do not include fun
768 * 0 otherwise */
769 int eventdel(int (*fun)(),char *path,void *arg) {
770 struct dbgcl *p;
771 int rv=EINVAL;
772 for (p=dbgclh; p!=NULL; p=p->next){
773 if (strncmp(p->path, path, strlen(path)) == 0) {
774 int i;
775 if (rv==EINVAL) rv=ENOENT;
776 for(i=0;i<p->nfun && (p->fun[i] != fun) && (p->funarg[i] != arg); i++)
778 if (i<p->nfun) {
779 p->nfun--; /* the last one */
780 p->fun[i]=p->fun[p->nfun]; /* swap it with the deleted element*/
781 rv=0;
785 return rv;
788 #endif
790 #ifdef VDEPLUGIN
791 static int pluginlist(FILE *f,char *arg)
793 #define PLUGINFMT "%-22s %s"
794 struct plugin *p;
795 int rv=ENOENT;
796 printoutc(f,PLUGINFMT,"NAME", "HELP");
797 printoutc(f,PLUGINFMT,"------------","----");
798 for (p=pluginh; p!=NULL; p=p->next){
799 if (strncmp(p->name, arg, strlen(arg)) == 0) {
800 printoutc(f,PLUGINFMT,p->name,p->help);
801 rv=0;
804 return rv;
807 /* This will be prefixed with getent("$HOME") */
808 #define USER_PLUGINS_DIR "/.vde2/plugins"
810 #ifndef MAX
811 # define MAX(a, b) ((a) > (b) ? (a) : (b))
812 #endif
814 * Try to dlopen a plugin trying different names and locations:
815 * (code from view-os by Gardenghi)
817 * 1) dlopen(modname)
818 * 2) dlopen(modname.so)
819 * 3) dlopen(user_umview_plugin_directory/modname)
820 * 4) dlopen(user_umview_plugin_directory/modname.so)
821 * 5) dlopen(global_umview_plugin_directory/modname)
822 * 6) dlopen(global_umview_plugin_directory/modname.so)
826 #define TRY_DLOPEN(fmt...) \
828 snprintf(testpath, tplen, fmt); \
829 if ((handle = dlopen(testpath, flag))) \
831 free(testpath); \
832 return handle; \
836 void *plugin_dlopen(const char *modname, int flag)
838 void *handle;
839 char *testpath;
840 int tplen;
841 char *homedir = getenv("HOME");
843 if (!modname)
844 return NULL;
846 if ((handle = dlopen(modname, flag)))
847 return handle;
849 /* If there is no home directory, use CWD */
850 if (!homedir)
851 homedir = ".";
853 tplen = strlen(modname) +
854 strlen(MODULES_EXT) + 2 + // + 1 is for a '/' and + 1 for \0
855 MAX(strlen(PLUGINS_DIR),
856 strlen(homedir) + strlen(USER_PLUGINS_DIR));
858 testpath = malloc(tplen);
860 TRY_DLOPEN("%s%s", modname, MODULES_EXT);
861 TRY_DLOPEN("%s%s/%s", homedir, USER_PLUGINS_DIR, modname);
862 TRY_DLOPEN("%s%s/%s%s", homedir, USER_PLUGINS_DIR, modname, MODULES_EXT);
863 TRY_DLOPEN("%s%s", PLUGINS_DIR, modname);
864 TRY_DLOPEN("%s/%s%s", PLUGINS_DIR, modname, MODULES_EXT);
866 free(testpath);
867 return NULL;
872 static int pluginadd(char *arg) {
873 void *handle;
874 struct plugin *p;
875 int rv=ENOENT;
876 if ((handle=plugin_dlopen(arg,RTLD_LAZY)) != NULL) {
877 if ((p=(struct plugin *) dlsym(handle,"vde_plugin_data")) != NULL) {
878 if (p->handle != NULL) { /* this dyn library is already loaded*/
879 dlclose(handle);
880 rv=EEXIST;
881 } else {
882 addplugin(p);
883 p->handle=handle;
884 rv=0;
886 } else {
887 rv=EINVAL;
890 return rv;
893 static int plugindel(char *arg) {
894 struct plugin **p=&pluginh;
895 while (*p!=NULL){
896 void *handle;
897 if (strncmp((*p)->name, arg, strlen(arg)) == 0
898 && ((*p)->handle != NULL)) {
899 struct plugin *this=*p;
900 delplugin(this);
901 handle=this->handle;
902 this->handle=NULL;
903 dlclose(handle);
904 return 0;
905 } else
906 p=&(*p)->next;
908 return ENOENT;
910 #endif
912 static struct comlist cl[]={
913 {"help","[arg]","Help (limited to arg when specified)",help,STRARG | WITHFILE},
914 {"logout","","logout from this mgmt terminal",vde_logout,NOARG},
915 {"shutdown","","shutdown of the switch",vde_shutdown,NOARG},
916 {"showinfo","","show switch version and info",showinfo,NOARG|WITHFILE},
917 {"load","path","load a configuration script",runscript,STRARG|WITHFD},
918 #ifdef DEBUGOPT
919 {"debug","============","DEBUG MENU",NULL,NOARG},
920 {"debug/list","","list debug categories",debuglist,STRARG|WITHFILE|WITHFD},
921 {"debug/add","dbgpath","enable debug info for a given category",debugadd,WITHFD|STRARG},
922 {"debug/del","dbgpath","disable debug info for a given category",debugdel,WITHFD|STRARG},
923 #endif
924 #ifdef VDEPLUGIN
925 {"plugin","============","PLUGINS MENU",NULL,NOARG},
926 {"plugin/list","","list plugins",pluginlist,STRARG|WITHFILE},
927 {"plugin/add","library","load a plugin",pluginadd,STRARG},
928 {"plugin/del","name","unload a plugin",plugindel,STRARG},
929 #endif
932 static void sighupmgmt(int signo)
934 EVENTOUT(MGMTSIGHUP, signo);
937 void start_consmgmt(void)
939 swmi.swmname="console-mgmt";
940 swmi.swmnopts=Nlong_options;
941 swmi.swmopts=long_options;
942 swmi.usage=usage;
943 swmi.parseopt=parseopt;
944 swmi.init=init;
945 swmi.handle_io=handle_io;
946 swmi.cleanup=cleanup;
947 ADDCL(cl);
948 #ifdef DEBUGOPT
949 ADDDBGCL(dl);
950 #endif
951 add_swm(&swmi);
952 #ifdef DEBUGOPT
953 signal(SIGHUP,sighupmgmt);
954 #endif