2 * BIRD Internet Routing Daemon -- Unix Entry Point
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
23 #include <sys/utsname.h>
26 #include "nest/bird.h"
27 #include "lib/lists.h"
28 #include "lib/resource.h"
29 #include "lib/socket.h"
30 #include "lib/event.h"
31 #include "lib/timer.h"
32 #include "lib/string.h"
33 #include "nest/route.h"
34 #include "nest/protocol.h"
35 #include "nest/iface.h"
37 #include "nest/locks.h"
38 #include "conf/conf.h"
39 #include "filter/filter.h"
40 #include "filter/data.h"
52 debug("INTERNAL STATE DUMP\n\n");
56 // XXXX tm_dump_all();
70 #ifdef CONFIG_RESTRICTED_PRIVILEGES
71 #include CONFIG_INCLUDE_SYSPRIV_H
75 drop_uid(uid_t uid UNUSED
)
77 die("Cannot change user on this platform");
88 if (setgroups(0, NULL
) < 0)
97 get_hostname(linpool
*lp
)
99 struct utsname uts
= {};
104 return lp_strdup(lp
, uts
.nodename
);
108 * Reading the Configuration
111 #ifdef PATH_IPROUTE_DIR
114 add_num_const(char *name
, int val
, const char *file
, const uint line
)
116 struct f_val
*v
= cfg_alloc(sizeof(struct f_val
));
117 *v
= (struct f_val
) { .type
= T_INT
, .val
.i
= val
};
118 struct symbol
*sym
= cf_get_symbol(name
);
119 if (sym
->class && (sym
->scope
== conf_this_scope
))
120 cf_error("Error reading value for %s from %s:%d: already defined", name
, file
, line
);
122 cf_define_symbol(sym
, SYM_CONSTANT
| T_INT
, val
, v
);
125 /* the code of read_iproute_table() is based on
126 rtnl_tab_initialize() from iproute2 package */
128 read_iproute_table(char *file
, char *prefix
, uint max
)
130 char buf
[512], namebuf
[512];
135 strcpy(namebuf
, prefix
);
136 name
= namebuf
+ strlen(prefix
);
138 fp
= fopen(file
, "r");
142 for (uint line
= 1; fgets(buf
, sizeof(buf
), fp
); line
++)
146 while (*p
== ' ' || *p
== '\t')
149 if (*p
== '#' || *p
== '\n' || *p
== 0)
152 if (sscanf(p
, "0x%x %s\n", &val
, name
) != 2 &&
153 sscanf(p
, "0x%x %s #", &val
, name
) != 2 &&
154 sscanf(p
, "%u %s\n", &val
, name
) != 2 &&
155 sscanf(p
, "%u %s #", &val
, name
) != 2)
161 for(p
= name
; *p
; p
++)
162 if ((*p
< 'a' || *p
> 'z') && (*p
< 'A' || *p
> 'Z') && (*p
< '0' || *p
> '9') && (*p
!= '_'))
165 add_num_const(namebuf
, val
, file
, line
);
171 #endif // PATH_IPROUTE_DIR
174 static char *config_name
= PATH_CONFIG_FILE
;
177 cf_read(byte
*dest
, uint len
, int fd
)
179 int l
= read(fd
, dest
, len
);
181 cf_error("Read error");
186 sysdep_preconfig(struct config
*c
)
188 init_list(&c
->logfiles
);
190 c
->latency_limit
= UNIX_DEFAULT_LATENCY_LIMIT
;
191 c
->watchdog_warning
= UNIX_DEFAULT_WATCHDOG_WARNING
;
193 #ifdef PATH_IPROUTE_DIR
194 read_iproute_table(PATH_IPROUTE_DIR
"/rt_protos", "ipp_", 255);
195 read_iproute_table(PATH_IPROUTE_DIR
"/rt_realms", "ipr_", 0xffffffff);
196 read_iproute_table(PATH_IPROUTE_DIR
"/rt_scopes", "ips_", 255);
197 read_iproute_table(PATH_IPROUTE_DIR
"/rt_tables", "ipt_", 0xffffffff);
202 sysdep_commit(struct config
*new, struct config
*old UNUSED
)
204 log_switch(0, &new->logfiles
, new->syslog_name
);
209 unix_read_config(struct config
**cp
, const char *name
)
211 struct config
*conf
= config_alloc(name
);
215 conf
->file_fd
= open(name
, O_RDONLY
);
216 if (conf
->file_fd
< 0)
218 cf_read_hook
= cf_read
;
219 ret
= config_parse(conf
);
220 close(conf
->file_fd
);
224 static struct config
*
229 if (!unix_read_config(&conf
, config_name
))
232 die("%s:%d:%d %s", conf
->err_file_name
, conf
->err_lino
, conf
->err_chno
, conf
->err_msg
);
234 die("Unable to open configuration file %s: %m", config_name
);
245 log(L_INFO
"Reconfiguration requested by SIGHUP");
246 if (!unix_read_config(&conf
, config_name
))
249 log(L_ERR
"%s:%d:%d %s", conf
->err_file_name
, conf
->err_lino
, conf
->err_chno
, conf
->err_msg
);
251 log(L_ERR
"Unable to open configuration file %s: %m", config_name
);
255 config_commit(conf
, RECONFIG_HARD
, 0);
258 static struct config
*
259 cmd_read_config(const char *name
)
266 cli_msg(-2, "Reading configuration from %s", name
);
267 if (!unix_read_config(&conf
, name
))
270 cli_msg(8002, "%s:%d:%d %s", conf
->err_file_name
, conf
->err_lino
, conf
->err_chno
, conf
->err_msg
);
272 cli_msg(8002, "%s: %m", name
);
281 cmd_check_config(const char *name
)
283 struct config
*conf
= cmd_read_config(name
);
287 cli_msg(20, "Configuration OK");
292 cmd_reconfig_msg(int r
)
296 case CONF_DONE
: cli_msg( 3, "Reconfigured"); break;
297 case CONF_PROGRESS
: cli_msg( 4, "Reconfiguration in progress"); break;
298 case CONF_QUEUED
: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break;
299 case CONF_UNQUEUED
: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break;
300 case CONF_CONFIRM
: cli_msg(18, "Reconfiguration confirmed"); break;
301 case CONF_SHUTDOWN
: cli_msg( 6, "Reconfiguration ignored, shutting down"); break;
302 case CONF_NOTHING
: cli_msg(19, "Nothing to do"); break;
307 /* Hack for scheduled undo notification */
308 cli
*cmd_reconfig_stored_cli
;
311 cmd_reconfig_undo_notify(void)
313 if (cmd_reconfig_stored_cli
)
315 cli
*c
= cmd_reconfig_stored_cli
;
316 cli_printf(c
, CLI_ASYNC_CODE
, "Config timeout expired, starting undo");
317 cli_write_trigger(c
);
322 cmd_reconfig(const char *name
, int type
, uint timeout
)
324 if (cli_access_restricted())
327 struct config
*conf
= cmd_read_config(name
);
331 int r
= config_commit(conf
, type
, timeout
);
333 if ((r
>= 0) && (timeout
> 0))
335 cmd_reconfig_stored_cli
= this_cli
;
336 cli_msg(-22, "Undo scheduled in %d s", timeout
);
343 cmd_reconfig_confirm(void)
345 if (cli_access_restricted())
348 int r
= config_confirm();
353 cmd_reconfig_undo(void)
355 if (cli_access_restricted())
358 cli_msg(-21, "Undo requested");
360 int r
= config_undo();
365 cmd_reconfig_status(void)
367 int s
= config_status();
368 btime t
= config_timer_status();
372 case CONF_DONE
: cli_msg(-3, "Daemon is up and running"); break;
373 case CONF_PROGRESS
: cli_msg(-4, "Reconfiguration in progress"); break;
374 case CONF_QUEUED
: cli_msg(-5, "Reconfiguration in progress, next one enqueued"); break;
375 case CONF_SHUTDOWN
: cli_msg(-6, "Shutdown in progress"); break;
380 cli_msg(-22, "Configuration unconfirmed, undo in %t s", t
);
387 * Command-Line Interface
391 static char *path_control_socket
= PATH_CONTROL_SOCKET
;
401 struct cli_out
*o
= c
->tx_pos
;
403 int len
= o
->wpos
- o
->outpos
;
407 if (sk_send(s
, len
) <= 0)
413 /* Everything is written */
419 cli_write_trigger(cli
*c
)
434 cli_get_command(cli
*c
)
437 byte
*t
= c
->rx_aux
? : s
->rbuf
;
438 byte
*tend
= s
->rpos
;
440 byte
*dend
= c
->rx_buf
+ CLI_RX_BUF_SIZE
- 2;
449 c
->rx_pos
= c
->rx_buf
;
452 return (d
< dend
) ? 1 : -1;
457 c
->rx_aux
= s
->rpos
= s
->rbuf
;
463 cli_rx(sock
*s
, uint size UNUSED
)
470 cli_err(sock
*s
, int err
)
472 if (config
->cli_debug
)
475 log(L_INFO
"CLI connection dropped: %s", strerror(err
));
477 log(L_INFO
"CLI connection closed");
483 cli_connect_err(sock
*s UNUSED
, int err
)
486 if (config
->cli_debug
)
487 log(L_INFO
"Failed to accept CLI connection: %s", strerror(err
));
491 cli_connect(sock
*s
, uint size UNUSED
)
495 if (config
->cli_debug
)
496 log(L_INFO
"CLI connect");
499 s
->err_hook
= cli_err
;
500 s
->data
= c
= cli_new(s
);
501 s
->pool
= c
->pool
; /* We need to have all the socket buffers allocated in the cli pool */
503 c
->rx_pos
= c
->rx_buf
;
510 cli_init_unix(uid_t use_uid
, gid_t use_gid
)
515 s
= cli_sk
= sk_new(cli_pool
);
516 s
->type
= SK_UNIX_PASSIVE
;
517 s
->rx_hook
= cli_connect
;
518 s
->err_hook
= cli_connect_err
;
522 /* Return value intentionally ignored */
523 unlink(path_control_socket
);
525 if (sk_open_unix(s
, path_control_socket
) < 0)
526 die("Cannot create control socket %s: %m", path_control_socket
);
528 if (use_uid
|| use_gid
)
529 if (chown(path_control_socket
, use_uid
, use_gid
) < 0)
532 if (chmod(path_control_socket
, 0660) < 0)
540 static char *pid_file
;
549 pid_fd
= open(pid_file
, O_WRONLY
|O_CREAT
, 0664);
551 die("Cannot create PID file %s: %m", pid_file
);
563 /* We don't use PID file for uniqueness, so no need for locking */
565 pl
= bsnprintf(ps
, sizeof(ps
), "%ld\n", (s64
) getpid());
567 bug("PID buffer too small");
569 rv
= ftruncate(pid_fd
, 0);
573 rv
= write(pid_fd
, ps
, pl
);
581 unlink_pid_file(void)
595 if (cli_access_restricted())
598 cli_msg(7, "Shutdown requested");
605 DBG("Shutting down...\n");
610 sysdep_shutdown_done(void)
613 unlink(path_control_socket
);
614 log_msg(L_FATAL
"Shutdown completed");
619 cmd_graceful_restart(void)
621 if (cli_access_restricted())
624 cli_msg(25, "Graceful restart requested");
633 volatile sig_atomic_t async_config_flag
;
634 volatile sig_atomic_t async_dump_flag
;
635 volatile sig_atomic_t async_shutdown_flag
;
638 handle_sighup(int sig UNUSED
)
640 DBG("Caught SIGHUP...\n");
641 async_config_flag
= 1;
645 handle_sigusr(int sig UNUSED
)
647 DBG("Caught SIGUSR...\n");
652 handle_sigterm(int sig UNUSED
)
654 DBG("Caught SIGTERM...\n");
655 async_shutdown_flag
= 1;
658 void watchdog_sigalrm(int sig UNUSED
);
665 bzero(&sa
, sizeof(sa
));
666 sa
.sa_handler
= handle_sigusr
;
667 sa
.sa_flags
= SA_RESTART
;
668 sigaction(SIGUSR1
, &sa
, NULL
);
669 sa
.sa_handler
= handle_sighup
;
670 sa
.sa_flags
= SA_RESTART
;
671 sigaction(SIGHUP
, &sa
, NULL
);
672 sa
.sa_handler
= handle_sigterm
;
673 sa
.sa_flags
= SA_RESTART
;
674 sigaction(SIGTERM
, &sa
, NULL
);
675 sa
.sa_handler
= watchdog_sigalrm
;
677 sigaction(SIGALRM
, &sa
, NULL
);
678 signal(SIGPIPE
, SIG_IGN
);
682 * Parsing of command-line arguments
685 static char *opt_list
= "bc:dD:ps:P:u:g:flRh";
688 static char *use_user
;
689 static char *use_group
;
690 static int run_in_foreground
= 0;
695 fprintf(stderr
, "Usage: %s [--version] [--help] [-c <config-file>] [OPTIONS]\n", bird_name
);
706 " -c <config-file> Use given configuration file instead of\n"
707 " " PATH_CONFIG_FILE
"\n"
708 " -d Enable debug messages and run bird in foreground\n"
709 " -D <debug-file> Log debug messages to given file instead of stderr\n"
710 " -f Run bird in foreground\n"
711 " -g <group> Use given group ID\n"
712 " -h, --help Display this information\n"
713 " -l Look for a configuration file and a control socket\n"
714 " in the current working directory\n"
715 " -p Test configuration file and exit without start\n"
716 " -P <pid-file> Create a PID file with given filename\n"
717 " -R Apply graceful restart recovery after start\n"
718 " -s <control-socket> Use given filename for a control socket\n"
719 " -u <user> Drop privileges and use given user ID\n"
720 " --version Display version of BIRD\n");
726 display_version(void)
728 fprintf(stderr
, "BIRD version " BIRD_VERSION
"\n");
733 get_bird_name(char *s
, char *def
)
747 get_uid(const char *s
)
757 rv
= strtol(s
, &endptr
, 10);
759 if (!errno
&& !*endptr
)
764 die("Cannot find user '%s'", s
);
770 get_gid(const char *s
)
780 rv
= strtol(s
, &endptr
, 10);
782 if (!errno
&& !*endptr
)
787 die("Cannot find group '%s'", s
);
793 parse_args(int argc
, char **argv
)
795 int config_changed
= 0;
796 int socket_changed
= 0;
799 bird_name
= get_bird_name(argv
[0], "bird");
802 if (!strcmp(argv
[1], "--version"))
804 if (!strcmp(argv
[1], "--help"))
807 while ((c
= getopt(argc
, argv
, opt_list
)) >= 0)
811 config_name
= optarg
;
816 run_in_foreground
= 1;
819 log_init_debug(optarg
);
825 path_control_socket
= optarg
;
838 run_in_foreground
= 1;
842 config_name
= xbasename(config_name
);
844 path_control_socket
= xbasename(path_control_socket
);
847 graceful_restart_recovery();
869 main(int argc
, char **argv
)
871 #ifdef HAVE_LIBDMALLOC
872 if (!getenv("DMALLOC_OPTIONS"))
873 dmalloc_debug(0x2f03d00);
876 parse_args(argc
, argv
);
877 log_switch(1, NULL
, NULL
);
890 uid_t use_uid
= get_uid(use_user
);
891 gid_t use_gid
= get_gid(use_group
);
895 test_old_bird(path_control_socket
);
896 cli_init_unix(use_uid
, use_gid
);
910 struct config
*conf
= read_config();
915 if (!run_in_foreground
)
924 if (open("/dev/null", O_RDWR
) < 0)
925 die("Cannot open /dev/null: %m");
936 config_commit(conf
, RECONFIG_HARD
, 0);
938 graceful_restart_init();
944 log(L_INFO
"Started");
945 DBG("Entering I/O loop.\n");
948 bug("I/O loop died");