File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / main.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:39:23 2021 UTC (4 years ago) by misho
Branches: mpd, MAIN
CVS tags: v5_9p16, v5_9, HEAD
mpd 5.9

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

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