1 /* $Id: cmd.c,v 1.35 2002/06/20 01:52:48 bsd Exp $ */
2 
3 /*
4  * Copyright 2000, 2001, 2002 Brian S. Dean <bsd@bsdhome.com>
5  * All Rights Reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
23  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28  * DAMAGE.
29  *
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <limits.h>
38 #include <fcntl.h>
39 #include <sys/stat.h>
40 #include <errno.h>
41 
42 #include "cmd.h"
43 #include "comserv.h"
44 #include "log.h"
45 
46 
47 extern char prog_img[];
48 extern char ** prog_argv;
49 extern char module_timestamp[];
50 
51 
52 char * cmd_versionid = "$Id: cmd.c,v 1.35 2002/06/20 01:52:48 bsd Exp $";
53 
54 
55 /*
56  * valid commands accepted on the command port
57  */
58 COMMAND commands[] = {
59   { "?",         cmd_help,      "print command list" },
60   { "help",      cmd_help,      "print command list" },
61   { "add",       cmd_add,       "add device id" },
62   { "ctl",       cmd_ctl,       "add control device id" },
63   { "devdir",    cmd_devdir,  "specify default directory for device entries" },
64   { "endpoints", cmd_endpoints, "show local and remote connections" },
65   { "list",      cmd_list,      "list device ids" },
66   { "logdir",    cmd_logdir,    "specify the default log directory" },
67   { "quit",      cmd_close,     "close the command connection" },
68   { "restart",   cmd_restart,   "restart daemon" },
69   { "serve",     cmd_serve,     "add a local service" },
70   { "set",       cmd_set,       "set parameters" },
71   { "show",      cmd_show,      "show parameters" },
72   { "shutdown",  cmd_shutdown,  "shutdown the daemon" },
73   { "status",    cmd_status,    "print daemon status" },
74   { "version",   cmd_version,   "print version timestamp" }
75 };
76 #define N_COMMANDS (sizeof(commands)/sizeof(commands[0]))
77 
78 
79 char cmd_logdir_buf[PATH_MAX];
80 
81 char cmd_devdir_buf[PATH_MAX];
82 
83 
84 
cmd_init(void)85 int cmd_init(void)
86 {
87   strcpy(cmd_logdir_buf, DEFAULT_LOGDIR);
88   strcpy(cmd_devdir_buf, DEFAULT_DEVDIR);
89 
90   return 0;
91 }
92 
93 
new_cmd(void)94 COMMAND_PORT * new_cmd(void)
95 {
96   COMMAND_PORT * c;
97 
98   c = (COMMAND_PORT *) malloc(sizeof(COMMAND_PORT));
99   if (c == NULL) {
100     msgout("out of memory allocating command structure\n");
101     exit(1);
102   }
103 
104   bzero(c,sizeof(*c));
105 
106   return c;
107 }
108 
109 
110 
find_cmd(char * cmd)111 COMMAND * find_cmd(char * cmd)
112 {
113   int i;
114 
115   /*
116    * find the command in the command table
117    */
118   for (i=0; i<N_COMMANDS; i++) {
119     if (strcmp(cmd,commands[i].command)==0) {
120       return &commands[i];
121     }
122   }
123 
124   return NULL;
125 }
126 
127 
128 
129 
locate_devid(char * d)130 COMSERV_PORT * locate_devid(char * d)
131 {
132   COMSERV_PORT * xp;
133 
134   for (xp = comserv_ports; xp; xp = xp->next) {
135     if (strcmp(xp->devid,d)==0)
136       return xp;
137   }
138 
139   return NULL;
140 }
141 
142 
143 
run_command(ENDPOINT * e)144 int run_command(ENDPOINT * e)
145 {
146   char * p;
147   char cmd[MAX_CMD];
148   int i;
149   COMMAND * c;
150 
151   p = e->command->buf;
152   while (*p && isspace(*p))
153     p++;
154 
155   if (!*p)
156     return 0;
157 
158   if (*p == '#')
159     return 0;
160 
161   i = 0;
162   while (*p && (i < 64) && !(isspace(*p))) {
163     cmd[i++] = *p++;
164   }
165   if (i == 64) {
166     fdprintf(e->fd, "command too long\n");
167     return -1;
168   }
169   cmd[i] = 0;
170 
171   while (*p && isspace(*p))
172     p++;
173 
174   c = find_cmd(cmd);
175   if (c == NULL) {
176     fdprintf(e->fd, "command \"%s\" not found\n", cmd);
177     return -2;
178   }
179 
180   if (DEBUG_CMDS())
181     msgout("exec(\"%s\",\"%s\")\n", cmd, p);
182 
183   c->function(e, p);
184 
185   return 0;
186 }
187 
188 
debugstr(unsigned int flags,char * buf)189 char * debugstr(unsigned int flags, char * buf)
190 {
191   static char sbuf[128];
192   char * b;
193   int len;
194 
195   if (!buf)
196     b = sbuf;
197   else
198     b = buf;
199 
200   b[0] = 0;
201 
202   if (flags & D_BUFFER)
203     strcat(b, "buffer, ");
204   else
205     strcat(b, "no buffer, ");
206 
207   if (flags & D_STATES)
208     strcat(b, "states, ");
209   else
210     strcat(b, "no states, ");
211 
212   if (flags & D_CONNECT)
213     strcat(b, "connect, ");
214   else
215     strcat(b, "no connect, ");
216 
217   if (flags & D_CMDS)
218     strcat(b, "cmds, ");
219   else
220     strcat(b, "no cmds, ");
221 
222   len = strlen(b);
223   if (len >=2 && (b[len-1] == ' ') && (b[len-2] == ','))
224     b[len-2] = 0;
225 
226   return b;
227 }
228 
229 
230 #define DBG_CHK(str, flag)    \
231   if (strcmp(b, str) == 0) {  \
232     match = 1;                \
233     if (neg) {                \
234       debug_flags &= ~flag;   \
235     }                         \
236     else {                    \
237       debug_flags |= flag;    \
238     }                         \
239   }
240 
241 
set_debug(ENDPOINT * e,COMSERV_PORT * xp,char * value)242 int set_debug(ENDPOINT * e, COMSERV_PORT * xp, char * value)
243 {
244   char buf[MAX_SET];
245   char * p, * b;
246   int i;
247   int neg;
248   int match;
249 
250   p = value;
251 
252   if (!*p) {
253     fdprintf(e->fd, "debug flags = %s\n",
254              debugstr(debug_flags, NULL));
255     return 0;
256   }
257 
258   while (*p) {
259 
260     while (*p && (isspace(*p) || (*p == ',')))
261       p++;
262 
263     i = 0;
264     while (*p && (i<sizeof(buf)) && !(isspace(*p) || (*p == ',')))
265       buf[i++] = *p++;
266 
267     if (i == sizeof(buf)) {
268       buf[i-1] = 0;
269       fdprintf(e->fd, "debugging flag \"%s\" is too long\n", buf);
270       return -1;
271     }
272 
273     buf[i] = 0;
274 
275     neg = 0;
276     b = buf;
277     if (strncmp(b, "no", 2) == 0) {
278       neg = 1;
279       b += 2;
280     }
281 
282     match = 0;
283 
284     DBG_CHK("buffer", D_BUFFER);
285     DBG_CHK("states", D_STATES);
286     DBG_CHK("connect", D_CONNECT);
287     DBG_CHK("cmds", D_CMDS);
288 
289     if (!match)
290       fdprintf(e->fd, "unrecognized debugging flag \"%s\"\n", b);
291 
292   }
293 
294   return 0;
295 }
296 
297 
298 
cmd_debug(ENDPOINT * e,char * cmdline)299 int cmd_debug(ENDPOINT * e, char * cmdline)
300 {
301   set_debug(e, NULL, cmdline);
302   return 0;
303 }
304 
305 
306 
cmd_endpoints(ENDPOINT * e,char * cmdline)307 int cmd_endpoints(ENDPOINT * e, char * cmdline)
308 {
309   int i;
310 
311   for (i=0; i<max_endpoint; i++) {
312     if (endpoint[i]) {
313       if (endpoint[i]->fd != -1) {
314         fdprintf(e->fd, "fd:[%03d] ", i);
315 #ifdef ENABLE_TELNET_PORT
316         if (i == lsock) {
317           fdprintf(e->fd, "INCOMING TELNET CONNECTIONS\n");
318         }
319         else
320 #endif
321           if (endpoint[i]->comserv) {
322             if (endpoint[i]->comserv->control) {
323               fdprintf(e->fd, "%-23s -> ", "CONTROL");
324             }
325             else {
326               fdprintf(e->fd, "%-15s Port %02d -> ",
327                        endpoint[i]->comserv->host,
328                        endpoint[i]->comserv->serport);
329             }
330             fdprintf(e->fd, "%s", endpoint[i]->comserv->localpath);
331             if (endpoint[i]->comserv->le &&
332                 (i == endpoint[i]->comserv->le->fd)) {
333               fdprintf(e->fd, " (L)");
334             }
335             else if (endpoint[i]->comserv->re &&
336                      (i == endpoint[i]->comserv->re->fd)) {
337               fdprintf(e->fd, " (R)");
338             }
339             else if (endpoint[i]->comserv->listen &&
340                      (i == endpoint[i]->comserv->listen->fd)) {
341               fdprintf(e->fd, " (LISTEN)");
342             }
343             fdprintf(e->fd, "\n");
344           }
345           else if (endpoint[i]->command) {
346             fdprintf(e->fd, "COMMAND: %s", endpoint[i]->command->name);
347             if (i == e->fd) {
348               fdprintf(e->fd, " (this is you)\n");
349             }
350             else {
351               fdprintf(e->fd, "\n");
352             }
353           }
354       }
355     }
356   }  /* for */
357 
358   return 0;
359 }
360 
361 
362 
cmd_close(ENDPOINT * e,char * cmdline)363 int cmd_close(ENDPOINT * e, char * cmdline)
364 {
365   msgout("%s is exiting command mode\n",
366          endpoint[e->fd]->command->name);
367 
368   fdprintf(e->fd, "goodbye\n");
369   CLEANUP(endpoint[e->fd]);
370 
371   return 0;
372 }
373 
374 
375 
cmd_help(ENDPOINT * e,char * cmdline)376 int cmd_help(ENDPOINT * e, char * cmdline)
377 {
378   int j;
379 
380   fdprintf(e->fd, "\nvalid commands:\n");
381   for (j=0; j<N_COMMANDS; j++) {
382     fdprintf(e->fd, "  %-15s - %s\n",
383              commands[j].command, commands[j].desc);
384   }
385   fdprintf(e->fd, "\n");
386 
387   return 0;
388 }
389 
390 
391 
cmd_shutdown(ENDPOINT * e,char * cmdline)392 int cmd_shutdown(ENDPOINT * e, char * cmdline)
393 {
394   int j;
395 
396   msgout("shutting down\n");
397 
398   for (j=0; j<FD_SETSIZE; j++) {
399     if (ISENABLED_RD(j) || ISENABLED_WR(j)) {
400       if (endpoint[j]->state == ST_CMDINPUT) {
401         fdprintf(j, "shutting down, goodbye\n");
402       }
403       CLEANUP(endpoint[j]);
404     }
405   }
406 
407   exit(0);
408 }
409 
410 
get_int(int fd,char * b,int * v)411 int get_int(int fd, char * b, int * v)
412 {
413   int iv;
414   char * ep, * q;
415 
416   iv = strtol(b, &ep, 0);
417   if ((ep == b) || !((*ep == 0)||isspace(*ep)||(*ep == ','))) {
418     fdprintf(fd, "invalid numeric escape code \"");
419     q = b;
420     while (*q && !(isspace(*ep)||(*ep == ','))) {
421       fdprintf(fd, "%c", *q);
422       q++;
423     }
424     fdprintf(fd, "\"\n");
425     return -1;
426   }
427 
428   *v = iv;
429   return 0;
430 }
431 
432 
433 
set_options(ENDPOINT * e,COMSERV_PORT * xp,char * opts)434 int set_options(ENDPOINT * e, COMSERV_PORT * xp, char * opts)
435 {
436   char * p;
437   char buf[MAX_CMD];
438   int i;
439 
440   p = opts;
441   while (*p) {
442     i = 0;
443     while (*p && (i < MAX_CMD) && !((*p == ',') || isspace(*p)))
444       buf[i++] = *p++;
445 
446     if (i == MAX_CMD) {
447       buf[i-1] = 0;
448       fdprintf(e->fd, "option name \"%s\" too long\n", buf);
449       return -1;
450     }
451 
452     buf[i] = 0;
453 
454     if (strcmp(buf,"wait")==0) {
455       if (xp) {
456         xp->flags |= OPT_WAIT;
457       }
458     }
459     else if (strcmp(buf,"nowait")==0) {
460       if (xp) {
461         xp->flags &= ~OPT_WAIT;
462       }
463     }
464     else if (strcmp(buf,"logall")==0) {
465       if (xp) {
466         xp->flags |= OPT_LOGALL;
467       }
468     }
469     else if (strcmp(buf,"nologall")==0) {
470       if (xp) {
471         xp->flags &= ~OPT_LOGALL;
472       }
473     }
474     else if (strcmp(buf,"loghex")==0) {
475       if (xp) {
476         xp->flags |= OPT_LOGHEX;
477       }
478     }
479     else if (strcmp(buf,"nologhex")==0) {
480       if (xp) {
481         xp->flags &= ~OPT_LOGHEX;
482       }
483     }
484     else if (strcmp(buf,"block")==0) {
485       if (xp) {
486         xp->flags |= OPT_BLOCK;
487       }
488     }
489     else if (strcmp(buf,"noblock")==0) {
490       if (xp) {
491         xp->flags &= ~OPT_BLOCK;
492         if (xp->re) {
493           /*
494            * this option must take effect immediately, so handle that
495            * here
496            */
497           if (!ISENABLED_RD(xp->re->fd)) {
498             if (DEBUG_BUFFER())
499               msgout("device \"%s\", option \"nobuffer\" set, "
500                      "enabling %s.rd\n",
501                      xp->devid, whichside(xp->re->state));
502             ENABLE_RD(xp->re->fd);
503             if (xp->re->bufcnt) {
504               xp->re->bufcnt = 0;
505               xp->re->bufptr = xp->re->buf;
506             }
507           }
508         }
509       }
510     }
511     else {
512       fdprintf(e->fd, "WARNING: device \"%s\", unrecognized option \"%s\"\n",
513                xp ? xp->devid : "global", buf);
514     }
515 
516     while (*p && isspace(*p))
517       p++;
518 
519     if (*p == ',') {
520       p++;
521     }
522 
523     while (*p && isspace(*p))
524       p++;
525 
526   }
527 
528   return 0;
529 }
530 
531 
cmd_restart(ENDPOINT * e,char * cmdline)532 int cmd_restart(ENDPOINT * e, char * cmdline)
533 {
534   int rc;
535   int i;
536 
537   if (prog_img[0] == 0) {
538     if (e)
539       fdprintf(e->fd, "can't determine my image file, can't restart\n");
540     else
541       msgout("can't determine my image file, can't restart\n");
542     return -1;
543   }
544 
545   msgout("restarting %s ...\n", prog_img);
546 
547   for (i=0; i<FD_SETSIZE; i++) {
548     close(i);
549   }
550 
551   prog_argv[0] = prog_img;
552   rc = execv(prog_img, prog_argv);
553 
554   msgout("can't re-exec \"%s\": %s\n", prog_img, strerror(errno));
555 
556   exit(1);
557 }
558 
559 
cmd_set(ENDPOINT * e,char * cmdline)560 int cmd_set(ENDPOINT * e, char * cmdline)
561 {
562   char buf[MAX_SET];
563   char * var;
564   char * value;
565   char * ep;
566   long ival;
567   char devid[MAX_DEVID];
568   char * p;
569   int i;
570   COMSERV_PORT * xp;
571 
572   i = 0;
573   p = cmdline;
574   while (*p && (i < MAX_DEVID) && !isspace(*p))
575     devid[i++] = *p++;
576   if (i == MAX_DEVID) {
577     devid[i-1] = 0;
578     fdprintf(e->fd, "devid \"%s\" is too long\n", devid);
579     return -1;
580   }
581   devid[i] = 0;
582 
583   if (strcmp(devid,"global") == 0) {
584     xp = &global;
585   }
586   else {
587     xp = locate_devid(devid);
588     if (xp == NULL) {
589       fdprintf(e->fd, "devid id \"%s\" not found, use \"add DeviceId ...\"\n",
590                devid);
591       return -2;
592     }
593   }
594 
595   while (*p && isspace(*p))
596     p++;
597 
598   buf[MAX_SET-1] = 0;
599   strncpy(buf,p,MAX_SET-1);
600   if (buf[MAX_SET-1] != 0) {
601     fdprintf(e->fd, "set: var=value text is too long\n");
602     return -1;
603   }
604 
605   var = buf;
606   p   = var;
607   while (*p && !((*p == '=') || isspace(*p)))
608     p++;
609 
610   if (isspace(*p)) {
611     *p = 0;
612     p++;
613   }
614 
615   while (*p && (*p != '='))
616     p++;
617 
618   if ((*p == 0) || (*p != '=')) {
619     fdprintf(e->fd, "expecting '='\n");
620     fdprintf(e->fd, "Usage: set DeviceId VAR=VALUE\n");
621   }
622 
623   *p = 0;
624   p++;
625 
626   while (*p && isspace(*p))
627     p++;
628 
629   if (*p == 0) {
630     fdprintf(e->fd, "expecting a value\n");
631     fdprintf(e->fd, "Usage: set DeviceId VAR=VALUE\n");
632   }
633 
634   value = p;
635 
636   if (strcmp(var,"verbose")==0) {
637     ival = strtol(value, &ep, 0);
638     if (*ep) {
639       fdprintf(e->fd, "set: couldn't parse %s value \"%s\"\n", var, value);
640       return -1;
641     }
642 
643     if (xp == &global) {
644       verbose = ival;
645     }
646 
647     return 0;
648   }
649   else if (strcmp(var,"options")==0) {
650     set_options(e, xp, value);
651     return 0;
652   }
653   else if (strcmp(var, "debug") == 0) {
654     set_debug(e, xp, value);
655     return 0;
656   }
657   else {
658     fdprintf(e->fd, "set: don't know about the \"%s\" variable\n", var);
659   }
660 
661   return -2;
662 }
663 
664 
665 
hexdump_line(char * buffer,unsigned char * p,int n,int pad)666 int hexdump_line(char * buffer, unsigned char * p, int n, int pad)
667 {
668   char * hexdata = "0123456789abcdef";
669   char * b;
670   int i, j;
671 
672   b = buffer;
673 
674   j = 0;
675   for (i=0; i<n; i++) {
676     if (i && ((i % 8) == 0))
677       b[j++] = ' ';
678     b[j++] = hexdata[(p[i] & 0xf0) >> 4];
679     b[j++] = hexdata[(p[i] & 0x0f)];
680     if (i < 15)
681       b[j++] = ' ';
682   }
683 
684   for (i=j; i<pad; i++)
685     b[i] = ' ';
686 
687   b[i] = 0;
688 
689   for (i=0; i<pad; i++) {
690     if (!((b[i] == '0') || (b[i] == ' ')))
691       return 0;
692   }
693 
694   return 1;
695 }
696 
697 
chardump_line(char * buffer,unsigned char * p,int n,int pad)698 int chardump_line(char * buffer, unsigned char * p, int n, int pad)
699 {
700   int i;
701   char b [ 128 ];
702 
703   for (i=0; i<n; i++) {
704     memcpy(b, p, n);
705     buffer[i] = '.';
706     if (isalpha(b[i]) || isdigit(b[i]) || ispunct(b[i]))
707       buffer[i] = b[i];
708     else if (isspace(b[i]))
709       buffer[i] = ' ';
710   }
711 
712   for (i=n; i<pad; i++)
713     buffer[i] = ' ';
714 
715   buffer[i] = 0;
716 
717   return 0;
718 }
719 
hexdump_buf(int fd,char * prefix,int startaddr,char * buf,int len)720 int hexdump_buf(int fd, char * prefix, int startaddr, char * buf, int len)
721 {
722   int addr;
723   int i, n;
724   unsigned char * p;
725   char dst1[80];
726   char dst2[80];
727 
728   addr = startaddr;
729   i = 0;
730   p = (unsigned char *)buf;
731   while (len) {
732     n = 16;
733     if (n > len)
734       n = len;
735     hexdump_line(dst1, p, n, 48);
736     chardump_line(dst2, p, n, 16);
737     fdprintf(fd, "%s%s  |%s|\n", prefix, dst1, dst2);
738     len -= n;
739     addr += n;
740     p += n;
741   }
742 
743   return 0;
744 }
745 
optionsstr(unsigned int flags,char * buf)746 char * optionsstr(unsigned int flags, char * buf)
747 {
748   static char sbuf[128];
749   char * b;
750   int len;
751 
752   if (!buf)
753     b = sbuf;
754   else
755     b = buf;
756 
757   b[0] = 0;
758 
759   if (flags & OPT_WAIT)
760     strcat(b, "wait, ");
761   else
762     strcat(b, "no wait, ");
763 
764   if (flags & OPT_LOGALL)
765     strcat(b, "logall, ");
766   else
767     strcat(b, "no logall, ");
768 
769   if (flags & OPT_LOGHEX)
770     strcat(b, "loghex, ");
771   else
772     strcat(b, "no loghex, ");
773 
774   if (flags & OPT_BLOCK)
775     strcat(b, "block, ");
776   else
777     strcat(b, "no block, ");
778 
779   len = strlen(b);
780   if (len >=2 && (b[len-1] == ' ') && (b[len-2] == ','))
781     b[len-2] = 0;
782 
783   return b;
784 }
785 
786 
show_devid(int fd,COMSERV_PORT * xp)787 int show_devid(int fd, COMSERV_PORT * xp)
788 {
789   int buflen;
790 
791   fdprintf(fd, "Device Id: %-8s\n", xp->devid);
792   fdprintf(fd, "  Local   : %s\n", xp->localpath);
793   fdprintf(fd, "  Remote  : %s %2d %5d\n", xp->host, xp->serport, xp->port);
794   fdprintf(fd, "  LogFile : %s\n",
795            xp->log ? xp->logfile : "N/A");
796   fdprintf(fd, "  Options : %s\n",
797            optionsstr(xp->flags, NULL));
798   fdprintf(fd, "  Data Tx : Local = %8d    Remote = %8d\n",
799            xp->n_le, xp->n_re);
800 
801   if (xp->le) {
802     buflen = xp->le->bufcnt;
803     if (buflen) {
804       fdprintf(fd, "  LBuffer : len=%d (contents below)\n", buflen);
805       hexdump_buf(fd, "  ", 0, xp->le->bufptr, buflen);
806     }
807     else {
808       fdprintf(fd, "  LBuffer : len=%d\n", buflen);
809     }
810   }
811 
812   if (xp->re) {
813     buflen = xp->re->bufcnt;
814     if (buflen) {
815       fdprintf(fd, "  RBuffer : len=%d (contents below)\n", buflen);
816       hexdump_buf(fd, "  ", 0, xp->re->bufptr, buflen);
817     }
818     else {
819       fdprintf(fd, "  RBuffer : len=%d\n", buflen);
820     }
821   }
822 
823   return 0;
824 }
825 
826 
827 
cmd_show(ENDPOINT * e,char * cmdline)828 int cmd_show(ENDPOINT * e, char * cmdline)
829 {
830   COMSERV_PORT * xp;
831 
832   if (strcmp(cmdline,"global")==0) {
833     fdprintf(e->fd,
834              "verbose     = %d\n"
835              "debug flags = %s\n",
836              verbose, debugstr(debug_flags, NULL));
837     show_devid(e->fd, &global);
838   }
839   else {
840     xp = locate_devid(cmdline);
841     if (xp == NULL) {
842       fdprintf(e->fd, "Device Id \"%s\" not found\n", cmdline);
843       return -1;
844     }
845 
846     show_devid(e->fd, xp);
847   }
848 
849   return 0;
850 }
851 
852 
853 
print_endpoint_status(int fd,ENDPOINT * e)854 int print_endpoint_status(int fd, ENDPOINT * e)
855 {
856   char * conn;
857 
858   if (e) {
859     if (e->state == ST_CONNECTING)
860       conn = "no";
861     else
862       conn = "yes";
863 
864     fdprintf(fd, "%4s ", conn);
865 
866     fdprintf(fd, "%3d ", e->fd);
867 
868     if (ISENABLED_RD(e->fd))
869       fdprintf(fd, " X ");
870     else
871       fdprintf(fd, "   ");
872 
873     if (ISENABLED_WR(e->fd))
874       fdprintf(fd, " X ");
875     else
876       fdprintf(fd, "   ");
877 
878     fdprintf(fd, "%4d ", e->bufcnt);
879   }
880   else {
881     fdprintf(fd, "%4s %15s", "no", " ");
882   }
883 
884   return 0;
885 }
886 
887 
888 
varw_field(char * b1,char * b2,char * b3,char * b4,int max,int wid,char * title,char * format)889 int varw_field(char * b1, char * b2, char * b3, char * b4, int max,
890                int wid, char * title, char * format)
891 {
892   int i;
893   int len;
894 
895   len = strlen(title);
896   if (wid < len)
897     wid = len;
898 
899   if (wid > (max-1))
900     wid = max-1;
901 
902 
903   for (i=0; i<wid; i++) {
904     b1[i] = ' ';
905     b3[i] = '-';
906   }
907   b1[i] = 0;
908   b3[i] = 0;
909 
910   strncpy(b2,title,max-1);
911   len = strlen(b2);
912   for (i=len; i<wid; i++)
913     b2[i] = ' ';
914   b2[i] = 0;
915 
916   snprintf(b4, max, "%%-%d%s", wid, format);
917 
918   return 0;
919 }
920 
921 
print_comserv_status(int fd,int devid_width,int host_width,int dev_width,COMSERV_PORT * xp,int dvdir)922 int print_comserv_status(int fd, int devid_width, int host_width,
923                          int dev_width, COMSERV_PORT * xp, int dvdir)
924 {
925   char id1[32], id2[32], id3[32], id4[8];
926   char dev1[64], dev2[64], dev3[64], dev4[8];
927   char h1[MAX_HOST], h2[MAX_HOST], h3[MAX_HOST], h4[8];
928   char * p;
929 
930   varw_field(id1, id2, id3, id4, sizeof(id1), devid_width, "Id", "s");
931   varw_field(dev1, dev2, dev3, dev4, sizeof(dev1), dev_width, "Device", "s");
932   varw_field(h1, h2, h3, h4, sizeof(h1), host_width, "Host", "s");
933 
934   if (xp == NULL) {
935     fdprintf(fd,
936              "%s %s Srl  TCP   %s Local Endpoint      Remote Endpoint\n"
937              "%s %s Port Port  %s Conn Fd  Rd Wr Data Conn Fd  Rd Wr Data\n"
938              "%s %s ---- ----- %s ---- --- -- -- ---- ---- --- -- -- ----\n",
939              id1, h1, dev1, id2, h2, dev2, id3, h3, dev3);
940     return 0;
941   }
942 
943   p = xp->localpath;
944   if (strncmp(cmd_devdir_buf, xp->localpath, dvdir) == 0) {
945     p = rindex(xp->localpath, '/');
946     if (p) {
947       p++;
948     }
949     else {
950       p = xp->localpath;
951     }
952   }
953 
954   snprintf(dev1, sizeof(dev1), dev4, p);
955   snprintf(id1, sizeof(id1), id4, xp->devid);
956   snprintf(h1, sizeof(h1), h4, xp->host);
957 
958   fdprintf(fd, "%s %s %4d %5d %s ",
959            id1, h1, xp->serport, xp->port, dev1);
960 
961   print_endpoint_status(fd, xp->le);
962   print_endpoint_status(fd, xp->re);
963 
964   fdprintf(fd, "\n");
965 
966   return 0;
967 }
968 
969 
970 
cmd_list(ENDPOINT * e,char * cmdline)971 int cmd_list(ENDPOINT * e, char * cmdline)
972 {
973   COMSERV_PORT * xp;
974 
975   xp = comserv_ports;
976   while (xp) {
977     fdprintf(e->fd, "%-15s %s %s\n",
978              xp->devid, xp->localpath,
979              xp->log ? xp->logfile : "<no-log>");
980     xp = xp->next;
981   }
982 
983   return 0;
984 }
985 
986 
987 
cmd_status(ENDPOINT * e,char * cmdline)988 int cmd_status(ENDPOINT * e, char * cmdline)
989 {
990   COMSERV_PORT * xp;
991   int dev_width, len, devid_width, host_width;
992   char * p;
993   int dvdir;
994 
995   fdprintf(e->fd,
996            "COMSERV revision timestamp %s\n"
997            "logdir = %s\n"
998            "devdir = %s\n",
999            module_timestamp, cmd_logdir_buf, cmd_devdir_buf);
1000 
1001   dvdir = strlen(cmd_devdir_buf);
1002   dev_width   = 0;
1003   devid_width = 0;
1004   host_width  = 0;
1005   xp = comserv_ports;
1006   while (xp) {
1007 
1008     if (strncmp(cmd_devdir_buf, xp->localpath, dvdir) == 0) {
1009       p = rindex(xp->localpath, '/');
1010       if (p) {
1011         p++;
1012         len = strlen(p);
1013       }
1014       else {
1015         len = strlen(xp->localpath);
1016       }
1017     }
1018     else {
1019       len = strlen(xp->localpath);
1020     }
1021     if (len > dev_width)
1022       dev_width = len;
1023 
1024     len = strlen(xp->devid);
1025     if (len > devid_width)
1026       devid_width = len;
1027 
1028     len = strlen(xp->host);
1029     if (len > host_width)
1030       host_width = len;
1031 
1032     xp = xp->next;
1033   }
1034 
1035   print_comserv_status(e->fd, devid_width, host_width, dev_width, NULL, dvdir);
1036 
1037   xp = comserv_ports;
1038   while (xp) {
1039     print_comserv_status(e->fd, devid_width, host_width, dev_width, xp, dvdir);
1040     xp = xp->next;
1041   }
1042 
1043   return 0;
1044 }
1045 
1046 
cmd_version(ENDPOINT * e,char * cmdline)1047 int cmd_version(ENDPOINT * e, char * cmdline)
1048 {
1049   fdprintf(e->fd, "revision timestamp = %s\n", module_timestamp);
1050   return 0;
1051 }
1052 
1053 
1054 
1055 
1056 
1057 
cmd_devdir(ENDPOINT * e,char * cmdline)1058 int cmd_devdir(ENDPOINT * e, char * cmdline)
1059 {
1060   char * p;
1061 
1062   p = cmdline;
1063   while (*p && isspace(*p))
1064     p++;
1065 
1066   if (*p) {
1067     strncpy(cmd_devdir_buf, cmdline, PATH_MAX);
1068     cmd_devdir_buf[PATH_MAX-1] = 0;
1069   }
1070 
1071   return 0;
1072 }
1073 
1074 
1075 
cmd_logdir(ENDPOINT * e,char * cmdline)1076 int cmd_logdir(ENDPOINT * e, char * cmdline)
1077 {
1078   char * p;
1079 
1080   p = cmdline;
1081   while (*p && isspace(*p))
1082     p++;
1083 
1084   if (*p) {
1085     strncpy(cmd_logdir_buf, p, PATH_MAX);
1086     cmd_logdir_buf[PATH_MAX-1] = 0;
1087   }
1088 
1089   return 0;
1090 }
1091 
1092 
1093 
cmd_add(ENDPOINT * e,char * cmdline)1094 int cmd_add(ENDPOINT * e, char * cmdline)
1095 {
1096   COMSERV_PORT * xp, * xp2;
1097   char devid [ 1024 ];
1098   char host  [ 1024 ];
1099   char localpath [ 1024 ];
1100   char logopt [ PATH_MAX ];
1101   int port;
1102   int serialport;
1103   int n;
1104 
1105   n = sscanf(cmdline, "%s %s %s %d %d %s",
1106              devid, localpath, host, &serialport, &port, logopt);
1107   if (n != 6) {
1108     fdprintf(e->fd,
1109              "invalid number of parameters (%d) to the 'add' command\n", n);
1110     fdprintf(e->fd, "Usage: add DevId LocalDev Host Port TCPPort LogOption\n");
1111     return -1;
1112   }
1113 
1114   xp2 = locate_devid(devid);
1115   if (xp2 != NULL) {
1116     fdprintf(e->fd,"Device Id \"%s\" already present\n", devid);
1117     return 0;
1118   }
1119 
1120   xp = new_comserv_port();
1121   strncpy(xp->devid, devid, MAX_DEVID-1);
1122   strncpy(xp->host, host, MAX_HOST-1);
1123   xp->serport = serialport;
1124   xp->port    = port;
1125   xp->logfd   = -1;
1126   xp->reconnect_time_incr = 1;
1127   xp->reconnect_time = time(NULL) + xp->reconnect_time_incr;
1128 
1129   /* default options flags */
1130   xp->flags = global.flags;
1131   xp->rflags = 0;
1132 
1133   if (localpath[0] == '/') {
1134     xp->localpath[0] = 0;
1135   }
1136   else {
1137     strcpy(xp->localpath, cmd_devdir_buf);
1138     strcat(xp->localpath, "/");
1139   }
1140   strncat(xp->localpath, localpath, PATH_MAX-1);
1141 
1142   if (strcasecmp(logopt, "log")==0) {
1143     xp->log = 1;
1144     strcpy(xp->logfile, cmd_logdir_buf);
1145     strcat(xp->logfile, "/");
1146     strcat(xp->logfile, xp->devid);
1147   }
1148   else if (strcasecmp(logopt, "nolog")==0) {
1149     xp->log = 0;
1150     xp->logfile[0] = 0;
1151   }
1152   else if (logopt[0] != '/') {
1153     xp->log = 1;
1154     strcpy(xp->logfile, cmd_logdir_buf);
1155     strcat(xp->logfile, "/");
1156     strcat(xp->logfile, logopt);
1157   }
1158   else {
1159     xp->log = 1;
1160     strcpy(xp->logfile, logopt);
1161   }
1162 
1163 
1164   if (!comserv_ports) {
1165     comserv_ports = xp;
1166   }
1167   else {
1168     for (xp2=comserv_ports; xp2->next; xp2 = xp2->next)
1169       ;
1170     xp2->next = xp;
1171   }
1172 
1173   /*
1174    * configure the newly added device id
1175    */
1176 
1177   if (verbose >= 1) {
1178     fdprintf(e->fd, "configuring device id \"%s\"\n", xp->devid);
1179   }
1180 
1181   /*
1182    * Open the log file if requested
1183    */
1184   if (xp->log) {
1185     mode_t mode;
1186     mode = S_IRUSR|S_IWUSR|S_IRGRP;
1187     xp->logfd = open(xp->logfile, O_CREAT|O_WRONLY|O_APPEND, mode);
1188     if (xp->logfd < 0) {
1189       fdprintf(e->fd,
1190                "failed to open log file \"%s\": %s; "
1191                "logging on this port disabled\n",
1192                xp->logfile, strerror(errno));
1193       xp->log = 0;
1194       xp->logfd = -1;
1195     }
1196   }
1197 
1198   if (verbose >= 1) {
1199     fdprintf(e->fd, "%s -> %s:%d, L[%d]<-->R[%d] logs->%s\n",
1200              xp->localpath,
1201              xp->host, xp->port,
1202              xp->le  ? xp->le->fd : -1,
1203              xp->re ? xp->re->fd : -1,
1204              xp->log ? xp->logfile : "<none>");
1205   }
1206 
1207   return 0;
1208 }
1209 
1210 
1211 /*
1212  *
1213  * serve devid /dev/cuaa0 1 2100 log
1214  */
1215 
1216 
cmd_serve(ENDPOINT * e,char * cmdline)1217 int cmd_serve(ENDPOINT * e, char * cmdline)
1218 {
1219   COMSERV_PORT * xp, * xp2;
1220   char devid [ 1024 ];
1221   char localpath [ 1024 ];
1222   char logopt [ PATH_MAX ];
1223   int port;
1224   int serialport;
1225   int n;
1226   int sock;
1227 
1228   n = sscanf(cmdline, "%s %s %d %d %s",
1229              devid, localpath, &serialport, &port, logopt);
1230   if (n != 5) {
1231     fdprintf(e->fd,
1232              "invalid number of parameters (%d) to the 'serve' command\n", n);
1233     fdprintf(e->fd, "Usage: serve DevId LocalDev TCPPort LogOption\n");
1234     return -1;
1235   }
1236 
1237   xp2 = locate_devid(devid);
1238   if (xp2 != NULL) {
1239     fdprintf(e->fd,"Device Id \"%s\" already present\n", devid);
1240     return 0;
1241   }
1242 
1243   xp = new_comserv_port();
1244   strncpy(xp->devid, devid, MAX_DEVID-1);
1245   strncpy(xp->host, "localhost", MAX_HOST-1);
1246   xp->serport = serialport;
1247   xp->port    = port;
1248   xp->logfd   = -1;
1249 
1250   /* default options flags */
1251   xp->flags = global.flags;
1252   xp->rflags = RFLAG_LISTEN;
1253 
1254   if (localpath[0] == '/') {
1255     xp->localpath[0] = 0;
1256   }
1257   else {
1258     strcpy(xp->localpath, cmd_devdir_buf);
1259     strcat(xp->localpath, "/");
1260   }
1261   strncat(xp->localpath, localpath, PATH_MAX-1);
1262 
1263   if (strcasecmp(logopt, "log")==0) {
1264     xp->log = 1;
1265     strcpy(xp->logfile, cmd_logdir_buf);
1266     strcat(xp->logfile, "/");
1267     strcat(xp->logfile, xp->devid);
1268   }
1269   else if (strcasecmp(logopt, "nolog")==0) {
1270     xp->log = 0;
1271     xp->logfile[0] = 0;
1272   }
1273   else if (logopt[0] != '/') {
1274     xp->log = 1;
1275     strcpy(xp->logfile, cmd_logdir_buf);
1276     strcat(xp->logfile, "/");
1277     strcat(xp->logfile, logopt);
1278   }
1279   else {
1280     xp->log = 1;
1281     strcpy(xp->logfile, logopt);
1282   }
1283 
1284 
1285   /*
1286    * configure the newly added device id
1287    */
1288 
1289   if (verbose >= 1) {
1290     fdprintf(e->fd, "configuring device id \"%s\"\n", xp->devid);
1291   }
1292 
1293   sock = sock_bind_service(NULL, xp->port);
1294   if (sock < 0) {
1295     if (sock == -1) {
1296       msgout("can't establish service for \"%s\" port %d\n",
1297              xp->devid, xp->port);
1298     }
1299     else {
1300       msgout("failed to establish service for \"%s\" port %d\n",
1301              xp->devid, xp->port);
1302     }
1303     free_comserv_port(xp);
1304     return -1;
1305   }
1306 
1307   /*
1308    * add this device node to the list
1309    */
1310   if (!comserv_ports) {
1311     comserv_ports = xp;
1312   }
1313   else {
1314     for (xp2=comserv_ports; xp2->next; xp2 = xp2->next)
1315       ;
1316     xp2->next = xp;
1317   }
1318 
1319   if (endpoint[sock] == NULL)
1320     endpoint[sock] = new_endp();
1321   init_endp(endpoint[sock]);
1322   endpoint[sock]->state   = ST_SERVICE;
1323   endpoint[sock]->fd      = sock;
1324   endpoint[sock]->command = NULL;
1325   endpoint[sock]->comserv = xp;
1326   ENABLE_RD(sock);
1327   maxfd = max(maxfd,sock);
1328   xp->listen = endpoint[sock];
1329 
1330 
1331   /*
1332    * Open the log file if requested
1333    */
1334   if (xp->log) {
1335     mode_t mode;
1336     mode = S_IRUSR|S_IWUSR|S_IRGRP;
1337     xp->logfd = open(xp->logfile, O_CREAT|O_WRONLY|O_APPEND, mode);
1338     if (xp->logfd < 0) {
1339       fdprintf(e->fd,
1340                "failed to open log file \"%s\": %s; "
1341                "logging on this port disabled\n",
1342                xp->logfile, strerror(errno));
1343       xp->log = 0;
1344       xp->logfd = -1;
1345     }
1346   }
1347 
1348   if (verbose >= 1) {
1349     fdprintf(e->fd, "%s -> %s:%d, L[%d]<-->R[%d] logs->%s\n",
1350              xp->localpath,
1351              xp->host, xp->port,
1352              xp->le  ? xp->le->fd : -1,
1353              xp->re ? xp->re->fd : -1,
1354              xp->log ? xp->logfile : "<none>");
1355   }
1356 
1357   return 0;
1358 }
1359 
1360 
1361 
cmd_ctl(ENDPOINT * e,char * cmdline)1362 int cmd_ctl(ENDPOINT * e, char * cmdline)
1363 {
1364   COMSERV_PORT * xp, * xp2;
1365   char devid [ 1024 ];
1366   char localpath [ 1024 ];
1367   int n;
1368   int xfd;
1369 
1370   n = sscanf(cmdline, "%s %s",
1371              devid, localpath);
1372   if (n != 2) {
1373     fdprintf(e->fd,
1374              "invalid number of parameters (%d) to the 'ctl' command\n",
1375              n);
1376     fdprintf(e->fd, "Usage: ctl DevId LocalDev\n");
1377     return -1;
1378   }
1379 
1380   xp2 = locate_devid(devid);
1381   if (xp2 != NULL) {
1382     fdprintf(e->fd, "Device Id \"%s\" already present\n", devid);
1383     return 0;
1384   }
1385 
1386   xp = new_comserv_port();
1387   strncpy(xp->devid, devid, MAX_DEVID-1);
1388   xp->host[0] = 0;
1389   xp->serport = 0;
1390   xp->port    = 0;
1391   xp->flags   = OPT_WAIT;
1392   xp->control = 1;  /* identify this as a control port */
1393 
1394   if (localpath[0] == '/') {
1395     xp->localpath[0] = 0;
1396   }
1397   else {
1398     strcpy(xp->localpath, cmd_devdir_buf);
1399     strcat(xp->localpath, "/");
1400   }
1401   strncat(xp->localpath, localpath, PATH_MAX-1);
1402 
1403   /*
1404    * add the control port to the list of device ids
1405    */
1406   if (!comserv_ports) {
1407     comserv_ports = xp;
1408   }
1409   else {
1410     for (xp2=comserv_ports; xp2->next; xp2 = xp2->next)
1411       ;
1412     xp2->next = xp;
1413   }
1414 
1415   /*
1416    * configure the newly added device id
1417    */
1418 
1419   if (verbose >= 1) {
1420     fdprintf(e->fd, "configuring device id \"%s\"\n",
1421              xp->devid);
1422   }
1423 
1424   /*
1425    * connect_user() will do the rest
1426    */
1427   xfd = connect_user(xp, 0);
1428   if (xfd < 0) {
1429     fdprintf(e->fd, "failed to initialize control connection\n");
1430     exit(1);
1431   }
1432 
1433   if (isatty(xp->le->fd)) {
1434     fdprintf(xp->le->fd, "\nwelcome, %s\n",
1435              xp->le->command->name);
1436     fdprintf(xp->le->fd, "%s", xp->le->command->prompt);
1437   }
1438 
1439   if (verbose >= 1) {
1440     msgout("%s -> control, L[%d]<-->control\n",
1441            xp->localpath,
1442            xp->le  ? xp->le->fd : -1);
1443   }
1444 
1445   return 0;
1446 }
1447 
1448 
1449