154359Sroberto/* 254359Sroberto * ntp_util.c - stuff I didn't have any other place for 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 582498Sroberto# include <config.h> 654359Sroberto#endif 754359Sroberto 854359Sroberto#include "ntpd.h" 954359Sroberto#include "ntp_unixtime.h" 1054359Sroberto#include "ntp_filegen.h" 1154359Sroberto#include "ntp_if.h" 1254359Sroberto#include "ntp_stdlib.h" 13285612Sdelphij#include "ntp_assert.h" 14285612Sdelphij#include "ntp_calendar.h" 15285612Sdelphij#include "ntp_leapsec.h" 16285612Sdelphij#include "lib_strbuf.h" 1754359Sroberto 1882498Sroberto#include <stdio.h> 1982498Sroberto#include <ctype.h> 2082498Sroberto#include <sys/types.h> 2182498Sroberto#ifdef HAVE_SYS_IOCTL_H 2282498Sroberto# include <sys/ioctl.h> 2382498Sroberto#endif 24285612Sdelphij#ifdef HAVE_UNISTD_H 25285612Sdelphij# include <unistd.h> 26285612Sdelphij#endif 27285612Sdelphij#include <sys/stat.h> 2882498Sroberto 2982498Sroberto#ifdef HAVE_IEEEFP_H 3082498Sroberto# include <ieeefp.h> 3182498Sroberto#endif 3282498Sroberto#ifdef HAVE_MATH_H 3382498Sroberto# include <math.h> 3482498Sroberto#endif 3582498Sroberto 3654359Sroberto#if defined(VMS) 37182007Sroberto# include <descrip.h> 3854359Sroberto#endif /* VMS */ 3954359Sroberto 4054359Sroberto/* 41285612Sdelphij * Defines used by the leapseconds stuff 4254359Sroberto */ 43285612Sdelphij#define MAX_TAI 100 /* max TAI offset (s) */ 44285612Sdelphij#define L_DAY 86400UL /* seconds per day */ 45285612Sdelphij#define L_YEAR (L_DAY * 365) /* days per year */ 46285612Sdelphij#define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */ 47285612Sdelphij#define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */ 48285612Sdelphij#define L_CENT (L_4YEAR * 25) /* days per century */ 49285612Sdelphij 5054359Sroberto/* 51285612Sdelphij * This contains odds and ends, including the hourly stats, various 52285612Sdelphij * configuration items, leapseconds stuff, etc. 5354359Sroberto */ 5454359Sroberto/* 55285612Sdelphij * File names 5654359Sroberto */ 57285612Sdelphijstatic char *key_file_name; /* keys file name */ 58285612Sdelphijstatic char *leapfile_name; /* leapseconds file name */ 59285612Sdelphijstatic struct stat leapfile_stat; /* leapseconds file stat() buffer */ 60285612Sdelphijstatic int /*BOOL*/have_leapfile = FALSE; 61285612Sdelphijchar *stats_drift_file; /* frequency file name */ 62285612Sdelphijstatic char *stats_temp_file; /* temp frequency file name */ 63285612Sdelphijstatic double wander_resid; /* last frequency update */ 64285612Sdelphijdouble wander_threshold = 1e-7; /* initial frequency threshold */ 6554359Sroberto 6654359Sroberto/* 6754359Sroberto * Statistics file stuff 6854359Sroberto */ 6954359Sroberto#ifndef NTP_VAR 70182007Sroberto# ifndef SYS_WINNT 71182007Sroberto# define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ 72182007Sroberto# else 73285612Sdelphij# define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ 74182007Sroberto# endif /* SYS_WINNT */ 7554359Sroberto#endif 7654359Sroberto 7754359Sroberto 78285612Sdelphijchar statsdir[MAXFILENAME] = NTP_VAR; 7954359Srobertostatic FILEGEN peerstats; 8054359Srobertostatic FILEGEN loopstats; 8154359Srobertostatic FILEGEN clockstats; 8254359Srobertostatic FILEGEN rawstats; 83132451Srobertostatic FILEGEN sysstats; 84285612Sdelphijstatic FILEGEN protostats; 85285612Sdelphijstatic FILEGEN cryptostats; 86182007Srobertostatic FILEGEN timingstats; 8754359Sroberto 8854359Sroberto/* 8954359Sroberto * This controls whether stats are written to the fileset. Provided 9054359Sroberto * so that ntpdc can turn off stats when the file system fills up. 9154359Sroberto */ 9254359Srobertoint stats_control; 9354359Sroberto 9454359Sroberto/* 95285612Sdelphij * Last frequency written to file. 96182007Sroberto */ 97285612Sdelphijstatic double prev_drift_comp; /* last frequency update */ 98182007Sroberto 99182007Sroberto/* 100285612Sdelphij * Function prototypes 10154359Sroberto */ 102285612Sdelphijstatic void record_sys_stats(void); 103285612Sdelphij void ntpd_time_stepped(void); 104285612Sdelphijstatic void check_leap_expiration(int, uint32_t, const time_t*); 105285612Sdelphij 106285612Sdelphij/* 107285612Sdelphij * Prototypes 108285612Sdelphij */ 109285612Sdelphij#ifdef DEBUG 110285612Sdelphijvoid uninit_util(void); 111285612Sdelphij#endif 112285612Sdelphij 113285612Sdelphij/* 114285612Sdelphij * uninit_util - free memory allocated by init_util 115285612Sdelphij */ 116285612Sdelphij#ifdef DEBUG 11754359Srobertovoid 118285612Sdelphijuninit_util(void) 11954359Sroberto{ 120285612Sdelphij#if defined(_MSC_VER) && defined (_DEBUG) 121285612Sdelphij _CrtCheckMemory(); 122285612Sdelphij#endif 123285612Sdelphij if (stats_drift_file) { 124285612Sdelphij free(stats_drift_file); 125285612Sdelphij free(stats_temp_file); 126285612Sdelphij stats_drift_file = NULL; 127285612Sdelphij stats_temp_file = NULL; 128285612Sdelphij } 129285612Sdelphij if (key_file_name) { 130285612Sdelphij free(key_file_name); 131285612Sdelphij key_file_name = NULL; 132285612Sdelphij } 133285612Sdelphij filegen_unregister("peerstats"); 134285612Sdelphij filegen_unregister("loopstats"); 135285612Sdelphij filegen_unregister("clockstats"); 136285612Sdelphij filegen_unregister("rawstats"); 137285612Sdelphij filegen_unregister("sysstats"); 138285612Sdelphij filegen_unregister("protostats"); 139285612Sdelphij#ifdef AUTOKEY 140285612Sdelphij filegen_unregister("cryptostats"); 141285612Sdelphij#endif /* AUTOKEY */ 142285612Sdelphij#ifdef DEBUG_TIMING 143285612Sdelphij filegen_unregister("timingstats"); 144285612Sdelphij#endif /* DEBUG_TIMING */ 14554359Sroberto 146285612Sdelphij#if defined(_MSC_VER) && defined (_DEBUG) 147285612Sdelphij _CrtCheckMemory(); 148285612Sdelphij#endif 149285612Sdelphij} 150285612Sdelphij#endif /* DEBUG */ 151132451Sroberto 15254359Sroberto 153285612Sdelphij/* 154285612Sdelphij * init_util - initialize the util module of ntpd 155285612Sdelphij */ 156285612Sdelphijvoid 157285612Sdelphijinit_util(void) 158285612Sdelphij{ 159285612Sdelphij filegen_register(statsdir, "peerstats", &peerstats); 160285612Sdelphij filegen_register(statsdir, "loopstats", &loopstats); 161285612Sdelphij filegen_register(statsdir, "clockstats", &clockstats); 162285612Sdelphij filegen_register(statsdir, "rawstats", &rawstats); 163285612Sdelphij filegen_register(statsdir, "sysstats", &sysstats); 164285612Sdelphij filegen_register(statsdir, "protostats", &protostats); 165285612Sdelphij filegen_register(statsdir, "cryptostats", &cryptostats); 166285612Sdelphij filegen_register(statsdir, "timingstats", &timingstats); 167285612Sdelphij /* 168285612Sdelphij * register with libntp ntp_set_tod() to call us back 169285612Sdelphij * when time is stepped. 170285612Sdelphij */ 171285612Sdelphij step_callback = &ntpd_time_stepped; 172285612Sdelphij#ifdef DEBUG 173285612Sdelphij atexit(&uninit_util); 174285612Sdelphij#endif /* DEBUG */ 17554359Sroberto} 17654359Sroberto 17754359Sroberto 17854359Sroberto/* 17954359Sroberto * hourly_stats - print some interesting stats 18054359Sroberto */ 18154359Srobertovoid 182182007Srobertowrite_stats(void) 18354359Sroberto{ 184285612Sdelphij FILE *fp; 18554359Sroberto#ifdef DOSYNCTODR 18654359Sroberto struct timeval tv; 18754359Sroberto#if !defined(VMS) 188285612Sdelphij int prio_set; 18954359Sroberto#endif 19054359Sroberto#ifdef HAVE_GETCLOCK 191285612Sdelphij struct timespec ts; 19254359Sroberto#endif 193285612Sdelphij int o_prio; 19454359Sroberto 19554359Sroberto /* 19654359Sroberto * Sometimes having a Sun can be a drag. 19754359Sroberto * 19854359Sroberto * The kernel variable dosynctodr controls whether the system's 19954359Sroberto * soft clock is kept in sync with the battery clock. If it 20054359Sroberto * is zero, then the soft clock is not synced, and the battery 20154359Sroberto * clock is simply left to rot. That means that when the system 20254359Sroberto * reboots, the battery clock (which has probably gone wacky) 20354359Sroberto * sets the soft clock. That means ntpd starts off with a very 20454359Sroberto * confused idea of what time it is. It then takes a large 20554359Sroberto * amount of time to figure out just how wacky the battery clock 20654359Sroberto * has made things drift, etc, etc. The solution is to make the 20754359Sroberto * battery clock sync up to system time. The way to do THAT is 20854359Sroberto * to simply set the time of day to the current time of day, but 20954359Sroberto * as quickly as possible. This may, or may not be a sensible 21054359Sroberto * thing to do. 21154359Sroberto * 21254359Sroberto * CAVEAT: settimeofday() steps the sun clock by about 800 us, 213285612Sdelphij * so setting DOSYNCTODR seems a bad idea in the 214285612Sdelphij * case of us resolution 21554359Sroberto */ 21654359Sroberto 21754359Sroberto#if !defined(VMS) 218285612Sdelphij /* 219285612Sdelphij * (prr) getpriority returns -1 on error, but -1 is also a valid 220132451Sroberto * return value (!), so instead we have to zero errno before the 221132451Sroberto * call and check it for non-zero afterwards. 22254359Sroberto */ 22354359Sroberto errno = 0; 22454359Sroberto prio_set = 0; 22554359Sroberto o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ 22654359Sroberto 227132451Sroberto /* 228132451Sroberto * (prr) if getpriority succeeded, call setpriority to raise 22954359Sroberto * scheduling priority as high as possible. If that succeeds 23054359Sroberto * as well, set the prio_set flag so we remember to reset 231132451Sroberto * priority to its previous value below. Note that on Solaris 232132451Sroberto * 2.6 (and beyond?), both getpriority and setpriority will fail 233132451Sroberto * with ESRCH, because sched_setscheduler (called from main) put 234132451Sroberto * us in the real-time scheduling class which setpriority 235132451Sroberto * doesn't know about. Being in the real-time class is better 236132451Sroberto * than anything setpriority can do, anyhow, so this error is 237132451Sroberto * silently ignored. 23854359Sroberto */ 23954359Sroberto if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) 240132451Sroberto prio_set = 1; /* overdrive */ 24154359Sroberto#endif /* VMS */ 24254359Sroberto#ifdef HAVE_GETCLOCK 243285612Sdelphij (void) getclock(TIMEOFDAY, &ts); 244285612Sdelphij tv.tv_sec = ts.tv_sec; 245285612Sdelphij tv.tv_usec = ts.tv_nsec / 1000; 24654359Sroberto#else /* not HAVE_GETCLOCK */ 24754359Sroberto GETTIMEOFDAY(&tv,(struct timezone *)NULL); 24854359Sroberto#endif /* not HAVE_GETCLOCK */ 249285612Sdelphij if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) 25054359Sroberto msyslog(LOG_ERR, "can't sync battery time: %m"); 25154359Sroberto#if !defined(VMS) 25254359Sroberto if (prio_set) 253132451Sroberto setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ 25454359Sroberto#endif /* VMS */ 25554359Sroberto#endif /* DOSYNCTODR */ 256132451Sroberto record_sys_stats(); 25754359Sroberto if (stats_drift_file != 0) { 258285612Sdelphij 259285612Sdelphij /* 260285612Sdelphij * When the frequency file is written, initialize the 261285612Sdelphij * prev_drift_comp and wander_resid. Thereafter, 262285612Sdelphij * reduce the wander_resid by half each hour. When 263285612Sdelphij * the difference between the prev_drift_comp and 264285612Sdelphij * drift_comp is less than the wander_resid, update 265285612Sdelphij * the frequncy file. This minimizes the file writes to 266285612Sdelphij * nonvolaile storage. 267285612Sdelphij */ 268285612Sdelphij#ifdef DEBUG 269285612Sdelphij if (debug) 270285612Sdelphij printf("write_stats: frequency %.6lf thresh %.6lf, freq %.6lf\n", 271285612Sdelphij (prev_drift_comp - drift_comp) * 1e6, wander_resid * 272285612Sdelphij 1e6, drift_comp * 1e6); 273285612Sdelphij#endif 274285612Sdelphij if (fabs(prev_drift_comp - drift_comp) < wander_resid) { 275285612Sdelphij wander_resid *= 0.5; 276285612Sdelphij return; 277285612Sdelphij } 278285612Sdelphij prev_drift_comp = drift_comp; 279285612Sdelphij wander_resid = wander_threshold; 28054359Sroberto if ((fp = fopen(stats_temp_file, "w")) == NULL) { 281285612Sdelphij msyslog(LOG_ERR, "frequency file %s: %m", 28254359Sroberto stats_temp_file); 28354359Sroberto return; 28454359Sroberto } 28554359Sroberto fprintf(fp, "%.3f\n", drift_comp * 1e6); 28654359Sroberto (void)fclose(fp); 28754359Sroberto /* atomic */ 28854359Sroberto#ifdef SYS_WINNT 289285612Sdelphij if (_unlink(stats_drift_file)) /* rename semantics differ under NT */ 290285612Sdelphij msyslog(LOG_WARNING, 291285612Sdelphij "Unable to remove prior drift file %s, %m", 292285612Sdelphij stats_drift_file); 29354359Sroberto#endif /* SYS_WINNT */ 29454359Sroberto 29554359Sroberto#ifndef NO_RENAME 296285612Sdelphij if (rename(stats_temp_file, stats_drift_file)) 297285612Sdelphij msyslog(LOG_WARNING, 298285612Sdelphij "Unable to rename temp drift file %s to %s, %m", 299285612Sdelphij stats_temp_file, stats_drift_file); 30054359Sroberto#else 301182007Sroberto /* we have no rename NFS of ftp in use */ 302285612Sdelphij if ((fp = fopen(stats_drift_file, "w")) == 303285612Sdelphij NULL) { 304285612Sdelphij msyslog(LOG_ERR, 305285612Sdelphij "frequency file %s: %m", 30654359Sroberto stats_drift_file); 30754359Sroberto return; 30854359Sroberto } 30954359Sroberto#endif 31054359Sroberto 31154359Sroberto#if defined(VMS) 31254359Sroberto /* PURGE */ 31354359Sroberto { 31454359Sroberto $DESCRIPTOR(oldvers,";-1"); 31554359Sroberto struct dsc$descriptor driftdsc = { 316285612Sdelphij strlen(stats_drift_file), 0, 0, 317285612Sdelphij stats_drift_file }; 318285612Sdelphij while(lib$delete_file(&oldvers, 319285612Sdelphij &driftdsc) & 1); 32054359Sroberto } 32154359Sroberto#endif 32254359Sroberto } 32354359Sroberto} 32454359Sroberto 32554359Sroberto 32654359Sroberto/* 32754359Sroberto * stats_config - configure the stats operation 32854359Sroberto */ 32954359Srobertovoid 33054359Srobertostats_config( 33154359Sroberto int item, 332182007Sroberto const char *invalue /* only one type so far */ 33354359Sroberto ) 33454359Sroberto{ 335285612Sdelphij FILE *fp; 336182007Sroberto const char *value; 337293650Sglebius size_t len; 338285612Sdelphij double old_drift; 339285612Sdelphij l_fp now; 340285612Sdelphij time_t ttnow; 341285612Sdelphij#ifndef VMS 342285612Sdelphij const char temp_ext[] = ".TEMP"; 343285612Sdelphij#else 344285612Sdelphij const char temp_ext[] = "-TEMP"; 345285612Sdelphij#endif 34654359Sroberto 347132451Sroberto /* 348132451Sroberto * Expand environment strings under Windows NT, since the 349132451Sroberto * command interpreter doesn't do this, the program must. 35054359Sroberto */ 35154359Sroberto#ifdef SYS_WINNT 35254359Sroberto char newvalue[MAX_PATH], parameter[MAX_PATH]; 35354359Sroberto 354132451Sroberto if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { 355285612Sdelphij switch (item) { 356285612Sdelphij case STATS_FREQ_FILE: 357285612Sdelphij strlcpy(parameter, "STATS_FREQ_FILE", 358285612Sdelphij sizeof(parameter)); 35954359Sroberto break; 360285612Sdelphij 361285612Sdelphij case STATS_LEAP_FILE: 362285612Sdelphij strlcpy(parameter, "STATS_LEAP_FILE", 363285612Sdelphij sizeof(parameter)); 36454359Sroberto break; 365285612Sdelphij 366285612Sdelphij case STATS_STATSDIR: 367285612Sdelphij strlcpy(parameter, "STATS_STATSDIR", 368285612Sdelphij sizeof(parameter)); 36954359Sroberto break; 370285612Sdelphij 371285612Sdelphij case STATS_PID_FILE: 372285612Sdelphij strlcpy(parameter, "STATS_PID_FILE", 373285612Sdelphij sizeof(parameter)); 37454359Sroberto break; 375285612Sdelphij 376285612Sdelphij default: 377285612Sdelphij strlcpy(parameter, "UNKNOWN", 378285612Sdelphij sizeof(parameter)); 379285612Sdelphij break; 38054359Sroberto } 38154359Sroberto value = invalue; 38254359Sroberto msyslog(LOG_ERR, 383285612Sdelphij "ExpandEnvironmentStrings(%s) failed: %m\n", 384285612Sdelphij parameter); 385132451Sroberto } else { 386132451Sroberto value = newvalue; 38754359Sroberto } 388285612Sdelphij#else 38954359Sroberto value = invalue; 39054359Sroberto#endif /* SYS_WINNT */ 39154359Sroberto 392285612Sdelphij switch (item) { 39354359Sroberto 394285612Sdelphij /* 395285612Sdelphij * Open and read frequency file. 396285612Sdelphij */ 397285612Sdelphij case STATS_FREQ_FILE: 398285612Sdelphij if (!value || (len = strlen(value)) == 0) 399285612Sdelphij break; 40054359Sroberto 401285612Sdelphij stats_drift_file = erealloc(stats_drift_file, len + 1); 402285612Sdelphij stats_temp_file = erealloc(stats_temp_file, 403285612Sdelphij len + sizeof(".TEMP")); 404285612Sdelphij memcpy(stats_drift_file, value, (size_t)(len+1)); 405285612Sdelphij memcpy(stats_temp_file, value, (size_t)len); 406285612Sdelphij memcpy(stats_temp_file + len, temp_ext, sizeof(temp_ext)); 40754359Sroberto 40854359Sroberto /* 409132451Sroberto * Open drift file and read frequency. If the file is 410132451Sroberto * missing or contains errors, tell the loop to reset. 41154359Sroberto */ 412285612Sdelphij if ((fp = fopen(stats_drift_file, "r")) == NULL) 41354359Sroberto break; 414285612Sdelphij 41554359Sroberto if (fscanf(fp, "%lf", &old_drift) != 1) { 416285612Sdelphij msyslog(LOG_ERR, 417285612Sdelphij "format error frequency file %s", 418285612Sdelphij stats_drift_file); 419132451Sroberto fclose(fp); 42054359Sroberto break; 421285612Sdelphij 42254359Sroberto } 423132451Sroberto fclose(fp); 424285612Sdelphij loop_config(LOOP_FREQ, old_drift); 425285612Sdelphij prev_drift_comp = drift_comp; 42654359Sroberto break; 427285612Sdelphij 428285612Sdelphij /* 429285612Sdelphij * Specify statistics directory. 430285612Sdelphij */ 431285612Sdelphij case STATS_STATSDIR: 432285612Sdelphij 433285612Sdelphij /* - 1 since value may be missing the DIR_SEP. */ 434285612Sdelphij if (strlen(value) >= sizeof(statsdir) - 1) { 43554359Sroberto msyslog(LOG_ERR, 436285612Sdelphij "statsdir too long (>%d, sigh)", 437285612Sdelphij (int)sizeof(statsdir) - 2); 43854359Sroberto } else { 439285612Sdelphij int add_dir_sep; 440293650Sglebius size_t value_l; 44154359Sroberto 442285612Sdelphij /* Add a DIR_SEP unless we already have one. */ 443285612Sdelphij value_l = strlen(value); 444285612Sdelphij if (0 == value_l) 445285612Sdelphij add_dir_sep = FALSE; 446285612Sdelphij else 447285612Sdelphij add_dir_sep = (DIR_SEP != 448285612Sdelphij value[value_l - 1]); 449285612Sdelphij 450285612Sdelphij if (add_dir_sep) 451285612Sdelphij snprintf(statsdir, sizeof(statsdir), 452285612Sdelphij "%s%c", value, DIR_SEP); 453285612Sdelphij else 454285612Sdelphij snprintf(statsdir, sizeof(statsdir), 455285612Sdelphij "%s", value); 456285612Sdelphij filegen_statsdir(); 45754359Sroberto } 45854359Sroberto break; 45954359Sroberto 460285612Sdelphij /* 461285612Sdelphij * Open pid file. 462285612Sdelphij */ 463285612Sdelphij case STATS_PID_FILE: 46454359Sroberto if ((fp = fopen(value, "w")) == NULL) { 465285612Sdelphij msyslog(LOG_ERR, "pid file %s: %m", 466285612Sdelphij value); 46754359Sroberto break; 46854359Sroberto } 469285612Sdelphij fprintf(fp, "%d", (int)getpid()); 470285612Sdelphij fclose(fp); 47154359Sroberto break; 47254359Sroberto 473285612Sdelphij /* 474285612Sdelphij * Read leapseconds file. 475285612Sdelphij * 476285612Sdelphij * Note: Currently a leap file without SHA1 signature is 477285612Sdelphij * accepted, but if there is a signature line, the signature 478285612Sdelphij * must be valid or the file is rejected. 479285612Sdelphij */ 480285612Sdelphij case STATS_LEAP_FILE: 481285612Sdelphij if (!value || (len = strlen(value)) == 0) 482285612Sdelphij break; 483285612Sdelphij 484285612Sdelphij leapfile_name = erealloc(leapfile_name, len + 1); 485285612Sdelphij memcpy(leapfile_name, value, len + 1); 486285612Sdelphij 487285612Sdelphij if (leapsec_load_file( 488285612Sdelphij leapfile_name, &leapfile_stat, TRUE, TRUE)) 489285612Sdelphij { 490285612Sdelphij leap_signature_t lsig; 491285612Sdelphij 492285612Sdelphij get_systime(&now); 493285612Sdelphij time(&ttnow); 494285612Sdelphij leapsec_getsig(&lsig); 495285612Sdelphij mprintf_event(EVNT_TAI, NULL, 496285612Sdelphij "%d leap %s %s %s", 497285612Sdelphij lsig.taiof, 498285612Sdelphij fstostr(lsig.ttime), 499285612Sdelphij leapsec_expired(now.l_ui, NULL) 500285612Sdelphij ? "expired" 501285612Sdelphij : "expires", 502285612Sdelphij fstostr(lsig.etime)); 503285612Sdelphij 504285612Sdelphij have_leapfile = TRUE; 505285612Sdelphij 506285612Sdelphij /* force an immediate daily expiration check of 507285612Sdelphij * the leap seconds table 508285612Sdelphij */ 509285612Sdelphij check_leap_expiration(TRUE, now.l_ui, &ttnow); 510285612Sdelphij } 511285612Sdelphij break; 512285612Sdelphij 513285612Sdelphij default: 51454359Sroberto /* oh well */ 51554359Sroberto break; 51654359Sroberto } 51754359Sroberto} 51854359Sroberto 519285612Sdelphij 52054359Sroberto/* 52154359Sroberto * record_peer_stats - write peer statistics to file 52254359Sroberto * 52354359Sroberto * file format: 524285612Sdelphij * day (MJD) 52554359Sroberto * time (s past UTC midnight) 526285612Sdelphij * IP address 527285612Sdelphij * status word (hex) 528285612Sdelphij * offset 529285612Sdelphij * delay 530285612Sdelphij * dispersion 531285612Sdelphij * jitter 53254359Sroberto*/ 53354359Srobertovoid 53454359Srobertorecord_peer_stats( 535285612Sdelphij sockaddr_u *addr, 536132451Sroberto int status, 537285612Sdelphij double offset, /* offset */ 538285612Sdelphij double delay, /* delay */ 539285612Sdelphij double dispersion, /* dispersion */ 540285612Sdelphij double jitter /* jitter */ 54154359Sroberto ) 54254359Sroberto{ 543132451Sroberto l_fp now; 544132451Sroberto u_long day; 54554359Sroberto 54654359Sroberto if (!stats_control) 54754359Sroberto return; 54854359Sroberto 549132451Sroberto get_systime(&now); 550132451Sroberto filegen_setup(&peerstats, now.l_ui); 551132451Sroberto day = now.l_ui / 86400 + MJD_1900; 552132451Sroberto now.l_ui %= 86400; 55354359Sroberto if (peerstats.fp != NULL) { 55454359Sroberto fprintf(peerstats.fp, 555285612Sdelphij "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, 556285612Sdelphij ulfptoa(&now, 3), stoa(addr), status, offset, 557285612Sdelphij delay, dispersion, jitter); 55854359Sroberto fflush(peerstats.fp); 55954359Sroberto } 56054359Sroberto} 561182007Sroberto 562285612Sdelphij 56354359Sroberto/* 56454359Sroberto * record_loop_stats - write loop filter statistics to file 56554359Sroberto * 56654359Sroberto * file format: 567285612Sdelphij * day (MJD) 56854359Sroberto * time (s past midnight) 569285612Sdelphij * offset 570285612Sdelphij * frequency (PPM) 571285612Sdelphij * jitter 572285612Sdelphij * wnder (PPM) 573285612Sdelphij * time constant (log2) 57454359Sroberto */ 57554359Srobertovoid 57682498Srobertorecord_loop_stats( 577285612Sdelphij double offset, /* offset */ 578285612Sdelphij double freq, /* frequency (PPM) */ 579285612Sdelphij double jitter, /* jitter */ 580285612Sdelphij double wander, /* wander (PPM) */ 581132451Sroberto int spoll 58282498Sroberto ) 58354359Sroberto{ 584132451Sroberto l_fp now; 585132451Sroberto u_long day; 58654359Sroberto 58754359Sroberto if (!stats_control) 58854359Sroberto return; 58954359Sroberto 590132451Sroberto get_systime(&now); 591132451Sroberto filegen_setup(&loopstats, now.l_ui); 592132451Sroberto day = now.l_ui / 86400 + MJD_1900; 593132451Sroberto now.l_ui %= 86400; 59454359Sroberto if (loopstats.fp != NULL) { 595182007Sroberto fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", 596132451Sroberto day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, 597285612Sdelphij wander * 1e6, spoll); 59854359Sroberto fflush(loopstats.fp); 59954359Sroberto } 60054359Sroberto} 60154359Sroberto 602285612Sdelphij 60354359Sroberto/* 60454359Sroberto * record_clock_stats - write clock statistics to file 60554359Sroberto * 60654359Sroberto * file format: 607285612Sdelphij * day (MJD) 60854359Sroberto * time (s past midnight) 609285612Sdelphij * IP address 61054359Sroberto * text message 61154359Sroberto */ 61254359Srobertovoid 61354359Srobertorecord_clock_stats( 614285612Sdelphij sockaddr_u *addr, 615285612Sdelphij const char *text /* timecode string */ 61654359Sroberto ) 61754359Sroberto{ 618132451Sroberto l_fp now; 619132451Sroberto u_long day; 62054359Sroberto 62154359Sroberto if (!stats_control) 62254359Sroberto return; 62354359Sroberto 624132451Sroberto get_systime(&now); 625132451Sroberto filegen_setup(&clockstats, now.l_ui); 626132451Sroberto day = now.l_ui / 86400 + MJD_1900; 627132451Sroberto now.l_ui %= 86400; 62854359Sroberto if (clockstats.fp != NULL) { 629285612Sdelphij fprintf(clockstats.fp, "%lu %s %s %s\n", day, 630285612Sdelphij ulfptoa(&now, 3), stoa(addr), text); 63154359Sroberto fflush(clockstats.fp); 63254359Sroberto } 63354359Sroberto} 63454359Sroberto 635285612Sdelphij 63654359Sroberto/* 637285612Sdelphij * mprintf_clock_stats - write clock statistics to file with 638285612Sdelphij * msnprintf-style formatting. 639285612Sdelphij */ 640285612Sdelphijint 641285612Sdelphijmprintf_clock_stats( 642285612Sdelphij sockaddr_u *addr, 643285612Sdelphij const char *fmt, 644285612Sdelphij ... 645285612Sdelphij ) 646285612Sdelphij{ 647285612Sdelphij va_list ap; 648285612Sdelphij int rc; 649285612Sdelphij char msg[512]; 650285612Sdelphij 651285612Sdelphij va_start(ap, fmt); 652285612Sdelphij rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 653285612Sdelphij va_end(ap); 654285612Sdelphij if (stats_control) 655285612Sdelphij record_clock_stats(addr, msg); 656285612Sdelphij 657285612Sdelphij return rc; 658285612Sdelphij} 659285612Sdelphij 660285612Sdelphij/* 66154359Sroberto * record_raw_stats - write raw timestamps to file 66254359Sroberto * 66354359Sroberto * file format 664285612Sdelphij * day (MJD) 66554359Sroberto * time (s past midnight) 66654359Sroberto * peer ip address 667285612Sdelphij * IP address 66854359Sroberto * t1 t2 t3 t4 timestamps 669330141Sdelphij * leap, version, mode, stratum, ppoll, precision, root delay, root dispersion, REFID 670330141Sdelphij * length and hex dump of any EFs and any legacy MAC. 67154359Sroberto */ 67254359Srobertovoid 67354359Srobertorecord_raw_stats( 674285612Sdelphij sockaddr_u *srcadr, 675285612Sdelphij sockaddr_u *dstadr, 676285612Sdelphij l_fp *t1, /* originate timestamp */ 677285612Sdelphij l_fp *t2, /* receive timestamp */ 678285612Sdelphij l_fp *t3, /* transmit timestamp */ 679285612Sdelphij l_fp *t4, /* destination timestamp */ 680285612Sdelphij int leap, 681285612Sdelphij int version, 682285612Sdelphij int mode, 683285612Sdelphij int stratum, 684285612Sdelphij int ppoll, 685285612Sdelphij int precision, 686285612Sdelphij double root_delay, /* seconds */ 687285612Sdelphij double root_dispersion,/* seconds */ 688330141Sdelphij u_int32 refid, 689330141Sdelphij int len, 690330141Sdelphij u_char *extra 69154359Sroberto ) 69254359Sroberto{ 693132451Sroberto l_fp now; 694132451Sroberto u_long day; 69554359Sroberto 69654359Sroberto if (!stats_control) 69754359Sroberto return; 69854359Sroberto 699132451Sroberto get_systime(&now); 700132451Sroberto filegen_setup(&rawstats, now.l_ui); 701132451Sroberto day = now.l_ui / 86400 + MJD_1900; 702132451Sroberto now.l_ui %= 86400; 70354359Sroberto if (rawstats.fp != NULL) { 704330141Sdelphij fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s", 705285612Sdelphij day, ulfptoa(&now, 3), 706330141Sdelphij srcadr ? stoa(srcadr) : "-", 707330141Sdelphij dstadr ? stoa(dstadr) : "-", 708285612Sdelphij ulfptoa(t1, 9), ulfptoa(t2, 9), 709285612Sdelphij ulfptoa(t3, 9), ulfptoa(t4, 9), 710285612Sdelphij leap, version, mode, stratum, ppoll, precision, 711285612Sdelphij root_delay, root_dispersion, refid_str(refid, stratum)); 712330141Sdelphij if (len > 0) { 713330141Sdelphij int i; 714330141Sdelphij 715330141Sdelphij fprintf(rawstats.fp, " %d: ", len); 716330141Sdelphij for (i = 0; i < len; ++i) { 717330141Sdelphij fprintf(rawstats.fp, "%02x", extra[i]); 718330141Sdelphij } 719330141Sdelphij } 720330141Sdelphij fprintf(rawstats.fp, "\n"); 72154359Sroberto fflush(rawstats.fp); 72254359Sroberto } 72354359Sroberto} 72454359Sroberto 725132451Sroberto 72654359Sroberto/* 727132451Sroberto * record_sys_stats - write system statistics to file 728132451Sroberto * 729132451Sroberto * file format 730285612Sdelphij * day (MJD) 731132451Sroberto * time (s past midnight) 732285612Sdelphij * time since reset 733132451Sroberto * packets recieved 734285612Sdelphij * packets for this host 735132451Sroberto * current version 736285612Sdelphij * old version 737132451Sroberto * access denied 738132451Sroberto * bad length or format 739132451Sroberto * bad authentication 740285612Sdelphij * declined 741132451Sroberto * rate exceeded 742285612Sdelphij * KoD sent 743132451Sroberto */ 744132451Srobertovoid 745132451Srobertorecord_sys_stats(void) 746132451Sroberto{ 747132451Sroberto l_fp now; 748132451Sroberto u_long day; 749132451Sroberto 750132451Sroberto if (!stats_control) 751132451Sroberto return; 752132451Sroberto 753132451Sroberto get_systime(&now); 754132451Sroberto filegen_setup(&sysstats, now.l_ui); 755132451Sroberto day = now.l_ui / 86400 + MJD_1900; 756132451Sroberto now.l_ui %= 86400; 757132451Sroberto if (sysstats.fp != NULL) { 758285612Sdelphij fprintf(sysstats.fp, 759285612Sdelphij "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 760285612Sdelphij day, ulfptoa(&now, 3), current_time - sys_stattime, 761285612Sdelphij sys_received, sys_processed, sys_newversion, 762285612Sdelphij sys_oldversion, sys_restricted, sys_badlength, 763285612Sdelphij sys_badauth, sys_declined, sys_limitrejected, 764285612Sdelphij sys_kodsent); 765132451Sroberto fflush(sysstats.fp); 766132451Sroberto proto_clr_stats(); 767132451Sroberto } 768132451Sroberto} 769132451Sroberto 770132451Sroberto 771132451Sroberto/* 772285612Sdelphij * record_proto_stats - write system statistics to file 773285612Sdelphij * 774285612Sdelphij * file format 775285612Sdelphij * day (MJD) 776285612Sdelphij * time (s past midnight) 777285612Sdelphij * text message 778285612Sdelphij */ 779285612Sdelphijvoid 780285612Sdelphijrecord_proto_stats( 781285612Sdelphij char *str /* text string */ 782285612Sdelphij ) 783285612Sdelphij{ 784285612Sdelphij l_fp now; 785285612Sdelphij u_long day; 786285612Sdelphij 787285612Sdelphij if (!stats_control) 788285612Sdelphij return; 789285612Sdelphij 790285612Sdelphij get_systime(&now); 791285612Sdelphij filegen_setup(&protostats, now.l_ui); 792285612Sdelphij day = now.l_ui / 86400 + MJD_1900; 793285612Sdelphij now.l_ui %= 86400; 794285612Sdelphij if (protostats.fp != NULL) { 795285612Sdelphij fprintf(protostats.fp, "%lu %s %s\n", day, 796285612Sdelphij ulfptoa(&now, 3), str); 797285612Sdelphij fflush(protostats.fp); 798285612Sdelphij } 799285612Sdelphij} 800285612Sdelphij 801285612Sdelphij 802285612Sdelphij#ifdef AUTOKEY 803285612Sdelphij/* 804132451Sroberto * record_crypto_stats - write crypto statistics to file 805132451Sroberto * 806132451Sroberto * file format: 807132451Sroberto * day (mjd) 808132451Sroberto * time (s past midnight) 809285612Sdelphij * peer ip address 810132451Sroberto * text message 811132451Sroberto */ 812132451Srobertovoid 813132451Srobertorecord_crypto_stats( 814285612Sdelphij sockaddr_u *addr, 815285612Sdelphij const char *text /* text message */ 816132451Sroberto ) 817132451Sroberto{ 818132451Sroberto l_fp now; 819132451Sroberto u_long day; 820132451Sroberto 821132451Sroberto if (!stats_control) 822132451Sroberto return; 823132451Sroberto 824132451Sroberto get_systime(&now); 825132451Sroberto filegen_setup(&cryptostats, now.l_ui); 826132451Sroberto day = now.l_ui / 86400 + MJD_1900; 827132451Sroberto now.l_ui %= 86400; 828132451Sroberto if (cryptostats.fp != NULL) { 829132451Sroberto if (addr == NULL) 830285612Sdelphij fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", 831132451Sroberto day, ulfptoa(&now, 3), text); 832132451Sroberto else 833132451Sroberto fprintf(cryptostats.fp, "%lu %s %s %s\n", 834132451Sroberto day, ulfptoa(&now, 3), stoa(addr), text); 835132451Sroberto fflush(cryptostats.fp); 836132451Sroberto } 837132451Sroberto} 838285612Sdelphij#endif /* AUTOKEY */ 839132451Sroberto 840285612Sdelphij 841182007Sroberto#ifdef DEBUG_TIMING 842182007Sroberto/* 843285612Sdelphij * record_timing_stats - write timing statistics to file 844182007Sroberto * 845182007Sroberto * file format: 846182007Sroberto * day (mjd) 847182007Sroberto * time (s past midnight) 848182007Sroberto * text message 849182007Sroberto */ 850182007Srobertovoid 851182007Srobertorecord_timing_stats( 852285612Sdelphij const char *text /* text message */ 853182007Sroberto ) 854182007Sroberto{ 855182007Sroberto static unsigned int flshcnt; 856182007Sroberto l_fp now; 857182007Sroberto u_long day; 858132451Sroberto 859182007Sroberto if (!stats_control) 860182007Sroberto return; 861182007Sroberto 862182007Sroberto get_systime(&now); 863182007Sroberto filegen_setup(&timingstats, now.l_ui); 864182007Sroberto day = now.l_ui / 86400 + MJD_1900; 865182007Sroberto now.l_ui %= 86400; 866182007Sroberto if (timingstats.fp != NULL) { 867285612Sdelphij fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, 868285612Sdelphij 3), text); 869182007Sroberto if (++flshcnt % 100 == 0) 870182007Sroberto fflush(timingstats.fp); 871182007Sroberto } 872182007Sroberto} 873182007Sroberto#endif 874285612Sdelphij 875285612Sdelphij 876132451Sroberto/* 877285612Sdelphij * check_leap_file - See if the leapseconds file has been updated. 878285612Sdelphij * 879285612Sdelphij * Returns: n/a 880285612Sdelphij * 881285612Sdelphij * Note: This loads a new leapfile on the fly. Currently a leap file 882285612Sdelphij * without SHA1 signature is accepted, but if there is a signature line, 883285612Sdelphij * the signature must be valid or the file is rejected. 884285612Sdelphij */ 885285612Sdelphijvoid 886285612Sdelphijcheck_leap_file( 887285612Sdelphij int is_daily_check, 888285612Sdelphij uint32_t ntptime , 889285612Sdelphij const time_t *systime 890285612Sdelphij ) 891285612Sdelphij{ 892285612Sdelphij /* just do nothing if there is no leap file */ 893285612Sdelphij if ( ! (leapfile_name && *leapfile_name)) 894285612Sdelphij return; 895285612Sdelphij 896285612Sdelphij /* try to load leapfile, force it if no leapfile loaded yet */ 897285612Sdelphij if (leapsec_load_file( 898285612Sdelphij leapfile_name, &leapfile_stat, 899285612Sdelphij !have_leapfile, is_daily_check)) 900285612Sdelphij have_leapfile = TRUE; 901285612Sdelphij else if (!have_leapfile) 902285612Sdelphij return; 903285612Sdelphij 904285612Sdelphij check_leap_expiration(is_daily_check, ntptime, systime); 905285612Sdelphij} 906285612Sdelphij 907285612Sdelphij/* 908285612Sdelphij * check expiration of a loaded leap table 909285612Sdelphij */ 910285612Sdelphijstatic void 911285612Sdelphijcheck_leap_expiration( 912285612Sdelphij int is_daily_check, 913285612Sdelphij uint32_t ntptime , 914285612Sdelphij const time_t *systime 915285612Sdelphij ) 916285612Sdelphij{ 917285612Sdelphij static const char * const logPrefix = "leapsecond file"; 918285612Sdelphij int rc; 919285612Sdelphij 920285612Sdelphij /* test the expiration of the leap data and log with proper 921285612Sdelphij * level and frequency (once/hour or once/day, depending on the 922285612Sdelphij * state. 923285612Sdelphij */ 924285612Sdelphij rc = leapsec_daystolive(ntptime, systime); 925285612Sdelphij if (rc == 0) { 926285612Sdelphij msyslog(LOG_WARNING, 927285612Sdelphij "%s ('%s'): will expire in less than one day", 928285612Sdelphij logPrefix, leapfile_name); 929285612Sdelphij } else if (is_daily_check && rc < 28) { 930285612Sdelphij if (rc < 0) 931285612Sdelphij msyslog(LOG_ERR, 932285612Sdelphij "%s ('%s'): expired less than %d day%s ago", 933285612Sdelphij logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s")); 934285612Sdelphij else 935285612Sdelphij msyslog(LOG_WARNING, 936285612Sdelphij "%s ('%s'): will expire in less than %d days", 937285612Sdelphij logPrefix, leapfile_name, 1+rc); 938285612Sdelphij } 939285612Sdelphij} 940285612Sdelphij 941285612Sdelphij 942285612Sdelphij/* 94354359Sroberto * getauthkeys - read the authentication keys from the specified file 94454359Sroberto */ 94554359Srobertovoid 94654359Srobertogetauthkeys( 947182007Sroberto const char *keyfile 94854359Sroberto ) 94954359Sroberto{ 950293650Sglebius size_t len; 95154359Sroberto 95254359Sroberto len = strlen(keyfile); 953285612Sdelphij if (!len) 95454359Sroberto return; 95554359Sroberto 95654359Sroberto#ifndef SYS_WINNT 957285612Sdelphij key_file_name = erealloc(key_file_name, len + 1); 958285612Sdelphij memcpy(key_file_name, keyfile, len + 1); 95954359Sroberto#else 960285612Sdelphij key_file_name = erealloc(key_file_name, _MAX_PATH); 961285612Sdelphij if (len + 1 > _MAX_PATH) 962285612Sdelphij return; 963285612Sdelphij if (!ExpandEnvironmentStrings(keyfile, key_file_name, 964285612Sdelphij _MAX_PATH)) { 96554359Sroberto msyslog(LOG_ERR, 966285612Sdelphij "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); 967285612Sdelphij strlcpy(key_file_name, keyfile, _MAX_PATH); 96854359Sroberto } 969285612Sdelphij key_file_name = erealloc(key_file_name, 970285612Sdelphij 1 + strlen(key_file_name)); 97154359Sroberto#endif /* SYS_WINNT */ 97254359Sroberto 97354359Sroberto authreadkeys(key_file_name); 97454359Sroberto} 97554359Sroberto 97654359Sroberto 97754359Sroberto/* 97854359Sroberto * rereadkeys - read the authentication key file over again. 97954359Sroberto */ 98054359Srobertovoid 98154359Srobertorereadkeys(void) 98254359Sroberto{ 983285612Sdelphij if (NULL != key_file_name) 984285612Sdelphij authreadkeys(key_file_name); 98554359Sroberto} 986132451Sroberto 987285612Sdelphij 988285612Sdelphij#if notyet 989132451Sroberto/* 990285612Sdelphij * ntp_exit - document explicitly that ntpd has exited 991132451Sroberto */ 992285612Sdelphijvoid 993285612Sdelphijntp_exit(int retval) 994285612Sdelphij{ 995285612Sdelphij msyslog(LOG_ERR, "EXITING with return code %d", retval); 996285612Sdelphij exit(retval); 997285612Sdelphij} 998285612Sdelphij#endif 999285612Sdelphij 1000285612Sdelphij/* 1001285612Sdelphij * fstostr - prettyprint NTP seconds 1002285612Sdelphij */ 1003285612Sdelphijchar * fstostr( 1004285612Sdelphij time_t ntp_stamp 1005132451Sroberto ) 1006132451Sroberto{ 1007285612Sdelphij char * buf; 1008285612Sdelphij struct calendar tm; 1009132451Sroberto 1010285612Sdelphij LIB_GETBUF(buf); 1011285612Sdelphij if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0) 1012285612Sdelphij snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error", 1013285612Sdelphij (long)ntp_stamp); 1014285612Sdelphij else 1015285612Sdelphij snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d", 1016285612Sdelphij tm.year, tm.month, tm.monthday, 1017285612Sdelphij tm.hour, tm.minute); 1018285612Sdelphij return buf; 1019285612Sdelphij} 1020132451Sroberto 1021132451Sroberto 1022182007Sroberto/* 1023285612Sdelphij * ntpd_time_stepped is called back by step_systime(), allowing ntpd 1024285612Sdelphij * to do any one-time processing necessitated by the step. 1025182007Sroberto */ 1026182007Srobertovoid 1027285612Sdelphijntpd_time_stepped(void) 1028182007Sroberto{ 1029285612Sdelphij u_int saved_mon_enabled; 1030285612Sdelphij 1031285612Sdelphij /* 1032285612Sdelphij * flush the monitor MRU list which contains l_fp timestamps 1033285612Sdelphij * which should not be compared across the step. 1034285612Sdelphij */ 1035285612Sdelphij if (MON_OFF != mon_enabled) { 1036285612Sdelphij saved_mon_enabled = mon_enabled; 1037285612Sdelphij mon_stop(MON_OFF); 1038285612Sdelphij mon_start(saved_mon_enabled); 1039285612Sdelphij } 1040285612Sdelphij 1041285612Sdelphij /* inform interpolating Windows code to allow time to go back */ 1042285612Sdelphij#ifdef SYS_WINNT 1043285612Sdelphij win_time_stepped(); 1044285612Sdelphij#endif 1045182007Sroberto} 1046