1 |
|
|
/* $NetBSD: main.c,v 1.6 1995/12/10 10:07:05 mycroft Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* The mrouted program is covered by the license in the accompanying file |
5 |
|
|
* named "LICENSE". Use of the mrouted program represents acceptance of |
6 |
|
|
* the terms and conditions listed in that file. |
7 |
|
|
* |
8 |
|
|
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of |
9 |
|
|
* Leland Stanford Junior University. |
10 |
|
|
*/ |
11 |
|
|
|
12 |
|
|
/* |
13 |
|
|
* Written by Steve Deering, Stanford University, February 1989. |
14 |
|
|
* |
15 |
|
|
* (An earlier version of DVMRP was implemented by David Waitzman of |
16 |
|
|
* BBN STC by extending Berkeley's routed program. Some of Waitzman's |
17 |
|
|
* extensions have been incorporated into mrouted, but none of the |
18 |
|
|
* original routed code has been adopted.) |
19 |
|
|
*/ |
20 |
|
|
|
21 |
|
|
|
22 |
|
|
#include "defs.h" |
23 |
|
|
#include <stdarg.h> |
24 |
|
|
#include <fcntl.h> |
25 |
|
|
#include <poll.h> |
26 |
|
|
#include <err.h> |
27 |
|
|
|
28 |
|
|
extern char *configfilename; |
29 |
|
|
char versionstring[100]; |
30 |
|
|
|
31 |
|
|
static char dumpfilename[] = _PATH_MROUTED_DUMP; |
32 |
|
|
static char cachefilename[] = _PATH_MROUTED_CACHE; |
33 |
|
|
static char genidfilename[] = _PATH_MROUTED_GENID; |
34 |
|
|
|
35 |
|
|
int cache_lifetime = DEFAULT_CACHE_LIFETIME; |
36 |
|
|
int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2; |
37 |
|
|
|
38 |
|
|
int debug = 0; |
39 |
|
|
u_char pruning = 1; /* Enable pruning by default */ |
40 |
|
|
|
41 |
|
|
#define NHANDLERS 2 |
42 |
|
|
|
43 |
|
|
static struct ihandler { |
44 |
|
|
int fd; /* File descriptor */ |
45 |
|
|
ihfunc_t func; /* Function to call */ |
46 |
|
|
} ihandlers[NHANDLERS]; |
47 |
|
|
static int nhandlers = 0; |
48 |
|
|
|
49 |
|
|
/* |
50 |
|
|
* Forward declarations. |
51 |
|
|
*/ |
52 |
|
|
static void fasttimer(int); |
53 |
|
|
static void done(int); |
54 |
|
|
static void dump(int); |
55 |
|
|
static void fdump(int); |
56 |
|
|
static void cdump(int); |
57 |
|
|
static void restart(int); |
58 |
|
|
static void timer(void); |
59 |
|
|
static void cleanup(void); |
60 |
|
|
static void resetlogging(void *); |
61 |
|
|
|
62 |
|
|
int |
63 |
|
|
register_input_handler(int fd, ihfunc_t func) |
64 |
|
|
{ |
65 |
|
|
if (nhandlers >= NHANDLERS) |
66 |
|
|
return -1; |
67 |
|
|
|
68 |
|
|
ihandlers[nhandlers].fd = fd; |
69 |
|
|
ihandlers[nhandlers++].func = func; |
70 |
|
|
|
71 |
|
|
return 0; |
72 |
|
|
} |
73 |
|
|
|
74 |
|
|
int |
75 |
|
|
main(int argc, char *argv[]) |
76 |
|
|
{ |
77 |
|
|
int recvlen; |
78 |
|
|
int dummy; |
79 |
|
|
FILE *fp; |
80 |
|
|
struct timeval now; |
81 |
|
|
u_int32_t prev_genid; |
82 |
|
|
struct pollfd *pfd; |
83 |
|
|
int vers, n, i, ch; |
84 |
|
|
sigset_t mask, omask; |
85 |
|
|
const char *errstr; |
86 |
|
|
|
87 |
|
|
if (geteuid() != 0) { |
88 |
|
|
fprintf(stderr, "must be root\n"); |
89 |
|
|
exit(1); |
90 |
|
|
} |
91 |
|
|
setvbuf(stderr, NULL, _IOLBF, 0); |
92 |
|
|
|
93 |
|
|
while ((ch = getopt(argc, argv, "c:d::p")) != -1) { |
94 |
|
|
switch (ch) { |
95 |
|
|
case 'c': |
96 |
|
|
configfilename = optarg; |
97 |
|
|
break; |
98 |
|
|
case 'd': |
99 |
|
|
if (!optarg) |
100 |
|
|
debug = DEFAULT_DEBUG; |
101 |
|
|
else { |
102 |
|
|
debug = strtonum(optarg, 0, 3, &errstr); |
103 |
|
|
if (errstr) { |
104 |
|
|
warnx("debug level %s", errstr); |
105 |
|
|
debug = DEFAULT_DEBUG; |
106 |
|
|
} |
107 |
|
|
} |
108 |
|
|
break; |
109 |
|
|
case 'p': |
110 |
|
|
pruning = 0; |
111 |
|
|
break; |
112 |
|
|
default: |
113 |
|
|
goto usage; |
114 |
|
|
} |
115 |
|
|
} |
116 |
|
|
argc -= optind; |
117 |
|
|
argv += optind; |
118 |
|
|
|
119 |
|
|
if (argc > 0) { |
120 |
|
|
usage: fprintf(stderr, |
121 |
|
|
"usage: mrouted [-p] [-c config_file] [-d [debug_level]]\n"); |
122 |
|
|
exit(1); |
123 |
|
|
} |
124 |
|
|
|
125 |
|
|
if (debug == 0) { |
126 |
|
|
/* |
127 |
|
|
* Detach from the terminal |
128 |
|
|
*/ |
129 |
|
|
int t; |
130 |
|
|
|
131 |
|
|
if (fork()) exit(0); |
132 |
|
|
(void)close(0); |
133 |
|
|
(void)close(1); |
134 |
|
|
(void)close(2); |
135 |
|
|
(void)open("/dev/null", O_RDONLY); |
136 |
|
|
(void)dup2(0, 1); |
137 |
|
|
(void)dup2(0, 2); |
138 |
|
|
#ifdef TIOCNOTTY |
139 |
|
|
t = open("/dev/tty", O_RDWR); |
140 |
|
|
if (t >= 0) { |
141 |
|
|
(void)ioctl(t, TIOCNOTTY, (char *)0); |
142 |
|
|
(void)close(t); |
143 |
|
|
} |
144 |
|
|
#else |
145 |
|
|
if (setsid() < 0) |
146 |
|
|
perror("setsid"); |
147 |
|
|
#endif |
148 |
|
|
} |
149 |
|
|
else |
150 |
|
|
fprintf(stderr, "debug level %u\n", debug); |
151 |
|
|
|
152 |
|
|
#ifdef LOG_DAEMON |
153 |
|
|
(void)openlog("mrouted", LOG_PID, LOG_DAEMON); |
154 |
|
|
(void)setlogmask(LOG_UPTO(LOG_NOTICE)); |
155 |
|
|
#else |
156 |
|
|
(void)openlog("mrouted", LOG_PID); |
157 |
|
|
#endif |
158 |
|
|
snprintf(versionstring, sizeof versionstring, "mrouted version %d.%d", |
159 |
|
|
PROTOCOL_VERSION, MROUTED_VERSION); |
160 |
|
|
|
161 |
|
|
logit(LOG_NOTICE, 0, "%s", versionstring); |
162 |
|
|
|
163 |
|
|
/* |
164 |
|
|
* Get generation id |
165 |
|
|
*/ |
166 |
|
|
gettimeofday(&now, NULL); |
167 |
|
|
dvmrp_genid = (u_int32_t)now.tv_sec; /* for a while after 2038 */ |
168 |
|
|
|
169 |
|
|
fp = fopen(genidfilename, "r"); |
170 |
|
|
if (fp != NULL) { |
171 |
|
|
fscanf(fp, "%d", &prev_genid); |
172 |
|
|
if (prev_genid == dvmrp_genid) |
173 |
|
|
dvmrp_genid++; |
174 |
|
|
(void) fclose(fp); |
175 |
|
|
} |
176 |
|
|
|
177 |
|
|
fp = fopen(genidfilename, "w"); |
178 |
|
|
if (fp != NULL) { |
179 |
|
|
fprintf(fp, "%d", dvmrp_genid); |
180 |
|
|
(void) fclose(fp); |
181 |
|
|
} |
182 |
|
|
|
183 |
|
|
callout_init(); |
184 |
|
|
init_igmp(); |
185 |
|
|
init_routes(); |
186 |
|
|
init_ktable(); |
187 |
|
|
k_init_dvmrp(); /* enable DVMRP routing in kernel */ |
188 |
|
|
|
189 |
|
|
#ifndef OLD_KERNEL |
190 |
|
|
vers = k_get_version(); |
191 |
|
|
/*XXX |
192 |
|
|
* This function must change whenever the kernel version changes |
193 |
|
|
*/ |
194 |
|
|
if ((((vers >> 8) & 0xff) != 3) || |
195 |
|
|
((vers & 0xff) != 5)) |
196 |
|
|
logit(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch", |
197 |
|
|
(vers >> 8) & 0xff, vers & 0xff, |
198 |
|
|
PROTOCOL_VERSION, MROUTED_VERSION); |
199 |
|
|
#endif |
200 |
|
|
|
201 |
|
|
init_vifs(); |
202 |
|
|
|
203 |
|
|
#ifdef RSRR |
204 |
|
|
rsrr_init(); |
205 |
|
|
#endif /* RSRR */ |
206 |
|
|
|
207 |
|
|
/* |
208 |
|
|
* Allow cleanup if unexpected exit. Apparently some architectures |
209 |
|
|
* have a kernel bug where closing the socket doesn't do an |
210 |
|
|
* ip_mrouter_done(), so we attempt to do it on exit. |
211 |
|
|
*/ |
212 |
|
|
atexit(cleanup); |
213 |
|
|
|
214 |
|
|
if (debug) |
215 |
|
|
fprintf(stderr, "pruning %s\n", pruning ? "on" : "off"); |
216 |
|
|
|
217 |
|
|
(void)signal(SIGALRM, fasttimer); |
218 |
|
|
|
219 |
|
|
(void)signal(SIGHUP, restart); |
220 |
|
|
(void)signal(SIGTERM, done); |
221 |
|
|
(void)signal(SIGINT, done); |
222 |
|
|
(void)signal(SIGUSR1, fdump); |
223 |
|
|
(void)signal(SIGUSR2, cdump); |
224 |
|
|
if (debug != 0) |
225 |
|
|
(void)signal(SIGQUIT, dump); |
226 |
|
|
|
227 |
|
|
pfd = calloc(sizeof(struct pollfd), 1 + nhandlers); |
228 |
|
|
pfd[0].fd = igmp_socket; |
229 |
|
|
pfd[0].events = POLLIN; |
230 |
|
|
for (i = 0; i < nhandlers; i++) { |
231 |
|
|
pfd[i + 1].fd = ihandlers[i].fd; |
232 |
|
|
pfd[i + 1].events = POLLIN; |
233 |
|
|
} |
234 |
|
|
|
235 |
|
|
/* |
236 |
|
|
* Install the vifs in the kernel as late as possible in the |
237 |
|
|
* initialization sequence. |
238 |
|
|
*/ |
239 |
|
|
init_installvifs(); |
240 |
|
|
|
241 |
|
|
if (debug >= 2) dump(0); |
242 |
|
|
|
243 |
|
|
/* Start up the log rate-limiter */ |
244 |
|
|
resetlogging(NULL); |
245 |
|
|
|
246 |
|
|
(void)alarm(1); /* schedule first timer interrupt */ |
247 |
|
|
|
248 |
|
|
/* |
249 |
|
|
* Main receive loop. |
250 |
|
|
*/ |
251 |
|
|
dummy = 0; |
252 |
|
|
for(;;) { |
253 |
|
|
if ((n = poll(pfd, nhandlers + 1, -1)) < 0) { |
254 |
|
|
if (errno != EINTR) /* SIGALRM is expected */ |
255 |
|
|
logit(LOG_WARNING, errno, "poll failed"); |
256 |
|
|
continue; |
257 |
|
|
} |
258 |
|
|
|
259 |
|
|
if (pfd[0].revents & POLLIN) { |
260 |
|
|
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, |
261 |
|
|
0, NULL, &dummy); |
262 |
|
|
if (recvlen < 0) { |
263 |
|
|
if (errno != EINTR) logit(LOG_ERR, errno, "recvfrom"); |
264 |
|
|
continue; |
265 |
|
|
} |
266 |
|
|
(void)sigemptyset(&mask); |
267 |
|
|
(void)sigaddset(&mask, SIGALRM); |
268 |
|
|
if (sigprocmask(SIG_BLOCK, &mask, &omask) < 0) |
269 |
|
|
logit(LOG_ERR, errno, "sigprocmask"); |
270 |
|
|
accept_igmp(recvlen); |
271 |
|
|
(void)sigprocmask(SIG_SETMASK, &omask, NULL); |
272 |
|
|
} |
273 |
|
|
|
274 |
|
|
for (i = 0; i < nhandlers; i++) { |
275 |
|
|
if (pfd[i + 1].revents & POLLIN) { |
276 |
|
|
(*ihandlers[i].func)(ihandlers[i].fd); |
277 |
|
|
} |
278 |
|
|
} |
279 |
|
|
} |
280 |
|
|
} |
281 |
|
|
|
282 |
|
|
|
283 |
|
|
/* |
284 |
|
|
* routine invoked every second. Its main goal is to cycle through |
285 |
|
|
* the routing table and send partial updates to all neighbors at a |
286 |
|
|
* rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL |
287 |
|
|
* seconds. Also, every TIMER_INTERVAL seconds it calls timer() to |
288 |
|
|
* do all the other time-based processing. |
289 |
|
|
*/ |
290 |
|
|
/* XXX signal race */ |
291 |
|
|
static void |
292 |
|
|
fasttimer(int i) |
293 |
|
|
{ |
294 |
|
|
static unsigned int tlast; |
295 |
|
|
static unsigned int nsent; |
296 |
|
|
unsigned int t = tlast + 1; |
297 |
|
|
int n; |
298 |
|
|
|
299 |
|
|
/* |
300 |
|
|
* if we're in the last second, send everything that's left. |
301 |
|
|
* otherwise send at least the fraction we should have sent by now. |
302 |
|
|
*/ |
303 |
|
|
if (t >= ROUTE_REPORT_INTERVAL) { |
304 |
|
|
int nleft = nroutes - nsent; |
305 |
|
|
while (nleft > 0) { |
306 |
|
|
if ((n = report_next_chunk()) <= 0) |
307 |
|
|
break; |
308 |
|
|
nleft -= n; |
309 |
|
|
} |
310 |
|
|
tlast = 0; |
311 |
|
|
nsent = 0; |
312 |
|
|
} else { |
313 |
|
|
unsigned int ncum = nroutes * t / ROUTE_REPORT_INTERVAL; |
314 |
|
|
while (nsent < ncum) { |
315 |
|
|
if ((n = report_next_chunk()) <= 0) |
316 |
|
|
break; |
317 |
|
|
nsent += n; |
318 |
|
|
} |
319 |
|
|
tlast = t; |
320 |
|
|
} |
321 |
|
|
if ((t % TIMER_INTERVAL) == 0) |
322 |
|
|
timer(); |
323 |
|
|
|
324 |
|
|
age_callout_queue();/* Advance the timer for the callout queue |
325 |
|
|
for groups */ |
326 |
|
|
alarm(1); |
327 |
|
|
} |
328 |
|
|
|
329 |
|
|
/* |
330 |
|
|
* The 'virtual_time' variable is initialized to a value that will cause the |
331 |
|
|
* first invocation of timer() to send a probe or route report to all vifs |
332 |
|
|
* and send group membership queries to all subnets for which this router is |
333 |
|
|
* querier. This first invocation occurs approximately TIMER_INTERVAL seconds |
334 |
|
|
* after the router starts up. Note that probes for neighbors and queries |
335 |
|
|
* for group memberships are also sent at start-up time, as part of initial- |
336 |
|
|
* ization. This repetition after a short interval is desirable for quickly |
337 |
|
|
* building up topology and membership information in the presence of possible |
338 |
|
|
* packet loss. |
339 |
|
|
* |
340 |
|
|
* 'virtual_time' advances at a rate that is only a crude approximation of |
341 |
|
|
* real time, because it does not take into account any time spent processing, |
342 |
|
|
* and because the timer intervals are sometimes shrunk by a random amount to |
343 |
|
|
* avoid unwanted synchronization with other routers. |
344 |
|
|
*/ |
345 |
|
|
|
346 |
|
|
static u_long virtual_time = 0; |
347 |
|
|
|
348 |
|
|
|
349 |
|
|
/* |
350 |
|
|
* Timer routine. Performs periodic neighbor probing, route reporting, and |
351 |
|
|
* group querying duties, and drives various timers in routing entries and |
352 |
|
|
* virtual interface data structures. |
353 |
|
|
*/ |
354 |
|
|
static void |
355 |
|
|
timer(void) |
356 |
|
|
{ |
357 |
|
|
age_routes(); /* Advance the timers in the route entries */ |
358 |
|
|
age_vifs(); /* Advance the timers for neighbors */ |
359 |
|
|
age_table_entry(); /* Advance the timers for the cache entries */ |
360 |
|
|
|
361 |
|
|
if (virtual_time % GROUP_QUERY_INTERVAL == 0) { |
362 |
|
|
/* |
363 |
|
|
* Time to query the local group memberships on all subnets |
364 |
|
|
* for which this router is the elected querier. |
365 |
|
|
*/ |
366 |
|
|
query_groups(); |
367 |
|
|
} |
368 |
|
|
|
369 |
|
|
if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) { |
370 |
|
|
/* |
371 |
|
|
* Time to send a probe on all vifs from which no neighbors have |
372 |
|
|
* been heard. Also, check if any inoperative interfaces have now |
373 |
|
|
* come up. (If they have, they will also be probed as part of |
374 |
|
|
* their initialization.) |
375 |
|
|
*/ |
376 |
|
|
probe_for_neighbors(); |
377 |
|
|
|
378 |
|
|
if (vifs_down) |
379 |
|
|
check_vif_state(); |
380 |
|
|
} |
381 |
|
|
|
382 |
|
|
delay_change_reports = FALSE; |
383 |
|
|
if (routes_changed) { |
384 |
|
|
/* |
385 |
|
|
* Some routes have changed since the last timer interrupt, but |
386 |
|
|
* have not been reported yet. Report the changed routes to all |
387 |
|
|
* neighbors. |
388 |
|
|
*/ |
389 |
|
|
report_to_all_neighbors(CHANGED_ROUTES); |
390 |
|
|
} |
391 |
|
|
|
392 |
|
|
/* |
393 |
|
|
* Advance virtual time |
394 |
|
|
*/ |
395 |
|
|
virtual_time += TIMER_INTERVAL; |
396 |
|
|
} |
397 |
|
|
|
398 |
|
|
|
399 |
|
|
/* |
400 |
|
|
* On termination, let everyone know we're going away. |
401 |
|
|
*/ |
402 |
|
|
/* XXX signal race */ |
403 |
|
|
static void |
404 |
|
|
done(int i) |
405 |
|
|
{ |
406 |
|
|
logit(LOG_NOTICE, 0, "%s exiting", versionstring); |
407 |
|
|
cleanup(); |
408 |
|
|
_exit(1); |
409 |
|
|
} |
410 |
|
|
|
411 |
|
|
/* XXX signal race, atexit race */ |
412 |
|
|
static void |
413 |
|
|
cleanup(void) |
414 |
|
|
{ |
415 |
|
|
static int in_cleanup = 0; |
416 |
|
|
|
417 |
|
|
if (!in_cleanup) { |
418 |
|
|
in_cleanup++; |
419 |
|
|
#ifdef RSRR |
420 |
|
|
rsrr_clean(); |
421 |
|
|
#endif /* RSRR */ |
422 |
|
|
expire_all_routes(); |
423 |
|
|
report_to_all_neighbors(ALL_ROUTES); |
424 |
|
|
k_stop_dvmrp(); |
425 |
|
|
} |
426 |
|
|
} |
427 |
|
|
|
428 |
|
|
|
429 |
|
|
/* |
430 |
|
|
* Dump internal data structures to stderr. |
431 |
|
|
*/ |
432 |
|
|
/* XXX signal race */ |
433 |
|
|
static void |
434 |
|
|
dump(int i) |
435 |
|
|
{ |
436 |
|
|
dump_vifs(stderr); |
437 |
|
|
dump_routes(stderr); |
438 |
|
|
} |
439 |
|
|
|
440 |
|
|
|
441 |
|
|
/* |
442 |
|
|
* Dump internal data structures to a file. |
443 |
|
|
*/ |
444 |
|
|
static void |
445 |
|
|
fdump(int i) |
446 |
|
|
{ |
447 |
|
|
FILE *fp; |
448 |
|
|
|
449 |
|
|
fp = fopen(dumpfilename, "w"); |
450 |
|
|
if (fp != NULL) { |
451 |
|
|
dump_vifs(fp); |
452 |
|
|
dump_routes(fp); |
453 |
|
|
(void) fclose(fp); |
454 |
|
|
} |
455 |
|
|
} |
456 |
|
|
|
457 |
|
|
|
458 |
|
|
/* |
459 |
|
|
* Dump local cache contents to a file. |
460 |
|
|
*/ |
461 |
|
|
/* XXX signal race */ |
462 |
|
|
static void |
463 |
|
|
cdump(int i) |
464 |
|
|
{ |
465 |
|
|
FILE *fp; |
466 |
|
|
|
467 |
|
|
fp = fopen(cachefilename, "w"); |
468 |
|
|
if (fp != NULL) { |
469 |
|
|
dump_cache(fp); |
470 |
|
|
(void) fclose(fp); |
471 |
|
|
} |
472 |
|
|
} |
473 |
|
|
|
474 |
|
|
|
475 |
|
|
/* |
476 |
|
|
* Restart mrouted |
477 |
|
|
*/ |
478 |
|
|
/* XXX signal race */ |
479 |
|
|
static void |
480 |
|
|
restart(int i) |
481 |
|
|
{ |
482 |
|
|
sigset_t mask, omask; |
483 |
|
|
|
484 |
|
|
logit(LOG_NOTICE, 0, "%s restart", versionstring); |
485 |
|
|
|
486 |
|
|
/* |
487 |
|
|
* reset all the entries |
488 |
|
|
*/ |
489 |
|
|
(void)sigemptyset(&mask); |
490 |
|
|
(void)sigaddset(&mask, SIGALRM); |
491 |
|
|
if (sigprocmask(SIG_BLOCK, &mask, &omask) < 0) |
492 |
|
|
logit(LOG_ERR, errno, "sigprocmask"); |
493 |
|
|
free_all_prunes(); |
494 |
|
|
free_all_routes(); |
495 |
|
|
stop_all_vifs(); |
496 |
|
|
k_stop_dvmrp(); |
497 |
|
|
close(igmp_socket); |
498 |
|
|
close(udp_socket); |
499 |
|
|
|
500 |
|
|
/* |
501 |
|
|
* start processing again |
502 |
|
|
*/ |
503 |
|
|
dvmrp_genid++; |
504 |
|
|
pruning = 1; |
505 |
|
|
|
506 |
|
|
init_igmp(); |
507 |
|
|
init_routes(); |
508 |
|
|
init_ktable(); |
509 |
|
|
init_vifs(); |
510 |
|
|
k_init_dvmrp(); /* enable DVMRP routing in kernel */ |
511 |
|
|
init_installvifs(); |
512 |
|
|
|
513 |
|
|
(void)sigprocmask(SIG_SETMASK, &omask, NULL); |
514 |
|
|
} |
515 |
|
|
|
516 |
|
|
#define LOG_MAX_MSGS 20 /* if > 20/minute then shut up for a while */ |
517 |
|
|
#define LOG_SHUT_UP 600 /* shut up for 10 minutes */ |
518 |
|
|
static int log_nmsgs = 0; |
519 |
|
|
|
520 |
|
|
static void |
521 |
|
|
resetlogging(void *arg) |
522 |
|
|
{ |
523 |
|
|
int nxttime = 60; |
524 |
|
|
void *narg = NULL; |
525 |
|
|
|
526 |
|
|
if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) { |
527 |
|
|
nxttime = LOG_SHUT_UP; |
528 |
|
|
narg = (void *)&log_nmsgs; /* just need some valid void * */ |
529 |
|
|
syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes", |
530 |
|
|
LOG_SHUT_UP / 60); |
531 |
|
|
} else { |
532 |
|
|
log_nmsgs = 0; |
533 |
|
|
} |
534 |
|
|
|
535 |
|
|
timer_setTimer(nxttime, resetlogging, narg); |
536 |
|
|
} |
537 |
|
|
|
538 |
|
|
/* |
539 |
|
|
* Log errors and other messages to the system log daemon and to stderr, |
540 |
|
|
* according to the severity of the message and the current debug level. |
541 |
|
|
* For errors of severity LOG_ERR or worse, terminate the program. |
542 |
|
|
*/ |
543 |
|
|
void |
544 |
|
|
logit(int severity, int syserr, char *format, ...) |
545 |
|
|
{ |
546 |
|
|
va_list ap; |
547 |
|
|
static char fmt[211] = "warning - "; |
548 |
|
|
char *msg; |
549 |
|
|
char tbuf[20]; |
550 |
|
|
struct timeval now; |
551 |
|
|
struct tm *thyme; |
552 |
|
|
time_t t; |
553 |
|
|
|
554 |
|
|
va_start(ap, format); |
555 |
|
|
vsnprintf(&fmt[10], sizeof fmt - 10, format, ap); |
556 |
|
|
va_end(ap); |
557 |
|
|
msg = (severity == LOG_WARNING) ? fmt : &fmt[10]; |
558 |
|
|
|
559 |
|
|
switch (debug) { |
560 |
|
|
case 0: break; |
561 |
|
|
case 1: if (severity > LOG_NOTICE) break; |
562 |
|
|
case 2: if (severity > LOG_INFO ) break; |
563 |
|
|
default: |
564 |
|
|
gettimeofday(&now,NULL); |
565 |
|
|
t = now.tv_sec; |
566 |
|
|
thyme = localtime(&t); |
567 |
|
|
strftime(tbuf, sizeof(tbuf), "%X.%%03d ", thyme); |
568 |
|
|
fprintf(stderr, tbuf, now.tv_usec / 1000); |
569 |
|
|
fprintf(stderr, "%s", msg); |
570 |
|
|
if (syserr == 0) |
571 |
|
|
fprintf(stderr, "\n"); |
572 |
|
|
else if (syserr < sys_nerr) |
573 |
|
|
fprintf(stderr, ": %s\n", sys_errlist[syserr]); |
574 |
|
|
else |
575 |
|
|
fprintf(stderr, ": errno %d\n", syserr); |
576 |
|
|
} |
577 |
|
|
|
578 |
|
|
if (severity <= LOG_NOTICE) { |
579 |
|
|
if (log_nmsgs++ < LOG_MAX_MSGS) { |
580 |
|
|
if (syserr != 0) { |
581 |
|
|
errno = syserr; |
582 |
|
|
syslog(severity, "%s: %m", msg); |
583 |
|
|
} else |
584 |
|
|
syslog(severity, "%s", msg); |
585 |
|
|
} |
586 |
|
|
|
587 |
|
|
if (severity <= LOG_ERR) exit(1); |
588 |
|
|
} |
589 |
|
|
} |
590 |
|
|
|
591 |
|
|
#ifdef DEBUG_MFC |
592 |
|
|
void |
593 |
|
|
md_logit(int what, u_int32_t origin, u_int32_t mcastgrp) |
594 |
|
|
{ |
595 |
|
|
static FILE *f = NULL; |
596 |
|
|
struct timeval tv; |
597 |
|
|
u_int32_t buf[4]; |
598 |
|
|
|
599 |
|
|
if (!f) { |
600 |
|
|
if ((f = fopen("/tmp/mrouted.clog", "w")) == NULL) { |
601 |
|
|
logit(LOG_ERR, errno, "open /tmp/mrouted.clog"); |
602 |
|
|
} |
603 |
|
|
} |
604 |
|
|
|
605 |
|
|
gettimeofday(&tv, NULL); |
606 |
|
|
buf[0] = tv.tv_sec; |
607 |
|
|
buf[1] = what; |
608 |
|
|
buf[2] = origin; |
609 |
|
|
buf[3] = mcastgrp; |
610 |
|
|
|
611 |
|
|
fwrite(buf, sizeof(u_int32_t), 4, f); |
612 |
|
|
} |
613 |
|
|
#endif |