Annotation of embedaddon/mpd/src/main.c, revision 1.1.1.2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>