1 /* Copyright 2005 Renzo Davoli - VDE-2
2 * --pidfile/-p and cleanup management by Mattia Belletti (C) 2004.
3 * Licensed under the GPLv2
15 #include <sys/types.h>
17 #include <sys/ioctl.h>
18 #include <sys/socket.h>
29 #include <sockutils.h>
36 static struct swmodule swmi
;
40 static char *pidfile
= NULL
;
41 static char pidfile_path
[PATH_MAX
];
42 static int daemonize
= 0;
43 static unsigned int console_type
=-1;
44 static unsigned int mgmt_ctl
=-1;
45 static unsigned int mgmt_data
=-1;
46 static int mgmt_mode
= 0600;
47 static char *mgmt_socket
= NULL
;
48 static char header
[]="VDE switch V.%s\n(C) R.Davoli 2005 - GPLv2\n";
49 static char prompt
[]="\nvde: ";
51 static struct comlist
*clh
=NULL
;
53 void addcl(int ncl
,struct comlist
*cl
)
56 static struct comlist
**clt
=&clh
;
57 for (i
=0;i
<ncl
;i
++,cl
++) {
64 void printlog(int priority
, const char *format
, ...)
68 va_start (arg
, format
);
71 vsyslog(priority
,format
,arg
);
73 fprintf(stderr
,"%s: ",prog
);
74 vfprintf(stderr
,format
,arg
);
80 void printoutc(int fd
, const char *format
, ...)
84 va_start (arg
, format
);
86 printlog(LOG_INFO
,format
,arg
);
88 char outbuf
[MAXCMD
+1];
89 vsnprintf(outbuf
,MAXCMD
,format
,arg
);
91 write(fd
,outbuf
,strlen(outbuf
));
95 void setmgmtperm(char *path
)
97 chmod(path
,mgmt_mode
);
100 static int help(int fd
,char *arg
)
104 printoutc(fd
,"%-18s %-15s %s","COMMAND PATH","SYNTAX","HELP");
105 printoutc(fd
,"%-18s %-15s %s","------------","--------------","------------");
106 for (p
=clh
;p
!=NULL
;p
=p
->next
)
107 if (strncmp(p
->path
,arg
,n
) == 0)
108 printoutc(fd
,"%-18s %-15s %s",p
->path
,p
->syntax
,p
->help
);
112 static int handle_cmd(int type
,int fd
,char *inbuf
)
116 while (*inbuf
== ' ' || *inbuf
== '\t') inbuf
++;
117 if (*inbuf
!= '\0' && *inbuf
!= '#') {
118 for (p
=clh
;p
!=NULL
&& (p
->doit
==NULL
|| strncmp(p
->path
,inbuf
,strlen(p
->path
))!=0); p
=p
->next
)
122 inbuf
+= strlen(p
->path
);
123 while (*inbuf
== ' ' || *inbuf
== '\t') inbuf
++;
124 if (p
->type
& WITHFD
) {
125 printoutc(fd
,"0000 DATA END WITH '.'");
126 switch(p
->type
& ~WITHFD
){
127 case NOARG
: rv
=p
->doit(fd
); break;
128 case INTARG
: rv
=p
->doit(fd
,atoi(inbuf
)); break;
129 case STRARG
: rv
=p
->doit(fd
,inbuf
); break;
134 case NOARG
: rv
=p
->doit(); break;
135 case INTARG
: rv
=p
->doit(atoi(inbuf
)); break;
136 case STRARG
: rv
=p
->doit(inbuf
); break;
140 if (rv
>= 0 && (rv
> 0 || fd
>= 0))
141 printoutc(fd
,"1%03d %s",rv
,strerror(rv
));
146 static int runscript(int fd
,char *path
)
148 FILE *f
=fopen(path
,"r");
153 while (fgets(buf
,MAXCMD
,f
) != NULL
) {
154 if (strlen(buf
) > 1 && buf
[strlen(buf
)-1]=='\n') buf
[strlen(buf
)-1]= '\0';
155 if (fd
>= 0) printoutc(fd
,"vde[%s]: %s",path
,buf
);
156 handle_cmd(mgmt_data
, fd
, buf
);
162 void loadrcfile(void)
165 runscript(-1,rcfile
);
168 snprintf(path
,PATH_MAX
,"%s/.vderc",getenv("HOME"));
169 if (access(path
,R_OK
) == 0)
172 if (access(STDRCFILE
,R_OK
) == 0)
173 runscript(-1,STDRCFILE
);
178 static void handle_input(unsigned char type
,int fd
,int revents
,int *unused
)
181 if (type
!= mgmt_ctl
) {
184 if (revents
& POLLIN
) {
185 n
= read(fd
, buf
, sizeof(buf
));
187 printlog(LOG_WARNING
,"Reading from mgmt %s",strerror(errno
));
191 if (type
== console_type
) {
192 printlog(LOG_WARNING
,"EOF on stdin, cleaning up and exiting");
200 if (n
>0 && buf
[n
-1] == '\n') buf
[n
-1] = 0;
201 cmdout
=handle_cmd(type
,(type
==console_type
)?STDOUT_FILENO
:fd
,buf
);
203 write(fd
,prompt
,strlen(prompt
));
205 if(type
==mgmt_data
) {
206 printoutc(fd
,"9999 END OF SESSION");
213 } else {/* mgmt ctl */
214 struct sockaddr addr
;
219 new = accept(fd
, &addr
, &len
);
221 printlog(LOG_WARNING
,"mgmt accept %s",strerror(errno
));
224 if(fcntl(new, F_SETFL
, O_NONBLOCK
) < 0){
225 printlog(LOG_WARNING
,"mgmt fcntl - setting O_NONBLOCK %s",strerror(errno
));
230 add_fd(new,mgmt_data
,-1);
231 snprintf(buf
,MAXCMD
,header
,PACKAGE_VERSION
);
232 write(new,buf
,strlen(buf
));
233 write(new,prompt
,strlen(prompt
));
237 static void save_pidfile()
239 if(pidfile
[0] != '/')
240 strncat(pidfile_path
, pidfile
, PATH_MAX
- strlen(pidfile_path
));
242 strcpy(pidfile_path
, pidfile
);
244 int fd
= open(pidfile_path
,
245 O_WRONLY
| O_CREAT
| O_EXCL
,
246 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
250 printlog(LOG_ERR
, "Error in pidfile creation: %s", strerror(errno
));
254 if((f
= fdopen(fd
, "w")) == NULL
) {
255 printlog(LOG_ERR
, "Error in FILE* construction: %s", strerror(errno
));
259 if(fprintf(f
, "%ld\n", (long int)getpid()) <= 0) {
260 printlog(LOG_ERR
, "Error in writing pidfile");
267 static void cleanup(unsigned char type
,int fd
,int arg
)
270 if((pidfile
!= NULL
) && unlink(pidfile_path
) < 0) {
271 printlog(LOG_WARNING
,"Couldn't remove pidfile '%s': %s", pidfile
, strerror(errno
));
275 if (type
== mgmt_ctl
&& mgmt_socket
!= NULL
) {
281 #define MGMTMODEARG 0x100
283 static struct option long_options
[] = {
284 {"daemon", 0, 0, 'd'},
285 {"pidfile", 1, 0, 'p'},
286 {"rcfile", 1, 0, 'f'},
288 {"mgmtmode", 1, 0, MGMTMODEARG
}
291 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
293 static void usage(void)
296 "(opts from consmgmt module)\n"
297 " -d, --daemon Daemonize vde_switch once run\n"
298 " -p, --pidfile PIDFILE Write pid of daemon to PIDFILE\n"
299 " -f, --rcfile Configuration file (overrides %s and ~/.vderc)\n"
300 " -M, --mgmt SOCK path of the management UNIX socket\n"
301 " --mgmtmode MODE management UNIX socket access mode (octal)\n"
305 static int parseopt(int c
, char *optarg
)
313 pidfile
=strdup(optarg
);
316 rcfile
=strdup(optarg
);
319 mgmt_socket
=strdup(optarg
);
322 sscanf(optarg
,"%o",&mgmt_mode
);
330 static void init(void)
333 openlog(basename(prog
), LOG_PID
, 0);
335 syslog(LOG_INFO
,"VDE_SWITCH started");
337 /* add stdin (if tty), connect and data fds to the set of fds we wait for
339 if(isatty(0) && !daemonize
)
341 console_type
=add_type(&swmi
,0);
342 add_fd(0,console_type
,-1);
345 /* saves current path in pidfile_path, because otherwise with daemonize() we
347 if(getcwd(pidfile_path
, PATH_MAX
-1) == NULL
) {
348 printlog(LOG_ERR
, "getcwd: %s", strerror(errno
));
351 strcat(pidfile_path
, "/");
352 if (daemonize
&& daemon(0, 1)) {
353 printlog(LOG_ERR
,"daemon: %s",strerror(errno
));
357 /* once here, we're sure we're the true process which will continue as a
358 * * server: save PID file if needed */
359 if(pidfile
) save_pidfile();
361 if(mgmt_socket
!= NULL
) {
363 struct sockaddr_un sun
;
366 if((mgmtconnfd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0){
367 printlog(LOG_ERR
,"mgmt socket: %s",strerror(errno
));
370 if(setsockopt(mgmtconnfd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &one
,
372 printlog(LOG_ERR
,"mgmt setsockopt: %s",strerror(errno
));
375 if(fcntl(mgmtconnfd
, F_SETFL
, O_NONBLOCK
) < 0){
376 printlog(LOG_ERR
,"Setting O_NONBLOCK on mgmt fd: %s",strerror(errno
));
379 sun
.sun_family
= PF_UNIX
;
380 snprintf(sun
.sun_path
,sizeof(sun
.sun_path
),"%s",mgmt_socket
);
381 if(bind(mgmtconnfd
, (struct sockaddr
*) &sun
, sizeof(sun
)) < 0){
382 if((errno
== EADDRINUSE
) && still_used(&sun
)) return;
383 else if(bind(mgmtconnfd
, (struct sockaddr
*) &sun
, sizeof(sun
)) < 0){
384 printlog(LOG_ERR
,"mgmt bind %s",strerror(errno
));
388 chmod(sun
.sun_path
,mgmt_mode
);
389 if(listen(mgmtconnfd
, 15) < 0){
390 printlog(LOG_ERR
,"mgmt listen: %s",strerror(errno
));
393 mgmt_ctl
=add_type(&swmi
,0);
394 mgmt_data
=add_type(&swmi
,0);
395 add_fd(mgmtconnfd
,mgmt_ctl
,-1);
399 static int vde_logout()
404 static int vde_shutdown()
406 printlog(LOG_WARNING
,"Shutdown from mgmt command");
410 static int showinfo(int fd
)
412 printoutc(fd
,header
,PACKAGE_VERSION
);
413 printoutc(fd
,"pid %d MAC %02x:%02x:%02x:%02x:%02x:%02x uptime %d",getpid(),
414 switchmac
[0], switchmac
[1], switchmac
[2], switchmac
[3], switchmac
[4], switchmac
[5],
417 printoutc(fd
,"mgmt %s perm 0%03o",mgmt_socket
,mgmt_mode
);
418 printoutc(fd
,"unsent_pktq_len %d",packetq_count());
422 static struct comlist cl
[]={
423 {"help","[arg]","Help (limited to arg when specified)",help
,STRARG
| WITHFD
},
424 {"logout","","logout from this mgmt terminal",vde_logout
,NOARG
},
425 {"shutdown","","shutdown of the switch",vde_shutdown
,NOARG
},
426 {"showinfo","","show switch version and info",showinfo
,NOARG
|WITHFD
},
427 {"load","path","load a configuration script",runscript
,STRARG
|WITHFD
},
430 void start_consmgmt(void)
432 swmi
.swmname
="console-mgmt";
433 swmi
.swmnopts
=Nlong_options
;
434 swmi
.swmopts
=long_options
;
436 swmi
.parseopt
=parseopt
;
438 swmi
.handle_input
=handle_input
;
439 swmi
.cleanup
=cleanup
;