Added dynamic loadable traffic control/queuing discipline support for vde_l3.
[vde.git] / vde-2 / consmgmt.c
blobba9ca11f308e4063c5bf0838950b5d6b417e59a3
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 <config.h>
9 #include <stdio.h>
10 #include <fcntl.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <syslog.h>
15 #include <stdlib.h>
16 #include <libgen.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/ioctl.h>
20 #include <sys/socket.h>
21 #include <sys/poll.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>
29 #include <vde.h>
30 #include <port.h>
31 #include <switch.h>
32 #include <sockutils.h>
33 #include <consmgmt.h>
34 #include <qtimer.h>
35 #include <packetq.h>
37 #define MAXCMD 128
39 #ifndef HAVE_OPEN_MEMSTREAM
40 #include <utils/open_memstream.h>
41 #endif
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 char *mgmt_socket = NULL;
55 static char header[]="VDE switch V.%s\n(C) Virtual Square Team (coord. R. Davoli) 2005,2006,2007 - GPLv2\n";
56 static char prompt[]="\nvde$ ";
58 static struct comlist *clh=NULL;
59 static struct comlist **clt=&clh;
60 #ifdef DEBUGOPT
61 #define DBGCLSTEP 8
62 static struct dbgcl *dbgclh=NULL;
63 static struct dbgcl **dbgclt=&dbgclh;
64 #define MGMTPORTNEW (dl)
65 #define MGMTPORTDEL (dl+1)
66 static struct dbgcl dl[]= {
67 {"mgmt/+",NULL,D_MGMT|D_PLUS},
68 {"mgmt/-",NULL,D_MGMT|D_MINUS}
70 #endif
71 #ifdef VDEPLUGIN
72 static struct plugin *pluginh=NULL;
73 static struct plugin **plugint=&pluginh;
74 #endif
76 void addcl(int ncl,struct comlist *cl)
78 register int i;
79 for (i=0;i<ncl;i++,cl++) {
80 cl->next=NULL;
81 (*clt)=cl;
82 clt=(&cl->next);
86 void delcl(int ncl,struct comlist *cl)
88 register int i;
89 for (i=0;i<ncl;i++,cl++) {
90 register struct comlist **p=&clh;
91 while (*p != NULL) {
92 if (*p == cl)
93 *p=cl->next;
94 else {
95 p=&(*p)->next;
96 clt=p;
102 #ifdef DEBUGOPT
103 void adddbgcl(int ncl,struct dbgcl *cl)
105 int i;
106 for (i=0;i<ncl;i++,cl++) {
107 cl->next=NULL;
108 (*dbgclt)=cl;
109 dbgclt=(&cl->next);
113 void deldbgcl(int ncl,struct dbgcl *cl)
115 register int i;
116 for (i=0;i<ncl;i++,cl++) {
117 register struct dbgcl **p=&dbgclh;
118 while (*p != NULL) {
119 if (*p == cl) {
120 if (cl->fds) free(cl->fds);
121 if (cl->fun) free(cl->fun);
122 *p=cl->next;
123 } else {
124 p=&(*p)->next;
125 dbgclt=p;
130 #endif
132 #ifdef VDEPLUGIN
133 void addplugin(struct plugin *cl)
135 cl->next=NULL;
136 (*plugint)=cl;
137 plugint=(&cl->next);
140 void delplugin(struct plugin *cl)
142 register struct plugin **p=&pluginh;
143 while (*p != NULL) {
144 if (*p == cl)
145 *p=cl->next;
146 else {
147 p=&(*p)->next;
148 plugint=p;
152 #endif
154 void printlog(int priority, const char *format, ...)
156 va_list arg;
158 va_start (arg, format);
160 if (logok)
161 vsyslog(priority,format,arg);
162 else {
163 fprintf(stderr,"%s: ",prog);
164 vfprintf(stderr,format,arg);
165 fprintf(stderr,"\n");
167 va_end (arg);
170 #if 0
171 void printoutc(int fd, const char *format, ...)
173 va_list arg;
175 va_start (arg, format);
176 #if 0
177 if (fd < 0)
178 printlog(LOG_INFO,format,arg);
179 else {
180 #endif
181 char outbuf[MAXCMD+1];
182 vsnprintf(outbuf,MAXCMD,format,arg);
183 strcat(outbuf,"\n");
184 write(fd,outbuf,strlen(outbuf));
185 #if 0
187 #endif
189 #endif
191 void printoutc(FILE *f, const char *format, ...)
193 va_list arg;
195 va_start (arg, format);
196 if (f) {
197 vfprintf(f,format,arg);
198 fprintf(f,"\n");
199 } else
200 printlog(LOG_INFO,format,arg);
201 va_end(arg);
204 #ifdef DEBUGOPT
205 static char _dbgnl='\n';
206 void debugout(struct dbgcl* cl, const char *format, ...)
208 va_list arg;
209 char *msg;
210 int i;
211 char *header;
212 struct iovec iov[]={{NULL,0},{NULL,0},{&_dbgnl,1}};
214 va_start (arg, format);
215 iov[0].iov_len=asprintf(&header,"3%03o %s ",cl->tag & 0777,cl->path);
216 iov[0].iov_base=header;
217 iov[1].iov_len=vasprintf(&msg,format,arg);
218 iov[1].iov_base=msg;
219 va_end (arg);
221 for (i=0; i<cl->nfds; i++)
222 writev(cl->fds[i],iov,3);
223 free(header);
224 free(msg);
227 void eventout(struct dbgcl* cl, ...)
229 int i;
230 va_list arg;
231 for (i=0; i<cl->nfun; i++) {
232 va_start (arg, cl);
233 (cl->fun[i])(cl,arg);
234 va_end(arg);
238 int packetfilter(struct dbgcl* cl, ...)
240 int i;
241 va_list arg;
242 int len;
243 va_start (arg, cl);
244 (void) va_arg(arg,int); /*port*/
245 (void) va_arg(arg,char *); /*buf*/
246 len=va_arg(arg,int);
247 va_end(arg);
248 for (i=0; i<cl->nfun && len>0; i++) {
249 va_start (arg, cl);
250 int rv=(cl->fun[i])(cl,arg);
251 va_end (arg);
252 if (rv!=0)
253 len=rv;
255 if (len < 0)
256 return 0;
257 else
258 return len;
260 #endif
262 void setmgmtperm(char *path)
264 chmod(path,mgmt_mode);
267 static int help(FILE *fd,char *arg)
269 struct comlist *p;
270 int n=strlen(arg);
271 printoutc(fd,"%-18s %-15s %s","COMMAND PATH","SYNTAX","HELP");
272 printoutc(fd,"%-18s %-15s %s","------------","--------------","------------");
273 for (p=clh;p!=NULL;p=p->next)
274 if (strncmp(p->path,arg,n) == 0)
275 printoutc(fd,"%-18s %-15s %s",p->path,p->syntax,p->help);
276 return 0;
279 static int handle_cmd(int type,int fd,char *inbuf)
281 struct comlist *p;
282 int rv=ENOSYS;
283 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
284 if (*inbuf != '\0' && *inbuf != '#') {
285 char *outbuf;
286 size_t outbufsize;
287 FILE *f;
288 if (fd >= 0)
289 f=open_memstream(&outbuf,&outbufsize);
290 else
291 f=NULL;
292 for (p=clh;p!=NULL && (p->doit==NULL || strncmp(p->path,inbuf,strlen(p->path))!=0); p=p->next)
294 if (p!=NULL)
296 inbuf += strlen(p->path);
297 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
298 if (p->type & WITHFD) {
299 if (p->type & WITHFILE) {
300 printoutc(f,"0000 DATA END WITH '.'");
301 switch(p->type & ~(WITHFILE | WITHFD)){
302 case NOARG: rv=p->doit(f,fd); break;
303 case INTARG: rv=p->doit(f,fd,atoi(inbuf)); break;
304 case STRARG: rv=p->doit(f,fd,inbuf); break;
306 printoutc(f,".");
307 } else {
308 switch(p->type & ~WITHFD){
309 case NOARG: rv=p->doit(fd); break;
310 case INTARG: rv=p->doit(fd,atoi(inbuf)); break;
311 case STRARG: rv=p->doit(fd,inbuf); break;
314 } else if (p->type & WITHFILE) {
315 printoutc(f,"0000 DATA END WITH '.'");
316 switch(p->type & ~WITHFILE){
317 case NOARG: rv=p->doit(f); break;
318 case INTARG: rv=p->doit(f,atoi(inbuf)); break;
319 case STRARG: rv=p->doit(f,inbuf); break;
321 printoutc(f,".");
322 } else {
323 switch(p->type){
324 case NOARG: rv=p->doit(); break;
325 case INTARG: rv=p->doit(atoi(inbuf)); break;
326 case STRARG: rv=p->doit(inbuf); break;
330 if (rv >= 0 && (rv > 0 || fd >= 0))
331 printoutc(f,"1%03d %s",rv,strerror(rv));
332 if (f) {
333 fclose(f);
334 write(fd,outbuf,outbufsize);
335 free(outbuf);
338 return rv;
341 static int runscript(int fd,char *path)
343 FILE *f=fopen(path,"r");
344 char buf[MAXCMD];
345 if (f==NULL)
346 return ENOENT;
347 else {
348 while (fgets(buf,MAXCMD,f) != NULL) {
349 if (strlen(buf) > 1 && buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]= '\0';
350 if (fd >= 0) {
351 char *scriptprompt=NULL;
352 asprintf(&scriptprompt,"vde[%s]: %s",path,buf);
353 write(fd,scriptprompt,strlen(scriptprompt));
354 free(scriptprompt);
356 handle_cmd(mgmt_data, fd, buf);
358 return 0;
362 void loadrcfile(void)
364 if (rcfile != NULL)
365 runscript(-1,rcfile);
366 else {
367 char path[PATH_MAX];
368 snprintf(path,PATH_MAX,"%s/.vderc",getenv("HOME"));
369 if (access(path,R_OK) == 0)
370 runscript(-1,path);
371 else {
372 if (access(STDRCFILE,R_OK) == 0)
373 runscript(-1,STDRCFILE);
378 void mgmtnewfd(int new)
380 char buf[MAXCMD];
381 if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
382 printlog(LOG_WARNING,"mgmt fcntl - setting O_NONBLOCK %s",strerror(errno));
383 close(new);
384 return;
387 add_fd(new,mgmt_data,-1);
388 EVENTOUT(MGMTPORTNEW,new);
389 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
390 write(new,buf,strlen(buf));
391 write(new,prompt,strlen(prompt));
394 #ifdef DEBUGOPT
395 static int debugdel(int fd,char *arg);
396 #endif
397 static char *EOS="9999 END OF SESSION";
398 static void handle_input(unsigned char type,int fd,int revents,int *unused)
400 char buf[MAXCMD];
401 if (type != mgmt_ctl) {
402 int n=0;
404 if (revents & POLLIN) {
405 n = read(fd, buf, sizeof(buf));
406 if(n < 0){
407 printlog(LOG_WARNING,"Reading from mgmt %s",strerror(errno));
410 if (n==0) { /*EOF*/
411 if (type == console_type) {
412 printlog(LOG_WARNING,"EOF on stdin, cleaning up and exiting");
413 exit(0);
414 } else {
415 #ifdef DEBUGOPT
416 debugdel(fd,"");
417 #endif
418 remove_fd(fd);
420 } else {
421 int cmdout;
422 buf[n]=0;
423 if (n>0 && buf[n-1] == '\n') buf[n-1] = 0;
424 cmdout=handle_cmd(type,(type==console_type)?STDOUT_FILENO:fd,buf);
425 if (cmdout >= 0)
426 write(fd,prompt,strlen(prompt));
427 else {
428 if(type==mgmt_data) {
429 write(fd,EOS,strlen(EOS));
430 #ifdef DEBUGOPT
431 EVENTOUT(MGMTPORTDEL,fd);
432 debugdel(fd,"");
433 #endif
434 remove_fd(fd);
436 if (cmdout == -2)
437 exit(0);
440 } else {/* mgmt ctl */
441 struct sockaddr addr;
442 int new;
443 socklen_t len;
445 len = sizeof(addr);
446 new = accept(fd, &addr, &len);
447 if(new < 0){
448 printlog(LOG_WARNING,"mgmt accept %s",strerror(errno));
449 return;
451 if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
452 printlog(LOG_WARNING,"mgmt fcntl - setting O_NONBLOCK %s",strerror(errno));
453 close(new);
454 return;
457 add_fd(new,mgmt_data,-1);
458 EVENTOUT(MGMTPORTNEW,new);
459 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
460 write(new,buf,strlen(buf));
461 write(new,prompt,strlen(prompt));
465 static void save_pidfile()
467 if(pidfile[0] != '/')
468 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
469 else
470 strcpy(pidfile_path, pidfile);
472 int fd = open(pidfile_path,
473 O_WRONLY | O_CREAT | O_EXCL,
474 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
475 FILE *f;
477 if(fd == -1) {
478 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
479 exit(1);
482 if((f = fdopen(fd, "w")) == NULL) {
483 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
484 exit(1);
487 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
488 printlog(LOG_ERR, "Error in writing pidfile");
489 exit(1);
492 fclose(f);
495 static void cleanup(unsigned char type,int fd,int arg)
497 if (fd < 0) {
498 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
499 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
501 } else {
502 close(fd);
503 if (type == mgmt_ctl && mgmt_socket != NULL) {
504 unlink(mgmt_socket);
509 #define MGMTMODEARG 0x100
511 static struct option long_options[] = {
512 {"daemon", 0, 0, 'd'},
513 {"pidfile", 1, 0, 'p'},
514 {"rcfile", 1, 0, 'f'},
515 {"mgmt", 1, 0, 'M'},
516 {"mgmtmode", 1, 0, MGMTMODEARG},
517 #ifdef DEBUGOPT
518 {"debugclients",1,0,'D'},
519 #endif
522 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
524 static void usage(void)
526 printf(
527 "(opts from consmgmt module)\n"
528 " -d, --daemon Daemonize vde_switch once run\n"
529 " -p, --pidfile PIDFILE Write pid of daemon to PIDFILE\n"
530 " -f, --rcfile Configuration file (overrides %s and ~/.vderc)\n"
531 " -M, --mgmt SOCK path of the management UNIX socket\n"
532 " --mgmtmode MODE management UNIX socket access mode (octal)\n"
533 #ifdef DEBUGOPT
534 " -D, --debugclients # number of debug clients allowed\n"
535 #endif
536 ,STDRCFILE);
539 static int parseopt(int c, char *optarg)
541 int outc=0;
542 switch (c) {
543 case 'd':
544 daemonize=1;
545 break;
546 case 'p':
547 pidfile=strdup(optarg);
548 break;
549 case 'f':
550 rcfile=strdup(optarg);
551 break;
552 case 'M':
553 mgmt_socket=strdup(optarg);
554 break;
555 case MGMTMODEARG:
556 sscanf(optarg,"%o",&mgmt_mode);
557 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,-1);
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 chmod(sun.sun_path,mgmt_mode);
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,-1);
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 printoutc(fd,"unsent_pktq_len %d",packetq_count());
653 return 0;
656 #ifdef DEBUGOPT
657 static int debuglist(FILE *f,int fd,char *path)
659 #define DEBUGFORMAT1 "%-22s %-3s %-6s %s"
660 #define DEBUGFORMAT2 "%-22s %03o %-6s %s"
661 struct dbgcl *p;
662 int i;
663 int rv=ENOENT;
664 printoutc(f,DEBUGFORMAT1,"CATEGORY", "TAG", "STATUS", "HELP");
665 printoutc(f,DEBUGFORMAT1,"------------","---","------", "----");
666 for (p=dbgclh; p!=NULL; p=p->next){
667 if (p->help && strncmp(p->path, path, strlen(path)) == 0) {
668 for (i=0; i<p->nfds && p->fds[i] != fd; i++)
670 rv=0;
671 printoutc(f, DEBUGFORMAT2, p->path, p->tag &0777, i<p->nfds ? "ON" : "OFF", p->help);
674 return rv;
677 /* EINVAL -> no matches
678 * EEXIST -> all the matches already include fd
679 * ENOMEM -> fd buffer realloc failed
680 * 0 otherwise */
681 static int debugadd(int fd,char *path) {
682 struct dbgcl *p;
683 int rv=EINVAL;
684 for (p=dbgclh; p!=NULL; p=p->next) {
685 if (p->help && strncmp(p->path, path, strlen(path)) == 0) {
686 int i;
687 if (rv==EINVAL) rv=EEXIST;
688 for(i=0;i<p->nfds && (p->fds[i] != fd); i++)
690 if (i>=p->nfds) {
691 if (i>=p->maxfds) {
692 int newsize=p->maxfds+DBGCLSTEP;
693 p->fds=realloc(p->fds,newsize*sizeof(int));
694 if (p->fds) {
695 p->maxfds=newsize;
696 p->fds[i]=fd;
697 p->nfds++;
698 if (rv != ENOMEM) rv=0;
699 } else
700 rv=ENOMEM;
701 } else {
702 p->fds[i]=fd;
703 p->nfds++;
704 if (rv != ENOMEM) rv=0;
709 return rv;
712 /* EINVAL -> no matches
713 * ENOENT -> all the matches do not include fd
714 * 0 otherwise */
715 static int debugdel(int fd,char *path) {
716 struct dbgcl *p;
717 int rv=EINVAL;
718 for (p=dbgclh; p!=NULL; p=p->next){
719 if (strncmp(p->path, path, strlen(path)) == 0) {
720 int i;
721 if (rv==EINVAL) rv=ENOENT;
722 for(i=0;i<p->nfds && (p->fds[i] != fd); i++)
724 if (i<p->nfds) {
725 p->nfds--; /* the last one */
726 p->fds[i]=p->fds[p->nfds]; /* swap it with the deleted element*/
727 rv=0;
731 return rv;
734 int eventadd(int (*fun)(),char *path,void *arg) {
735 struct dbgcl *p;
736 int rv=EINVAL;
737 for (p=dbgclh; p!=NULL; p=p->next) {
738 if (strncmp(p->path, path, strlen(path)) == 0) {
739 int i;
740 if (rv==EINVAL) rv=EEXIST;
741 for(i=0;i<p->nfun && (p->fun[i] != fun); i++)
743 if (i>=p->nfun) {
744 if (i>=p->maxfun) {
745 int newsize=p->maxfun+DBGCLSTEP;
746 p->fun=realloc(p->fun,newsize*sizeof(int));
747 p->funarg=realloc(p->funarg,newsize*sizeof(void *));
748 if (p->fun && p->funarg) {
749 p->maxfun=newsize;
750 p->fun[i]=fun;
751 p->funarg[i]=arg;
752 p->nfun++;
753 if (rv != ENOMEM) rv=0;
754 } else
755 rv=ENOMEM;
756 } else {
757 p->fun[i]=fun;
758 p->nfun++;
759 if (rv != ENOMEM) rv=0;
764 return rv;
767 /* EINVAL -> no matches
768 * ENOENT -> all the matches do not include fun
769 * 0 otherwise */
770 int eventdel(int (*fun)(),char *path,void *arg) {
771 struct dbgcl *p;
772 int rv=EINVAL;
773 for (p=dbgclh; p!=NULL; p=p->next){
774 if (strncmp(p->path, path, strlen(path)) == 0) {
775 int i;
776 if (rv==EINVAL) rv=ENOENT;
777 for(i=0;i<p->nfun && (p->fun[i] != fun) && (p->funarg[i] != arg); i++)
779 if (i<p->nfun) {
780 p->nfun--; /* the last one */
781 p->fun[i]=p->fun[p->nfun]; /* swap it with the deleted element*/
782 rv=0;
786 return rv;
789 #endif
791 #ifdef VDEPLUGIN
792 static int pluginlist(FILE *f,char *arg)
794 #define PLUGINFMT "%-22s %s"
795 struct plugin *p;
796 int rv=ENOENT;
797 printoutc(f,PLUGINFMT,"NAME", "HELP");
798 printoutc(f,PLUGINFMT,"------------","----");
799 for (p=pluginh; p!=NULL; p=p->next){
800 if (strncmp(p->name, arg, strlen(arg)) == 0) {
801 printoutc(f,PLUGINFMT,p->name,p->help);
802 rv=0;
805 return rv;
808 static int pluginadd(char *arg) {
809 void *handle;
810 struct plugin *p;
811 int rv=ENOENT;
812 if ((handle=dlopen(arg,RTLD_LAZY)) != NULL) {
813 if ((p=(struct plugin *) dlsym(handle,"vde_plugin_data")) != NULL) {
814 if (p->handle != NULL) { /* this dyn library is already loaded*/
815 dlclose(handle);
816 rv=EEXIST;
817 } else {
818 addplugin(p);
819 p->handle=handle;
820 rv=0;
822 } else {
823 rv=EINVAL;
826 return rv;
829 static int plugindel(char *arg) {
830 int rv=ENOENT;
831 struct plugin **p=&pluginh;
832 while (*p!=NULL){
833 if (strncmp((*p)->name, arg, strlen(arg)) == 0
834 && ((*p)->handle != NULL)) {
835 struct plugin *this=*p;
836 delplugin(this);
837 dlclose(this->handle);
838 rv=0;
839 } else
840 p=&(*p)->next;
842 return rv;
844 #endif
846 static struct comlist cl[]={
847 {"help","[arg]","Help (limited to arg when specified)",help,STRARG | WITHFILE},
848 {"logout","","logout from this mgmt terminal",vde_logout,NOARG},
849 {"shutdown","","shutdown of the switch",vde_shutdown,NOARG},
850 {"showinfo","","show switch version and info",showinfo,NOARG|WITHFILE},
851 {"load","path","load a configuration script",runscript,STRARG|WITHFD},
852 #ifdef DEBUGOPT
853 {"debug","============","DEBUG MENU",NULL,NOARG},
854 {"debug/list","","list debug categories",debuglist,STRARG|WITHFILE|WITHFD},
855 {"debug/add","dbgpath","enable debug info for a given category",debugadd,WITHFD|STRARG},
856 {"debug/del","dbgpath","disable debug info for a given category",debugdel,WITHFD|STRARG},
857 #endif
858 #ifdef VDEPLUGIN
859 {"plugin","============","PLUGINS MENU",NULL,NOARG},
860 {"plugin/list","","list plugins",pluginlist,STRARG|WITHFILE},
861 {"plugin/add","library","load a plugin",pluginadd,STRARG},
862 {"plugin/del","name","unload a plugin",plugindel,STRARG},
863 #endif
866 void start_consmgmt(void)
868 swmi.swmname="console-mgmt";
869 swmi.swmnopts=Nlong_options;
870 swmi.swmopts=long_options;
871 swmi.usage=usage;
872 swmi.parseopt=parseopt;
873 swmi.init=init;
874 swmi.handle_input=handle_input;
875 swmi.cleanup=cleanup;
876 ADDCL(cl);
877 #ifdef DEBUGOPT
878 ADDDBGCL(dl);
879 #endif
880 add_swm(&swmi);