]>
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 | |
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 |
48 | static int debug_flag = 1; | |
49 | #else | |
50 | static int debug_flag = 0; | |
51 | #endif | |
52 | ||
4c9dd1e4 MM |
53 | void |
54 | async_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 | ||
78 | static inline void | |
3e236955 | 79 | drop_uid(uid_t uid UNUSED) |
1bc26957 OZ |
80 | { |
81 | die("Cannot change user on this platform"); | |
82 | } | |
83 | ||
84 | #endif | |
85 | ||
86 | static inline void | |
87 | drop_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 | ||
99 | static inline void | |
100 | add_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 */ | |
111 | static void | |
112 | read_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 | 158 | static char *config_name = PATH_CONFIG_FILE; |
70591fa0 MM |
159 | |
160 | static int | |
ae80a2de | 161 | cf_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 |
169 | void |
170 | sysdep_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 | 185 | int |
6578a604 | 186 | sysdep_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 |
192 | static int |
193 | unix_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 | 208 | static struct config * |
50fe90ed MM |
209 | read_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 |
224 | void |
225 | async_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 |
242 | static struct config * |
243 | cmd_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 | ||
264 | void | |
265 | cmd_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 | ||
275 | static void | |
276 | cmd_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 */ | |
292 | cli *cmd_reconfig_stored_cli; | |
293 | ||
294 | void | |
295 | cmd_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 | ||
305 | void | |
3e405fb1 | 306 | cmd_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 | ||
326 | void | |
327 | cmd_reconfig_confirm(void) | |
328 | { | |
329 | if (cli_access_restricted()) | |
330 | return; | |
331 | ||
332 | int r = config_confirm(); | |
333 | cmd_reconfig_msg(r); | |
334 | } | |
335 | ||
336 | void | |
337 | cmd_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 | ||
352 | static sock *cli_sk; | |
dc82daaa | 353 | static char *path_control_socket = PATH_CONTROL_SOCKET; |
7d3aab1c | 354 | |
6baef17e OZ |
355 | |
356 | static void | |
7d3aab1c MM |
357 | cli_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 | ||
380 | void | |
381 | cli_write_trigger(cli *c) | |
382 | { | |
383 | sock *s = c->priv; | |
384 | ||
385 | if (s->tbuf == NULL) | |
386 | cli_write(c); | |
387 | } | |
388 | ||
389 | static void | |
390 | cli_tx(sock *s) | |
391 | { | |
392 | cli_write(s->data); | |
7d3aab1c MM |
393 | } |
394 | ||
395 | int | |
396 | cli_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 | ||
424 | static int | |
3e236955 | 425 | cli_rx(sock *s, uint size UNUSED) |
7d3aab1c | 426 | { |
7d3aab1c MM |
427 | cli_kick(s->data); |
428 | return 0; | |
429 | } | |
430 | ||
7d3aab1c MM |
431 | static void |
432 | cli_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 | ||
444 | static int | |
3e236955 | 445 | cli_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 | ||
463 | static void | |
e8b89a61 | 464 | cli_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 | ||
493 | static char *pid_file; | |
494 | static int pid_fd; | |
495 | ||
496 | static inline void | |
497 | open_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 | ||
507 | static inline void | |
508 | write_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 | ||
533 | static inline void | |
534 | unlink_pid_file(void) | |
535 | { | |
536 | if (pid_file) | |
537 | unlink(pid_file); | |
538 | } | |
539 | ||
540 | ||
f4aabcee MM |
541 | /* |
542 | * Shutdown | |
543 | */ | |
544 | ||
e0a45fb4 OZ |
545 | void |
546 | cmd_shutdown(void) | |
547 | { | |
548 | if (cli_access_restricted()) | |
549 | return; | |
550 | ||
551 | cli_msg(7, "Shutdown requested"); | |
552 | order_shutdown(); | |
553 | } | |
554 | ||
f4aabcee MM |
555 | void |
556 | async_shutdown(void) | |
557 | { | |
6b9fa320 | 558 | DBG("Shutting down...\n"); |
bf8558bc | 559 | order_shutdown(); |
f4aabcee MM |
560 | } |
561 | ||
562 | void | |
bf8558bc | 563 | sysdep_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 |
575 | volatile int async_config_flag; |
576 | volatile int async_dump_flag; | |
577 | volatile int async_shutdown_flag; | |
578 | ||
4c9dd1e4 | 579 | static void |
6578a604 | 580 | handle_sighup(int sig UNUSED) |
4c9dd1e4 | 581 | { |
6b9fa320 | 582 | DBG("Caught SIGHUP...\n"); |
4c9dd1e4 MM |
583 | async_config_flag = 1; |
584 | } | |
585 | ||
586 | static void | |
6578a604 | 587 | handle_sigusr(int sig UNUSED) |
4c9dd1e4 | 588 | { |
6b9fa320 | 589 | DBG("Caught SIGUSR...\n"); |
4c9dd1e4 MM |
590 | async_dump_flag = 1; |
591 | } | |
592 | ||
f4aabcee | 593 | static void |
6578a604 | 594 | handle_sigterm(int sig UNUSED) |
f4aabcee | 595 | { |
6b9fa320 | 596 | DBG("Caught SIGTERM...\n"); |
f4aabcee MM |
597 | async_shutdown_flag = 1; |
598 | } | |
599 | ||
8bcb5fb1 OZ |
600 | void watchdog_sigalrm(int sig UNUSED); |
601 | ||
4c9dd1e4 MM |
602 | static void |
603 | signal_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 | 627 | static char *opt_list = "bc:dD:ps:P:u:g:flRh"; |
44d4ab7a OZ |
628 | static int parse_and_exit; |
629 | char *bird_name; | |
1bc26957 OZ |
630 | static char *use_user; |
631 | static char *use_group; | |
1cd198cf | 632 | static int run_in_foreground = 0; |
0bcba21e | 633 | |
4c9dd1e4 | 634 | static void |
292f7858 | 635 | display_usage(void) |
4c9dd1e4 | 636 | { |
292f7858 PT |
637 | fprintf(stderr, "Usage: %s [--version] [--help] [-c <config-file>] [OPTIONS]\n", bird_name); |
638 | } | |
639 | ||
640 | static void | |
641 | display_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 | ||
668 | static void | |
669 | display_version(void) | |
670 | { | |
671 | fprintf(stderr, "BIRD version " BIRD_VERSION "\n"); | |
672 | exit(0); | |
4c9dd1e4 MM |
673 | } |
674 | ||
44d4ab7a OZ |
675 | static inline char * |
676 | get_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 |
689 | static inline uid_t |
690 | get_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 | ||
712 | static inline gid_t | |
713 | get_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 |
735 | static void |
736 | parse_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 | |
816 | int | |
4c9dd1e4 | 817 | main(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 | } |