Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / main.c @ 1bc26957

History | View | Annotate | Download (10.9 KB)

1 25697773 Martin Mares
/*
2
 *        BIRD Internet Routing Daemon -- Unix Entry Point
3
 *
4 50fe90ed Martin Mares
 *        (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 25697773 Martin Mares
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8
9 9a220cab Martin Mares
#undef LOCAL_DEBUG
10 6b9fa320 Martin Mares
11 1bc26957 Ondrej Zajicek
#define _GNU_SOURCE 1
12
13 25697773 Martin Mares
#include <stdio.h>
14 7a2105be Martin Mares
#include <stdlib.h>
15 70591fa0 Martin Mares
#include <fcntl.h>
16
#include <unistd.h>
17 b1a1faba Ondrej Filip
#include <signal.h>
18 1bc26957 Ondrej Zajicek
#include <pwd.h>
19
#include <grp.h>
20 25697773 Martin Mares
21
#include "nest/bird.h"
22
#include "lib/lists.h"
23
#include "lib/resource.h"
24 b5d9ee5c Martin Mares
#include "lib/socket.h"
25 14dea0ed Martin Mares
#include "lib/event.h"
26 221135d6 Martin Mares
#include "lib/string.h"
27 25697773 Martin Mares
#include "nest/route.h"
28 b5d9ee5c Martin Mares
#include "nest/protocol.h"
29 8a48ecb8 Martin Mares
#include "nest/iface.h"
30 7d3aab1c Martin Mares
#include "nest/cli.h"
31 f545d387 Martin Mares
#include "nest/locks.h"
32 70591fa0 Martin Mares
#include "conf/conf.h"
33 b9d70dc8 Pavel Machek
#include "filter/filter.h"
34 b5d9ee5c Martin Mares
35
#include "unix.h"
36 7e7790c6 Martin Mares
#include "krt.h"
37 b5d9ee5c Martin Mares
38
/*
39
 *        Debugging
40
 */
41
42 f9eb8f7e Martin Mares
#ifdef DEBUGGING
43
static int debug_flag = 1;
44
#else
45
static int debug_flag = 0;
46
#endif
47
48 4c9dd1e4 Martin Mares
void
49
async_dump(void)
50 b5d9ee5c Martin Mares
{
51 4c9dd1e4 Martin Mares
  debug("INTERNAL STATE DUMP\n\n");
52 b5d9ee5c Martin Mares
53 5bc512aa Martin Mares
  rdump(&root_pool);
54 b5d9ee5c Martin Mares
  sk_dump_all();
55
  tm_dump_all();
56 8a48ecb8 Martin Mares
  if_dump_all();
57 869c6959 Martin Mares
  neigh_dump_all();
58 b5d9ee5c Martin Mares
  rta_dump_all();
59
  rt_dump_all();
60 86b00230 Pavel Machek
  protos_dump_all();
61 b5d9ee5c Martin Mares
62
  debug("\n");
63
}
64
65
/*
66 1bc26957 Ondrej Zajicek
 *        Dropping privileges
67
 */
68
69
#ifdef CONFIG_RESTRICTED_PRIVILEGES
70
#include "lib/syspriv.h"
71
#else
72
73
static inline void
74
drop_uid(uid_t uid)
75
{
76
  die("Cannot change user on this platform");
77
}
78
79
#endif
80
81
static inline void
82
drop_gid(gid_t gid)
83
{
84
  if (setgid(gid) < 0)
85
    die("setgid: %m");
86
}
87
88
/*
89 70591fa0 Martin Mares
 *        Reading the Configuration
90 b5d9ee5c Martin Mares
 */
91
92 acc93efd Ondrej Zajicek
#ifdef PATH_IPROUTE_DIR
93
94
static inline void
95
add_num_const(char *name, int val)
96
{
97
  struct symbol *s = cf_find_symbol(name);
98
  s->class = SYM_NUMBER;
99
  s->def = NULL;
100
  s->aux = val;
101
}
102
103
/* the code of read_iproute_table() is based on
104
   rtnl_tab_initialize() from iproute2 package */
