]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/unix/main.c
Merge branch 'master' into int-new
[thirdparty/bird.git] / sysdep / unix / main.c
1 /*
2 * BIRD Internet Routing Daemon -- Unix Entry Point
3 *
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #undef LOCAL_DEBUG
10
11 #ifndef _GNU_SOURCE
12 #define _GNU_SOURCE
13 #endif
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <signal.h>
20 #include <pwd.h>
21 #include <grp.h>
22 #include <sys/stat.h>
23 #include <libgen.h>
24
25 #include "nest/bird.h"
26 #include "lib/lists.h"
27 #include "lib/resource.h"
28 #include "lib/socket.h"
29 #include "lib/event.h"
30 #include "lib/timer.h"
31 #include "lib/string.h"
32 #include "nest/route.h"
33 #include "nest/protocol.h"
34 #include "nest/iface.h"
35 #include "nest/cli.h"
36 #include "nest/locks.h"
37 #include "conf/conf.h"
38 #include "filter/filter.h"
39
40 #include "unix.h"
41 #include "krt.h"
42
43 /*
44 * Debugging
45 */
46
47 #ifdef DEBUGGING
48 static int debug_flag = 1;
49 #else
50 static int debug_flag = 0;
51 #endif
52
53 void
54 async_dump(void)
55 {
56 debug("INTERNAL STATE DUMP\n\n");
57
58 rdump(&root_pool);
59 sk_dump_all();
60 // XXXX tm_dump_all();
61 if_dump_all();
62 neigh_dump_all();
63 rta_dump_all();
64 rt_dump_all();
65 protos_dump_all();
66
67 debug("\n");
68 }
69
70 /*
71 * Dropping privileges
72 */
73
74 #ifdef CONFIG_RESTRICTED_PRIVILEGES
75 #include CONFIG_INCLUDE_SYSPRIV_H
76 #else
77
78 static inline void
79 drop_uid(uid_t uid UNUSED)
80 {
81 die("Cannot change user on this platform");
82 }
83
84 #endif
85
86 static inline void
87 drop_gid(gid_t gid)
88 {
89 if (setgid(gid) < 0)
90 die("setgid: %m");
91 }
92
93 /*
94 * Reading the Configuration
95 */
96
97 #ifdef PATH_IPROUTE_DIR
98
99 static inline void
100 add_num_const(char *name, int val)
101 {
102 struct symbol *s = cf_get_symbol(name);
103 s->class = SYM_CONSTANT | T_INT;
104 s->def = cfg_allocz(sizeof(struct f_val));
105 SYM_TYPE(s) = T_INT;
106 SYM_VAL(s).i = val;
107 }
108
109 /* the code of read_iproute_table() is based on
110 rtnl_tab_initialize() from iproute2 package */
111 static void
112 read_iproute_table(char *file, char *prefix, int max)
113 {
114 char buf[512], namebuf[512];
115 char *name;
116 int val;
117 FILE *fp;
118
119 strcpy(namebuf, prefix);
120 name = namebuf + strlen(prefix);
121
122 fp = fopen(file, "r");
123 if (!fp)
124 return;
125
126 while (fgets(buf, sizeof(buf), fp))
127 {
128 char *p = buf;
129
130 while (*p == ' ' || *p == '\t')
131 p++;
132
133 if (*p == '#' || *p == '\n' || *p == 0)
134 continue;
135
136 if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
137 sscanf(p, "0x%x %s #", &val, name) != 2 &&
138 sscanf(p, "%d %s\n", &val, name) != 2 &&
139 sscanf(p, "%d %s #", &val, name) != 2)
140 continue;
141
142 if (val < 0 || val > max)
143 continue;
144
145 for(p = name; *p; p++)
146 if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
147 *p = '_';
148
149 add_num_const(namebuf, val);
150 }
151
152 fclose(fp);
153 }
154
155 #endif // PATH_IPROUTE_DIR
156
157
158 static char *config_name = PATH_CONFIG_FILE;
159
160 static int
161 cf_read(byte *dest, uint len, int fd)
162 {
163 int l = read(fd, dest, len);
164 if (l < 0)
165 cf_error("Read error");
166 return l;
167 }
168
169 void
170 sysdep_preconfig(struct config *c)
171 {
172 init_list(&c->logfiles);
173
174 c->latency_limit = UNIX_DEFAULT_LATENCY_LIMIT;
175 c->watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING;
176
177 #ifdef PATH_IPROUTE_DIR
178 read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
179 read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
180 read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
181 read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
182 #endif
183 }
184
185 int
186 sysdep_commit(struct config *new, struct config *old UNUSED)
187 {
188 log_switch(debug_flag, &new->logfiles, new->syslog_name);
189 return 0;
190 }
191
192 static int
193 unix_read_config(struct config **cp, char *name)
194 {
195 struct config *conf = config_alloc(name);
196 int ret;
197
198 *cp = conf;
199 conf->file_fd = open(name, O_RDONLY);
200 if (conf->file_fd < 0)
201 return 0;
202 cf_read_hook = cf_read;
203 ret = config_parse(conf);
204 close(conf->file_fd);
205 return ret;
206 }
207
208 static struct config *
209 read_config(void)
210 {
211 struct config *conf;
212
213 if (!unix_read_config(&conf, config_name))
214 {
215 if (conf->err_msg)
216 die("%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
217 else
218 die("Unable to open configuration file %s: %m", config_name);
219 }
220
221 return conf;
222 }
223
224 void
225 async_config(void)
226 {
227 struct config *conf;
228
229 log(L_INFO "Reconfiguration requested by SIGHUP");
230 if (!unix_read_config(&conf, config_name))
231 {
232 if (conf->err_msg)
233 log(L_ERR "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
234 else
235 log(L_ERR "Unable to open configuration file %s: %m", config_name);
236 config_free(conf);
237 }
238 else
239 config_commit(conf, RECONFIG_HARD, 0);
240 }
241
242 static struct config *
243 cmd_read_config(char *name)
244 {
245 struct config *conf;
246
247 if (!name)
248 name = config_name;
249
250 cli_msg(-2, "Reading configuration from %s", name);
251 if (!unix_read_config(&conf, name))
252 {
253 if (conf->err_msg)
254 cli_msg(8002, "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
255 else
256 cli_msg(8002, "%s: %m", name);
257 config_free(conf);
258 conf = NULL;
259 }
260
261 return conf;
262 }
263
264 void
265 cmd_check_config(char *name)
266 {
267 struct config *conf = cmd_read_config(name);
268 if (!conf)
269 return;
270
271 cli_msg(20, "Configuration OK");
272 config_free(conf);
273 }
274
275 static void
276 cmd_reconfig_msg(int r)
277 {
278 switch (r)
279 {
280 case CONF_DONE: cli_msg( 3, "Reconfigured"); break;
281 case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break;
282 case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break;
283 case CONF_UNQUEUED: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break;
284 case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break;
285 case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break;
286 case CONF_NOTHING: cli_msg(19, "Nothing to do"); break;
287 default: break;
288 }
289 }
290
291 /* Hack for scheduled undo notification */
292 cli *cmd_reconfig_stored_cli;
293
294 void
295 cmd_reconfig_undo_notify(void)
296 {
297 if (cmd_reconfig_stored_cli)
298 {
299 cli *c = cmd_reconfig_stored_cli;
300 cli_printf(c, CLI_ASYNC_CODE, "Config timeout expired, starting undo");
301 cli_write_trigger(c);
302 }
303 }
304
305 void
306 cmd_reconfig(char *name, int type, uint timeout)
307 {
308 if (cli_access_restricted())
309 return;
310
311 struct config *conf = cmd_read_config(name);
312 if (!conf)
313 return;
314
315 int r = config_commit(conf, type, timeout);
316
317 if ((r >= 0) && (timeout > 0))
318 {
319 cmd_reconfig_stored_cli = this_cli;
320 cli_msg(-22, "Undo scheduled in %d s", timeout);
321 }
322
323 cmd_reconfig_msg(r);
324 }
325
326 void
327 cmd_reconfig_confirm(void)
328 {
329 if (cli_access_restricted())
330 return;
331
332 int r = config_confirm();
333 cmd_reconfig_msg(r);
334 }
335
336 void
337 cmd_reconfig_undo(void)
338 {
339 if (cli_access_restricted())
340 return;
341
342 cli_msg(-21, "Undo requested");
343
344 int r = config_undo();
345 cmd_reconfig_msg(r);
346 }
347
348 /*
349 * Command-Line Interface
350 */
351
352 static sock *cli_sk;
353 static char *path_control_socket = PATH_CONTROL_SOCKET;
354
355
356 static void
357 cli_write(cli *c)
358 {
359 sock *s = c->priv;
360
361 while (c->tx_pos)
362 {
363 struct cli_out *o = c->tx_pos;
364
365 int len = o->wpos - o->outpos;
366 s->tbuf = o->outpos;
367 o->outpos = o->wpos;
368
369 if (sk_send(s, len) <= 0)
370 return;
371
372 c->tx_pos = o->next;
373 }
374
375 /* Everything is written */
376 s->tbuf = NULL;
377 cli_written(c);
378 }
379
380 void
381 cli_write_trigger(cli *c)
382 {
383 sock *s = c->priv;
384
385 if (s->tbuf == NULL)
386 cli_write(c);
387 }
388
389 static void
390 cli_tx(sock *s)
391 {
392 cli_write(s->data);
393 }
394
395 int
396 cli_get_command(cli *c)
397 {
398 sock *s = c->priv;
399 byte *t = c->rx_aux ? : s->rbuf;
400 byte *tend = s->rpos;
401 byte *d = c->rx_pos;
402 byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
403
404 while (t < tend)
405 {
406 if (*t == '\r')
407 t++;
408 else if (*t == '\n')
409 {
410 t++;
411 c->rx_pos = c->rx_buf;
412 c->rx_aux = t;
413 *d = 0;
414 return (d < dend) ? 1 : -1;
415 }
416 else if (d < dend)
417 *d++ = *t++;
418 }
419 c->rx_aux = s->rpos = s->rbuf;
420 c->rx_pos = d;
421 return 0;
422 }
423
424 static int
425 cli_rx(sock *s, uint size UNUSED)
426 {
427 cli_kick(s->data);
428 return 0;
429 }
430
431 static void
432 cli_err(sock *s, int err)
433 {
434 if (config->cli_debug)
435 {
436 if (err)
437 log(L_INFO "CLI connection dropped: %s", strerror(err));
438 else
439 log(L_INFO "CLI connection closed");
440 }
441 cli_free(s->data);
442 }
443
444 static int
445 cli_connect(sock *s, uint size UNUSED)
446 {
447 cli *c;
448
449 if (config->cli_debug)
450 log(L_INFO "CLI connect");
451 s->rx_hook = cli_rx;
452 s->tx_hook = cli_tx;
453 s->err_hook = cli_err;
454 s->data = c = cli_new(s);
455 s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
456 s->fast_rx = 1;
457 c->rx_pos = c->rx_buf;
458 c->rx_aux = NULL;
459 rmove(s, c->pool);
460 return 1;
461 }
462
463 static void
464 cli_init_unix(uid_t use_uid, gid_t use_gid)
465 {
466 sock *s;
467
468 cli_init();
469 s = cli_sk = sk_new(cli_pool);
470 s->type = SK_UNIX_PASSIVE;
471 s->rx_hook = cli_connect;
472 s->rbsize = 1024;
473 s->fast_rx = 1;
474
475 /* Return value intentionally ignored */
476 unlink(path_control_socket);
477
478 if (sk_open_unix(s, path_control_socket) < 0)
479 die("Cannot create control socket %s: %m", path_control_socket);
480
481 if (use_uid || use_gid)
482 if (chown(path_control_socket, use_uid, use_gid) < 0)
483 die("chown: %m");
484
485 if (chmod(path_control_socket, 0660) < 0)
486 die("chmod: %m");
487 }
488
489 /*
490 * PID file
491 */
492
493 static char *pid_file;
494 static int pid_fd;
495
496 static inline void
497 open_pid_file(void)
498 {
499 if (!pid_file)
500 return;
501
502 pid_fd = open(pid_file, O_WRONLY|O_CREAT, 0664);
503 if (pid_fd < 0)
504 die("Cannot create PID file %s: %m", pid_file);
505 }
506
507 static inline void
508 write_pid_file(void)
509 {
510 int pl, rv;
511 char ps[24];
512
513 if (!pid_file)
514 return;
515
516 /* We don't use PID file for uniqueness, so no need for locking */
517
518 pl = bsnprintf(ps, sizeof(ps), "%ld\n", (long) getpid());
519 if (pl < 0)
520 bug("PID buffer too small");
521
522 rv = ftruncate(pid_fd, 0);
523 if (rv < 0)
524 die("fruncate: %m");
525
526 rv = write(pid_fd, ps, pl);
527 if(rv < 0)
528 die("write: %m");
529
530 close(pid_fd);
531 }
532
533 static inline void
534 unlink_pid_file(void)
535 {
536 if (pid_file)
537 unlink(pid_file);
538 }
539
540
541 /*
542 * Shutdown
543 */
544
545 void
546 cmd_shutdown(void)
547 {
548 if (cli_access_restricted())
549 return;
550
551 cli_msg(7, "Shutdown requested");
552 order_shutdown();
553 }
554
555 void
556 async_shutdown(void)
557 {
558 DBG("Shutting down...\n");
559 order_shutdown();
560 }
561
562 void
563 sysdep_shutdown_done(void)
564 {
565 unlink_pid_file();
566 unlink(path_control_socket);
567 log_msg(L_FATAL "Shutdown completed");
568 exit(0);
569 }
570
571 /*
572 * Signals
573 */
574
575 volatile int async_config_flag;
576 volatile int async_dump_flag;
577 volatile int async_shutdown_flag;
578
579 static void
580 handle_sighup(int sig UNUSED)
581 {
582 DBG("Caught SIGHUP...\n");
583 async_config_flag = 1;
584 }
585
586 static void
587 handle_sigusr(int sig UNUSED)
588 {
589 DBG("Caught SIGUSR...\n");
590 async_dump_flag = 1;
591 }
592
593 static void
594 handle_sigterm(int sig UNUSED)
595 {
596 DBG("Caught SIGTERM...\n");
597 async_shutdown_flag = 1;
598 }
599
600 void watchdog_sigalrm(int sig UNUSED);
601
602 static void
603 signal_init(void)
604 {
605 struct sigaction sa;
606
607 bzero(&sa, sizeof(sa));
608 sa.sa_handler = handle_sigusr;
609 sa.sa_flags = SA_RESTART;
610 sigaction(SIGUSR1, &sa, NULL);
611 sa.sa_handler = handle_sighup;
612 sa.sa_flags = SA_RESTART;
613 sigaction(SIGHUP, &sa, NULL);
614 sa.sa_handler = handle_sigterm;
615 sa.sa_flags = SA_RESTART;
616 sigaction(SIGTERM, &sa, NULL);
617 sa.sa_handler = watchdog_sigalrm;
618 sa.sa_flags = 0;
619 sigaction(SIGALRM, &sa, NULL);
620 signal(SIGPIPE, SIG_IGN);
621 }
622
623 /*
624 * Parsing of command-line arguments
625 */
626
627 static char *opt_list = "c:dD:ps:P:u:g:flRh";
628 static int parse_and_exit;
629 char *bird_name;
630 static char *use_user;
631 static char *use_group;
632 static int run_in_foreground = 0;
633
634 static void
635 display_usage(void)
636 {
637 fprintf(stderr, "Usage: %s [--version] [--help] [-c <config-file>] [OPTIONS]\n", bird_name);
638 }
639
640 static void
641 display_help(void)
642 {
643 display_usage();
644
645 fprintf(stderr,
646 "\n"
647 "Options: \n"
648 " -c <config-file> Use given configuration file instead\n"
649 " of prefix/etc/bird.conf\n"
650 " -d Enable debug messages and run bird in foreground\n"
651 " -D <debug-file> Log debug messages to given file instead of stderr\n"
652 " -f Run bird in foreground\n"
653 " -g <group> Use given group ID\n"
654 " -h, --help Display this information\n"
655 " -l Look for a configuration file and a communication socket\n"
656 " file in the current working directory\n"
657 " -p Test configuration file and exit without start\n"
658 " -P <pid-file> Create a PID file with given filename\n"
659 " -R Apply graceful restart recovery after start\n"
660 " -s <control-socket> Use given filename for a control socket\n"
661 " -u <user> Drop privileges and use given user ID\n"
662 " --version Display version of BIRD\n");
663
664 exit(0);
665 }
666
667 static void
668 display_version(void)
669 {
670 fprintf(stderr, "BIRD version " BIRD_VERSION "\n");
671 exit(0);
672 }
673
674 static inline char *
675 get_bird_name(char *s, char *def)
676 {
677 char *t;
678 if (!s)
679 return def;
680 t = strrchr(s, '/');
681 if (!t)
682 return s;
683 if (!t[1])
684 return def;
685 return t+1;
686 }
687
688 static inline uid_t
689 get_uid(const char *s)
690 {
691 struct passwd *pw;
692 char *endptr;
693 long int rv;
694
695 if (!s)
696 return 0;
697
698 errno = 0;
699 rv = strtol(s, &endptr, 10);
700
701 if (!errno && !*endptr)
702 return rv;
703
704 pw = getpwnam(s);
705 if (!pw)
706 die("Cannot find user '%s'", s);
707
708 return pw->pw_uid;
709 }
710
711 static inline gid_t
712 get_gid(const char *s)
713 {
714 struct group *gr;
715 char *endptr;
716 long int rv;
717
718 if (!s)
719 return 0;
720
721 errno = 0;
722 rv = strtol(s, &endptr, 10);
723
724 if (!errno && !*endptr)
725 return rv;
726
727 gr = getgrnam(s);
728 if (!gr)
729 die("Cannot find group '%s'", s);
730
731 return gr->gr_gid;
732 }
733
734 static void
735 parse_args(int argc, char **argv)
736 {
737 int config_changed = 0;
738 int socket_changed = 0;
739 int c;
740
741 bird_name = get_bird_name(argv[0], "bird");
742 if (argc == 2)
743 {
744 if (!strcmp(argv[1], "--version"))
745 display_version();
746 if (!strcmp(argv[1], "--help"))
747 display_help();
748 }
749 while ((c = getopt(argc, argv, opt_list)) >= 0)
750 switch (c)
751 {
752 case 'c':
753 config_name = optarg;
754 config_changed = 1;
755 break;
756 case 'd':
757 debug_flag |= 1;
758 break;
759 case 'D':
760 log_init_debug(optarg);
761 debug_flag |= 2;
762 break;
763 case 'p':
764 parse_and_exit = 1;
765 break;
766 case 's':
767 path_control_socket = optarg;
768 socket_changed = 1;
769 break;
770 case 'P':
771 pid_file = optarg;
772 break;
773 case 'u':
774 use_user = optarg;
775 break;
776 case 'g':
777 use_group = optarg;
778 break;
779 case 'f':
780 run_in_foreground = 1;
781 break;
782 case 'l':
783 if (!config_changed)
784 config_name = xbasename(config_name);
785 if (!socket_changed)
786 path_control_socket = xbasename(path_control_socket);
787 break;
788 case 'R':
789 graceful_restart_recovery();
790 break;
791 case 'h':
792 display_help();
793 break;
794 default:
795 fputc('\n', stderr);
796 display_usage();
797 exit(1);
798 }
799 if (optind < argc)
800 {
801 display_usage();
802 exit(1);
803 }
804 }
805
806 /*
807 * Hic Est main()
808 */
809
810 int
811 main(int argc, char **argv)
812 {
813 #ifdef HAVE_LIBDMALLOC
814 if (!getenv("DMALLOC_OPTIONS"))
815 dmalloc_debug(0x2f03d00);
816 #endif
817
818 parse_args(argc, argv);
819 if (debug_flag == 1)
820 log_init_debug("");
821 log_switch(debug_flag, NULL, NULL);
822
823 net_init();
824 resource_init();
825 timer_init();
826 olock_init();
827 io_init();
828 rt_init();
829 if_init();
830 // roa_init();
831 config_init();
832
833 uid_t use_uid = get_uid(use_user);
834 gid_t use_gid = get_gid(use_group);
835
836 if (!parse_and_exit)
837 {
838 test_old_bird(path_control_socket);
839 cli_init_unix(use_uid, use_gid);
840 }
841
842 if (use_gid)
843 drop_gid(use_gid);
844
845 if (use_uid)
846 drop_uid(use_uid);
847
848 if (!parse_and_exit)
849 open_pid_file();
850
851 protos_build();
852 proto_build(&proto_unix_kernel);
853 proto_build(&proto_unix_iface);
854
855 struct config *conf = read_config();
856
857 if (parse_and_exit)
858 exit(0);
859
860 if (!(debug_flag||run_in_foreground))
861 {
862 pid_t pid = fork();
863 if (pid < 0)
864 die("fork: %m");
865 if (pid)
866 return 0;
867 setsid();
868 close(0);
869 if (open("/dev/null", O_RDWR) < 0)
870 die("Cannot open /dev/null: %m");
871 dup2(0, 1);
872 dup2(0, 2);
873 }
874
875 main_thread_init();
876
877 write_pid_file();
878
879 signal_init();
880
881 config_commit(conf, RECONFIG_HARD, 0);
882
883 graceful_restart_init();
884
885 #ifdef LOCAL_DEBUG
886 async_dump_flag = 1;
887 #endif
888
889 log(L_INFO "Started");
890 DBG("Entering I/O loop.\n");
891
892 io_loop();
893 bug("I/O loop died");
894 }