Annotation of embedaddon/mpd/src/main.c, revision 1.1.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>