2 * VDETELWEB: VDE telnet and WEB interface
6 * Copyright 2005 Renzo Davoli University of Bologna - Italy
7 * --pidfile/-p and cleanup management by Mattia Belletti (C) 2004
8 * (copied from vde_switch code).
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/select.h>
38 #include <sys/utsname.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
46 #include "vdetelweb.h"
58 static char *pidfile
= NULL
;
59 static char pidfile_path
[_POSIX_PATH_MAX
];
63 struct pollfd pfd
[MAXFD
];
64 typedef int (*intfun
)();
68 #define ROOTCONFFILE "/etc/vde/vdetelwebrc"
70 void printlog(int priority
, const char *format
, ...)
74 va_start (arg
, format
);
77 vsyslog(priority
,format
,arg
);
79 fprintf(stderr
,"%s: ",progname
);
80 vfprintf(stderr
,format
,arg
);
87 static void cleanup(void)
89 if((pidfile
!= NULL
) && unlink(pidfile_path
) < 0) {
90 printlog(LOG_WARNING
,"Couldn't remove pidfile '%s': %s", pidfile
, strerror(errno
));
94 static void sig_handler(int sig
)
101 static void setsighandlers()
103 /* setting signal handlers.
104 * * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
105 * * ignores all the others signals which could cause termination. */
106 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
107 { SIGHUP
, "SIGHUP", 0 },
108 { SIGINT
, "SIGINT", 0 },
109 { SIGPIPE
, "SIGPIPE", 1 },
110 { SIGALRM
, "SIGALRM", 1 },
111 { SIGTERM
, "SIGTERM", 0 },
112 { SIGUSR1
, "SIGUSR1", 1 },
113 { SIGUSR2
, "SIGUSR2", 1 },
114 { SIGPOLL
, "SIGPOLL", 1 },
115 { SIGPROF
, "SIGPROF", 1 },
116 { SIGVTALRM
, "SIGVTALRM", 1 },
117 { SIGSTKFLT
, "SIGSTKFLT", 1 },
118 { SIGIO
, "SIGIO", 1 },
119 { SIGPWR
, "SIGPWR", 1 },
120 { SIGUNUSED
, "SIGUNUSED", 1 },
125 for(i
= 0; signals
[i
].sig
!= 0; i
++)
126 if(signal(signals
[i
].sig
,
127 signals
[i
].ignore
? SIG_IGN
: sig_handler
) < 0)
128 perror("Setting handler");
131 static void usage(char *progname
) {
132 fprintf (stderr
,"Usage: %s [-w] [-t] [-d] [-n nodename] [-p pidfile] mgmt_socket\n"
133 " %s [--web] [--telnet] [--daemon] [--nodename nodename] [--pidfile pidfile] mgmt_socket\n",progname
,progname
);
137 void setprompt(char *ctrl
,char *nodename
)
140 if (nodename
==NULL
) {
143 snprintf(buf
,BUFSIZE
,"VDE2@%s[%s]: ",un
.nodename
,ctrl
);
145 snprintf(buf
,BUFSIZE
,"VDE2@%s[%s]: ",nodename
,ctrl
);
149 int openvdem(char *mgmt
,char *progname
, struct netif
**nif
,char *nodename
)
151 struct sockaddr_un sun
;
153 char buf
[BUFSIZE
+1],*line2
,*ctrl
;
154 sun
.sun_family
=PF_UNIX
;
155 snprintf(sun
.sun_path
,UNIX_PATH_MAX
,"%s",mgmt
);
156 fd
=socket(PF_UNIX
,SOCK_STREAM
,0);
157 if (connect(fd
,(struct sockaddr
*)(&sun
),sizeof(sun
)) < 0) {
158 printlog(LOG_ERR
,"mgmt connect %s",strerror(errno
));
161 if ((n
=read(fd
,buf
,BUFSIZE
))<=0) {
162 printlog(LOG_ERR
,"banner %s",strerror(errno
));
166 if ((ctrl
=rindex(buf
,'\n')) != NULL
)
169 write(fd
,"ds/showinfo\n",13);
170 if ((n
=read(fd
,buf
,BUFSIZE
))<=0) {
171 printlog(LOG_ERR
,"read ctl socket %s",strerror(errno
));
175 if ((line2
=index(buf
,'\n')) == NULL
) {
176 printlog(LOG_ERR
,"read ctl socket parse error 1");
180 if (strncmp(line2
,"ctl dir ",8) != 0) {
181 printlog(LOG_ERR
,"read ctl socket parse error");
184 for(ctrl
=line2
+8;*ctrl
!='\n' && ctrl
<buf
+n
;ctrl
++)
188 setprompt(ctrl
,nodename
);
190 *nif
=lwip_vdeif_add(ctrl
);
192 printlog(LOG_ERR
,"cannot connect to the switch");
200 static void bitno2mask(unsigned char *addr
,int bitno
,int len
)
203 for(i
=0;i
<len
;i
++,bitno
-= 8) {
209 addr
[i
]=256 - (1<<(8-bitno
));
213 static void sockaddr2ip_6addr(struct ip_addr
*ipaddrp
,unsigned char *addr
)
216 (addr
[0]<<8)|addr
[1],
217 (addr
[2]<<8)|addr
[3],
218 (addr
[4]<<8)|addr
[5],
219 (addr
[6]<<8)|addr
[7],
220 (addr
[8]<<8)|addr
[9],
221 (addr
[10]<<8)|addr
[11],
222 (addr
[12]<<8)|addr
[13],
223 (addr
[14]<<8)|addr
[15]);
226 static void readip(char *arg
,struct netif
*nif
,int af
)
228 char *bit
=rindex(arg
,'/');
230 printlog(LOG_ERR
,"ip addresses must include the netmask i.e. addr/maskbits");
232 int bitno
=atoi(bit
+1);
234 struct addrinfo
*res
,hint
;
235 struct ip_addr ipaddr
,netmask
;
237 memset(&hint
,0,sizeof(hint
));
239 if (err
=getaddrinfo(arg
,NULL
,&hint
,&res
))
240 printlog(LOG_ERR
,"ip address %s error %s",arg
,gai_strerror(err
));
242 switch(res
->ai_family
) {
244 struct sockaddr_in
*in
=(struct sockaddr_in
*)res
->ai_addr
;
245 int addrh
=ntohl(in
->sin_addr
.s_addr
);
246 unsigned char i
,addr
[4];
247 for (i
=0;i
<4;i
++,addrh
>>=8)
249 IP64_ADDR(&ipaddr
, addr
[0],addr
[1],addr
[2],addr
[3]);
250 bitno2mask(addr
,bitno
,4);
251 IP64_MASKADDR(&netmask
, addr
[0],addr
[1],addr
[2],addr
[3]);
252 lwip_add_addr(nif
,&ipaddr
,&netmask
);
256 struct sockaddr_in6
*in
=(struct sockaddr_in6
*)res
->ai_addr
;
258 unsigned char *addr
=in
->sin6_addr
.s6_addr
;
259 sockaddr2ip_6addr(&ipaddr
,addr
);
260 bitno2mask(addr
,bitno
,16);
261 sockaddr2ip_6addr(&netmask
,addr
);
262 lwip_add_addr(nif
,&ipaddr
,&netmask
);
266 printlog(LOG_ERR
,"unsupported Address Family: %s",arg
);
273 static void readdefroute(char *arg
,struct netif
*nif
,int af
)
275 struct addrinfo
*res
,hint
;
276 struct ip_addr ipaddr
,netmask
;
278 memset(&hint
,0,sizeof(hint
));
280 if (err
=getaddrinfo(arg
,NULL
,&hint
,&res
))
281 printlog(LOG_ERR
,"ip address %s error %s",arg
,gai_strerror(err
));
283 switch(res
->ai_family
) {
285 struct sockaddr_in
*in
=(struct sockaddr_in
*)res
->ai_addr
;
286 int addrh
=ntohl(in
->sin_addr
.s_addr
);
287 unsigned char i
,addr
[4];
288 for (i
=0;i
<4;i
++,addrh
>>=8)
290 IP64_ADDR(&ipaddr
, addr
[0],addr
[1],addr
[2],addr
[3]);
291 lwip_add_route(IP_ADDR_ANY
,IP_ADDR_ANY
,&ipaddr
,nif
,0);
295 struct sockaddr_in6
*in
=(struct sockaddr_in6
*)res
->ai_addr
;
297 sockaddr2ip_6addr(&ipaddr
,in
->sin6_addr
.s6_addr
);
298 lwip_add_route(IP_ADDR_ANY
,IP_ADDR_ANY
,&ipaddr
,nif
,0);
302 printlog(LOG_ERR
,"unsupported Address Family: %s",arg
);
308 static void readpassword(char *arg
,int unused
)
318 {"ip4",readip
,PF_INET
},
319 {"ip6",readip
,PF_INET6
},
321 {"defroute4",readdefroute
,PF_INET
},
322 {"defroute6",readdefroute
,PF_INET6
},
323 {"defroute",readdefroute
,0},
324 {"password",readpassword
,0},
327 int readconffile(char *path
,struct netif
*nif
)
330 char buf
[BUFSIZE
],*s
;
331 if (path
== NULL
&& geteuid() == 0)
335 if((f
=fopen(path
,"r"))==NULL
)
337 while (fgets(buf
,BUFSIZE
,f
) != NULL
) {
338 if ((s
=rindex(buf
,'\n')) != NULL
)
340 for(s
=buf
;*s
== ' ' || *s
== '\t';s
++)
344 for (scf
=cft
;scf
->tag
!= NULL
;scf
++)
345 if(strncmp(s
,scf
->tag
,strlen(scf
->tag
)) == 0){
347 for(;*s
== ' ' || *s
== '\t';s
++)
350 for(;*s
== ' ' || *s
== '\t';s
++)
352 scf
->f(s
,nif
,scf
->arg
);
355 if (scf
->tag
== NULL
) {
356 printlog(LOG_ERR
,"rc file syntax error: %s",buf
);
363 int addpfd(int fd
,intfun cb
)
367 pfd
[npfd
].events
=POLLIN
|POLLHUP
;
378 for (i
=fn
;i
<npfd
-1;i
++) {
381 status
[i
]=status
[i
+1];
386 int pfdsearch(int fd
)
389 for (i
=0;i
<npfd
&& pfd
[i
].fd
!=fd
;i
++)
394 int setfds(fd_set
*rds
, fd_set
*exc
)
399 for (i
=0;i
<npfd
;i
++) {
400 FD_SET(pfd
[i
].fd
,rds
);
401 FD_SET(pfd
[i
].fd
,exc
);
402 if (pfd
[i
].fd
>max
) max
=pfd
[i
].fd
;
407 static void save_pidfile()
409 if(pidfile
[0] != '/')
410 strncat(pidfile_path
, pidfile
, PATH_MAX
- strlen(pidfile_path
));
412 strcpy(pidfile_path
, pidfile
);
414 int fd
= open(pidfile_path
,
415 O_WRONLY
| O_CREAT
| O_EXCL
,
416 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
420 printlog(LOG_ERR
, "Error in pidfile creation: %s", strerror(errno
));
424 if((f
= fdopen(fd
, "w")) == NULL
) {
425 printlog(LOG_ERR
, "Error in FILE* construction: %s", strerror(errno
));
429 if(fprintf(f
, "%ld\n", (long int)getpid()) <= 0) {
430 printlog(LOG_ERR
, "Error in writing pidfile");
437 int main(int argc
, char *argv
[])
447 int option_index
= 0;
449 static struct option long_options
[] = {
450 {"daemon", 0, 0, 'd'},
452 {"telnet", 0, 0, 't'},
456 {"nodename",1,0,'n'},
457 {"pidfile", 1, 0, 'p'},
460 c
= getopt_long_only (argc
, argv
, "hdwtM:f:n:",
461 long_options
, &option_index
);
470 conffile
=strdup(optarg
);
473 nodename
=strdup(optarg
);
485 pidfile
=strdup(optarg
);
488 usage(argv
[0]); //implies exit
492 if (optind
< argc
&& mgmt
==NULL
)
496 printlog(LOG_ERR
,"mgmt_socket not defined");
499 if (telnet
==0 && web
==0) {
500 printlog(LOG_ERR
,"at least one service option (-t -w) must be specified");
506 openlog(basename(argv
[0]), LOG_PID
, 0);
508 syslog(LOG_INFO
,"VDETELWEB started");
511 /* saves current path in pidfile_path, because otherwise with daemonize() we
513 if(getcwd(pidfile_path
, PATH_MAX
-1) == NULL
) {
514 printlog(LOG_ERR
, "getcwd: %s", strerror(errno
));
517 strcat(pidfile_path
, "/");
519 if (daemonize
&& daemon(0, 1)) {
520 printlog(LOG_ERR
,"daemon: %s",strerror(errno
));
523 /* once here, we're sure we're the true process which will continue as a
524 * server: save PID file if needed */
525 if(pidfile
) save_pidfile();
528 vdefd
=openvdem(mgmt
,argv
[0],&nif
,nodename
);
529 if (readconffile(conffile
,nif
) < 0) {
530 printlog(LOG_ERR
,"configuration file not found");
542 int max
=setfds(&rds
,&exc
);
543 m
=lwip_select(max
,&rds
,NULL
,&exc
,NULL
);
544 for(i
=0; m
>0 && i
<max
; i
++) {
545 if (FD_ISSET(i
,&rds
) || FD_ISSET(i
,&exc
)) {