2 * ntp_util.c - stuff I didn't have any other place for
11 #include "ntp_unixtime.h"
12 #include "ntp_filegen.h"
14 #include "ntp_stdlib.h"
18 #include <sys/types.h>
19 #ifdef HAVE_SYS_IOCTL_H
20 # include <sys/ioctl.h>
32 # include <sys/resource.h>
41 * This contains odds and ends. Right now the only thing you'll find
42 * in here is the hourly stats printer and some code to support
43 * rereading the keys file, but I may eventually put other things in
44 * here such as code to do something with the leap bits.
47 * Name of the keys file
49 static char *key_file_name;
52 * The name of the drift_comp file and the temporary.
54 static char *stats_drift_file;
55 static char *stats_temp_file;
56 int stats_write_period = 3600; /* # of seconds between writes. */
57 double stats_write_tolerance = 0;
58 static double prev_drift_comp = 99999.;
61 * Statistics file stuff
65 # define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */
67 # define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */
68 # endif /* SYS_WINNT */
72 # define MAXPATHLEN 256
75 static char statsdir[MAXPATHLEN] = NTP_VAR;
77 static FILEGEN peerstats;
78 static FILEGEN loopstats;
79 static FILEGEN clockstats;
80 static FILEGEN rawstats;
81 static FILEGEN sysstats;
83 static FILEGEN timingstats;
86 static FILEGEN cryptostats;
90 * This controls whether stats are written to the fileset. Provided
91 * so that ntpdc can turn off stats when the file system fills up.
96 * Initial frequency offset later passed to the loopfilter.
101 * init_util - initialize the utilities
106 stats_drift_file = 0;
110 filegen_register(&statsdir[0], "peerstats", &peerstats);
112 filegen_register(&statsdir[0], "loopstats", &loopstats);
114 filegen_register(&statsdir[0], "clockstats", &clockstats);
116 filegen_register(&statsdir[0], "rawstats", &rawstats);
118 filegen_register(&statsdir[0], "sysstats", &sysstats);
121 filegen_register(&statsdir[0], "cryptostats", &cryptostats);
125 filegen_register(&statsdir[0], "timingstats", &timingstats);
131 * hourly_stats - print some interesting stats
149 * Sometimes having a Sun can be a drag.
151 * The kernel variable dosynctodr controls whether the system's
152 * soft clock is kept in sync with the battery clock. If it
153 * is zero, then the soft clock is not synced, and the battery
154 * clock is simply left to rot. That means that when the system
155 * reboots, the battery clock (which has probably gone wacky)
156 * sets the soft clock. That means ntpd starts off with a very
157 * confused idea of what time it is. It then takes a large
158 * amount of time to figure out just how wacky the battery clock
159 * has made things drift, etc, etc. The solution is to make the
160 * battery clock sync up to system time. The way to do THAT is
161 * to simply set the time of day to the current time of day, but
162 * as quickly as possible. This may, or may not be a sensible
165 * CAVEAT: settimeofday() steps the sun clock by about 800 us,
166 * so setting DOSYNCTODR seems a bad idea in the
167 * case of us resolution
171 /* (prr) getpriority returns -1 on error, but -1 is also a valid
172 * return value (!), so instead we have to zero errno before the
173 * call and check it for non-zero afterwards.
177 o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */
180 * (prr) if getpriority succeeded, call setpriority to raise
181 * scheduling priority as high as possible. If that succeeds
182 * as well, set the prio_set flag so we remember to reset
183 * priority to its previous value below. Note that on Solaris
184 * 2.6 (and beyond?), both getpriority and setpriority will fail
185 * with ESRCH, because sched_setscheduler (called from main) put
186 * us in the real-time scheduling class which setpriority
187 * doesn't know about. Being in the real-time class is better
188 * than anything setpriority can do, anyhow, so this error is
191 if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0))
192 prio_set = 1; /* overdrive */
195 (void) getclock(TIMEOFDAY, &ts);
196 tv.tv_sec = ts.tv_sec;
197 tv.tv_usec = ts.tv_nsec / 1000;
198 #else /* not HAVE_GETCLOCK */
199 GETTIMEOFDAY(&tv,(struct timezone *)NULL);
200 #endif /* not HAVE_GETCLOCK */
201 if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) {
202 msyslog(LOG_ERR, "can't sync battery time: %m");
206 setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
208 #endif /* DOSYNCTODR */
210 NLOG(NLOG_SYSSTATIST)
212 "offset %.6f sec freq %.3f ppm error %.6f poll %d",
213 last_offset, drift_comp * 1e6, sys_jitter,
218 if ((u_long)(fabs(prev_drift_comp - drift_comp) * 1e9) <=
219 (u_long)(fabs(stats_write_tolerance * drift_comp) * 1e9)) {
222 prev_drift_comp = drift_comp;
223 if (stats_drift_file != 0) {
224 if ((fp = fopen(stats_temp_file, "w")) == NULL) {
225 msyslog(LOG_ERR, "can't open %s: %m",
229 fprintf(fp, "%.3f\n", drift_comp * 1e6);
233 (void) _unlink(stats_drift_file); /* rename semantics differ under NT */
234 #endif /* SYS_WINNT */
237 (void) rename(stats_temp_file, stats_drift_file);
239 /* we have no rename NFS of ftp in use */
240 if ((fp = fopen(stats_drift_file, "w")) == NULL) {
241 msyslog(LOG_ERR, "can't open %s: %m",
251 $DESCRIPTOR(oldvers,";-1");
252 struct dsc$descriptor driftdsc = {
253 strlen(stats_drift_file),0,0,stats_drift_file };
255 while(lib$delete_file(&oldvers,&driftdsc) & 1) ;
263 * stats_config - configure the stats operation
268 const char *invalue /* only one type so far */
276 * Expand environment strings under Windows NT, since the
277 * command interpreter doesn't do this, the program must.
280 char newvalue[MAX_PATH], parameter[MAX_PATH];
282 if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) {
284 case STATS_FREQ_FILE:
285 strcpy(parameter,"STATS_FREQ_FILE");
288 strcpy(parameter,"STATS_STATSDIR");
291 strcpy(parameter,"STATS_PID_FILE");
294 strcpy(parameter,"UNKNOWN");
300 "ExpandEnvironmentStrings(%s) failed: %m\n", parameter);
306 #endif /* SYS_WINNT */
309 case STATS_FREQ_FILE:
310 if (stats_drift_file != 0) {
311 (void) free(stats_drift_file);
312 (void) free(stats_temp_file);
313 stats_drift_file = 0;
317 if (value == 0 || (len = strlen(value)) == 0)
320 stats_drift_file = (char*)emalloc((u_int)(len + 1));
322 stats_temp_file = (char*)emalloc((u_int)(len +
325 stats_temp_file = (char*)emalloc((u_int)(len +
328 memmove(stats_drift_file, value, (unsigned)(len+1));
329 memmove(stats_temp_file, value, (unsigned)len);
331 memmove(stats_temp_file + len, ".TEMP",
334 memmove(stats_temp_file + len, "-TEMP",
339 * Open drift file and read frequency. If the file is
340 * missing or contains errors, tell the loop to reset.
342 if ((fp = fopen(stats_drift_file, "r")) == NULL) {
346 if (fscanf(fp, "%lf", &old_drift) != 1) {
347 msyslog(LOG_ERR, "Frequency format error in %s",
354 prev_drift_comp = old_drift / 1e6;
356 "frequency initialized %.3f PPM from %s",
357 old_drift, stats_drift_file);
361 if (strlen(value) >= sizeof(statsdir)) {
363 "value for statsdir too long (>%d, sigh)",
364 (int)sizeof(statsdir)-1);
369 strcpy(statsdir,value);
370 if(peerstats.prefix == &statsdir[0] &&
371 peerstats.fp != NULL) {
372 fclose(peerstats.fp);
374 filegen_setup(&peerstats, now.l_ui);
376 if(loopstats.prefix == &statsdir[0] &&
377 loopstats.fp != NULL) {
378 fclose(loopstats.fp);
380 filegen_setup(&loopstats, now.l_ui);
382 if(clockstats.prefix == &statsdir[0] &&
383 clockstats.fp != NULL) {
384 fclose(clockstats.fp);
385 clockstats.fp = NULL;
386 filegen_setup(&clockstats, now.l_ui);
388 if(rawstats.prefix == &statsdir[0] &&
389 rawstats.fp != NULL) {
392 filegen_setup(&rawstats, now.l_ui);
394 if(sysstats.prefix == &statsdir[0] &&
395 sysstats.fp != NULL) {
398 filegen_setup(&sysstats, now.l_ui);
401 if(cryptostats.prefix == &statsdir[0] &&
402 cryptostats.fp != NULL) {
403 fclose(cryptostats.fp);
404 cryptostats.fp = NULL;
405 filegen_setup(&cryptostats, now.l_ui);
412 if ((fp = fopen(value, "w")) == NULL) {
413 msyslog(LOG_ERR, "Can't open %s: %m", value);
416 fprintf(fp, "%d", (int) getpid());
427 * record_peer_stats - write peer statistics to file
431 * time (s past UTC midnight)
433 * peer status word (hex)
436 * peer error bound (s)
441 struct sockaddr_storage *addr,
456 filegen_setup(&peerstats, now.l_ui);
457 day = now.l_ui / 86400 + MJD_1900;
459 if (peerstats.fp != NULL) {
460 fprintf(peerstats.fp,
461 "%lu %s %s %x %.9f %.9f %.9f %.9f\n",
462 day, ulfptoa(&now, 3), stoa(addr), status, offset,
463 delay, dispersion, skew);
464 fflush(peerstats.fp);
469 * record_loop_stats - write loop filter statistics to file
473 * time (s past midnight)
475 * frequency (approx ppm)
476 * time constant (log base 2)
494 filegen_setup(&loopstats, now.l_ui);
495 day = now.l_ui / 86400 + MJD_1900;
497 if (loopstats.fp != NULL) {
498 fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n",
499 day, ulfptoa(&now, 3), offset, freq * 1e6, jitter,
500 stability * 1e6, spoll);
501 fflush(loopstats.fp);
506 * record_clock_stats - write clock statistics to file
510 * time (s past midnight)
516 struct sockaddr_storage *addr,
527 filegen_setup(&clockstats, now.l_ui);
528 day = now.l_ui / 86400 + MJD_1900;
530 if (clockstats.fp != NULL) {
531 fprintf(clockstats.fp, "%lu %s %s %s\n",
532 day, ulfptoa(&now, 3), stoa(addr), text);
533 fflush(clockstats.fp);
538 * record_raw_stats - write raw timestamps to file
542 * time (s past midnight)
545 * t1 t2 t3 t4 timestamps
549 struct sockaddr_storage *srcadr,
550 struct sockaddr_storage *dstadr,
564 filegen_setup(&rawstats, now.l_ui);
565 day = now.l_ui / 86400 + MJD_1900;
567 if (rawstats.fp != NULL) {
568 fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n",
569 day, ulfptoa(&now, 3), stoa(srcadr), dstadr ? stoa(dstadr) : "-",
570 ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9),
578 * record_sys_stats - write system statistics to file
581 * time (s past midnight)
582 * time since startup (hr)
589 * bad length or format
594 record_sys_stats(void)
603 filegen_setup(&sysstats, now.l_ui);
604 day = now.l_ui / 86400 + MJD_1900;
606 if (sysstats.fp != NULL) {
608 "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
609 day, ulfptoa(&now, 3), sys_stattime / 3600,
610 sys_received, sys_processed, sys_newversionpkt,
611 sys_oldversionpkt, sys_unknownversion,
612 sys_restricted, sys_badlength, sys_badauth,
622 * record_crypto_stats - write crypto statistics to file
626 * time (s past midnight)
632 struct sockaddr_storage *addr,
643 filegen_setup(&cryptostats, now.l_ui);
644 day = now.l_ui / 86400 + MJD_1900;
646 if (cryptostats.fp != NULL) {
648 fprintf(cryptostats.fp, "%lu %s %s\n",
649 day, ulfptoa(&now, 3), text);
651 fprintf(cryptostats.fp, "%lu %s %s %s\n",
652 day, ulfptoa(&now, 3), stoa(addr), text);
653 fflush(cryptostats.fp);
660 * record_crypto_stats - write crypto statistics to file
664 * time (s past midnight)
672 static unsigned int flshcnt;
680 filegen_setup(&timingstats, now.l_ui);
681 day = now.l_ui / 86400 + MJD_1900;
683 if (timingstats.fp != NULL) {
684 fprintf(timingstats.fp, "%lu %s %s\n",
685 day, lfptoa(&now, 3), text);
686 if (++flshcnt % 100 == 0)
687 fflush(timingstats.fp);
692 * getauthkeys - read the authentication keys from the specified file
701 len = strlen(keyfile);
705 if (key_file_name != 0) {
706 if (len > (int)strlen(key_file_name)) {
707 (void) free(key_file_name);
712 if (key_file_name == 0) {
714 key_file_name = (char*)emalloc((u_int) (len + 1));
716 key_file_name = (char*)emalloc((u_int) (MAXPATHLEN));
720 memmove(key_file_name, keyfile, (unsigned)(len+1));
722 if (!ExpandEnvironmentStrings(keyfile, key_file_name, MAXPATHLEN))
725 "ExpandEnvironmentStrings(KEY_FILE) failed: %m\n");
727 #endif /* SYS_WINNT */
729 authreadkeys(key_file_name);
734 * rereadkeys - read the authentication key file over again.
739 if (key_file_name != 0)
740 authreadkeys(key_file_name);
744 * sock_hash - hash an sockaddr_storage structure
748 struct sockaddr_storage *addr
759 * We can't just hash the whole thing because there are hidden
760 * fields in sockaddr_in6 that might be filled in by recvfrom(),
761 * so just use the family, port and address.
763 ch = (char *)&addr->ss_family;
764 hashVal = 37 * hashVal + (int)*ch;
765 if (sizeof(addr->ss_family) > 1) {
767 hashVal = 37 * hashVal + (int)*ch;
769 switch(addr->ss_family) {
771 ch = (char *)&((struct sockaddr_in *)addr)->sin_addr;
772 len = sizeof(struct in_addr);
775 ch = (char *)&((struct sockaddr_in6 *)addr)->sin6_addr;
776 len = sizeof(struct in6_addr);
780 for (i = 0; i < len ; i++)
781 hashVal = 37 * hashVal + (int)*(ch + i);
783 hashVal = hashVal % 128; /* % MON_HASH_SIZE hardcoded */
793 * ntp_exit - document explicitly that ntpd has exited
798 msyslog(LOG_ERR, "EXITING with return code %d", retval);