Annotation of embedaddon/mpd/src/main.c, revision 1.1.1.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:
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
68: { 0, 'v', "version", "",
69: "Show version information" },
70: { 0, 'h', "help", "",
71: "Show usage information" },
72: };
73:
74: #define OPTLIST_SIZE (sizeof(OptList) / sizeof(*OptList))
75:
76: /* How long to wait for graceful shutdown when we recieve a SIGTERM */
77: #define TERMINATE_DEATH_WAIT (2 * SECONDS)
78:
79: /*
80: * GLOBAL VARIABLES
81: */
82:
83: Rep *gReps;
84: Link *gLinks;
85: Bund *gBundles;
86: int gNumReps;
87: int gNumLinks;
88: int gNumBundles;
89: struct console gConsole;
90: #ifndef NOWEB
91: struct web gWeb;
92: #endif
93: struct radsrv gRadsrv;
94: int gBackground = FALSE;
95: int gShutdownInProgress = FALSE;
96: int gOverload = 0;
97: pid_t gPid;
98: int gRouteSeq = 0;
99:
100: #ifdef PHYSTYPE_PPTP
101: int gPPTPto = 10;
102: int gPPTPtunlimit = 100;
103: #endif
104: #ifdef PHYSTYPE_L2TP
105: int gL2TPto = 10;
106: #if ((__FreeBSD_version > 603100 && __FreeBSD_version < 700000) || __FreeBSD_version >= 700055)
107: int gL2TPtunlimit = 100;
108: #else
109: int gL2TPtunlimit = 10;
110: #endif
111: #endif
112: int gChildren = 0; /* Current number of children links */
113: int gMaxChildren = 10000; /* Maximal number of children links */
114:
115: #ifdef USE_NG_BPF
116: struct acl *acl_filters[ACL_FILTERS]; /* mpd's global internal bpf filters */
117: #endif
118:
119: struct globalconf gGlobalConf;
120:
121: pthread_mutex_t gGiantMutex;
122:
123: const char *gConfigFile = CONF_FILE;
124: const char *gConfDirectory = PATH_CONF_DIR;
125:
126: const char *gVersion = MPD_VERSION;
127:
128: /*
129: * INTERNAL FUNCTIONS
130: */
131:
132: static void Usage(int ex) __dead2;
133: static void OptParse(int ac, char *av[]);
134: static int OptApply(Option opt, int ac, char *av[]);
135: static Option OptDecode(char *arg, int longform);
136:
137: static void ConfigRead(int type, void *arg);
138: static void OpenCloseSignal(int sig);
139: static void FatalSignal(int sig);
140: static void SignalHandler(int type, void *arg);
141: static void CloseIfaces(void);
142:
143:
144: /*
145: * INTERNAL VARIABLES
146: */
147:
148: static int gKillProc = FALSE;
149: static const char *gPidFile = PID_FILE;
150: static const char *gPeerSystem = NULL;
151: static EventRef gSignalEvent;
152: static EventRef gConfigReadEvent;
153: static int gSignalPipe[2];
154: static struct context gCtx;
155:
156: /*
157: * main()
158: */
159:
160: int
161: main(int ac, char *av[])
162: {
163: int ret, k;
164: char *args[MAX_ARGS];
165: Context c;
166: PhysType pt;
167:
168: gPid=getpid();
169:
170: /* enable libpdel typed_mem */
171: typed_mem_enable();
172:
173: /* init global-config */
174: memset(&gGlobalConf, 0, sizeof(gGlobalConf));
175:
176: /* Read and parse command line */
177: if (ac > MAX_ARGS)
178: ac = MAX_ARGS;
179: memcpy(args, av, ac * sizeof(*av)); /* Copy to preserve "ps" output */
180: OptParse(ac - 1, args + 1);
181:
182: /* init console-stuff */
183: ConsoleInit(&gConsole);
184:
185: memset(&gCtx, 0, sizeof(gCtx));
186: gCtx.priv = 2;
187: if (gBackground) {
188: c = &gCtx;
189: } else {
190: c = StdConsoleConnect(&gConsole);
191: if (c == NULL)
192: c = &gCtx;
193: }
194:
195: #ifndef NOWEB
196: /* init web-stuff */
197: WebInit(&gWeb);
198: #endif
199:
200: #ifdef RAD_COA_REQUEST
201: /* init RADIUS server */
202: RadsrvInit(&gRadsrv);
203: #endif
204:
205: /* Set up libnetgraph logging */
206: NgSetErrLog(NgFuncErr, NgFuncErrx);
207:
208: /* Background mode? */
209: if (gBackground) {
210: if (daemon(TRUE, FALSE) < 0)
211: err(1, "daemon");
212: gPid=getpid();
213: (void) chdir(gConfDirectory);
214: }
215:
216: /* Open log file */
217: if (LogOpen())
218: exit(EX_ERRDEAD);
219:
220: /* Randomize */
221: srandomdev();
222:
223: /* Welcome */
224: Greetings();
225:
226: /* Check PID file */
227: if (PIDCheck(gPidFile, gKillProc) < 0)
228: exit(EX_UNAVAILABLE);
229:
230: /* Do some initialization */
231: MpSetDiscrim();
232: IPPoolInit();
233: #ifdef CCP_MPPC
234: MppcTestCap();
235: #endif
236: if ((LinksInit() != 0) || (CcpsInit() != 0) || (EcpsInit() != 0))
237: exit(EX_UNAVAILABLE);
238:
239: /* Init device types. */
240: for (k = 0; (pt = gPhysTypes[k]); k++) {
241: if (pt->tinit && (pt->tinit)()) {
242: Log(LG_ERR, ("Device type '%s' initialization error.\n", pt->name));
243: exit(EX_UNAVAILABLE);
244: }
245: }
246:
247: ret = pthread_mutex_init (&gGiantMutex, NULL);
248: if (ret != 0) {
249: Log(LG_ERR, ("Could not create giant mutex %d", ret));
250: exit(EX_UNAVAILABLE);
251: }
252:
253: /* Create signaling pipe */
254: if ((ret = pipe(gSignalPipe)) != 0) {
255: Log(LG_ERR, ("Could not create signal pipe %d", ret));
256: exit(EX_UNAVAILABLE);
257: }
258: if (EventRegister(&gSignalEvent, EVENT_READ, gSignalPipe[0],
259: EVENT_RECURRING, SignalHandler, NULL) != 0)
260: exit(EX_UNAVAILABLE);
261:
262: /* Register for some common fatal signals so we can exit cleanly */
263: signal(SIGINT, SendSignal);
264: signal(SIGTERM, SendSignal);
265: signal(SIGHUP, SendSignal);
266:
267: /* Catastrophic signals */
268: signal(SIGSEGV, SendSignal);
269: signal(SIGBUS, SendSignal);
270: signal(SIGABRT, SendSignal);
271:
272: /* Other signals make us do things */
273: signal(SIGUSR1, SendSignal);
274: signal(SIGUSR2, SendSignal);
275:
276: /* Signals we ignore */
277: signal(SIGPIPE, SIG_IGN);
278:
279: EventRegister(&gConfigReadEvent, EVENT_TIMEOUT,
280: 0, 0, ConfigRead, c);
281:
282: pthread_exit(NULL);
283:
284: assert(0);
285: return(1); /* Never reached, but needed to silence compiler warning */
286: }
287:
288: /*
289: * Greetings()
290: */
291:
292: void
293: Greetings(void)
294: {
295: Log(LG_ALWAYS, ("Multi-link PPP daemon for FreeBSD"));
296: Log(LG_ALWAYS, (" "));
297: Log(LG_ALWAYS, ("process %lu started, version %s", (u_long) gPid, gVersion));
298: }
299:
300: /*
301: * ConfigRead()
302: *
303: * handler of initial configuration reading event
304: */
305: static void
306: ConfigRead(int type, void *arg)
307: {
308: Context c = (Context)arg;
309:
310: /* Read startup configuration section */
311: ReadFile(gConfigFile, STARTUP_CONF, DoCommand, c);
312:
313: /* Read configuration as specified on the command line, or default */
314: if (!gPeerSystem)
315: ReadFile(gConfigFile, DEFAULT_CONF, DoCommand, c);
316: else {
317: if (ReadFile(gConfigFile, gPeerSystem, DoCommand, c) < 0) {
318: Log(LG_ERR, ("can't read configuration for \"%s\"", gPeerSystem));
319: DoExit(EX_CONFIG);
320: }
321: }
322: CheckOneShot();
323: if (c->cs)
324: c->cs->prompt(c->cs);
325: }
326:
327: /*
328: * CloseIfaces()
329: */
330:
331: static void
332: CloseIfaces(void)
333: {
334: Bund b;
335: int k;
336:
337: /* Shut down all interfaces we grabbed */
338: for (k = 0; k < gNumBundles; k++) {
339: if (((b = gBundles[k]) != NULL) && (!b->tmpl)) {
340: IfaceClose(b);
341: BundNcpsClose(b);
342: }
343: }
344: }
345:
346: /*
347: * DoExit()
348: *
349: * Cleanup and exit
350: */
351:
352: void
353: DoExit(int code)
354: {
355: Bund b;
356: Rep r;
357: Link l;
358: PhysType pt;
359: int k;
360:
361: gShutdownInProgress=1;
362: /* Weak attempt to record what happened */
363: if (code == EX_ERRDEAD)
364: Log(LG_ERR, ("fatal error, exiting"));
365:
366: /* Shutdown stuff */
367: if (code != EX_TERMINATE) /* kludge to avoid double shutdown */
368: CloseIfaces();
369:
370: NgFuncShutdownGlobal();
371:
372: /* Blow away all netgraph nodes */
373: for (k = 0; k < gNumBundles; k++) {
374: if ((b = gBundles[k]) != NULL)
375: BundShutdown(b);
376: }
377:
378: for (k = 0; k < gNumReps; k++) {
379: if ((r = gReps[k]) != NULL)
380: RepShutdown(r);
381: }
382:
383: for (k = 0; k < gNumLinks; k++) {
384: if ((l = gLinks[k]) != NULL)
385: LinkShutdown(l);
386: }
387:
388: /* Shutdown device types. */
389: for (k = 0; (pt = gPhysTypes[k]); k++) {
390: if (pt->tshutdown)
391: (pt->tshutdown)();
392: }
393:
394: EcpsShutdown();
395: CcpsShutdown();
396: LinksShutdown();
397:
398: /* Remove our PID file and exit */
399: ConsoleShutdown(&gConsole);
400: Log(LG_ALWAYS, ("process %d terminated", gPid));
401: LogClose();
402: (void) unlink(gPidFile);
403: exit(code == EX_TERMINATE ? EX_NORMAL : code);
404: }
405:
406: /*
407: * SendSignal()
408: *
409: * Send a signal through the signaling pipe
410: * don't add printf's here or any function
411: * wich isn't re-entrant
412: */
413:
414: void
415: SendSignal(int sig)
416: {
417: if (sig == SIGSEGV || sig == SIGBUS || sig == SIGABRT)
418: FatalSignal(sig);
419: write(gSignalPipe[1], &sig, 1);
420: }
421:
422: /*
423: * SignalHandler()
424: *
425: * dispatch signal
426: */
427: static void
428: SignalHandler(int type, void *arg)
429: {
430: u_char sig;
431:
432: read(gSignalPipe[0], &sig, sizeof(sig));
433:
434: switch(sig) {
435: case SIGUSR1:
436: case SIGUSR2:
437: OpenCloseSignal(sig);
438: break;
439:
440: default:
441: FatalSignal(sig);
442: }
443: }
444:
445: /*
446: * FatalSignal()
447: *
448: * Gracefully exit on receipt of a fatal signal
449: */
450:
451: static void
452: FatalSignal(int sig)
453: {
454: Bund b;
455: static struct pppTimer gDeathTimer;
456: int k;
457: int upLinkCount;
458:
459: /* If a SIGTERM or SIGINT, gracefully shutdown; otherwise shutdown now */
460: Log(LG_ERR, ("caught fatal signal %s", sys_signame[sig]));
461: gShutdownInProgress=1;
462: for (k = 0; k < gNumBundles; k++) {
463: if ((b = gBundles[k])) {
464: if (sig != SIGTERM && sig != SIGINT)
465: RecordLinkUpDownReason(b, NULL, 0, STR_FATAL_SHUTDOWN, NULL);
466: else
467: RecordLinkUpDownReason(b, NULL, 0, STR_ADMIN_SHUTDOWN, NULL);
468: }
469: }
470: upLinkCount = 0;
471: for (k = 0; k < gNumLinks; k++) {
472: if (gLinks[k] && (gLinks[k]->state!=PHYS_STATE_DOWN))
473: upLinkCount++;
474: }
475:
476: /* We are going down. No more signals. */
477: signal(SIGINT, SIG_IGN);
478: signal(SIGTERM, SIG_IGN);
479: signal(SIGUSR1, SIG_IGN);
480: signal(SIGUSR2, SIG_IGN);
481:
482: if (sig != SIGTERM && sig != SIGINT)
483: DoExit(EX_ERRDEAD);
484:
485: CloseIfaces();
486: TimerInit(&gDeathTimer, "DeathTimer",
487: TERMINATE_DEATH_WAIT * (upLinkCount/100+1), (void (*)(void *)) DoExit, (void *) EX_TERMINATE);
488: TimerStart(&gDeathTimer);
489: }
490:
491: /*
492: * OpenCloseSignal()
493: */
494:
495: static void
496: OpenCloseSignal(int sig)
497: {
498: int k;
499: Link l;
500:
501: for (k = 0;
502: k < gNumLinks && (gLinks[k] == NULL || gLinks[k]->tmpl);
503: k++);
504: if (k == gNumLinks) {
505: Log(LG_ALWAYS, ("rec'd signal %s, no link defined, ignored", sys_signame[sig]));
506: return;
507: }
508:
509: l = gLinks[k];
510:
511: /* Open/Close Link */
512: if (l && l->type) {
513: if (sig == SIGUSR1) {
514: Log(LG_ALWAYS, ("[%s] rec'd signal %s, opening",
515: l->name, sys_signame[sig]));
516: RecordLinkUpDownReason(NULL, l, 1, STR_MANUALLY, NULL);
517: LinkOpen(l);
518: } else {
519: Log(LG_ALWAYS, ("[%s] rec'd signal %s, closing",
520: l->name, sys_signame[sig]));
521: RecordLinkUpDownReason(NULL, l, 0, STR_MANUALLY, NULL);
522: LinkClose(l);
523: }
524: } else
525: Log(LG_ALWAYS, ("rec'd signal %s, ignored", sys_signame[sig]));
526: }
527:
528: void
529: CheckOneShot(void)
530: {
531: int i;
532: if (!Enabled(&gGlobalConf.options, GLOBAL_CONF_ONESHOT))
533: return;
534: for (i = 0; i < gNumLinks; i++) {
535: if (gLinks[i] && !gLinks[i]->tmpl)
536: return;
537: }
538: Log(LG_ALWAYS, ("One-shot mode enabled and no links found. Terminating daemon."));
539: SendSignal(SIGTERM);
540: }
541:
542: /*
543: * OptParse()
544: */
545:
546: static void
547: OptParse(int ac, char *av[])
548: {
549: int used, consumed;
550:
551: /* Get option flags */
552: for ( ; ac > 0 && **av == '-'; ac--, av++) {
553: if (*++(*av) == '-') { /* Long form */
554: if (*++(*av) == 0) { /* "--" forces end of options */
555: ac--; av++;
556: break;
557: } else {
558: used = OptApply(OptDecode(*av, TRUE), ac - 1, av + 1);
559: ac -= used; av += used;
560: }
561: } else { /* Short form */
562: for (used = 0; **av; (*av)++, used += consumed) {
563: consumed = OptApply(OptDecode(*av, FALSE), ac - 1, av + 1);
564: if (used && consumed)
565: Usage(EX_USAGE);
566: }
567: ac -= used; av += used;
568: }
569: }
570:
571: /* Get system names */
572: switch (ac) {
573: case 0:
574: break;
575: case 1:
576: gPeerSystem = *av;
577: break;
578: default:
579: Usage(EX_USAGE);
580: }
581: }
582:
583: /*
584: * OptApply()
585: */
586:
587: static int
588: OptApply(Option opt, int ac, char *av[])
589: {
590: #ifdef SYSLOG_FACILITY
591: memset(gSysLogIdent, 0, sizeof(gSysLogIdent));
592: #endif
593:
594: if (opt == NULL)
595: Usage(EX_USAGE);
596: if (ac < opt->n_args)
597: Usage(EX_USAGE);
598: switch (opt->sflag) {
599: case 'b':
600: gBackground = TRUE;
601: return(0);
602: case 'd':
603: gConfDirectory = *av;
604: return(1);
605: case 'f':
606: gConfigFile = *av;
607: return(1);
608: case 'o':
609: Enable(&gGlobalConf.options, GLOBAL_CONF_ONESHOT);
610: return(0);
611: case 'p':
612: gPidFile = *av;
613: return(1);
614: case 'k':
615: gKillProc = TRUE;
616: return(0);
617: #ifdef SYSLOG_FACILITY
618: case 's':
619: strlcpy(gSysLogIdent, *av, sizeof(gSysLogIdent));
620: return(1);
621: #endif
622: case 'v':
623: fprintf(stderr, "Version %s\n", gVersion);
624: exit(EX_NORMAL);
625: case 'h':
626: Usage(EX_NORMAL);
627: default:
628: assert(0);
629: }
630: return(0);
631: }
632:
633: /*
634: * OptDecode()
635: */
636:
637: static Option
638: OptDecode(char *arg, int longform)
639: {
640: Option opt;
641: size_t k;
642:
643: for (k = 0; k < OPTLIST_SIZE; k++) {
644: opt = OptList + k;
645: if (longform ?
646: !strcmp(arg, opt->lflag) : (*arg == opt->sflag))
647: return(opt);
648: }
649: return(NULL);
650: }
651:
652: /*
653: * Usage()
654: */
655:
656: static void
657: Usage(int ex)
658: {
659: Option opt;
660: char buf[100];
661: size_t k;
662:
663: fprintf(stderr, "Usage: mpd5 %s\n", UsageStr);
664: fprintf(stderr, "Options:\n");
665: for (k = 0; k < OPTLIST_SIZE; k++) {
666: opt = OptList + k;
667: snprintf(buf, sizeof(buf), " -%c, --%-s %s",
668: opt->sflag, opt->lflag, opt->usage);
669: fprintf(stderr, "%-40s%s\n", buf, opt->desc);
670: }
671: exit(ex);
672: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>