1 /*
2 * ser2net - A program for allowing telnet connection to serial ports
3 * Copyright (C) 2001 Corey Minyard <minyard@acm.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /* This file holds the code that reads the configuration file and
21 calls the code in dataxfer to actually create all the ports in the
22 configuration file. */
23
24 #include <stdlib.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <stdio.h>
29 #include <syslog.h>
30 #include <stdarg.h>
31 #include <limits.h>
32
33 #include "dataxfer.h"
34 #include "readconfig.h"
35 #include "utils.h"
36 #include "telnet.h"
37 #include "led.h"
38
39 #ifdef HAVE_OPENIPMI
40 #include <OpenIPMI/ipmi_conn.h>
41 #include <OpenIPMI/ipmi_sol.h>
42 #endif
43
44 #define PORT_BUFSIZE 64 /* Default data transfer buffer size */
45
46 extern char *config_port;
47
48 static int config_num = 0;
49
50 static int lineno = 0;
51
52 struct longstr_s
53 {
54 char *name;
55 char *str;
56 unsigned int length;
57 enum str_type type;
58 struct longstr_s *next;
59 };
60
61 /* All the strings in the system. */
62 struct longstr_s *longstrs = NULL;
63
isoctdigit(char c)64 static int isoctdigit(char c)
65 {
66 return ((c >= '0') && (c <= '7'));
67 }
68
69 /* Assumes the value is pre-checked */
hexchar_to_val(char c)70 static int hexchar_to_val(char c)
71 {
72 if ((c >= '0') && (c <= '9'))
73 return c - '0';
74 if (isupper(c))
75 return c - 'A' + 10;
76 return c - 'a' + 10;
77 }
78
79 /*
80 * Convert \004 and other ESC sequences in place, inspired from
81 * http://stackoverflow.com/questions/17015970/how-does-c-compiler-convert-escape-sequence-to-actual-bytes
82 */
83 static void
translateescapes(char * string,unsigned int * outlen,char ** err,char ** errpos)84 translateescapes(char *string, unsigned int *outlen,
85 char **err, char **errpos)
86 {
87 char *ip = string, *op = string;
88 unsigned int cleft = strlen(string);
89 unsigned int iplen;
90
91 *err = NULL;
92 while (*ip) {
93 cleft--;
94 if (*ip != '\\') {
95 *op++ = *ip++;
96 continue;
97 }
98
99 if (cleft == 0)
100 goto out_str_in_bslash;
101
102 iplen = 2;
103 switch (ip[1]) {
104 case '\\': *op = '\\'; break;
105 case 'r': *op = '\r'; break;
106 case 'n': *op = '\n'; break;
107 case 't': *op = '\t'; break;
108 case 'v': *op = '\v'; break;
109 case 'a': *op = '\a'; break;
110 case '0': case '1': case '2': case '3':
111 case '4': case '5': case '6': case '7':
112 if (cleft < 3)
113 goto out_str_in_bslash;
114 if (!isoctdigit(ip[2]) || !isoctdigit(ip[3])) {
115 *err = "Invalid octal sequence";
116 *errpos = ip - 1;
117 }
118 iplen = 4;
119 *op = (ip[1] -'0') * 64 + (ip[2] - '0') * 8 + (ip[3] - '0');
120 break;
121 case 'x':
122 if (cleft < 3)
123 goto out_str_in_bslash;
124 if (!isxdigit(ip[2]) || !isxdigit(ip[3])) {
125 *err = "Invalid octal sequence";
126 *errpos = ip - 1;
127 }
128 iplen = 4;
129 *op = 16 * hexchar_to_val(ip[2]) + hexchar_to_val(ip[3]);
130 break;
131 default:
132 *err = "Unknown escape sequence";
133 *errpos = ip - 1;
134 return;
135 }
136
137 ip += iplen;
138 cleft -= iplen;
139 op++;
140 }
141
142 *outlen = op - string;
143 *op = '\0';
144 return;
145
146 out_str_in_bslash:
147 *err = "end of string right after a \\";
148 *errpos = "";
149 }
150
151 /* Parse the incoming string, it may be on multiple lines. */
152 static void
handle_longstr(const char * name,const char * line,enum str_type type)153 handle_longstr(const char *name, const char *line, enum str_type type)
154 {
155 struct longstr_s *longstr;
156
157 /* If the user gave an empty string, we get a NULL. */
158 if (!line)
159 line = "";
160
161 longstr = malloc(sizeof(*longstr));
162 if (!longstr) {
163 syslog(LOG_ERR, "Out of memory handling string on %d", lineno);
164 return;
165 }
166 memset(longstr, 0, sizeof(*longstr));
167 longstr->type = type;
168
169 longstr->name = strdup(name);
170 if (!longstr->name) {
171 syslog(LOG_ERR, "Out of memory handling longstr on %d", lineno);
172 goto out_err;
173 }
174
175 longstr->str = strdup(line);
176 if (!longstr->str) {
177 syslog(LOG_ERR, "Out of memory handling longstr on %d", lineno);
178 goto out_err;
179 }
180
181 longstr->length = strlen(line);
182
183 if (longstr->type == CLOSEON) {
184 char *err = NULL, *errpos = NULL;
185
186 translateescapes(longstr->str, &longstr->length,
187 &err, &errpos);
188 if (err) {
189 syslog(LOG_ERR, "%s (starting at %s) on line %d", err, errpos,
190 lineno);
191 goto out_err;
192 }
193 }
194
195 longstr->next = longstrs;
196 longstrs = longstr;
197 return;
198
199 out_err:
200 if (longstr->name)
201 free(longstr->name);
202 if (longstr->str)
203 free(longstr->str);
204 free(longstr);
205 return;
206 }
207
208 char *
find_str(const char * name,enum str_type * type,unsigned int * len)209 find_str(const char *name, enum str_type *type, unsigned int *len)
210 {
211 struct longstr_s *longstr = longstrs;
212
213 while (longstr) {
214 if (strcmp(name, longstr->name) == 0) {
215 char *rv;
216
217 /* Note that longstrs can contain \0, so be careful in handling */
218 if (type)
219 *type = longstr->type;
220 if (len)
221 *len = longstr->length;
222 rv = malloc(longstr->length + 1);
223 if (!rv)
224 return NULL;
225 memcpy(rv, longstr->str, longstr->length + 1);
226 return rv;
227 }
228 longstr = longstr->next;
229 }
230 return NULL;
231 }
232
233 void
free_longstrs(void)234 free_longstrs(void)
235 {
236
237 while (longstrs) {
238 struct longstr_s *longstr = longstrs;
239
240 longstrs = longstrs->next;
241 free(longstr->name);
242 free(longstr->str);
243 free(longstr);
244 }
245 }
246
247 struct tracefile_s
248 {
249 char *name;
250 char *str;
251 struct tracefile_s *next;
252 };
253
254 #if HAVE_DECL_TIOCSRS485
255 struct rs485conf_s
256 {
257 char *name;
258 struct serial_rs485 conf;
259 struct rs485conf_s *next;
260 };
261 #endif
262
263 /* All the tracefiles in the system. */
264 struct tracefile_s *tracefiles = NULL;
265
266 static void
handle_tracefile(char * name,char * fname)267 handle_tracefile(char *name, char *fname)
268 {
269 struct tracefile_s *new_tracefile;
270
271 new_tracefile = malloc(sizeof(*new_tracefile));
272 if (!new_tracefile) {
273 syslog(LOG_ERR, "Out of memory handling tracefile on %d", lineno);
274 return;
275 }
276
277 new_tracefile->name = strdup(name);
278 if (!new_tracefile->name) {
279 syslog(LOG_ERR, "Out of memory handling tracefile on %d", lineno);
280 free(new_tracefile);
281 return;
282 }
283
284 new_tracefile->str = strdup(fname);
285 if (!new_tracefile->str) {
286 syslog(LOG_ERR, "Out of memory handling tracefile on %d", lineno);
287 free(new_tracefile->name);
288 free(new_tracefile);
289 return;
290 }
291
292 new_tracefile->next = tracefiles;
293 tracefiles = new_tracefile;
294 }
295
296 char *
find_tracefile(const char * name)297 find_tracefile(const char *name)
298 {
299 struct tracefile_s *tracefile = tracefiles;
300
301 while (tracefile) {
302 if (strcmp(name, tracefile->name) == 0)
303 return strdup(tracefile->str);
304 tracefile = tracefile->next;
305 }
306 syslog(LOG_ERR, "Tracefile %s not found, it will be ignored", name);
307 return NULL;
308 }
309
310 void
free_tracefiles(void)311 free_tracefiles(void)
312 {
313 while (tracefiles) {
314 struct tracefile_s *tracefile = tracefiles;
315
316 tracefiles = tracefiles->next;
317 free(tracefile->name);
318 free(tracefile->str);
319 free(tracefile);
320 }
321 }
322
323 #if HAVE_DECL_TIOCSRS485
324 /* All the RS485 configs in the system. */
325 struct rs485conf_s *rs485confs = NULL;
326
327 static void
handle_rs485conf(char * name,char * str)328 handle_rs485conf(char *name, char *str)
329 {
330 struct rs485conf_s *new_rs485conf;
331 uint8_t rts_on_send, rx_during_tx;
332
333 new_rs485conf = malloc(sizeof(*new_rs485conf));
334 if (!new_rs485conf) {
335 syslog(LOG_ERR, "Out of memory handling rs485 config on %d", lineno);
336 return;
337 }
338 memset(new_rs485conf, 0, sizeof(*new_rs485conf));
339
340 new_rs485conf->name = strdup(name);
341 if (!new_rs485conf->name) {
342 syslog(LOG_ERR, "Out of memory handling rs485 config on %d", lineno);
343 goto out_err;
344 }
345
346 if (sscanf(str, "%10u:%10u:%1hhu:%1hhu",
347 &new_rs485conf->conf.delay_rts_before_send,
348 &new_rs485conf->conf.delay_rts_after_send,
349 &rts_on_send,
350 &rx_during_tx) != 4) {
351 syslog(LOG_ERR, "Couldn't parse RS485 config on %d", lineno);
352 goto out_err;
353 }
354
355 /* check, if flags have values 0 or 1 */
356 if (rts_on_send > 1) {
357 syslog(LOG_ERR, "RTS_ON_SEND parameter can be 0 or 1 on %d", lineno);
358 goto out_err;
359 }
360
361 if (rx_during_tx > 1) {
362 syslog(LOG_ERR, "RX_DURING_TX parameter can be 0 or 1 on %d", lineno);
363 goto out_err;
364 }
365
366 new_rs485conf->conf.flags = SER_RS485_ENABLED;
367
368 if (rts_on_send) {
369 new_rs485conf->conf.flags |= SER_RS485_RTS_ON_SEND;
370 } else {
371 new_rs485conf->conf.flags |= SER_RS485_RTS_AFTER_SEND;
372 }
373
374 if (rx_during_tx) {
375 new_rs485conf->conf.flags |= SER_RS485_RX_DURING_TX;
376 }
377
378 new_rs485conf->next = rs485confs;
379 rs485confs = new_rs485conf;
380 return;
381
382 out_err:
383 if (new_rs485conf->name)
384 free(new_rs485conf->name);
385 free(new_rs485conf);
386 }
387
388 struct serial_rs485 *
find_rs485conf(const char * name)389 find_rs485conf(const char *name)
390 {
391 struct rs485conf_s *new_rs485conf = rs485confs;
392
393 while (new_rs485conf) {
394 if (strcmp(name, new_rs485conf->name) == 0)
395 return &new_rs485conf->conf;
396 new_rs485conf = new_rs485conf->next;
397 }
398 syslog(LOG_ERR, "RS485 configuration %s not found, it will be ignored", name);
399 return NULL;
400 }
401
402 void
free_rs485confs(void)403 free_rs485confs(void)
404 {
405 while (rs485confs) {
406 struct rs485conf_s *rs485conf = rs485confs;
407
408 rs485confs = rs485confs->next;
409 free(rs485conf->name);
410 free(rs485conf);
411 }
412 }
413 #else
free_rs485confs(void)414 void free_rs485confs(void) { }
415 #endif
416
417 static int
startswith(char * str,const char * test,char ** strtok_data)418 startswith(char *str, const char *test, char **strtok_data)
419 {
420 int len = strlen(test);
421
422 if ((strncmp(str, test, len) == 0) && (str[len] == ':')) {
423 strtok_r(str, ":", strtok_data);
424 return 1;
425 }
426 return 0;
427 }
428
429 static int
syslog_eprint(struct absout * e,const char * str,...)430 syslog_eprint(struct absout *e, const char *str, ...)
431 {
432 va_list ap;
433 char buf[1024];
434
435 va_start(ap, str);
436 vsnprintf(buf, sizeof(buf), str, ap);
437 va_end(ap);
438 syslog(LOG_ERR, "%s on line %d", buf, *((int *) e->data));
439 return 0;
440 }
441
442 static struct absout syslog_eout = {
443 .out = syslog_eprint,
444 .data = &lineno
445 };
446
447 struct enum_val
448 {
449 char *str;
450 int val;
451 };
452
453 static int
lookup_enum(struct enum_val * enums,const char * str,int len)454 lookup_enum(struct enum_val *enums, const char *str, int len)
455 {
456 while (enums->str != NULL) {
457 if (len == -1 && strcmp(enums->str, str) == 0)
458 return enums->val;
459 if (strlen(enums->str) == len && strncmp(enums->str, str, len) == 0)
460 return enums->val;
461 enums++;
462 }
463 return -1;
464 }
465
466 static struct enum_val speed_enums[] = {
467 { "300", 300 },
468 { "600", 600 },
469 { "1200", 1200 },
470 { "2400", 2400 },
471 { "4800", 4800 },
472 { "9600", 9600 },
473 { "19200", 19200 },
474 { "38400", 38400 },
475 { "57600", 57600 },
476 { "115200", 115200 },
477 { "230400", 230400 },
478 { "460800", 460800 },
479 { "500000", 500000 },
480 { "576000", 576000 },
481 { "921600", 921600 },
482 { "1000000",1000000 },
483 { "1152000",1152000 },
484 { "1500000",1500000 },
485 { "2000000",2000000 },
486 { "2500000",2500000 },
487 { "3000000",3000000 },
488 { "3500000",3500000 },
489 { "4000000",4000000 },
490 { NULL },
491 };
492
493 int
speedstr_to_speed(const char * speed)494 speedstr_to_speed(const char *speed)
495 {
496 return lookup_enum(speed_enums, speed, -1);
497 }
498
499 struct enum_val parity_enums[] = {
500 { "NONE", PARITY_NONE },
501 { "EVEN", PARITY_EVEN },
502 { "ODD", PARITY_ODD },
503 { "none", PARITY_NONE },
504 { "even", PARITY_EVEN },
505 { "odd", PARITY_ODD },
506 { "MARK", PARITY_MARK },
507 { "SPACE", PARITY_SPACE },
508 { "mark", PARITY_MARK },
509 { "space", PARITY_SPACE },
510 { NULL }
511 };
512
513 #ifdef HAVE_OPENIPMI
514 struct enum_val shared_serial_alert_enums[] = {
515 { "fail", ipmi_sol_serial_alerts_fail },
516 { "deferred", ipmi_sol_serial_alerts_deferred },
517 { "succeed", ipmi_sol_serial_alerts_succeed },
518 { NULL }
519 };
520 #endif
521
522 enum parity_vals
lookup_parity(const char * str)523 lookup_parity(const char *str)
524 {
525 return lookup_enum(parity_enums, str, -1);
526 }
527
528 enum default_type { DEFAULT_INT, DEFAULT_BOOL, DEFAULT_ENUM, DEFAULT_STR };
529
530 struct default_data
531 {
532 const char *name;
533 enum default_type type;
534 int min;
535 int max;
536 struct enum_val *enums;
537 union {
538 int intval;
539 char *strval;
540 } val;
541 union {
542 int intval;
543 const char *strval;
544 } def;
545 const char *altname;
546 };
547
548 struct default_data defaults[] = {
549 /* serial device only */
550 { "stopbits", DEFAULT_INT, .min = 1, .max = 2, .def.intval = 1 },
551 { "databits", DEFAULT_INT, .min = 5, .max = 8, .def.intval = 8 },
552 { "parity", DEFAULT_ENUM, .enums = parity_enums,
553 .def.intval = PARITY_NONE },
554 { "xonxoff", DEFAULT_BOOL, .def.intval = 0 },
555 { "rtscts", DEFAULT_BOOL, .def.intval = 0 },
556 { "local", DEFAULT_BOOL, .def.intval = 0 },
557 { "hangup_when_done", DEFAULT_BOOL, .def.intval = 0 },
558 /* Serial port and SOL */
559 { "speed", DEFAULT_ENUM, .enums = speed_enums,
560 .def.intval = 9600 },
561 { "nobreak", DEFAULT_BOOL, .def.intval = 0 },
562 /* All port types */
563 { "remctl", DEFAULT_BOOL, .def.intval = 0 },
564 { "telnet_brk_on_sync",DEFAULT_BOOL,.def.intval = 0 },
565 { "kickolduser", DEFAULT_BOOL, .def.intval = 0 },
566 { "chardelay", DEFAULT_BOOL, .def.intval = 1 },
567 { "chardelay-scale",DEFAULT_INT, .min = 1, .max = 1000,
568 .def.intval = 20 },
569 { "chardelay-min", DEFAULT_INT, .min = 1, .max = 100000,
570 .def.intval = 1000 },
571 { "chardelay-max", DEFAULT_INT, .min = 1, .max = 1000000,
572 .def.intval = 20000 },
573 { "dev-to-net-bufsize", DEFAULT_INT,.min = 1, .max = 65536,
574 .def.intval = PORT_BUFSIZE,
575 .altname = "dev-to-tcp-bufsize" },
576 { "net-to-dev-bufsize", DEFAULT_INT,.min = 1, .max = 65536,
577 .def.intval = PORT_BUFSIZE,
578 .altname = "tcp-to-dev-bufsize" },
579 { "max-connections", DEFAULT_INT, .min=1, .max=65536,
580 .def.intval = 1 },
581 #ifdef HAVE_OPENIPMI
582 /* SOL only */
583 { "authenticated", DEFAULT_BOOL, .def.intval = 1 },
584 { "encrypted", DEFAULT_BOOL, .def.intval = 1 },
585 { "ack-timeout", DEFAULT_INT, .min = 1, .max = INT_MAX,
586 .def.intval = 1000000 },
587 { "ack-retries", DEFAULT_INT, .min = 1, .max = INT_MAX,
588 .def.intval = 10 },
589 { "shared-serial-alert", DEFAULT_ENUM, .enums = shared_serial_alert_enums,
590 .def.intval = ipmi_sol_serial_alerts_fail },
591 { "deassert_CTS_DCD_DSR_on_connect", DEFAULT_BOOL, .def.intval = 0 },
592 #endif
593 { "remaddr", DEFAULT_STR, .def.strval = "" },
594 { NULL }
595 };
596
597
598 static void
setup_defaults(void)599 setup_defaults(void)
600 {
601 int i;
602
603 for (i = 0; defaults[i].name; i++) {
604 if (defaults[i].type == DEFAULT_STR) {
605 if (defaults[i].val.strval) {
606 free(defaults[i].val.strval);
607 defaults[i].val.strval = NULL;
608 }
609 } else {
610 defaults[i].val.intval = defaults[i].def.intval;
611 }
612 }
613 }
614
cmp_default_name(struct default_data * def,const char * name)615 static int cmp_default_name(struct default_data *def, const char *name)
616 {
617 return (strcmp(def->name, name) == 0 ||
618 (def->altname && strcmp(def->altname, name) == 0));
619 }
620
621 int
find_default_int(const char * name)622 find_default_int(const char *name)
623 {
624 int i;
625
626 for (i = 0; defaults[i].name; i++) {
627 if (cmp_default_name(&defaults[i], name) &&
628 defaults[i].type != DEFAULT_STR)
629 return defaults[i].val.intval;
630 }
631 abort();
632 }
633
634 char *
find_default_str(const char * name)635 find_default_str(const char *name)
636 {
637 int i;
638
639 for (i = 0; defaults[i].name; i++) {
640 if (cmp_default_name(&defaults[i], name) &&
641 defaults[i].type == DEFAULT_STR) {
642 const char *s = defaults[i].val.strval;
643 if (!s)
644 s = defaults[i].def.strval;
645 return strdup(s);
646 }
647 }
648 abort();
649 }
650
651 static void
handle_new_default(const char * name,const char * str)652 handle_new_default(const char *name, const char *str)
653 {
654 int i, val, len;
655 char *end, *sval;
656 const char *s;
657
658 while (isspace(*str))
659 str++;
660 s = str;
661 while (!isspace(*s) && *s != '\0')
662 s++;
663 if (s == str) {
664 syslog(LOG_ERR, "No default value on %d", lineno);
665 return;
666 }
667 len = s - str;
668
669 for (i = 0; defaults[i].name; i++) {
670 if (!cmp_default_name(&defaults[i], name))
671 continue;
672
673 switch (defaults[i].type) {
674 case DEFAULT_INT:
675 val = strtoul(str, &end, 10);
676 if (end != s) {
677 syslog(LOG_ERR, "Invalid integer value on %d", lineno);
678 return;
679 }
680 if (val < defaults[i].min || val > defaults[i].max) {
681 syslog(LOG_ERR, "Integer value out of range on %d, "
682 "min is %d, max is %d",
683 lineno, defaults[i].min, defaults[i].max);
684 return;
685 }
686 defaults[i].val.intval = val;
687 break;
688
689 case DEFAULT_BOOL:
690 val = strtoul(str, &end, 10);
691 if (end == s)
692 defaults[i].val.intval = !!val;
693 else if (len == 4 && ((strncmp(str, "true", 4) == 0) ||
694 (strncmp(str, "TRUE", 4) == 0)))
695 defaults[i].val.intval = 1;
696 else if (len == 5 && ((strncmp(str, "false", 5) == 0) ||
697 (strncmp(str, "FALSE", 5) == 0)))
698 defaults[i].val.intval = 0;
699 else
700 syslog(LOG_ERR, "Invalid integer value on %d", lineno);
701 break;
702
703 case DEFAULT_ENUM:
704 val = lookup_enum(defaults[i].enums, str, len);
705 if (val == -1) {
706 syslog(LOG_ERR, "Invalid enumeration value on %d", lineno);
707 return;
708 }
709 defaults[i].val.intval = val;
710 break;
711
712 case DEFAULT_STR:
713 sval = strdup(str);
714 if (!sval) {
715 syslog(LOG_ERR, "Out of memory processing default string on"
716 " line %d", lineno);
717 return;
718 }
719 if (defaults[i].val.strval)
720 free(defaults[i].val.strval);
721 defaults[i].val.strval = sval;
722 break;
723 }
724 return;
725 }
726
727 syslog(LOG_ERR, "unknown default name '%s' on %d", name, lineno);
728 }
729
730 /*
731 * This rather complicated variable is used to scan the string for
732 * ":off", ":telnet", ":raw:", or ":rawlp:". It's a basic state
733 * machine where if a character in the first string "c" matches the
734 * current character, you go to the state machine index in the
735 * corresponding location giving by the character in string "next".
736 * So ":raw:" would see the ":" in state zero and go to state 1. Then
737 * the "r" in state 1 would go to state 7. Then "a" in state 7 would
738 * go to state 8, "w" to state name. The ":" has a zero, that means a
739 * match was found.
740 *
741 * This is nasty, but it allows there to be ":" characters in the
742 * portnum so that IPV6 addresses can be specified.
743 */
744 static struct {
745 char *c;
746 char *next;
747 } scanstate[] = {
748 { ":", "\x01" }, /* 0x00 */
749 { "tro", "\x02\x07\x0b" }, /* 0x01 */
750 { "e", "\x03" }, /* 0x02 */
751 { "l", "\x04" }, /* 0x03 */
752 { "n", "\x05" }, /* 0x04 */
753 { "e", "\x06" }, /* 0x05 */
754 { "t", "\x0d" }, /* 0x06 */
755 { "a", "\x08" }, /* 0x07 */
756 { "w", "\x09" }, /* 0x09 */
757 { ":l", "\x00\x0a" }, /* 0x09 */
758 { "p", "\x0d" }, /* 0x0a */
759 { "f", "\x0c" }, /* 0x0b */
760 { "f", "\x0d" }, /* 0x0c */
761 { ":", "\x00" } /* 0x0d */
762 };
763
764 static char *
scan_for_state(char * str)765 scan_for_state(char *str)
766 {
767 int s = 0;
768 char *b = str;
769
770 for (; *str; str++) {
771 int i;
772
773 for (i = 0; scanstate[s].c[i]; i++) {
774 if (scanstate[s].c[i] == *str)
775 break;
776 }
777
778 if (scanstate[s].c[i]) {
779 s = scanstate[s].next[i];
780 if (s == 0)
781 return b;
782 } else {
783 s = 0;
784 b = str + 1;
785 }
786 }
787
788 return NULL;
789 }
790
791 int
handle_config_line(char * inbuf,int len)792 handle_config_line(char *inbuf, int len)
793 {
794 char *portnum, *state, *timeout, *devname, *devcfg;
795 char *strtok_data = NULL;
796
797 if (len == 0)
798 /* Ignore empty lines */
799 goto out;
800
801 if (inbuf[0] == '#')
802 /* Ignore comments. */
803 goto out;
804
805 if (inbuf[len - 1] == '\\')
806 return len - 1; /* Continued line. */
807
808 if (startswith(inbuf, "BANNER", &strtok_data)) {
809 char *name = strtok_r(NULL, ":", &strtok_data);
810 char *str = strtok_r(NULL, "\n", &strtok_data);
811 if (name == NULL) {
812 syslog(LOG_ERR, "No banner name given on line %d", lineno);
813 goto out;
814 }
815 handle_longstr(name, str, BANNER);
816 goto out;
817 }
818
819 if (startswith(inbuf, "SIGNATURE", &strtok_data)) {
820 char *name = strtok_r(NULL, ":", &strtok_data);
821 char *str = strtok_r(NULL, "\n", &strtok_data);
822 if (name == NULL) {
823 syslog(LOG_ERR, "No signature given on line %d", lineno);
824 goto out;
825 }
826 handle_longstr(name, str, SIGNATURE);
827 goto out;
828 }
829
830 if (startswith(inbuf, "OPENSTR", &strtok_data)) {
831 char *name = strtok_r(NULL, ":", &strtok_data);
832 char *str = strtok_r(NULL, "\n", &strtok_data);
833 if (name == NULL) {
834 syslog(LOG_ERR, "No open string name given on line %d", lineno);
835 goto out;
836 }
837 handle_longstr(name, str, OPENSTR);
838 goto out;
839 }
840
841 if (startswith(inbuf, "CLOSESTR", &strtok_data)) {
842 char *name = strtok_r(NULL, ":", &strtok_data);
843 char *str = strtok_r(NULL, "\n", &strtok_data);
844 if (name == NULL) {
845 syslog(LOG_ERR, "No close string name given on line %d", lineno);
846 goto out;
847 }
848 handle_longstr(name, str, CLOSESTR);
849 goto out;
850 }
851
852 if (startswith(inbuf, "CLOSEON", &strtok_data)) {
853 char *name = strtok_r(NULL, ":", &strtok_data);
854 char *str = strtok_r(NULL, "\n", &strtok_data);
855 if (name == NULL) {
856 syslog(LOG_ERR, "No close on string name given on line %d", lineno);
857 goto out;
858 }
859 handle_longstr(name, str, CLOSEON);
860 goto out;
861 }
862
863 if (startswith(inbuf, "DEVICE", &strtok_data)) {
864 char *name = strtok_r(NULL, ":", &strtok_data);
865 char *str = strtok_r(NULL, "\n", &strtok_data);
866 if (name == NULL) {
867 syslog(LOG_ERR, "No device name given on line %d", lineno);
868 goto out;
869 }
870 handle_longstr(name, str, DEVNAME);
871 goto out;
872 }
873
874 if (startswith(inbuf, "TRACEFILE", &strtok_data)) {
875 char *name = strtok_r(NULL, ":", &strtok_data);
876 char *str = strtok_r(NULL, "\n", &strtok_data);
877 if (name == NULL) {
878 syslog(LOG_ERR, "No tracefile name given on line %d", lineno);
879 goto out;
880 }
881 if ((str == NULL) || (strlen(str) == 0)) {
882 syslog(LOG_ERR, "No tracefile given on line %d", lineno);
883 goto out;
884 }
885 handle_tracefile(name, str);
886 goto out;
887 }
888
889 if (startswith(inbuf, "CONTROLPORT", &strtok_data)) {
890 if (config_port)
891 /*
892 * The control port has already been configured either on the
893 * command line or on a previous statement. Only take the first.
894 */
895 goto out;
896 config_port = strdup(strtok_r(NULL, "\n", &strtok_data));
897 if (!config_port) {
898 syslog(LOG_ERR, "Could not allocate memory for CONTROLPORT");
899 goto out;
900 }
901 goto out;
902 }
903
904 #if HAVE_DECL_TIOCSRS485
905 if (startswith(inbuf, "RS485CONF", &strtok_data)) {
906 char *name = strtok_r(NULL, ":", &strtok_data);
907 char *str = strtok_r(NULL, "\n", &strtok_data);
908 if (name == NULL) {
909 syslog(LOG_ERR, "No signature given on line %d", lineno);
910 goto out;
911 }
912 if ((str == NULL) || (strlen(str) == 0)) {
913 syslog(LOG_ERR, "No RS485 configuration given on line %d", lineno);
914 goto out;
915 }
916 handle_rs485conf(name, str);
917 goto out;
918 }
919 #endif
920
921 if (startswith(inbuf, "DEFAULT", &strtok_data)) {
922 char *name = strtok_r(NULL, ":", &strtok_data);
923 char *str = strtok_r(NULL, "\n", &strtok_data);
924 if (name == NULL) {
925 syslog(LOG_ERR, "No default name given on line %d", lineno);
926 goto out;
927 }
928 handle_new_default(name, str);
929 goto out;
930 }
931
932 if (startswith(inbuf, "ROTATOR", &strtok_data)) {
933 char *name = strtok_r(NULL, ":", &strtok_data);
934 char *str = strtok_r(NULL, "\n", &strtok_data);
935 if (name == NULL) {
936 syslog(LOG_ERR, "No rotator name given on line %d", lineno);
937 goto out;
938 }
939 add_rotator(name, str, lineno);
940 goto out;
941 }
942
943 if (startswith(inbuf, "LED", &strtok_data)) {
944 char *name = strtok_r(NULL, ":", &strtok_data);
945 char *str = strtok_r(NULL, "\n", &strtok_data);
946 if (name == NULL) {
947 syslog(LOG_ERR, "No LED name given on line %d", lineno);
948 goto out;
949 }
950 if ((str == NULL) || (strlen(str) == 0)) {
951 syslog(LOG_ERR, "No LED given on line %d", lineno);
952 goto out;
953 }
954 handle_led(name, str, lineno);
955 goto out;
956 }
957
958 /* Scan for the state. */
959 state = scan_for_state(inbuf);
960 if (!state) {
961 syslog(LOG_ERR, "No state given on line %d", lineno);
962 goto out;
963 }
964
965 /* Everything before the state is the port number. */
966 portnum = inbuf;
967 *state = '\0';
968 state++;
969
970 /* Terminate the state. */
971 inbuf = strchr(state, ':'); /* ":" must be there if scan_for_state works */
972 *inbuf = '\0';
973 inbuf++;
974
975 timeout = strtok_r(inbuf, ":", &strtok_data);
976 if (timeout == NULL) {
977 syslog(LOG_ERR, "No timeout given on line %d", lineno);
978 goto out;
979 }
980
981 devname = strtok_r(NULL, ":", &strtok_data);
982 if (devname == NULL) {
983 syslog(LOG_ERR, "No device name given on line %d", lineno);
984 goto out;
985 }
986
987 devcfg = strtok_r(NULL, "", &strtok_data);
988 if (devcfg == NULL) {
989 /* An empty device config is ok. */
990 devcfg = "";
991 }
992
993 portconfig(&syslog_eout, portnum, state, timeout, devname, devcfg,
994 config_num);
995
996 out:
997 return 0;
998 }
999
1000 void
readconfig_init(void)1001 readconfig_init(void)
1002 {
1003 setup_defaults();
1004 free_longstrs();
1005 free_tracefiles();
1006 #if HAVE_DECL_TIOCSRS485
1007 free_rs485confs();
1008 #endif
1009 free_leds();
1010
1011 config_num++;
1012 free_rotators();
1013 }
1014
1015 /* Read the specified configuration file and call the routine to
1016 create the ports. */
1017 int
readconfig(char * filename)1018 readconfig(char *filename)
1019 {
1020 FILE *instream = NULL;
1021 int linesize = 256;
1022 char *inbuf = malloc(linesize);
1023 int rv = 0, pos = 0;
1024
1025 if (!inbuf) {
1026 syslog(LOG_ERR, "Unable to allocate input buffer");
1027 return -1;
1028 }
1029
1030 lineno = 0;
1031
1032 instream = fopen(filename, "r");
1033 if (!instream) {
1034 syslog(LOG_ERR, "Unable to open config file '%s': %m", filename);
1035 rv = -1;
1036 goto out_err;
1037 }
1038
1039 while (fgets(inbuf + pos, linesize - pos, instream) != NULL) {
1040 int len = strlen(inbuf);
1041 lineno++;
1042 if (len >= (linesize - 1) && inbuf[len - 1] != '\n') {
1043 char *new_inbuf;
1044
1045 /* We filled up the buffer. Expand the line. */
1046 pos = len;
1047 linesize += 256;
1048 new_inbuf = realloc(inbuf, linesize);
1049 if (!new_inbuf) {
1050 syslog(LOG_ERR, "Unable to reallocate input buffer");
1051 rv = -1;
1052 goto out_err;
1053 }
1054 inbuf = new_inbuf;
1055 continue;
1056 }
1057
1058 /* Remove the '\n' */
1059 if (len > 0 && inbuf[len - 1] == '\n') {
1060 inbuf[len - 1] = '\0';
1061 len--;
1062 }
1063 pos = handle_config_line(inbuf, len);
1064 }
1065 if (pos > 0)
1066 handle_config_line(inbuf, strlen(inbuf));
1067
1068 /* Delete anything that wasn't in the new config file. */
1069 clear_old_port_config(config_num);
1070
1071 out_err:
1072 if (instream)
1073 fclose(instream);
1074 free(inbuf);
1075 return rv;
1076 }
1077
1078