]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/unix/main.c
Main: Improve BIRD help messages
[thirdparty/bird.git] / sysdep / unix / main.c
CommitLineData
25697773
MM
1/*
2 * BIRD Internet Routing Daemon -- Unix Entry Point
3 *
50fe90ed 4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
25697773
MM
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9a220cab 9#undef LOCAL_DEBUG
6b9fa320 10
1bc26957
OZ
11#define _GNU_SOURCE 1
12
25697773 13#include <stdio.h>
7a2105be 14#include <stdlib.h>
70591fa0
MM
15#include <fcntl.h>
16#include <unistd.h>
b1a1faba 17#include <signal.h>
1bc26957
OZ
18#include <pwd.h>
19#include <grp.h>
b1b19433 20#include <sys/stat.h>
48ec367a 21#include <libgen.h>
25697773
MM
22
23#include "nest/bird.h"
24#include "lib/lists.h"
25#include "lib/resource.h"
b5d9ee5c 26#include "lib/socket.h"
14dea0ed 27#include "lib/event.h"
221135d6 28#include "lib/string.h"
25697773 29#include "nest/route.h"
b5d9ee5c 30#include "nest/protocol.h"
8a48ecb8 31#include "nest/iface.h"
7d3aab1c 32#include "nest/cli.h"
f545d387 33#include "nest/locks.h"
70591fa0 34#include "conf/conf.h"
b9d70dc8 35#include "filter/filter.h"
b5d9ee5c
MM
36
37#include "unix.h"
7e7790c6 38#include "krt.h"
b5d9ee5c
MM
39
40/*
41 * Debugging
42 */
43
f9eb8f7e
MM
44#ifdef DEBUGGING
45static int debug_flag = 1;
46#else
47static int debug_flag = 0;
48#endif
49
4c9dd1e4
MM
50void
51async_dump(void)
b5d9ee5c 52{
4c9dd1e4 53 debug("INTERNAL STATE DUMP\n\n");
b5d9ee5c 54
5bc512aa 55 rdump(&root_pool);
b5d9ee5c
MM
56 sk_dump_all();
57 tm_dump_all();
8a48ecb8 58 if_dump_all();
869c6959 59 neigh_dump_all();
b5d9ee5c
MM
60 rta_dump_all();
61 rt_dump_all();
86b00230 62 protos_dump_all();
b5d9ee5c
MM
63
64 debug("\n");
65}
66
1bc26957
OZ
67/*
68 * Dropping privileges
69 */
70
71#ifdef CONFIG_RESTRICTED_PRIVILEGES
72#include "lib/syspriv.h"
73#else
74
75static inline void
76drop_uid(uid_t uid)
77{
78 die("Cannot change user on this platform");
79}
80
81#endif
82
83static inline void
84drop_gid(gid_t gid)
85{
86 if (setgid(gid) < 0)
87 die("setgid: %m");
88}
89
b5d9ee5c 90/*
70591fa0 91 * Reading the Configuration
b5d9ee5c
MM
92 */
93
acc93efd
OZ
94#ifdef PATH_IPROUTE_DIR
95
96static inline void
97add_num_const(char *name, int val)
98{
9b9a7143 99 struct symbol *s = cf_get_symbol(name);
1103b32e
OZ
100 s->class = SYM_CONSTANT | T_INT;
101 s->def = cfg_allocz(sizeof(struct f_val));
102 SYM_TYPE(s) = T_INT;
103 SYM_VAL(s).i = val;
acc93efd
OZ
104}
105
106/* the code of read_iproute_table() is based on
107 rtnl_tab_initialize() from iproute2 package */
108static void
109read_iproute_table(char *file, char *prefix, int max)
110{
111 char buf[512], namebuf[512];
112 char *name;
113 int val;
114 FILE *fp;
115
116 strcpy(namebuf, prefix);
117 name = namebuf + strlen(prefix);
118
119 fp = fopen(file, "r");
120 if (!fp)
121 return;
122
123 while (fgets(buf, sizeof(buf), fp))
124 {
125 char *p = buf;
126
127 while (*p == ' ' || *p == '\t')
128 p++;
129
130 if (*p == '#' || *p == '\n' || *p == 0)
131 continue;
132
133 if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
134 sscanf(p, "0x%x %s #", &val, name) != 2 &&
135 sscanf(p, "%d %s\n", &val, name) != 2 &&
136 sscanf(p, "%d %s #", &val, name) != 2)
137 continue;
138
139 if (val < 0 || val > max)
140 continue;
141
142 for(p = name; *p; p++)
143 if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
144 *p = '_';
145
146 add_num_const(namebuf, val);
147 }
148
149 fclose(fp);
150}
151
152#endif // PATH_IPROUTE_DIR
153
154
ab188fb7 155static char *config_name = PATH_CONFIG_FILE;
70591fa0
MM
156
157static int
ae80a2de 158cf_read(byte *dest, uint len, int fd)
70591fa0 159{
48ec367a 160 int l = read(fd, dest, len);
70591fa0
MM
161 if (l < 0)
162 cf_error("Read error");
163 return l;
164}
165
a0c37b45
MM
166void
167sysdep_preconfig(struct config *c)
168{
169 init_list(&c->logfiles);
acc93efd 170
8bcb5fb1
OZ
171 c->latency_limit = UNIX_DEFAULT_LATENCY_LIMIT;
172 c->watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING;
173
acc93efd 174#ifdef PATH_IPROUTE_DIR
72aed1a0 175 read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
acc93efd
OZ
176 read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
177 read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
178 read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
179#endif
a0c37b45
MM
180}
181
50fe90ed 182int
6578a604 183sysdep_commit(struct config *new, struct config *old UNUSED)
a0c37b45 184{
44d4ab7a 185 log_switch(debug_flag, &new->logfiles, new->syslog_name);
50fe90ed 186 return 0;
a0c37b45
MM
187}
188
50fe90ed
MM
189static int
190unix_read_config(struct config **cp, char *name)
70591fa0 191{
50fe90ed 192 struct config *conf = config_alloc(name);
3c3271d9 193 int ret;
31b3e1bb 194
50fe90ed 195 *cp = conf;
48ec367a
OF
196 conf->file_fd = open(name, O_RDONLY);
197 if (conf->file_fd < 0)
50fe90ed 198 return 0;
70591fa0 199 cf_read_hook = cf_read;
3c3271d9 200 ret = config_parse(conf);
48ec367a 201 close(conf->file_fd);
3c3271d9 202 return ret;
50fe90ed
MM
203}
204
0e175f9f 205static struct config *
50fe90ed
MM
206read_config(void)
207{
208 struct config *conf;
209
210 if (!unix_read_config(&conf, config_name))
211 {
212 if (conf->err_msg)
48ec367a 213 die("%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
50fe90ed
MM
214 else
215 die("Unable to open configuration file %s: %m", config_name);
216 }
0e175f9f
OZ
217
218 return conf;
70591fa0 219}
31b3e1bb 220
4c9dd1e4
MM
221void
222async_config(void)
223{
50fe90ed
MM
224 struct config *conf;
225
226 log(L_INFO "Reconfiguration requested by SIGHUP");
227 if (!unix_read_config(&conf, config_name))
228 {
229 if (conf->err_msg)
48ec367a 230 log(L_ERR "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
50fe90ed
MM
231 else
232 log(L_ERR "Unable to open configuration file %s: %m", config_name);
233 config_free(conf);
234 }
235 else
a92cf57d 236 config_commit(conf, RECONFIG_HARD, 0);
50fe90ed
MM
237}
238
a92cf57d
OZ
239static struct config *
240cmd_read_config(char *name)
50fe90ed
MM
241{
242 struct config *conf;
243
244 if (!name)
245 name = config_name;
a92cf57d 246
50fe90ed
MM
247 cli_msg(-2, "Reading configuration from %s", name);
248 if (!unix_read_config(&conf, name))
249 {
250 if (conf->err_msg)
ed7c4b0c 251 cli_msg(8002, "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
50fe90ed
MM
252 else
253 cli_msg(8002, "%s: %m", name);
254 config_free(conf);
a92cf57d 255 conf = NULL;
50fe90ed 256 }
a92cf57d
OZ
257
258 return conf;
259}
260
261void
262cmd_check_config(char *name)
263{
264 struct config *conf = cmd_read_config(name);
265 if (!conf)
266 return;
267
268 cli_msg(20, "Configuration OK");
269 config_free(conf);
270}
271
272static void
273cmd_reconfig_msg(int r)
274{
275 switch (r)
50fe90ed 276 {
a92cf57d
OZ
277 case CONF_DONE: cli_msg( 3, "Reconfigured"); break;
278 case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break;
279 case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break;
280 case CONF_UNQUEUED: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break;
281 case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break;
282 case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break;
283 case CONF_NOTHING: cli_msg(19, "Nothing to do"); break;
284 default: break;
285 }
286}
287
288/* Hack for scheduled undo notification */
289cli *cmd_reconfig_stored_cli;
290
291void
292cmd_reconfig_undo_notify(void)
293{
294 if (cmd_reconfig_stored_cli)
295 {
296 cli *c = cmd_reconfig_stored_cli;
297 cli_printf(c, CLI_ASYNC_CODE, "Config timeout expired, starting undo");
298 cli_write_trigger(c);
299 }
300}
301
302void
303cmd_reconfig(char *name, int type, int timeout)
304{
305 if (cli_access_restricted())
306 return;
307
308 struct config *conf = cmd_read_config(name);
309 if (!conf)
310 return;
311
312 int r = config_commit(conf, type, timeout);
313
314 if ((r >= 0) && (timeout > 0))
315 {
316 cmd_reconfig_stored_cli = this_cli;
317 cli_msg(-22, "Undo scheduled in %d s", timeout);
50fe90ed 318 }
a92cf57d
OZ
319
320 cmd_reconfig_msg(r);
321}
322
323void
324cmd_reconfig_confirm(void)
325{
326 if (cli_access_restricted())
327 return;
328
329 int r = config_confirm();
330 cmd_reconfig_msg(r);
331}
332
333void
334cmd_reconfig_undo(void)
335{
336 if (cli_access_restricted())
337 return;
338
339 cli_msg(-21, "Undo requested");
340
341 int r = config_undo();
342 cmd_reconfig_msg(r);
4c9dd1e4
MM
343}
344
7d3aab1c
MM
345/*
346 * Command-Line Interface
347 */
348
349static sock *cli_sk;
dc82daaa 350static char *path_control_socket = PATH_CONTROL_SOCKET;
7d3aab1c 351
6baef17e
OZ
352
353static void
7d3aab1c
MM
354cli_write(cli *c)
355{
356 sock *s = c->priv;
357
6baef17e 358 while (c->tx_pos)
7d3aab1c
MM
359 {
360 struct cli_out *o = c->tx_pos;
6baef17e
OZ
361
362 int len = o->wpos - o->outpos;
7d3aab1c 363 s->tbuf = o->outpos;
6baef17e
OZ
364 o->outpos = o->wpos;
365
366 if (sk_send(s, len) <= 0)
367 return;
368
369 c->tx_pos = o->next;
7d3aab1c 370 }
6baef17e
OZ
371
372 /* Everything is written */
373 s->tbuf = NULL;
374 cli_written(c);
375}
376
377void
378cli_write_trigger(cli *c)
379{
380 sock *s = c->priv;
381
382 if (s->tbuf == NULL)
383 cli_write(c);
384}
385
386static void
387cli_tx(sock *s)
388{
389 cli_write(s->data);
7d3aab1c
MM
390}
391
392int
393cli_get_command(cli *c)
394{
395 sock *s = c->priv;
396 byte *t = c->rx_aux ? : s->rbuf;
397 byte *tend = s->rpos;
398 byte *d = c->rx_pos;
399 byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
400
401 while (t < tend)
402 {
403 if (*t == '\r')
404 t++;
405 else if (*t == '\n')
406 {
407 t++;
408 c->rx_pos = c->rx_buf;
409 c->rx_aux = t;
410 *d = 0;
411 return (d < dend) ? 1 : -1;
412 }
413 else if (d < dend)
414 *d++ = *t++;
415 }
416 c->rx_aux = s->rpos = s->rbuf;
417 c->rx_pos = d;
418 return 0;
419}
420
421static int
6578a604 422cli_rx(sock *s, int size UNUSED)
7d3aab1c 423{
7d3aab1c
MM
424 cli_kick(s->data);
425 return 0;
426}
427
7d3aab1c
MM
428static void
429cli_err(sock *s, int err)
430{
4761efdb
MM
431 if (config->cli_debug)
432 {
433 if (err)
434 log(L_INFO "CLI connection dropped: %s", strerror(err));
435 else
436 log(L_INFO "CLI connection closed");
437 }
7d3aab1c
MM
438 cli_free(s->data);
439}
440
441static int
6578a604 442cli_connect(sock *s, int size UNUSED)
7d3aab1c
MM
443{
444 cli *c;
445
4761efdb
MM
446 if (config->cli_debug)
447 log(L_INFO "CLI connect");
7d3aab1c
MM
448 s->rx_hook = cli_rx;
449 s->tx_hook = cli_tx;
450 s->err_hook = cli_err;
7d3aab1c 451 s->data = c = cli_new(s);
dc82daaa 452 s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
9e7b3ebd 453 s->fast_rx = 1;
7d3aab1c
MM
454 c->rx_pos = c->rx_buf;
455 c->rx_aux = NULL;
ea0ac8f6 456 rmove(s, c->pool);
7d3aab1c
MM
457 return 1;
458}
459
460static void
e8b89a61 461cli_init_unix(uid_t use_uid, gid_t use_gid)
7d3aab1c
MM
462{
463 sock *s;
464
465 cli_init();
466 s = cli_sk = sk_new(cli_pool);
467 s->type = SK_UNIX_PASSIVE;
468 s->rx_hook = cli_connect;
e1ddd993 469 s->rbsize = 1024;
9e7b3ebd 470 s->fast_rx = 1;
05476c4d
OZ
471
472 /* Return value intentionally ignored */
473 unlink(path_control_socket);
474
475 if (sk_open_unix(s, path_control_socket) < 0)
476 die("Cannot create control socket %s: %m", path_control_socket);
e8b89a61
OZ
477
478 if (use_uid || use_gid)
479 if (chown(path_control_socket, use_uid, use_gid) < 0)
480 die("chown: %m");
481
482 if (chmod(path_control_socket, 0660) < 0)
483 die("chmod: %m");
7d3aab1c
MM
484}
485
e7c23802
OZ
486/*
487 * PID file
488 */
489
490static char *pid_file;
491static int pid_fd;
492
493static inline void
494open_pid_file(void)
495{
496 if (!pid_file)
497 return;
498
499 pid_fd = open(pid_file, O_WRONLY|O_CREAT, 0664);
500 if (pid_fd < 0)
501 die("Cannot create PID file %s: %m", pid_file);
502}
503
504static inline void
505write_pid_file(void)
506{
507 int pl, rv;
508 char ps[24];
509
510 if (!pid_file)
511 return;
512
513 /* We don't use PID file for uniqueness, so no need for locking */
514
515 pl = bsnprintf(ps, sizeof(ps), "%ld\n", (long) getpid());
516 if (pl < 0)
517 bug("PID buffer too small");
518
519 rv = ftruncate(pid_fd, 0);
520 if (rv < 0)
521 die("fruncate: %m");
522
523 rv = write(pid_fd, ps, pl);
524 if(rv < 0)
525 die("write: %m");
526
527 close(pid_fd);
528}
529
530static inline void
531unlink_pid_file(void)
532{
533 if (pid_file)
534 unlink(pid_file);
535}
536
537
f4aabcee
MM
538/*
539 * Shutdown
540 */
541
e0a45fb4
OZ
542void
543cmd_shutdown(void)
544{
545 if (cli_access_restricted())
546 return;
547
548 cli_msg(7, "Shutdown requested");
549 order_shutdown();
550}
551
f4aabcee
MM
552void
553async_shutdown(void)
554{
6b9fa320 555 DBG("Shutting down...\n");
bf8558bc 556 order_shutdown();
f4aabcee
MM
557}
558
559void
bf8558bc 560sysdep_shutdown_done(void)
f4aabcee 561{
e7c23802 562 unlink_pid_file();
d3f36e59 563 unlink(path_control_socket);
76b53a4e 564 log_msg(L_FATAL "Shutdown completed");
653b4015 565 exit(0);
f4aabcee
MM
566}
567
4c9dd1e4
MM
568/*
569 * Signals
570 */
571
572static void
6578a604 573handle_sighup(int sig UNUSED)
4c9dd1e4 574{
6b9fa320 575 DBG("Caught SIGHUP...\n");
4c9dd1e4
MM
576 async_config_flag = 1;
577}
578
579static void
6578a604 580handle_sigusr(int sig UNUSED)
4c9dd1e4 581{
6b9fa320 582 DBG("Caught SIGUSR...\n");
4c9dd1e4
MM
583 async_dump_flag = 1;
584}
585
f4aabcee 586static void
6578a604 587handle_sigterm(int sig UNUSED)
f4aabcee 588{
6b9fa320 589 DBG("Caught SIGTERM...\n");
f4aabcee
MM
590 async_shutdown_flag = 1;
591}
592
8bcb5fb1
OZ
593void watchdog_sigalrm(int sig UNUSED);
594
4c9dd1e4
MM
595static void
596signal_init(void)
597{
598 struct sigaction sa;
599
600 bzero(&sa, sizeof(sa));
601 sa.sa_handler = handle_sigusr;
602 sa.sa_flags = SA_RESTART;
603 sigaction(SIGUSR1, &sa, NULL);
604 sa.sa_handler = handle_sighup;
605 sa.sa_flags = SA_RESTART;
606 sigaction(SIGHUP, &sa, NULL);
f4aabcee
MM
607 sa.sa_handler = handle_sigterm;
608 sa.sa_flags = SA_RESTART;
609 sigaction(SIGTERM, &sa, NULL);
8bcb5fb1
OZ
610 sa.sa_handler = watchdog_sigalrm;
611 sa.sa_flags = 0;
612 sigaction(SIGALRM, &sa, NULL);
4c9dd1e4
MM
613 signal(SIGPIPE, SIG_IGN);
614}
615
616/*
617 * Parsing of command-line arguments
618 */
619
292f7858 620static char *opt_list = "c:dD:ps:P:u:g:flRh";
44d4ab7a
OZ
621static int parse_and_exit;
622char *bird_name;
1bc26957
OZ
623static char *use_user;
624static char *use_group;
1cd198cf 625static int run_in_foreground = 0;
0bcba21e 626
4c9dd1e4 627static void
292f7858 628display_usage(void)
4c9dd1e4 629{
292f7858
PT
630 fprintf(stderr, "Usage: %s [--version] [--help] [-c <config-file>] [OPTIONS]\n", bird_name);
631}
632
633static void
634display_help(void)
635{
636 display_usage();
637
638 fprintf(stderr,
639 "\n"
640 "Options: \n"
641 " -c <config-file> Use given configuration file instead\n"
642 " of prefix/etc/bird.conf\n"
643 " -d Enable debug messages and run bird in foreground\n"
644 " -D <debug-file> Log debug messages to given file instead of stderr\n"
645 " -f Run bird in foreground\n"
646 " -g <group> Use given group ID\n"
647 " -h, --help Display this information\n"
648 " -l Look for a configuration file and a communication socket\n"
649 " file in the current working directory\n"
650 " -p Test configuration file and exit without start\n"
651 " -P <pid-file> Create a PID file with given filename\n"
652 " -R Apply graceful restart recovery after start\n"
653 " -s <control-socket> Use given filename for a control socket\n"
654 " -u <user> Drop privileges and use given user ID\n"
655 " --version Display version of BIRD\n");
656
657 exit(0);
658}
659
660static void
661display_version(void)
662{
663 fprintf(stderr, "BIRD version " BIRD_VERSION "\n");
664 exit(0);
4c9dd1e4
MM
665}
666
44d4ab7a
OZ
667static inline char *
668get_bird_name(char *s, char *def)
669{
670 char *t;
671 if (!s)
672 return def;
673 t = strrchr(s, '/');
674 if (!t)
675 return s;
676 if (!t[1])
677 return def;
678 return t+1;
679}
a4644ed6 680
1bc26957
OZ
681static inline uid_t
682get_uid(const char *s)
683{
684 struct passwd *pw;
685 char *endptr;
e8b89a61
OZ
686 long int rv;
687
688 if (!s)
689 return 0;
690
1bc26957 691 errno = 0;
e8b89a61 692 rv = strtol(s, &endptr, 10);
1bc26957
OZ
693
694 if (!errno && !*endptr)
695 return rv;
696
697 pw = getpwnam(s);
698 if (!pw)
699 die("Cannot find user '%s'", s);
700
701 return pw->pw_uid;
702}
703
704static inline gid_t
705get_gid(const char *s)
706{
707 struct group *gr;
708 char *endptr;
e8b89a61
OZ
709 long int rv;
710
711 if (!s)
712 return 0;
f2ae2bad 713
1bc26957 714 errno = 0;
e8b89a61 715 rv = strtol(s, &endptr, 10);
1bc26957
OZ
716
717 if (!errno && !*endptr)
718 return rv;
719
720 gr = getgrnam(s);
721 if (!gr)
722 die("Cannot find group '%s'", s);
723
724 return gr->gr_gid;
725}
726
4c9dd1e4
MM
727static void
728parse_args(int argc, char **argv)
729{
f2ae2bad
OZ
730 int config_changed = 0;
731 int socket_changed = 0;
4c9dd1e4
MM
732 int c;
733
44d4ab7a 734 bird_name = get_bird_name(argv[0], "bird");
e67af428
MM
735 if (argc == 2)
736 {
737 if (!strcmp(argv[1], "--version"))
292f7858 738 display_version();
e67af428 739 if (!strcmp(argv[1], "--help"))
292f7858 740 display_help();
e67af428 741 }
4c9dd1e4
MM
742 while ((c = getopt(argc, argv, opt_list)) >= 0)
743 switch (c)
744 {
745 case 'c':
746 config_name = optarg;
f2ae2bad 747 config_changed = 1;
4c9dd1e4
MM
748 break;
749 case 'd':
a0c37b45
MM
750 debug_flag |= 1;
751 break;
752 case 'D':
4c9dd1e4 753 log_init_debug(optarg);
a0c37b45 754 debug_flag |= 2;
4c9dd1e4 755 break;
a4644ed6
OZ
756 case 'p':
757 parse_and_exit = 1;
758 break;
dc82daaa
MM
759 case 's':
760 path_control_socket = optarg;
f2ae2bad 761 socket_changed = 1;
dc82daaa 762 break;
e7c23802
OZ
763 case 'P':
764 pid_file = optarg;
765 break;
1bc26957
OZ
766 case 'u':
767 use_user = optarg;
768 break;
769 case 'g':
770 use_group = optarg;
771 break;
1cd198cf
OF
772 case 'f':
773 run_in_foreground = 1;
774 break;
f2ae2bad
OZ
775 case 'l':
776 if (!config_changed)
777 config_name = xbasename(config_name);
778 if (!socket_changed)
779 path_control_socket = xbasename(path_control_socket);
780 break;
0c791f87
OZ
781 case 'R':
782 graceful_restart_recovery();
783 break;
292f7858
PT
784 case 'h':
785 display_help();
786 break;
4c9dd1e4 787 default:
292f7858
PT
788 fputc('\n', stderr);
789 display_usage();
790 exit(1);
4c9dd1e4
MM
791 }
792 if (optind < argc)
292f7858
PT
793 {
794 display_usage();
795 exit(1);
796 }
4c9dd1e4
MM
797}
798
fd50083d
MM
799/*
800 * Hic Est main()
801 */
25697773
MM
802
803int
4c9dd1e4 804main(int argc, char **argv)
25697773 805{
7a2105be
MM
806#ifdef HAVE_LIBDMALLOC
807 if (!getenv("DMALLOC_OPTIONS"))
808 dmalloc_debug(0x2f03d00);
809#endif
810
4c9dd1e4 811 parse_args(argc, argv);
a0c37b45
MM
812 if (debug_flag == 1)
813 log_init_debug("");
44d4ab7a 814 log_switch(debug_flag, NULL, NULL);
4c9dd1e4 815
c74c0e3c 816 resource_init();
f545d387 817 olock_init();
b5d9ee5c 818 io_init();
2326b001 819 rt_init();
8a48ecb8 820 if_init();
af582c48 821 roa_init();
a92cf57d 822 config_init();
c74c0e3c 823
e8b89a61
OZ
824 uid_t use_uid = get_uid(use_user);
825 gid_t use_gid = get_gid(use_group);
826
97e46d28 827 if (!parse_and_exit)
e8b89a61
OZ
828 {
829 test_old_bird(path_control_socket);
830 cli_init_unix(use_uid, use_gid);
831 }
832
833 if (use_gid)
834 drop_gid(use_gid);
835
836 if (use_uid)
837 drop_uid(use_uid);
97e46d28 838
e7c23802
OZ
839 if (!parse_and_exit)
840 open_pid_file();
841
0432c017 842 protos_build();
3991d84e
MM
843 proto_build(&proto_unix_kernel);
844 proto_build(&proto_unix_iface);
c74c0e3c 845
0e175f9f 846 struct config *conf = read_config();
8a48ecb8 847
a4644ed6
OZ
848 if (parse_and_exit)
849 exit(0);
850
1cd198cf 851 if (!(debug_flag||run_in_foreground))
0bcba21e
MM
852 {
853 pid_t pid = fork();
854 if (pid < 0)
855 die("fork: %m");
4524331a 856 if (pid)
0bcba21e
MM
857 return 0;
858 setsid();
8411a37e
MM
859 close(0);
860 if (open("/dev/null", O_RDWR) < 0)
861 die("Cannot open /dev/null: %m");
862 dup2(0, 1);
863 dup2(0, 2);
0bcba21e
MM
864 }
865
4e398e34
OZ
866 main_thread_init();
867
e7c23802
OZ
868 write_pid_file();
869
b5d9ee5c
MM
870 signal_init();
871
0e175f9f
OZ
872 config_commit(conf, RECONFIG_HARD, 0);
873
0c791f87
OZ
874 graceful_restart_init();
875
9a220cab
MM
876#ifdef LOCAL_DEBUG
877 async_dump_flag = 1;
878#endif
8a48ecb8 879
76b53a4e 880 log(L_INFO "Started");
6b9fa320 881 DBG("Entering I/O loop.\n");
25697773 882
b5d9ee5c 883 io_loop();
08c69a77 884 bug("I/O loop died");
25697773 885}