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
);
192 struct autolink
*find_alink_pid(int pid
);
194 static void catch_zombies(int signo
)
199 if( (a
=find_alink_pid(wait(&status
))) )
203 static void setsighandlers()
205 /* setting signal handlers.
206 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
207 * ignores all the others signals which could cause termination. */
208 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
209 { SIGHUP
, "SIGHUP", 0 },
210 { SIGINT
, "SIGINT", 0 },
211 { SIGPIPE
, "SIGPIPE", 1 },
212 { SIGALRM
, "SIGALRM", 1 },
213 { SIGTERM
, "SIGTERM", 0 },
214 { SIGUSR1
, "SIGUSR1", 1 },
215 { SIGUSR2
, "SIGUSR2", 1 },
216 { SIGPROF
, "SIGPROF", 1 },
217 { SIGVTALRM
, "SIGVTALRM", 1 },
219 { SIGPOLL
, "SIGPOLL", 1 },
221 { SIGSTKFLT
, "SIGSTKFLT", 1 },
223 { SIGIO
, "SIGIO", 1 },
224 { SIGPWR
, "SIGPWR", 1 },
226 { SIGUNUSED
, "SIGUNUSED", 1 },
230 { SIGXCPU
, "SIGXCPU", 1 },
231 { SIGXFSZ
, "SIGXFSZ", 1 },
237 for(i
= 0; signals
[i
].sig
!= 0; i
++)
238 if(signal(signals
[i
].sig
, signals
[i
].ignore
? SIG_IGN
:
240 printlog(LOG_ERR
,"Setting handler for %s: %s",
241 signals
[i
].name
, strerror(errno
));
243 signal(SIGCHLD
,catch_zombies
);
247 struct wire
*find_wire(char *type
)
249 struct wire
*curwire
= av_wires
;
251 if(!strcmp(curwire
->type
, type
))
253 curwire
= curwire
->next
;
258 struct alwire
*find_alwire(char *type
, struct autolink
*alink
)
260 struct alwire
*curalwire
= alink
->wires
[0];
261 /* each wires[i] has same types */
263 if(!strcmp(curalwire
->type
, type
))
265 curalwire
= curalwire
->next
;
270 struct autolink
*find_alink_port(int port
)
272 struct autolink
*curlink
= alinks
;
274 if( curlink
->portno
== port
)
276 curlink
= curlink
->next
;
281 struct autolink
*find_alink_pid(int pid
)
283 struct autolink
*curlink
= alinks
;
285 if(curlink
->wirepid
== pid
)
287 curlink
= curlink
->next
;
292 struct autolink
*find_alink(char *name
)
294 struct autolink
*curlink
= alinks
;
296 if(!strcmp(curlink
->name
, name
))
298 curlink
= curlink
->next
;
303 struct autolink
*alink_exists(struct autolink
*al
)
305 struct autolink
*c
= alinks
;
314 int port_reserve(void)
317 int p
; char cmd
[strlen("port/create")+5];
319 for(p
=1; p
<= MAXPORTS
; p
++){
320 sprintf(cmd
, "port/create %d", p
);
321 if(!vdemgmt_sendcmd(vdemgmt
, cmd
, NULL
))
327 void port_dispose(int p
)
330 char cmd
[strlen("port/remove")+5];
331 sprintf(cmd
, "port/remove %d", p
);
332 vdemgmt_sendcmd(vdemgmt
, cmd
, NULL
);
336 char *strrplc(char **s
, char *old
, char *new)
338 /* create new string (free old) replacing old with new */
340 char *limit
, *new_s
, *old_s
;
341 int slen
, oldlen
, newlen
, headlen
, diff
, taillen
= 0;
345 slen
=strlen(old_s
); oldlen
=strlen(old
); newlen
=strlen(new);
347 limit
= strstr(old_s
, old
);
351 headlen
= (int)limit
- (int)old_s
;
352 diff
= newlen
- oldlen
;
353 taillen
= slen
- ( headlen
+ oldlen
);
355 if( (new_s
=(char *)malloc(slen
+diff
+1)) == NULL
)
358 snprintf(new_s
, headlen
+1, "%s", old_s
);
359 snprintf(new_s
+headlen
, newlen
+1, "%s", new);
360 snprintf(new_s
+headlen
+newlen
, taillen
+1, "%s", old_s
+headlen
+oldlen
);
366 void alink_connect(struct autolink
*link
)
369 char *token
, *dupcmd
, **myargv
= NULL
;
370 int count
=0, s
[2], sdata
=1;
373 printlog(LOG_ERR
, "alink_connect null connwire");
377 printlog(LOG_NOTICE
,"[%s] connecting wire: %s to %s", link
->name
,
378 link
->connwire
->type
, link
->hosts
[link
->connhost
]);
380 for( dupcmd
=strdup(link
->connwire
->cmd
) ; ; dupcmd
=NULL
){
381 token
= strtok(dupcmd
, " ");
382 myargv
=realloc(myargv
, (count
+1)*sizeof(char *));
389 if( socketpair(AF_UNIX
, SOCK_STREAM
, 0, s
) ) exit(1);
391 if( (link
->wirepid
= fork()) == 0 ){
392 /* parent goes first, otherwise pid may be lost */
393 read(s
[1],&sdata
,sizeof(int));
394 close(s
[0]); close(s
[1]);
395 execvp(myargv
[0], myargv
);
396 /* TODO: handle return from execvp */
398 write(s
[0],&sdata
,sizeof(int));
399 close(s
[0]); close(s
[1]);
404 void insert_job(void (*f
)(struct autolink
*al
), struct autolink
*al
, int gap
)
406 struct job
*j
=jq
, *pj
=jq
, *nj
; time_t now
;
408 /* remove other jobs for same alink, if any */
411 if (jq
== j
) jq
=j
->n
;
419 /* insert job, ordered by time */
420 if ((nj
=(struct job
*)malloc(sizeof(struct job
))) == NULL
){
421 printlog(LOG_ERR
, "%s, cannot alloc new job", __FUNCTION__
);
425 nj
->f
=f
; nj
->time
=now
+gap
; nj
->al
=al
; nj
->n
=NULL
;
432 if (j
->time
> nj
->time
){
450 struct job
*extract_job()
458 /* Async functions and handlers */
459 void alink_try(struct autolink
*al
);
461 void alink_check(struct autolink
*al
)
463 if (al
->state
!= ST_ACTIVE
){
464 printlog(LOG_NOTICE
, "[%s] check failed, scheduled new wire connection", al
->name
);
465 kill(al
->wirepid
, SIGQUIT
);
466 insert_job(alink_try
, al
, SCHED_TRY
);
469 printlog(LOG_NOTICE
, "[%s] check passed", al
->name
);
472 void alink_try(struct autolink
*al
)
479 /* change wire if died too fast,
480 * try hosts in round robin */
481 if(al
->connwire
->try > (now
- CHANGEWIRETIME
)){
482 if(!al
->connwire
->next
){
484 if( al
->hosts
[al
->connhost
] == NULL
)
486 al
->connwire
= al
->wires
[al
->connhost
];
488 al
->connwire
= al
->connwire
->next
;
490 printlog(LOG_NOTICE
, "[%s] try next wire: %s (%s)", al
->name
,
491 al
->connwire
->type
, al
->hosts
[al
->connhost
]);
492 /* suspend autolink if cycled too fast */
493 if(al
->connwire
->oldtry
> (now
- SLEEPWIRETIME
)){
494 printlog(LOG_NOTICE
, "[%s], go suspend", al
->name
);
495 insert_job(alink_try
, al
, SCHED_LONGTRY
);
500 al
->connwire
->oldtry
= al
->connwire
->try;
501 al
->connwire
->try = now
;
505 insert_job(alink_check
, al
, SCHED_CHECK
);
508 void ah_padd(const char *event
, int tag
, const char *data
)
514 for( s
= (char *)data
; *s
!= ' ' ; s
++);
518 al
= find_alink_port(port
);
519 if (!al
|| !al
->enabled
)
521 printlog(LOG_NOTICE
, "[%s] received %s for port %d", al
->name
, event
, port
);
523 if (al
->state
== ST_DISCARD
){
524 al
->state
= ST_ACTIVE
;
525 printlog(LOG_NOTICE
, "[%s] state change, discard -> active", al
->name
);
529 void ah_pdel(const char *event
, int tag
, const char *data
)
535 for( s
= (char *)data
; *s
!= ' ' ; s
++);
539 al
= find_alink_port(port
);
540 if (!al
|| !al
->enabled
)
542 printlog(LOG_NOTICE
, "[%s] received %s for port %d", al
->name
, event
, port
);
544 if (al
->state
== ST_ACTIVE
){
545 al
->state
= ST_DISCARD
;
546 printlog(LOG_NOTICE
, "[%s] state change, active -> discard", al
->name
);
547 if(al
->wirepid
!= -1)
548 kill(al
->wirepid
, SIGQUIT
);
549 printlog(LOG_NOTICE
, "[%s] scheduled new wire connection");
550 insert_job(alink_try
, al
, SCHED_TRY
);
554 void ah_state(const char *event
, int tag
, const char *data
)
559 for( s
= (char *)data
; *s
!= ' ' ; s
++);
563 al
= find_alink_port(port
);
564 if (!al
|| !al
->enabled
)
566 printlog(LOG_NOTICE
, "[%s] received %s for port %d", al
->name
, event
, port
);
568 if (strstr(data
, "learning+forwarding") && (al
->state
== ST_DISCARD
)){
569 al
->state
= ST_ACTIVE
;
570 printlog(LOG_NOTICE
, "[%s] state change, discard -> active", al
->name
);
573 if (strstr(data
, "discarding") && (al
->state
== ST_ACTIVE
)){
574 al
->state
= ST_DISCARD
;
575 printlog(LOG_NOTICE
, "[%s] state change, active -> discard", al
->name
);
581 int jobsqueue(int fd
, char *arg
)
583 time_t now
; struct job
*j
;
586 printoutc(fd
, "jobs queue is empty");
592 printoutc(fd
, "TIME: %d, ACTION: %s, LINK: %s", j
->time
- now
,
593 (j
->f
== alink_try
) ? "try " : "check", j
->al
->name
);
600 int alinklinkonoff(int fd
, char *arg
)
603 char *endname
, *name
;
604 int namelen
, vallen
, value
;
605 struct autolink
*curlink
;
607 /* check if we have name and type */
608 endname
= strstr(arg
, " ");
609 namelen
= (int)endname
- (int)arg
;
610 if( namelen
<= 0 ) return EINVAL
;
612 vallen
= ((int)arg
+strlen(arg
)) - ((int)endname
+1);
613 if( vallen
<= 0 ) return EINVAL
;
615 if( sscanf(endname
+1, "%i", &value
) != 1)
618 /* pick autolink and wire */
619 if( (name
= (char *)malloc(namelen
+1) ) == NULL
) exit(1);
620 snprintf(name
, namelen
+1, "%s", arg
);
622 curlink
= find_alink(name
);
624 if(!curlink
) return ENXIO
;
627 if(!curlink
->wires
) return ENXIO
;
628 if(curlink
->enabled
) return 0;
629 curlink
->enabled
= 1;
630 curlink
->state
= ST_DISCARD
;
631 curlink
->connwire
=curlink
->wires
[0];
635 if(!curlink
->enabled
) return 0;
636 curlink
->enabled
= 0;
637 kill(curlink
->wirepid
, SIGQUIT
);
638 curlink
->connwire
= NULL
;
643 int alinkdeltypelink(int fd
, char *arg
)
646 char *endname
, *name
, *type
;
647 int namelen
, typelen
, i
;
648 struct autolink
*curlink
;
649 struct alwire
*curalwire
, *prevalwire
;
651 /* check if we have name and type */
652 endname
= strstr(arg
, " ");
653 namelen
= (int)endname
- (int)arg
;
654 if( namelen
<= 0 ) return EINVAL
;
656 typelen
= strlen(arg
) - namelen
-1;
657 if( typelen
<= 0 ) return EINVAL
;
660 if( (name
= (char *)malloc(namelen
+1) ) == NULL
) exit(1);
661 snprintf(name
, namelen
+1, "%s", arg
);
663 curlink
= find_alink(name
);
665 if(!curlink
) return ENXIO
;
666 if(curlink
->enabled
) return EINVAL
; /* avoid RC */
668 if(!curlink
->wires
[0]) return EINVAL
; /* no wires! */
671 if( (type
= (char *)malloc(typelen
+1) ) == NULL
) exit(1);
672 snprintf(type
, typelen
+1, "%s", endname
+1);
674 for( i
= 0 ; curlink
->hosts
[i
] != NULL
; i
++){
675 curalwire
= prevalwire
= curlink
->wires
[i
];
678 if(!strcmp(curalwire
->type
, type
)){
679 if(curalwire
== curlink
->wires
[i
]){
680 curlink
->wires
[i
] = curalwire
->next
;
683 prevalwire
->next
= curalwire
->next
;
685 free(curalwire
->type
);
686 free(curalwire
->cmd
);
691 prevalwire
= curalwire
;
692 curalwire
= curalwire
->next
;
700 int alinkaddtypelink(int fd
, char *arg
)
703 char *endname
, *name
, *type
, portbuf
[42];
704 int namelen
, typelen
, i
;
705 struct autolink
*curlink
;
707 struct alwire
*alwire
;
709 /* check if we have name and type */
710 endname
= strstr(arg
, " ");
711 namelen
= (int)endname
- (int)arg
;
712 if( namelen
<= 0 ) return EINVAL
;
714 typelen
= strlen(arg
) - namelen
-1;
715 if( typelen
<= 0 ) return EINVAL
;
717 /* pick autolink and wire */
718 if( (name
= (char *)malloc(namelen
+1) ) == NULL
) exit(1);
719 snprintf(name
, namelen
+1, "%s", arg
);
721 curlink
= find_alink(name
);
723 if(!curlink
) return ENXIO
;
724 if(curlink
->enabled
) return EINVAL
; /* avoid RC */
726 if( (type
= (char *)malloc(typelen
+1) ) == NULL
) exit(1);
727 snprintf(type
, typelen
+1, "%s", endname
+1);
729 wire
= find_wire(type
);
731 if(!wire
) return ENXIO
;
733 /* only one wire type for each autolink */
734 alwire
= find_alwire(wire
->type
, curlink
);
735 if(alwire
) return EINVAL
;
738 for( i
= 0 ; curlink
->hosts
[i
] != NULL
; i
++ ){
739 if(!curlink
->wires
[i
]){
740 if( (curlink
->wires
[i
] = (struct alwire
*)
741 malloc(sizeof(struct alwire
))) == NULL
)
743 alwire
= curlink
->wires
[i
];
746 alwire
= curlink
->wires
[i
];
748 alwire
= alwire
->next
;
749 if( (alwire
->next
=(struct alwire
*)
750 malloc(sizeof(struct alwire
))) == NULL
)
752 alwire
= alwire
->next
;
755 /* set port, sock and remotehost in alwire command */
756 if( (alwire
->cmd
= (char *)malloc(strlen(wire
->cmd
)+1)) == NULL
)
759 strcpy(alwire
->cmd
, wire
->cmd
);
760 sprintf(portbuf
, "%u", curlink
->portno
);
761 strrplc(&(alwire
->cmd
), myport
, portbuf
);
762 strrplc(&(alwire
->cmd
), mysock
, vdeswitch
);
763 strrplc(&(alwire
->cmd
), myhost
, curlink
->hosts
[i
]);
765 /* fill rest of alwire struct */
766 if( (alwire
->type
= (char *)
767 malloc(strlen(wire
->type
)+1)) == NULL
)
770 strcpy(alwire
->type
, wire
->type
);
779 int alinkdellink(int fd
, char *arg
)
782 struct autolink
*curlink
, *prevlink
;
783 struct alwire
*curalwire
, *prevalwire
;
786 if(!alinks
) return EINVAL
;
788 prevlink
= curlink
= alinks
;
790 if(!strcmp(curlink
->name
, arg
)){
791 if(curlink
->enabled
) return EINVAL
; /* avoid RC */
792 if(curlink
== alinks
){
793 alinks
= curlink
->next
;
796 prevlink
->next
= curlink
->next
;
798 port_dispose(curlink
->portno
);
800 /* remove hosts and alwires */
801 for ( i
= 0 ; curlink
->hosts
[i
] != NULL
; i
++){
802 free(curlink
->hosts
[i
]);
803 curalwire
= curlink
->wires
[i
];
805 prevalwire
= curalwire
;
806 curalwire
= curalwire
->next
;
810 free(curlink
->hosts
);
811 free(curlink
->wires
);
816 curlink
= curlink
->next
;
821 int alinkaddlink(int fd
, char *arg
)
824 char *name
, *endname
= NULL
, *tmphosts
, *token
;
825 int namelen
, hostlen
, i
, j
;
826 struct autolink
*curlink
;
828 /* check if we have name and remotehost */
829 endname
= strstr(arg
, " ");
830 namelen
= (int)endname
- (int)arg
;
831 if( namelen
<= 0 ) return EINVAL
;
833 hostlen
= strlen(arg
) - namelen
-1;
834 if( hostlen
<= 0 ) return EINVAL
;
836 /* alloc and set name */
837 if( (name
= (char *)malloc(namelen
+1) ) == NULL
) exit(1);
838 snprintf(name
, namelen
+1, "%s", arg
);
840 /* check for duplicate */
841 if( find_alink(name
) ){
842 free(name
); return EINVAL
;
847 alinks
= (struct autolink
*)malloc(sizeof(struct autolink
));
848 if(alinks
== NULL
) exit(1);
853 curlink
= curlink
->next
;
854 curlink
->next
= (struct autolink
*)
855 malloc(sizeof(struct autolink
));
856 if(curlink
->next
== NULL
) exit(1);
857 curlink
= curlink
->next
;
859 curlink
->name
= name
;
861 /* reserve a port on switch */
862 if( (curlink
->portno
= port_reserve()) < 0 ){
865 if(alinks
== curlink
) alinks
= NULL
;
869 /* alloc and set remote host array (null terminated) */
872 for( tmphosts
=strdup(endname
+1) ; ; tmphosts
=NULL
){
873 token
= strtok(tmphosts
, " ");
874 curlink
->hosts
=realloc(curlink
->hosts
, (i
+1)*sizeof(char *));
875 if(!curlink
->hosts
) exit(1);
876 curlink
->hosts
[i
]=token
;
880 /* alloc wires array */
881 if( (curlink
->wires
= malloc(i
*sizeof(char *))) == NULL
) exit(1);
882 for( j
= 0 ; j
< i
; j
++)
883 curlink
->wires
[j
] = NULL
;
885 curlink
->enabled
= 0;
887 curlink
->connhost
= 0;
888 curlink
->connwire
= NULL
;
889 curlink
->next
= NULL
;
894 int alinkrunninglinks(int fd
, char *arg
)
896 struct autolink
*curlink
;
899 if(!alinks
) return 0;
903 if( curlink
->enabled
&& (curlink
->wirepid
!= -1) &&
904 ( curlink
->state
== ST_ACTIVE
) &&
905 (curlink
->connwire
->try <
906 now
- CHANGEWIRETIME
) ) {
907 /* show only stable connections */
908 printoutc(fd
, "NAME = %s , RHOST = %s , WIRE = %s ,"
909 " PID: %d", curlink
->name
,
910 curlink
->hosts
[curlink
->connhost
],
911 curlink
->connwire
->type
,
915 curlink
= curlink
->next
;
920 int alinkshowlinks(int fd
, char *arg
)
922 struct autolink
*curlink
;
923 struct alwire
*curalwire
= NULL
;
927 printoutc(fd
, "no autolink defined");
932 printoutc(fd
, "NAME = %s (PORT: %d%s)", curlink
->name
,
934 (curlink
->enabled
?" - ACTIVE":""));
935 for(i
= 0 ; curlink
->hosts
[i
] != NULL
; i
++){
936 printoutc(fd
, "RHOST: %s", curlink
->hosts
[i
]);
937 if(curlink
->wires
[i
]){
938 printoutc(fd
, "WIRES:");
939 curalwire
= curlink
->wires
[i
];
942 printoutc(fd
,"%s: %s\n", curalwire
->type
,
944 curalwire
= curalwire
->next
;
948 curlink
= curlink
->next
;
953 int alinkdelwire(int fd
, char* arg
)
955 struct wire
*curwire
, *prevwire
;
957 if(!av_wires
) return EINVAL
;
959 prevwire
= curwire
= av_wires
;
961 if(!strcmp(curwire
->type
, arg
)){
962 if(curwire
== av_wires
){
963 av_wires
= curwire
->next
;
966 prevwire
->next
= curwire
->next
;
974 curwire
= curwire
->next
;
979 int alinkaddwire(int fd
, char* arg
)
982 struct wire
*curwire
= NULL
;
987 /* check if we have type and command */
988 char *endtype
= strstr(arg
, " ");
989 typelen
= (int)endtype
- (int)arg
;
990 if( typelen
<= 0 ) return EINVAL
;
991 cmdlen
= strlen(arg
) - typelen
-1;
992 if( cmdlen
<= 0 ) return EINVAL
;
994 /* alloc and set type */
995 if( (type
= (char *)malloc(typelen
+1) ) == NULL
) exit(1);
996 snprintf(type
, typelen
+1, "%s", arg
);
998 /* check for duplicate */
999 if( find_wire(type
) ){
1000 free(type
); return EINVAL
;
1003 if(av_wires
== NULL
){
1004 av_wires
= (struct wire
*)malloc(sizeof(struct wire
));
1005 if(av_wires
== NULL
) exit(1);
1009 while(curwire
->next
)
1010 curwire
= curwire
->next
;
1011 curwire
->next
= (struct wire
*)malloc(sizeof(struct wire
));
1012 if(curwire
->next
== NULL
) exit(1);
1013 curwire
= curwire
->next
;
1016 curwire
->next
= NULL
;
1017 curwire
->type
= type
;
1019 /* alloc and set command */
1020 if( (curwire
->cmd
= (char *)malloc(cmdlen
+1) ) == NULL
)
1022 snprintf(curwire
->cmd
, cmdlen
+1, "%s", endtype
+1);
1024 /* check variables */
1025 if( !strstr(curwire
->cmd
, myport
) || !strstr(curwire
->cmd
, mysock
) ||
1026 !strstr(curwire
->cmd
, myhost
) ){
1027 free(curwire
->type
); free(curwire
->cmd
);
1029 if(av_wires
== curwire
) av_wires
= NULL
;
1036 int alinkshowwires(int fd
, char *arg
)
1038 struct wire
*curwire
;
1040 printoutc(fd
, "no wire defined");
1045 printoutc(fd
, "TYPE = %s\nCMD = %s\n", curwire
->type
,
1047 curwire
= curwire
->next
;
1052 int alinkshutdown(int fd
, char *arg
)
1054 printlog(LOG_WARNING
,"Shutdown from mgmt command");
1058 int alinkhelp(int fd
, char *arg
)
1061 printoutc(fd
, "help: print a summary of mgmt commands");
1062 printoutc(fd
, "shutdown: terminate");
1063 printoutc(fd
, "runscript: load a config file [args: PATH]");
1064 printoutc(fd
, "showwires: list inserted wires");
1065 printoutc(fd
, "addwire: add a type of wire, with variables [args: TYPE CMD]");
1066 printoutc(fd
, "delwire: delete a type of wire [args: TYPE]");
1067 printoutc(fd
, "showlinks: list inserted autolinks");
1068 printoutc(fd
, "runninglinks: print running links");
1069 printoutc(fd
, "addlink: add an autolink [args: NAME REMOTEHOSTS]");
1070 printoutc(fd
, "dellink: delete an autolink [args: NAME]");
1071 printoutc(fd
, "addtypelink: add a type of wire to named link [args: NAME TYPE]");
1072 printoutc(fd
, "deltypelink: delete a type of wire from named link [args: NAME TYPE]");
1073 printoutc(fd
, "linkonoff: activate/deactivate autolink [args: NAME 1/0]");
1074 printoutc(fd
, "jobsqueue: print status of job queue");
1081 int (*fun
)(int fd
,char *arg
);
1084 {"shutdown", alinkshutdown
},
1085 {"showwires", alinkshowwires
},
1086 {"addwire", alinkaddwire
},
1087 {"delwire", alinkdelwire
},
1089 {"showlinks", alinkshowlinks
},
1090 {"runninglinks", alinkrunninglinks
},
1091 {"addlink", alinkaddlink
},
1092 {"dellink", alinkdellink
},
1094 {"addtypelink", alinkaddtypelink
},
1095 {"deltypelink", alinkdeltypelink
},
1096 {"linkonoff", alinklinkonoff
},
1097 {"runscript", runscript
},
1099 {"jobsqueue", jobsqueue
},
1102 #define NCL sizeof(cl)/sizeof(struct comlist)
1104 static int handle_cmd(int fd
,char *inbuf
)
1108 while (*inbuf
== ' ' || *inbuf
== '\t') inbuf
++;
1109 if (*inbuf
!= '\0' && *inbuf
!= '#') {
1111 strncmp(cl
[i
].tag
,inbuf
,strlen(cl
[i
].tag
))!=0; i
++)
1114 inbuf
+= strlen(cl
[i
].tag
);
1115 while (*inbuf
== ' ' || *inbuf
== '\t') inbuf
++;
1116 printoutc(fd
,"0000 DATA END WITH '.'");
1117 rv
=cl
[i
].fun(fd
,inbuf
);
1120 printoutc(fd
,"1%03d %s",rv
,strerror(rv
));
1126 static int mgmtcommand(int fd
)
1130 n
= read(fd
, buf
, MAXCMD
);
1132 printlog(LOG_ERR
,"read from mgmt %s", strerror(errno
));
1139 if (n
>0 && buf
[n
-1] == '\n')
1141 rv
=handle_cmd(fd
,buf
);
1143 write(fd
,prompt
,strlen(prompt
));
1148 static int newmgmtconn(int fd
,struct pollfd
*pfd
,int nfds
)
1153 struct sockaddr addr
;
1154 new = accept(fd
, &addr
, &len
);
1156 printlog(LOG_ERR
,"mgmt accept %s",strerror(errno
));
1159 if (nfds
< MAXCONS
) {
1161 if(fcntl(new, F_SETFL
, O_NONBLOCK
) < 0){
1162 printlog(LOG_WARNING
, "mgmt fcntl - setting "
1163 "O_NONBLOCK %s",strerror(errno
));
1169 pfd
[nfds
].events
=POLLIN
| POLLHUP
;
1170 pfd
[nfds
].revents
=0;
1172 snprintf(buf
,MAXCMD
,header
,PACKAGE_VERSION
);
1173 write(new,buf
,strlen(buf
));
1174 write(new,prompt
,strlen(prompt
));
1177 printlog(LOG_ERR
,"too many mgmt connections");
1183 static int delmgmtconn(int i
,struct pollfd
*pfd
,int nfds
)
1187 memmove(pfd
+i
,pfd
+i
+1,sizeof (struct pollfd
) * (nfds
-i
-1));
1193 static int openmgmt(char *mgmt
)
1196 struct sockaddr_un sun
;
1199 if((mgmtconnfd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0){
1200 fprintf(stderr
,"%s: mgmt socket: %s",progname
,strerror(errno
));
1203 if(setsockopt(mgmtconnfd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &one
,
1205 fprintf(stderr
,"%s: mgmt setsockopt: %s",progname
,
1209 if(fcntl(mgmtconnfd
, F_SETFL
, O_NONBLOCK
) < 0){
1210 fprintf(stderr
,"%s: Setting O_NONBLOCK on mgmt fd: %s",
1211 progname
,strerror(errno
));
1214 sun
.sun_family
= PF_UNIX
;
1215 snprintf(sun
.sun_path
,sizeof(sun
.sun_path
),"%s",mgmt
);
1216 if(bind(mgmtconnfd
, (struct sockaddr
*) &sun
, sizeof(sun
)) < 0){
1217 fprintf(stderr
,"%s: mgmt bind %s",progname
,strerror(errno
));
1220 chmod(sun
.sun_path
,mgmtmode
);
1221 if(listen(mgmtconnfd
, 15) < 0){
1222 fprintf(stderr
,"%s: mgmt listen: %s",progname
,strerror(errno
));
1228 static int runscript(int fd
,char *path
)
1230 FILE *f
=fopen(path
,"r");
1235 while (fgets(buf
,MAXCMD
,f
) != NULL
) {
1236 if (strlen(buf
) > 1 && buf
[strlen(buf
)-1]=='\n')
1237 buf
[strlen(buf
)-1]= '\0';
1238 if (fd
>= 0) printoutc(fd
,"vde_autolink[%s]: %s",
1240 handle_cmd(fd
, buf
);
1246 static void loadrcfile(void)
1249 runscript(-1,rcfile
);
1251 char path
[PATH_MAX
];
1252 snprintf(path
,PATH_MAX
,"%s/.vde2/vde_autolink.rc",getenv("HOME"));
1253 if (access(path
,R_OK
) == 0)
1256 if (access(STDRCFILE
,R_OK
) == 0)
1257 runscript(-1,STDRCFILE
);
1262 static void save_pidfile()
1264 if(pidfile
[0] != '/')
1265 strncat(pidfile_path
, pidfile
, PATH_MAX
- strlen(pidfile_path
));
1267 strcpy(pidfile_path
, pidfile
);
1269 int fd
= open(pidfile_path
,
1270 O_WRONLY
| O_CREAT
| O_EXCL
,
1271 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
1275 printlog(LOG_ERR
, "Error in pidfile creation: %s",
1280 if((f
= fdopen(fd
, "w")) == NULL
) {
1281 printlog(LOG_ERR
, "Error in FILE* construction: %s",
1286 if(fprintf(f
, "%ld\n", (long int)getpid()) <= 0) {
1287 printlog(LOG_ERR
, "Error in writing pidfile");
1294 static void usage(void)
1297 " -h, --help Display this help\n"
1298 " -f, --rcfile Configuration file (overrides %s and ~/.vde_autolinkrc)\n"
1299 " -d, --daemon Daemonize vde_autolink once run\n"
1300 " -p, --pidfile PIDFILE Write pid of daemon to PIDFILE\n"
1301 " -M, --mgmt SOCK Path of the management UNIX socket\n"
1302 " --mgmtmode MODE Management UNIX socket access mode (octal)\n"
1303 " -s, --sock [*] Attach to this vde_switch socket\n"
1304 " -S, --switchmgmt [*] Attach to this vde_switch management socket\n"
1305 " [*] == Required option!\n"
1309 int main(int argc
,char **argv
)
1312 int n
, npfd
=0, option_index
;
1313 int mgmtfd
, mgmtindex
=-1, vdemgindex
=-1, consoleindex
=-1;
1314 struct job
*j
; time_t now
;
1316 static struct option long_options
[] = {
1317 {"help", 0, 0, 'h'},
1318 {"rcfile", 1, 0, 'f'},
1319 {"daemon", 0, 0, 'd'},
1320 {"pidfile", 1, 0, 'p'},
1321 {"mgmt", 1, 0, 'M'},
1322 {"mgmtmode", 1, 0, MGMTMODEARG
},
1323 {"sock", 1, 0, 's'},
1324 {"switchmgmt", 1, 0, 'S'},
1326 progname
=basename(argv
[0]);
1333 c
= GETOPT_LONG (argc
, argv
, "hf:dp:M:s:S:",
1334 long_options
, &option_index
);
1342 rcfile
=strdup(optarg
);
1348 pidfile
=strdup(optarg
);
1351 mgmt
=strdup(optarg
);
1354 sscanf(optarg
,"%o",&mgmtmode
);
1357 vdeswitch
=strdup(optarg
);
1360 switchmgmt
=strdup(optarg
);
1371 if( !vdeswitch
|| !switchmgmt
)
1375 openlog(basename(progname
), LOG_PID
, 0);
1377 syslog(LOG_INFO
,"VDE_AUTOLINK started");
1380 if(isatty(0) && !daemonize
){
1382 pfd
[consoleindex
].fd
=0;
1383 pfd
[consoleindex
].events
=POLLIN
| POLLHUP
;
1384 pfd
[consoleindex
].revents
=0;
1388 if(getcwd(pidfile_path
, PATH_MAX
-1) == NULL
) {
1389 printlog(LOG_ERR
, "getcwd: %s", strerror(errno
));
1392 strcat(pidfile_path
, "/");
1393 if (daemonize
&& daemon(0, 1)) {
1394 printlog(LOG_ERR
,"daemon: %s",strerror(errno
));
1397 if(pidfile
) save_pidfile();
1399 if( (vdemgmt
=vdemgmt_open(switchmgmt
)) == NULL
){
1400 printlog(LOG_ERR
, "cannot open %s\n", switchmgmt
);
1404 pfd
[vdemgindex
].fd
=vdemgmt_getfd(vdemgmt
);
1405 pfd
[vdemgindex
].events
=POLLIN
| POLLHUP
;
1406 pfd
[vdemgindex
].revents
=0;
1409 if( vdemgmt_asyncreg(vdemgmt
, FSTPDBG_PADD
, ah_padd
)
1410 || vdemgmt_asyncreg(vdemgmt
, FSTPDBG_PDEL
, ah_pdel
)
1411 || vdemgmt_asyncreg(vdemgmt
, FSTPDBG_STAT
, ah_state
) ){
1412 printlog(LOG_ERR
, "cannot register async handler on switch");
1417 mgmtfd
=openmgmt(mgmt
);
1419 pfd
[mgmtindex
].fd
=mgmtfd
;
1420 pfd
[mgmtindex
].events
=POLLIN
| POLLHUP
;
1421 pfd
[mgmtindex
].revents
=0;
1429 n
=poll(pfd
,npfd
,polltimeout
);
1431 /* Handle async output from switch */
1432 if(pfd
[vdemgindex
].revents
& POLLHUP
){
1433 printlog(LOG_ERR
, "switch closed connection, exiting");
1436 if( pfd
[vdemgindex
].revents
& POLLIN
)
1437 vdemgmt_asyncrecv(vdemgmt
);
1439 /* Handle console connections and commands */
1440 if(consoleindex
>= 0 &&
1441 ( pfd
[consoleindex
].revents
& POLLHUP
||
1442 (pfd
[consoleindex
].revents
& POLLIN
&&
1443 mgmtcommand(pfd
[consoleindex
].fd
)<0) ) )
1446 if (mgmt
&& (pfd
[mgmtindex
].revents
!= 0))
1447 npfd
=newmgmtconn(pfd
[mgmtindex
].fd
,pfd
,npfd
);
1449 if (mgmt
&& (npfd
> mgmtindex
+1)) {
1451 for (i
=mgmtindex
+1;i
<npfd
;i
++) {
1452 if( (pfd
[i
].revents
& POLLHUP
) ||
1453 ((pfd
[i
].revents
& POLLIN
) &&
1454 (mgmtcommand(pfd
[i
].fd
) < 0)) )
1455 npfd
=delmgmtconn(i
,pfd
,npfd
);
1459 /* Run scheduled jobs and compute new timeout for poll */
1461 while ( jq
&& (now
> jq
->time
) ){
1463 if (alink_exists(j
->al
) && j
->al
->enabled
)
1467 polltimeout
= jq
? jq
->time
- now
: -1 ;