Fixed some details on help messages
[vde.git] / vde-2 / consmgmt.c
blobc6e373cfba41b96eae23027c0b5dfe17ca12bd12
1 /* Copyright 2005 Renzo Davoli - VDE-2
2 * --pidfile/-p and cleanup management by Mattia Belletti (C) 2004.
3 * Licensed under the GPLv2
4 */
6 #include <config.h>
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <syslog.h>
13 #include <stdlib.h>
14 #include <libgen.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/ioctl.h>
18 #include <sys/socket.h>
19 #include <sys/poll.h>
20 #include <linux/un.h>
21 #include <net/if.h>
22 #include <stdarg.h>
23 #define _GNU_SOURCE
24 #include <getopt.h>
26 #include <port.h>
27 #include <switch.h>
28 #include <sockutils.h>
29 #include <consmgmt.h>
30 #include <qtimer.h>
32 #define MAXCMD 128
34 static struct swmodule swmi;
36 static int logok=0;
37 static char *rcfile;
38 static char *pidfile = NULL;
39 static char pidfile_path[_POSIX_PATH_MAX];
40 static int daemonize = 0;
41 static unsigned int console_type=-1;
42 static unsigned int mgmt_ctl=-1;
43 static unsigned int mgmt_data=-1;
44 static int mgmt_mode = 0600;
45 static char *mgmt_socket = NULL;
46 static char header[]="VDE switch V.%s\n(C) R.Davoli 2005 - GPLv2\n";
47 static char prompt[]="\nvde: ";
49 static struct comlist *clh=NULL;
51 void addcl(int ncl,struct comlist *cl)
53 register int i;
54 static struct comlist **clt=&clh;
55 for (i=0;i<ncl;i++,cl++) {
56 cl->next=NULL;
57 (*clt)=cl;
58 clt=(&cl->next);
62 void printlog(int priority, const char *format, ...)
64 va_list arg;
66 va_start (arg, format);
68 if (logok)
69 vsyslog(priority,format,arg);
70 else {
71 fprintf(stderr,"%s: ",prog);
72 vfprintf(stderr,format,arg);
73 fprintf(stderr,"\n");
75 va_end (arg);
78 void printoutc(int fd, const char *format, ...)
80 va_list arg;
82 va_start (arg, format);
83 if (fd < 0)
84 printlog(LOG_INFO,format,arg);
85 else {
86 char outbuf[MAXCMD+1];
87 vsnprintf(outbuf,MAXCMD,format,arg);
88 strcat(outbuf,"\n");
89 write(fd,outbuf,strlen(outbuf));
93 void setmgmtperm(char *path)
95 chmod(path,mgmt_mode);
98 static int help(int fd,char *arg)
100 struct comlist *p;
101 int n=strlen(arg);
102 printoutc(fd,"%-18s %-15s %s","COMMAND PATH","SYNTAX","HELP");
103 printoutc(fd,"%-18s %-15s %s","------------","--------------","------------");
104 for (p=clh;p!=NULL;p=p->next)
105 if (strncmp(p->path,arg,n) == 0)
106 printoutc(fd,"%-18s %-15s %s",p->path,p->syntax,p->help);
107 return 0;
110 static int handle_cmd(int type,int fd,char *inbuf)
112 struct comlist *p;
113 int rv=ENOSYS;
114 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
115 if (*inbuf != '\0' && *inbuf != '#') {
116 for (p=clh;p!=NULL && (p->doit==NULL || strncmp(p->path,inbuf,strlen(p->path))!=0); p=p->next)
118 if (p!=NULL)
120 inbuf += strlen(p->path);
121 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
122 if (p->type & WITHFD) {
123 printoutc(fd,"0000 DATA END WITH '.'");
124 switch(p->type & ~WITHFD){
125 case NOARG: rv=p->doit(fd); break;
126 case INTARG: rv=p->doit(fd,atoi(inbuf)); break;
127 case STRARG: rv=p->doit(fd,inbuf); break;
129 printoutc(fd,".");
130 } else {
131 switch(p->type){
132 case NOARG: rv=p->doit(); break;
133 case INTARG: rv=p->doit(atoi(inbuf)); break;
134 case STRARG: rv=p->doit(inbuf); break;
138 if (rv >= 0 && (rv > 0 || fd >= 0))
139 printoutc(fd,"1%03d %s",rv,strerror(rv));
141 return rv;
144 static int runscript(int fd,char *path)
146 FILE *f=fopen(path,"r");
147 char buf[MAXCMD];
148 if (f==NULL)
149 return ENOENT;
150 else {
151 while (fgets(buf,MAXCMD,f) != NULL) {
152 if (strlen(buf) > 1 && buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]= '\0';
153 if (fd >= 0) printoutc(fd,"vde[%s]: %s",path,buf);
154 handle_cmd(mgmt_data, fd, buf);
156 return 0;
160 void loadrcfile(void)
162 if (rcfile != NULL)
163 runscript(-1,rcfile);
164 else {
165 char path[PATH_MAX];
166 snprintf(path,PATH_MAX,"%s/.vderc",getenv("HOME"));
167 if (access(path,R_OK) == 0)
168 runscript(-1,path);
169 else {
170 if (access(STDRCFILE,R_OK) == 0)
171 runscript(-1,STDRCFILE);
176 static void handle_input(unsigned char type,int fd,int revents,int *unused)
178 char buf[MAXCMD];
179 if (type != mgmt_ctl) {
180 int n=0;
182 if (revents & POLLIN) {
183 n = read(fd, buf, sizeof(buf));
184 if(n < 0){
185 printlog(LOG_WARNING,"Reading from mgmt %s",strerror(errno));
188 if (n==0) { /*EOF*/
189 if (type == console_type) {
190 printlog(LOG_WARNING,"EOF on stdin, cleaning up and exiting");
191 exit(0);
192 } else {
193 remove_fd(fd);
195 } else {
196 int cmdout;
197 buf[n]=0;
198 if (n>0 && buf[n-1] == '\n') buf[n-1] = 0;
199 cmdout=handle_cmd(type,(type==console_type)?STDOUT_FILENO:fd,buf);
200 if (cmdout >= 0)
201 write(fd,prompt,strlen(prompt));
202 else {
203 if(type==mgmt_data) {
204 printoutc(fd,"9999 END OF SESSION");
205 remove_fd(fd);
207 if (cmdout == -2)
208 exit(0);
211 } else {/* mgmt ctl */
212 struct sockaddr addr;
213 int len, new;
215 len = sizeof(addr);
216 new = accept(fd, &addr, &len);
217 if(new < 0){
218 printlog(LOG_WARNING,"mgmt accept %s",strerror(errno));
219 return;
221 if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
222 printlog(LOG_WARNING,"mgmt fcntl - setting O_NONBLOCK %s",strerror(errno));
223 close(new);
224 return;
227 add_fd(new,mgmt_data,-1);
228 snprintf(buf,MAXCMD,header,PACKAGE_VERSION);
229 write(new,buf,strlen(buf));
230 write(new,prompt,strlen(prompt));
234 static void save_pidfile()
236 if(pidfile[0] != '/')
237 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
238 else
239 strcpy(pidfile_path, pidfile);
241 int fd = open(pidfile_path,
242 O_WRONLY | O_CREAT | O_EXCL,
243 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
244 FILE *f;
246 if(fd == -1) {
247 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
248 exit(1);
251 if((f = fdopen(fd, "w")) == NULL) {
252 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
253 exit(1);
256 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
257 printlog(LOG_ERR, "Error in writing pidfile");
258 exit(1);
261 fclose(f);
264 static void cleanup(unsigned char type,int fd,int arg)
266 if (fd < 0) {
267 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
268 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
270 } else {
271 close(fd);
272 if (type == mgmt_ctl && mgmt_socket != NULL) {
273 unlink(mgmt_socket);
278 #define MGMTMODEARG 0x100
280 static struct option long_options[] = {
281 {"daemon", 0, 0, 'd'},
282 {"pidfile", 1, 0, 'p'},
283 {"rcfile", 1, 0, 'f'},
284 {"mgmt", 1, 0, 'M'},
285 {"mgmtmode", 1, 0, MGMTMODEARG}
288 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
290 static void usage(void)
292 printf(
293 "(opts from consmgmt module)\n"
294 " -d, --daemon Daemonize vde_switch once run\n"
295 " -p, --pidfile PIDFILE Write pid of daemon to PIDFILE\n"
296 " -f, --rcfile Configuration file (overrides %s and ~/.vderc)\n"
297 " -M, --mgmt SOCK path of the management UNIX socket\n"
298 " --mgmtmode MODE management UNIX socket access mode (octal)\n"
299 ,STDRCFILE);
302 static int parseopt(int c, char *optarg)
304 int outc=0;
305 switch (c) {
306 case 'd':
307 daemonize=1;
308 break;
309 case 'p':
310 pidfile=strdup(optarg);
311 break;
312 case 'f':
313 rcfile=strdup(optarg);
314 break;
315 case 'M':
316 mgmt_socket=strdup(optarg);
317 break;
318 case MGMTMODEARG:
319 sscanf(optarg,"%o",&mgmt_mode);
320 break;
321 default:
322 outc=c;
324 return outc;
327 static void init(void)
329 if (daemonize) {
330 openlog(basename(prog), LOG_PID, 0);
331 logok=1;
332 syslog(LOG_INFO,"VDE_SWITCH started");
334 /* add stdin (if tty), connect and data fds to the set of fds we wait for
335 * * input */
336 if(isatty(0) && !daemonize)
338 console_type=add_type(&swmi,0);
339 add_fd(0,console_type,-1);
342 /* saves current path in pidfile_path, because otherwise with daemonize() we
343 * * forget it */
344 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
345 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
346 exit(1);
348 strcat(pidfile_path, "/");
349 if (daemonize && daemon(0, 1)) {
350 printlog(LOG_ERR,"daemon: %s",strerror(errno));
351 exit(1);
354 /* once here, we're sure we're the true process which will continue as a
355 * * server: save PID file if needed */
356 if(pidfile) save_pidfile();
358 if(mgmt_socket != NULL) {
359 int mgmtconnfd;
360 struct sockaddr_un sun;
361 int one = 1;
363 if((mgmtconnfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
364 printlog(LOG_ERR,"mgmt socket: %s",strerror(errno));
365 return;
367 if(setsockopt(mgmtconnfd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
368 sizeof(one)) < 0){
369 printlog(LOG_ERR,"mgmt setsockopt: %s",strerror(errno));
370 return;
372 if(fcntl(mgmtconnfd, F_SETFL, O_NONBLOCK) < 0){
373 printlog(LOG_ERR,"Setting O_NONBLOCK on mgmt fd: %s",strerror(errno));
374 return;
376 sun.sun_family = PF_UNIX;
377 snprintf(sun.sun_path,UNIX_PATH_MAX,"%s",mgmt_socket);
378 if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
379 if((errno == EADDRINUSE) && still_used(&sun)) return;
380 else if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
381 printlog(LOG_ERR,"mgmt bind %s",strerror(errno));
382 return;
385 chmod(sun.sun_path,mgmt_mode);
386 if(listen(mgmtconnfd, 15) < 0){
387 printlog(LOG_ERR,"mgmt listen: %s",strerror(errno));
388 return;
390 mgmt_ctl=add_type(&swmi,0);
391 mgmt_data=add_type(&swmi,0);
392 add_fd(mgmtconnfd,mgmt_ctl,-1);
396 static int vde_logout()
398 return -1;
401 static int vde_shutdown()
403 printlog(LOG_WARNING,"Shutdown from mgmt command");
404 return -2;
407 static int showinfo(int fd)
409 printoutc(fd,header,PACKAGE_VERSION);
410 printoutc(fd,"pid %d MAC %02x:%02x:%02x:%02x:%02x:%02x uptime %d",getpid(),
411 switchmac[0], switchmac[1], switchmac[2], switchmac[3], switchmac[4], switchmac[5],
412 qtime());
413 if (mgmt_socket)
414 printoutc(fd,"mgmt %s perm 0%03o",mgmt_socket,mgmt_mode);
415 return 0;
418 static struct comlist cl[]={
419 {"help","[arg]","Help (limited to arg when specified)",help,STRARG | WITHFD},
420 {"logout","","logout from this mgmt terminal",vde_logout,NOARG},
421 {"shutdown","","shutdown of the switch",vde_shutdown,NOARG},
422 {"showinfo","","show switch version and info",showinfo,NOARG|WITHFD},
423 {"load","path","load a configuration script",runscript,STRARG|WITHFD},
426 void start_consmgmt(void)
428 swmi.swmname="console-mgmt";
429 swmi.swmnopts=Nlong_options;
430 swmi.swmopts=long_options;
431 swmi.usage=usage;
432 swmi.parseopt=parseopt;
433 swmi.init=init;
434 swmi.handle_input=handle_input;
435 swmi.cleanup=cleanup;
436 ADDCL(cl);
437 add_swm(&swmi);