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 is the entry point for the ser2net program. It reads
21 parameters, initializes everything, then starts the select loop. */
22
23 /* TODO
24 *
25 * Add some type of security
26 */
27
28 #include <stdio.h>
29 #include <signal.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <syslog.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <errno.h>
36
37 #include "ser2net.h"
38 #include "readconfig.h"
39 #include "controller.h"
40 #include "utils.h"
41 #include "selector.h"
42 #include "dataxfer.h"
43 #include "locking.h"
44 #include "led.h"
45
46 static char *config_file = "/usr/local/etc/ser2net.conf";
47 int config_port_from_cmdline = 0;
48 char *config_port = NULL; /* Can be set from readconfig, too. */
49 static char *pid_file = NULL;
50 static int detach = 1;
51 int ser2net_debug = 0;
52 int ser2net_debug_level = 0;
53 volatile int in_shutdown = 0;
54 #ifdef USE_UUCP_LOCKING
55 int uucp_locking_enabled = 1;
56 #endif
57 #ifdef USE_PTHREADS
58 int num_threads = 1;
59 struct thread_info {
60 pthread_t id;
61 };
62 struct thread_info *threads;
63 #endif
64
65
66 struct selector_s *ser2net_sel;
67 char *rfc2217_signature = "ser2net";
68
69 static char *help_string =
70 "%s: Valid parameters are:\n"
71 " -c <config file> - use a config file besides /usr/local/etc/ser2net.conf\n"
72 " -C <config line> - Handle a single configuration line. This may be\n"
73 " specified multiple times for multiple lines. This is just like a\n"
74 " line in the config file. This disables the default config file,\n"
75 " you must specify a -c after the last -C to have it read a config\n"
76 " file, too.\n"
77 " -p <controller port> - Start a controller session on the given TCP port\n"
78 " -P <file> - set location of pid file\n"
79 " -n - Don't detach from the controlling terminal\n"
80 " -d - Don't detach and send debug I/O to standard output\n"
81 " -l - Increate the debugging level\n"
82 #ifdef USE_UUCP_LOCKING
83 " -u - Disable UUCP locking\n"
84 #endif
85 #ifdef USE_PTHREADS
86 " -t <num threads> - Use the given number of threads, default 1\n"
87 #endif
88 " -b - unused (was Do CISCO IOS baud-rate negotiation, instead of RFC2217)\n"
89 " -v - print the program's version and exit\n"
90 " -s - specify a default signature for RFC2217 protocol\n";
91
92 static void
reread_config_file(void)93 reread_config_file(void)
94 {
95 if (config_file) {
96 char *prev_config_port = config_port;
97 config_port = NULL;
98 syslog(LOG_INFO, "Got SIGHUP, re-reading configuration");
99 readconfig_init();
100 readconfig(config_file);
101 if (config_port_from_cmdline) {
102 /* Never override the config port from the command line. */
103 free(config_port);
104 config_port = prev_config_port;
105 goto config_port_unchanged;
106 }
107 if (config_port && prev_config_port
108 && (strcmp(config_port, prev_config_port) == 0)) {
109 free(prev_config_port);
110 goto config_port_unchanged;
111 }
112
113 if (prev_config_port) {
114 controller_shutdown();
115 free(prev_config_port);
116 }
117
118 if (config_port) {
119 int rv = controller_init(config_port);
120 if (rv == CONTROLLER_INVALID_TCP_SPEC)
121 syslog(LOG_ERR, "Invalid control port specified: %s",
122 config_port);
123 else if (rv == CONTROLLER_OUT_OF_MEMORY)
124 syslog(LOG_ERR, "Out of memory opening control port: %s",
125 config_port);
126 else if (rv == CONTROLLER_CANT_OPEN_PORT)
127 syslog(LOG_ERR, "Can't open control port: %s",
128 config_port);
129 if (rv) {
130 syslog(LOG_ERR, "Control port is disabled");
131 free(config_port);
132 config_port = NULL;
133 }
134 }
135 }
136 config_port_unchanged:
137 return;
138 }
139
140 static void
arg_error(char * name)141 arg_error(char *name)
142 {
143 fprintf(stderr, help_string, name);
144 exit(1);
145 }
146
147 static void
make_pidfile(void)148 make_pidfile(void)
149 {
150 FILE *fpidfile;
151 if (!pid_file)
152 return;
153 fpidfile = fopen(pid_file, "w");
154 if (!fpidfile) {
155 syslog(LOG_WARNING,
156 "Error opening pidfile '%s': %m, pidfile not created",
157 pid_file);
158 pid_file = NULL;
159 return;
160 }
161 fprintf(fpidfile, "%d\n", getpid());
162 fclose(fpidfile);
163 }
164
165 static int dummyrv; /* Used to ignore return values of read() and write(). */
166
167 /* Used to reliably deliver signals to a thread. This is a pipe that
168 we write to from a signal handler to make sure it wakes up. */
169 static int sig_fd_alert = -1;
170 static int sig_fd_watch = -1;
171 static volatile int reread_config = 0; /* Did I get a HUP signal? */
172 static volatile int term_prog = 0; /* Did I get an INT signal? */
173
174 static void
sig_wake_selector(void)175 sig_wake_selector(void)
176 {
177 char dummy = 0;
178
179 dummyrv = write(sig_fd_alert, &dummy, 1);
180 }
181
182 static void
sighup_handler(int sig)183 sighup_handler(int sig)
184 {
185 reread_config = 1;
186 sig_wake_selector();
187 }
188
189 static void
sigint_handler(int sig)190 sigint_handler(int sig)
191 {
192 term_prog = 1;
193 sig_wake_selector();
194 }
195
196 #if USE_PTHREADS
197 DEFINE_LOCK_INIT(static, config_lock)
198 static int in_config_read = 0;
199
200 DEFINE_LOCK_INIT(static, maint_lock)
201
202 int ser2net_wake_sig = SIGUSR1;
203 void (*finish_shutdown)(void);
204
205 void
start_maint_op(void)206 start_maint_op(void)
207 {
208 LOCK(maint_lock);
209 }
210
211 void
end_maint_op(void)212 end_maint_op(void)
213 {
214 UNLOCK(maint_lock);
215 }
216
217 static void *
config_reread_thread(void * dummy)218 config_reread_thread(void *dummy)
219 {
220 pthread_detach(pthread_self());
221 start_maint_op();
222 reread_config_file();
223 end_maint_op();
224 LOCK(config_lock);
225 in_config_read = 0;
226 UNLOCK(config_lock);
227 return NULL;
228 }
229
230 static void
thread_reread_config_file(void)231 thread_reread_config_file(void)
232 {
233 int rv;
234 pthread_t thread;
235
236 LOCK(config_lock);
237 if (in_config_read) {
238 UNLOCK(config_lock);
239 return;
240 }
241 in_config_read = 1;
242 UNLOCK(config_lock);
243
244 rv = pthread_create(&thread, NULL, config_reread_thread, NULL);
245 if (rv) {
246 syslog(LOG_ERR,
247 "Unable to start thread to reread config file: %s",
248 strerror(rv));
249 LOCK(config_lock);
250 in_config_read = 0;
251 UNLOCK(config_lock);
252 }
253 }
254
255 static void
wake_thread_sighandler(int sig)256 wake_thread_sighandler(int sig)
257 {
258 /* Nothing to do, sending the sig just wakes up select(). */
259 }
260
261 static void
wake_thread_send_sig(long thread_id,void * cb_data)262 wake_thread_send_sig(long thread_id, void *cb_data)
263 {
264 pthread_t *id = (void *) thread_id;
265
266 pthread_kill(*id, ser2net_wake_sig);
267 }
268
269 static void *
op_loop(void * dummy)270 op_loop(void *dummy)
271 {
272 pthread_t self = pthread_self();
273
274 while (!in_shutdown)
275 sel_select(ser2net_sel, wake_thread_send_sig, (long) &self, NULL, NULL);
276
277 /* Join the threads only in the first thread. You cannot join the
278 first thread. Finish thw shutdown in the first thread. */
279 if (self == threads[0].id) {
280 int i;
281
282 for (i = 0; i < num_threads; i++) {
283 if (threads[i].id == self)
284 continue;
285 pthread_join(threads[i].id, NULL);
286 }
287 free(threads);
288
289 finish_shutdown();
290 }
291 return NULL;
292 }
293
294 static void
start_threads(void)295 start_threads(void)
296 {
297 int i, rv;
298 struct sigaction act;
299
300 act.sa_handler = wake_thread_sighandler;
301 sigemptyset(&act.sa_mask);
302 act.sa_flags = 0;
303 rv = sigaction(ser2net_wake_sig, &act, NULL);
304 if (rv) {
305 syslog(LOG_ERR, "Unable to set sigaction: %s", strerror(errno));
306 exit(1);
307 }
308
309 threads = malloc(sizeof(*threads) * num_threads);
310 if (!threads) {
311 syslog(LOG_ERR, "Unable to allocate thread info");
312 exit(1);
313 }
314
315 threads[0].id = pthread_self();
316
317 for (i = 1; i < num_threads; i++) {
318 rv = pthread_create(&threads[i].id, NULL, op_loop, NULL);
319 if (rv) {
320 syslog(LOG_ERR, "Unable to start thread: %s", strerror(rv));
321 exit(1);
322 }
323 }
324 }
325
326 static void
stop_threads(void (* finish)(void))327 stop_threads(void (*finish)(void))
328 {
329 int i;
330 pthread_t self = pthread_self();
331
332 in_shutdown = 1;
333 finish_shutdown = finish;
334 start_maint_op();
335 /* Make sure we aren't in a reconfig. */
336 end_maint_op();
337
338 for (i = 0; i < num_threads; i++) {
339 if (threads[i].id == self)
340 continue;
341 pthread_kill(threads[i].id, ser2net_wake_sig);
342 }
343 }
344
345 struct sel_lock_s
346 {
347 pthread_mutex_t lock;
348 };
349
350 static sel_lock_t *
slock_alloc(void * cb_data)351 slock_alloc(void *cb_data)
352 {
353 sel_lock_t *l;
354
355 l = malloc(sizeof(*l));
356 if (!l)
357 return NULL;
358 pthread_mutex_init(&l->lock, NULL);
359 return l;
360 }
361
362 static void
slock_free(sel_lock_t * l)363 slock_free(sel_lock_t *l)
364 {
365 pthread_mutex_destroy(&l->lock);
366 free(l);
367 }
368
369 static void
slock_lock(sel_lock_t * l)370 slock_lock(sel_lock_t *l)
371 {
372 pthread_mutex_lock(&l->lock);
373 }
374
375 static void
slock_unlock(sel_lock_t * l)376 slock_unlock(sel_lock_t *l)
377 {
378 pthread_mutex_unlock(&l->lock);
379 }
380
381 #else
382 int ser2net_wake_sig = 0;
start_maint_op(void)383 void start_maint_op(void) { }
end_maint_op(void)384 void end_maint_op(void) { }
start_threads(void)385 static void start_threads(void) { }
stop_threads(void (* finish)(void))386 static void stop_threads(void (*finish)(void)) { finish(); }
387 #define slock_alloc NULL
388 #define slock_free NULL
389 #define slock_lock NULL
390 #define slock_unlock NULL
391 static void *
op_loop(void * dummy)392 op_loop(void *dummy)
393 {
394 sel_select_loop(ser2net_sel, NULL, 0, NULL);
395 return NULL;
396 }
397 #endif /* USE_PTHREADS */
398
399 static void
finish_shutdown_cleanly(void)400 finish_shutdown_cleanly(void)
401 {
402 struct timeval tv;
403
404 sel_clear_fd_handlers(ser2net_sel, sig_fd_watch);
405 free_rotators();
406 free_controllers();
407 shutdown_ports();
408 do {
409 if (check_ports_shutdown())
410 break;
411 tv.tv_sec = 1;
412 tv.tv_usec = 0;
413 sel_select(ser2net_sel, NULL, 0, NULL, &tv);
414 } while(1);
415
416 sol_shutdown(); /* Free's the selector. */
417
418 free_longstrs();
419 free_tracefiles();
420 free_rs485confs();
421
422 if (pid_file)
423 unlink(pid_file);
424
425 exit(1);
426 }
427
428 static void
shutdown_cleanly(void)429 shutdown_cleanly(void)
430 {
431 stop_threads(finish_shutdown_cleanly);
432 }
433
434 static void
sig_fd_read_handler(int fd,void * cb_data)435 sig_fd_read_handler(int fd, void *cb_data)
436 {
437 char dummy[10];
438
439 dummyrv = read(fd, dummy, sizeof(dummy));
440
441 if (term_prog)
442 shutdown_cleanly();
443
444 if (reread_config && !in_shutdown) {
445 #if USE_PTHREADS
446 thread_reread_config_file();
447 #else
448 reread_config_file();
449 #endif
450 }
451 }
452
453 static void
setup_signals(void)454 setup_signals(void)
455 {
456 struct sigaction act;
457 int err;
458 int pipefds[2];
459
460 /* Ignore SIGPIPEs so they don't kill us. */
461 signal(SIGPIPE, SIG_IGN);
462
463 err = pipe(pipefds);
464 if (err)
465 goto out;
466
467 sig_fd_alert = pipefds[1];
468 sig_fd_watch = pipefds[0];
469
470 act.sa_handler = sighup_handler;
471 sigemptyset(&act.sa_mask);
472 act.sa_flags = SA_RESTART;
473 err = sigaction(SIGHUP, &act, NULL);
474 if (err)
475 goto out;
476
477 act.sa_handler = sigint_handler;
478 /* Only handle SIGINT once. */
479 act.sa_flags |= SA_RESETHAND;
480 err = sigaction(SIGINT, &act, NULL);
481 if (!err)
482 err = sigaction(SIGQUIT, &act, NULL);
483 if (!err)
484 err = sigaction(SIGTERM, &act, NULL);
485 if (err)
486 goto out;
487
488 sel_set_fd_handlers(ser2net_sel, sig_fd_watch, NULL, sig_fd_read_handler,
489 NULL, NULL, NULL);
490 sel_set_fd_read_handler(ser2net_sel, sig_fd_watch, SEL_FD_HANDLER_ENABLED);
491
492 out:
493 if (err) {
494 fprintf(stderr, "Error setting up signals: %s\n", strerror(errno));
495 exit(1);
496 }
497 }
498
499 int
main(int argc,char * argv[])500 main(int argc, char *argv[])
501 {
502 int i;
503 int err;
504 #ifdef USE_PTHREADS
505 char *end;
506 #endif
507 char **config_lines;
508 int num_config_lines = 0;
509
510 config_lines = malloc(sizeof(*config_lines));
511 if (!config_lines) {
512 fprintf(stderr, "Out of memory\n");
513 exit(1);
514 }
515 *config_lines = NULL;
516
517 if (led_driver_init() < 0) {
518 fprintf(stderr, "Error while initializing LED drivers\n");
519 exit(1);
520 }
521
522 for (i = 1; i < argc; i++) {
523 if ((argv[i][0] != '-') || (strlen(argv[i]) != 2)) {
524 fprintf(stderr, "Invalid argument: '%s'\n", argv[i]);
525 arg_error(argv[0]);
526 }
527
528 switch (argv[i][1]) {
529 case 'n':
530 detach = 0;
531 break;
532
533 case 'd':
534 detach = 0;
535 ser2net_debug = 1;
536 break;
537
538 case 'l':
539 ser2net_debug_level++;
540 break;
541
542 case 'b':
543 break;
544
545 case 'C':
546 /* Get a config line. */
547 i++;
548 if (i == argc) {
549 fprintf(stderr, "No config line specified with -C\n");
550 arg_error(argv[0]);
551 }
552 num_config_lines++;
553 config_lines = realloc(config_lines, sizeof(*config_lines) *
554 (num_config_lines + 1));
555 if (!config_lines) {
556 fprintf(stderr, "Out of memory handling config line\n");
557 exit(1);
558 }
559 config_lines[num_config_lines - 1] = argv[i];
560 config_file = NULL;
561 break;
562
563 case 'c':
564 /* Get a config file. */
565 i++;
566 if (i == argc) {
567 fprintf(stderr, "No config file specified with -c\n");
568 arg_error(argv[0]);
569 }
570 config_file = argv[i];
571 break;
572
573 case 'p':
574 /* Get the control port. */
575 i++;
576 if (i == argc) {
577 fprintf(stderr, "No control port specified with -p\n");
578 arg_error(argv[0]);
579 }
580 config_port = strdup(argv[i]);
581 if (!config_port) {
582 fprintf(stderr, "Could not allocate memory for -p\n");
583 exit(1);
584 }
585 config_port_from_cmdline = 1;
586 break;
587
588 case 'P':
589 i++;
590 if (i == argc) {
591 fprintf(stderr, "No pid file specified with -P\n");
592 arg_error(argv[0]);
593 }
594 pid_file = argv[i];
595 break;
596
597 #ifdef USE_UUCP_LOCKING
598 case 'u':
599 uucp_locking_enabled = 0;
600 break;
601 #endif
602
603 case 'v':
604 printf("%s version %s\n", argv[0], VERSION);
605 exit(0);
606
607 case 's':
608 i++;
609 if (i == argc) {
610 fprintf(stderr, "No signature specified\n");
611 exit(1);
612 }
613 rfc2217_signature = argv[i];
614 break;
615
616 #ifdef USE_PTHREADS
617 case 't':
618 i++;
619 if (i == argc) {
620 fprintf(stderr, "No thread count specified\n");
621 exit(1);
622 }
623 num_threads = strtoul(argv[i], &end, 10);
624 if (end == argv[i] || *end != '\0') {
625 fprintf(stderr, "Invalid thread count specified: %s\n",
626 argv[i]);
627 exit(1);
628 }
629 break;
630 #endif
631
632 default:
633 fprintf(stderr, "Invalid option: '%s'\n", argv[i]);
634 arg_error(argv[0]);
635 }
636 }
637
638 #ifdef USE_PTHREADS
639 if (num_threads > 1)
640 err = sel_alloc_selector_thread(&ser2net_sel, ser2net_wake_sig,
641 slock_alloc, slock_free,
642 slock_lock, slock_unlock, NULL);
643 else
644 #endif
645 err = sel_alloc_selector_nothread(&ser2net_sel);
646
647 if (err) {
648 fprintf(stderr,
649 "Could not initialize ser2net selector: '%s'\n",
650 strerror(err));
651 exit(1);
652 }
653
654 setup_signals();
655
656 err = sol_init();
657 if (err) {
658 fprintf(stderr,
659 "Could not initialize IPMI SOL: '%s'\n",
660 strerror(-err));
661 exit(1);
662 }
663
664 if (ser2net_debug && !detach)
665 openlog("ser2net", LOG_PID | LOG_CONS | LOG_PERROR, LOG_DAEMON);
666
667 readconfig_init();
668 for (i = 0; i < num_config_lines; i++)
669 handle_config_line(config_lines[i], strlen(config_lines[i]));
670 free(config_lines);
671 if (config_file) {
672 if (readconfig(config_file) == -1)
673 exit(1);
674 }
675
676 if (config_port != NULL) {
677 int rv;
678 rv = controller_init(config_port);
679 if (rv == CONTROLLER_INVALID_TCP_SPEC) {
680 fprintf(stderr, "Invalid control port specified: %s\n",
681 config_port);
682 arg_error(argv[0]);
683 }
684 if (rv == CONTROLLER_CANT_OPEN_PORT) {
685 fprintf(stderr, "Unable to open control port, see syslog: %s\n",
686 config_port);
687 exit(1);
688 }
689 }
690
691 if (detach) {
692 int pid;
693
694 /* Detach from the calling terminal. */
695 openlog("ser2net", LOG_PID | LOG_CONS, LOG_DAEMON);
696 syslog(LOG_NOTICE, "ser2net startup");
697 if ((pid = fork()) > 0) {
698 exit(0);
699 } else if (pid < 0) {
700 syslog(LOG_ERR, "Error forking first fork: %s", strerror(errno));
701 exit(1);
702 } else {
703 /* setsid() is necessary if we really want to demonize */
704 setsid();
705 /* Second fork to really deamonize me. */
706 if ((pid = fork()) > 0) {
707 exit(0);
708 } else if (pid < 0) {
709 syslog(LOG_ERR, "Error forking second fork: %s",
710 strerror(errno));
711 exit(1);
712 }
713 }
714
715 /* Close all my standard I/O. */
716 if (chdir("/") < 0) {
717 syslog(LOG_ERR, "unable to chdir to '/': %s", strerror(errno));
718 exit(1);
719 }
720 close(0);
721 close(1);
722 close(2);
723 }
724
725 /* write pid file */
726 make_pidfile();
727
728 start_threads();
729 op_loop(NULL);
730
731 sel_free_selector(ser2net_sel);
732
733 return 0;
734 }
735