Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / main.c @ acc93efd

History | View | Annotate | Download (9.75 KB)

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
#include <stdio.h>
12
#include <stdlib.h>
13
#include <fcntl.h>
14
#include <unistd.h>
15
#include <signal.h>
16

    
17
#include "nest/bird.h"
18
#include "lib/lists.h"
19
#include "lib/resource.h"
20
#include "lib/socket.h"
21
#include "lib/event.h"
22
#include "lib/string.h"
23
#include "nest/route.h"
24
#include "nest/protocol.h"
25
#include "nest/iface.h"
26
#include "nest/cli.h"
27
#include "nest/locks.h"
28
#include "conf/conf.h"
29
#include "filter/filter.h"
30

    
31
#include "unix.h"
32
#include "krt.h"
33

    
34
/*
35
 *        Debugging
36
 */
37

    
38
#ifdef DEBUGGING
39
static int debug_flag = 1;
40
#else
41
static int debug_flag = 0;
42
#endif
43

    
44
void
45
async_dump(void)
46
{
47
  debug("INTERNAL STATE DUMP\n\n");
48

    
49
  rdump(&root_pool);
50
  sk_dump_all();
51
  tm_dump_all();
52
  if_dump_all();
53
  neigh_dump_all();
54
  rta_dump_all();
55
  rt_dump_all();
56
  protos_dump_all();
57

    
58
  debug("\n");
59
}
60

    
61
/*
62
 *        Reading the Configuration
63
 */
64

    
65
#ifdef PATH_IPROUTE_DIR
66

    
67
static inline void
68
add_num_const(char *name, int val)
69
{
70
  struct symbol *s = cf_find_symbol(name);
71
  s->class = SYM_NUMBER;
72
  s->def = NULL;
73
  s->aux = val;
74
}
75

    
76
/* the code of read_iproute_table() is based on
77
   rtnl_tab_initialize() from iproute2 package */
78
static void
79
read_iproute_table(char *file, char *prefix, int max)
80
{
81
  char buf[512], namebuf[512];
82
  char *name;
83
  int val;
84
  FILE *fp;
85

    
86
  strcpy(namebuf, prefix);
87
  name = namebuf + strlen(prefix);
88

    
89
  fp = fopen(file, "r");
90
  if (!fp)
91
    return;
92

    
93
  while (fgets(buf, sizeof(buf), fp))
94
  {
95
    char *p = buf;
96

    
97
    while (*p == ' ' || *p == '\t')
98
      p++;
99

    
100
    if (*p == '#' || *p == '\n' || *p == 0)
101
      continue;
102
   
103
    if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
104
        sscanf(p, "0x%x %s #", &val, name) != 2 &&
105
        sscanf(p, "%d %s\n", &val, name) != 2 &&
106
        sscanf(p, "%d %s #", &val, name) != 2)
107
      continue;
108

    
109
    if (val < 0 || val > max)
110
      continue;
111

    
112
    for(p = name; *p; p++)
113
      if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
114
        *p = '_';
115

    
116
    add_num_const(namebuf, val);
117
  }
118

    
119
  fclose(fp);
