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>