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