In 2014, I think we can stop trying to outsmart the compiler. Remove
[vde.git] / vde-2 / src / kvde_switch / consmgmt.c
blobff4d600e6553500bdec189c8e456b8f1db520e08
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 <limits.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/un.h>
22 #include <sys/uio.h>
23 #include <net/if.h>
24 #include <stdarg.h>
25 #include <getopt.h>
26 #include <dlfcn.h>
27 #include <time.h>
29 #include <config.h>
30 #include <vde.h>
31 #include <vdecommon.h>
33 #include "../vde_switch/switch.h"
34 #include "sockutils.h"
35 #include "consmgmt.h"
37 #define MAXCMD 128
39 static struct swmodule swmi;
40 extern time_t starting_time;
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[]="KVDE switch V.%s\n(C) Virtual Square Team (coord. R. Davoli) 2005,...,2008 - 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 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 int i;
86 for (i=0;i<ncl;i++,cl++) {
87 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 int i;
113 for (i=0;i<ncl;i++,cl++) {
114 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 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 #if 0
168 void printoutc(int fd, const char *format, ...)
170 va_list arg;
172 va_start (arg, format);
173 #if 0
174 if (fd < 0)
175 printlog(LOG_INFO,format,arg);
176 else {
177 #endif
178 char outbuf[MAXCMD+1];
179 vsnprintf(outbuf,MAXCMD,format,arg);
180 strcat(outbuf,"\n");
181 write(fd,outbuf,strlen(outbuf));
182 #if 0
184 #endif
186 #endif
188 void printoutc(FILE *f, const char *format, ...)
190 va_list arg;
192 va_start (arg, format);
193 if (f) {
194 vfprintf(f,format,arg);
195 fprintf(f,"\n");
196 } else
197 printlog(LOG_INFO,format,arg);
198 va_end(arg);
201 #ifdef DEBUGOPT
202 static char _dbgnl='\n';
203 void debugout(struct dbgcl* cl, const char *format, ...)
205 va_list arg;
206 char *msg;
207 int i;
208 char *header;
209 struct iovec iov[]={{NULL,0},{NULL,0},{&_dbgnl,1}};
211 va_start (arg, format);
212 iov[0].iov_len=asprintf(&header,"3%03o %s ",cl->tag & 0777,cl->path);
213 iov[0].iov_base=header;
214 iov[1].iov_len=vasprintf(&msg,format,arg);
215 iov[1].iov_base=msg;
216 va_end (arg);
218 for (i=0; i<cl->nfds; i++)
219 writev(cl->fds[i],iov,3);
220 free(header);
221 free(msg);
224 void eventout(struct dbgcl* cl, ...)
226 int i;
227 va_list arg;
228 for (i=0; i<cl->nfun; i++) {
229 va_start (arg, cl);
230 (cl->fun[i])(cl,arg);
231 va_end(arg);
235 int packetfilter(struct dbgcl* cl, ...)
237 int i;
238 va_list arg;
239 int len;
240 va_start (arg, cl);
241 (void) va_arg(arg,int); /*port*/
242 (void) va_arg(arg,char *); /*buf*/
243 len=va_arg(arg,int);
244 va_end(arg);
245 for (i=0; i<cl->nfun && len>0; i++) {
246 va_start (arg, cl);
247 int rv=(cl->fun[i])(cl,arg);
248 va_end (arg);
249 if (rv!=0)
250 len=rv;
252 if (len < 0)
253 return 0;
254 else
255 return len;
257 #endif
259 void setmgmtperm(char *path)
261 chmod(path,mgmt_mode);
264 static int help(FILE *fd,char *arg)
266 struct comlist *p;
267 int n=strlen(arg);
268 printoutc(fd,"%-18s %-15s %s","COMMAND PATH","SYNTAX","HELP");
269 printoutc(fd,"%-18s %-15s %s","------------","--------------","------------");
270 for (p=clh;p!=NULL;p=p->next)
271 if (strncmp(p->path,arg,n) == 0)
272 printoutc(fd,"%-18s %-15s %s",p->path,p->syntax,p->help);
273 return 0;
276 static int handle_cmd(int type,int fd,char *inbuf)
278 struct comlist *p;
279 int rv=ENOSYS;
280 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
281 if (*inbuf != '\0' && *inbuf != '#') {
282 char *outbuf;
283 size_t outbufsize;
284 FILE *f;
285 if (fd >= 0)
286 f=open_memstream(&outbuf,&outbufsize);
287 else
288 f=NULL;
289 for (p=clh;p!=NULL && (p->doit==NULL || strncmp(p->path,inbuf,strlen(p->path))!=0); p=p->next)
291 if (p!=NULL)
293 inbuf += strlen(p->path);
294 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
295 if (p->type & WITHFD) {
296 if (p->type & WITHFILE) {
297 printoutc(f,"0000 DATA END WITH '.'");
298 switch(p->type & ~(WITHFILE | WITHFD)){
299 case NOARG: rv=p->doit(f,fd); break;
300 case INTARG: rv=p->doit(f,fd,atoi(inbuf)); break;
301 case STRARG: rv=p->doit(f,fd,inbuf); break;
303 printoutc(f,".");
304 } else {
305 switch(p->type & ~WITHFD){
306 case NOARG: rv=p->doit(fd); break;
307 case INTARG: rv=p->doit(fd,atoi(inbuf)); break;
308 case STRARG: rv=p->doit(fd,inbuf); break;
311 } else if (p->type & WITHFILE) {
312 printoutc(f,"0000 DATA END WITH '.'");
313 switch(p->type & ~WITHFILE){
314 case NOARG: rv=p->doit(f); break;
315 case INTARG: rv=p->doit(f,atoi(inbuf)); break;
316 case STRARG: rv=p->doit(f,inbuf); break;
318 printoutc(f,".");
319 } else {
320 switch(p->type){
321 case NOARG: rv=p->doit(); break;
322 case INTARG: rv=p->doit(atoi(inbuf)); break;
323 case STRARG: rv=p->doit(inbuf); break;
327 if (rv >= 0 && (rv > 0 || fd >= 0))
328 printoutc(f,"1%03d %s",rv,strerror(rv));
329 if (f) {
330 fclose(f);
331 write(fd,outbuf,outbufsize);
332 free(outbuf);
335 return rv;
338 static int runscript(int fd,char *path)
340 FILE *f=fopen(path,"r");
341 char buf[MAXCMD];
342 if (f==NULL)
343 return ENOENT;
344 else {
345 while (fgets(buf,MAXCMD,f) != NULL) {
346 if (strlen(buf) > 1 && buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]= '\0';
347 if (fd >= 0) {
348 char *scriptprompt=NULL;
349 asprintf(&scriptprompt,"vde[%s]: %s",path,buf);
350 write(fd,scriptprompt,strlen(scriptprompt));
351 free(scriptprompt);
353 handle_cmd(mgmt_data, fd, buf);
355 return 0;
359 void loadrcfile(void)
361 if (rcfile != NULL)
362 runscript(-1,rcfile);
363 else {
364 char path[PATH_MAX];
365 snprintf(path,PATH_MAX,"%s/.vde2/vde_switch.rc",getenv("HOME"));
366 if (access(path,R_OK) == 0)
367 runscript(-1,path);
368 else {
369 if (access(STDRCFILE,R_OK) == 0)
370 runscript(-1,STDRCFILE);
375 void mgmtnewfd(int new)
377 char buf[MAXCMD];
378 if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
379 printlog(LOG_WARNING,"mgmt fcntl - setting O_NONBLOCK %s",strerror(errno));
380 close(new);
381 return;
384 add_fd(new,mgmt_data,NULL);
385 EVENTOUT(MGMTPORTNEW,new);
386 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
387 write(new,buf,strlen(buf));
388 write(new,prompt,strlen(prompt));
391 #ifdef DEBUGOPT
392 static int debugdel(int fd,char *arg);
393 #endif
394 static char *EOS="9999 END OF SESSION";
395 static void handle_io(unsigned char type,int fd,int revents,void *unused)
397 char buf[MAXCMD];
398 if (type != mgmt_ctl) {
399 int n=0;
401 if (revents & POLLIN) {
402 n = read(fd, buf, sizeof(buf));
403 if(n < 0){
404 printlog(LOG_WARNING,"Reading from mgmt %s",strerror(errno));
407 if (n==0) { /*EOF*/
408 if (type == console_type) {
409 printlog(LOG_WARNING,"EOF on stdin, cleaning up and exiting");
410 exit(0);
411 } else {
412 #ifdef DEBUGOPT
413 debugdel(fd,"");
414 #endif
415 remove_fd(fd);
417 } else {
418 int cmdout;
419 buf[n]=0;
420 if (n>0 && buf[n-1] == '\n') buf[n-1] = 0;
421 cmdout=handle_cmd(type,(type==console_type)?STDOUT_FILENO:fd,buf);
422 if (cmdout >= 0)
423 write(fd,prompt,strlen(prompt));
424 else {
425 if(type==mgmt_data) {
426 write(fd,EOS,strlen(EOS));
427 #ifdef DEBUGOPT
428 EVENTOUT(MGMTPORTDEL,fd);
429 debugdel(fd,"");
430 #endif
431 remove_fd(fd);
433 if (cmdout == -2)
434 exit(0);
437 } else {/* mgmt ctl */
438 struct sockaddr addr;
439 int new;
440 socklen_t len;
442 len = sizeof(addr);
443 new = accept(fd, &addr, &len);
444 if(new < 0){
445 printlog(LOG_WARNING,"mgmt accept %s",strerror(errno));
446 return;
448 if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
449 printlog(LOG_WARNING,"mgmt fcntl - setting O_NONBLOCK %s",strerror(errno));
450 close(new);
451 return;
454 add_fd(new,mgmt_data,NULL);
455 EVENTOUT(MGMTPORTNEW,new);
456 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
457 write(new,buf,strlen(buf));
458 write(new,prompt,strlen(prompt));
462 static void save_pidfile()
464 if(pidfile[0] != '/')
465 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path) - 1);
466 else
467 strncpy(pidfile_path, pidfile, PATH_MAX - 1);
469 int fd = open(pidfile_path,
470 O_WRONLY | O_CREAT | O_EXCL,
471 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
472 FILE *f;
474 if(fd == -1) {
475 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
476 exit(1);
479 if((f = fdopen(fd, "w")) == NULL) {
480 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
481 exit(1);
484 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
485 printlog(LOG_ERR, "Error in writing pidfile");
486 exit(1);
489 fclose(f);
492 static void cleanup(unsigned char type,int fd,void *unused)
494 if (fd < 0) {
495 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
496 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
498 } else {
499 close(fd);
500 if (type == mgmt_ctl && mgmt_socket != NULL) {
501 unlink(mgmt_socket);
506 #define MGMTMODEARG 0x100
508 static struct option long_options[] = {
509 {"daemon", 0, 0, 'd'},
510 {"pidfile", 1, 0, 'p'},
511 {"rcfile", 1, 0, 'f'},
512 {"mgmt", 1, 0, 'M'},
513 {"mgmtmode", 1, 0, MGMTMODEARG},
514 #ifdef DEBUGOPT
515 {"debugclients",1,0,'D'},
516 #endif
519 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
521 static void usage(void)
523 printf(
524 "(opts from consmgmt module)\n"
525 " -d, --daemon Daemonize vde_switch once run\n"
526 " -p, --pidfile PIDFILE Write pid of daemon to PIDFILE\n"
527 " -f, --rcfile Configuration file (overrides %s and ~/.vderc)\n"
528 " -M, --mgmt SOCK path of the management UNIX socket\n"
529 " --mgmtmode MODE management UNIX socket access mode (octal)\n"
530 #ifdef DEBUGOPT
531 " -D, --debugclients # number of debug clients allowed\n"
532 #endif
533 ,STDRCFILE);
536 static int parseopt(int c, char *optarg)
538 int outc=0;
539 switch (c) {
540 case 'd':
541 daemonize=1;
542 break;
543 case 'p':
544 pidfile=strdup(optarg);
545 break;
546 case 'f':
547 rcfile=strdup(optarg);
548 break;
549 case 'M':
550 mgmt_socket=strdup(optarg);
551 break;
552 case MGMTMODEARG:
553 sscanf(optarg,"%o",&mgmt_mode);
554 break;
555 default:
556 outc=c;
558 return outc;
561 static void init(void)
563 if (daemonize) {
564 openlog(basename(prog), LOG_PID, 0);
565 logok=1;
566 syslog(LOG_INFO,"VDE_SWITCH started");
568 /* add stdin (if tty), connect and data fds to the set of fds we wait for
569 * * input */
570 if(!daemonize)
572 console_type=add_type(&swmi,0);
573 add_fd(0,console_type,NULL);
576 /* saves current path in pidfile_path, because otherwise with daemonize() we
577 * * forget it */
578 if(getcwd(pidfile_path, PATH_MAX-2) == NULL) {
579 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
580 exit(1);
582 strcat(pidfile_path, "/");
583 if (daemonize && daemon(0, 0)) {
584 printlog(LOG_ERR,"daemon: %s",strerror(errno));
585 exit(1);
588 /* once here, we're sure we're the true process which will continue as a
589 * * server: save PID file if needed */
590 if(pidfile) save_pidfile();
592 if(mgmt_socket != NULL) {
593 int mgmtconnfd;
594 struct sockaddr_un sun;
595 int one = 1;
597 if((mgmtconnfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
598 printlog(LOG_ERR,"mgmt socket: %s",strerror(errno));
599 return;
601 if(setsockopt(mgmtconnfd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
602 sizeof(one)) < 0){
603 printlog(LOG_ERR,"mgmt setsockopt: %s",strerror(errno));
604 return;
606 if(fcntl(mgmtconnfd, F_SETFL, O_NONBLOCK) < 0){
607 printlog(LOG_ERR,"Setting O_NONBLOCK on mgmt fd: %s",strerror(errno));
608 return;
610 sun.sun_family = PF_UNIX;
611 snprintf(sun.sun_path,sizeof(sun.sun_path),"%s",mgmt_socket);
612 if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
613 if((errno == EADDRINUSE) && still_used(&sun)) return;
614 else if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
615 printlog(LOG_ERR,"mgmt bind %s",strerror(errno));
616 return;
619 chmod(sun.sun_path,mgmt_mode);
620 if(listen(mgmtconnfd, 15) < 0){
621 printlog(LOG_ERR,"mgmt listen: %s",strerror(errno));
622 return;
624 mgmt_ctl=add_type(&swmi,0);
625 mgmt_data=add_type(&swmi,0);
626 add_fd(mgmtconnfd,mgmt_ctl,NULL);
630 static int vde_logout()
632 return -1;
635 static int vde_shutdown()
637 printlog(LOG_WARNING,"Shutdown from mgmt command");
638 return -2;
641 static int showinfo(FILE *fd)
643 printoutc(fd,header,PACKAGE_VERSION);
644 printoutc(fd,"pid %d MAC %02x:%02x:%02x:%02x:%02x:%02x uptime %d",getpid(),
645 switchmac[0], switchmac[1], switchmac[2], switchmac[3], switchmac[4], switchmac[5],
646 time(NULL)-starting_time);
647 if (mgmt_socket)
648 printoutc(fd,"mgmt %s perm 0%03o",mgmt_socket,mgmt_mode);
649 return 0;
652 #ifdef DEBUGOPT
653 static int debuglist(FILE *f,int fd,char *path)
655 #define DEBUGFORMAT1 "%-22s %-3s %-6s %s"
656 #define DEBUGFORMAT2 "%-22s %03o %-6s %s"
657 struct dbgcl *p;
658 int i;
659 int rv=ENOENT;
660 printoutc(f,DEBUGFORMAT1,"CATEGORY", "TAG", "STATUS", "HELP");
661 printoutc(f,DEBUGFORMAT1,"------------","---","------", "----");
662 for (p=dbgclh; p!=NULL; p=p->next){
663 if (p->help && strncmp(p->path, path, strlen(path)) == 0) {
664 for (i=0; i<p->nfds && p->fds[i] != fd; i++)
666 rv=0;
667 printoutc(f, DEBUGFORMAT2, p->path, p->tag &0777, i<p->nfds ? "ON" : "OFF", p->help);
670 return rv;
673 /* EINVAL -> no matches
674 * EEXIST -> all the matches already include fd
675 * ENOMEM -> fd buffer realloc failed
676 * 0 otherwise */
677 static int debugadd(int fd,char *path) {
678 struct dbgcl *p;
679 int rv=EINVAL;
680 for (p=dbgclh; p!=NULL; p=p->next) {
681 if (p->help && strncmp(p->path, path, strlen(path)) == 0) {
682 int i;
683 if (rv==EINVAL) rv=EEXIST;
684 for(i=0;i<p->nfds && (p->fds[i] != fd); i++)
686 if (i>=p->nfds) {
687 if (i>=p->maxfds) {
688 int newsize=p->maxfds+DBGCLSTEP;
689 p->fds=realloc(p->fds,newsize*sizeof(int));
690 if (p->fds) {
691 p->maxfds=newsize;
692 p->fds[i]=fd;
693 p->nfds++;
694 if (rv != ENOMEM) rv=0;
695 } else
696 rv=ENOMEM;
697 } else {
698 p->fds[i]=fd;
699 p->nfds++;
700 if (rv != ENOMEM) rv=0;
705 return rv;
708 /* EINVAL -> no matches
709 * ENOENT -> all the matches do not include fd
710 * 0 otherwise */
711 static int debugdel(int fd,char *path) {
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=ENOENT;
718 for(i=0;i<p->nfds && (p->fds[i] != fd); i++)
720 if (i<p->nfds) {
721 p->nfds--; /* the last one */
722 p->fds[i]=p->fds[p->nfds]; /* swap it with the deleted element*/
723 rv=0;
727 return rv;
730 int eventadd(int (*fun)(),char *path,void *arg) {
731 struct dbgcl *p;
732 int rv=EINVAL;
733 for (p=dbgclh; p!=NULL; p=p->next) {
734 if (strncmp(p->path, path, strlen(path)) == 0) {
735 int i;
736 if (rv==EINVAL) rv=EEXIST;
737 for(i=0;i<p->nfun && (p->fun[i] != fun); i++)
739 if (i>=p->nfun) {
740 if (i>=p->maxfun) {
741 int newsize=p->maxfun+DBGCLSTEP;
742 p->fun=realloc(p->fun,newsize*sizeof(int));
743 p->funarg=realloc(p->funarg,newsize*sizeof(void *));
744 if (p->fun && p->funarg) {
745 p->maxfun=newsize;
746 p->fun[i]=fun;
747 p->funarg[i]=arg;
748 p->nfun++;
749 if (rv != ENOMEM) rv=0;
750 } else
751 rv=ENOMEM;
752 } else {
753 p->fun[i]=fun;
754 p->nfun++;
755 if (rv != ENOMEM) rv=0;
760 return rv;
763 /* EINVAL -> no matches
764 * ENOENT -> all the matches do not include fun
765 * 0 otherwise */
766 int eventdel(int (*fun)(),char *path,void *arg) {
767 struct dbgcl *p;
768 int rv=EINVAL;
769 for (p=dbgclh; p!=NULL; p=p->next){
770 if (strncmp(p->path, path, strlen(path)) == 0) {
771 int i;
772 if (rv==EINVAL) rv=ENOENT;
773 for(i=0;i<p->nfun && (p->fun[i] != fun) && (p->funarg[i] != arg); i++)
775 if (i<p->nfun) {
776 p->nfun--; /* the last one */
777 p->fun[i]=p->fun[p->nfun]; /* swap it with the deleted element*/
778 rv=0;
782 return rv;
785 #endif
787 #ifdef VDEPLUGIN
788 static int pluginlist(FILE *f,char *arg)
790 #define PLUGINFMT "%-22s %s"
791 struct plugin *p;
792 int rv=ENOENT;
793 printoutc(f,PLUGINFMT,"NAME", "HELP");
794 printoutc(f,PLUGINFMT,"------------","----");
795 for (p=pluginh; p!=NULL; p=p->next){
796 if (strncmp(p->name, arg, strlen(arg)) == 0) {
797 printoutc(f,PLUGINFMT,p->name,p->help);
798 rv=0;
801 return rv;
804 static int pluginadd(char *arg) {
805 void *handle;
806 struct plugin *p;
807 int rv=ENOENT;
808 if ((handle=dlopen(arg,RTLD_LAZY)) != NULL) {
809 if ((p=(struct plugin *) dlsym(handle,"vde_plugin_data")) != NULL) {
810 if (p->handle != NULL) { /* this dyn library is already loaded*/
811 dlclose(handle);
812 rv=EEXIST;
813 } else {
814 addplugin(p);
815 p->handle=handle;
816 rv=0;
818 } else {
819 rv=EINVAL;
822 return rv;
825 static int plugindel(char *arg) {
826 int rv=ENOENT;
827 struct plugin **p=&pluginh;
828 while (*p!=NULL){
829 if (strncmp((*p)->name, arg, strlen(arg)) == 0
830 && ((*p)->handle != NULL)) {
831 struct plugin *this=*p;
832 delplugin(this);
833 dlclose(this->handle);
834 rv=0;
835 } else
836 p=&(*p)->next;
838 return rv;
840 #endif
842 static struct comlist cl[]={
843 {"help","[arg]","Help (limited to arg when specified)",help,STRARG | WITHFILE},
844 {"logout","","logout from this mgmt terminal",vde_logout,NOARG},
845 {"shutdown","","shutdown of the switch",vde_shutdown,NOARG},
846 {"showinfo","","show switch version and info",showinfo,NOARG|WITHFILE},
847 {"load","path","load a configuration script",runscript,STRARG|WITHFD},
848 #ifdef DEBUGOPT
849 {"debug","============","DEBUG MENU",NULL,NOARG},
850 {"debug/list","","list debug categories",debuglist,STRARG|WITHFILE|WITHFD},
851 {"debug/add","dbgpath","enable debug info for a given category",debugadd,WITHFD|STRARG},
852 {"debug/del","dbgpath","disable debug info for a given category",debugdel,WITHFD|STRARG},
853 #endif
854 #ifdef VDEPLUGIN
855 {"plugin","============","PLUGINS MENU",NULL,NOARG},
856 {"plugin/list","","list plugins",pluginlist,STRARG|WITHFILE},
857 {"plugin/add","library","load a plugin",pluginadd,STRARG},
858 {"plugin/del","name","unload a plugin",plugindel,STRARG},
859 #endif
862 void start_consmgmt(void)
864 swmi.swmname="console-mgmt";
865 swmi.swmnopts=Nlong_options;
866 swmi.swmopts=long_options;
867 swmi.usage=usage;
868 swmi.parseopt=parseopt;
869 swmi.init=init;
870 swmi.handle_io=handle_io;
871 swmi.cleanup=cleanup;
872 ADDCL(cl);
873 #ifdef DEBUGOPT
874 ADDDBGCL(dl);
875 #endif
876 add_swm(&swmi);