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