Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / ntpd / ntp_util.c
bloba73045cfee6b28d74bab22909745874fbb1c923c
1 /* $NetBSD: ntp_util.c,v 1.6 2006/06/18 21:35:57 kardel Exp $ */
3 /*
4 * ntp_util.c - stuff I didn't have any other place for
5 */
7 #ifdef HAVE_CONFIG_H
8 # include <config.h>
9 #endif
11 #include "ntpd.h"
12 #include "ntp_io.h"
13 #include "ntp_unixtime.h"
14 #include "ntp_filegen.h"
15 #include "ntp_if.h"
16 #include "ntp_stdlib.h"
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_IOCTL_H
22 # include <sys/ioctl.h>
23 #endif
25 #ifdef HAVE_IEEEFP_H
26 # include <ieeefp.h>
27 #endif
28 #ifdef HAVE_MATH_H
29 # include <math.h>
30 #endif
32 #ifdef DOSYNCTODR
33 # if !defined(VMS)
34 # include <sys/resource.h>
35 # endif /* VMS */
36 #endif
38 #if defined(VMS)
39 # include <descrip.h>
40 #endif /* VMS */
43 * This contains odds and ends. Right now the only thing you'll find
44 * in here is the hourly stats printer and some code to support
45 * rereading the keys file, but I may eventually put other things in
46 * here such as code to do something with the leap bits.
49 * Name of the keys file
51 static char *key_file_name;
54 * The name of the drift_comp file and the temporary.
56 static char *stats_drift_file;
57 static char *stats_temp_file;
58 int stats_write_period = 3600; /* # of seconds between writes. */
59 double stats_write_tolerance = 0;
60 static double prev_drift_comp = 99999.;
63 * Statistics file stuff
65 #ifndef NTP_VAR
66 # ifndef SYS_WINNT
67 # define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */
68 # else
69 # define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */
70 # endif /* SYS_WINNT */
71 #endif
73 #ifndef MAXPATHLEN
74 # define MAXPATHLEN 256
75 #endif
77 static char statsdir[MAXPATHLEN] = NTP_VAR;
79 static FILEGEN peerstats;
80 static FILEGEN loopstats;
81 static FILEGEN clockstats;
82 static FILEGEN rawstats;
83 static FILEGEN sysstats;
84 #ifdef DEBUG_TIMING
85 static FILEGEN timingstats;
86 #endif
87 #ifdef OPENSSL
88 static FILEGEN cryptostats;
89 #endif /* OPENSSL */
92 * This controls whether stats are written to the fileset. Provided
93 * so that ntpdc can turn off stats when the file system fills up.
95 int stats_control;
98 * Initial frequency offset later passed to the loopfilter.
100 double old_drift;
103 * init_util - initialize the utilities
105 void
106 init_util(void)
108 stats_drift_file = 0;
109 stats_temp_file = 0;
110 key_file_name = 0;
112 filegen_register(&statsdir[0], "peerstats", &peerstats);
114 filegen_register(&statsdir[0], "loopstats", &loopstats);
116 filegen_register(&statsdir[0], "clockstats", &clockstats);
118 filegen_register(&statsdir[0], "rawstats", &rawstats);
120 filegen_register(&statsdir[0], "sysstats", &sysstats);
122 #ifdef OPENSSL
123 filegen_register(&statsdir[0], "cryptostats", &cryptostats);
124 #endif /* OPENSSL */
126 #ifdef DEBUG_TIMING
127 filegen_register(&statsdir[0], "timingstats", &timingstats);
128 #endif
133 * hourly_stats - print some interesting stats
135 void
136 write_stats(void)
138 FILE *fp;
140 #ifdef DOSYNCTODR
141 struct timeval tv;
142 #if !defined(VMS)
143 int prio_set;
144 #endif
145 #ifdef HAVE_GETCLOCK
146 struct timespec ts;
147 #endif
148 int o_prio;
151 * Sometimes having a Sun can be a drag.
153 * The kernel variable dosynctodr controls whether the system's
154 * soft clock is kept in sync with the battery clock. If it
155 * is zero, then the soft clock is not synced, and the battery
156 * clock is simply left to rot. That means that when the system
157 * reboots, the battery clock (which has probably gone wacky)
158 * sets the soft clock. That means ntpd starts off with a very
159 * confused idea of what time it is. It then takes a large
160 * amount of time to figure out just how wacky the battery clock
161 * has made things drift, etc, etc. The solution is to make the
162 * battery clock sync up to system time. The way to do THAT is
163 * to simply set the time of day to the current time of day, but
164 * as quickly as possible. This may, or may not be a sensible
165 * thing to do.
167 * CAVEAT: settimeofday() steps the sun clock by about 800 us,
168 * so setting DOSYNCTODR seems a bad idea in the
169 * case of us resolution
172 #if !defined(VMS)
173 /* (prr) getpriority returns -1 on error, but -1 is also a valid
174 * return value (!), so instead we have to zero errno before the
175 * call and check it for non-zero afterwards.
177 errno = 0;
178 prio_set = 0;
179 o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */
182 * (prr) if getpriority succeeded, call setpriority to raise
183 * scheduling priority as high as possible. If that succeeds
184 * as well, set the prio_set flag so we remember to reset
185 * priority to its previous value below. Note that on Solaris
186 * 2.6 (and beyond?), both getpriority and setpriority will fail
187 * with ESRCH, because sched_setscheduler (called from main) put
188 * us in the real-time scheduling class which setpriority
189 * doesn't know about. Being in the real-time class is better
190 * than anything setpriority can do, anyhow, so this error is
191 * silently ignored.
193 if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0))
194 prio_set = 1; /* overdrive */
195 #endif /* VMS */
196 #ifdef HAVE_GETCLOCK
197 (void) getclock(TIMEOFDAY, &ts);
198 tv.tv_sec = ts.tv_sec;
199 tv.tv_usec = ts.tv_nsec / 1000;
200 #else /* not HAVE_GETCLOCK */
201 GETTIMEOFDAY(&tv,(struct timezone *)NULL);
202 #endif /* not HAVE_GETCLOCK */
203 if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) {
204 msyslog(LOG_ERR, "can't sync battery time: %m");
206 #if !defined(VMS)
207 if (prio_set)
208 setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
209 #endif /* VMS */
210 #endif /* DOSYNCTODR */
212 NLOG(NLOG_SYSSTATIST)
213 msyslog(LOG_INFO,
214 "offset %.6f sec freq %.3f ppm error %.6f poll %d",
215 last_offset, drift_comp * 1e6, sys_jitter,
216 sys_poll);
219 record_sys_stats();
220 if ((u_long)(fabs(prev_drift_comp - drift_comp) * 1e9) <=
221 (u_long)(fabs(stats_write_tolerance * drift_comp) * 1e9)) {
222 return;
224 prev_drift_comp = drift_comp;
225 if (stats_drift_file != 0) {
226 if ((fp = fopen(stats_temp_file, "w")) == NULL) {
227 msyslog(LOG_ERR, "can't open %s: %m",
228 stats_temp_file);
229 return;
231 fprintf(fp, "%.3f\n", drift_comp * 1e6);
232 (void)fclose(fp);
233 /* atomic */
234 #ifdef SYS_WINNT
235 (void) _unlink(stats_drift_file); /* rename semantics differ under NT */
236 #endif /* SYS_WINNT */
238 #ifndef NO_RENAME
239 (void) rename(stats_temp_file, stats_drift_file);
240 #else
241 /* we have no rename NFS of ftp in use */
242 if ((fp = fopen(stats_drift_file, "w")) == NULL) {
243 msyslog(LOG_ERR, "can't open %s: %m",
244 stats_drift_file);
245 return;
248 #endif
250 #if defined(VMS)
251 /* PURGE */
253 $DESCRIPTOR(oldvers,";-1");
254 struct dsc$descriptor driftdsc = {
255 strlen(stats_drift_file),0,0,stats_drift_file };
257 while(lib$delete_file(&oldvers,&driftdsc) & 1) ;
259 #endif
265 * stats_config - configure the stats operation
267 void
268 stats_config(
269 int item,
270 const char *invalue /* only one type so far */
273 FILE *fp;
274 const char *value;
275 int len;
278 * Expand environment strings under Windows NT, since the
279 * command interpreter doesn't do this, the program must.
281 #ifdef SYS_WINNT
282 char newvalue[MAX_PATH], parameter[MAX_PATH];
284 if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) {
285 switch(item) {
286 case STATS_FREQ_FILE:
287 strcpy(parameter,"STATS_FREQ_FILE");
288 break;
289 case STATS_STATSDIR:
290 strcpy(parameter,"STATS_STATSDIR");
291 break;
292 case STATS_PID_FILE:
293 strcpy(parameter,"STATS_PID_FILE");
294 break;
295 default:
296 strcpy(parameter,"UNKNOWN");
297 break;
299 value = invalue;
301 msyslog(LOG_ERR,
302 "ExpandEnvironmentStrings(%s) failed: %m\n", parameter);
303 } else {
304 value = newvalue;
306 #else
307 value = invalue;
308 #endif /* SYS_WINNT */
310 switch(item) {
311 case STATS_FREQ_FILE:
312 if (stats_drift_file != 0) {
313 (void) free(stats_drift_file);
314 (void) free(stats_temp_file);
315 stats_drift_file = 0;
316 stats_temp_file = 0;
319 if (value == 0 || (len = strlen(value)) == 0)
320 break;
322 stats_drift_file = (char*)emalloc((u_int)(len + 1));
323 #if !defined(VMS)
324 stats_temp_file = (char*)emalloc((u_int)(len +
325 sizeof(".TEMP")));
326 #else
327 stats_temp_file = (char*)emalloc((u_int)(len +
328 sizeof("-TEMP")));
329 #endif /* VMS */
330 memmove(stats_drift_file, value, (unsigned)(len+1));
331 memmove(stats_temp_file, value, (unsigned)len);
332 #if !defined(VMS)
333 memmove(stats_temp_file + len, ".TEMP",
334 sizeof(".TEMP"));
335 #else
336 memmove(stats_temp_file + len, "-TEMP",
337 sizeof("-TEMP"));
338 #endif /* VMS */
341 * Open drift file and read frequency. If the file is
342 * missing or contains errors, tell the loop to reset.
344 if ((fp = fopen(stats_drift_file, "r")) == NULL) {
345 old_drift = 1e9;
346 break;
348 if (fscanf(fp, "%lf", &old_drift) != 1) {
349 msyslog(LOG_ERR, "Frequency format error in %s",
350 stats_drift_file);
351 old_drift = 1e9;
352 fclose(fp);
353 break;
355 fclose(fp);
356 prev_drift_comp = old_drift / 1e6;
357 msyslog(LOG_INFO,
358 "frequency initialized %.3f PPM from %s",
359 old_drift, stats_drift_file);
360 break;
362 case STATS_STATSDIR:
363 if (strlen(value) >= sizeof(statsdir)) {
364 msyslog(LOG_ERR,
365 "value for statsdir too long (>%d, sigh)",
366 (int)sizeof(statsdir)-1);
367 } else {
368 l_fp now;
370 get_systime(&now);
371 strcpy(statsdir,value);
372 if(peerstats.prefix == &statsdir[0] &&
373 peerstats.fp != NULL) {
374 fclose(peerstats.fp);
375 peerstats.fp = NULL;
376 filegen_setup(&peerstats, now.l_ui);
378 if(loopstats.prefix == &statsdir[0] &&
379 loopstats.fp != NULL) {
380 fclose(loopstats.fp);
381 loopstats.fp = NULL;
382 filegen_setup(&loopstats, now.l_ui);
384 if(clockstats.prefix == &statsdir[0] &&
385 clockstats.fp != NULL) {
386 fclose(clockstats.fp);
387 clockstats.fp = NULL;
388 filegen_setup(&clockstats, now.l_ui);
390 if(rawstats.prefix == &statsdir[0] &&
391 rawstats.fp != NULL) {
392 fclose(rawstats.fp);
393 rawstats.fp = NULL;
394 filegen_setup(&rawstats, now.l_ui);
396 if(sysstats.prefix == &statsdir[0] &&
397 sysstats.fp != NULL) {
398 fclose(sysstats.fp);
399 sysstats.fp = NULL;
400 filegen_setup(&sysstats, now.l_ui);
402 #ifdef OPENSSL
403 if(cryptostats.prefix == &statsdir[0] &&
404 cryptostats.fp != NULL) {
405 fclose(cryptostats.fp);
406 cryptostats.fp = NULL;
407 filegen_setup(&cryptostats, now.l_ui);
409 #endif /* OPENSSL */
411 break;
413 case STATS_PID_FILE:
414 if ((fp = fopen(value, "w")) == NULL) {
415 msyslog(LOG_ERR, "Can't open %s: %m", value);
416 break;
418 fprintf(fp, "%d", (int) getpid());
419 fclose(fp);;
420 break;
422 default:
423 /* oh well */
424 break;
429 * record_peer_stats - write peer statistics to file
431 * file format:
432 * day (mjd)
433 * time (s past UTC midnight)
434 * peer (ip address)
435 * peer status word (hex)
436 * peer offset (s)
437 * peer delay (s)
438 * peer error bound (s)
439 * peer error (s)
441 void
442 record_peer_stats(
443 struct sockaddr_storage *addr,
444 int status,
445 double offset,
446 double delay,
447 double dispersion,
448 double skew
451 l_fp now;
452 u_long day;
454 if (!stats_control)
455 return;
457 get_systime(&now);
458 filegen_setup(&peerstats, now.l_ui);
459 day = now.l_ui / 86400 + MJD_1900;
460 now.l_ui %= 86400;
461 if (peerstats.fp != NULL) {
462 fprintf(peerstats.fp,
463 "%lu %s %s %x %.9f %.9f %.9f %.9f\n",
464 day, ulfptoa(&now, 3), stoa(addr), status, offset,
465 delay, dispersion, skew);
466 fflush(peerstats.fp);
471 * record_loop_stats - write loop filter statistics to file
473 * file format:
474 * day (mjd)
475 * time (s past midnight)
476 * offset (s)
477 * frequency (approx ppm)
478 * time constant (log base 2)
480 void
481 record_loop_stats(
482 double offset,
483 double freq,
484 double jitter,
485 double stability,
486 int spoll
489 l_fp now;
490 u_long day;
492 if (!stats_control)
493 return;
495 get_systime(&now);
496 filegen_setup(&loopstats, now.l_ui);
497 day = now.l_ui / 86400 + MJD_1900;
498 now.l_ui %= 86400;
499 if (loopstats.fp != NULL) {
500 fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n",
501 day, ulfptoa(&now, 3), offset, freq * 1e6, jitter,
502 stability * 1e6, spoll);
503 fflush(loopstats.fp);
508 * record_clock_stats - write clock statistics to file
510 * file format:
511 * day (mjd)
512 * time (s past midnight)
513 * peer (ip address)
514 * text message
516 void
517 record_clock_stats(
518 struct sockaddr_storage *addr,
519 const char *text
522 l_fp now;
523 u_long day;
525 if (!stats_control)
526 return;
528 get_systime(&now);
529 filegen_setup(&clockstats, now.l_ui);
530 day = now.l_ui / 86400 + MJD_1900;
531 now.l_ui %= 86400;
532 if (clockstats.fp != NULL) {
533 fprintf(clockstats.fp, "%lu %s %s %s\n",
534 day, ulfptoa(&now, 3), stoa(addr), text);
535 fflush(clockstats.fp);
540 * record_raw_stats - write raw timestamps to file
543 * file format
544 * time (s past midnight)
545 * peer ip address
546 * local ip address
547 * t1 t2 t3 t4 timestamps
549 void
550 record_raw_stats(
551 struct sockaddr_storage *srcadr,
552 struct sockaddr_storage *dstadr,
553 l_fp *t1,
554 l_fp *t2,
555 l_fp *t3,
556 l_fp *t4
559 l_fp now;
560 u_long day;
562 if (!stats_control)
563 return;
565 get_systime(&now);
566 filegen_setup(&rawstats, now.l_ui);
567 day = now.l_ui / 86400 + MJD_1900;
568 now.l_ui %= 86400;
569 if (rawstats.fp != NULL) {
570 fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n",
571 day, ulfptoa(&now, 3), stoa(srcadr), dstadr ? stoa(dstadr) : "-",
572 ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9),
573 ulfptoa(t4, 9));
574 fflush(rawstats.fp);
580 * record_sys_stats - write system statistics to file
582 * file format
583 * time (s past midnight)
584 * time since startup (hr)
585 * packets recieved
586 * packets processed
587 * current version
588 * previous version
589 * bad version
590 * access denied
591 * bad length or format
592 * bad authentication
593 * rate exceeded
595 void
596 record_sys_stats(void)
598 l_fp now;
599 u_long day;
601 if (!stats_control)
602 return;
604 get_systime(&now);
605 filegen_setup(&sysstats, now.l_ui);
606 day = now.l_ui / 86400 + MJD_1900;
607 now.l_ui %= 86400;
608 if (sysstats.fp != NULL) {
609 fprintf(sysstats.fp,
610 "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
611 day, ulfptoa(&now, 3), sys_stattime / 3600,
612 sys_received, sys_processed, sys_newversionpkt,
613 sys_oldversionpkt, sys_unknownversion,
614 sys_restricted, sys_badlength, sys_badauth,
615 sys_limitrejected);
616 fflush(sysstats.fp);
617 proto_clr_stats();
622 #ifdef OPENSSL
624 * record_crypto_stats - write crypto statistics to file
626 * file format:
627 * day (mjd)
628 * time (s past midnight)
629 * peer (ip address)
630 * text message
632 void
633 record_crypto_stats(
634 struct sockaddr_storage *addr,
635 const char *text
638 l_fp now;
639 u_long day;
641 if (!stats_control)
642 return;
644 get_systime(&now);
645 filegen_setup(&cryptostats, now.l_ui);
646 day = now.l_ui / 86400 + MJD_1900;
647 now.l_ui %= 86400;
648 if (cryptostats.fp != NULL) {
649 if (addr == NULL)
650 fprintf(cryptostats.fp, "%lu %s %s\n",
651 day, ulfptoa(&now, 3), text);
652 else
653 fprintf(cryptostats.fp, "%lu %s %s %s\n",
654 day, ulfptoa(&now, 3), stoa(addr), text);
655 fflush(cryptostats.fp);
658 #endif /* OPENSSL */
660 #ifdef DEBUG_TIMING
662 * record_crypto_stats - write crypto statistics to file
664 * file format:
665 * day (mjd)
666 * time (s past midnight)
667 * text message
669 void
670 record_timing_stats(
671 const char *text
674 static unsigned int flshcnt;
675 l_fp now;
676 u_long day;
678 if (!stats_control)
679 return;
681 get_systime(&now);
682 filegen_setup(&timingstats, now.l_ui);
683 day = now.l_ui / 86400 + MJD_1900;
684 now.l_ui %= 86400;
685 if (timingstats.fp != NULL) {
686 fprintf(timingstats.fp, "%lu %s %s\n",
687 day, lfptoa(&now, 3), text);
688 if (++flshcnt % 100 == 0)
689 fflush(timingstats.fp);
692 #endif
694 * getauthkeys - read the authentication keys from the specified file
696 void
697 getauthkeys(
698 const char *keyfile
701 int len;
703 len = strlen(keyfile);
704 if (len == 0)
705 return;
707 if (key_file_name != 0) {
708 if (len > (int)strlen(key_file_name)) {
709 (void) free(key_file_name);
710 key_file_name = 0;
714 if (key_file_name == 0) {
715 #ifndef SYS_WINNT
716 key_file_name = (char*)emalloc((u_int) (len + 1));
717 #else
718 key_file_name = (char*)emalloc((u_int) (MAXPATHLEN));
719 #endif
721 #ifndef SYS_WINNT
722 memmove(key_file_name, keyfile, (unsigned)(len+1));
723 #else
724 if (!ExpandEnvironmentStrings(keyfile, key_file_name, MAXPATHLEN))
726 msyslog(LOG_ERR,
727 "ExpandEnvironmentStrings(KEY_FILE) failed: %m\n");
729 #endif /* SYS_WINNT */
731 authreadkeys(key_file_name);
736 * rereadkeys - read the authentication key file over again.
738 void
739 rereadkeys(void)
741 if (key_file_name != 0)
742 authreadkeys(key_file_name);
746 * sock_hash - hash an sockaddr_storage structure
749 sock_hash(
750 struct sockaddr_storage *addr
753 int hashVal;
754 int i;
755 int len;
756 char *ch;
758 hashVal = 0;
759 len = 0;
761 * We can't just hash the whole thing because there are hidden
762 * fields in sockaddr_in6 that might be filled in by recvfrom(),
763 * so just use the family, port and address.
765 ch = (char *)&addr->ss_family;
766 hashVal = 37 * hashVal + (int)*ch;
767 if (sizeof(addr->ss_family) > 1) {
768 ch++;
769 hashVal = 37 * hashVal + (int)*ch;
771 switch(addr->ss_family) {
772 case AF_INET:
773 ch = (char *)&((struct sockaddr_in *)addr)->sin_addr;
774 len = sizeof(struct in_addr);
775 break;
776 case AF_INET6:
777 ch = (char *)&((struct sockaddr_in6 *)addr)->sin6_addr;
778 len = sizeof(struct in6_addr);
779 break;
782 for (i = 0; i < len ; i++)
783 hashVal = 37 * hashVal + (int)*(ch + i);
785 hashVal = hashVal % 128; /* % MON_HASH_SIZE hardcoded */
787 if (hashVal < 0)
788 hashVal += 128;
790 return hashVal;
793 #if notyet
795 * ntp_exit - document explicitly that ntpd has exited
797 void
798 ntp_exit(int retval)
800 msyslog(LOG_ERR, "EXITING with return code %d", retval);
801 exit(retval);
803 #endif