105
static void
106
read_iproute_table(char *file, char *prefix, int max)
107
{
108
  char buf[512], namebuf[512];
109
  char *name;
110
  int val;
111
  FILE *fp;
112
113
  strcpy(namebuf, prefix);
114
  name = namebuf + strlen(prefix);
115
116
  fp = fopen(file, "r");
117
  if (!fp)
118
    return;
119
120
  while (fgets(buf, sizeof(buf), fp))
121
  {
122
    char *p = buf;
123
124
    while (*p == ' ' || *p == '\t')
125
      p++;
126
127
    if (*p == '#' || *p == '\n' || *p == 0)
128
      continue;
129
   
130
    if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
131
        sscanf(p, "0x%x %s #", &val, name) != 2 &&
132
        sscanf(p, "%d %s\n", &val, name) != 2 &&
133
        sscanf(p, "%d %s #", &val, name) != 2)
134
      continue;
135
136
    if (val < 0 || val > max)
137
      continue;
138
139
    for(p = name; *p; p++)
140
      if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
141
        *p = '_';
142
143
    add_num_const(namebuf, val);
144
  }
145
146
  fclose(fp);
147
}
148
149
#endif // PATH_IPROUTE_DIR
150
151
152 70591fa0 Martin Mares
static int conf_fd;
153 4c9dd1e4 Martin Mares
static char *config_name = PATH_CONFIG;
154 70591fa0 Martin Mares
155
static int
156
cf_read(byte *dest, unsigned int len)
157
{
158
  int l = read(conf_fd, dest, len);
159
  if (l < 0)
160
    cf_error("Read error");
161
  return l;
162
}
163
164 a0c37b45 Martin Mares
void
165
sysdep_preconfig(struct config *c)
166
{
167
  init_list(&c->logfiles);
168 acc93efd Ondrej Zajicek
169
#ifdef PATH_IPROUTE_DIR
170
  // read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
171
  read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
172
  read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
173
  read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
174
#endif
175 a0c37b45 Martin Mares
}
176
177 50fe90ed Martin Mares
int
178 6578a604 Martin Mares
sysdep_commit(struct config *new, struct config *old UNUSED)
179 a0c37b45 Martin Mares
{
180 44d4ab7a Ondrej Zajicek
  log_switch(debug_flag, &new->logfiles, new->syslog_name);
181 50fe90ed Martin Mares
  return 0;
182 a0c37b45 Martin Mares
}
183
184 50fe90ed Martin Mares
static int
185
unix_read_config(struct config **cp, char *name)
186 70591fa0 Martin Mares
{
187 50fe90ed Martin Mares
  struct config *conf = config_alloc(name);
188 3c3271d9 Ondrej Filip
  int ret;
189 31b3e1bb Martin Mares
190 50fe90ed Martin Mares
  *cp = conf;
191
  conf_fd = open(name, O_RDONLY);
192 70591fa0 Martin Mares
  if (conf_fd < 0)
193 50fe90ed Martin Mares
    return 0;
194 70591fa0 Martin Mares
  cf_read_hook = cf_read;
195 3c3271d9 Ondrej Filip
  ret = config_parse(conf);
196
  close(conf_fd);
197
  return ret;
198 50fe90ed Martin Mares
}
199
200
static void
201
read_config(void)
202
{
203
  struct config *conf;
204
205
  if (!unix_read_config(&conf, config_name))
206
    {
207
      if (conf->err_msg)
208
        die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
209
      else
210
        die("Unable to open configuration file %s: %m", config_name);
211
    }
212 bf1aec97 Ondrej Zajicek
  config_commit(conf, RECONFIG_HARD);
213 70591fa0 Martin Mares
}
214 31b3e1bb Martin Mares
215 4c9dd1e4 Martin Mares
void
216
async_config(void)
217
{
218 50fe90ed Martin Mares
  struct config *conf;
219
220
  log(L_INFO "Reconfiguration requested by SIGHUP");
221
  if (!unix_read_config(&conf, config_name))
222
    {
223
      if (conf->err_msg)
224
        log(L_ERR "%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
225
      else
226
        log(L_ERR "Unable to open configuration file %s: %m", config_name);
227
      config_free(conf);
228
    }
229
  else
230 bf1aec97 Ondrej Zajicek
    config_commit(conf, RECONFIG_HARD);
231 50fe90ed Martin Mares
}
232
233
void
234 bf1aec97 Ondrej Zajicek
cmd_reconfig(char *name, int type)
235 50fe90ed Martin Mares
{
236
  struct config *conf;
237
238 e0a45fb4 Ondrej Zajicek
  if (cli_access_restricted())
239
    return;
240
241 50fe90ed Martin Mares
  if (!name)
242
    name = config_name;
243
  cli_msg(-2, "Reading configuration from %s", name);
244
  if (!unix_read_config(&conf, name))
245
    {
246
      if (conf->err_msg)
247
        cli_msg(8002, "%s, line %d: %s", name, conf->err_lino, conf->err_msg);
248
      else
249
        cli_msg(8002, "%s: %m", name);
250
      config_free(conf);
251
    }
252
  else
253
    {
254 bf1aec97 Ondrej Zajicek
      switch (config_commit(conf, type))
255 50fe90ed Martin Mares
        {
256
        case CONF_DONE:
257
          cli_msg(3, "Reconfigured.");
258
          break;
259
        case CONF_PROGRESS:
260
          cli_msg(4, "Reconfiguration in progress.");
261
          break;
262 bf8558bc Martin Mares
        case CONF_SHUTDOWN:
263
          cli_msg(6, "Reconfiguration ignored, shutting down.");
264
          break;
265 50fe90ed Martin Mares
        default:
266
          cli_msg(5, "Reconfiguration already in progress, queueing new config");
267
        }
268
    }
269 4c9dd1e4 Martin Mares
}
270
271
/*
272 7d3aab1c Martin Mares
 *        Command-Line Interface
273
 */
274
275
static sock *cli_sk;
276 dc82daaa Martin Mares
static char *path_control_socket = PATH_CONTROL_SOCKET;
277 7d3aab1c Martin Mares
278 6baef17e Ondrej Zajicek
279
static void
280 7d3aab1c Martin Mares
cli_write(cli *c)
281
{
282
  sock *s = c->priv;
283
284 6baef17e Ondrej Zajicek
  while (c->tx_pos)
285 7d3aab1c Martin Mares
    {
286
      struct cli_out *o = c->tx_pos;
287 6baef17e Ondrej Zajicek
288
      int len = o->wpos - o->outpos;
289 7d3aab1c Martin Mares
      s->tbuf = o->outpos;
290 6baef17e Ondrej Zajicek
      o->outpos = o->wpos;
291
292
      if (sk_send(s, len) <= 0)
293
        return;
294
295
      c->tx_pos = o->next;
296 7d3aab1c Martin Mares
    }
297 6baef17e Ondrej Zajicek
298
  /* Everything is written */
299
  s->tbuf = NULL;
300
  cli_written(c);
301
}
302
303
void
304
cli_write_trigger(cli *c)
305
{
306
  sock *s = c->priv;
307
308
  if (s->tbuf == NULL)
309
    cli_write(c);
310
}
311
312
static void
313
cli_tx(sock *s)
314
{
315
  cli_write(s->data);
316 7d3aab1c Martin Mares
}
317
318
int
319
cli_get_command(cli *c)
320
{
321
  sock *s = c->priv;
322
  byte *t = c->rx_aux ? : s->rbuf;
323
  byte *tend = s->rpos;
324
  byte *d = c->rx_pos;
325
  byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
326
327
  while (t < tend)
328
    {
329
      if (*t == '\r')
330
        t++;
331
      else if (*t == '\n')
332
        {
333
          t++;
334
          c->rx_pos = c->rx_buf;
335
          c->rx_aux = t;
336
          *d = 0;
337
          return (d < dend) ? 1 : -1;
338
        }
339
      else if (d < dend)
340
        *d++ = *t++;
341
    }
342
  c->rx_aux = s->rpos = s->rbuf;
343
  c->rx_pos = d;
344
  return 0;
345
}
346
347
static int
348 6578a604 Martin Mares
cli_rx(sock *s, int size UNUSED)
349 7d3aab1c Martin Mares
{
350
  cli_kick(s->data);
351
  return 0;
352
}
353
354
static void
355
cli_err(sock *s, int err)
356
{
357 4761efdb Martin Mares
  if (config->cli_debug)
358
    {
359
      if (err)
360
        log(L_INFO "CLI connection dropped: %s", strerror(err));
361
      else
362
        log(L_INFO "CLI connection closed");
363
    }
364 7d3aab1c Martin Mares
  cli_free(s->data);
365
}
366
367
static int
368 6578a604 Martin Mares
cli_connect(sock *s, int size UNUSED)
369 7d3aab1c Martin Mares
{
370
  cli *c;
371
372 4761efdb Martin Mares
  if (config->cli_debug)
373
    log(L_INFO "CLI connect");
374 7d3aab1c Martin Mares
  s->rx_hook = cli_rx;
375
  s->tx_hook = cli_tx;
376
  s->err_hook = cli_err;
377
  s->data = c = cli_new(s);
378 dc82daaa Martin Mares
  s->pool = c->pool;                /* We need to have all the socket buffers allocated in the cli pool */
379 7d3aab1c Martin Mares
  c->rx_pos = c->rx_buf;
380
  c->rx_aux = NULL;
381 ea0ac8f6 Martin Mares
  rmove(s, c->pool);
382 7d3aab1c Martin Mares
  return 1;
383
}
384
385
static void
386
cli_init_unix(void)
387
{
388
  sock *s;
389
390
  cli_init();
391
  s = cli_sk = sk_new(cli_pool);
392
  s->type = SK_UNIX_PASSIVE;
393
  s->rx_hook = cli_connect;
394 e1ddd993 Martin Mares
  s->rbsize = 1024;
395 97e46d28 Ondrej Zajicek
  sk_open_unix(s, path_control_socket);
396 7d3aab1c Martin Mares
}
397
398
/*
399 f4aabcee Martin Mares
 *        Shutdown
400
 */
401
402
void
403 e0a45fb4 Ondrej Zajicek
cmd_shutdown(void)
404
{
405
  if (cli_access_restricted())
406
    return;
407
408
  cli_msg(7, "Shutdown requested");
409
  order_shutdown();
410
}
411
412
void
413 f4aabcee Martin Mares
async_shutdown(void)
414
{
415 6b9fa320 Martin Mares
  DBG("Shutting down...\n");
416 bf8558bc Martin Mares
  order_shutdown();
417 f4aabcee Martin Mares
}
418
419
void
420 bf8558bc Martin Mares
sysdep_shutdown_done(void)
421 f4aabcee Martin Mares
{
422 d3f36e59 Ondrej Zajicek
  unlink(path_control_socket);
423 76b53a4e Ondrej Zajicek
  log_msg(L_FATAL "Shutdown completed");
424 653b4015 Ondrej Zajicek
  exit(0);
425 f4aabcee Martin Mares
}
426
427
/*
428 4c9dd1e4 Martin Mares
 *        Signals
429
 */
430
431
static void
432 6578a604 Martin Mares
handle_sighup(int sig UNUSED)
433 4c9dd1e4 Martin Mares
{
434 6b9fa320 Martin Mares
  DBG("Caught SIGHUP...\n");
435 4c9dd1e4 Martin Mares
  async_config_flag = 1;
436
}
437
438
static void
439 6578a604 Martin Mares
handle_sigusr(int sig UNUSED)
440 4c9dd1e4 Martin Mares
{
441 6b9fa320 Martin Mares
  DBG("Caught SIGUSR...\n");
442 4c9dd1e4 Martin Mares
  async_dump_flag = 1;
443
}
444
445
static void
446 6578a604 Martin Mares
handle_sigterm(int sig UNUSED)
447 f4aabcee Martin Mares
{
448 6b9fa320 Martin Mares
  DBG("Caught SIGTERM...\n");
449 f4aabcee Martin Mares
  async_shutdown_flag = 1;
450
}
451
452
static void
453 4c9dd1e4 Martin Mares
signal_init(void)
454
{
455
  struct sigaction sa;
456
457
  bzero(&sa, sizeof(sa));
458
  sa.sa_handler = handle_sigusr;
459
  sa.sa_flags = SA_RESTART;
460
  sigaction(SIGUSR1, &sa, NULL);
461
  sa.sa_handler = handle_sighup;
462
  sa.sa_flags = SA_RESTART;
463
  sigaction(SIGHUP, &sa, NULL);
464 f4aabcee Martin Mares
  sa.sa_handler = handle_sigterm;
465
  sa.sa_flags = SA_RESTART;
466
  sigaction(SIGTERM, &sa, NULL);
467 4c9dd1e4 Martin Mares
  signal(SIGPIPE, SIG_IGN);
468
}
469
470
/*
471
 *        Parsing of command-line arguments
472
 */
473
474 1bc26957 Ondrej Zajicek
static char *opt_list = "c:dD:ps:u:g:";
475 44d4ab7a Ondrej Zajicek
static int parse_and_exit;
476
char *bird_name;
477 1bc26957 Ondrej Zajicek
static char *use_user;
478
static char *use_group;
479 0bcba21e Martin Mares
480 4c9dd1e4 Martin Mares
static void
481
usage(void)
482
{
483 1bc26957 Ondrej Zajicek
  fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-u <user>] [-g <group>]\n", bird_name);
484 4c9dd1e4 Martin Mares
  exit(1);
485
}
486
487 44d4ab7a Ondrej Zajicek
static inline char *
488
get_bird_name(char *s, char *def)
489
{
490
  char *t;
491
  if (!s)
492
    return def;
493
  t = strrchr(s, '/');
494
  if (!t)
495
    return s;
496
  if (!t[1])
497
    return def;
498
  return t+1;
499
}
500 a4644ed6 Ondrej Zajicek
501 1bc26957 Ondrej Zajicek
static inline uid_t
502
get_uid(const char *s)
503
{
504
  struct passwd *pw;
505
  char *endptr;
506
  
507
  errno = 0;
508
  long int rv = strtol(s, &endptr, 10);
509
510
  if (!errno && !*endptr)
511
    return rv;
512
513
  pw = getpwnam(s);
514
  if (!pw)
515
    die("Cannot find user '%s'", s);
516
517
  return pw->pw_uid;
518
}
519
520
static inline gid_t
521
get_gid(const char *s)
522
{
523
  struct group *gr;
524
  char *endptr;
525
  
526
  errno = 0;
527
  long int rv = strtol(s, &endptr, 10);
528
529
  if (!errno && !*endptr)
530
    return rv;
531
532
  gr = getgrnam(s);
533
  if (!gr)
534
    die("Cannot find group '%s'", s);
535
536
  return gr->gr_gid;
537
}
538
539 4c9dd1e4 Martin Mares
static void
540
parse_args(int argc, char **argv)
541
{
542
  int c;
543
544 44d4ab7a Ondrej Zajicek
  bird_name = get_bird_name(argv[0], "bird");
545 e67af428 Martin Mares
  if (argc == 2)
546
    {
547
      if (!strcmp(argv[1], "--version"))
548
        {
549
          fprintf(stderr, "BIRD version " BIRD_VERSION "\n");
550
          exit(0);
551
        }
552
      if (!strcmp(argv[1], "--help"))
553
        usage();
554
    }
555 4c9dd1e4 Martin Mares
  while ((c = getopt(argc, argv, opt_list)) >= 0)
556
    switch (c)
557
      {
558
      case 'c':
559
        config_name = optarg;
560
        break;
561
      case 'd':
562 a0c37b45 Martin Mares
        debug_flag |= 1;
563
        break;
564
      case 'D':
565 4c9dd1e4 Martin Mares
        log_init_debug(optarg);
566 a0c37b45 Martin Mares
        debug_flag |= 2;
567 4c9dd1e4 Martin Mares
        break;
568 a4644ed6 Ondrej Zajicek
      case 'p':
569
        parse_and_exit = 1;
570
        break;
571 dc82daaa Martin Mares
      case 's':
572
        path_control_socket = optarg;
573
        break;
574 1bc26957 Ondrej Zajicek
      case 'u':
575
        use_user = optarg;
576
        break;
577
      case 'g':
578
        use_group = optarg;
579
        break;
580 4c9dd1e4 Martin Mares
      default:
581
        usage();
582
      }
583
  if (optind < argc)
584
    usage();
585
}
586
587 fd50083d Martin Mares
/*
588
 *        Hic Est main()
589
 */
