Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (10.9 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
#define _GNU_SOURCE 1
12

    
13
#include <stdio.h>
14
#include <stdlib.h>
15
#include <fcntl.h>
16
#include <unistd.h>
17
#include <signal.h>
18
#include <pwd.h>
19
#include <grp.h>
20

    
21
#include "nest/bird.h"
22
#include "lib/lists.h"
23
#include "lib/resource.h"
24
#include "lib/socket.h"
25
#include "lib/event.h"
26
#include "lib/string.h"
27
#include "nest/route.h"
28
#include "nest/protocol.h"
29
#include "nest/iface.h"
30
#include "nest/cli.h"
31
#include "nest/locks.h"
32
#include "conf/conf.h"
33
#include "filter/filter.h"
34

    
35
#include "unix.h"
36
#include "krt.h"
37

    
38
/*
39
 *        Debugging
40
 */
41

    
42
#ifdef DEBUGGING
43
static int debug_flag = 1;
44
#else
45
static int debug_flag = 0;
46
#endif
47

    
48
void
49
async_dump(void)
50
{
51
  debug("INTERNAL STATE DUMP\n\n");
52

    
53
  rdump(&root_pool);
54
  sk_dump_all();
55
  tm_dump_all();
56
  if_dump_all();
57
  neigh_dump_all();
58
  rta_dump_all();
59
  rt_dump_all();
60
  protos_dump_all();
61

    
62
  debug("\n");
63
}
64

    
65
/*
66
 *        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
 *        Reading the Configuration
90
 */
91

    
92
#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
static int conf_fd;
153
static char *config_name = PATH_CONFIG;
154

    
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
void
165
sysdep_preconfig(struct config *c)
166
{
167
  init_list(&c->logfiles);
168

    
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
}
176

    
177
int
178
sysdep_commit(struct config *new, struct config *old UNUSED)
179
{
180
  log_switch(debug_flag, &new->logfiles, new->syslog_name);
181
  return 0;
182
}
183

    
184
static int
185
unix_read_config(struct config **cp, char *name)
186
{
187
  struct config *conf = config_alloc(name);
188
  int ret;
189

    
190
  *cp = conf;
191
  conf_fd = open(name, O_RDONLY);
192
  if (conf_fd < 0)
193
    return 0;
194
  cf_read_hook = cf_read;
195
  ret = config_parse(conf);
196
  close(conf_fd);
197
  return ret;
198
}
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
  config_commit(conf, RECONFIG_HARD);
213
}
214

    
215
void
216
async_config(void)
217
{
218
  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
    config_commit(conf, RECONFIG_HARD);
231
}
232

    
233
void
234
cmd_reconfig(char *name, int type)
235
{
236
  struct config *conf;
237

    
238
  if (cli_access_restricted())
239
    return;
240

    
241
  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
      switch (config_commit(conf, type))
255
        {
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
        case CONF_SHUTDOWN:
263
          cli_msg(6, "Reconfiguration ignored, shutting down.");
264
          break;
265
        default:
266
          cli_msg(5, "Reconfiguration already in progress, queueing new config");
267
        }
268
    }
269
}
270

    
271
/*
272
 *        Command-Line Interface
273
 */
274

    
275
static sock *cli_sk;
276
static char *path_control_socket = PATH_CONTROL_SOCKET;
277

    
278

    
279
static void
280
cli_write(cli *c)
281
{
282
  sock *s = c->priv;
283

    
284
  while (c->tx_pos)
285
    {
286
      struct cli_out *o = c->tx_pos;
287

    
288
      int len = o->wpos - o->outpos;
289
      s->tbuf = o->outpos;
290
      o->outpos = o->wpos;
291

    
292
      if (sk_send(s, len) <= 0)
293
        return;
294

    
295
      c->tx_pos = o->next;
296
    }
297

    
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
}
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
cli_rx(sock *s, int size UNUSED)
349
{
350
  cli_kick(s->data);
351
  return 0;
352
}
353

    
354
static void
355
cli_err(sock *s, int err)
356
{
357
  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
  cli_free(s->data);
365
}
366

    
367
static int
368
cli_connect(sock *s, int size UNUSED)
369
{
370
  cli *c;
371

    
372
  if (config->cli_debug)
373
    log(L_INFO "CLI connect");
374
  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
  s->pool = c->pool;                /* We need to have all the socket buffers allocated in the cli pool */
379
  c->rx_pos = c->rx_buf;
380
  c->rx_aux = NULL;
381
  rmove(s, c->pool);
382
  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
  s->rbsize = 1024;
395
  sk_open_unix(s, path_control_socket);
396
}
397

    
398
/*
399
 *        Shutdown
400
 */
