--- /dev/null
- sym = cf_find_symbol(TESTING_FILTER_NAME);
+/*
+ * Filters: Utility Functions Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "test/birdtest.h"
+#include <test/bt-utils.h>
+
+#include "filter/filter.h"
+#include "lib/main_helper.h"
+#include "conf/conf.h"
+
+static int
+t_simple(void)
+{
+#define TESTING_FILTER_NAME "testing_filter"
+
+ bt_bird_init();
+
+ /*
+ struct config *cfg = bt_config_parse(
+ BT_CONFIG_SIMPLE
+ "\n"
+ "filter " TESTING_FILTER_NAME "\n"
+ "{\n"
+ " if net ~ 10.0.0.0/20 then\n"
+ " accept;\n"
+ " else\n"
+ " reject;\n"
+ "}\n"
+ "\n"
+ "filter " TESTING_FILTER_NAME "2\n"
+ "{\n"
+ " if net ~ 10.0.0.0/20 then\n"
+ " accept;\n"
+ " else {\n"
+ " reject; } \n"
+ "}\n"
+ "\n"
+ );
+*/
+
+ struct symbol *sym = NULL;
- sym2 = cf_find_symbol(TESTING_FILTER_NAME "2");
++ sym = cf_get_symbol(TESTING_FILTER_NAME);
+
+ struct symbol *sym2 = NULL;
++ sym2 = cf_get_symbol(TESTING_FILTER_NAME "2");
+
+
+ struct filter *f = sym->def;
+ struct filter *f2 = sym2->def;
+ bt_assert(strcmp(filter_name(f), TESTING_FILTER_NAME) == 0);
+
+
+ bt_assert(filter_same(f,f2));
+
+// bt_debug("f_eval_asn: %u \n", f_eval_asn(f->root));
+// bt_debug("f_eval_int: %u \n", f_eval_int(f->root));
+// struct f_val v = f_eval(f->root, cfg->mem);
+// bt_debug("v type: %d \n", v.type);
+
+
+ /* TODO: check the testing filter */
+
+ return BT_SUCCESS;
+}
+
+static char *
+load_file(const char *filename)
+{
+ FILE *f = fopen(filename, "rb");
+ bt_assert_msg(f, "Cannot open file %s", filename);
+ fseek(f, 0, SEEK_END);
+ long pos = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ char *file_body = mb_allocz(&root_pool, pos+1);
+ bt_assert_msg(file_body, "Memory allocation failed for file %s", filename);
+ bt_assert_msg(fread(file_body, pos, 1, f) == 1, "Failed reading from file %s", filename);
+
+ fclose(f);
+ return file_body;
+}
+
+static int
+t_example_config_files(const void *filename_void)
+{
+ bt_bird_init();
+
+ char *filename = (char *)filename_void;
+ bt_debug("Testing BIRD configuration from %s\n", filename);
+
+ char *cfg_str = load_file(filename);
+ bt_config_parse(cfg_str);
+ mb_free(cfg_str);
+
+ config_name = filename;
+ read_config();
+ struct config *conf = read_config();
+ config_commit(conf, RECONFIG_HARD, 0);
+
+ return bt_test_suite_success;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_simple, "Simple filter testing");
+
+ const char *files[] = {
+// "filter/test.conf",
+ "filter/test.conf2",
+// "filter/test_bgp_filtering.conf",
+#ifdef IPV6
+ "filter/test6.conf",
+#endif
+ };
+ size_t files_arr_size = sizeof(files)/sizeof(files[0]);
+ size_t i;
+ for (i = 0; i < files_arr_size; i++)
+ bt_test_suite_arg_extra(t_example_config_files, files[i], BT_DEFAULT_FORKING, 30, "Test a example config file %s", files[i]);
+
+ return bt_end();
+}
#include "unix.h"
#include "krt.h"
-/*
- * Debugging
- */
-
-#ifdef DEBUGGING
-static int debug_flag = 1;
-#else
-static int debug_flag = 0;
-#endif
-
-void
-async_dump(void)
-{
- debug("INTERNAL STATE DUMP\n\n");
-
- rdump(&root_pool);
- sk_dump_all();
- tm_dump_all();
- if_dump_all();
- neigh_dump_all();
- rta_dump_all();
- rt_dump_all();
- protos_dump_all();
-
- debug("\n");
-}
-
-/*
- * Dropping privileges
- */
-
-#ifdef CONFIG_RESTRICTED_PRIVILEGES
-#include "lib/syspriv.h"
-#else
-
-static inline void
-drop_uid(uid_t uid)
-{
- die("Cannot change user on this platform");
-}
-
-#endif
-
-static inline void
-drop_gid(gid_t gid)
-{
- if (setgid(gid) < 0)
- die("setgid: %m");
-}
-
-/*
- * Reading the Configuration
- */
-
-#ifdef PATH_IPROUTE_DIR
-
-static inline void
-add_num_const(char *name, int val)
-{
- struct symbol *s = cf_get_symbol(name);
- s->class = SYM_CONSTANT | T_INT;
- s->def = cfg_allocz(sizeof(struct f_val));
- SYM_TYPE(s) = T_INT;
- SYM_VAL(s).i = val;
-}
-
-/* the code of read_iproute_table() is based on
- rtnl_tab_initialize() from iproute2 package */
-static void
-read_iproute_table(char *file, char *prefix, int max)
-{
- char buf[512], namebuf[512];
- char *name;
- int val;
- FILE *fp;
-
- strcpy(namebuf, prefix);
- name = namebuf + strlen(prefix);
-
- fp = fopen(file, "r");
- if (!fp)
- return;
-
- while (fgets(buf, sizeof(buf), fp))
- {
- char *p = buf;
-
- while (*p == ' ' || *p == '\t')
- p++;
-
- if (*p == '#' || *p == '\n' || *p == 0)
- continue;
-
- if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
- sscanf(p, "0x%x %s #", &val, name) != 2 &&
- sscanf(p, "%d %s\n", &val, name) != 2 &&
- sscanf(p, "%d %s #", &val, name) != 2)
- continue;
-
- if (val < 0 || val > max)
- continue;
-
- for(p = name; *p; p++)
- if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
- *p = '_';
-
- add_num_const(namebuf, val);
- }
-
- fclose(fp);
-}
-
-#endif // PATH_IPROUTE_DIR
-
-
-static char *config_name = PATH_CONFIG_FILE;
-
-static int
-cf_read(byte *dest, uint len, int fd)
-{
- int l = read(fd, dest, len);
- if (l < 0)
- cf_error("Read error");
- return l;
-}
-
-void
-sysdep_preconfig(struct config *c)
-{
- init_list(&c->logfiles);
-
- c->latency_limit = UNIX_DEFAULT_LATENCY_LIMIT;
- c->watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING;
-
-#ifdef PATH_IPROUTE_DIR
- read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
- read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
- read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
- read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
-#endif
-}
-
-int
-sysdep_commit(struct config *new, struct config *old UNUSED)
-{
- log_switch(debug_flag, &new->logfiles, new->syslog_name);
- return 0;
-}
-
-static int
-unix_read_config(struct config **cp, char *name)
-{
- struct config *conf = config_alloc(name);
- int ret;
-
- *cp = conf;
- conf->file_fd = open(name, O_RDONLY);
- if (conf->file_fd < 0)
- return 0;
- cf_read_hook = cf_read;
- ret = config_parse(conf);
- close(conf->file_fd);
- return ret;
-}
-
-static struct config *
-read_config(void)
-{
- struct config *conf;
-
- if (!unix_read_config(&conf, config_name))
- {
- if (conf->err_msg)
- die("%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
- else
- die("Unable to open configuration file %s: %m", config_name);
- }
-
- return conf;
-}
-
-void
-async_config(void)
-{
- struct config *conf;
-
- log(L_INFO "Reconfiguration requested by SIGHUP");
- if (!unix_read_config(&conf, config_name))
- {
- if (conf->err_msg)
- log(L_ERR "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
- else
- log(L_ERR "Unable to open configuration file %s: %m", config_name);
- config_free(conf);
- }
- else
- config_commit(conf, RECONFIG_HARD, 0);
-}
-
-static struct config *
-cmd_read_config(char *name)
-{
- struct config *conf;
-
- if (!name)
- name = config_name;
-
- cli_msg(-2, "Reading configuration from %s", name);
- if (!unix_read_config(&conf, name))
- {
- if (conf->err_msg)
- cli_msg(8002, "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
- else
- cli_msg(8002, "%s: %m", name);
- config_free(conf);
- conf = NULL;
- }
-
- return conf;
-}
-
-void
-cmd_check_config(char *name)
-{
- struct config *conf = cmd_read_config(name);
- if (!conf)
- return;
-
- cli_msg(20, "Configuration OK");
- config_free(conf);
-}
-
-static void
-cmd_reconfig_msg(int r)
-{
- switch (r)
- {
- case CONF_DONE: cli_msg( 3, "Reconfigured"); break;
- case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break;
- case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break;
- case CONF_UNQUEUED: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break;
- case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break;
- case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break;
- case CONF_NOTHING: cli_msg(19, "Nothing to do"); break;
- default: break;
- }
-}
-
-/* Hack for scheduled undo notification */
-cli *cmd_reconfig_stored_cli;
-
-void
-cmd_reconfig_undo_notify(void)
-{
- if (cmd_reconfig_stored_cli)
- {
- cli *c = cmd_reconfig_stored_cli;
- cli_printf(c, CLI_ASYNC_CODE, "Config timeout expired, starting undo");
- cli_write_trigger(c);
- }
-}
-
-void
-cmd_reconfig(char *name, int type, int timeout)
-{
- if (cli_access_restricted())
- return;
-
- struct config *conf = cmd_read_config(name);
- if (!conf)
- return;
-
- int r = config_commit(conf, type, timeout);
-
- if ((r >= 0) && (timeout > 0))
- {
- cmd_reconfig_stored_cli = this_cli;
- cli_msg(-22, "Undo scheduled in %d s", timeout);
- }
-
- cmd_reconfig_msg(r);
-}
-
-void
-cmd_reconfig_confirm(void)
-{
- if (cli_access_restricted())
- return;
-
- int r = config_confirm();
- cmd_reconfig_msg(r);
-}
-
-void
-cmd_reconfig_undo(void)
-{
- if (cli_access_restricted())
- return;
-
- cli_msg(-21, "Undo requested");
-
- int r = config_undo();
- cmd_reconfig_msg(r);
-}
-
-/*
- * Command-Line Interface
- */
-
-static sock *cli_sk;
-static char *path_control_socket = PATH_CONTROL_SOCKET;
-
-
-static void
-cli_write(cli *c)
-{
- sock *s = c->priv;
-
- while (c->tx_pos)
- {
- struct cli_out *o = c->tx_pos;
-
- int len = o->wpos - o->outpos;
- s->tbuf = o->outpos;
- o->outpos = o->wpos;
-
- if (sk_send(s, len) <= 0)
- return;
-
- c->tx_pos = o->next;
- }
-
- /* Everything is written */
- s->tbuf = NULL;
- cli_written(c);
-}
-
-void
-cli_write_trigger(cli *c)
-{
- sock *s = c->priv;
-
- if (s->tbuf == NULL)
- cli_write(c);
-}
-
-static void
-cli_tx(sock *s)
-{
- cli_write(s->data);
-}
-
-int
-cli_get_command(cli *c)
-{
- sock *s = c->priv;
- byte *t = c->rx_aux ? : s->rbuf;
- byte *tend = s->rpos;
- byte *d = c->rx_pos;
- byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
-
- while (t < tend)
- {
- if (*t == '\r')
- t++;
- else if (*t == '\n')
- {
- t++;
- c->rx_pos = c->rx_buf;
- c->rx_aux = t;
- *d = 0;
- return (d < dend) ? 1 : -1;
- }
- else if (d < dend)
- *d++ = *t++;
- }
- c->rx_aux = s->rpos = s->rbuf;
- c->rx_pos = d;
- return 0;
-}
-
-static int
-cli_rx(sock *s, int size UNUSED)
-{
- cli_kick(s->data);
- return 0;
-}
-
-static void
-cli_err(sock *s, int err)
-{
- if (config->cli_debug)
- {
- if (err)
- log(L_INFO "CLI connection dropped: %s", strerror(err));
- else
- log(L_INFO "CLI connection closed");
- }
- cli_free(s->data);
-}
-
-static int
-cli_connect(sock *s, int size UNUSED)
-{
- cli *c;
-
- if (config->cli_debug)
- log(L_INFO "CLI connect");
- s->rx_hook = cli_rx;
- s->tx_hook = cli_tx;
- s->err_hook = cli_err;
- s->data = c = cli_new(s);
- s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
- c->rx_pos = c->rx_buf;
- c->rx_aux = NULL;
- rmove(s, c->pool);
- return 1;
-}
-
-static void
-cli_init_unix(uid_t use_uid, gid_t use_gid)
-{
- sock *s;
-
- cli_init();
- s = cli_sk = sk_new(cli_pool);
- s->type = SK_UNIX_PASSIVE;
- s->rx_hook = cli_connect;
- s->rbsize = 1024;
-
- /* Return value intentionally ignored */
- unlink(path_control_socket);
-
- if (sk_open_unix(s, path_control_socket) < 0)
- die("Cannot create control socket %s: %m", path_control_socket);
-
- if (use_uid || use_gid)
- if (chown(path_control_socket, use_uid, use_gid) < 0)
- die("chown: %m");
-
- if (chmod(path_control_socket, 0660) < 0)
- die("chmod: %m");
-}
-
-/*
- * PID file
- */
-
-static char *pid_file;
-static int pid_fd;
-
-static inline void
-open_pid_file(void)
-{
- if (!pid_file)
- return;
-
- pid_fd = open(pid_file, O_WRONLY|O_CREAT, 0664);
- if (pid_fd < 0)
- die("Cannot create PID file %s: %m", pid_file);
-}
-
-static inline void
-write_pid_file(void)
-{
- int pl, rv;
- char ps[24];
-
- if (!pid_file)
- return;
-
- /* We don't use PID file for uniqueness, so no need for locking */
-
- pl = bsnprintf(ps, sizeof(ps), "%ld\n", (long) getpid());
- if (pl < 0)
- bug("PID buffer too small");
-
- rv = ftruncate(pid_fd, 0);
- if (rv < 0)
- die("fruncate: %m");
-
- rv = write(pid_fd, ps, pl);
- if(rv < 0)
- die("write: %m");
-
- close(pid_fd);
-}
-
-static inline void
-unlink_pid_file(void)
-{
- if (pid_file)
- unlink(pid_file);
-}
-
-
-/*
- * Shutdown
- */
-
-void
-cmd_shutdown(void)
-{
- if (cli_access_restricted())
- return;
-
- cli_msg(7, "Shutdown requested");
- order_shutdown();
-}
-
-void
-async_shutdown(void)
-{
- DBG("Shutting down...\n");
- order_shutdown();
-}
-
-void
-sysdep_shutdown_done(void)
-{
- unlink_pid_file();
- unlink(path_control_socket);
- log_msg(L_FATAL "Shutdown completed");
- exit(0);
-}
-
-/*
- * Signals
- */
-
-static void
-handle_sighup(int sig UNUSED)
-{
- DBG("Caught SIGHUP...\n");
- async_config_flag = 1;
-}
-
-static void
-handle_sigusr(int sig UNUSED)
-{
- DBG("Caught SIGUSR...\n");
- async_dump_flag = 1;
-}
-
-static void
-handle_sigterm(int sig UNUSED)
-{
- DBG("Caught SIGTERM...\n");
- async_shutdown_flag = 1;
-}
-
-void watchdog_sigalrm(int sig UNUSED);
-
-static void
-signal_init(void)
-{
- struct sigaction sa;
-
- bzero(&sa, sizeof(sa));
- sa.sa_handler = handle_sigusr;
- sa.sa_flags = SA_RESTART;
- sigaction(SIGUSR1, &sa, NULL);
- sa.sa_handler = handle_sighup;
- sa.sa_flags = SA_RESTART;
- sigaction(SIGHUP, &sa, NULL);
- sa.sa_handler = handle_sigterm;
- sa.sa_flags = SA_RESTART;
- sigaction(SIGTERM, &sa, NULL);
- sa.sa_handler = watchdog_sigalrm;
- sa.sa_flags = 0;
- sigaction(SIGALRM, &sa, NULL);
- signal(SIGPIPE, SIG_IGN);
-}
-
-/*
- * Parsing of command-line arguments
- */
-
-static char *opt_list = "c:dD:ps:P:u:g:fR";
-static int parse_and_exit;
-char *bird_name;
-static char *use_user;
-static char *use_group;
-static int run_in_foreground = 0;
-
-static void
-usage(void)
-{
- fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-P <pid-file>] [-u <user>] [-g <group>] [-f] [-R]\n", bird_name);
- exit(1);
-}
-
-static inline char *
-get_bird_name(char *s, char *def)
-{
- char *t;
- if (!s)
- return def;
- t = strrchr(s, '/');
- if (!t)
- return s;
- if (!t[1])
- return def;
- return t+1;
-}
-
-static inline uid_t
-get_uid(const char *s)
-{
- struct passwd *pw;
- char *endptr;
- long int rv;
-
- if (!s)
- return 0;
-
- errno = 0;
- rv = strtol(s, &endptr, 10);
-
- if (!errno && !*endptr)
- return rv;
-
- pw = getpwnam(s);
- if (!pw)
- die("Cannot find user '%s'", s);
-
- return pw->pw_uid;
-}
-
-static inline gid_t
-get_gid(const char *s)
-{
- struct group *gr;
- char *endptr;
- long int rv;
-
- if (!s)
- return 0;
-
- errno = 0;
- rv = strtol(s, &endptr, 10);
-
- if (!errno && !*endptr)
- return rv;
-
- gr = getgrnam(s);
- if (!gr)
- die("Cannot find group '%s'", s);
-
- return gr->gr_gid;
-}
-
-static void
-parse_args(int argc, char **argv)
-{
- int c;
-
- bird_name = get_bird_name(argv[0], "bird");
- if (argc == 2)
- {
- if (!strcmp(argv[1], "--version"))
- {
- fprintf(stderr, "BIRD version " BIRD_VERSION "\n");
- exit(0);
- }
- if (!strcmp(argv[1], "--help"))
- usage();
- }
- while ((c = getopt(argc, argv, opt_list)) >= 0)
- switch (c)
- {
- case 'c':
- config_name = optarg;
- break;
- case 'd':
- debug_flag |= 1;
- break;
- case 'D':
- log_init_debug(optarg);
- debug_flag |= 2;
- break;
- case 'p':
- parse_and_exit = 1;
- break;
- case 's':
- path_control_socket = optarg;
- break;
- case 'P':
- pid_file = optarg;
- break;
- case 'u':
- use_user = optarg;
- break;
- case 'g':
- use_group = optarg;
- break;
- case 'f':
- run_in_foreground = 1;
- break;
- case 'R':
- graceful_restart_recovery();
- break;
- default:
- usage();
- }
- if (optind < argc)
- usage();
-}
+#include "lib/main_helper.h"
-
/*
* Hic Est main()
*/
--- /dev/null
- struct symbol *s = cf_find_symbol(name);
+/*
+ * BIRD Internet Routing Daemon -- Helper for main.c
+ *
+ * (c) 1998--2000 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#undef LOCAL_DEBUG
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/stat.h>
+#include <libgen.h>
+
+#include "nest/bird.h"
+#include "lib/lists.h"
+#include "lib/resource.h"
+#include "lib/socket.h"
+#include "lib/event.h"
+#include "lib/string.h"
+#include "nest/route.h"
+#include "nest/protocol.h"
+#include "nest/iface.h"
+#include "nest/cli.h"
+#include "nest/locks.h"
+#include "conf/conf.h"
+#include "filter/filter.h"
+
+#include "unix.h"
+#include "krt.h"
+
+#include "lib/main_helper.h"
+
+/*
+ * Debugging
+ */
+
+#ifdef DEBUGGING
+int debug_flag = 1;
+#else
+int debug_flag = 0;
+#endif
+
+void
+async_dump(void)
+{
+ debug("INTERNAL STATE DUMP\n\n");
+
+ rdump(&root_pool);
+ sk_dump_all();
+ tm_dump_all();
+ if_dump_all();
+ neigh_dump_all();
+ rta_dump_all();
+ rt_dump_all();
+ protos_dump_all();
+
+ debug("\n");
+}
+
+/*
+ * Dropping privileges
+ */
+
+#ifdef CONFIG_RESTRICTED_PRIVILEGES
+#include "lib/syspriv.h"
+#else
+
+void
+drop_uid(uid_t uid)
+{
+ die("Cannot change user on this platform");
+}
+
+#endif
+
+void
+drop_gid(gid_t gid)
+{
+ if (setgid(gid) < 0)
+ die("setgid: %m");
+}
+
+/*
+ * Reading the Configuration
+ */
+
+#ifdef PATH_IPROUTE_DIR
+
+void
+add_num_const(char *name, int val)
+{
++ struct symbol *s = cf_get_symbol(name);
+ s->class = SYM_CONSTANT | T_INT;
+ s->def = cfg_allocz(sizeof(struct f_val));
+ SYM_TYPE(s) = T_INT;
+ SYM_VAL(s).i = val;
+}
+
+/* the code of read_iproute_table() is based on
+ rtnl_tab_initialize() from iproute2 package */
+void
+read_iproute_table(char *file, char *prefix, int max)
+{
+ char buf[512], namebuf[512];
+ char *name;
+ int val;
+ FILE *fp;
+
+ strcpy(namebuf, prefix);
+ name = namebuf + strlen(prefix);
+
+ fp = fopen(file, "r");
+ if (!fp)
+ return;
+
+ while (fgets(buf, sizeof(buf), fp))
+ {
+ char *p = buf;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (*p == '#' || *p == '\n' || *p == 0)
+ continue;
+
+ if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
+ sscanf(p, "0x%x %s #", &val, name) != 2 &&
+ sscanf(p, "%d %s\n", &val, name) != 2 &&
+ sscanf(p, "%d %s #", &val, name) != 2)
+ continue;
+
+ if (val < 0 || val > max)
+ continue;
+
+ for(p = name; *p; p++)
+ if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
+ *p = '_';
+
+ add_num_const(namebuf, val);
+ }
+
+ fclose(fp);
+}
+
+#endif // PATH_IPROUTE_DIR
+
+
+char *config_name = PATH_CONFIG_FILE;
+
+int
+cf_read(byte *dest, uint len, int fd)
+{
+ int l = read(fd, dest, len);
+ if (l < 0)
+ cf_error("Read error");
+ return l;
+}
+
+void
+sysdep_preconfig(struct config *c)
+{
+ init_list(&c->logfiles);
+
+ c->latency_limit = UNIX_DEFAULT_LATENCY_LIMIT;
+ c->watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING;
+
+#ifdef PATH_IPROUTE_DIR
+ read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
+ read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
+ read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
+ read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
+#endif
+}
+
+int
+sysdep_commit(struct config *new, struct config *old UNUSED)
+{
+ log_switch(debug_flag, &new->logfiles, new->syslog_name);
+ return 0;
+}
+
+int
+unix_read_config(struct config **cp, char *name)
+{
+ struct config *conf = config_alloc(name);
+ int ret;
+
+ *cp = conf;
+ conf->file_fd = open(name, O_RDONLY);
+ if (conf->file_fd < 0)
+ return 0;
+ cf_read_hook = cf_read;
+ ret = config_parse(conf);
+ close(conf->file_fd);
+ return ret;
+}
+
+struct config *
+read_config(void)
+{
+ struct config *conf;
+
+ if (!unix_read_config(&conf, config_name))
+ {
+ if (conf->err_msg)
+ die("%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
+ else
+ die("Unable to open configuration file %s: %m", config_name);
+ }
+
+ return conf;
+}
+
+void
+async_config(void)
+{
+ struct config *conf;
+
+ log(L_INFO "Reconfiguration requested by SIGHUP");
+ if (!unix_read_config(&conf, config_name))
+ {
+ if (conf->err_msg)
+ log(L_ERR "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
+ else
+ log(L_ERR "Unable to open configuration file %s: %m", config_name);
+ config_free(conf);
+ }
+ else
+ config_commit(conf, RECONFIG_HARD, 0);
+}
+
+struct config *
+cmd_read_config(char *name)
+{
+ struct config *conf;
+
+ if (!name)
+ name = config_name;
+
+ cli_msg(-2, "Reading configuration from %s", name);
+ if (!unix_read_config(&conf, name))
+ {
+ if (conf->err_msg)
+ cli_msg(8002, "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
+ else
+ cli_msg(8002, "%s: %m", name);
+ config_free(conf);
+ conf = NULL;
+ }
+
+ return conf;
+}
+
+void
+cmd_check_config(char *name)
+{
+ struct config *conf = cmd_read_config(name);
+ if (!conf)
+ return;
+
+ cli_msg(20, "Configuration OK");
+ config_free(conf);
+}
+
+void
+cmd_reconfig_msg(int r)
+{
+ switch (r)
+ {
+ case CONF_DONE: cli_msg( 3, "Reconfigured"); break;
+ case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break;
+ case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break;
+ case CONF_UNQUEUED: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break;
+ case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break;
+ case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break;
+ case CONF_NOTHING: cli_msg(19, "Nothing to do"); break;
+ default: break;
+ }
+}
+
+/* Hack for scheduled undo notification */
+cli *cmd_reconfig_stored_cli;
+
+void
+cmd_reconfig_undo_notify(void)
+{
+ if (cmd_reconfig_stored_cli)
+ {
+ cli *c = cmd_reconfig_stored_cli;
+ cli_printf(c, CLI_ASYNC_CODE, "Config timeout expired, starting undo");
+ cli_write_trigger(c);
+ }
+}
+
+void
+cmd_reconfig(char *name, int type, int timeout)
+{
+ if (cli_access_restricted())
+ return;
+
+ struct config *conf = cmd_read_config(name);
+ if (!conf)
+ return;
+
+ int r = config_commit(conf, type, timeout);
+
+ if ((r >= 0) && (timeout > 0))
+ {
+ cmd_reconfig_stored_cli = this_cli;
+ cli_msg(-22, "Undo scheduled in %d s", timeout);
+ }
+
+ cmd_reconfig_msg(r);
+}
+
+void
+cmd_reconfig_confirm(void)
+{
+ if (cli_access_restricted())
+ return;
+
+ int r = config_confirm();
+ cmd_reconfig_msg(r);
+}
+
+void
+cmd_reconfig_undo(void)
+{
+ if (cli_access_restricted())
+ return;
+
+ cli_msg(-21, "Undo requested");
+
+ int r = config_undo();
+ cmd_reconfig_msg(r);
+}
+
+/*
+ * Command-Line Interface
+ */
+
+sock *cli_sk;
+char *path_control_socket = PATH_CONTROL_SOCKET;
+
+
+void
+cli_write(cli *c)
+{
+ sock *s = c->priv;
+
+ while (c->tx_pos)
+ {
+ struct cli_out *o = c->tx_pos;
+
+ int len = o->wpos - o->outpos;
+ s->tbuf = o->outpos;
+ o->outpos = o->wpos;
+
+ if (sk_send(s, len) <= 0)
+ return;
+
+ c->tx_pos = o->next;
+ }
+
+ /* Everything is written */
+ s->tbuf = NULL;
+ cli_written(c);
+}
+
+void
+cli_write_trigger(cli *c)
+{
+ sock *s = c->priv;
+
+ if (s->tbuf == NULL)
+ cli_write(c);
+}
+
+void
+cli_tx(sock *s)
+{
+ cli_write(s->data);
+}
+
+int
+cli_get_command(cli *c)
+{
+ sock *s = c->priv;
+ byte *t = c->rx_aux ? : s->rbuf;
+ byte *tend = s->rpos;
+ byte *d = c->rx_pos;
+ byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
+
+ while (t < tend)
+ {
+ if (*t == '\r')
+ t++;
+ else if (*t == '\n')
+ {
+ t++;
+ c->rx_pos = c->rx_buf;
+ c->rx_aux = t;
+ *d = 0;
+ return (d < dend) ? 1 : -1;
+ }
+ else if (d < dend)
+ *d++ = *t++;
+ }
+ c->rx_aux = s->rpos = s->rbuf;
+ c->rx_pos = d;
+ return 0;
+}
+
+int
+cli_rx(sock *s, int size UNUSED)
+{
+ cli_kick(s->data);
+ return 0;
+}
+
+void
+cli_err(sock *s, int err)
+{
+ if (config->cli_debug)
+ {
+ if (err)
+ log(L_INFO "CLI connection dropped: %s", strerror(err));
+ else
+ log(L_INFO "CLI connection closed");
+ }
+ cli_free(s->data);
+}
+
+int
+cli_connect(sock *s, int size UNUSED)
+{
+ cli *c;
+
+ if (config->cli_debug)
+ log(L_INFO "CLI connect");
+ s->rx_hook = cli_rx;
+ s->tx_hook = cli_tx;
+ s->err_hook = cli_err;
+ s->data = c = cli_new(s);
+ s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
+ c->rx_pos = c->rx_buf;
+ c->rx_aux = NULL;
+ rmove(s, c->pool);
+ return 1;
+}
+
+void
+cli_init_unix(uid_t use_uid, gid_t use_gid)
+{
+ sock *s;
+
+ cli_init();
+ s = cli_sk = sk_new(cli_pool);
+ s->type = SK_UNIX_PASSIVE;
+ s->rx_hook = cli_connect;
+ s->rbsize = 1024;
+
+ /* Return value intentionally ignored */
+ unlink(path_control_socket);
+
+ if (sk_open_unix(s, path_control_socket) < 0)
+ die("Cannot create control socket %s: %m", path_control_socket);
+
+ if (use_uid || use_gid)
+ if (chown(path_control_socket, use_uid, use_gid) < 0)
+ die("chown: %m");
+
+ if (chmod(path_control_socket, 0660) < 0)
+ die("chmod: %m");
+}
+
+/*
+ * PID file
+ */
+
+char *pid_file;
+int pid_fd;
+
+void
+open_pid_file(void)
+{
+ if (!pid_file)
+ return;
+
+ pid_fd = open(pid_file, O_WRONLY|O_CREAT, 0664);
+ if (pid_fd < 0)
+ die("Cannot create PID file %s: %m", pid_file);
+}
+
+void
+write_pid_file(void)
+{
+ int pl, rv;
+ char ps[24];
+
+ if (!pid_file)
+ return;
+
+ /* We don't use PID file for uniqueness, so no need for locking */
+
+ pl = bsnprintf(ps, sizeof(ps), "%ld\n", (long) getpid());
+ if (pl < 0)
+ bug("PID buffer too small");
+
+ rv = ftruncate(pid_fd, 0);
+ if (rv < 0)
+ die("fruncate: %m");
+
+ rv = write(pid_fd, ps, pl);
+ if(rv < 0)
+ die("write: %m");
+
+ close(pid_fd);
+}
+
+void
+unlink_pid_file(void)
+{
+ if (pid_file)
+ unlink(pid_file);
+}
+
+
+/*
+ * Shutdown
+ */
+
+void
+cmd_shutdown(void)
+{
+ if (cli_access_restricted())
+ return;
+
+ cli_msg(7, "Shutdown requested");
+ order_shutdown();
+}
+
+void
+async_shutdown(void)
+{
+ DBG("Shutting down...\n");
+ order_shutdown();
+}
+
+void
+sysdep_shutdown_done(void)
+{
+ unlink_pid_file();
+ unlink(path_control_socket);
+ log_msg(L_FATAL "Shutdown completed");
+ exit(0);
+}
+
+/*
+ * Signals
+ */
+
+void
+handle_sighup(int sig UNUSED)
+{
+ DBG("Caught SIGHUP...\n");
+ async_config_flag = 1;
+}
+
+void
+handle_sigusr(int sig UNUSED)
+{
+ DBG("Caught SIGUSR...\n");
+ async_dump_flag = 1;
+}
+
+void
+handle_sigterm(int sig UNUSED)
+{
+ DBG("Caught SIGTERM...\n");
+ async_shutdown_flag = 1;
+}
+
+void watchdog_sigalrm(int sig UNUSED);
+
+void
+signal_init(void)
+{
+ struct sigaction sa;
+
+ bzero(&sa, sizeof(sa));
+ sa.sa_handler = handle_sigusr;
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGUSR1, &sa, NULL);
+ sa.sa_handler = handle_sighup;
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGHUP, &sa, NULL);
+ sa.sa_handler = handle_sigterm;
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGTERM, &sa, NULL);
+ sa.sa_handler = watchdog_sigalrm;
+ sa.sa_flags = 0;
+ sigaction(SIGALRM, &sa, NULL);
+ signal(SIGPIPE, SIG_IGN);
+}
+
+/*
+ * Parsing of command-line arguments
+ */
+
+char *opt_list = "c:dD:ps:P:u:g:fR";
+int parse_and_exit;
+char *bird_name;
+char *use_user;
+char *use_group;
+int run_in_foreground = 0;
+
+void
+usage(void)
+{
+ fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-P <pid-file>] [-u <user>] [-g <group>] [-f] [-R]\n", bird_name);
+ exit(1);
+}
+
+char *
+get_bird_name(char *s, char *def)
+{
+ char *t;
+ if (!s)
+ return def;
+ t = strrchr(s, '/');
+ if (!t)
+ return s;
+ if (!t[1])
+ return def;
+ return t+1;
+}
+
+uid_t
+get_uid(const char *s)
+{
+ struct passwd *pw;
+ char *endptr;
+ long int rv;
+
+ if (!s)
+ return 0;
+
+ errno = 0;
+ rv = strtol(s, &endptr, 10);
+
+ if (!errno && !*endptr)
+ return rv;
+
+ pw = getpwnam(s);
+ if (!pw)
+ die("Cannot find user '%s'", s);
+
+ return pw->pw_uid;
+}
+
+gid_t
+get_gid(const char *s)
+{
+ struct group *gr;
+ char *endptr;
+ long int rv;
+
+ if (!s)
+ return 0;
+
+ errno = 0;
+ rv = strtol(s, &endptr, 10);
+
+ if (!errno && !*endptr)
+ return rv;
+
+ gr = getgrnam(s);
+ if (!gr)
+ die("Cannot find group '%s'", s);
+
+ return gr->gr_gid;
+}
+
+void
+parse_args(int argc, char **argv)
+{
+ int c;
+
+ bird_name = get_bird_name(argv[0], "bird");
+ if (argc == 2)
+ {
+ if (!strcmp(argv[1], "--version"))
+ {
+ fprintf(stderr, "BIRD version " BIRD_VERSION "\n");
+ exit(0);
+ }
+ if (!strcmp(argv[1], "--help"))
+ usage();
+ }
+ while ((c = getopt(argc, argv, opt_list)) >= 0)
+ switch (c)
+ {
+ case 'c':
+ config_name = optarg;
+ break;
+ case 'd':
+ debug_flag |= 1;
+ break;
+ case 'D':
+ log_init_debug(optarg);
+ debug_flag |= 2;
+ break;
+ case 'p':
+ parse_and_exit = 1;
+ break;
+ case 's':
+ path_control_socket = optarg;
+ break;
+ case 'P':
+ pid_file = optarg;
+ break;
+ case 'u':
+ use_user = optarg;
+ break;
+ case 'g':
+ use_group = optarg;
+ break;
+ case 'f':
+ run_in_foreground = 1;
+ break;
+ case 'R':
+ graceful_restart_recovery();
+ break;
+ default:
+ usage();
+ }
+ if (optind < argc)
+ usage();
+}
set -e ; for a in $(dynamic-dirs) ; do $(MAKE) -C $$a $@ ; done
set -e ; for a in $(static-dirs) $(client-dirs) ; do $(MAKE) -C $$a -f $(srcdir_abs)/$$a/Makefile $@ ; done
-$(exedir)/bird: $(bird-dep)
- @echo LD $(LDFLAGS) -o $@ $^ $(LIBS)
- @$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+$(exedir)/bird: $(bird-dep) lib/main.o
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
$(exedir)/birdc: $(birdc-dep)
- $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(CLIENT_LIBS)
+ @echo LD $(LDFLAGS) -o $@ $^ $(LIBS) $(CLIENT_LIBS)
+ @$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(CLIENT_LIBS)
$(exedir)/birdcl: $(birdcl-dep)
- $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+ @echo LD $(LDFLAGS) -o $@ $^ $(LIBS)
+ @$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
.dir-stamp: sysdep/paths.h
mkdir -p $(static-dirs) $(client-dirs) $(doc-dirs)