120
}
121

    
122
#endif // PATH_IPROUTE_DIR
123

    
124

    
125
static int conf_fd;
126
static char *config_name = PATH_CONFIG;
127

    
128
static int
129
cf_read(byte *dest, unsigned int len)
130
{
131
  int l = read(conf_fd, dest, len);
132
  if (l < 0)
133
    cf_error("Read error");
134
  return l;
135
}
136

    
137
void
138
sysdep_preconfig(struct config *c)
139
{
140
  init_list(&c->logfiles);
141

    
142
#ifdef PATH_IPROUTE_DIR
143
  // read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
144
  read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
145
  read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
146
  read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
147
#endif
148
}
149

    
150
int
151
sysdep_commit(struct config *new, struct config *old UNUSED)
152
{
153
  log_switch(debug_flag, &new->logfiles, new->syslog_name);
154
  return 0;
155
}
156

    
157
static int
158
unix_read_config(struct config **cp, char *name)
159
{
160
  struct config *conf = config_alloc(name);
161
  int ret;
162

    
163
  *cp = conf;
164
  conf_fd = open(name, O_RDONLY);
165
  if (conf_fd < 0)
166
    return 0;
167
  cf_read_hook = cf_read;
168
  ret = config_parse(conf);
169
  close(conf_fd);
170
  return ret;
171
}
172

    
173
static void
174
read_config(void)
175
{
176
  struct config *conf;
177

    
178
  if (!unix_read_config(&conf, config_name))
179
    {
180
      if (conf->err_msg)
181
        die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
182
      else
183
        die("Unable to open configuration file %s: %m", config_name);
184
    }
185
  config_commit(conf, RECONFIG_HARD);
186
}
187

    
188
void
189
async_config(void)
190
{
191
  struct config *conf;
192

    
193
  log(L_INFO "Reconfiguration requested by SIGHUP");
194
  if (!unix_read_config(&conf, config_name))
195
    {
196
      if (conf->err_msg)
197
        log(L_ERR "%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
198
      else
199
        log(L_ERR "Unable to open configuration file %s: %m", config_name);
200
      config_free(conf);
201
    }
202
  else
203
    config_commit(conf, RECONFIG_HARD);
204
}
205

    
206
void
207
cmd_reconfig(char *name, int type)
208
{
209
  struct config *conf;
210

    
211
  if (cli_access_restricted())
212
    return;
213

    
214
  if (!name)
215
    name = config_name;
216
  cli_msg(-2, "Reading configuration from %s", name);
217
  if (!unix_read_config(&conf, name))
218
    {
219
      if (conf->err_msg)
220
        cli_msg(8002, "%s, line %d: %s", name, conf->err_lino, conf->err_msg);
221
      else
222
        cli_msg(8002, "%s: %m", name);
223
      config_free(conf);
224
    }
225
  else
226
    {
227
      switch (config_commit(conf, type))
228
        {
229
        case CONF_DONE:
230
          cli_msg(3, "Reconfigured.");
231
          break;
232
        case CONF_PROGRESS:
233
          cli_msg(4, "Reconfiguration in progress.");
234
          break;
235
        case CONF_SHUTDOWN:
236
          cli_msg(6, "Reconfiguration ignored, shutting down.");
237
          break;
238
        default:
239
          cli_msg(5, "Reconfiguration already in progress, queueing new config");
240
        }
241
    }
242
}
243

    
244
/*
245
 *        Command-Line Interface
246
 */
247

    
248
static sock *cli_sk;
249
static char *path_control_socket = PATH_CONTROL_SOCKET;
250

    
251

    
252
static void
253
cli_write(cli *c)
254
{
255
  sock *s = c->priv;
256

    
257
  while (c->tx_pos)
258
    {
259
      struct cli_out *o = c->tx_pos;
260

    
261
      int len = o->wpos - o->outpos;
262
      s->tbuf = o->outpos;
263
      o->outpos = o->wpos;
264

    
265
      if (sk_send(s, len) <= 0)
266
        return;
267

    
268
      c->tx_pos = o->next;
269
    }
270

    
271
  /* Everything is written */
272
  s->tbuf = NULL;
273
  cli_written(c);
274
}
275

    
276
void
277
cli_write_trigger(cli *c)
278
{
279
  sock *s = c->priv;
280

    
281
  if (s->tbuf == NULL)
282
    cli_write(c);
283
}
284

    
285
static void
286
cli_tx(sock *s)
287
{
288
  cli_write(s->data);
289
}
290

    
291
int
292
cli_get_command(cli *c)
293
{
294
  sock *s = c->priv;
295
  byte *t = c->rx_aux ? : s->rbuf;
296
  byte *tend = s->rpos;
297
  byte *d = c->rx_pos;
298
  byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
299

    
300
  while (t < tend)
301
    {
302
      if (*t == '\r')
303
        t++;
304
      else if (*t == '\n')
305
        {
306
          t++;
307
          c->rx_pos = c->rx_buf;
308
          c->rx_aux = t;
309
          *d = 0;
310
          return (d < dend) ? 1 : -1;
311
        }
312
      else if (d < dend)
313
        *d++ = *t++;
314
    }
315
  c->rx_aux = s->rpos = s->rbuf;
316
  c->rx_pos = d;
317
  return 0;
318
}
319

    
320
static int
321
cli_rx(sock *s, int size UNUSED)
322
{
323
  cli_kick(s->data);
324
  return 0;
325
}
326

    
327
static void
328
cli_err(sock *s, int err)
329
{
330
  if (config->cli_debug)
331
    {
332
      if (err)
333
        log(L_INFO "CLI connection dropped: %s", strerror(err));
334
      else
335
        log(L_INFO "CLI connection closed");
336
    }
337
  cli_free(s->data);
338
}
339

    
340
static int
341
cli_connect(sock *s, int size UNUSED)
342
{
343
  cli *c;
344

    
345
  if (config->cli_debug)
346
    log(L_INFO "CLI connect");
347
  s->rx_hook = cli_rx;
348
  s->tx_hook = cli_tx;
349
  s->err_hook = cli_err;
350
  s->data = c = cli_new(s);
351
  s->pool = c->pool;                /* We need to have all the socket buffers allocated in the cli pool */
352
  c->rx_pos = c->rx_buf;
353
  c->rx_aux = NULL;
354
  rmove(s, c->pool);
355
  return 1;
356
}
357

    
358
static void
359
cli_init_unix(void)
360
{
361
  sock *s;
362

    
363
  cli_init();
364
  s = cli_sk = sk_new(cli_pool);
365
  s->type = SK_UNIX_PASSIVE;
366
  s->rx_hook = cli_connect;
367
  s->rbsize = 1024;
368
  sk_open_unix(s, path_control_socket);
369
}
370

    
371
/*
372
 *        Shutdown
373
 */
374

    
375
void
376
cmd_shutdown(void)
377
{
378
  if (cli_access_restricted())
379
    return;
380

    
381
  cli_msg(7, "Shutdown requested");
382
  order_shutdown();
383
}
384

    
385
void
386
async_shutdown(void)
387
{
388
  DBG("Shutting down...\n");
389
  order_shutdown();
390
}
391

    
392
void
393
sysdep_shutdown_done(void)
394
{
395
  unlink(path_control_socket);
396
  log_msg(L_FATAL "Shutdown completed");
397
  exit(0);
398
}
399

    
400
/*
401
 *        Signals
402
 */
403

    
404
static void
405
handle_sighup(int sig UNUSED)
406
{
407
  DBG("Caught SIGHUP...\n");
408
  async_config_flag = 1;
409
}
410

    
411
static void
412
handle_sigusr(int sig UNUSED)
413
{
414
  DBG("Caught SIGUSR...\n");
415
  async_dump_flag = 1;
416
}
417

    
418
static void
419
handle_sigterm(int sig UNUSED)
420
{
421
  DBG("Caught SIGTERM...\n");
422
  async_shutdown_flag = 1;
423
}
424

    
425
static void
426
signal_init(void)
427
{
428
  struct sigaction sa;
429

    
430
  bzero(&sa, sizeof(sa));
431
  sa.sa_handler = handle_sigusr;
432
  sa.sa_flags = SA_RESTART;
433
  sigaction(SIGUSR1, &sa, NULL);
434
  sa.sa_handler = handle_sighup;
435
  sa.sa_flags = SA_RESTART;
436
  sigaction(SIGHUP, &sa, NULL);
437
  sa.sa_handler = handle_sigterm;
438
  sa.sa_flags = SA_RESTART;
439
  sigaction(SIGTERM, &sa, NULL);
440
  signal(SIGPIPE, SIG_IGN);
441
}
442

    
443
/*
444
 *        Parsing of command-line arguments
445
 */
446

    
447
static char *opt_list = "c:dD:ps:";
448
static int parse_and_exit;
449
char *bird_name;
450

    
451
static void
452
usage(void)
453
{
454
  fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>]\n", bird_name);
455
  exit(1);
456
}
457

    
458
static inline char *
459
get_bird_name(char *s, char *def)
460
{
461
  char *t;
462
  if (!s)
463
    return def;
464
  t = strrchr(s, '/');
465
  if (!t)
466
    return s;
467
  if (!t[1])
468
    return def;
469
  return t+1;
470
}
471

    
472
static void
473
parse_args(int argc, char **argv)
474
{
475
  int c;
476

    
477
  bird_name = get_bird_name(argv[0], "bird");
478
  if (argc == 2)
479
    {
480
      if (!strcmp(argv[1], "--version"))
481
        {
482
          fprintf(stderr, "BIRD version " BIRD_VERSION "\n");
483
          exit(0);
484
        }
485
      if (!strcmp(argv[1], "--help"))
486
        usage();
487
    }
488
  while ((c = getopt(argc, argv, opt_list)) >= 0)
489
    switch (c)
490
      {
491
      case 'c':
492
        config_name = optarg;
493
        break;
494
      case 'd':
495
        debug_flag |= 1;
496
        break;
497
      case 'D':
498
        log_init_debug(optarg);
499
        debug_flag |= 2;
500
        break;
501
      case 'p':
502
        parse_and_exit = 1;
503
        break;
504
      case 's':
505
        path_control_socket = optarg;
506
        break;
507
      default:
508
        usage();
509
      }
510
  if (optind < argc)
511
    usage();
512
}
513

    
514
/*
515
 *        Hic Est main()
516
 */
