Annotation of embedaddon/mpd/src/main.c, revision 1.1
1.1 ! misho 1: /*
! 2: * main.c
! 3: *
! 4: * Written by Toshiharu OHNO <tony-o@iij.ad.jp>
! 5: * Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved.
! 6: * See ``COPYRIGHT.iij''
! 7: *
! 8: * Rewritten by Archie Cobbs <archie@freebsd.org>
! 9: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
! 10: * See ``COPYRIGHT.whistle''
! 11: */
! 12:
! 13: #include "ppp.h"
! 14: #include "mp.h"
! 15: #include "iface.h"
! 16: #include "command.h"
! 17: #include "console.h"
! 18: #ifndef NOWEB
! 19: #include "web.h"
! 20: #endif
! 21: #include "radsrv.h"
! 22: #include "ngfunc.h"
! 23: #include "util.h"
! 24: #include "ippool.h"
! 25: #ifdef CCP_MPPC
! 26: #include "ccp_mppc.h"
! 27: #endif
! 28:
! 29: #include <netgraph.h>
! 30:
! 31: /*
! 32: * DEFINITIONS
! 33: */
! 34:
! 35: /* Implied system name when none specified on the command line */
! 36: #define DEFAULT_CONF "default"
! 37: #define STARTUP_CONF "startup"
! 38:
! 39: #define MAX_ARGS 50
! 40:
! 41: struct option {
! 42: short n_args;
! 43: char sflag;
! 44: const char *lflag;
! 45: const char *usage;
! 46: const char *desc;
! 47: };
! 48: typedef struct option *Option;
! 49:
! 50: static const char *UsageStr = "[options] [system]";
! 51: static struct option OptList[] = {
! 52: { 0, 'b', "background", "",
! 53: "Run as a background daemon" },
! 54: { 1, 'd', "directory", "config-dir",
! 55: "Set config file directory" },
! 56: { 0, 'k', "kill", "",
! 57: "Kill running mpd process before start" },
! 58: { 1, 'f', "file", "config-file",
! 59: "Set configuration file" },
! 60: { 0, 'o', "one-shot", "",
! 61: "Terminate daemon after last link shutdown" },
! 62: { 1, 'p', "pidfile", "filename",
! 63: "Set PID filename" },
! 64: #ifdef SYSLOG_FACILITY
! 65: { 1, 's', "syslog-ident", "ident",
! 66: "Identifier to use for syslog" },
! 67: #endif
! 68: { 0, 'v', "version", "",
! 69: "Show version information" },
! 70: { 0, 'h', "help", "",
! 71: "Show usage information" },
! 72: };
! 73:
! 74: #define OPTLIST_SIZE (sizeof(OptList) / sizeof(*OptList))
! 75:
! 76: /* How long to wait for graceful shutdown when we recieve a SIGTERM */
! 77: #define TERMINATE_DEATH_WAIT (2 * SECONDS)
! 78:
! 79: /*
! 80: * GLOBAL VARIABLES
! 81: */
! 82:
! 83: Rep *gReps;
! 84: Link *gLinks;
! 85: Bund *gBundles;
! 86: int gNumReps;
! 87: int gNumLinks;
! 88: int gNumBundles;
! 89: struct console gConsole;
! 90: #ifndef NOWEB
! 91: struct web gWeb;
! 92: #endif
! 93: struct radsrv gRadsrv;
! 94: int gBackground = FALSE;
! 95: int gShutdownInProgress = FALSE;
! 96: int gOverload = 0;
! 97: pid_t gPid;
! 98: int gRouteSeq = 0;
! 99:
! 100: #ifdef PHYSTYPE_PPTP
! 101: int gPPTPto = 10;
! 102: int gPPTPtunlimit = 100;
! 103: #endif
! 104: #ifdef PHYSTYPE_L2TP
! 105: int gL2TPto = 10;
! 106: #if ((__FreeBSD_version > 603100 && __FreeBSD_version < 700000) || __FreeBSD_version >= 700055)
! 107: int gL2TPtunlimit = 100;
! 108: #else
! 109: int gL2TPtunlimit = 10;
! 110: #endif
! 111: #endif
! 112: int gChildren = 0; /* Current number of children links */
! 113: int gMaxChildren = 10000; /* Maximal number of children links */
! 114:
! 115: #ifdef USE_NG_BPF
! 116: struct acl *acl_filters[ACL_FILTERS]; /* mpd's global internal bpf filters */
! 117: #endif
! 118:
! 119: struct globalconf gGlobalConf;
! 120:
! 121: pthread_mutex_t gGiantMutex;
! 122:
! 123: const char *gConfigFile = CONF_FILE;
! 124: const char *gConfDirectory = PATH_CONF_DIR;
! 125:
! 126: const char *gVersion = MPD_VERSION;
! 127:
! 128: /*
! 129: * INTERNAL FUNCTIONS
! 130: */
! 131:
! 132: static void Usage(int ex) __dead2;
! 133: static void OptParse(int ac, char *av[]);
! 134: static int OptApply(Option opt, int ac, char *av[]);
! 135: static Option OptDecode(char *arg, int longform);
! 136:
! 137: static void ConfigRead(int type, void *arg);
! 138: static void OpenCloseSignal(int sig);
! 139: static void FatalSignal(int sig);
! 140: static void SignalHandler(int type, void *arg);
! 141: static void CloseIfaces(void);
! 142:
! 143:
! 144: /*
! 145: * INTERNAL VARIABLES
! 146: */
! 147:
! 148: static int gKillProc = FALSE;
! 149: static const char *gPidFile = PID_FILE;
! 150: static const char *gPeerSystem = NULL;
! 151: static EventRef gSignalEvent;
! 152: static EventRef gConfigReadEvent;
! 153: static int gSignalPipe[2];
! 154: static struct context gCtx;
! 155:
! 156: /*
! 157: * main()
! 158: */
! 159:
! 160: int
! 161: main(int ac, char *av[])
! 162: {
! 163: int ret, k;
! 164: char *args[MAX_ARGS];
! 165: Context c;
! 166: PhysType pt;
! 167:
! 168: gPid=getpid();
! 169:
! 170: /* enable libpdel typed_mem */
! 171: typed_mem_enable();
! 172:
! 173: /* init global-config */
! 174: memset(&gGlobalConf, 0, sizeof(gGlobalConf));
! 175:
! 176: /* Read and parse command line */
! 177: if (ac > MAX_ARGS)
! 178: ac = MAX_ARGS;
! 179: memcpy(args, av, ac * sizeof(*av)); /* Copy to preserve "ps" output */
! 180: OptParse(ac - 1, args + 1);
! 181:
! 182: /* init console-stuff */
! 183: ConsoleInit(&gConsole);
! 184:
! 185: memset(&gCtx, 0, sizeof(gCtx));
! 186: gCtx.priv = 2;
! 187: if (gBackground) {
! 188: c = &gCtx;
! 189: } else {
! 190: c = StdConsoleConnect(&gConsole);
! 191: if (c == NULL)
! 192: c = &gCtx;
! 193: }
! 194:
! 195: #ifndef NOWEB
! 196: /* init web-stuff */
! 197: WebInit(&gWeb);
! 198: #endif
! 199:
! 200: #ifdef RAD_COA_REQUEST
! 201: /* init RADIUS server */
! 202: RadsrvInit(&gRadsrv);
! 203: #endif
! 204:
! 205: /* Set up libnetgraph logging */
! 206: NgSetErrLog(NgFuncErr, NgFuncErrx);
! 207:
! 208: /* Background mode? */
! 209: if (gBackground) {
! 210: if (daemon(TRUE, FALSE) < 0)
! 211: err(1, "daemon");
! 212: gPid=getpid();
! 213: (void) chdir(gConfDirectory);
! 214: }
! 215:
! 216: /* Open log file */
! 217: if (LogOpen())
! 218: exit(EX_ERRDEAD);
! 219:
! 220: /* Randomize */
! 221: srandomdev();
! 222:
! 223: /* Welcome */
! 224: Greetings();
! 225:
! 226: /* Check PID file */
! 227: if (PIDCheck(gPidFile, gKillProc) < 0)
! 228: exit(EX_UNAVAILABLE);
! 229:
! 230: /* Do some initialization */
! 231: MpSetDiscrim();
! 232: IPPoolInit();
! 233: #ifdef CCP_MPPC
! 234: MppcTestCap();
! 235: #endif
! 236: if ((LinksInit() != 0) || (CcpsInit() != 0) || (EcpsInit() != 0))
! 237: exit(EX_UNAVAILABLE);
! 238:
! 239: /* Init device types. */
! 240: for (k = 0; (pt = gPhysTypes[k]); k++) {
! 241: if (pt->tinit && (pt->tinit)()) {
! 242: Log(LG_ERR, ("Device type '%s' initialization error.\n", pt->name));
! 243: exit(EX_UNAVAILABLE);
! 244: }
! 245: }
! 246:
! 247: ret = pthread_mutex_init (&gGiantMutex, NULL);
! 248: if (ret != 0) {
! 249: Log(LG_ERR, ("Could not create giant mutex %d", ret));
! 250: exit(EX_UNAVAILABLE);
! 251: }
! 252:
! 253: /* Create signaling pipe */
! 254: if ((ret = pipe(gSignalPipe)) != 0) {
! 255: Log(LG_ERR, ("Could not create signal pipe %d", ret));
! 256: exit(EX_UNAVAILABLE);
! 257: }
! 258: if (EventRegister(&gSignalEvent, EVENT_READ, gSignalPipe[0],
! 259: EVENT_RECURRING, SignalHandler, NULL) != 0)
! 260: exit(EX_UNAVAILABLE);
! 261:
! 262: /* Register for some common fatal signals so we can exit cleanly */
! 263: signal(SIGINT, SendSignal);
! 264: signal(SIGTERM, SendSignal);
! 265: signal(SIGHUP, SendSignal);
! 266:
! 267: /* Catastrophic signals */
! 268: signal(SIGSEGV, SendSignal);
! 269: signal(SIGBUS, SendSignal);
! 270: signal(SIGABRT, SendSignal);
! 271:
! 272: /* Other signals make us do things */
! 273: signal(SIGUSR1, SendSignal);
! 274: signal(SIGUSR2, SendSignal);
! 275:
! 276: /* Signals we ignore */
! 277: signal(SIGPIPE, SIG_IGN);
! 278:
! 279: EventRegister(&gConfigReadEvent, EVENT_TIMEOUT,
! 280: 0, 0, ConfigRead, c);
! 281:
! 282: pthread_exit(NULL);
! 283:
! 284: assert(0);
! 285: return(1); /* Never reached, but needed to silence compiler warning */
! 286: }
! 287:
! 288: /*
! 289: * Greetings()
! 290: */
! 291:
! 292: void
! 293: Greetings(void)
! 294: {
! 295: Log(LG_ALWAYS, ("Multi-link PPP daemon for FreeBSD"));
! 296: Log(LG_ALWAYS, (" "));
! 297: Log(LG_ALWAYS, ("process %lu started, version %s", (u_long) gPid, gVersion));
! 298: }
! 299:
! 300: /*
! 301: * ConfigRead()
! 302: *
! 303: * handler of initial configuration reading event
! 304: */
! 305: static void
! 306: ConfigRead(int type, void *arg)
! 307: {
! 308: Context c = (Context)arg;
! 309:
! 310: /* Read startup configuration section */
! 311: ReadFile(gConfigFile, STARTUP_CONF, DoCommand, c);
! 312:
! 313: /* Read configuration as specified on the command line, or default */
! 314: if (!gPeerSystem)
! 315: ReadFile(gConfigFile, DEFAULT_CONF, DoCommand, c);
! 316: else {
! 317: if (ReadFile(gConfigFile, gPeerSystem, DoCommand, c) < 0) {
! 318: Log(LG_ERR, ("can't read configuration for \"%s\"", gPeerSystem));
! 319: DoExit(EX_CONFIG);
! 320: }
! 321: }
! 322: CheckOneShot();
! 323: if (c->cs)
! 324: c->cs->prompt(c->cs);
! 325: }
! 326:
! 327: /*
! 328: * CloseIfaces()
! 329: */
! 330:
! 331: static void
! 332: CloseIfaces(void)
! 333: {
! 334: Bund b;
! 335: int k;
! 336:
! 337: /* Shut down all interfaces we grabbed */
! 338: for (k = 0; k < gNumBundles; k++) {
! 339: if (((b = gBundles[k]) != NULL) && (!b->tmpl)) {
! 340: IfaceClose(b);
! 341: BundNcpsClose(b);
! 342: }
! 343: }
! 344: }
! 345:
! 346: /*
! 347: * DoExit()
! 348: *
! 349: * Cleanup and exit
! 350: */
! 351:
! 352: void
! 353: DoExit(int code)
! 354: {
! 355: Bund b;
! 356: Rep r;
! 357: Link l;
! 358: PhysType pt;
! 359: int k;
! 360:
! 361: gShutdownInProgress=1;
! 362: /* Weak attempt to record what happened */
! 363: if (code == EX_ERRDEAD)
! 364: Log(LG_ERR, ("fatal error, exiting"));
! 365:
! 366: /* Shutdown stuff */
! 367: if (code != EX_TERMINATE) /* kludge to avoid double shutdown */
! 368: CloseIfaces();
! 369:
! 370: NgFuncShutdownGlobal();
! 371:
! 372: /* Blow away all netgraph nodes */
! 373: for (k = 0; k < gNumBundles; k++) {
! 374: if ((b = gBundles[k]) != NULL)
! 375: BundShutdown(b);
! 376: }
! 377:
! 378: for (k = 0; k < gNumReps; k++) {
! 379: if ((r = gReps[k]) != NULL)
! 380: RepShutdown(r);
! 381: }
! 382:
! 383: for (k = 0; k < gNumLinks; k++) {
! 384: if ((l = gLinks[k]) != NULL)
! 385: LinkShutdown(l);
! 386: }
! 387:
! 388: /* Shutdown device types. */
! 389: for (k = 0; (pt = gPhysTypes[k]); k++) {
! 390: if (pt->tshutdown)
! 391: (pt->tshutdown)();
! 392: }
! 393:
! 394: EcpsShutdown();
! 395: CcpsShutdown();
! 396: LinksShutdown();
! 397:
! 398: /* Remove our PID file and exit */
! 399: ConsoleShutdown(&gConsole);
! 400: Log(LG_ALWAYS, ("process %d terminated", gPid));
! 401: LogClose();
! 402: (void) unlink(gPidFile);
! 403: exit(code == EX_TERMINATE ? EX_NORMAL : code);
! 404: }
! 405:
! 406: /*
! 407: * SendSignal()
! 408: *
! 409: * Send a signal through the signaling pipe
! 410: * don't add printf's here or any function
! 411: * wich isn't re-entrant
! 412: */
! 413:
! 414: void
! 415: SendSignal(int sig)
! 416: {
! 417: if (sig == SIGSEGV || sig == SIGBUS || sig == SIGABRT)
! 418: FatalSignal(sig);
! 419: write(gSignalPipe[1], &sig, 1);
! 420: }
! 421:
! 422: /*
! 423: * SignalHandler()
! 424: *
! 425: * dispatch signal
! 426: */
! 427: static void
! 428: SignalHandler(int type, void *arg)
! 429: {
! 430: u_char sig;
! 431:
! 432: read(gSignalPipe[0], &sig, sizeof(sig));
! 433:
! 434: switch(sig) {
! 435: case SIGUSR1:
! 436: case SIGUSR2:
! 437: OpenCloseSignal(sig);
! 438: break;
! 439:
! 440: default:
! 441: FatalSignal(sig);
! 442: }
! 443: }
! 444:
! 445: /*
! 446: * FatalSignal()
! 447: *
! 448: * Gracefully exit on receipt of a fatal signal
! 449: */
! 450:
! 451: static void
! 452: FatalSignal(int sig)
! 453: {
! 454: Bund b;
! 455: static struct pppTimer gDeathTimer;
! 456: int k;
! 457: int upLinkCount;
! 458:
! 459: /* If a SIGTERM or SIGINT, gracefully shutdown; otherwise shutdown now */
! 460: Log(LG_ERR, ("caught fatal signal %s", sys_signame[sig]));
! 461: gShutdownInProgress=1;
! 462: for (k = 0; k < gNumBundles; k++) {
! 463: if ((b = gBundles[k])) {
! 464: if (sig != SIGTERM && sig != SIGINT)
! 465: RecordLinkUpDownReason(b, NULL, 0, STR_FATAL_SHUTDOWN, NULL);
! 466: else
! 467: RecordLinkUpDownReason(b, NULL, 0, STR_ADMIN_SHUTDOWN, NULL);
! 468: }
! 469: }
! 470: upLinkCount = 0;
! 471: for (k = 0; k < gNumLinks; k++) {
! 472: if (gLinks[k] && (gLinks[k]->state!=PHYS_STATE_DOWN))
! 473: upLinkCount++;
! 474: }
! 475:
! 476: /* We are going down. No more signals. */
! 477: signal(SIGINT, SIG_IGN);
! 478: signal(SIGTERM, SIG_IGN);
! 479: signal(SIGUSR1, SIG_IGN);
! 480: signal(SIGUSR2, SIG_IGN);
! 481:
! 482: if (sig != SIGTERM && sig != SIGINT)
! 483: DoExit(EX_ERRDEAD);
! 484:
! 485: CloseIfaces();
! 486: TimerInit(&gDeathTimer, "DeathTimer",
! 487: TERMINATE_DEATH_WAIT * (upLinkCount/100+1), (void (*)(void *)) DoExit, (void *) EX_TERMINATE);
! 488: TimerStart(&gDeathTimer);
! 489: }
! 490:
! 491: /*
! 492: * OpenCloseSignal()
! 493: */
! 494:
! 495: static void
! 496: OpenCloseSignal(int sig)
! 497: {
! 498: int k;
! 499: Link l;
! 500:
! 501: for (k = 0;
! 502: k < gNumLinks && (gLinks[k] == NULL || gLinks[k]->tmpl);
! 503: k++);
! 504: if (k == gNumLinks) {
! 505: Log(LG_ALWAYS, ("rec'd signal %s, no link defined, ignored", sys_signame[sig]));
! 506: return;
! 507: }
! 508:
! 509: l = gLinks[k];
! 510:
! 511: /* Open/Close Link */
! 512: if (l && l->type) {
! 513: if (sig == SIGUSR1) {
! 514: Log(LG_ALWAYS, ("[%s] rec'd signal %s, opening",
! 515: l->name, sys_signame[sig]));
! 516: RecordLinkUpDownReason(NULL, l, 1, STR_MANUALLY, NULL);
! 517: LinkOpen(l);
! 518: } else {
! 519: Log(LG_ALWAYS, ("[%s] rec'd signal %s, closing",
! 520: l->name, sys_signame[sig]));
! 521: RecordLinkUpDownReason(NULL, l, 0, STR_MANUALLY, NULL);
! 522: LinkClose(l);
! 523: }
! 524: } else
! 525: Log(LG_ALWAYS, ("rec'd signal %s, ignored", sys_signame[sig]));
! 526: }
! 527:
! 528: void
! 529: CheckOneShot(void)
! 530: {
! 531: int i;
! 532: if (!Enabled(&gGlobalConf.options, GLOBAL_CONF_ONESHOT))
! 533: return;
! 534: for (i = 0; i < gNumLinks; i++) {
! 535: if (gLinks[i] && !gLinks[i]->tmpl)
! 536: return;
! 537: }
! 538: Log(LG_ALWAYS, ("One-shot mode enabled and no links found. Terminating daemon."));
! 539: SendSignal(SIGTERM);
! 540: }
! 541:
! 542: /*
! 543: * OptParse()
! 544: */
! 545:
! 546: static void
! 547: OptParse(int ac, char *av[])
! 548: {
! 549: int used, consumed;
! 550:
! 551: /* Get option flags */
! 552: for ( ; ac > 0 && **av == '-'; ac--, av++) {
! 553: if (*++(*av) == '-') { /* Long form */
! 554: if (*++(*av) == 0) { /* "--" forces end of options */
! 555: ac--; av++;
! 556: break;
! 557: } else {
! 558: used = OptApply(OptDecode(*av, TRUE), ac - 1, av + 1);
! 559: ac -= used; av += used;
! 560: }
! 561: } else { /* Short form */
! 562: for (used = 0; **av; (*av)++, used += consumed) {
! 563: consumed = OptApply(OptDecode(*av, FALSE), ac - 1, av + 1);
! 564: if (used && consumed)
! 565: Usage(EX_USAGE);
! 566: }
! 567: ac -= used; av += used;
! 568: }
! 569: }
! 570:
! 571: /* Get system names */
! 572: switch (ac) {
! 573: case 0:
! 574: break;
! 575: case 1:
! 576: gPeerSystem = *av;
! 577: break;
! 578: default:
! 579: Usage(EX_USAGE);
! 580: }
! 581: }
! 582:
! 583: /*
! 584: * OptApply()
! 585: */
! 586:
! 587: static int
! 588: OptApply(Option opt, int ac, char *av[])
! 589: {
! 590: #ifdef SYSLOG_FACILITY
! 591: memset(gSysLogIdent, 0, sizeof(gSysLogIdent));
! 592: #endif
! 593:
! 594: if (opt == NULL)
! 595: Usage(EX_USAGE);
! 596: if (ac < opt->n_args)
! 597: Usage(EX_USAGE);
! 598: switch (opt->sflag) {
! 599: case 'b':
! 600: gBackground = TRUE;
! 601: return(0);
! 602: case 'd':
! 603: gConfDirectory = *av;
! 604: return(1);
! 605: case 'f':
! 606: gConfigFile = *av;
! 607: return(1);
! 608: case 'o':
! 609: Enable(&gGlobalConf.options, GLOBAL_CONF_ONESHOT);
! 610: return(0);
! 611: case 'p':
! 612: gPidFile = *av;
! 613: return(1);
! 614: case 'k':
! 615: gKillProc = TRUE;
! 616: return(0);
! 617: #ifdef SYSLOG_FACILITY
! 618: case 's':
! 619: strlcpy(gSysLogIdent, *av, sizeof(gSysLogIdent));
! 620: return(1);
! 621: #endif
! 622: case 'v':
! 623: fprintf(stderr, "Version %s\n", gVersion);
! 624: exit(EX_NORMAL);
! 625: case 'h':
! 626: Usage(EX_NORMAL);
! 627: default:
! 628: assert(0);
! 629: }
! 630: return(0);
! 631: }
! 632:
! 633: /*
! 634: * OptDecode()
! 635: */
! 636:
! 637: static Option
! 638: OptDecode(char *arg, int longform)
! 639: {
! 640: Option opt;
! 641: size_t k;
! 642:
! 643: for (k = 0; k < OPTLIST_SIZE; k++) {
! 644: opt = OptList + k;
! 645: if (longform ?
! 646: !strcmp(arg, opt->lflag) : (*arg == opt->sflag))
! 647: return(opt);
! 648: }
! 649: return(NULL);
! 650: }
! 651:
! 652: /*
! 653: * Usage()
! 654: */
! 655:
! 656: static void
! 657: Usage(int ex)
! 658: {
! 659: Option opt;
! 660: char buf[100];
! 661: size_t k;
! 662:
! 663: fprintf(stderr, "Usage: mpd5 %s\n", UsageStr);
! 664: fprintf(stderr, "Options:\n");
! 665: for (k = 0; k < OPTLIST_SIZE; k++) {
! 666: opt = OptList + k;
! 667: snprintf(buf, sizeof(buf), " -%c, --%-s %s",
! 668: opt->sflag, opt->lflag, opt->usage);
! 669: fprintf(stderr, "%-40s%s\n", buf, opt->desc);
! 670: }
! 671: exit(ex);
! 672: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>