]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge branch 'master' into birdtest
authorPavel Tvrdík <pawel.tvrdik@gmail.com>
Thu, 12 Nov 2015 15:12:45 +0000 (16:12 +0100)
committerPavel Tvrdík <pawel.tvrdik@gmail.com>
Thu, 12 Nov 2015 15:20:37 +0000 (16:20 +0100)
12 files changed:
1  2 
conf/conf.c
conf/conf.h
filter/filter.h
filter/filter_test.c
lib/birdlib.h
proto/ospf/packet.c
proto/ospf/rt.c
sysdep/unix/io.c
sysdep/unix/main.c
sysdep/unix/main_helper.c
tools/Makefile.in
tools/Rules.in

diff --cc conf/conf.c
Simple merge
diff --cc conf/conf.h
Simple merge
diff --cc filter/filter.h
Simple merge
index a1a1243d08ad578fea7489a559e6029d69ba14cf,0000000000000000000000000000000000000000..b5c35993b6ab873c8cf21858b2f884044d31ad3b
mode 100644,000000..100644
--- /dev/null
@@@ -1,136 -1,0 +1,136 @@@
-   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();
 +}
diff --cc lib/birdlib.h
Simple merge
Simple merge
diff --cc proto/ospf/rt.c
Simple merge
Simple merge
index eb33a566c12f1bf531416b338f3df03e600292b2,24d34f6017e1a37b1b2442eef2ae2e982f4f12ee..1f3a91d15899c9b3c055c864994a2e3799757e84
  #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()
   */
index 7b71bed12e103c7834b5f0d9f623932112de88e6,0000000000000000000000000000000000000000..42a9e6cb834042eb5024cfa272f3c5536bf15e38
mode 100644,000000..100644
--- /dev/null
@@@ -1,751 -1,0 +1,751 @@@
-   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();
 +}
index 3c4573b3ccea03009cb034ec46c4898bde2c2925,01bb7a7c1459bbbf12ba670baaf1af8e3c5cf956..46c7d11265e6f469d5beff05c72888e932aeb8f4
@@@ -52,14 -36,17 +52,16 @@@ subdir: sysdep/paths.h .dir-stamp .dep-
        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)
diff --cc tools/Rules.in
Simple merge