517

    
518
int
519
main(int argc, char **argv)
520
{
521
#ifdef HAVE_LIBDMALLOC
522
  if (!getenv("DMALLOC_OPTIONS"))
523
    dmalloc_debug(0x2f03d00);
524
#endif
525

    
526
  parse_args(argc, argv);
527
  if (debug_flag == 1)
528
    log_init_debug("");
529
  log_switch(debug_flag, NULL, NULL);
530

    
531
  if (!parse_and_exit)
532
    test_old_bird(path_control_socket);
533

    
534
  DBG("Initializing.\n");
535
  resource_init();
536
  olock_init();
537
  io_init();
538
  rt_init();
539
  if_init();
540

    
541
  if (!parse_and_exit)
542
    cli_init_unix();
543

    
544
  protos_build();
545
  proto_build(&proto_unix_kernel);
546
  proto_build(&proto_unix_iface);
547

    
548
  read_config();
549

    
550
  if (parse_and_exit)
551
    exit(0);
552

    
553
  if (!debug_flag)
554
    {
555
      pid_t pid = fork();
556
      if (pid < 0)
557
        die("fork: %m");
558
      if (pid)
559
        return 0;
560
      setsid();
561
      close(0);
562
      if (open("/dev/null", O_RDWR) < 0)
563
        die("Cannot open /dev/null: %m");
564
      dup2(0, 1);
565
      dup2(0, 2);
566
    }
567

    
568
  signal_init();
569

    
570
#ifdef LOCAL_DEBUG
571
  async_dump_flag = 1;
572
#endif
573

    
574
  log(L_INFO "Started");
575
  DBG("Entering I/O loop.\n");
576

    
577
  io_loop();
578
  bug("I/O loop died");
579
}