401

    
402
void
403
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
async_shutdown(void)
414
{
415
  DBG("Shutting down...\n");
416
  order_shutdown();
417
}
418

    
419
void
420
sysdep_shutdown_done(void)
421
{
422
  unlink(path_control_socket);
423
  log_msg(L_FATAL "Shutdown completed");
424
  exit(0);
425
}
426

    
427
/*
428
 *        Signals
429
 */
430

    
431
static void
432
handle_sighup(int sig UNUSED)
433
{
434
  DBG("Caught SIGHUP...\n");
435
  async_config_flag = 1;
436
}
437

    
438
static void
439
handle_sigusr(int sig UNUSED)
440
{
441
  DBG("Caught SIGUSR...\n");
442
  async_dump_flag = 1;
443
}
444

    
445
static void
446
handle_sigterm(int sig UNUSED)
447
{
448
  DBG("Caught SIGTERM...\n");
449
  async_shutdown_flag = 1;
450
}
451

    
452
static void
453
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
  sa.sa_handler = handle_sigterm;
465
  sa.sa_flags = SA_RESTART;
466
  sigaction(SIGTERM, &sa, NULL);
467
  signal(SIGPIPE, SIG_IGN);
468
}
469

    
470
/*
471
 *        Parsing of command-line arguments
472
 */
473

    
474
static char *opt_list = "c:dD:ps:u:g:";
475
static int parse_and_exit;
476
char *bird_name;
477
static char *use_user;
478
static char *use_group;
479

    
480
static void
481
usage(void)
482
{
483
  fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-u <user>] [-g <group>]\n", bird_name);
484
  exit(1);
485
}
486

    
487
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

    
501
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
static void
540
parse_args(int argc, char **argv)
541
{
542
  int c;
543

    
544
  bird_name = get_bird_name(argv[0], "bird");
545
  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
  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
        debug_flag |= 1;
563
        break;
564
      case 'D':
565
        log_init_debug(optarg);
566
        debug_flag |= 2;
567
        break;
568
      case 'p':
569
        parse_and_exit = 1;
570
        break;
571
      case 's':
572
        path_control_socket = optarg;
573
        break;
574
      case 'u':
575
        use_user = optarg;
576
        break;
577
      case 'g':
578
        use_group = optarg;
579
        break;
580
      default:
581
        usage();
582
      }
583
  if (optind < argc)
584
    usage();
585
}
586

    
587
/*
588
 *        Hic Est main()
589
 */
590

    
591
int
592
main(int argc, char **argv)
593
{
594
#ifdef HAVE_LIBDMALLOC
595
  if (!getenv("DMALLOC_OPTIONS"))
596
    dmalloc_debug(0x2f03d00);
597
#endif
598

    
599
  parse_args(argc, argv);
600
  if (debug_flag == 1)
601
    log_init_debug("");
602
  log_switch(debug_flag, NULL, NULL);
603

    
604
  if (use_group)
605
    drop_gid(get_gid(use_group));
606

    
607
  if (use_user)
608
    drop_uid(get_uid(use_user));
609

    
610
  if (!parse_and_exit)
611
    test_old_bird(path_control_socket);
612

    
613
  DBG("Initializing.\n");
614
  resource_init();
615
  olock_init();
616
  io_init();
617
  rt_init();
618
  if_init();
619

    
620
  if (!parse_and_exit)
621
    cli_init_unix();
622

    
623
  protos_build();
624
  proto_build(&proto_unix_kernel);
625
  proto_build(&proto_unix_iface);
626

    
627
  read_config();
628

    
629
  if (parse_and_exit)
630
    exit(0);
631

    
632
  if (!debug_flag)
633
    {
634
      pid_t pid = fork();
635
      if (pid < 0)
636
        die("fork: %m");
637
      if (pid)
638
        return 0;
639
      setsid();
640
      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
    }
646

    
647
  signal_init();
648

    
649
#ifdef LOCAL_DEBUG
650
  async_dump_flag = 1;
651
#endif
652

    
653
  log(L_INFO "Started");
654
  DBG("Entering I/O loop.\n");
655

    
656
  io_loop();
657
  bug("I/O loop died");
658
}