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 rereading
43 * the keys file, but I may eventually put other things in here such as
44 * code to do something with the leap bits.
48 * Name of the keys file
50 static char *key_file_name;
53 * The name of the drift_comp file and the temporary.
55 static char *stats_drift_file;
56 static char *stats_temp_file;
59 * Statistics file stuff
63 #define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */
65 #define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */
66 #endif /* SYS_WINNT */
70 #define MAXPATHLEN 256
73 static char statsdir[MAXPATHLEN] = NTP_VAR;
75 static FILEGEN peerstats;
76 static FILEGEN loopstats;
77 static FILEGEN clockstats;
78 static FILEGEN rawstats;
81 * This controls whether stats are written to the fileset. Provided
82 * so that ntpdc can turn off stats when the file system fills up.
87 * init_util - initialize the utilities
96 #define PEERNAME "peerstats"
97 #define LOOPNAME "loopstats"
98 #define CLOCKNAME "clockstats"
99 #define RAWNAME "rawstats"
101 peerstats.prefix = &statsdir[0];
102 peerstats.basename = (char*)emalloc(strlen(PEERNAME)+1);
103 strcpy(peerstats.basename, PEERNAME);
105 peerstats.type = FILEGEN_DAY;
106 peerstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/
107 filegen_register("peerstats", &peerstats);
110 loopstats.prefix = &statsdir[0];
111 loopstats.basename = (char*)emalloc(strlen(LOOPNAME)+1);
112 strcpy(loopstats.basename, LOOPNAME);
114 loopstats.type = FILEGEN_DAY;
115 loopstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/
116 filegen_register("loopstats", &loopstats);
118 clockstats.fp = NULL;
119 clockstats.prefix = &statsdir[0];
120 clockstats.basename = (char*)emalloc(strlen(CLOCKNAME)+1);
121 strcpy(clockstats.basename, CLOCKNAME);
123 clockstats.type = FILEGEN_DAY;
124 clockstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/
125 filegen_register("clockstats", &clockstats);
128 rawstats.prefix = &statsdir[0];
129 rawstats.basename = (char*)emalloc(strlen(RAWNAME)+1);
130 strcpy(rawstats.basename, RAWNAME);
132 rawstats.type = FILEGEN_DAY;
133 rawstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/
134 filegen_register("rawstats", &rawstats);
145 * hourly_stats - print some interesting stats
163 * Sometimes having a Sun can be a drag.
165 * The kernel variable dosynctodr controls whether the system's
166 * soft clock is kept in sync with the battery clock. If it
167 * is zero, then the soft clock is not synced, and the battery
168 * clock is simply left to rot. That means that when the system
169 * reboots, the battery clock (which has probably gone wacky)
170 * sets the soft clock. That means ntpd starts off with a very
171 * confused idea of what time it is. It then takes a large
172 * amount of time to figure out just how wacky the battery clock
173 * has made things drift, etc, etc. The solution is to make the
174 * battery clock sync up to system time. The way to do THAT is
175 * to simply set the time of day to the current time of day, but
176 * as quickly as possible. This may, or may not be a sensible
179 * CAVEAT: settimeofday() steps the sun clock by about 800 us,
180 * so setting DOSYNCTODR seems a bad idea in the
181 * case of us resolution
185 /* (prr) getpriority returns -1 on error, but -1 is also a valid
186 * return value (!), so instead we have to zero errno before the call
187 * and check it for non-zero afterwards.
192 o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */
194 /* (prr) if getpriority succeeded, call setpriority to raise
195 * scheduling priority as high as possible. If that succeeds
196 * as well, set the prio_set flag so we remember to reset
197 * priority to its previous value below. Note that on Solaris 2.6
198 * (and beyond?), both getpriority and setpriority will fail with
199 * ESRCH, because sched_setscheduler (called from main) put us in
200 * the real-time scheduling class which setpriority doesn't know about.
201 * Being in the real-time class is better than anything setpriority
202 * can do, anyhow, so this error is silently ignored.
205 if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0))
206 prio_set = 1; /* overdrive */
209 (void) getclock(TIMEOFDAY, &ts);
210 tv.tv_sec = ts.tv_sec;
211 tv.tv_usec = ts.tv_nsec / 1000;
212 #else /* not HAVE_GETCLOCK */
213 GETTIMEOFDAY(&tv,(struct timezone *)NULL);
214 #endif /* not HAVE_GETCLOCK */
215 if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0)
217 msyslog(LOG_ERR, "can't sync battery time: %m");
221 setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
223 #endif /* DOSYNCTODR */
225 NLOG(NLOG_SYSSTATIST)
227 "offset %.6f sec freq %.3f ppm error %.6f poll %d",
228 last_offset, drift_comp * 1e6, sys_jitter, sys_poll);
231 if (stats_drift_file != 0) {
232 if ((fp = fopen(stats_temp_file, "w")) == NULL) {
233 msyslog(LOG_ERR, "can't open %s: %m",
237 fprintf(fp, "%.3f\n", drift_comp * 1e6);
241 (void) unlink(stats_drift_file); /* rename semantics differ under NT */
242 #endif /* SYS_WINNT */
245 (void) rename(stats_temp_file, stats_drift_file);
247 /* we have no rename NFS of ftp in use*/
248 if ((fp = fopen(stats_drift_file, "w")) == NULL) {
249 msyslog(LOG_ERR, "can't open %s: %m",
259 $DESCRIPTOR(oldvers,";-1");
260 struct dsc$descriptor driftdsc = {
261 strlen(stats_drift_file),0,0,stats_drift_file };
263 while(lib$delete_file(&oldvers,&driftdsc) & 1) ;
271 * stats_config - configure the stats operation
276 char *invalue /* only one type so far */
284 /* Expand environment strings under Windows NT, since the command
285 * interpreter doesn't do this, the program must.
288 char newvalue[MAX_PATH], parameter[MAX_PATH];
290 if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH))
293 case STATS_FREQ_FILE:
294 strcpy(parameter,"STATS_FREQ_FILE");
297 strcpy(parameter,"STATS_STATSDIR");
300 strcpy(parameter,"STATS_PID_FILE");
303 strcpy(parameter,"UNKNOWN");
309 "ExpandEnvironmentStrings(%s) failed: %m\n", parameter);
315 #endif /* SYS_WINNT */
320 case STATS_FREQ_FILE:
321 if (stats_drift_file != 0) {
322 (void) free(stats_drift_file);
323 (void) free(stats_temp_file);
324 stats_drift_file = 0;
328 if (value == 0 || (len = strlen(value)) == 0)
331 stats_drift_file = (char*)emalloc((u_int)(len + 1));
333 stats_temp_file = (char*)emalloc((u_int)(len + sizeof(".TEMP")));
335 stats_temp_file = (char*)emalloc((u_int)(len + sizeof("-TEMP")));
337 memmove(stats_drift_file, value, (unsigned)(len+1));
338 memmove(stats_temp_file, value, (unsigned)len);
340 memmove(stats_temp_file + len, ".TEMP", sizeof(".TEMP"));
342 memmove(stats_temp_file + len, "-TEMP", sizeof("-TEMP"));
346 * Open drift file and read frequency
348 if ((fp = fopen(stats_drift_file, "r")) == NULL) {
351 if (fscanf(fp, "%lf", &old_drift) != 1) {
352 msyslog(LOG_ERR, "Un-parsable frequency in %s",
361 #else /* not HAVE_FINITE */
362 # ifdef HAVE_ISFINITE
364 # else /* not HAVE_ISFINITE */
366 # endif /* not HAVE_ISFINITE */
367 #endif /* not HAVE_FINITE */
368 || (fabs(old_drift) > (NTP_MAXFREQ * 1e6))) {
369 msyslog(LOG_ERR, "invalid frequency (%f) in %s",
370 old_drift, stats_drift_file);
373 msyslog(LOG_INFO, "frequency initialized %.3f from %s",
374 old_drift, stats_drift_file);
375 loop_config(LOOP_DRIFTCOMP, old_drift / 1e6);
379 if (strlen(value) >= sizeof(statsdir)) {
381 "value for statsdir too long (>%d, sigh)",
382 (int)sizeof(statsdir)-1);
387 strcpy(statsdir,value);
388 if(peerstats.prefix == &statsdir[0] &&
389 peerstats.fp != NULL) {
390 fclose(peerstats.fp);
392 filegen_setup(&peerstats, now.l_ui);
394 if(loopstats.prefix == &statsdir[0] &&
395 loopstats.fp != NULL) {
396 fclose(loopstats.fp);
398 filegen_setup(&loopstats, now.l_ui);
400 if(clockstats.prefix == &statsdir[0] &&
401 clockstats.fp != NULL) {
402 fclose(clockstats.fp);
403 clockstats.fp = NULL;
404 filegen_setup(&clockstats, now.l_ui);
406 if(rawstats.prefix == &statsdir[0] &&
407 rawstats.fp != NULL) {
410 filegen_setup(&rawstats, now.l_ui);
416 if ((fp = fopen(value, "w")) == NULL) {
417 msyslog(LOG_ERR, "Can't open %s: %m", value);
420 fprintf(fp, "%d", (int) getpid());
431 * record_peer_stats - write peer statistics to file
435 * time (s past UTC midnight)
437 * peer status word (hex)
440 * peer error bound (s)
445 struct sockaddr_in *addr,
457 u_long day, sec, msec;
462 (void) getclock(TIMEOFDAY, &ts);
463 tv.tv_sec = ts.tv_sec;
464 tv.tv_usec = ts.tv_nsec / 1000;
465 #else /* not HAVE_GETCLOCK */
466 GETTIMEOFDAY(&tv, (struct timezone *)NULL);
467 #endif /* not HAVE_GETCLOCK */
468 day = tv.tv_sec / 86400 + MJD_1970;
469 sec = tv.tv_sec % 86400;
470 msec = tv.tv_usec / 1000;
472 filegen_setup(&peerstats, (u_long)(tv.tv_sec + JAN_1970));
473 if (peerstats.fp != NULL) {
474 fprintf(peerstats.fp,
475 "%lu %lu.%03lu %s %x %.9f %.9f %.9f %.9f\n",
476 day, sec, msec, ntoa(addr), status, offset,
477 delay, dispersion, skew);
478 fflush(peerstats.fp);
482 * record_loop_stats - write loop filter statistics to file
486 * time (s past midnight)
488 * frequency (approx ppm)
489 * time constant (log base 2)
504 u_long day, sec, msec;
509 (void) getclock(TIMEOFDAY, &ts);
510 tv.tv_sec = ts.tv_sec;
511 tv.tv_usec = ts.tv_nsec / 1000;
512 #else /* not HAVE_GETCLOCK */
513 GETTIMEOFDAY(&tv, (struct timezone *)NULL);
514 #endif /* not HAVE_GETCLOCK */
515 day = tv.tv_sec / 86400 + MJD_1970;
516 sec = tv.tv_sec % 86400;
517 msec = tv.tv_usec / 1000;
519 filegen_setup(&loopstats, (u_long)(tv.tv_sec + JAN_1970));
520 if (loopstats.fp != NULL) {
521 fprintf(loopstats.fp, "%lu %lu.%03lu %.9f %.6f %.9f %.6f %d\n",
522 day, sec, msec, offset, freq * 1e6, jitter,
523 stability * 1e6, poll);
524 fflush(loopstats.fp);
529 * record_clock_stats - write clock statistics to file
533 * time (s past midnight)
539 struct sockaddr_in *addr,
547 u_long day, sec, msec;
552 (void) getclock(TIMEOFDAY, &ts);
553 tv.tv_sec = ts.tv_sec;
554 tv.tv_usec = ts.tv_nsec / 1000;
555 #else /* not HAVE_GETCLOCK */
556 GETTIMEOFDAY(&tv, (struct timezone *)NULL);
557 #endif /* not HAVE_GETCLOCK */
558 day = tv.tv_sec / 86400 + MJD_1970;
559 sec = tv.tv_sec % 86400;
560 msec = tv.tv_usec / 1000;
562 filegen_setup(&clockstats, (u_long)(tv.tv_sec + JAN_1970));
563 if (clockstats.fp != NULL) {
564 fprintf(clockstats.fp, "%lu %lu.%03lu %s %s\n",
565 day, sec, msec, ntoa(addr), text);
566 fflush(clockstats.fp);
571 * record_raw_stats - write raw timestamps to file
575 * time (s past midnight)
578 * t1 t2 t3 t4 timestamps
582 struct sockaddr_in *srcadr,
583 struct sockaddr_in *dstadr,
594 u_long day, sec, msec;
599 (void) getclock(TIMEOFDAY, &ts);
600 tv.tv_sec = ts.tv_sec;
601 tv.tv_usec = ts.tv_nsec / 1000;
602 #else /* not HAVE_GETCLOCK */
603 GETTIMEOFDAY(&tv, (struct timezone *)NULL);
604 #endif /* not HAVE_GETCLOCK */
605 day = tv.tv_sec / 86400 + MJD_1970;
606 sec = tv.tv_sec % 86400;
607 msec = tv.tv_usec / 1000;
609 filegen_setup(&rawstats, (u_long)(tv.tv_sec + JAN_1970));
610 if (rawstats.fp != NULL) {
611 fprintf(rawstats.fp, "%lu %lu.%03lu %s %s %s %s %s %s\n",
612 day, sec, msec, ntoa(srcadr), ntoa(dstadr),
613 ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9),
620 * getauthkeys - read the authentication keys from the specified file
629 len = strlen(keyfile);
633 if (key_file_name != 0) {
634 if (len > (int)strlen(key_file_name)) {
635 (void) free(key_file_name);
640 if (key_file_name == 0) {
642 key_file_name = (char*)emalloc((u_int) (len + 1));
644 key_file_name = (char*)emalloc((u_int) (MAXPATHLEN));
648 memmove(key_file_name, keyfile, (unsigned)(len+1));
650 if (!ExpandEnvironmentStrings(keyfile, key_file_name, MAXPATHLEN))
653 "ExpandEnvironmentStrings(KEY_FILE) failed: %m\n");
655 #endif /* SYS_WINNT */
657 authreadkeys(key_file_name);
662 * rereadkeys - read the authentication key file over again.
667 if (key_file_name != 0)
668 authreadkeys(key_file_name);