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