Annotation of embedaddon/mpd/src/main.c, revision 1.1.1.4.2.1
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
1.1.1.4.2.1! misho 100: #ifdef USE_RADIUS
1.1 misho 101: struct radsrv gRadsrv;
1.1.1.4.2.1! misho 102: #endif
1.1 misho 103: int gBackground = FALSE;
104: int gShutdownInProgress = FALSE;
105: int gOverload = 0;
106: pid_t gPid;
107: int gRouteSeq = 0;
108:
109: #ifdef PHYSTYPE_PPTP
110: int gPPTPto = 10;
1.1.1.4 misho 111: unsigned gPPTPtunlimit = 100;
1.1 misho 112: #endif
113: #ifdef PHYSTYPE_L2TP
114: int gL2TPto = 10;
115: #if ((__FreeBSD_version > 603100 && __FreeBSD_version < 700000) || __FreeBSD_version >= 700055)
1.1.1.4 misho 116: unsigned gL2TPtunlimit = 100;
1.1 misho 117: #else
1.1.1.4 misho 118: unsigned gL2TPtunlimit = 10;
1.1 misho 119: #endif
120: #endif
121: int gChildren = 0; /* Current number of children links */
122: int gMaxChildren = 10000; /* Maximal number of children links */
123:
124: #ifdef USE_NG_BPF
125: struct acl *acl_filters[ACL_FILTERS]; /* mpd's global internal bpf filters */
126: #endif
127:
1.1.1.2 misho 128: #ifdef USE_PAM
129: char gPamService[32];
130: #endif
131:
1.1 misho 132: struct globalconf gGlobalConf;
133:
134: pthread_mutex_t gGiantMutex;
135:
136: const char *gConfigFile = CONF_FILE;
137: const char *gConfDirectory = PATH_CONF_DIR;
138:
139: const char *gVersion = MPD_VERSION;
140:
141: /*
142: * INTERNAL FUNCTIONS
143: */
144:
145: static void Usage(int ex) __dead2;
146: static void OptParse(int ac, char *av[]);
147: static int OptApply(Option opt, int ac, char *av[]);
148: static Option OptDecode(char *arg, int longform);
149:
150: static void ConfigRead(int type, void *arg);
151: static void OpenCloseSignal(int sig);
152: static void FatalSignal(int sig);
153: static void SignalHandler(int type, void *arg);
154: static void CloseIfaces(void);
155:
156:
157: /*
158: * INTERNAL VARIABLES
159: */
160:
161: static int gKillProc = FALSE;
162: static const char *gPidFile = PID_FILE;
163: static const char *gPeerSystem = NULL;
164: static EventRef gSignalEvent;
165: static EventRef gConfigReadEvent;
166: static int gSignalPipe[2];
167: static struct context gCtx;
168:
169: /*
170: * main()
171: */
172:
173: int
174: main(int ac, char *av[])
175: {
176: int ret, k;
177: char *args[MAX_ARGS];
178: Context c;
1.1.1.4 misho 179: const struct phystype *pt;
1.1 misho 180:
1.1.1.3 misho 181: gPid = getpid();
1.1 misho 182:
183: /* enable libpdel typed_mem */
184: typed_mem_enable();
185:
186: /* init global-config */
187: memset(&gGlobalConf, 0, sizeof(gGlobalConf));
188:
189: /* Read and parse command line */
190: if (ac > MAX_ARGS)
191: ac = MAX_ARGS;
192: memcpy(args, av, ac * sizeof(*av)); /* Copy to preserve "ps" output */
193: OptParse(ac - 1, args + 1);
194:
195: /* init console-stuff */
196: ConsoleInit(&gConsole);
197:
198: memset(&gCtx, 0, sizeof(gCtx));
199: gCtx.priv = 2;
200: if (gBackground) {
201: c = &gCtx;
202: } else {
203: c = StdConsoleConnect(&gConsole);
204: if (c == NULL)
205: c = &gCtx;
206: }
207:
208: #ifndef NOWEB
209: /* init web-stuff */
210: WebInit(&gWeb);
211: #endif
212:
213: #ifdef RAD_COA_REQUEST
214: /* init RADIUS server */
215: RadsrvInit(&gRadsrv);
216: #endif
217:
1.1.1.2 misho 218: #ifdef USE_PAM
219: if (!*gPamService)
220: strcpy(gPamService, "mpd");
221: #endif
222:
223:
1.1 misho 224: /* Set up libnetgraph logging */
225: NgSetErrLog(NgFuncErr, NgFuncErrx);
226:
227: /* Background mode? */
228: if (gBackground) {
229: if (daemon(TRUE, FALSE) < 0)
230: err(1, "daemon");
231: gPid=getpid();
232: (void) chdir(gConfDirectory);
233: }
234:
235: /* Open log file */
236: if (LogOpen())
237: exit(EX_ERRDEAD);
238:
239: /* Randomize */
240: srandomdev();
241:
242: /* Welcome */
243: Greetings();
244:
245: /* Check PID file */
246: if (PIDCheck(gPidFile, gKillProc) < 0)
247: exit(EX_UNAVAILABLE);
248:
249: /* Do some initialization */
250: MpSetDiscrim();
251: IPPoolInit();
252: #ifdef CCP_MPPC
253: MppcTestCap();
254: #endif
255: if ((LinksInit() != 0) || (CcpsInit() != 0) || (EcpsInit() != 0))
256: exit(EX_UNAVAILABLE);
257:
258: /* Init device types. */
259: for (k = 0; (pt = gPhysTypes[k]); k++) {
260: if (pt->tinit && (pt->tinit)()) {
261: Log(LG_ERR, ("Device type '%s' initialization error.\n", pt->name));
262: exit(EX_UNAVAILABLE);
263: }
264: }
265:
266: ret = pthread_mutex_init (&gGiantMutex, NULL);
267: if (ret != 0) {
268: Log(LG_ERR, ("Could not create giant mutex %d", ret));
269: exit(EX_UNAVAILABLE);
270: }
271:
272: /* Create signaling pipe */
1.1.1.3 misho 273: if (pipe(gSignalPipe) < 0) {
274: Perror("Could not create signal pipe");
1.1 misho 275: exit(EX_UNAVAILABLE);
276: }
277: if (EventRegister(&gSignalEvent, EVENT_READ, gSignalPipe[0],
278: EVENT_RECURRING, SignalHandler, NULL) != 0)
279: exit(EX_UNAVAILABLE);
280:
281: /* Register for some common fatal signals so we can exit cleanly */
282: signal(SIGINT, SendSignal);
283: signal(SIGTERM, SendSignal);
284: signal(SIGHUP, SendSignal);
285:
286: /* Catastrophic signals */
287: signal(SIGSEGV, SendSignal);
288: signal(SIGBUS, SendSignal);
289: signal(SIGABRT, SendSignal);
290:
291: /* Other signals make us do things */
292: signal(SIGUSR1, SendSignal);
293: signal(SIGUSR2, SendSignal);
294:
295: /* Signals we ignore */
296: signal(SIGPIPE, SIG_IGN);
297:
298: EventRegister(&gConfigReadEvent, EVENT_TIMEOUT,
299: 0, 0, ConfigRead, c);
300:
301: pthread_exit(NULL);
302:
303: assert(0);
304: return(1); /* Never reached, but needed to silence compiler warning */
305: }
306:
307: /*
308: * Greetings()
309: */
310:
311: void
312: Greetings(void)
313: {
314: Log(LG_ALWAYS, ("Multi-link PPP daemon for FreeBSD"));
315: Log(LG_ALWAYS, (" "));
316: Log(LG_ALWAYS, ("process %lu started, version %s", (u_long) gPid, gVersion));
317: }
318:
319: /*
320: * ConfigRead()
321: *
322: * handler of initial configuration reading event
323: */
324: static void
325: ConfigRead(int type, void *arg)
326: {
327: Context c = (Context)arg;
1.1.1.3 misho 328: int err;
1.1 misho 329:
1.1.1.4 misho 330: (void)type;
1.1 misho 331: /* Read startup configuration section */
1.1.1.3 misho 332: err = ReadFile(gConfigFile, STARTUP_CONF, DoCommand, c);
1.1 misho 333:
334: /* Read configuration as specified on the command line, or default */
1.1.1.3 misho 335: if (!gPeerSystem) {
336: if (err != -2)
337: ReadFile(gConfigFile, DEFAULT_CONF, DoCommand, c);
338: } else {
339: if (err == -2 || ReadFile(gConfigFile, gPeerSystem, DoCommand, c) < 0) {
1.1 misho 340: Log(LG_ERR, ("can't read configuration for \"%s\"", gPeerSystem));
341: DoExit(EX_CONFIG);
342: }
343: }
344: CheckOneShot();
345: if (c->cs)
346: c->cs->prompt(c->cs);
347: }
348:
349: /*
350: * CloseIfaces()
351: */
352:
353: static void
354: CloseIfaces(void)
355: {
356: Bund b;
357: int k;
358:
359: /* Shut down all interfaces we grabbed */
360: for (k = 0; k < gNumBundles; k++) {
361: if (((b = gBundles[k]) != NULL) && (!b->tmpl)) {
362: IfaceClose(b);
363: BundNcpsClose(b);
364: }
365: }
366: }
367:
368: /*
369: * DoExit()
370: *
371: * Cleanup and exit
372: */
373:
374: void
375: DoExit(int code)
376: {
377: Bund b;
378: Rep r;
379: Link l;
1.1.1.4 misho 380: const struct phystype *pt;
1.1 misho 381: int k;
382:
383: gShutdownInProgress=1;
384: /* Weak attempt to record what happened */
385: if (code == EX_ERRDEAD)
386: Log(LG_ERR, ("fatal error, exiting"));
387:
388: /* Shutdown stuff */
389: if (code != EX_TERMINATE) /* kludge to avoid double shutdown */
390: CloseIfaces();
391:
392: NgFuncShutdownGlobal();
393:
394: /* Blow away all netgraph nodes */
395: for (k = 0; k < gNumBundles; k++) {
396: if ((b = gBundles[k]) != NULL)
397: BundShutdown(b);
398: }
399:
400: for (k = 0; k < gNumReps; k++) {
401: if ((r = gReps[k]) != NULL)
402: RepShutdown(r);
403: }
404:
405: for (k = 0; k < gNumLinks; k++) {
406: if ((l = gLinks[k]) != NULL)
407: LinkShutdown(l);
408: }
409:
410: /* Shutdown device types. */
411: for (k = 0; (pt = gPhysTypes[k]); k++) {
412: if (pt->tshutdown)
413: (pt->tshutdown)();
414: }
415:
416: EcpsShutdown();
417: CcpsShutdown();
418: LinksShutdown();
419:
420: /* Remove our PID file and exit */
421: ConsoleShutdown(&gConsole);
422: Log(LG_ALWAYS, ("process %d terminated", gPid));
423: LogClose();
424: (void) unlink(gPidFile);
425: exit(code == EX_TERMINATE ? EX_NORMAL : code);
426: }
427:
428: /*
429: * SendSignal()
430: *
431: * Send a signal through the signaling pipe
432: * don't add printf's here or any function
433: * wich isn't re-entrant
434: */
435:
436: void
437: SendSignal(int sig)
438: {
439: if (sig == SIGSEGV || sig == SIGBUS || sig == SIGABRT)
440: FatalSignal(sig);
441: write(gSignalPipe[1], &sig, 1);
442: }
443:
444: /*
445: * SignalHandler()
446: *
447: * dispatch signal
448: */
449: static void
450: SignalHandler(int type, void *arg)
451: {
452: u_char sig;
453:
1.1.1.4 misho 454: (void)type;
455: (void)arg;
1.1 misho 456: read(gSignalPipe[0], &sig, sizeof(sig));
457:
458: switch(sig) {
459: case SIGUSR1:
460: case SIGUSR2:
461: OpenCloseSignal(sig);
462: break;
463:
464: default:
465: FatalSignal(sig);
466: }
467: }
468:
469: /*
470: * FatalSignal()
471: *
472: * Gracefully exit on receipt of a fatal signal
473: */
474:
475: static void
476: FatalSignal(int sig)
477: {
478: Bund b;
479: static struct pppTimer gDeathTimer;
480: int k;
481: int upLinkCount;
1.1.1.3 misho 482: #ifdef USE_BACKTRACE
483: void *buffer[100];
484: char **strings;
485: int n;
486: #endif
1.1 misho 487:
488: /* If a SIGTERM or SIGINT, gracefully shutdown; otherwise shutdown now */
489: Log(LG_ERR, ("caught fatal signal %s", sys_signame[sig]));
490: gShutdownInProgress=1;
1.1.1.3 misho 491: #ifdef USE_BACKTRACE
492: if (sig != SIGTERM && sig != SIGINT) {
493: n = backtrace(buffer, 100);
494: strings = backtrace_symbols(buffer, n);
495: if (strings == NULL) {
496: Log(LG_ERR, ("No backtrace symbols found"));
497: } else {
498: for (k = 0; k < n; k++) {
499: Log(LG_ERR, ("%s", strings[k]));
500: }
501: free(strings);
502: }
503: }
504: #endif
1.1 misho 505: for (k = 0; k < gNumBundles; k++) {
506: if ((b = gBundles[k])) {
507: if (sig != SIGTERM && sig != SIGINT)
508: RecordLinkUpDownReason(b, NULL, 0, STR_FATAL_SHUTDOWN, NULL);
509: else
510: RecordLinkUpDownReason(b, NULL, 0, STR_ADMIN_SHUTDOWN, NULL);
511: }
512: }
513: upLinkCount = 0;
514: for (k = 0; k < gNumLinks; k++) {
515: if (gLinks[k] && (gLinks[k]->state!=PHYS_STATE_DOWN))
516: upLinkCount++;
517: }
518:
519: /* We are going down. No more signals. */
520: signal(SIGINT, SIG_IGN);
521: signal(SIGTERM, SIG_IGN);
522: signal(SIGUSR1, SIG_IGN);
523: signal(SIGUSR2, SIG_IGN);
524:
525: if (sig != SIGTERM && sig != SIGINT)
526: DoExit(EX_ERRDEAD);
527:
528: CloseIfaces();
529: TimerInit(&gDeathTimer, "DeathTimer",
530: TERMINATE_DEATH_WAIT * (upLinkCount/100+1), (void (*)(void *)) DoExit, (void *) EX_TERMINATE);
531: TimerStart(&gDeathTimer);
532: }
533:
534: /*
535: * OpenCloseSignal()
536: */
537:
538: static void
539: OpenCloseSignal(int sig)
540: {
541: int k;
542: Link l;
543:
544: for (k = 0;
545: k < gNumLinks && (gLinks[k] == NULL || gLinks[k]->tmpl);
546: k++);
547: if (k == gNumLinks) {
548: Log(LG_ALWAYS, ("rec'd signal %s, no link defined, ignored", sys_signame[sig]));
549: return;
550: }
551:
552: l = gLinks[k];
553:
554: /* Open/Close Link */
555: if (l && l->type) {
556: if (sig == SIGUSR1) {
557: Log(LG_ALWAYS, ("[%s] rec'd signal %s, opening",
558: l->name, sys_signame[sig]));
1.1.1.4.2.1! misho 559: LinkOpenAdm(l);
1.1 misho 560: } else {
561: Log(LG_ALWAYS, ("[%s] rec'd signal %s, closing",
562: l->name, sys_signame[sig]));
1.1.1.4.2.1! misho 563: LinkCloseAdm(l);
1.1 misho 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>