/src/ntp-dev/ntpd/ntp_util.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * ntp_util.c - stuff I didn't have any other place for |
3 | | */ |
4 | | #ifdef HAVE_CONFIG_H |
5 | | # include <config.h> |
6 | | #endif |
7 | | |
8 | | #include "ntpd.h" |
9 | | #include "ntp_unixtime.h" |
10 | | #include "ntp_filegen.h" |
11 | | #include "ntp_if.h" |
12 | | #include "ntp_stdlib.h" |
13 | | #include "ntp_assert.h" |
14 | | #include "ntp_calendar.h" |
15 | | #include "ntp_leapsec.h" |
16 | | #include "lib_strbuf.h" |
17 | | |
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 |
24 | | #ifdef HAVE_UNISTD_H |
25 | | # include <unistd.h> |
26 | | #endif |
27 | | #include <sys/stat.h> |
28 | | |
29 | | #ifdef HAVE_IEEEFP_H |
30 | | # include <ieeefp.h> |
31 | | #endif |
32 | | #ifdef HAVE_MATH_H |
33 | | # include <math.h> |
34 | | #endif |
35 | | |
36 | | #if defined(VMS) |
37 | | # include <descrip.h> |
38 | | #endif /* VMS */ |
39 | | |
40 | | /* |
41 | | * Defines used by the leapseconds stuff |
42 | | */ |
43 | | #define MAX_TAI 100 /* max TAI offset (s) */ |
44 | | #define L_DAY 86400UL /* seconds per day */ |
45 | | #define L_YEAR (L_DAY * 365) /* days per year */ |
46 | | #define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */ |
47 | | #define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */ |
48 | | #define L_CENT (L_4YEAR * 25) /* days per century */ |
49 | | |
50 | | /* |
51 | | * This contains odds and ends, including the hourly stats, various |
52 | | * configuration items, leapseconds stuff, etc. |
53 | | */ |
54 | | /* |
55 | | * File names |
56 | | */ |
57 | | static char *key_file_name; /* keys file name */ |
58 | | static char *leapfile_name; /* leapseconds file name */ |
59 | | static struct stat leapfile_stat; /* leapseconds file stat() buffer */ |
60 | | static int /*BOOL*/have_leapfile = FALSE; |
61 | | char *stats_drift_file; /* frequency file name */ |
62 | | static char *stats_temp_file; /* temp frequency file name */ |
63 | | static double wander_resid; /* last frequency update */ |
64 | | double wander_threshold = 1e-7; /* initial frequency threshold */ |
65 | | |
66 | | /* |
67 | | * Statistics file stuff |
68 | | */ |
69 | | #ifndef NTP_VAR |
70 | | # ifndef SYS_WINNT |
71 | | # define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ |
72 | | # else |
73 | | # define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ |
74 | | # endif /* SYS_WINNT */ |
75 | | #endif |
76 | | |
77 | | |
78 | | char statsdir[MAXFILENAME] = NTP_VAR; |
79 | | static FILEGEN peerstats; |
80 | | static FILEGEN loopstats; |
81 | | static FILEGEN clockstats; |
82 | | static FILEGEN rawstats; |
83 | | static FILEGEN sysstats; |
84 | | static FILEGEN protostats; |
85 | | static FILEGEN cryptostats; |
86 | | static FILEGEN timingstats; |
87 | | |
88 | | /* |
89 | | * This controls whether stats are written to the fileset. Provided |
90 | | * so that ntpdc can turn off stats when the file system fills up. |
91 | | */ |
92 | | int stats_control; |
93 | | |
94 | | /* |
95 | | * Last frequency written to file. |
96 | | */ |
97 | | static double prev_drift_comp; /* last frequency update */ |
98 | | |
99 | | /* |
100 | | * Function prototypes |
101 | | */ |
102 | | static void record_sys_stats(void); |
103 | | void ntpd_time_stepped(void); |
104 | | static void check_leap_expiration(int, uint32_t, const time_t*); |
105 | | |
106 | | /* |
107 | | * Prototypes |
108 | | */ |
109 | | #ifdef DEBUG |
110 | | void uninit_util(void); |
111 | | #endif |
112 | | |
113 | | /* |
114 | | * uninit_util - free memory allocated by init_util |
115 | | */ |
116 | | #ifdef DEBUG |
117 | | void |
118 | | uninit_util(void) |
119 | 1 | { |
120 | | #if defined(_MSC_VER) && defined (_DEBUG) |
121 | | _CrtCheckMemory(); |
122 | | #endif |
123 | 1 | if (stats_drift_file) { |
124 | 0 | free(stats_drift_file); |
125 | 0 | free(stats_temp_file); |
126 | 0 | stats_drift_file = NULL; |
127 | 0 | stats_temp_file = NULL; |
128 | 0 | } |
129 | 1 | if (key_file_name) { |
130 | 0 | free(key_file_name); |
131 | 0 | key_file_name = NULL; |
132 | 0 | } |
133 | 1 | filegen_unregister("peerstats"); |
134 | 1 | filegen_unregister("loopstats"); |
135 | 1 | filegen_unregister("clockstats"); |
136 | 1 | filegen_unregister("rawstats"); |
137 | 1 | filegen_unregister("sysstats"); |
138 | 1 | filegen_unregister("protostats"); |
139 | | #ifdef AUTOKEY |
140 | | filegen_unregister("cryptostats"); |
141 | | #endif /* AUTOKEY */ |
142 | | #ifdef DEBUG_TIMING |
143 | | filegen_unregister("timingstats"); |
144 | | #endif /* DEBUG_TIMING */ |
145 | | |
146 | | #if defined(_MSC_VER) && defined (_DEBUG) |
147 | | _CrtCheckMemory(); |
148 | | #endif |
149 | 1 | } |
150 | | #endif /* DEBUG */ |
151 | | |
152 | | |
153 | | /* |
154 | | * init_util - initialize the util module of ntpd |
155 | | */ |
156 | | void |
157 | | init_util(void) |
158 | 1 | { |
159 | 1 | filegen_register(statsdir, "peerstats", &peerstats); |
160 | 1 | filegen_register(statsdir, "loopstats", &loopstats); |
161 | 1 | filegen_register(statsdir, "clockstats", &clockstats); |
162 | 1 | filegen_register(statsdir, "rawstats", &rawstats); |
163 | 1 | filegen_register(statsdir, "sysstats", &sysstats); |
164 | 1 | filegen_register(statsdir, "protostats", &protostats); |
165 | 1 | filegen_register(statsdir, "cryptostats", &cryptostats); |
166 | 1 | filegen_register(statsdir, "timingstats", &timingstats); |
167 | | /* |
168 | | * register with libntp ntp_set_tod() to call us back |
169 | | * when time is stepped. |
170 | | */ |
171 | 1 | step_callback = &ntpd_time_stepped; |
172 | 1 | #ifdef DEBUG |
173 | 1 | atexit(&uninit_util); |
174 | 1 | #endif /* DEBUG */ |
175 | 1 | } |
176 | | |
177 | | |
178 | | /* |
179 | | * hourly_stats - print some interesting stats |
180 | | */ |
181 | | void |
182 | | write_stats(void) |
183 | 0 | { |
184 | 0 | FILE *fp; |
185 | | #ifdef DOSYNCTODR |
186 | | struct timeval tv; |
187 | | #if !defined(VMS) |
188 | | int prio_set; |
189 | | #endif |
190 | | #ifdef HAVE_GETCLOCK |
191 | | struct timespec ts; |
192 | | #endif |
193 | | int o_prio; |
194 | | |
195 | | /* |
196 | | * Sometimes having a Sun can be a drag. |
197 | | * |
198 | | * The kernel variable dosynctodr controls whether the system's |
199 | | * soft clock is kept in sync with the battery clock. If it |
200 | | * is zero, then the soft clock is not synced, and the battery |
201 | | * clock is simply left to rot. That means that when the system |
202 | | * reboots, the battery clock (which has probably gone wacky) |
203 | | * sets the soft clock. That means ntpd starts off with a very |
204 | | * confused idea of what time it is. It then takes a large |
205 | | * amount of time to figure out just how wacky the battery clock |
206 | | * has made things drift, etc, etc. The solution is to make the |
207 | | * battery clock sync up to system time. The way to do THAT is |
208 | | * to simply set the time of day to the current time of day, but |
209 | | * as quickly as possible. This may, or may not be a sensible |
210 | | * thing to do. |
211 | | * |
212 | | * CAVEAT: settimeofday() steps the sun clock by about 800 us, |
213 | | * so setting DOSYNCTODR seems a bad idea in the |
214 | | * case of us resolution |
215 | | */ |
216 | | |
217 | | #if !defined(VMS) |
218 | | /* |
219 | | * (prr) getpriority returns -1 on error, but -1 is also a valid |
220 | | * return value (!), so instead we have to zero errno before the |
221 | | * call and check it for non-zero afterwards. |
222 | | */ |
223 | | errno = 0; |
224 | | prio_set = 0; |
225 | | o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ |
226 | | |
227 | | /* |
228 | | * (prr) if getpriority succeeded, call setpriority to raise |
229 | | * scheduling priority as high as possible. If that succeeds |
230 | | * as well, set the prio_set flag so we remember to reset |
231 | | * priority to its previous value below. Note that on Solaris |
232 | | * 2.6 (and beyond?), both getpriority and setpriority will fail |
233 | | * with ESRCH, because sched_setscheduler (called from main) put |
234 | | * us in the real-time scheduling class which setpriority |
235 | | * doesn't know about. Being in the real-time class is better |
236 | | * than anything setpriority can do, anyhow, so this error is |
237 | | * silently ignored. |
238 | | */ |
239 | | if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) |
240 | | prio_set = 1; /* overdrive */ |
241 | | #endif /* VMS */ |
242 | | #ifdef HAVE_GETCLOCK |
243 | | (void) getclock(TIMEOFDAY, &ts); |
244 | | tv.tv_sec = ts.tv_sec; |
245 | | tv.tv_usec = ts.tv_nsec / 1000; |
246 | | #else /* not HAVE_GETCLOCK */ |
247 | | GETTIMEOFDAY(&tv,(struct timezone *)NULL); |
248 | | #endif /* not HAVE_GETCLOCK */ |
249 | | if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) |
250 | | msyslog(LOG_ERR, "can't sync battery time: %m"); |
251 | | #if !defined(VMS) |
252 | | if (prio_set) |
253 | | setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ |
254 | | #endif /* VMS */ |
255 | | #endif /* DOSYNCTODR */ |
256 | 0 | record_sys_stats(); |
257 | 0 | if (stats_drift_file != 0) { |
258 | | |
259 | | /* |
260 | | * When the frequency file is written, initialize the |
261 | | * prev_drift_comp and wander_resid. Thereafter, |
262 | | * reduce the wander_resid by half each hour. When |
263 | | * the difference between the prev_drift_comp and |
264 | | * drift_comp is less than the wander_resid, update |
265 | | * the frequncy file. This minimizes the file writes to |
266 | | * nonvolaile storage. |
267 | | */ |
268 | 0 | #ifdef DEBUG |
269 | 0 | if (debug) |
270 | 0 | printf("write_stats: frequency %.6lf thresh %.6lf, freq %.6lf\n", |
271 | 0 | (prev_drift_comp - drift_comp) * 1e6, wander_resid * |
272 | 0 | 1e6, drift_comp * 1e6); |
273 | 0 | #endif |
274 | 0 | if (fabs(prev_drift_comp - drift_comp) < wander_resid) { |
275 | 0 | wander_resid *= 0.5; |
276 | 0 | return; |
277 | 0 | } |
278 | 0 | prev_drift_comp = drift_comp; |
279 | 0 | wander_resid = wander_threshold; |
280 | 0 | if ((fp = fopen(stats_temp_file, "w")) == NULL) { |
281 | 0 | msyslog(LOG_ERR, "frequency file %s: %m", |
282 | 0 | stats_temp_file); |
283 | 0 | return; |
284 | 0 | } |
285 | 0 | fprintf(fp, "%.3f\n", drift_comp * 1e6); |
286 | 0 | (void)fclose(fp); |
287 | | /* atomic */ |
288 | | #ifdef SYS_WINNT |
289 | | if (_unlink(stats_drift_file)) /* rename semantics differ under NT */ |
290 | | msyslog(LOG_WARNING, |
291 | | "Unable to remove prior drift file %s, %m", |
292 | | stats_drift_file); |
293 | | #endif /* SYS_WINNT */ |
294 | |
|
295 | 0 | #ifndef NO_RENAME |
296 | 0 | if (rename(stats_temp_file, stats_drift_file)) |
297 | 0 | msyslog(LOG_WARNING, |
298 | 0 | "Unable to rename temp drift file %s to %s, %m", |
299 | 0 | stats_temp_file, stats_drift_file); |
300 | | #else |
301 | | /* we have no rename NFS of ftp in use */ |
302 | | if ((fp = fopen(stats_drift_file, "w")) == |
303 | | NULL) { |
304 | | msyslog(LOG_ERR, |
305 | | "frequency file %s: %m", |
306 | | stats_drift_file); |
307 | | return; |
308 | | } |
309 | | #endif |
310 | |
|
311 | | #if defined(VMS) |
312 | | /* PURGE */ |
313 | | { |
314 | | $DESCRIPTOR(oldvers,";-1"); |
315 | | struct dsc$descriptor driftdsc = { |
316 | | strlen(stats_drift_file), 0, 0, |
317 | | stats_drift_file }; |
318 | | while(lib$delete_file(&oldvers, |
319 | | &driftdsc) & 1); |
320 | | } |
321 | | #endif |
322 | 0 | } |
323 | 0 | } |
324 | | |
325 | | |
326 | | /* |
327 | | * stats_config - configure the stats operation |
328 | | */ |
329 | | void |
330 | | stats_config( |
331 | | int item, |
332 | | const char *invalue /* only one type so far */ |
333 | | ) |
334 | 0 | { |
335 | 0 | FILE *fp; |
336 | 0 | const char *value; |
337 | 0 | size_t len; |
338 | 0 | double old_drift; |
339 | 0 | l_fp now; |
340 | 0 | time_t ttnow; |
341 | 0 | #ifndef VMS |
342 | 0 | const char temp_ext[] = ".TEMP"; |
343 | | #else |
344 | | const char temp_ext[] = "-TEMP"; |
345 | | #endif |
346 | | |
347 | | /* |
348 | | * Expand environment strings under Windows NT, since the |
349 | | * command interpreter doesn't do this, the program must. |
350 | | */ |
351 | | #ifdef SYS_WINNT |
352 | | char newvalue[MAX_PATH], parameter[MAX_PATH]; |
353 | | |
354 | | if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { |
355 | | switch (item) { |
356 | | case STATS_FREQ_FILE: |
357 | | strlcpy(parameter, "STATS_FREQ_FILE", |
358 | | sizeof(parameter)); |
359 | | break; |
360 | | |
361 | | case STATS_LEAP_FILE: |
362 | | strlcpy(parameter, "STATS_LEAP_FILE", |
363 | | sizeof(parameter)); |
364 | | break; |
365 | | |
366 | | case STATS_STATSDIR: |
367 | | strlcpy(parameter, "STATS_STATSDIR", |
368 | | sizeof(parameter)); |
369 | | break; |
370 | | |
371 | | case STATS_PID_FILE: |
372 | | strlcpy(parameter, "STATS_PID_FILE", |
373 | | sizeof(parameter)); |
374 | | break; |
375 | | |
376 | | default: |
377 | | strlcpy(parameter, "UNKNOWN", |
378 | | sizeof(parameter)); |
379 | | break; |
380 | | } |
381 | | value = invalue; |
382 | | msyslog(LOG_ERR, |
383 | | "ExpandEnvironmentStrings(%s) failed: %m\n", |
384 | | parameter); |
385 | | } else { |
386 | | value = newvalue; |
387 | | } |
388 | | #else |
389 | 0 | value = invalue; |
390 | 0 | #endif /* SYS_WINNT */ |
391 | |
|
392 | 0 | switch (item) { |
393 | | |
394 | | /* |
395 | | * Open and read frequency file. |
396 | | */ |
397 | 0 | case STATS_FREQ_FILE: |
398 | 0 | if (!value || (len = strlen(value)) == 0) |
399 | 0 | break; |
400 | | |
401 | 0 | stats_drift_file = erealloc(stats_drift_file, len + 1); |
402 | 0 | stats_temp_file = erealloc(stats_temp_file, |
403 | 0 | len + sizeof(".TEMP")); |
404 | 0 | memcpy(stats_drift_file, value, (size_t)(len+1)); |
405 | 0 | memcpy(stats_temp_file, value, (size_t)len); |
406 | 0 | memcpy(stats_temp_file + len, temp_ext, sizeof(temp_ext)); |
407 | | |
408 | | /* |
409 | | * Open drift file and read frequency. If the file is |
410 | | * missing or contains errors, tell the loop to reset. |
411 | | */ |
412 | 0 | if ((fp = fopen(stats_drift_file, "r")) == NULL) |
413 | 0 | break; |
414 | | |
415 | 0 | if (fscanf(fp, "%lf", &old_drift) != 1) { |
416 | 0 | msyslog(LOG_ERR, |
417 | 0 | "format error frequency file %s", |
418 | 0 | stats_drift_file); |
419 | 0 | fclose(fp); |
420 | 0 | break; |
421 | |
|
422 | 0 | } |
423 | 0 | fclose(fp); |
424 | 0 | loop_config(LOOP_FREQ, old_drift); |
425 | 0 | prev_drift_comp = drift_comp; |
426 | 0 | break; |
427 | | |
428 | | /* |
429 | | * Specify statistics directory. |
430 | | */ |
431 | 0 | case STATS_STATSDIR: |
432 | | |
433 | | /* - 1 since value may be missing the DIR_SEP. */ |
434 | 0 | if (strlen(value) >= sizeof(statsdir) - 1) { |
435 | 0 | msyslog(LOG_ERR, |
436 | 0 | "statsdir too long (>%d, sigh)", |
437 | 0 | (int)sizeof(statsdir) - 2); |
438 | 0 | } else { |
439 | 0 | int add_dir_sep; |
440 | 0 | size_t value_l; |
441 | | |
442 | | /* Add a DIR_SEP unless we already have one. */ |
443 | 0 | value_l = strlen(value); |
444 | 0 | if (0 == value_l) |
445 | 0 | add_dir_sep = FALSE; |
446 | 0 | else |
447 | 0 | add_dir_sep = (DIR_SEP != |
448 | 0 | value[value_l - 1]); |
449 | |
|
450 | 0 | if (add_dir_sep) |
451 | 0 | snprintf(statsdir, sizeof(statsdir), |
452 | 0 | "%s%c", value, DIR_SEP); |
453 | 0 | else |
454 | 0 | snprintf(statsdir, sizeof(statsdir), |
455 | 0 | "%s", value); |
456 | 0 | filegen_statsdir(); |
457 | 0 | } |
458 | 0 | break; |
459 | | |
460 | | /* |
461 | | * Open pid file. |
462 | | */ |
463 | 0 | case STATS_PID_FILE: |
464 | 0 | if ((fp = fopen(value, "w")) == NULL) { |
465 | 0 | msyslog(LOG_ERR, "pid file %s: %m", |
466 | 0 | value); |
467 | 0 | break; |
468 | 0 | } |
469 | 0 | fprintf(fp, "%d", (int)getpid()); |
470 | 0 | fclose(fp); |
471 | 0 | break; |
472 | | |
473 | | /* |
474 | | * Read leapseconds file. |
475 | | * |
476 | | * Note: Currently a leap file without SHA1 signature is |
477 | | * accepted, but if there is a signature line, the signature |
478 | | * must be valid or the file is rejected. |
479 | | */ |
480 | 0 | case STATS_LEAP_FILE: |
481 | 0 | if (!value || (len = strlen(value)) == 0) |
482 | 0 | break; |
483 | | |
484 | 0 | leapfile_name = erealloc(leapfile_name, len + 1); |
485 | 0 | memcpy(leapfile_name, value, len + 1); |
486 | |
|
487 | 0 | if (leapsec_load_file( |
488 | 0 | leapfile_name, &leapfile_stat, TRUE, TRUE)) |
489 | 0 | { |
490 | 0 | leap_signature_t lsig; |
491 | |
|
492 | 0 | get_systime(&now); |
493 | 0 | time(&ttnow); |
494 | 0 | leapsec_getsig(&lsig); |
495 | 0 | mprintf_event(EVNT_TAI, NULL, |
496 | 0 | "%d leap %s %s %s", |
497 | 0 | lsig.taiof, |
498 | 0 | fstostr(lsig.ttime), |
499 | 0 | leapsec_expired(now.l_ui, NULL) |
500 | 0 | ? "expired" |
501 | 0 | : "expires", |
502 | 0 | fstostr(lsig.etime)); |
503 | |
|
504 | 0 | have_leapfile = TRUE; |
505 | | |
506 | | /* force an immediate daily expiration check of |
507 | | * the leap seconds table |
508 | | */ |
509 | 0 | check_leap_expiration(TRUE, now.l_ui, &ttnow); |
510 | 0 | } |
511 | 0 | break; |
512 | | |
513 | 0 | default: |
514 | | /* oh well */ |
515 | 0 | break; |
516 | 0 | } |
517 | 0 | } |
518 | | |
519 | | |
520 | | /* |
521 | | * record_peer_stats - write peer statistics to file |
522 | | * |
523 | | * file format: |
524 | | * day (MJD) |
525 | | * time (s past UTC midnight) |
526 | | * IP address |
527 | | * status word (hex) |
528 | | * offset |
529 | | * delay |
530 | | * dispersion |
531 | | * jitter |
532 | | */ |
533 | | void |
534 | | record_peer_stats( |
535 | | sockaddr_u *addr, |
536 | | int status, |
537 | | double offset, /* offset */ |
538 | | double delay, /* delay */ |
539 | | double dispersion, /* dispersion */ |
540 | | double jitter /* jitter */ |
541 | | ) |
542 | 0 | { |
543 | 0 | l_fp now; |
544 | 0 | u_long day; |
545 | |
|
546 | 0 | if (!stats_control) |
547 | 0 | return; |
548 | | |
549 | 0 | get_systime(&now); |
550 | 0 | filegen_setup(&peerstats, now.l_ui); |
551 | 0 | day = now.l_ui / 86400 + MJD_1900; |
552 | 0 | now.l_ui %= 86400; |
553 | 0 | if (peerstats.fp != NULL) { |
554 | 0 | fprintf(peerstats.fp, |
555 | 0 | "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, |
556 | 0 | ulfptoa(&now, 3), stoa(addr), status, offset, |
557 | 0 | delay, dispersion, jitter); |
558 | 0 | fflush(peerstats.fp); |
559 | 0 | } |
560 | 0 | } |
561 | | |
562 | | |
563 | | /* |
564 | | * record_loop_stats - write loop filter statistics to file |
565 | | * |
566 | | * file format: |
567 | | * day (MJD) |
568 | | * time (s past midnight) |
569 | | * offset |
570 | | * frequency (PPM) |
571 | | * jitter |
572 | | * wnder (PPM) |
573 | | * time constant (log2) |
574 | | */ |
575 | | void |
576 | | record_loop_stats( |
577 | | double offset, /* offset */ |
578 | | double freq, /* frequency (PPM) */ |
579 | | double jitter, /* jitter */ |
580 | | double wander, /* wander (PPM) */ |
581 | | int spoll |
582 | | ) |
583 | 0 | { |
584 | 0 | l_fp now; |
585 | 0 | u_long day; |
586 | |
|
587 | 0 | if (!stats_control) |
588 | 0 | return; |
589 | | |
590 | 0 | get_systime(&now); |
591 | 0 | filegen_setup(&loopstats, now.l_ui); |
592 | 0 | day = now.l_ui / 86400 + MJD_1900; |
593 | 0 | now.l_ui %= 86400; |
594 | 0 | if (loopstats.fp != NULL) { |
595 | 0 | fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", |
596 | 0 | day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, |
597 | 0 | wander * 1e6, spoll); |
598 | 0 | fflush(loopstats.fp); |
599 | 0 | } |
600 | 0 | } |
601 | | |
602 | | |
603 | | /* |
604 | | * record_clock_stats - write clock statistics to file |
605 | | * |
606 | | * file format: |
607 | | * day (MJD) |
608 | | * time (s past midnight) |
609 | | * IP address |
610 | | * text message |
611 | | */ |
612 | | void |
613 | | record_clock_stats( |
614 | | sockaddr_u *addr, |
615 | | const char *text /* timecode string */ |
616 | | ) |
617 | 0 | { |
618 | 0 | l_fp now; |
619 | 0 | u_long day; |
620 | |
|
621 | 0 | if (!stats_control) |
622 | 0 | return; |
623 | | |
624 | 0 | get_systime(&now); |
625 | 0 | filegen_setup(&clockstats, now.l_ui); |
626 | 0 | day = now.l_ui / 86400 + MJD_1900; |
627 | 0 | now.l_ui %= 86400; |
628 | 0 | if (clockstats.fp != NULL) { |
629 | 0 | fprintf(clockstats.fp, "%lu %s %s %s\n", day, |
630 | 0 | ulfptoa(&now, 3), stoa(addr), text); |
631 | 0 | fflush(clockstats.fp); |
632 | 0 | } |
633 | 0 | } |
634 | | |
635 | | |
636 | | /* |
637 | | * mprintf_clock_stats - write clock statistics to file with |
638 | | * msnprintf-style formatting. |
639 | | */ |
640 | | int |
641 | | mprintf_clock_stats( |
642 | | sockaddr_u *addr, |
643 | | const char *fmt, |
644 | | ... |
645 | | ) |
646 | 0 | { |
647 | 0 | va_list ap; |
648 | 0 | int rc; |
649 | 0 | char msg[512]; |
650 | |
|
651 | 0 | va_start(ap, fmt); |
652 | 0 | rc = mvsnprintf(msg, sizeof(msg), fmt, ap); |
653 | 0 | va_end(ap); |
654 | 0 | if (stats_control) |
655 | 0 | record_clock_stats(addr, msg); |
656 | |
|
657 | 0 | return rc; |
658 | 0 | } |
659 | | |
660 | | /* |
661 | | * record_raw_stats - write raw timestamps to file |
662 | | * |
663 | | * file format |
664 | | * day (MJD) |
665 | | * time (s past midnight) |
666 | | * peer ip address |
667 | | * IP address |
668 | | * t1 t2 t3 t4 timestamps |
669 | | * leap, version, mode, stratum, ppoll, precision, root delay, root dispersion, REFID |
670 | | * length and hex dump of any EFs and any legacy MAC. |
671 | | */ |
672 | | void |
673 | | record_raw_stats( |
674 | | sockaddr_u *srcadr, |
675 | | sockaddr_u *dstadr, |
676 | | l_fp *t1, /* originate timestamp */ |
677 | | l_fp *t2, /* receive timestamp */ |
678 | | l_fp *t3, /* transmit timestamp */ |
679 | | l_fp *t4, /* destination timestamp */ |
680 | | int leap, |
681 | | int version, |
682 | | int mode, |
683 | | int stratum, |
684 | | int ppoll, |
685 | | int precision, |
686 | | double root_delay, /* seconds */ |
687 | | double root_dispersion,/* seconds */ |
688 | | u_int32 refid, |
689 | | int len, |
690 | | u_char *extra |
691 | | ) |
692 | 724 | { |
693 | 724 | l_fp now; |
694 | 724 | u_long day; |
695 | | |
696 | 724 | if (!stats_control) |
697 | 0 | return; |
698 | | |
699 | 724 | get_systime(&now); |
700 | 724 | filegen_setup(&rawstats, now.l_ui); |
701 | 724 | day = now.l_ui / 86400 + MJD_1900; |
702 | 724 | now.l_ui %= 86400; |
703 | 724 | if (rawstats.fp != NULL) { |
704 | 0 | fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s", |
705 | 0 | day, ulfptoa(&now, 3), |
706 | 0 | srcadr ? stoa(srcadr) : "-", |
707 | 0 | dstadr ? stoa(dstadr) : "-", |
708 | 0 | ulfptoa(t1, 9), ulfptoa(t2, 9), |
709 | 0 | ulfptoa(t3, 9), ulfptoa(t4, 9), |
710 | 0 | leap, version, mode, stratum, ppoll, precision, |
711 | 0 | root_delay, root_dispersion, refid_str(refid, stratum)); |
712 | 0 | if (len > 0) { |
713 | 0 | int i; |
714 | |
|
715 | 0 | fprintf(rawstats.fp, " %d: ", len); |
716 | 0 | for (i = 0; i < len; ++i) { |
717 | 0 | fprintf(rawstats.fp, "%02x", extra[i]); |
718 | 0 | } |
719 | 0 | } |
720 | 0 | fprintf(rawstats.fp, "\n"); |
721 | 0 | fflush(rawstats.fp); |
722 | 0 | } |
723 | 724 | } |
724 | | |
725 | | |
726 | | /* |
727 | | * record_sys_stats - write system statistics to file |
728 | | * |
729 | | * file format |
730 | | * day (MJD) |
731 | | * time (s past midnight) |
732 | | * time since reset |
733 | | * packets recieved |
734 | | * packets for this host |
735 | | * current version |
736 | | * old version |
737 | | * access denied |
738 | | * bad length or format |
739 | | * bad authentication |
740 | | * declined |
741 | | * rate exceeded |
742 | | * KoD sent |
743 | | */ |
744 | | void |
745 | | record_sys_stats(void) |
746 | 0 | { |
747 | 0 | l_fp now; |
748 | 0 | u_long day; |
749 | |
|
750 | 0 | if (!stats_control) |
751 | 0 | return; |
752 | | |
753 | 0 | get_systime(&now); |
754 | 0 | filegen_setup(&sysstats, now.l_ui); |
755 | 0 | day = now.l_ui / 86400 + MJD_1900; |
756 | 0 | now.l_ui %= 86400; |
757 | 0 | if (sysstats.fp != NULL) { |
758 | 0 | fprintf(sysstats.fp, |
759 | 0 | "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", |
760 | 0 | day, ulfptoa(&now, 3), current_time - sys_stattime, |
761 | 0 | sys_received, sys_processed, sys_newversion, |
762 | 0 | sys_oldversion, sys_restricted, sys_badlength, |
763 | 0 | sys_badauth, sys_declined, sys_limitrejected, |
764 | 0 | sys_kodsent); |
765 | 0 | fflush(sysstats.fp); |
766 | 0 | proto_clr_stats(); |
767 | 0 | } |
768 | 0 | } |
769 | | |
770 | | |
771 | | /* |
772 | | * record_proto_stats - write system statistics to file |
773 | | * |
774 | | * file format |
775 | | * day (MJD) |
776 | | * time (s past midnight) |
777 | | * text message |
778 | | */ |
779 | | void |
780 | | record_proto_stats( |
781 | | char *str /* text string */ |
782 | | ) |
783 | 15 | { |
784 | 15 | l_fp now; |
785 | 15 | u_long day; |
786 | | |
787 | 15 | if (!stats_control) |
788 | 0 | return; |
789 | | |
790 | 15 | get_systime(&now); |
791 | 15 | filegen_setup(&protostats, now.l_ui); |
792 | 15 | day = now.l_ui / 86400 + MJD_1900; |
793 | 15 | now.l_ui %= 86400; |
794 | 15 | if (protostats.fp != NULL) { |
795 | 0 | fprintf(protostats.fp, "%lu %s %s\n", day, |
796 | 0 | ulfptoa(&now, 3), str); |
797 | 0 | fflush(protostats.fp); |
798 | 0 | } |
799 | 15 | } |
800 | | |
801 | | |
802 | | #ifdef AUTOKEY |
803 | | /* |
804 | | * record_crypto_stats - write crypto statistics to file |
805 | | * |
806 | | * file format: |
807 | | * day (mjd) |
808 | | * time (s past midnight) |
809 | | * peer ip address |
810 | | * text message |
811 | | */ |
812 | | void |
813 | | record_crypto_stats( |
814 | | sockaddr_u *addr, |
815 | | const char *text /* text message */ |
816 | | ) |
817 | | { |
818 | | l_fp now; |
819 | | u_long day; |
820 | | |
821 | | if (!stats_control) |
822 | | return; |
823 | | |
824 | | get_systime(&now); |
825 | | filegen_setup(&cryptostats, now.l_ui); |
826 | | day = now.l_ui / 86400 + MJD_1900; |
827 | | now.l_ui %= 86400; |
828 | | if (cryptostats.fp != NULL) { |
829 | | if (addr == NULL) |
830 | | fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", |
831 | | day, ulfptoa(&now, 3), text); |
832 | | else |
833 | | fprintf(cryptostats.fp, "%lu %s %s %s\n", |
834 | | day, ulfptoa(&now, 3), stoa(addr), text); |
835 | | fflush(cryptostats.fp); |
836 | | } |
837 | | } |
838 | | #endif /* AUTOKEY */ |
839 | | |
840 | | |
841 | | #ifdef DEBUG_TIMING |
842 | | /* |
843 | | * record_timing_stats - write timing statistics to file |
844 | | * |
845 | | * file format: |
846 | | * day (mjd) |
847 | | * time (s past midnight) |
848 | | * text message |
849 | | */ |
850 | | void |
851 | | record_timing_stats( |
852 | | const char *text /* text message */ |
853 | | ) |
854 | | { |
855 | | static unsigned int flshcnt; |
856 | | l_fp now; |
857 | | u_long day; |
858 | | |
859 | | if (!stats_control) |
860 | | return; |
861 | | |
862 | | get_systime(&now); |
863 | | filegen_setup(&timingstats, now.l_ui); |
864 | | day = now.l_ui / 86400 + MJD_1900; |
865 | | now.l_ui %= 86400; |
866 | | if (timingstats.fp != NULL) { |
867 | | fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, |
868 | | 3), text); |
869 | | if (++flshcnt % 100 == 0) |
870 | | fflush(timingstats.fp); |
871 | | } |
872 | | } |
873 | | #endif |
874 | | |
875 | | |
876 | | /* |
877 | | * check_leap_file - See if the leapseconds file has been updated. |
878 | | * |
879 | | * Returns: n/a |
880 | | * |
881 | | * Note: This loads a new leapfile on the fly. Currently a leap file |
882 | | * without SHA1 signature is accepted, but if there is a signature line, |
883 | | * the signature must be valid or the file is rejected. |
884 | | */ |
885 | | void |
886 | | check_leap_file( |
887 | | int is_daily_check, |
888 | | uint32_t ntptime , |
889 | | const time_t *systime |
890 | | ) |
891 | 0 | { |
892 | | /* just do nothing if there is no leap file */ |
893 | 0 | if ( ! (leapfile_name && *leapfile_name)) |
894 | 0 | return; |
895 | | |
896 | | /* try to load leapfile, force it if no leapfile loaded yet */ |
897 | 0 | if (leapsec_load_file( |
898 | 0 | leapfile_name, &leapfile_stat, |
899 | 0 | !have_leapfile, is_daily_check)) |
900 | 0 | have_leapfile = TRUE; |
901 | 0 | else if (!have_leapfile) |
902 | 0 | return; |
903 | | |
904 | 0 | check_leap_expiration(is_daily_check, ntptime, systime); |
905 | 0 | } |
906 | | |
907 | | /* |
908 | | * check expiration of a loaded leap table |
909 | | */ |
910 | | static void |
911 | | check_leap_expiration( |
912 | | int is_daily_check, |
913 | | uint32_t ntptime , |
914 | | const time_t *systime |
915 | | ) |
916 | 0 | { |
917 | 0 | static const char * const logPrefix = "leapsecond file"; |
918 | 0 | int rc; |
919 | | |
920 | | /* test the expiration of the leap data and log with proper |
921 | | * level and frequency (once/hour or once/day, depending on the |
922 | | * state. |
923 | | */ |
924 | 0 | rc = leapsec_daystolive(ntptime, systime); |
925 | 0 | if (rc == 0) { |
926 | 0 | msyslog(LOG_WARNING, |
927 | 0 | "%s ('%s'): will expire in less than one day", |
928 | 0 | logPrefix, leapfile_name); |
929 | 0 | } else if (is_daily_check && rc < 28) { |
930 | 0 | if (rc < 0) |
931 | 0 | msyslog(LOG_ERR, |
932 | 0 | "%s ('%s'): expired less than %d day%s ago", |
933 | 0 | logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s")); |
934 | 0 | else |
935 | 0 | msyslog(LOG_WARNING, |
936 | 0 | "%s ('%s'): will expire in less than %d days", |
937 | 0 | logPrefix, leapfile_name, 1+rc); |
938 | 0 | } |
939 | 0 | } |
940 | | |
941 | | |
942 | | /* |
943 | | * getauthkeys - read the authentication keys from the specified file |
944 | | */ |
945 | | void |
946 | | getauthkeys( |
947 | | const char *keyfile |
948 | | ) |
949 | 0 | { |
950 | 0 | size_t len; |
951 | |
|
952 | 0 | len = strlen(keyfile); |
953 | 0 | if (!len) |
954 | 0 | return; |
955 | | |
956 | 0 | #ifndef SYS_WINNT |
957 | 0 | key_file_name = erealloc(key_file_name, len + 1); |
958 | 0 | memcpy(key_file_name, keyfile, len + 1); |
959 | | #else |
960 | | key_file_name = erealloc(key_file_name, _MAX_PATH); |
961 | | if (len + 1 > _MAX_PATH) |
962 | | return; |
963 | | if (!ExpandEnvironmentStrings(keyfile, key_file_name, |
964 | | _MAX_PATH)) { |
965 | | msyslog(LOG_ERR, |
966 | | "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); |
967 | | strlcpy(key_file_name, keyfile, _MAX_PATH); |
968 | | } |
969 | | key_file_name = erealloc(key_file_name, |
970 | | 1 + strlen(key_file_name)); |
971 | | #endif /* SYS_WINNT */ |
972 | |
|
973 | 0 | authreadkeys(key_file_name); |
974 | 0 | } |
975 | | |
976 | | |
977 | | /* |
978 | | * rereadkeys - read the authentication key file over again. |
979 | | */ |
980 | | void |
981 | | rereadkeys(void) |
982 | 0 | { |
983 | 0 | if (NULL != key_file_name) |
984 | 0 | authreadkeys(key_file_name); |
985 | 0 | } |
986 | | |
987 | | |
988 | | #if notyet |
989 | | /* |
990 | | * ntp_exit - document explicitly that ntpd has exited |
991 | | */ |
992 | | void |
993 | | ntp_exit(int retval) |
994 | | { |
995 | | msyslog(LOG_ERR, "EXITING with return code %d", retval); |
996 | | exit(retval); |
997 | | } |
998 | | #endif |
999 | | |
1000 | | /* |
1001 | | * fstostr - prettyprint NTP seconds |
1002 | | */ |
1003 | | char * fstostr( |
1004 | | time_t ntp_stamp |
1005 | | ) |
1006 | 0 | { |
1007 | 0 | char * buf; |
1008 | 0 | struct calendar tm; |
1009 | |
|
1010 | 0 | LIB_GETBUF(buf); |
1011 | 0 | if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0) |
1012 | 0 | snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error", |
1013 | 0 | (long)ntp_stamp); |
1014 | 0 | else |
1015 | 0 | snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d", |
1016 | 0 | tm.year, tm.month, tm.monthday, |
1017 | 0 | tm.hour, tm.minute); |
1018 | 0 | return buf; |
1019 | 0 | } |
1020 | | |
1021 | | |
1022 | | /* |
1023 | | * ntpd_time_stepped is called back by step_systime(), allowing ntpd |
1024 | | * to do any one-time processing necessitated by the step. |
1025 | | */ |
1026 | | void |
1027 | | ntpd_time_stepped(void) |
1028 | 0 | { |
1029 | 0 | u_int saved_mon_enabled; |
1030 | | |
1031 | | /* |
1032 | | * flush the monitor MRU list which contains l_fp timestamps |
1033 | | * which should not be compared across the step. |
1034 | | */ |
1035 | 0 | if (MON_OFF != mon_enabled) { |
1036 | 0 | saved_mon_enabled = mon_enabled; |
1037 | 0 | mon_stop(MON_OFF); |
1038 | 0 | mon_start(saved_mon_enabled); |
1039 | 0 | } |
1040 | | |
1041 | | /* inform interpolating Windows code to allow time to go back */ |
1042 | | #ifdef SYS_WINNT |
1043 | | win_time_stepped(); |
1044 | | #endif |
1045 | 0 | } |