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