some bugfixes about plugins.
[vde.git] / vde-2 / src / vde_switch / consmgmt.c
bloba0ba5093b95a1d61c9906ad58343127160199ef5
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 <libgen.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/ioctl.h>
19 #include <sys/socket.h>
20 #include <sys/un.h>
21 #include <sys/uio.h>
22 #include <net/if.h>
23 #include <stdarg.h>
24 #include <getopt.h>
25 #include <dlfcn.h>
27 #include <config.h>
28 #include <vde.h>
29 #include <vdecommon.h>
31 #include "port.h"
32 #include "switch.h"
33 #include "sockutils.h"
34 #include "consmgmt.h"
35 #include "qtimer.h"
36 #include "packetq.h"
38 #define MAXCMD 128
40 static struct swmodule swmi;
42 static int logok=0;
43 static char *rcfile;
44 static char *pidfile = NULL;
45 static char pidfile_path[PATH_MAX];
46 static int daemonize = 0;
47 static unsigned int console_type=-1;
48 static unsigned int mgmt_ctl=-1;
49 static unsigned int mgmt_data=-1;
50 static int mgmt_mode = 0600;
51 static char *mgmt_socket = NULL;
52 static char header[]="VDE switch V.%s\n(C) Virtual Square Team (coord. R. Davoli) 2005,2006,2007 - GPLv2\n";
53 static char prompt[]="\nvde$ ";
55 static struct comlist *clh=NULL;
56 static struct comlist **clt=&clh;
57 #ifdef DEBUGOPT
58 #define DBGCLSTEP 8
59 static struct dbgcl *dbgclh=NULL;
60 static struct dbgcl **dbgclt=&dbgclh;
61 #define MGMTPORTNEW (dl)
62 #define MGMTPORTDEL (dl+1)
63 static struct dbgcl dl[]= {
64 {"mgmt/+",NULL,D_MGMT|D_PLUS},
65 {"mgmt/-",NULL,D_MGMT|D_MINUS}
67 #endif
68 #ifdef VDEPLUGIN
69 static struct plugin *pluginh=NULL;
70 static struct plugin **plugint=&pluginh;
71 #endif
73 void addcl(int ncl,struct comlist *cl)
75 register int i;
76 for (i=0;i<ncl;i++,cl++) {
77 cl->next=NULL;
78 (*clt)=cl;
79 clt=(&cl->next);
83 void delcl(int ncl,struct comlist *cl)
85 register int i;
86 for (i=0;i<ncl;i++,cl++) {
87 register struct comlist **p=&clh;
88 while (*p != NULL) {
89 if (*p == cl)
90 *p=cl->next;
91 else {
92 p=&(*p)->next;
93 clt=p;
99 #ifdef DEBUGOPT
100 void adddbgcl(int ncl,struct dbgcl *cl)
102 int i;
103 for (i=0;i<ncl;i++,cl++) {
104 cl->next=NULL;
105 (*dbgclt)=cl;
106 dbgclt=(&cl->next);
110 void deldbgcl(int ncl,struct dbgcl *cl)
112 register int i;
113 for (i=0;i<ncl;i++,cl++) {
114 register struct dbgcl **p=&dbgclh;
115 while (*p != NULL) {
116 if (*p == cl) {
117 if (cl->fds) free(cl->fds);
118 if (cl->fun) free(cl->fun);
119 *p=cl->next;
120 } else {
121 p=&(*p)->next;
122 dbgclt=p;
127 #endif
129 #ifdef VDEPLUGIN
130 void addplugin(struct plugin *cl)
132 cl->next=NULL;
133 (*plugint)=cl;
134 plugint=(&cl->next);
137 void delplugin(struct plugin *cl)
139 register struct plugin **p=&pluginh;
140 while (*p != NULL) {
141 if (*p == cl)
142 *p=cl->next;
143 else {
144 p=&(*p)->next;
145 plugint=p;
149 #endif
151 void printlog(int priority, const char *format, ...)
153 va_list arg;
155 va_start (arg, format);
157 if (logok)
158 vsyslog(priority,format,arg);
159 else {
160 fprintf(stderr,"%s: ",prog);
161 vfprintf(stderr,format,arg);
162 fprintf(stderr,"\n");
164 va_end (arg);
167 void printoutc(FILE *f, const char *format, ...)
169 va_list arg;
171 va_start (arg, format);
172 if (f) {
173 vfprintf(f,format,arg);
174 fprintf(f,"\n");
175 } else
176 printlog(LOG_INFO,format,arg);
177 va_end(arg);
180 #ifdef DEBUGOPT
181 static char _dbgnl='\n';
182 void debugout(struct dbgcl* cl, const char *format, ...)
184 va_list arg;
185 char *msg;
186 int i;
187 char *header;
188 struct iovec iov[]={{NULL,0},{NULL,0},{&_dbgnl,1}};
190 va_start (arg, format);
191 iov[0].iov_len=asprintf(&header,"3%03o %s ",cl->tag & 0777,cl->path);
192 iov[0].iov_base=header;
193 iov[1].iov_len=vasprintf(&msg,format,arg);
194 iov[1].iov_base=msg;
195 va_end (arg);
197 for (i=0; i<cl->nfds; i++)
198 writev(cl->fds[i],iov,3);
199 free(header);
200 free(msg);
203 void eventout(struct dbgcl* cl, ...)
205 int i;
206 va_list arg;
207 for (i=0; i<cl->nfun; i++) {
208 va_start (arg, cl);
209 (cl->fun[i])(cl,cl->funarg[i],arg);
210 va_end(arg);
214 int packetfilter(struct dbgcl* cl, ...)
216 int i;
217 va_list arg;
218 int len;
219 va_start (arg, cl);
220 (void) va_arg(arg,int); /*port*/
221 (void) va_arg(arg,char *); /*buf*/
222 len=va_arg(arg,int);
223 va_end(arg);
224 for (i=0; i<cl->nfun && len>0; i++) {
225 va_start (arg, cl);
226 int rv=(cl->fun[i])(cl,cl->funarg[i],arg);
227 va_end (arg);
228 if (rv!=0)
229 len=rv;
231 if (len < 0)
232 return 0;
233 else
234 return len;
236 #endif
238 void setmgmtperm(char *path)
240 chmod(path,mgmt_mode);
243 static int help(FILE *fd,char *arg)
245 struct comlist *p;
246 int n=strlen(arg);
247 printoutc(fd,"%-18s %-15s %s","COMMAND PATH","SYNTAX","HELP");
248 printoutc(fd,"%-18s %-15s %s","------------","--------------","------------");
249 for (p=clh;p!=NULL;p=p->next)
250 if (strncmp(p->path,arg,n) == 0)
251 printoutc(fd,"%-18s %-15s %s",p->path,p->syntax,p->help);
252 return 0;
255 static int handle_cmd(int type,int fd,char *inbuf)
257 struct comlist *p;
258 int rv=ENOSYS;
259 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
260 if (*inbuf != '\0' && *inbuf != '#') {
261 char *outbuf;
262 size_t outbufsize;
263 FILE *f;
264 if (fd >= 0)
265 f=open_memstream(&outbuf,&outbufsize);
266 else
267 f=NULL;
268 for (p=clh;p!=NULL && (p->doit==NULL || strncmp(p->path,inbuf,strlen(p->path))!=0); p=p->next)
270 if (p!=NULL)
272 inbuf += strlen(p->path);
273 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
274 if (p->type & WITHFD) {
275 if (p->type & WITHFILE) {
276 printoutc(f,"0000 DATA END WITH '.'");
277 switch(p->type & ~(WITHFILE | WITHFD)){
278 case NOARG: rv=p->doit(f,fd); break;
279 case INTARG: rv=p->doit(f,fd,atoi(inbuf)); break;
280 case STRARG: rv=p->doit(f,fd,inbuf); break;
282 printoutc(f,".");
283 } else {
284 switch(p->type & ~WITHFD){
285 case NOARG: rv=p->doit(fd); break;
286 case INTARG: rv=p->doit(fd,atoi(inbuf)); break;
287 case STRARG: rv=p->doit(fd,inbuf); break;
290 } else if (p->type & WITHFILE) {
291 printoutc(f,"0000 DATA END WITH '.'");
292 switch(p->type & ~WITHFILE){
293 case NOARG: rv=p->doit(f); break;
294 case INTARG: rv=p->doit(f,atoi(inbuf)); break;
295 case STRARG: rv=p->doit(f,inbuf); break;
297 printoutc(f,".");
298 } else {
299 switch(p->type){
300 case NOARG: rv=p->doit(); break;
301 case INTARG: rv=p->doit(atoi(inbuf)); break;
302 case STRARG: rv=p->doit(inbuf); break;
306 if (rv >= 0 && (rv > 0 || fd >= 0))
307 printoutc(f,"1%03d %s",rv,strerror(rv));
308 if (f) {
309 fclose(f);
310 write(fd,outbuf,outbufsize);
311 free(outbuf);
314 return rv;
317 static int runscript(int fd,char *path)
319 FILE *f=fopen(path,"r");
320 char buf[MAXCMD];
321 if (f==NULL)
322 return errno;
323 else {
324 while (fgets(buf,MAXCMD,f) != NULL) {
325 if (strlen(buf) > 1 && buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]= '\0';
326 if (fd >= 0) {
327 char *scriptprompt=NULL;
328 asprintf(&scriptprompt,"vde[%s]: %s",path,buf);
329 write(fd,scriptprompt,strlen(scriptprompt));
330 free(scriptprompt);
332 handle_cmd(mgmt_data, fd, buf);
334 fclose(f);
335 return 0;
339 void loadrcfile(void)
341 if (rcfile != NULL)
342 runscript(-1,rcfile);
343 else {
344 char path[PATH_MAX];
345 snprintf(path,PATH_MAX,"%s/.vde2/vde_switch.rc",getenv("HOME"));
346 if (access(path,R_OK) == 0)
347 runscript(-1,path);
348 else {
349 if (access(STDRCFILE,R_OK) == 0)
350 runscript(-1,STDRCFILE);
355 void mgmtnewfd(int new)
357 char buf[MAXCMD];
358 if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
359 printlog(LOG_WARNING,"mgmt fcntl - setting O_NONBLOCK %s",strerror(errno));
360 close(new);
361 return;
364 add_fd(new,mgmt_data,-1);
365 EVENTOUT(MGMTPORTNEW,new);
366 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
367 write(new,buf,strlen(buf));
368 write(new,prompt,strlen(prompt));
371 #ifdef DEBUGOPT
372 static int debugdel(int fd,char *arg);
373 #endif
374 static char *EOS="9999 END OF SESSION";
375 static void handle_input(unsigned char type,int fd,int revents,int *unused)
377 char buf[MAXCMD];
378 if (type != mgmt_ctl) {
379 int n=0;
381 if (revents & POLLIN) {
382 n = read(fd, buf, sizeof(buf));
383 if(n < 0){
384 printlog(LOG_WARNING,"Reading from mgmt %s",strerror(errno));
387 if (n==0) { /*EOF*/
388 if (type == console_type) {
389 printlog(LOG_WARNING,"EOF on stdin, cleaning up and exiting");
390 exit(0);
391 } else {
392 #ifdef DEBUGOPT
393 debugdel(fd,"");
394 #endif
395 remove_fd(fd);
397 } else {
398 int cmdout;
399 buf[n]=0;
400 if (n>0 && buf[n-1] == '\n') buf[n-1] = 0;
401 cmdout=handle_cmd(type,(type==console_type)?STDOUT_FILENO:fd,buf);
402 if (cmdout >= 0)
403 write(fd,prompt,strlen(prompt));
404 else {
405 if(type==mgmt_data) {
406 write(fd,EOS,strlen(EOS));
407 #ifdef DEBUGOPT
408 EVENTOUT(MGMTPORTDEL,fd);
409 debugdel(fd,"");
410 #endif
411 remove_fd(fd);
413 if (cmdout == -2)
414 exit(0);
417 } else {/* mgmt ctl */
418 struct sockaddr addr;
419 int new;
420 socklen_t len;
422 len = sizeof(addr);
423 new = accept(fd, &addr, &len);
424 if(new < 0){
425 printlog(LOG_WARNING,"mgmt accept %s",strerror(errno));
426 return;
428 if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
429 printlog(LOG_WARNING,"mgmt fcntl - setting O_NONBLOCK %s",strerror(errno));
430 close(new);
431 return;
434 add_fd(new,mgmt_data,-1);
435 EVENTOUT(MGMTPORTNEW,new);
436 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
437 write(new,buf,strlen(buf));
438 write(new,prompt,strlen(prompt));
442 static void save_pidfile()
444 if(pidfile[0] != '/')
445 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
446 else
447 strcpy(pidfile_path, pidfile);
449 int fd = open(pidfile_path,
450 O_WRONLY | O_CREAT | O_EXCL,
451 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
452 FILE *f;
454 if(fd == -1) {
455 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
456 exit(1);
459 if((f = fdopen(fd, "w")) == NULL) {
460 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
461 exit(1);
464 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
465 printlog(LOG_ERR, "Error in writing pidfile");
466 exit(1);
469 fclose(f);
472 static void cleanup(unsigned char type,int fd,int arg)
474 if (fd < 0) {
475 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
476 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
478 } else {
479 close(fd);
480 if (type == mgmt_ctl && mgmt_socket != NULL) {
481 unlink(mgmt_socket);
486 #define MGMTMODEARG 0x100
488 static struct option long_options[] = {
489 {"daemon", 0, 0, 'd'},
490 {"pidfile", 1, 0, 'p'},
491 {"rcfile", 1, 0, 'f'},
492 {"mgmt", 1, 0, 'M'},
493 {"mgmtmode", 1, 0, MGMTMODEARG},
494 #ifdef DEBUGOPT
495 {"debugclients",1,0,'D'},
496 #endif
499 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
501 static void usage(void)
503 printf(
504 "(opts from consmgmt module)\n"
505 " -d, --daemon Daemonize vde_switch once run\n"
506 " -p, --pidfile PIDFILE Write pid of daemon to PIDFILE\n"
507 " -f, --rcfile Configuration file (overrides %s and ~/.vderc)\n"
508 " -M, --mgmt SOCK path of the management UNIX socket\n"
509 " --mgmtmode MODE management UNIX socket access mode (octal)\n"
510 #ifdef DEBUGOPT
511 " -D, --debugclients # number of debug clients allowed\n"
512 #endif
513 ,STDRCFILE);
516 static int parseopt(int c, char *optarg)
518 int outc=0;
519 switch (c) {
520 case 'd':
521 daemonize=1;
522 break;
523 case 'p':
524 pidfile=strdup(optarg);
525 break;
526 case 'f':
527 rcfile=strdup(optarg);
528 break;
529 case 'M':
530 mgmt_socket=strdup(optarg);
531 break;
532 case MGMTMODEARG:
533 sscanf(optarg,"%o",&mgmt_mode);
534 break;
535 default:
536 outc=c;
538 return outc;
541 static void init(void)
543 if (daemonize) {
544 openlog(basename(prog), LOG_PID, 0);
545 logok=1;
546 syslog(LOG_INFO,"VDE_SWITCH started");
548 /* add stdin (if tty), connect and data fds to the set of fds we wait for
549 * * input */
550 if(isatty(0) && !daemonize)
552 console_type=add_type(&swmi,0);
553 add_fd(0,console_type,-1);
556 /* saves current path in pidfile_path, because otherwise with daemonize() we
557 * * forget it */
558 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
559 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
560 exit(1);
562 strcat(pidfile_path, "/");
563 if (daemonize && daemon(0, 0)) {
564 printlog(LOG_ERR,"daemon: %s",strerror(errno));
565 exit(1);
568 /* once here, we're sure we're the true process which will continue as a
569 * * server: save PID file if needed */
570 if(pidfile) save_pidfile();
572 if(mgmt_socket != NULL) {
573 int mgmtconnfd;
574 struct sockaddr_un sun;
575 int one = 1;
577 if((mgmtconnfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
578 printlog(LOG_ERR,"mgmt socket: %s",strerror(errno));
579 return;
581 if(setsockopt(mgmtconnfd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
582 sizeof(one)) < 0){
583 printlog(LOG_ERR,"mgmt setsockopt: %s",strerror(errno));
584 return;
586 if(fcntl(mgmtconnfd, F_SETFL, O_NONBLOCK) < 0){
587 printlog(LOG_ERR,"Setting O_NONBLOCK on mgmt fd: %s",strerror(errno));
588 return;
590 sun.sun_family = PF_UNIX;
591 snprintf(sun.sun_path,sizeof(sun.sun_path),"%s",mgmt_socket);
592 if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
593 if((errno == EADDRINUSE) && still_used(&sun)) return;
594 else if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
595 printlog(LOG_ERR,"mgmt bind %s",strerror(errno));
596 return;
599 chmod(sun.sun_path,mgmt_mode);
600 if(listen(mgmtconnfd, 15) < 0){
601 printlog(LOG_ERR,"mgmt listen: %s",strerror(errno));
602 return;
604 mgmt_ctl=add_type(&swmi,0);
605 mgmt_data=add_type(&swmi,0);
606 add_fd(mgmtconnfd,mgmt_ctl,-1);
610 static int vde_logout()
612 return -1;
615 static int vde_shutdown()
617 printlog(LOG_WARNING,"Shutdown from mgmt command");
618 return -2;
621 static int showinfo(FILE *fd)
623 printoutc(fd,header,PACKAGE_VERSION);
624 printoutc(fd,"pid %d MAC %02x:%02x:%02x:%02x:%02x:%02x uptime %d",getpid(),
625 switchmac[0], switchmac[1], switchmac[2], switchmac[3], switchmac[4], switchmac[5],
626 qtime());
627 if (mgmt_socket)
628 printoutc(fd,"mgmt %s perm 0%03o",mgmt_socket,mgmt_mode);
629 printoutc(fd,"unsent_pktq_len %d",packetq_count());
630 return 0;
633 #ifdef DEBUGOPT
634 static int debuglist(FILE *f,int fd,char *path)
636 #define DEBUGFORMAT1 "%-22s %-3s %-6s %s"
637 #define DEBUGFORMAT2 "%-22s %03o %-6s %s"
638 struct dbgcl *p;
639 int i;
640 int rv=ENOENT;
641 printoutc(f,DEBUGFORMAT1,"CATEGORY", "TAG", "STATUS", "HELP");
642 printoutc(f,DEBUGFORMAT1,"------------","---","------", "----");
643 for (p=dbgclh; p!=NULL; p=p->next){
644 if (p->help && strncmp(p->path, path, strlen(path)) == 0) {
645 for (i=0; i<p->nfds && p->fds[i] != fd; i++)
647 rv=0;
648 printoutc(f, DEBUGFORMAT2, p->path, p->tag &0777, i<p->nfds ? "ON" : "OFF", p->help);
651 return rv;
654 /* EINVAL -> no matches
655 * EEXIST -> all the matches already include fd
656 * ENOMEM -> fd buffer realloc failed
657 * 0 otherwise */
658 static int debugadd(int fd,char *path) {
659 struct dbgcl *p;
660 int rv=EINVAL;
661 for (p=dbgclh; p!=NULL; p=p->next) {
662 if (p->help && strncmp(p->path, path, strlen(path)) == 0) {
663 int i;
664 if (rv==EINVAL) rv=EEXIST;
665 for(i=0;i<p->nfds && (p->fds[i] != fd); i++)
667 if (i>=p->nfds) {
668 if (i>=p->maxfds) {
669 int newsize=p->maxfds+DBGCLSTEP;
670 p->fds=realloc(p->fds,newsize*sizeof(int));
671 if (p->fds) {
672 p->maxfds=newsize;
673 p->fds[i]=fd;
674 p->nfds++;
675 if (rv != ENOMEM) rv=0;
676 } else
677 rv=ENOMEM;
678 } else {
679 p->fds[i]=fd;
680 p->nfds++;
681 if (rv != ENOMEM) rv=0;
686 return rv;
689 /* EINVAL -> no matches
690 * ENOENT -> all the matches do not include fd
691 * 0 otherwise */
692 static int debugdel(int fd,char *path) {
693 struct dbgcl *p;
694 int rv=EINVAL;
695 for (p=dbgclh; p!=NULL; p=p->next){
696 if (strncmp(p->path, path, strlen(path)) == 0) {
697 int i;
698 if (rv==EINVAL) rv=ENOENT;
699 for(i=0;i<p->nfds && (p->fds[i] != fd); i++)
701 if (i<p->nfds) {
702 p->nfds--; /* the last one */
703 p->fds[i]=p->fds[p->nfds]; /* swap it with the deleted element*/
704 rv=0;
708 return rv;
711 int eventadd(int (*fun)(),char *path,void *arg) {
712 struct dbgcl *p;
713 int rv=EINVAL;
714 for (p=dbgclh; p!=NULL; p=p->next) {
715 if (strncmp(p->path, path, strlen(path)) == 0) {
716 int i;
717 if (rv==EINVAL) rv=EEXIST;
718 for(i=0;i<p->nfun && (p->fun[i] != fun); i++)
720 if (i>=p->nfun) {
721 if (i>=p->maxfun) {
722 int newsize=p->maxfun+DBGCLSTEP;
723 p->fun=realloc(p->fun,newsize*sizeof(int));
724 p->funarg=realloc(p->funarg,newsize*sizeof(void *));
725 if (p->fun && p->funarg) {
726 p->maxfun=newsize;
727 p->fun[i]=fun;
728 p->funarg[i]=arg;
729 p->nfun++;
730 if (rv != ENOMEM) rv=0;
731 } else
732 rv=ENOMEM;
733 } else {
734 p->fun[i]=fun;
735 p->nfun++;
736 if (rv != ENOMEM) rv=0;
741 return rv;
744 /* EINVAL -> no matches
745 * ENOENT -> all the matches do not include fun
746 * 0 otherwise */
747 int eventdel(int (*fun)(),char *path,void *arg) {
748 struct dbgcl *p;
749 int rv=EINVAL;
750 for (p=dbgclh; p!=NULL; p=p->next){
751 if (strncmp(p->path, path, strlen(path)) == 0) {
752 int i;
753 if (rv==EINVAL) rv=ENOENT;
754 for(i=0;i<p->nfun && (p->fun[i] != fun) && (p->funarg[i] != arg); i++)
756 if (i<p->nfun) {
757 p->nfun--; /* the last one */
758 p->fun[i]=p->fun[p->nfun]; /* swap it with the deleted element*/
759 rv=0;
763 return rv;
766 #endif
768 #ifdef VDEPLUGIN
769 static int pluginlist(FILE *f,char *arg)
771 #define PLUGINFMT "%-22s %s"
772 struct plugin *p;
773 int rv=ENOENT;
774 printoutc(f,PLUGINFMT,"NAME", "HELP");
775 printoutc(f,PLUGINFMT,"------------","----");
776 for (p=pluginh; p!=NULL; p=p->next){
777 if (strncmp(p->name, arg, strlen(arg)) == 0) {
778 printoutc(f,PLUGINFMT,p->name,p->help);
779 rv=0;
782 return rv;
785 static int pluginadd(char *arg) {
786 void *handle;
787 struct plugin *p;
788 int rv=ENOENT;
789 if ((handle=dlopen(arg,RTLD_LAZY)) != NULL) {
790 if ((p=(struct plugin *) dlsym(handle,"vde_plugin_data")) != NULL) {
791 if (p->handle != NULL) { /* this dyn library is already loaded*/
792 dlclose(handle);
793 rv=EEXIST;
794 } else {
795 addplugin(p);
796 p->handle=handle;
797 rv=0;
799 } else {
800 rv=EINVAL;
803 return rv;
806 static int plugindel(char *arg) {
807 struct plugin **p=&pluginh;
808 while (*p!=NULL){
809 void *handle;
810 if (strncmp((*p)->name, arg, strlen(arg)) == 0
811 && ((*p)->handle != NULL)) {
812 struct plugin *this=*p;
813 delplugin(this);
814 handle=this->handle;
815 this->handle=NULL;
816 dlclose(handle);
817 return 0;
818 } else
819 p=&(*p)->next;
821 return ENOENT;
823 #endif
825 static struct comlist cl[]={
826 {"help","[arg]","Help (limited to arg when specified)",help,STRARG | WITHFILE},
827 {"logout","","logout from this mgmt terminal",vde_logout,NOARG},
828 {"shutdown","","shutdown of the switch",vde_shutdown,NOARG},
829 {"showinfo","","show switch version and info",showinfo,NOARG|WITHFILE},
830 {"load","path","load a configuration script",runscript,STRARG|WITHFD},
831 #ifdef DEBUGOPT
832 {"debug","============","DEBUG MENU",NULL,NOARG},
833 {"debug/list","","list debug categories",debuglist,STRARG|WITHFILE|WITHFD},
834 {"debug/add","dbgpath","enable debug info for a given category",debugadd,WITHFD|STRARG},
835 {"debug/del","dbgpath","disable debug info for a given category",debugdel,WITHFD|STRARG},
836 #endif
837 #ifdef VDEPLUGIN
838 {"plugin","============","PLUGINS MENU",NULL,NOARG},
839 {"plugin/list","","list plugins",pluginlist,STRARG|WITHFILE},
840 {"plugin/add","library","load a plugin",pluginadd,STRARG},
841 {"plugin/del","name","unload a plugin",plugindel,STRARG},
842 #endif
845 void start_consmgmt(void)
847 swmi.swmname="console-mgmt";
848 swmi.swmnopts=Nlong_options;
849 swmi.swmopts=long_options;
850 swmi.usage=usage;
851 swmi.parseopt=parseopt;
852 swmi.init=init;
853 swmi.handle_input=handle_input;
854 swmi.cleanup=cleanup;
855 ADDCL(cl);
856 #ifdef DEBUGOPT
857 ADDDBGCL(dl);
858 #endif
859 add_swm(&swmi);