2 * Copyright (C) 2007 - Luca Bigliardi
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version 2
6 * of the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include <sys/socket.h>
34 #include <sys/types.h>
39 #include <vdecommon.h>
40 #include <libvdemgmt.h>
42 #define STDRCFILE "/etc/vde2/vde_autolink.rc"
45 #define MGMTMODEARG 129
48 #define FSTPDBG_PADD "fstp/+"
49 #define FSTPDBG_PDEL "fstp/-"
50 #define FSTPDBG_STAT "fstp/status"
55 #define CHANGEWIRETIME 8
56 #define SLEEPWIRETIME 30
58 #define SCHED_LONGTRY 120
59 #define SCHED_CHECK 30
64 char *progname
= NULL
;
67 char *vdeswitch
= NULL
;
68 char *switchmgmt
= NULL
;
72 char pidfile_path
[PATH_MAX
];
73 struct pollfd pfd
[MAXCONS
];
75 struct vdemgmt
* vdemgmt
=NULL
;
78 static int runscript(int fd
,char *path
);
80 static char prompt
[]="\nVDEal$ ";
81 static char header
[]="\nVDE autolink V.%s\n(C) L.Bigliardi 2007 - GPLv2\n";
83 static char *myport
= "$myport";
84 static char *mysock
= "$mysock";
85 static char *myhost
= "$remotehost";
102 char *name
; /* alink name */
103 char **hosts
; /* list of remote hosts */
104 unsigned int portno
; /* number of switch port */
105 int enabled
; /* flag for active */
106 int state
; /* link status */
107 int connhost
; /* current remote host to connect to */
108 struct alwire
*connwire
; /* current type of wire we try to use */
109 int wirepid
; /* pid of wire, -1 if no up */
110 struct alwire
**wires
; /* list of wire types to use */
111 struct autolink
*next
;
114 static struct wire
*av_wires
= NULL
;
115 static struct autolink
*alinks
= NULL
;
118 void (*f
)(struct autolink
*al
);
124 static struct job
*jq
= NULL
;
126 /* Generic utils (from vde framework) */
127 void printlog(int priority
, const char *format
, ...)
131 va_start (arg
, format
);
134 vsyslog(priority
,format
,arg
);
136 fprintf(stderr
,"%s: ",progname
);
137 vfprintf(stderr
,format
,arg
);
138 fprintf(stderr
,"\n");
143 void printoutc(int fd
, const char *format
, ...)
146 char outbuf
[MAXCMD
+1];
148 va_start (arg
, format
);
149 vsnprintf(outbuf
,MAXCMD
,format
,arg
);
151 write(fd
,outbuf
,strlen(outbuf
));
154 void port_dispose(int p
);
156 static void cleanup(void)
160 struct autolink
*curlink
= alinks
;
162 /* kill every link */
164 port_dispose(curlink
->portno
);
165 if ( (tmppid
= curlink
->wirepid
) != -1) {
166 curlink
->wirepid
= -1;
167 kill(tmppid
, SIGQUIT
);
169 curlink
= curlink
->next
;
172 /* close management connections */
176 vdemgmt_asyncunreg(vdemgmt
, FSTPDBG_PADD
);
177 vdemgmt_asyncunreg(vdemgmt
, FSTPDBG_PDEL
);
178 vdemgmt_asyncunreg(vdemgmt
, FSTPDBG_STAT
);
179 vdemgmt_close(vdemgmt
);
183 static void sig_handler(int sig
)
186 /*fprintf(stderr,"Caught signal %d, cleaning up and exiting", sig);*/
188 signal(sig
, SIG_DFL
);
195 struct autolink
*find_alink_pid(int pid
);
197 static void catch_zombies(int signo
)
202 if( (a
=find_alink_pid(wait(&status
))) )
206 static void setsighandlers()
208 /* setting signal handlers.
209 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
210 * ignores all the others signals which could cause termination. */
211 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
212 { SIGHUP
, "SIGHUP", 0 },
213 { SIGINT
, "SIGINT", 0 },
214 { SIGPIPE
, "SIGPIPE", 1 },
215 { SIGALRM
, "SIGALRM", 1 },
216 { SIGTERM
, "SIGTERM", 0 },
217 { SIGUSR1
, "SIGUSR1", 1 },
218 { SIGUSR2
, "SIGUSR2", 1 },
219 { SIGPROF
, "SIGPROF", 1 },
220 { SIGVTALRM
, "SIGVTALRM", 1 },
222 { SIGPOLL
, "SIGPOLL", 1 },
224 { SIGSTKFLT
, "SIGSTKFLT", 1 },
226 { SIGIO
, "SIGIO", 1 },
227 { SIGPWR
, "SIGPWR", 1 },
229 { SIGUNUSED
, "SIGUNUSED", 1 },
233 { SIGXCPU
, "SIGXCPU", 1 },
234 { SIGXFSZ
, "SIGXFSZ", 1 },
240 for(i
= 0; signals
[i
].sig
!= 0; i
++)
241 if(signal(signals
[i
].sig
, signals
[i
].ignore
? SIG_IGN
:
243 printlog(LOG_ERR
,"Setting handler for %s: %s",
244 signals
[i
].name
, strerror(errno
));
246 signal(SIGCHLD
,catch_zombies
);
250 struct wire
*find_wire(char *type
)
252 struct wire
*curwire
= av_wires
;
254 if(!strcmp(curwire
->type
, type
))
256 curwire
= curwire
->next
;
261 struct alwire
*find_alwire(char *type
, struct autolink
*alink
)
263 struct alwire
*curalwire
= alink
->wires
[0];
264 /* each wires[i] has same types */
266 if(!strcmp(curalwire
->type
, type
))
268 curalwire
= curalwire
->next
;
273 struct autolink
*find_alink_port(int port
)
275 struct autolink
*curlink
= alinks
;
277 if( curlink
->portno
== port
)
279 curlink
= curlink
->next
;
284 struct autolink
*find_alink_pid(int pid
)
286 struct autolink
*curlink
= alinks
;
288 if(curlink
->wirepid
== pid
)
290 curlink
= curlink
->next
;
295 struct autolink
*find_alink(char *name
)
297 struct autolink
*curlink
= alinks
;
299 if(!strcmp(curlink
->name
, name
))
301 curlink
= curlink
->next
;
306 struct autolink
*alink_exists(struct autolink
*al
)
308 struct autolink
*c
= alinks
;
317 int port_reserve(void)
320 int p
; char cmd
[strlen("port/create")+5];
322 for(p
=1; p
<= MAXPORTS
; p
++){
323 sprintf(cmd
, "port/create %d", p
);
324 if(!vdemgmt_sendcmd(vdemgmt
, cmd
, NULL
))
330 void port_dispose(int p
)
333 char cmd
[strlen("port/remove")+5];
334 sprintf(cmd
, "port/remove %d", p
);
335 vdemgmt_sendcmd(vdemgmt
, cmd
, NULL
);
339 char *strrplc(char **s
, char *old
, char *new)
341 /* create new string (free old) replacing old with new */
343 char *limit
, *new_s
, *old_s
;
344 int slen
, oldlen
, newlen
, headlen
, diff
, taillen
= 0;
348 slen
=strlen(old_s
); oldlen
=strlen(old
); newlen
=strlen(new);
350 limit
= strstr(old_s
, old
);
354 headlen
= (int)(limit
- old_s
);
355 diff
= newlen
- oldlen
;
356 taillen
= slen
- ( headlen
+ oldlen
);
358 if( (new_s
=(char *)malloc(slen
+diff
+1)) == NULL
)
361 snprintf(new_s
, headlen
+1, "%s", old_s
);
362 snprintf(new_s
+headlen
, newlen
+1, "%s", new);
363 snprintf(new_s
+headlen
+newlen
, taillen
+1, "%s", old_s
+headlen
+oldlen
);
369 void alink_connect(struct autolink
*link
)
372 char *token
, *dupcmd
, **myargv
= NULL
;
373 int count
=0, s
[2], sdata
=1;
376 printlog(LOG_ERR
, "alink_connect null connwire");
380 printlog(LOG_NOTICE
,"[%s] connecting wire: %s to %s", link
->name
,
381 link
->connwire
->type
, link
->hosts
[link
->connhost
]);
383 for( dupcmd
=strdup(link
->connwire
->cmd
) ; ; dupcmd
=NULL
){
384 token
= strtok(dupcmd
, " ");
385 myargv
=realloc(myargv
, (count
+1)*sizeof(char *));
392 if( socketpair(AF_UNIX
, SOCK_STREAM
, 0, s
) ) exit(1);
394 if( (link
->wirepid
= fork()) == 0 ){
395 /* parent goes first, otherwise pid may be lost */
396 read(s
[1],&sdata
,sizeof(int));
397 close(s
[0]); close(s
[1]);
398 execvp(myargv
[0], myargv
);
399 /* TODO: handle return from execvp */
401 write(s
[0],&sdata
,sizeof(int));
402 close(s
[0]); close(s
[1]);
407 void insert_job(void (*f
)(struct autolink
*al
), struct autolink
*al
, int gap
)
409 struct job
*j
=jq
, *pj
=jq
, *nj
; time_t now
;
411 /* remove other jobs for same alink, if any */
414 if (jq
== j
) jq
=j
->n
;
422 /* insert job, ordered by time */
423 if ((nj
=(struct job
*)malloc(sizeof(struct job
))) == NULL
){
424 printlog(LOG_ERR
, "%s, cannot alloc new job", __FUNCTION__
);
428 nj
->f
=f
; nj
->time
=now
+gap
; nj
->al
=al
; nj
->n
=NULL
;
435 if (j
->time
> nj
->time
){
453 struct job
*extract_job()
461 /* Async functions and handlers */
462 void alink_try(struct autolink
*al
);
464 void alink_check(struct autolink
*al
)
466 if (al
->state
!= ST_ACTIVE
){
467 printlog(LOG_NOTICE
, "[%s] check failed, scheduled new wire connection", al
->name
);
468 kill(al
->wirepid
, SIGQUIT
);
469 insert_job(alink_try
, al
, SCHED_TRY
);
472 printlog(LOG_NOTICE
, "[%s] check passed", al
->name
);
475 void alink_try(struct autolink
*al
)
482 /* change wire if died too fast,
483 * try hosts in round robin */
484 if(al
->connwire
->try > (now
- CHANGEWIRETIME
)){
485 if(!al
->connwire
->next
){
487 if( al
->hosts
[al
->connhost
] == NULL
)
489 al
->connwire
= al
->wires
[al
->connhost
];
491 al
->connwire
= al
->connwire
->next
;
493 printlog(LOG_NOTICE
, "[%s] try next wire: %s (%s)", al
->name
,
494 al
->connwire
->type
, al
->hosts
[al
->connhost
]);
495 /* suspend autolink if cycled too fast */
496 if(al
->connwire
->oldtry
> (now
- SLEEPWIRETIME
)){
497 printlog(LOG_NOTICE
, "[%s], go suspend", al
->name
);
498 insert_job(alink_try
, al
, SCHED_LONGTRY
);
503 al
->connwire
->oldtry
= al
->connwire
->try;
504 al
->connwire
->try = now
;
508 insert_job(alink_check
, al
, SCHED_CHECK
);
511 void ah_padd(const char *event
, int tag
, const char *data
)
517 for( s
= (char *)data
; *s
!= ' ' ; s
++);
521 al
= find_alink_port(port
);
522 if (!al
|| !al
->enabled
)
524 printlog(LOG_NOTICE
, "[%s] received %s for port %d", al
->name
, event
, port
);
526 if (al
->state
== ST_DISCARD
){
527 al
->state
= ST_ACTIVE
;
528 printlog(LOG_NOTICE
, "[%s] state change, discard -> active", al
->name
);
532 void ah_pdel(const char *event
, int tag
, const char *data
)
538 for( s
= (char *)data
; *s
!= ' ' ; s
++);
542 al
= find_alink_port(port
);
543 if (!al
|| !al
->enabled
)
545 printlog(LOG_NOTICE
, "[%s] received %s for port %d", al
->name
, event
, port
);
547 if (al
->state
== ST_ACTIVE
){
548 al
->state
= ST_DISCARD
;
549 printlog(LOG_NOTICE
, "[%s] state change, active -> discard", al
->name
);
550 if(al
->wirepid
!= -1)
551 kill(al
->wirepid
, SIGQUIT
);
552 printlog(LOG_NOTICE
, "[%s] scheduled new wire connection");
553 insert_job(alink_try
, al
, SCHED_TRY
);
557 void ah_state(const char *event
, int tag
, const char *data
)
562 for( s
= (char *)data
; *s
!= ' ' ; s
++);
566 al
= find_alink_port(port
);
567 if (!al
|| !al
->enabled
)
569 printlog(LOG_NOTICE
, "[%s] received %s for port %d", al
->name
, event
, port
);
571 if (strstr(data
, "learning+forwarding") && (al
->state
== ST_DISCARD
)){
572 al
->state
= ST_ACTIVE
;
573 printlog(LOG_NOTICE
, "[%s] state change, discard -> active", al
->name
);
576 if (strstr(data
, "discarding") && (al
->state
== ST_ACTIVE
)){
577 al
->state
= ST_DISCARD
;
578 printlog(LOG_NOTICE
, "[%s] state change, active -> discard", al
->name
);
584 int jobsqueue(int fd
, char *arg
)
586 time_t now
; struct job
*j
;
589 printoutc(fd
, "jobs queue is empty");
595 printoutc(fd
, "TIME: %d, ACTION: %s, LINK: %s", j
->time
- now
,
596 (j
->f
== alink_try
) ? "try " : "check", j
->al
->name
);
603 int alinklinkonoff(int fd
, char *arg
)
606 char *endname
, *name
;
607 int namelen
, vallen
, value
;
608 struct autolink
*curlink
;
610 /* check if we have name and type */
611 endname
= strstr(arg
, " ");
612 namelen
= (int)(endname
- arg
);
613 if( namelen
<= 0 ) return EINVAL
;
615 vallen
= (int)(arg
+strlen(arg
) - (endname
+1));
616 if( vallen
<= 0 ) return EINVAL
;
618 if( sscanf(endname
+1, "%i", &value
) != 1)
621 /* pick autolink and wire */
622 if( (name
= (char *)malloc(namelen
+1) ) == NULL
) exit(1);
623 snprintf(name
, namelen
+1, "%s", arg
);
625 curlink
= find_alink(name
);
627 if(!curlink
) return ENXIO
;
630 if(!curlink
->wires
) return ENXIO
;
631 if(curlink
->enabled
) return 0;
632 curlink
->enabled
= 1;
633 curlink
->state
= ST_DISCARD
;
634 curlink
->connwire
=curlink
->wires
[0];
638 if(!curlink
->enabled
) return 0;
639 curlink
->enabled
= 0;
640 kill(curlink
->wirepid
, SIGQUIT
);
641 curlink
->connwire
= NULL
;
646 int alinkdeltypelink(int fd
, char *arg
)
649 char *endname
, *name
, *type
;
650 int namelen
, typelen
, i
;
651 struct autolink
*curlink
;
652 struct alwire
*curalwire
, *prevalwire
;
654 /* check if we have name and type */
655 endname
= strstr(arg
, " ");
656 namelen
= (int)(endname
- arg
);
657 if( namelen
<= 0 ) return EINVAL
;
659 typelen
= strlen(arg
) - namelen
-1;
660 if( typelen
<= 0 ) return EINVAL
;
663 if( (name
= (char *)malloc(namelen
+1) ) == NULL
) exit(1);
664 snprintf(name
, namelen
+1, "%s", arg
);
666 curlink
= find_alink(name
);
668 if(!curlink
) return ENXIO
;
669 if(curlink
->enabled
) return EINVAL
; /* avoid RC */
671 if(!curlink
->wires
[0]) return EINVAL
; /* no wires! */
674 if( (type
= (char *)malloc(typelen
+1) ) == NULL
) exit(1);
675 snprintf(type
, typelen
+1, "%s", endname
+1);
677 for( i
= 0 ; curlink
->hosts
[i
] != NULL
; i
++){
678 curalwire
= prevalwire
= curlink
->wires
[i
];
681 if(!strcmp(curalwire
->type
, type
)){
682 if(curalwire
== curlink
->wires
[i
]){
683 curlink
->wires
[i
] = curalwire
->next
;
686 prevalwire
->next
= curalwire
->next
;
688 free(curalwire
->type
);
689 free(curalwire
->cmd
);
694 prevalwire
= curalwire
;
695 curalwire
= curalwire
->next
;
703 int alinkaddtypelink(int fd
, char *arg
)
706 char *endname
, *name
, *type
, portbuf
[42];
707 int namelen
, typelen
, i
;
708 struct autolink
*curlink
;
710 struct alwire
*alwire
;
712 /* check if we have name and type */
713 endname
= strstr(arg
, " ");
714 namelen
= (int)(endname
- arg
);
715 if( namelen
<= 0 ) return EINVAL
;
717 typelen
= strlen(arg
) - namelen
-1;
718 if( typelen
<= 0 ) return EINVAL
;
720 /* pick autolink and wire */
721 if( (name
= (char *)malloc(namelen
+1) ) == NULL
) exit(1);
722 snprintf(name
, namelen
+1, "%s", arg
);
724 curlink
= find_alink(name
);
726 if(!curlink
) return ENXIO
;
727 if(curlink
->enabled
) return EINVAL
; /* avoid RC */
729 if( (type
= (char *)malloc(typelen
+1) ) == NULL
) exit(1);
730 snprintf(type
, typelen
+1, "%s", endname
+1);
732 wire
= find_wire(type
);
734 if(!wire
) return ENXIO
;
736 /* only one wire type for each autolink */
737 alwire
= find_alwire(wire
->type
, curlink
);
738 if(alwire
) return EINVAL
;
741 for( i
= 0 ; curlink
->hosts
[i
] != NULL
; i
++ ){
742 if(!curlink
->wires
[i
]){
743 if( (curlink
->wires
[i
] = (struct alwire
*)
744 malloc(sizeof(struct alwire
))) == NULL
)
746 alwire
= curlink
->wires
[i
];
749 alwire
= curlink
->wires
[i
];
751 alwire
= alwire
->next
;
752 if( (alwire
->next
=(struct alwire
*)
753 malloc(sizeof(struct alwire
))) == NULL
)
755 alwire
= alwire
->next
;
758 /* set port, sock and remotehost in alwire command */
759 if( (alwire
->cmd
= (char *)malloc(strlen(wire
->cmd
)+1)) == NULL
)
762 strcpy(alwire
->cmd
, wire
->cmd
);
763 sprintf(portbuf
, "%u", curlink
->portno
);
764 strrplc(&(alwire
->cmd
), myport
, portbuf
);
765 strrplc(&(alwire
->cmd
), mysock
, vdeswitch
);
766 strrplc(&(alwire
->cmd
), myhost
, curlink
->hosts
[i
]);
768 /* fill rest of alwire struct */
769 if( (alwire
->type
= (char *)
770 malloc(strlen(wire
->type
)+1)) == NULL
)
773 strcpy(alwire
->type
, wire
->type
);
782 int alinkdellink(int fd
, char *arg
)
785 struct autolink
*curlink
, *prevlink
;
786 struct alwire
*curalwire
, *prevalwire
;
789 if(!alinks
) return EINVAL
;
791 prevlink
= curlink
= alinks
;
793 if(!strcmp(curlink
->name
, arg
)){
794 if(curlink
->enabled
) return EINVAL
; /* avoid RC */
795 if(curlink
== alinks
){
796 alinks
= curlink
->next
;
799 prevlink
->next
= curlink
->next
;
801 port_dispose(curlink
->portno
);
803 /* remove hosts and alwires */
804 for ( i
= 0 ; curlink
->hosts
[i
] != NULL
; i
++){
805 free(curlink
->hosts
[i
]);
806 curalwire
= curlink
->wires
[i
];
808 prevalwire
= curalwire
;
809 curalwire
= curalwire
->next
;
813 free(curlink
->hosts
);
814 free(curlink
->wires
);
819 curlink
= curlink
->next
;
824 int alinkaddlink(int fd
, char *arg
)
827 char *name
, *endname
= NULL
, *tmphosts
, *token
;
828 int namelen
, hostlen
, i
, j
;
829 struct autolink
*curlink
;
831 /* check if we have name and remotehost */
832 endname
= strstr(arg
, " ");
833 namelen
= (int)(endname
- arg
);
834 if( namelen
<= 0 ) return EINVAL
;
836 hostlen
= strlen(arg
) - namelen
-1;
837 if( hostlen
<= 0 ) return EINVAL
;
839 /* alloc and set name */
840 if( (name
= (char *)malloc(namelen
+1) ) == NULL
) exit(1);
841 snprintf(name
, namelen
+1, "%s", arg
);
843 /* check for duplicate */
844 if( find_alink(name
) ){
845 free(name
); return EINVAL
;
850 alinks
= (struct autolink
*)malloc(sizeof(struct autolink
));
851 if(alinks
== NULL
) exit(1);
856 curlink
= curlink
->next
;
857 curlink
->next
= (struct autolink
*)
858 malloc(sizeof(struct autolink
));
859 if(curlink
->next
== NULL
) exit(1);
860 curlink
= curlink
->next
;
862 curlink
->name
= name
;
864 /* reserve a port on switch */
865 if( (curlink
->portno
= port_reserve()) < 0 ){
868 if(alinks
== curlink
) alinks
= NULL
;
872 /* alloc and set remote host array (null terminated) */
875 for( tmphosts
=strdup(endname
+1) ; ; tmphosts
=NULL
){
876 token
= strtok(tmphosts
, " ");
877 curlink
->hosts
=realloc(curlink
->hosts
, (i
+1)*sizeof(char *));
878 if(!curlink
->hosts
) exit(1);
879 curlink
->hosts
[i
]=token
;
883 /* alloc wires array */
884 if( (curlink
->wires
= malloc(i
*sizeof(char *))) == NULL
) exit(1);
885 for( j
= 0 ; j
< i
; j
++)
886 curlink
->wires
[j
] = NULL
;
888 curlink
->enabled
= 0;
890 curlink
->connhost
= 0;
891 curlink
->connwire
= NULL
;
892 curlink
->next
= NULL
;
897 int alinkrunninglinks(int fd
, char *arg
)
899 struct autolink
*curlink
;
902 if(!alinks
) return 0;
906 if( curlink
->enabled
&& (curlink
->wirepid
!= -1) &&
907 ( curlink
->state
== ST_ACTIVE
) &&
908 (curlink
->connwire
->try <
909 now
- CHANGEWIRETIME
) ) {
910 /* show only stable connections */
911 printoutc(fd
, "NAME = %s , RHOST = %s , WIRE = %s ,"
912 " PID: %d", curlink
->name
,
913 curlink
->hosts
[curlink
->connhost
],
914 curlink
->connwire
->type
,
918 curlink
= curlink
->next
;
923 int alinkshowlinks(int fd
, char *arg
)
925 struct autolink
*curlink
;
926 struct alwire
*curalwire
= NULL
;
930 printoutc(fd
, "no autolink defined");
935 printoutc(fd
, "NAME = %s (PORT: %d%s)", curlink
->name
,
937 (curlink
->enabled
?" - ACTIVE":""));
938 for(i
= 0 ; curlink
->hosts
[i
] != NULL
; i
++){
939 printoutc(fd
, "RHOST: %s", curlink
->hosts
[i
]);
940 if(curlink
->wires
[i
]){
941 printoutc(fd
, "WIRES:");
942 curalwire
= curlink
->wires
[i
];
945 printoutc(fd
,"%s: %s\n", curalwire
->type
,
947 curalwire
= curalwire
->next
;
951 curlink
= curlink
->next
;
956 int alinkdelwire(int fd
, char* arg
)
958 struct wire
*curwire
, *prevwire
;
960 if(!av_wires
) return EINVAL
;
962 prevwire
= curwire
= av_wires
;
964 if(!strcmp(curwire
->type
, arg
)){
965 if(curwire
== av_wires
){
966 av_wires
= curwire
->next
;
969 prevwire
->next
= curwire
->next
;
977 curwire
= curwire
->next
;
982 int alinkaddwire(int fd
, char* arg
)
985 struct wire
*curwire
= NULL
;
990 /* check if we have type and command */
991 char *endtype
= strstr(arg
, " ");
992 typelen
= (int)(endtype
- arg
);
993 if( typelen
<= 0 ) return EINVAL
;
994 cmdlen
= strlen(arg
) - typelen
-1;
995 if( cmdlen
<= 0 ) return EINVAL
;
997 /* alloc and set type */
998 if( (type
= (char *)malloc(typelen
+1) ) == NULL
) exit(1);
999 snprintf(type
, typelen
+1, "%s", arg
);
1001 /* check for duplicate */
1002 if( find_wire(type
) ){
1003 free(type
); return EINVAL
;
1006 if(av_wires
== NULL
){
1007 av_wires
= (struct wire
*)malloc(sizeof(struct wire
));
1008 if(av_wires
== NULL
) exit(1);
1012 while(curwire
->next
)
1013 curwire
= curwire
->next
;
1014 curwire
->next
= (struct wire
*)malloc(sizeof(struct wire
));
1015 if(curwire
->next
== NULL
) exit(1);
1016 curwire
= curwire
->next
;
1019 curwire
->next
= NULL
;
1020 curwire
->type
= type
;
1022 /* alloc and set command */
1023 if( (curwire
->cmd
= (char *)malloc(cmdlen
+1) ) == NULL
)
1025 snprintf(curwire
->cmd
, cmdlen
+1, "%s", endtype
+1);
1027 /* check variables */
1028 if( !strstr(curwire
->cmd
, myport
) || !strstr(curwire
->cmd
, mysock
) ||
1029 !strstr(curwire
->cmd
, myhost
) ){
1030 free(curwire
->type
); free(curwire
->cmd
);
1032 if(av_wires
== curwire
) av_wires
= NULL
;
1039 int alinkshowwires(int fd
, char *arg
)
1041 struct wire
*curwire
;
1043 printoutc(fd
, "no wire defined");
1048 printoutc(fd
, "TYPE = %s\nCMD = %s\n", curwire
->type
,
1050 curwire
= curwire
->next
;
1055 int alinkshutdown(int fd
, char *arg
)
1057 printlog(LOG_WARNING
,"Shutdown from mgmt command");
1061 int alinkhelp(int fd
, char *arg
)
1064 printoutc(fd
, "help: print a summary of mgmt commands");
1065 printoutc(fd
, "shutdown: terminate");
1066 printoutc(fd
, "runscript: load a config file [args: PATH]");
1067 printoutc(fd
, "showwires: list inserted wires");
1068 printoutc(fd
, "addwire: add a type of wire, with variables [args: TYPE CMD]");
1069 printoutc(fd
, "delwire: delete a type of wire [args: TYPE]");
1070 printoutc(fd
, "showlinks: list inserted autolinks");
1071 printoutc(fd
, "runninglinks: print running links");
1072 printoutc(fd
, "addlink: add an autolink [args: NAME REMOTEHOSTS]");
1073 printoutc(fd
, "dellink: delete an autolink [args: NAME]");
1074 printoutc(fd
, "addtypelink: add a type of wire to named link [args: NAME TYPE]");
1075 printoutc(fd
, "deltypelink: delete a type of wire from named link [args: NAME TYPE]");
1076 printoutc(fd
, "linkonoff: activate/deactivate autolink [args: NAME 1/0]");
1077 printoutc(fd
, "jobsqueue: print status of job queue");
1084 int (*fun
)(int fd
,char *arg
);
1087 {"shutdown", alinkshutdown
},
1088 {"showwires", alinkshowwires
},
1089 {"addwire", alinkaddwire
},
1090 {"delwire", alinkdelwire
},
1092 {"showlinks", alinkshowlinks
},
1093 {"runninglinks", alinkrunninglinks
},
1094 {"addlink", alinkaddlink
},
1095 {"dellink", alinkdellink
},
1097 {"addtypelink", alinkaddtypelink
},
1098 {"deltypelink", alinkdeltypelink
},
1099 {"linkonoff", alinklinkonoff
},
1100 {"runscript", runscript
},
1102 {"jobsqueue", jobsqueue
},
1105 #define NCL sizeof(cl)/sizeof(struct comlist)
1107 static int handle_cmd(int fd
,char *inbuf
)
1111 while (*inbuf
== ' ' || *inbuf
== '\t') inbuf
++;
1112 if (*inbuf
!= '\0' && *inbuf
!= '#') {
1114 strncmp(cl
[i
].tag
,inbuf
,strlen(cl
[i
].tag
))!=0; i
++)
1117 inbuf
+= strlen(cl
[i
].tag
);
1118 while (*inbuf
== ' ' || *inbuf
== '\t') inbuf
++;
1119 printoutc(fd
,"0000 DATA END WITH '.'");
1120 rv
=cl
[i
].fun(fd
,inbuf
);
1124 printoutc(fd
,"1000 Success");
1126 printoutc(fd
,"1%03d %s",rv
,strerror(rv
));
1133 static int mgmtcommand(int fd
)
1137 n
= read(fd
, buf
, MAXCMD
);
1139 printlog(LOG_ERR
,"read from mgmt %s", strerror(errno
));
1146 if (n
>0 && buf
[n
-1] == '\n')
1148 rv
=handle_cmd(fd
,buf
);
1150 write(fd
,prompt
,strlen(prompt
));
1155 static int newmgmtconn(int fd
,struct pollfd
*pfd
,int nfds
)
1160 struct sockaddr addr
;
1161 new = accept(fd
, &addr
, &len
);
1163 printlog(LOG_ERR
,"mgmt accept %s",strerror(errno
));
1166 if (nfds
< MAXCONS
) {
1168 if(fcntl(new, F_SETFL
, O_NONBLOCK
) < 0){
1169 printlog(LOG_WARNING
, "mgmt fcntl - setting "
1170 "O_NONBLOCK %s",strerror(errno
));
1176 pfd
[nfds
].events
=POLLIN
| POLLHUP
;
1177 pfd
[nfds
].revents
=0;
1179 snprintf(buf
,MAXCMD
,header
,PACKAGE_VERSION
);
1180 write(new,buf
,strlen(buf
));
1181 write(new,prompt
,strlen(prompt
));
1184 printlog(LOG_ERR
,"too many mgmt connections");
1190 static int delmgmtconn(int i
,struct pollfd
*pfd
,int nfds
)
1194 memmove(pfd
+i
,pfd
+i
+1,sizeof (struct pollfd
) * (nfds
-i
-1));
1200 static int openmgmt(char *mgmt
)
1203 struct sockaddr_un sun
;
1206 if((mgmtconnfd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0){
1207 fprintf(stderr
,"%s: mgmt socket: %s",progname
,strerror(errno
));
1210 if(setsockopt(mgmtconnfd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &one
,
1212 fprintf(stderr
,"%s: mgmt setsockopt: %s",progname
,
1216 if(fcntl(mgmtconnfd
, F_SETFL
, O_NONBLOCK
) < 0){
1217 fprintf(stderr
,"%s: Setting O_NONBLOCK on mgmt fd: %s",
1218 progname
,strerror(errno
));
1221 sun
.sun_family
= PF_UNIX
;
1222 snprintf(sun
.sun_path
,sizeof(sun
.sun_path
),"%s",mgmt
);
1223 if(bind(mgmtconnfd
, (struct sockaddr
*) &sun
, sizeof(sun
)) < 0){
1224 fprintf(stderr
,"%s: mgmt bind %s",progname
,strerror(errno
));
1227 chmod(sun
.sun_path
,mgmtmode
);
1228 if(listen(mgmtconnfd
, 15) < 0){
1229 fprintf(stderr
,"%s: mgmt listen: %s",progname
,strerror(errno
));
1235 static int runscript(int fd
,char *path
)
1237 FILE *f
=fopen(path
,"r");
1242 while (fgets(buf
,MAXCMD
,f
) != NULL
) {
1243 if (strlen(buf
) > 1 && buf
[strlen(buf
)-1]=='\n')
1244 buf
[strlen(buf
)-1]= '\0';
1245 if (fd
>= 0) printoutc(fd
,"vde_autolink[%s]: %s",
1247 handle_cmd(fd
, buf
);
1253 static void loadrcfile(void)
1256 runscript(-1,rcfile
);
1258 char path
[PATH_MAX
];
1259 snprintf(path
,PATH_MAX
,"%s/.vde2/vde_autolink.rc",getenv("HOME"));
1260 if (access(path
,R_OK
) == 0)
1263 if (access(STDRCFILE
,R_OK
) == 0)
1264 runscript(-1,STDRCFILE
);
1269 static void save_pidfile()
1271 if(pidfile
[0] != '/')
1272 strncat(pidfile_path
, pidfile
, PATH_MAX
- strlen(pidfile_path
));
1274 strcpy(pidfile_path
, pidfile
);
1276 int fd
= open(pidfile_path
,
1277 O_WRONLY
| O_CREAT
| O_EXCL
,
1278 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
1282 printlog(LOG_ERR
, "Error in pidfile creation: %s",
1287 if((f
= fdopen(fd
, "w")) == NULL
) {
1288 printlog(LOG_ERR
, "Error in FILE* construction: %s",
1293 if(fprintf(f
, "%ld\n", (long int)getpid()) <= 0) {
1294 printlog(LOG_ERR
, "Error in writing pidfile");
1301 static void usage(void)
1304 " -h, --help Display this help\n"
1305 " -f, --rcfile Configuration file (overrides %s and ~/.vde_autolinkrc)\n"
1306 " -d, --daemon Daemonize vde_autolink once run\n"
1307 " -p, --pidfile PIDFILE Write pid of daemon to PIDFILE\n"
1308 " -M, --mgmt SOCK Path of the management UNIX socket\n"
1309 " --mgmtmode MODE Management UNIX socket access mode (octal)\n"
1310 " -s, --sock [*] Attach to this vde_switch socket\n"
1311 " -S, --switchmgmt [*] Attach to this vde_switch management socket\n"
1312 " [*] == Required option!\n"
1316 int main(int argc
,char **argv
)
1319 int npfd
=0, option_index
;
1320 int mgmtfd
, mgmtindex
=-1, vdemgindex
=-1, consoleindex
=-1;
1321 struct job
*j
; time_t now
;
1323 static struct option long_options
[] = {
1324 {"help", 0, 0, 'h'},
1325 {"rcfile", 1, 0, 'f'},
1326 {"daemon", 0, 0, 'd'},
1327 {"pidfile", 1, 0, 'p'},
1328 {"mgmt", 1, 0, 'M'},
1329 {"mgmtmode", 1, 0, MGMTMODEARG
},
1330 {"sock", 1, 0, 's'},
1331 {"switchmgmt", 1, 0, 'S'},
1333 progname
=basename(argv
[0]);
1340 c
= GETOPT_LONG (argc
, argv
, "hf:dp:M:s:S:",
1341 long_options
, &option_index
);
1349 rcfile
=strdup(optarg
);
1355 pidfile
=strdup(optarg
);
1358 mgmt
=strdup(optarg
);
1361 sscanf(optarg
,"%o",&mgmtmode
);
1364 vdeswitch
=strdup(optarg
);
1367 switchmgmt
=strdup(optarg
);
1378 if( !vdeswitch
|| !switchmgmt
)
1382 openlog(basename(progname
), LOG_PID
, 0);
1384 syslog(LOG_INFO
,"VDE_AUTOLINK started");
1387 if(isatty(0) && !daemonize
){
1389 pfd
[consoleindex
].fd
=0;
1390 pfd
[consoleindex
].events
=POLLIN
| POLLHUP
;
1391 pfd
[consoleindex
].revents
=0;
1395 if(getcwd(pidfile_path
, PATH_MAX
-1) == NULL
) {
1396 printlog(LOG_ERR
, "getcwd: %s", strerror(errno
));
1399 strcat(pidfile_path
, "/");
1400 if (daemonize
&& daemon(0, 1)) {
1401 printlog(LOG_ERR
,"daemon: %s",strerror(errno
));
1404 if(pidfile
) save_pidfile();
1406 if( (vdemgmt
=vdemgmt_open(switchmgmt
)) == NULL
){
1407 printlog(LOG_ERR
, "cannot open %s\n", switchmgmt
);
1411 pfd
[vdemgindex
].fd
=vdemgmt_getfd(vdemgmt
);
1412 pfd
[vdemgindex
].events
=POLLIN
| POLLHUP
;
1413 pfd
[vdemgindex
].revents
=0;
1416 if( vdemgmt_asyncreg(vdemgmt
, FSTPDBG_PADD
, ah_padd
)
1417 || vdemgmt_asyncreg(vdemgmt
, FSTPDBG_PDEL
, ah_pdel
)
1418 || vdemgmt_asyncreg(vdemgmt
, FSTPDBG_STAT
, ah_state
) ){
1419 printlog(LOG_ERR
, "cannot register async handler on switch");
1424 mgmtfd
=openmgmt(mgmt
);
1426 pfd
[mgmtindex
].fd
=mgmtfd
;
1427 pfd
[mgmtindex
].events
=POLLIN
| POLLHUP
;
1428 pfd
[mgmtindex
].revents
=0;
1436 poll(pfd
,npfd
,polltimeout
);
1438 /* Handle async output from switch */
1439 if(pfd
[vdemgindex
].revents
& POLLHUP
){
1440 printlog(LOG_ERR
, "switch closed connection, exiting");
1443 if( pfd
[vdemgindex
].revents
& POLLIN
)
1444 vdemgmt_asyncrecv(vdemgmt
);
1446 /* Handle console connections and commands */
1447 if(consoleindex
>= 0 &&
1448 ( pfd
[consoleindex
].revents
& POLLHUP
||
1449 (pfd
[consoleindex
].revents
& POLLIN
&&
1450 mgmtcommand(pfd
[consoleindex
].fd
)<0) ) )
1453 if (mgmt
&& (pfd
[mgmtindex
].revents
!= 0))
1454 npfd
=newmgmtconn(pfd
[mgmtindex
].fd
,pfd
,npfd
);
1456 if (mgmt
&& (npfd
> mgmtindex
+1)) {
1458 for (i
=mgmtindex
+1;i
<npfd
;i
++) {
1459 if( (pfd
[i
].revents
& POLLHUP
) ||
1460 ((pfd
[i
].revents
& POLLIN
) &&
1461 (mgmtcommand(pfd
[i
].fd
) < 0)) )
1462 npfd
=delmgmtconn(i
,pfd
,npfd
);
1466 /* Run scheduled jobs and compute new timeout for poll */
1468 while ( jq
&& (now
> jq
->time
) ){
1470 if (alink_exists(j
->al
) && j
->al
->enabled
)
1474 polltimeout
= jq
? jq
->time
- now
: -1 ;