Annotation of embedaddon/mpd/src/main.c, revision 1.1.1.4
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:
1.1.1.3 misho 29: #ifdef USE_BACKTRACE
30: #include <execinfo.h>
31: #endif
1.1 misho 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:
1.1.1.3 misho 53: static const char *UsageStr = "[options] [configuration]";
1.1 misho 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
1.1.1.2 misho 71: #ifdef USE_PAM
72: { 1, 'm', "pam-service", "service",
73: "PAM service name" },
74: #endif
1.1 misho 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;
1.1.1.4 ! misho 109: unsigned gPPTPtunlimit = 100;
1.1 misho 110: #endif
111: #ifdef PHYSTYPE_L2TP
112: int gL2TPto = 10;
113: #if ((__FreeBSD_version > 603100 && __FreeBSD_version < 700000) || __FreeBSD_version >= 700055)
1.1.1.4 ! misho 114: unsigned gL2TPtunlimit = 100;
1.1 misho 115: #else
1.1.1.4 ! misho 116: unsigned gL2TPtunlimit = 10;
1.1 misho 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:
1.1.1.2 misho 126: #ifdef USE_PAM
127: char gPamService[32];
128: #endif
129:
1.1 misho 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;
1.1.1.4 ! misho 177: const struct phystype *pt;
1.1 misho 178:
1.1.1.3 misho 179: gPid = getpid();
1.1 misho 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:
1.1.1.2 misho 216: #ifdef USE_PAM
217: if (!*gPamService)
218: strcpy(gPamService, "mpd");
219: #endif
220:
221:
1.1 misho 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 */
1.1.1.3 misho 271: if (pipe(gSignalPipe) < 0) {
272: Perror("Could not create signal pipe");
1.1 misho 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;
1.1.1.3 misho 326: int err;
1.1 misho 327:
1.1.1.4 ! misho 328: (void)type;
1.1 misho 329: /* Read startup configuration section */
1.1.1.3 misho 330: err = ReadFile(gConfigFile, STARTUP_CONF, DoCommand, c);
1.1 misho 331:
332: /* Read configuration as specified on the command line, or default */
1.1.1.3 misho 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) {
1.1 misho 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;
1.1.1.4 ! misho 378: const struct phystype *pt;
1.1 misho 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:
1.1.1.4 ! misho 452: (void)type;
! 453: (void)arg;
1.1 misho 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;
1.1.1.3 misho 480: #ifdef USE_BACKTRACE
481: void *buffer[100];
482: char **strings;
483: int n;
484: #endif
1.1 misho 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;
1.1.1.3 misho 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
1.1 misho 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
1.1.1.2 misho 634: #ifdef USE_PAM
635: memset(gPamService, 0, sizeof(gPamService));
636: #endif
1.1 misho 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
1.1.1.2 misho 666: #ifdef USE_PAM
667: case 'm':
668: strlcpy(gPamService, *av, sizeof(gPamService));
669: return(1);
670: #endif
1.1 misho 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);
1.1.1.3 misho 718: fprintf(stderr, "%-35s%s\n", buf, opt->desc);
1.1 misho 719: }
720: exit(ex);
721: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>