Annotation of embedaddon/mpd/src/main.c, revision 1.1.1.3
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;
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:
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;
177: PhysType pt;
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:
328: /* Read startup configuration section */
1.1.1.3 ! misho 329: err = ReadFile(gConfigFile, STARTUP_CONF, DoCommand, c);
1.1 misho 330:
331: /* Read configuration as specified on the command line, or default */
1.1.1.3 ! misho 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) {
1.1 misho 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;
1.1.1.3 ! misho 477: #ifdef USE_BACKTRACE
! 478: void *buffer[100];
! 479: char **strings;
! 480: int n;
! 481: #endif
1.1 misho 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;
1.1.1.3 ! misho 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
1.1 misho 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
1.1.1.2 misho 631: #ifdef USE_PAM
632: memset(gPamService, 0, sizeof(gPamService));
633: #endif
1.1 misho 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
1.1.1.2 misho 663: #ifdef USE_PAM
664: case 'm':
665: strlcpy(gPamService, *av, sizeof(gPamService));
666: return(1);
667: #endif
1.1 misho 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);
1.1.1.3 ! misho 715: fprintf(stderr, "%-35s%s\n", buf, opt->desc);
1.1 misho 716: }
717: exit(ex);
718: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>