590 25697773 Martin Mares
591
int
592 4c9dd1e4 Martin Mares
main(int argc, char **argv)
593 25697773 Martin Mares
{
594 7a2105be Martin Mares
#ifdef HAVE_LIBDMALLOC
595
  if (!getenv("DMALLOC_OPTIONS"))
596
    dmalloc_debug(0x2f03d00);
597
#endif
598
599 4c9dd1e4 Martin Mares
  parse_args(argc, argv);
600 a0c37b45 Martin Mares
  if (debug_flag == 1)
601
    log_init_debug("");
602 44d4ab7a Ondrej Zajicek
  log_switch(debug_flag, NULL, NULL);
603 4c9dd1e4 Martin Mares
604 1bc26957 Ondrej Zajicek
  if (use_group)
605
    drop_gid(get_gid(use_group));
606
607
  if (use_user)
608
    drop_uid(get_uid(use_user));
609
610 a6250a7d Ondrej Zajicek
  if (!parse_and_exit)
611
    test_old_bird(path_control_socket);
612 41c8976e Ondrej Filip
613 6b9fa320 Martin Mares
  DBG("Initializing.\n");
614 c74c0e3c Martin Mares
  resource_init();
615 f545d387 Martin Mares
  olock_init();
616 b5d9ee5c Martin Mares
  io_init();
617 2326b001 Martin Mares
  rt_init();
618 8a48ecb8 Martin Mares
  if_init();
619 c74c0e3c Martin Mares
620 97e46d28 Ondrej Zajicek
  if (!parse_and_exit)
621
    cli_init_unix();
622
623 0432c017 Martin Mares
  protos_build();
624 3991d84e Martin Mares
  proto_build(&proto_unix_kernel);
625
  proto_build(&proto_unix_iface);
626 c74c0e3c Martin Mares
627
  read_config();
628 8a48ecb8 Martin Mares
629 a4644ed6 Ondrej Zajicek
  if (parse_and_exit)
630
    exit(0);
631
632 0bcba21e Martin Mares
  if (!debug_flag)
633
    {
634
      pid_t pid = fork();
635
      if (pid < 0)
636
        die("fork: %m");
637 4524331a Martin Mares
      if (pid)
638 0bcba21e Martin Mares
        return 0;
639
      setsid();
640 8411a37e Martin Mares
      close(0);
641
      if (open("/dev/null", O_RDWR) < 0)
642
        die("Cannot open /dev/null: %m");
643
      dup2(0, 1);
644
      dup2(0, 2);
645 0bcba21e Martin Mares
    }
646
647 b5d9ee5c Martin Mares
  signal_init();
648
649 9a220cab Martin Mares
#ifdef LOCAL_DEBUG
650
  async_dump_flag = 1;
651
#endif
652 8a48ecb8 Martin Mares
653 76b53a4e Ondrej Zajicek
  log(L_INFO "Started");
654 6b9fa320 Martin Mares
  DBG("Entering I/O loop.\n");
655 25697773 Martin Mares
656 b5d9ee5c Martin Mares
  io_loop();
657 08c69a77 Martin Mares
  bug("I/O loop died");
658 25697773 Martin Mares
}