File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / main.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:56:12 2016 UTC (7 years, 8 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_8p7, v5_8p1_cross, v5_8p1, v5_8, HEAD
mpd 5.8

    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:   int			gPPTPtunlimit = 100;
  110: #endif
  111: #ifdef PHYSTYPE_L2TP
  112:   int			gL2TPto = 10;
  113: #if ((__FreeBSD_version > 603100 && __FreeBSD_version < 700000) || __FreeBSD_version >= 700055)
  114:   int			gL2TPtunlimit = 100;
  115: #else
  116:   int			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:     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:     /* Read startup configuration section */
  329:     err = ReadFile(gConfigFile, STARTUP_CONF, DoCommand, c);
  330: 
  331:     /* Read configuration as specified on the command line, or default */
  332:     if (!gPeerSystem) {
  333: 	if (err != -2)
  334: 	    ReadFile(gConfigFile, DEFAULT_CONF, DoCommand, c);
  335:     } else {
  336: 	if (err == -2 || ReadFile(gConfigFile, gPeerSystem, DoCommand, c) < 0) {
  337: 	    Log(LG_ERR, ("can't read configuration for \"%s\"", gPeerSystem));
  338: 	    DoExit(EX_CONFIG);
  339: 	}
  340:     }
  341:     CheckOneShot();
  342:     if (c->cs)
  343: 	c->cs->prompt(c->cs);
  344: }
  345: 
  346: /*
  347:  * CloseIfaces()
  348:  */
  349: 
  350: static void
  351: CloseIfaces(void)
  352: {
  353:     Bund	b;
  354:     int		k;
  355: 
  356:     /* Shut down all interfaces we grabbed */
  357:     for (k = 0; k < gNumBundles; k++) {
  358: 	if (((b = gBundles[k]) != NULL) && (!b->tmpl)) {
  359:     	    IfaceClose(b);
  360:     	    BundNcpsClose(b);
  361: 	}
  362:     }
  363: }
  364: 
  365: /*
  366:  * DoExit()
  367:  *
  368:  * Cleanup and exit
  369:  */
  370: 
  371: void
  372: DoExit(int code)
  373: {
  374:     Bund	b;
  375:     Rep		r;
  376:     Link	l;
  377:     PhysType	pt;
  378:     int		k;
  379: 
  380:     gShutdownInProgress=1;
  381:     /* Weak attempt to record what happened */
  382:     if (code == EX_ERRDEAD)
  383: 	Log(LG_ERR, ("fatal error, exiting"));
  384: 
  385:     /* Shutdown stuff */
  386:     if (code != EX_TERMINATE)	/* kludge to avoid double shutdown */
  387: 	CloseIfaces();
  388: 
  389:     NgFuncShutdownGlobal();
  390: 
  391:     /* Blow away all netgraph nodes */
  392:     for (k = 0; k < gNumBundles; k++) {
  393: 	if ((b = gBundles[k]) != NULL)
  394:     	    BundShutdown(b);
  395:     }
  396: 
  397:     for (k = 0; k < gNumReps; k++) {
  398: 	if ((r = gReps[k]) != NULL)
  399:     	    RepShutdown(r);
  400:     }
  401: 
  402:     for (k = 0; k < gNumLinks; k++) {
  403: 	if ((l = gLinks[k]) != NULL)
  404:     	    LinkShutdown(l);
  405:     }
  406: 
  407:     /* Shutdown device types. */
  408:     for (k = 0; (pt = gPhysTypes[k]); k++) {
  409: 	if (pt->tshutdown)
  410: 	    (pt->tshutdown)();
  411:     }
  412: 
  413:     EcpsShutdown();
  414:     CcpsShutdown();
  415:     LinksShutdown();
  416: 
  417:     /* Remove our PID file and exit */
  418:     ConsoleShutdown(&gConsole);
  419:     Log(LG_ALWAYS, ("process %d terminated", gPid));
  420:     LogClose();
  421:     (void) unlink(gPidFile);
  422:     exit(code == EX_TERMINATE ? EX_NORMAL : code);
  423: }
  424: 
  425: /*
  426:  * SendSignal()
  427:  *
  428:  * Send a signal through the signaling pipe
  429:  * don't add printf's here or any function
  430:  * wich isn't re-entrant
  431:  */
  432: 
  433: void
  434: SendSignal(int sig)
  435: {
  436:     if (sig == SIGSEGV || sig == SIGBUS || sig == SIGABRT)
  437: 	FatalSignal(sig);
  438:     write(gSignalPipe[1], &sig, 1);
  439: }
  440: 
  441: /*
  442:  * SignalHandler()
  443:  *
  444:  * dispatch signal
  445:  */
  446: static void
  447: SignalHandler(int type, void *arg)
  448: {
  449:     u_char	sig;
  450: 
  451:     read(gSignalPipe[0], &sig, sizeof(sig));
  452: 
  453:     switch(sig) {
  454: 	case SIGUSR1:
  455: 	case SIGUSR2:
  456:     	    OpenCloseSignal(sig);
  457:     	    break;
  458: 
  459: 	default:
  460:     	    FatalSignal(sig);
  461:     }
  462: }
  463: 
  464: /*
  465:  * FatalSignal()
  466:  *
  467:  * Gracefully exit on receipt of a fatal signal
  468:  */
  469: 
  470: static void
  471: FatalSignal(int sig)
  472: {
  473:     Bund 	b;
  474:     static struct pppTimer	gDeathTimer;
  475:     int				k;
  476:     int				upLinkCount;
  477: #ifdef USE_BACKTRACE
  478:     void			*buffer[100];
  479:     char			**strings;
  480:     int				n;
  481: #endif
  482: 
  483:     /* If a SIGTERM or SIGINT, gracefully shutdown; otherwise shutdown now */
  484:     Log(LG_ERR, ("caught fatal signal %s", sys_signame[sig]));
  485:     gShutdownInProgress=1;
  486: #ifdef USE_BACKTRACE
  487:     if (sig != SIGTERM && sig != SIGINT) {
  488:         n = backtrace(buffer, 100);
  489:         strings = backtrace_symbols(buffer, n);
  490:         if (strings == NULL) {
  491:             Log(LG_ERR, ("No backtrace symbols found"));
  492:         } else {
  493:             for (k = 0; k < n; k++) {
  494:                 Log(LG_ERR, ("%s", strings[k]));
  495:             }
  496:             free(strings);
  497:         }
  498:     }
  499: #endif
  500:     for (k = 0; k < gNumBundles; k++) {
  501: 	if ((b = gBundles[k])) {
  502:     	    if (sig != SIGTERM && sig != SIGINT)
  503:     		RecordLinkUpDownReason(b, NULL, 0, STR_FATAL_SHUTDOWN, NULL);
  504:     	    else
  505:     		RecordLinkUpDownReason(b, NULL, 0, STR_ADMIN_SHUTDOWN, NULL);
  506: 	}
  507:     }
  508:     upLinkCount = 0;
  509:     for (k = 0; k < gNumLinks; k++) {
  510: 	if (gLinks[k] && (gLinks[k]->state!=PHYS_STATE_DOWN))
  511: 	    upLinkCount++;
  512:     }
  513: 
  514:     /* We are going down. No more signals. */
  515:     signal(SIGINT, SIG_IGN);
  516:     signal(SIGTERM, SIG_IGN);
  517:     signal(SIGUSR1, SIG_IGN);
  518:     signal(SIGUSR2, SIG_IGN);
  519: 
  520:     if (sig != SIGTERM && sig != SIGINT)
  521: 	DoExit(EX_ERRDEAD);
  522: 
  523:     CloseIfaces();
  524:     TimerInit(&gDeathTimer, "DeathTimer",
  525: 	TERMINATE_DEATH_WAIT * (upLinkCount/100+1), (void (*)(void *)) DoExit, (void *) EX_TERMINATE);
  526:     TimerStart(&gDeathTimer);
  527: }
  528: 
  529: /*
  530:  * OpenCloseSignal()
  531:  */
  532: 
  533: static void
  534: OpenCloseSignal(int sig)
  535: {
  536:     int		k;
  537:     Link	l;
  538: 
  539:     for (k = 0;
  540: 	k < gNumLinks && (gLinks[k] == NULL || gLinks[k]->tmpl);
  541: 	k++);
  542:     if (k == gNumLinks) {
  543: 	Log(LG_ALWAYS, ("rec'd signal %s, no link defined, ignored", sys_signame[sig]));
  544: 	return;
  545:     }
  546: 
  547:     l = gLinks[k];
  548: 
  549:     /* Open/Close Link */
  550:     if (l && l->type) {
  551: 	if (sig == SIGUSR1) {
  552: 	    Log(LG_ALWAYS, ("[%s] rec'd signal %s, opening",
  553:     		l->name, sys_signame[sig]));
  554: 	    RecordLinkUpDownReason(NULL, l, 1, STR_MANUALLY, NULL);
  555: 	    LinkOpen(l);
  556: 	} else {
  557: 	    Log(LG_ALWAYS, ("[%s] rec'd signal %s, closing",
  558:     		l->name, sys_signame[sig]));
  559: 	    RecordLinkUpDownReason(NULL, l, 0, STR_MANUALLY, NULL);
  560: 	    LinkClose(l);
  561: 	}
  562:     } else
  563: 	Log(LG_ALWAYS, ("rec'd signal %s, ignored", sys_signame[sig]));
  564: }
  565: 
  566: void
  567: CheckOneShot(void)
  568: {
  569:     int	i;
  570:     if (!Enabled(&gGlobalConf.options, GLOBAL_CONF_ONESHOT))
  571: 	return;
  572:     for (i = 0; i < gNumLinks; i++) {
  573: 	if (gLinks[i] && !gLinks[i]->tmpl)
  574: 	    return;
  575:     }
  576:     Log(LG_ALWAYS, ("One-shot mode enabled and no links found. Terminating daemon."));
  577:     SendSignal(SIGTERM);
  578: }
  579: 
  580: /*
  581:  * OptParse()
  582:  */
  583: 
  584: static void
  585: OptParse(int ac, char *av[])
  586: {
  587:     int	used, consumed;
  588: 
  589:     /* Get option flags */
  590:     for ( ; ac > 0 && **av == '-'; ac--, av++) {
  591: 	if (*++(*av) == '-') {	/* Long form */
  592:     	    if (*++(*av) == 0) {	/* "--" forces end of options */
  593: 		ac--; av++;
  594: 		break;
  595:     	    } else {
  596: 		used = OptApply(OptDecode(*av, TRUE), ac - 1, av + 1);
  597: 		ac -= used; av += used;
  598:     	    }
  599: 	} else {			/* Short form */
  600:     	    for (used = 0; **av; (*av)++, used += consumed) {
  601: 		consumed = OptApply(OptDecode(*av, FALSE), ac - 1, av + 1);
  602: 		if (used && consumed)
  603: 		    Usage(EX_USAGE);
  604:     	    }
  605:     	    ac -= used; av += used;
  606: 	}
  607:     }
  608: 
  609:     /* Get system names */
  610:     switch (ac) {
  611: 	case 0:
  612:     	    break;
  613: 	case 1:
  614:     	    gPeerSystem = *av;
  615:     	    break;
  616: 	default:
  617:     	    Usage(EX_USAGE);
  618:     }
  619: }
  620: 
  621: /*
  622:  * OptApply()
  623:  */
  624: 
  625: static int
  626: OptApply(Option opt, int ac, char *av[])
  627: {
  628: #ifdef SYSLOG_FACILITY
  629:     memset(gSysLogIdent, 0, sizeof(gSysLogIdent));
  630: #endif
  631: #ifdef USE_PAM
  632:     memset(gPamService, 0, sizeof(gPamService));
  633: #endif
  634: 
  635:     if (opt == NULL)
  636: 	Usage(EX_USAGE);
  637:     if (ac < opt->n_args)
  638: 	Usage(EX_USAGE);
  639:     switch (opt->sflag) {
  640: 	case 'b':
  641:     	    gBackground = TRUE;
  642:     	    return(0);
  643: 	case 'd':
  644:     	    gConfDirectory = *av;
  645:     	    return(1);
  646: 	case 'f':
  647:     	    gConfigFile = *av;
  648:     	    return(1);
  649: 	case 'o':
  650: 	    Enable(&gGlobalConf.options, GLOBAL_CONF_ONESHOT);
  651:     	    return(0);
  652: 	case 'p':
  653:     	    gPidFile = *av;
  654:     	    return(1);
  655: 	case 'k':
  656:     	    gKillProc = TRUE;
  657:     	    return(0);
  658: #ifdef SYSLOG_FACILITY
  659: 	case 's':
  660:     	    strlcpy(gSysLogIdent, *av, sizeof(gSysLogIdent));
  661:     	    return(1);
  662: #endif
  663: #ifdef USE_PAM
  664: 	case 'm':
  665:     	    strlcpy(gPamService, *av, sizeof(gPamService));
  666:     	    return(1);
  667: #endif
  668: 	case 'v':
  669:     	    fprintf(stderr, "Version %s\n", gVersion);
  670:     	    exit(EX_NORMAL);
  671: 	case 'h':
  672:     	    Usage(EX_NORMAL);
  673: 	default:
  674:     	    assert(0);
  675:     }
  676:     return(0);
  677: }
  678: 
  679: /*
  680:  * OptDecode()
  681:  */
  682: 
  683: static Option
  684: OptDecode(char *arg, int longform)
  685: {
  686:     Option	opt;
  687:     size_t	k;
  688: 
  689:     for (k = 0; k < OPTLIST_SIZE; k++) {
  690: 	opt = OptList + k;
  691: 	if (longform ?
  692: 	    !strcmp(arg, opt->lflag) : (*arg == opt->sflag))
  693:         return(opt);
  694:     }
  695:     return(NULL);
  696: }
  697: 
  698: /*
  699:  * Usage()
  700:  */
  701: 
  702: static void
  703: Usage(int ex)
  704: {
  705:     Option		opt;
  706:     char		buf[100];
  707:     size_t		k;
  708: 
  709:     fprintf(stderr, "Usage: mpd5 %s\n", UsageStr);
  710:     fprintf(stderr, "Options:\n");
  711:     for (k = 0; k < OPTLIST_SIZE; k++) {
  712: 	opt = OptList + k;
  713: 	snprintf(buf, sizeof(buf), "  -%c, --%-s %s",
  714:     	    opt->sflag, opt->lflag, opt->usage);
  715: 	fprintf(stderr, "%-35s%s\n", buf, opt->desc);
  716:     }
  717:     exit(ex);
  718: }

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