1*eabc0478Schristos /* $NetBSD: ntp_util.c,v 1.11 2024/08/18 20:47:18 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * ntp_util.c - stuff I didn't have any other place for 5abb0f93cSkardel */ 6abb0f93cSkardel #ifdef HAVE_CONFIG_H 7abb0f93cSkardel # include <config.h> 8abb0f93cSkardel #endif 9abb0f93cSkardel 10abb0f93cSkardel #include "ntpd.h" 11abb0f93cSkardel #include "ntp_unixtime.h" 12abb0f93cSkardel #include "ntp_filegen.h" 13abb0f93cSkardel #include "ntp_if.h" 14abb0f93cSkardel #include "ntp_stdlib.h" 15abb0f93cSkardel #include "ntp_assert.h" 162950cc38Schristos #include "ntp_calendar.h" 172950cc38Schristos #include "ntp_leapsec.h" 18abb0f93cSkardel 19abb0f93cSkardel #include <stdio.h> 20abb0f93cSkardel #include <ctype.h> 21abb0f93cSkardel #include <sys/types.h> 22abb0f93cSkardel #ifdef HAVE_SYS_IOCTL_H 23abb0f93cSkardel # include <sys/ioctl.h> 24abb0f93cSkardel #endif 252950cc38Schristos #ifdef HAVE_UNISTD_H 262950cc38Schristos # include <unistd.h> 272950cc38Schristos #endif 282950cc38Schristos #include <sys/stat.h> 29abb0f93cSkardel 30abb0f93cSkardel #ifdef HAVE_IEEEFP_H 31abb0f93cSkardel # include <ieeefp.h> 32abb0f93cSkardel #endif 33abb0f93cSkardel #ifdef HAVE_MATH_H 34abb0f93cSkardel # include <math.h> 35abb0f93cSkardel #endif 36abb0f93cSkardel 37abb0f93cSkardel #if defined(VMS) 38abb0f93cSkardel # include <descrip.h> 39abb0f93cSkardel #endif /* VMS */ 40abb0f93cSkardel 41abb0f93cSkardel /* 42abb0f93cSkardel * Defines used by the leapseconds stuff 43abb0f93cSkardel */ 44abb0f93cSkardel #define MAX_TAI 100 /* max TAI offset (s) */ 45abb0f93cSkardel #define L_DAY 86400UL /* seconds per day */ 46abb0f93cSkardel #define L_YEAR (L_DAY * 365) /* days per year */ 47abb0f93cSkardel #define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */ 48abb0f93cSkardel #define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */ 49abb0f93cSkardel #define L_CENT (L_4YEAR * 25) /* days per century */ 50abb0f93cSkardel 51abb0f93cSkardel /* 52abb0f93cSkardel * This contains odds and ends, including the hourly stats, various 53abb0f93cSkardel * configuration items, leapseconds stuff, etc. 54abb0f93cSkardel */ 55abb0f93cSkardel /* 56abb0f93cSkardel * File names 57abb0f93cSkardel */ 58abb0f93cSkardel static char *key_file_name; /* keys file name */ 59ea66d795Schristos static char *leapfile_name; /* leapseconds file name */ 60ea66d795Schristos static struct stat leapfile_stat; /* leapseconds file stat() buffer */ 61ea66d795Schristos static int /*BOOL*/have_leapfile = FALSE; 62cdfa2a7eSchristos static int /*BOOL*/chck_leaphash = TRUE; 63abb0f93cSkardel char *stats_drift_file; /* frequency file name */ 64abb0f93cSkardel static char *stats_temp_file; /* temp frequency file name */ 652950cc38Schristos static double wander_resid; /* last frequency update */ 662950cc38Schristos double wander_threshold = 1e-7; /* initial frequency threshold */ 67abb0f93cSkardel 68abb0f93cSkardel /* 69abb0f93cSkardel * Statistics file stuff 70abb0f93cSkardel */ 71abb0f93cSkardel #ifndef NTP_VAR 72abb0f93cSkardel # ifndef SYS_WINNT 73abb0f93cSkardel # define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ 74abb0f93cSkardel # else 75abb0f93cSkardel # define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ 76abb0f93cSkardel # endif /* SYS_WINNT */ 77abb0f93cSkardel #endif 78abb0f93cSkardel 79abb0f93cSkardel 802950cc38Schristos char statsdir[MAXFILENAME] = NTP_VAR; 81abb0f93cSkardel static FILEGEN peerstats; 82abb0f93cSkardel static FILEGEN loopstats; 83abb0f93cSkardel static FILEGEN clockstats; 84abb0f93cSkardel static FILEGEN rawstats; 85abb0f93cSkardel static FILEGEN sysstats; 86abb0f93cSkardel static FILEGEN protostats; 872950cc38Schristos static FILEGEN cryptostats; 882950cc38Schristos static FILEGEN timingstats; 89abb0f93cSkardel 90abb0f93cSkardel /* 91abb0f93cSkardel * This controls whether stats are written to the fileset. Provided 92abb0f93cSkardel * so that ntpdc can turn off stats when the file system fills up. 93abb0f93cSkardel */ 94abb0f93cSkardel int stats_control; 95abb0f93cSkardel 96abb0f93cSkardel /* 972950cc38Schristos * Last frequency written to file. 98abb0f93cSkardel */ 99abb0f93cSkardel static double prev_drift_comp; /* last frequency update */ 100abb0f93cSkardel 101abb0f93cSkardel /* 1022950cc38Schristos * Function prototypes 103abb0f93cSkardel */ 104abb0f93cSkardel static void record_sys_stats(void); 1052950cc38Schristos void ntpd_time_stepped(void); 106ea66d795Schristos static void check_leap_expiration(int, uint32_t, const time_t*); 107abb0f93cSkardel 108abb0f93cSkardel /* 109abb0f93cSkardel * Prototypes 110abb0f93cSkardel */ 111abb0f93cSkardel #ifdef DEBUG 112abb0f93cSkardel void uninit_util(void); 113abb0f93cSkardel #endif 114abb0f93cSkardel 115abb0f93cSkardel /* 116abb0f93cSkardel * uninit_util - free memory allocated by init_util 117abb0f93cSkardel */ 118abb0f93cSkardel #ifdef DEBUG 119abb0f93cSkardel void 120abb0f93cSkardel uninit_util(void) 121abb0f93cSkardel { 122abb0f93cSkardel #if defined(_MSC_VER) && defined (_DEBUG) 123abb0f93cSkardel _CrtCheckMemory(); 124abb0f93cSkardel #endif 125abb0f93cSkardel if (stats_drift_file) { 126abb0f93cSkardel free(stats_drift_file); 127abb0f93cSkardel free(stats_temp_file); 128abb0f93cSkardel stats_drift_file = NULL; 129abb0f93cSkardel stats_temp_file = NULL; 130abb0f93cSkardel } 131abb0f93cSkardel if (key_file_name) { 132abb0f93cSkardel free(key_file_name); 133abb0f93cSkardel key_file_name = NULL; 134abb0f93cSkardel } 135abb0f93cSkardel filegen_unregister("peerstats"); 136abb0f93cSkardel filegen_unregister("loopstats"); 137abb0f93cSkardel filegen_unregister("clockstats"); 138abb0f93cSkardel filegen_unregister("rawstats"); 139abb0f93cSkardel filegen_unregister("sysstats"); 140abb0f93cSkardel filegen_unregister("protostats"); 1412950cc38Schristos #ifdef AUTOKEY 142abb0f93cSkardel filegen_unregister("cryptostats"); 1432950cc38Schristos #endif /* AUTOKEY */ 144abb0f93cSkardel #ifdef DEBUG_TIMING 145abb0f93cSkardel filegen_unregister("timingstats"); 146abb0f93cSkardel #endif /* DEBUG_TIMING */ 147abb0f93cSkardel 148abb0f93cSkardel #if defined(_MSC_VER) && defined (_DEBUG) 149abb0f93cSkardel _CrtCheckMemory(); 150abb0f93cSkardel #endif 151abb0f93cSkardel } 152abb0f93cSkardel #endif /* DEBUG */ 153abb0f93cSkardel 154abb0f93cSkardel 155abb0f93cSkardel /* 1562950cc38Schristos * init_util - initialize the util module of ntpd 157abb0f93cSkardel */ 158abb0f93cSkardel void 159abb0f93cSkardel init_util(void) 160abb0f93cSkardel { 161abb0f93cSkardel filegen_register(statsdir, "peerstats", &peerstats); 162abb0f93cSkardel filegen_register(statsdir, "loopstats", &loopstats); 163abb0f93cSkardel filegen_register(statsdir, "clockstats", &clockstats); 164abb0f93cSkardel filegen_register(statsdir, "rawstats", &rawstats); 165abb0f93cSkardel filegen_register(statsdir, "sysstats", &sysstats); 166abb0f93cSkardel filegen_register(statsdir, "protostats", &protostats); 167abb0f93cSkardel filegen_register(statsdir, "cryptostats", &cryptostats); 168abb0f93cSkardel filegen_register(statsdir, "timingstats", &timingstats); 1692950cc38Schristos /* 1702950cc38Schristos * register with libntp ntp_set_tod() to call us back 1712950cc38Schristos * when time is stepped. 1722950cc38Schristos */ 1732950cc38Schristos step_callback = &ntpd_time_stepped; 174abb0f93cSkardel #ifdef DEBUG 1752950cc38Schristos atexit(&uninit_util); 176abb0f93cSkardel #endif /* DEBUG */ 177abb0f93cSkardel } 178abb0f93cSkardel 179abb0f93cSkardel 180abb0f93cSkardel /* 181abb0f93cSkardel * hourly_stats - print some interesting stats 182abb0f93cSkardel */ 183abb0f93cSkardel void 184abb0f93cSkardel write_stats(void) 185abb0f93cSkardel { 186*eabc0478Schristos FILE *fp = NULL; 187abb0f93cSkardel #ifdef DOSYNCTODR 188abb0f93cSkardel struct timeval tv; 189abb0f93cSkardel #if !defined(VMS) 190abb0f93cSkardel int prio_set; 191abb0f93cSkardel #endif 192abb0f93cSkardel #ifdef HAVE_GETCLOCK 193abb0f93cSkardel struct timespec ts; 194abb0f93cSkardel #endif 195abb0f93cSkardel int o_prio; 196abb0f93cSkardel 197abb0f93cSkardel /* 198abb0f93cSkardel * Sometimes having a Sun can be a drag. 199abb0f93cSkardel * 200abb0f93cSkardel * The kernel variable dosynctodr controls whether the system's 201abb0f93cSkardel * soft clock is kept in sync with the battery clock. If it 202abb0f93cSkardel * is zero, then the soft clock is not synced, and the battery 203abb0f93cSkardel * clock is simply left to rot. That means that when the system 204abb0f93cSkardel * reboots, the battery clock (which has probably gone wacky) 205abb0f93cSkardel * sets the soft clock. That means ntpd starts off with a very 206abb0f93cSkardel * confused idea of what time it is. It then takes a large 207abb0f93cSkardel * amount of time to figure out just how wacky the battery clock 208abb0f93cSkardel * has made things drift, etc, etc. The solution is to make the 209abb0f93cSkardel * battery clock sync up to system time. The way to do THAT is 210abb0f93cSkardel * to simply set the time of day to the current time of day, but 211abb0f93cSkardel * as quickly as possible. This may, or may not be a sensible 212abb0f93cSkardel * thing to do. 213abb0f93cSkardel * 214abb0f93cSkardel * CAVEAT: settimeofday() steps the sun clock by about 800 us, 215abb0f93cSkardel * so setting DOSYNCTODR seems a bad idea in the 216abb0f93cSkardel * case of us resolution 217abb0f93cSkardel */ 218abb0f93cSkardel 219abb0f93cSkardel #if !defined(VMS) 220abb0f93cSkardel /* 221abb0f93cSkardel * (prr) getpriority returns -1 on error, but -1 is also a valid 222abb0f93cSkardel * return value (!), so instead we have to zero errno before the 223abb0f93cSkardel * call and check it for non-zero afterwards. 224abb0f93cSkardel */ 225abb0f93cSkardel errno = 0; 226abb0f93cSkardel prio_set = 0; 227abb0f93cSkardel o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ 228abb0f93cSkardel 229abb0f93cSkardel /* 230abb0f93cSkardel * (prr) if getpriority succeeded, call setpriority to raise 231abb0f93cSkardel * scheduling priority as high as possible. If that succeeds 232abb0f93cSkardel * as well, set the prio_set flag so we remember to reset 233abb0f93cSkardel * priority to its previous value below. Note that on Solaris 234abb0f93cSkardel * 2.6 (and beyond?), both getpriority and setpriority will fail 235abb0f93cSkardel * with ESRCH, because sched_setscheduler (called from main) put 236abb0f93cSkardel * us in the real-time scheduling class which setpriority 237abb0f93cSkardel * doesn't know about. Being in the real-time class is better 238abb0f93cSkardel * than anything setpriority can do, anyhow, so this error is 239abb0f93cSkardel * silently ignored. 240abb0f93cSkardel */ 241abb0f93cSkardel if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) 242abb0f93cSkardel prio_set = 1; /* overdrive */ 243abb0f93cSkardel #endif /* VMS */ 244abb0f93cSkardel #ifdef HAVE_GETCLOCK 245abb0f93cSkardel (void) getclock(TIMEOFDAY, &ts); 246abb0f93cSkardel tv.tv_sec = ts.tv_sec; 247abb0f93cSkardel tv.tv_usec = ts.tv_nsec / 1000; 248abb0f93cSkardel #else /* not HAVE_GETCLOCK */ 249abb0f93cSkardel GETTIMEOFDAY(&tv,(struct timezone *)NULL); 250abb0f93cSkardel #endif /* not HAVE_GETCLOCK */ 251abb0f93cSkardel if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) 252abb0f93cSkardel msyslog(LOG_ERR, "can't sync battery time: %m"); 253abb0f93cSkardel #if !defined(VMS) 254abb0f93cSkardel if (prio_set) 255abb0f93cSkardel setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ 256abb0f93cSkardel #endif /* VMS */ 257abb0f93cSkardel #endif /* DOSYNCTODR */ 258abb0f93cSkardel record_sys_stats(); 2592950cc38Schristos if (stats_drift_file != 0) { 260abb0f93cSkardel 261abb0f93cSkardel /* 262abb0f93cSkardel * When the frequency file is written, initialize the 2632950cc38Schristos * prev_drift_comp and wander_resid. Thereafter, 2642950cc38Schristos * reduce the wander_resid by half each hour. When 2652950cc38Schristos * the difference between the prev_drift_comp and 2662950cc38Schristos * drift_comp is less than the wander_resid, update 2672950cc38Schristos * the frequncy file. This minimizes the file writes to 2682950cc38Schristos * nonvolaile storage. 269abb0f93cSkardel */ 270*eabc0478Schristos DPRINTF(1, ("write_stats: frequency %.6f thresh %.6f, freq %.6f\n", 2712950cc38Schristos (prev_drift_comp - drift_comp) * 1e6, wander_resid * 272*eabc0478Schristos 1e6, drift_comp * 1e6)); 273*eabc0478Schristos 2742950cc38Schristos if (fabs(prev_drift_comp - drift_comp) < wander_resid) { 2752950cc38Schristos wander_resid *= 0.5; 2762950cc38Schristos return; 2772950cc38Schristos } 2782950cc38Schristos prev_drift_comp = drift_comp; 279abb0f93cSkardel wander_resid = wander_threshold; 2802950cc38Schristos if ((fp = fopen(stats_temp_file, "w")) == NULL) { 2812950cc38Schristos msyslog(LOG_ERR, "frequency file %s: %m", 282abb0f93cSkardel stats_temp_file); 283abb0f93cSkardel return; 284abb0f93cSkardel } 285*eabc0478Schristos fprintf(fp, "%.6f\n", drift_comp * 1e6); 286abb0f93cSkardel (void)fclose(fp); 287abb0f93cSkardel /* atomic */ 288abb0f93cSkardel #ifdef SYS_WINNT 289abb0f93cSkardel if (_unlink(stats_drift_file)) /* rename semantics differ under NT */ 290abb0f93cSkardel msyslog(LOG_WARNING, 291abb0f93cSkardel "Unable to remove prior drift file %s, %m", 292abb0f93cSkardel stats_drift_file); 293abb0f93cSkardel #endif /* SYS_WINNT */ 294abb0f93cSkardel 295abb0f93cSkardel #ifndef NO_RENAME 296abb0f93cSkardel if (rename(stats_temp_file, stats_drift_file)) 297abb0f93cSkardel msyslog(LOG_WARNING, 298abb0f93cSkardel "Unable to rename temp drift file %s to %s, %m", 299abb0f93cSkardel stats_temp_file, stats_drift_file); 300abb0f93cSkardel #else 301abb0f93cSkardel /* we have no rename NFS of ftp in use */ 302abb0f93cSkardel if ((fp = fopen(stats_drift_file, "w")) == 303abb0f93cSkardel NULL) { 304abb0f93cSkardel msyslog(LOG_ERR, 305abb0f93cSkardel "frequency file %s: %m", 306abb0f93cSkardel stats_drift_file); 307abb0f93cSkardel return; 308abb0f93cSkardel } 309abb0f93cSkardel #endif 310abb0f93cSkardel 311abb0f93cSkardel #if defined(VMS) 312abb0f93cSkardel /* PURGE */ 313abb0f93cSkardel { 314abb0f93cSkardel $DESCRIPTOR(oldvers,";-1"); 315abb0f93cSkardel struct dsc$descriptor driftdsc = { 316abb0f93cSkardel strlen(stats_drift_file), 0, 0, 317abb0f93cSkardel stats_drift_file }; 318abb0f93cSkardel while(lib$delete_file(&oldvers, 319abb0f93cSkardel &driftdsc) & 1); 320abb0f93cSkardel } 321abb0f93cSkardel #endif 322abb0f93cSkardel } 323abb0f93cSkardel } 324abb0f93cSkardel 325abb0f93cSkardel 326abb0f93cSkardel /* 327*eabc0478Schristos * If an option was given on the command line make sure it takes 328*eabc0478Schristos * precedence over the configuration file, as command-line options 329*eabc0478Schristos * are processed first. Similarly, if an option is given in the 330*eabc0478Schristos * configuration file, do not allow it to be overridden with runtime 331*eabc0478Schristos * configuration. Done by simply remembering an option was already 332*eabc0478Schristos * seen. 333*eabc0478Schristos */ 334*eabc0478Schristos static int 335*eabc0478Schristos allow_config( 336*eabc0478Schristos u_int option, 337*eabc0478Schristos int/*BOOL*/ cmdopt 338*eabc0478Schristos ) 339*eabc0478Schristos { 340*eabc0478Schristos static u_int seen = 0; /* stat options previously set */ 341*eabc0478Schristos u_int mask; 342*eabc0478Schristos int retv; 343*eabc0478Schristos 344*eabc0478Schristos if (cmdopt) { 345*eabc0478Schristos DEBUG_REQUIRE(option < sizeof(mask) * 8); 346*eabc0478Schristos mask = 1u << option; 347*eabc0478Schristos retv = !(seen & mask); 348*eabc0478Schristos seen |= mask; 349*eabc0478Schristos } else { 350*eabc0478Schristos retv = FALSE; 351*eabc0478Schristos } 352*eabc0478Schristos return retv; 353*eabc0478Schristos } 354*eabc0478Schristos 355*eabc0478Schristos 356*eabc0478Schristos /* 357abb0f93cSkardel * stats_config - configure the stats operation 358abb0f93cSkardel */ 359abb0f93cSkardel void 360abb0f93cSkardel stats_config( 361abb0f93cSkardel int item, 362cdfa2a7eSchristos const char *invalue, /* only one type so far */ 363cdfa2a7eSchristos int optflag 364abb0f93cSkardel ) 365abb0f93cSkardel { 366*eabc0478Schristos FILE *fp = NULL; 367abb0f93cSkardel const char *value; 3688b8da087Schristos size_t len; 3692950cc38Schristos double old_drift; 3702950cc38Schristos l_fp now; 371ea66d795Schristos time_t ttnow; 372*eabc0478Schristos char dirsep_or_nul; 373f4ffd55aSplunky #ifndef VMS 374*eabc0478Schristos static const char temp_ext[] = ".TEMP"; 375f4ffd55aSplunky #else 376*eabc0478Schristos static const char temp_ext[] = "-TEMP"; 377f4ffd55aSplunky #endif 378abb0f93cSkardel 379abb0f93cSkardel /* 380abb0f93cSkardel * Expand environment strings under Windows NT, since the 381abb0f93cSkardel * command interpreter doesn't do this, the program must. 382abb0f93cSkardel */ 383abb0f93cSkardel #ifdef SYS_WINNT 384abb0f93cSkardel char newvalue[MAX_PATH], parameter[MAX_PATH]; 385abb0f93cSkardel 386abb0f93cSkardel if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { 387abb0f93cSkardel switch (item) { 388abb0f93cSkardel case STATS_FREQ_FILE: 3892950cc38Schristos strlcpy(parameter, "STATS_FREQ_FILE", 3902950cc38Schristos sizeof(parameter)); 391abb0f93cSkardel break; 392abb0f93cSkardel 393abb0f93cSkardel case STATS_LEAP_FILE: 3942950cc38Schristos strlcpy(parameter, "STATS_LEAP_FILE", 3952950cc38Schristos sizeof(parameter)); 396abb0f93cSkardel break; 397abb0f93cSkardel 398abb0f93cSkardel case STATS_STATSDIR: 3992950cc38Schristos strlcpy(parameter, "STATS_STATSDIR", 4002950cc38Schristos sizeof(parameter)); 401abb0f93cSkardel break; 402abb0f93cSkardel 403abb0f93cSkardel case STATS_PID_FILE: 4042950cc38Schristos strlcpy(parameter, "STATS_PID_FILE", 4052950cc38Schristos sizeof(parameter)); 406abb0f93cSkardel break; 407abb0f93cSkardel 408abb0f93cSkardel default: 4092950cc38Schristos strlcpy(parameter, "UNKNOWN", 4102950cc38Schristos sizeof(parameter)); 411abb0f93cSkardel break; 412abb0f93cSkardel } 413abb0f93cSkardel value = invalue; 414abb0f93cSkardel msyslog(LOG_ERR, 415abb0f93cSkardel "ExpandEnvironmentStrings(%s) failed: %m\n", 416abb0f93cSkardel parameter); 417abb0f93cSkardel } else { 418abb0f93cSkardel value = newvalue; 419abb0f93cSkardel } 420abb0f93cSkardel #else 421abb0f93cSkardel value = invalue; 422abb0f93cSkardel #endif /* SYS_WINNT */ 423abb0f93cSkardel 424abb0f93cSkardel switch (item) { 425abb0f93cSkardel 426abb0f93cSkardel /* 427abb0f93cSkardel * Open and read frequency file. 428abb0f93cSkardel */ 429abb0f93cSkardel case STATS_FREQ_FILE: 430*eabc0478Schristos if (!allow_config(STATS_FREQ_FILE, optflag)) { 431abb0f93cSkardel break; 432*eabc0478Schristos } 433*eabc0478Schristos if (!value || 0 == (len = strlen(value))) { 434*eabc0478Schristos free(stats_drift_file); 435*eabc0478Schristos free(stats_temp_file); 436*eabc0478Schristos stats_drift_file = stats_temp_file = NULL; 437*eabc0478Schristos } else { 438*eabc0478Schristos stats_drift_file = erealloc(stats_drift_file, 439*eabc0478Schristos 1 + len); 440abb0f93cSkardel stats_temp_file = erealloc(stats_temp_file, 441*eabc0478Schristos len + sizeof(temp_ext)); 442*eabc0478Schristos memcpy(stats_drift_file, value, 1 + len); 443*eabc0478Schristos memcpy(stats_temp_file, value, len); 444*eabc0478Schristos memcpy(stats_temp_file + len, temp_ext, 445*eabc0478Schristos sizeof(temp_ext)); 446*eabc0478Schristos } 447abb0f93cSkardel 448abb0f93cSkardel /* 449abb0f93cSkardel * Open drift file and read frequency. If the file is 450abb0f93cSkardel * missing or contains errors, tell the loop to reset. 451abb0f93cSkardel */ 452*eabc0478Schristos if (NULL == stats_drift_file) { 453*eabc0478Schristos goto nofreq; 454*eabc0478Schristos } else if ((fp = fopen(stats_drift_file, "r")) == NULL) { 455*eabc0478Schristos if (errno != ENOENT) { 456*eabc0478Schristos msyslog(LOG_WARNING, 457*eabc0478Schristos "cannot read frequency file %s: %m", 458*eabc0478Schristos stats_drift_file); 459*eabc0478Schristos } 460*eabc0478Schristos goto nofreq; 461*eabc0478Schristos } else if (fscanf(fp, "%lf", &old_drift) != 1) { 462abb0f93cSkardel msyslog(LOG_ERR, 463abb0f93cSkardel "format error frequency file %s", 464abb0f93cSkardel stats_drift_file); 465*eabc0478Schristos nofreq: 466*eabc0478Schristos prev_drift_comp = 0.0; 467*eabc0478Schristos loop_config(LOOP_NOFREQ, prev_drift_comp); 468*eabc0478Schristos } else { 4692950cc38Schristos loop_config(LOOP_FREQ, old_drift); 4702950cc38Schristos prev_drift_comp = drift_comp; 471*eabc0478Schristos msyslog(LOG_INFO, 472*eabc0478Schristos "initial drift restored to %.6f", 473*eabc0478Schristos old_drift); 474*eabc0478Schristos } 475*eabc0478Schristos if (NULL != fp) { 476*eabc0478Schristos fclose(fp); 477*eabc0478Schristos } 478abb0f93cSkardel break; 479abb0f93cSkardel 480abb0f93cSkardel /* 481abb0f93cSkardel * Specify statistics directory. 482abb0f93cSkardel */ 483abb0f93cSkardel case STATS_STATSDIR: 484*eabc0478Schristos if (!allow_config(STATS_STATSDIR, optflag)) { 485*eabc0478Schristos break; 486abb0f93cSkardel } 487*eabc0478Schristos /* - 2 since value may be missing the DIR_SEP. */ 488*eabc0478Schristos len = strlen(value); 489*eabc0478Schristos if (len > sizeof(statsdir) - 2) { 490*eabc0478Schristos msyslog(LOG_ERR, 491*eabc0478Schristos "statsdir %s too long (>%u)", value, 492*eabc0478Schristos (u_int)sizeof(statsdir) - 2); 493*eabc0478Schristos break; 494*eabc0478Schristos } 495*eabc0478Schristos /* Add a DIR_SEP unless we already have one. */ 496*eabc0478Schristos if (0 == len || DIR_SEP == value[len - 1]) { 497*eabc0478Schristos dirsep_or_nul = '\0'; 498*eabc0478Schristos } else { 499*eabc0478Schristos dirsep_or_nul = DIR_SEP; 500*eabc0478Schristos } 501*eabc0478Schristos snprintf(statsdir, sizeof(statsdir), "%s%c", 502*eabc0478Schristos value, dirsep_or_nul); 503*eabc0478Schristos filegen_statsdir(); 504abb0f93cSkardel break; 505abb0f93cSkardel 506abb0f93cSkardel /* 507*eabc0478Schristos * Write pid file. 508abb0f93cSkardel */ 509abb0f93cSkardel case STATS_PID_FILE: 510*eabc0478Schristos if (!allow_config(STATS_PID_FILE, optflag)) { 511abb0f93cSkardel break; 512abb0f93cSkardel } 513*eabc0478Schristos if ((fp = fopen(value, "w")) == NULL) { 514*eabc0478Schristos msyslog(LOG_ERR, "pid file %s: %m", value); 515*eabc0478Schristos break; 516*eabc0478Schristos } 517*eabc0478Schristos fprintf(fp, "%ld", (long)getpid()); 518ea66d795Schristos fclose(fp); 519abb0f93cSkardel break; 520abb0f93cSkardel 521abb0f93cSkardel /* 522abb0f93cSkardel * Read leapseconds file. 523ea66d795Schristos * 524*eabc0478Schristos * By default a leap file without SHA1 signature is accepted, 525*eabc0478Schristos * but if there is a signature line, the signature must be 526*eabc0478Schristos * valid or the leapfile line in ntp.conf must have ignorehash. 527abb0f93cSkardel */ 528abb0f93cSkardel case STATS_LEAP_FILE: 529*eabc0478Schristos if (NULL == value || 0 == (len = strlen(value))) { 5302950cc38Schristos break; 531*eabc0478Schristos } 532ea66d795Schristos leapfile_name = erealloc(leapfile_name, len + 1); 533ea66d795Schristos memcpy(leapfile_name, value, len + 1); 534cdfa2a7eSchristos chck_leaphash = optflag; 5352950cc38Schristos 536ea66d795Schristos if (leapsec_load_file( 537cdfa2a7eSchristos leapfile_name, &leapfile_stat, 538*eabc0478Schristos TRUE, TRUE, chck_leaphash)) { 5392950cc38Schristos leap_signature_t lsig; 5402950cc38Schristos 5412950cc38Schristos get_systime(&now); 542ea66d795Schristos time(&ttnow); 543ea66d795Schristos leapsec_getsig(&lsig); 5442950cc38Schristos mprintf_event(EVNT_TAI, NULL, 545*eabc0478Schristos "%d leap %s expire%s %s", 5462950cc38Schristos lsig.taiof, 5472950cc38Schristos fstostr(lsig.ttime), 5482950cc38Schristos leapsec_expired(now.l_ui, NULL) 549*eabc0478Schristos ? "d" 550*eabc0478Schristos : "s", 5512950cc38Schristos fstostr(lsig.etime)); 552ea66d795Schristos 553ea66d795Schristos have_leapfile = TRUE; 554ea66d795Schristos 555ea66d795Schristos /* force an immediate daily expiration check of 556ea66d795Schristos * the leap seconds table 557ea66d795Schristos */ 558ea66d795Schristos check_leap_expiration(TRUE, now.l_ui, &ttnow); 559abb0f93cSkardel } 560abb0f93cSkardel break; 561abb0f93cSkardel 562abb0f93cSkardel default: 563abb0f93cSkardel /* oh well */ 564abb0f93cSkardel break; 565abb0f93cSkardel } 566abb0f93cSkardel } 567abb0f93cSkardel 568abb0f93cSkardel 569abb0f93cSkardel /* 570abb0f93cSkardel * record_peer_stats - write peer statistics to file 571abb0f93cSkardel * 572abb0f93cSkardel * file format: 573abb0f93cSkardel * day (MJD) 574abb0f93cSkardel * time (s past UTC midnight) 575abb0f93cSkardel * IP address 576abb0f93cSkardel * status word (hex) 577abb0f93cSkardel * offset 578abb0f93cSkardel * delay 579abb0f93cSkardel * dispersion 580abb0f93cSkardel * jitter 581abb0f93cSkardel */ 582abb0f93cSkardel void 583abb0f93cSkardel record_peer_stats( 584abb0f93cSkardel sockaddr_u * addr, 585abb0f93cSkardel int status, 586*eabc0478Schristos double offset, 587*eabc0478Schristos double delay, 588*eabc0478Schristos double dispersion, 589*eabc0478Schristos double jitter 590abb0f93cSkardel ) 591abb0f93cSkardel { 592abb0f93cSkardel l_fp now; 593abb0f93cSkardel u_long day; 594abb0f93cSkardel 595*eabc0478Schristos if (!stats_control) { 596abb0f93cSkardel return; 597*eabc0478Schristos } 598abb0f93cSkardel get_systime(&now); 599abb0f93cSkardel filegen_setup(&peerstats, now.l_ui); 600*eabc0478Schristos if (NULL == peerstats.fp) { 601*eabc0478Schristos return; 602*eabc0478Schristos } 603abb0f93cSkardel day = now.l_ui / 86400 + MJD_1900; 604abb0f93cSkardel now.l_ui %= 86400; 605abb0f93cSkardel fprintf(peerstats.fp, 606abb0f93cSkardel "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, 607abb0f93cSkardel ulfptoa(&now, 3), stoa(addr), status, offset, 608abb0f93cSkardel delay, dispersion, jitter); 609abb0f93cSkardel fflush(peerstats.fp); 610abb0f93cSkardel } 611abb0f93cSkardel 612abb0f93cSkardel 613abb0f93cSkardel /* 614abb0f93cSkardel * record_loop_stats - write loop filter statistics to file 615abb0f93cSkardel * 616abb0f93cSkardel * file format: 617abb0f93cSkardel * day (MJD) 618abb0f93cSkardel * time (s past midnight) 619abb0f93cSkardel * offset 620abb0f93cSkardel * frequency (PPM) 621abb0f93cSkardel * jitter 622abb0f93cSkardel * wnder (PPM) 623abb0f93cSkardel * time constant (log2) 624abb0f93cSkardel */ 625abb0f93cSkardel void 626abb0f93cSkardel record_loop_stats( 627abb0f93cSkardel double offset, /* offset */ 628abb0f93cSkardel double freq, /* frequency (PPM) */ 629abb0f93cSkardel double jitter, /* jitter */ 630abb0f93cSkardel double wander, /* wander (PPM) */ 631abb0f93cSkardel int spoll 632abb0f93cSkardel ) 633abb0f93cSkardel { 634abb0f93cSkardel l_fp now; 635abb0f93cSkardel u_long day; 636abb0f93cSkardel 637abb0f93cSkardel if (!stats_control) 638abb0f93cSkardel return; 639abb0f93cSkardel 640abb0f93cSkardel get_systime(&now); 641abb0f93cSkardel filegen_setup(&loopstats, now.l_ui); 642abb0f93cSkardel day = now.l_ui / 86400 + MJD_1900; 643abb0f93cSkardel now.l_ui %= 86400; 644abb0f93cSkardel if (loopstats.fp != NULL) { 645abb0f93cSkardel fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", 646abb0f93cSkardel day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, 647abb0f93cSkardel wander * 1e6, spoll); 648abb0f93cSkardel fflush(loopstats.fp); 649abb0f93cSkardel } 650abb0f93cSkardel } 651abb0f93cSkardel 652abb0f93cSkardel 653abb0f93cSkardel /* 654abb0f93cSkardel * record_clock_stats - write clock statistics to file 655abb0f93cSkardel * 656abb0f93cSkardel * file format: 657abb0f93cSkardel * day (MJD) 658abb0f93cSkardel * time (s past midnight) 659abb0f93cSkardel * IP address 660abb0f93cSkardel * text message 661abb0f93cSkardel */ 662abb0f93cSkardel void 663abb0f93cSkardel record_clock_stats( 664abb0f93cSkardel sockaddr_u *addr, 665abb0f93cSkardel const char *text /* timecode string */ 666abb0f93cSkardel ) 667abb0f93cSkardel { 668abb0f93cSkardel l_fp now; 669abb0f93cSkardel u_long day; 670abb0f93cSkardel 671abb0f93cSkardel if (!stats_control) 672abb0f93cSkardel return; 673abb0f93cSkardel 674abb0f93cSkardel get_systime(&now); 675abb0f93cSkardel filegen_setup(&clockstats, now.l_ui); 676abb0f93cSkardel day = now.l_ui / 86400 + MJD_1900; 677abb0f93cSkardel now.l_ui %= 86400; 678abb0f93cSkardel if (clockstats.fp != NULL) { 679abb0f93cSkardel fprintf(clockstats.fp, "%lu %s %s %s\n", day, 680abb0f93cSkardel ulfptoa(&now, 3), stoa(addr), text); 681abb0f93cSkardel fflush(clockstats.fp); 682abb0f93cSkardel } 683abb0f93cSkardel } 684abb0f93cSkardel 685abb0f93cSkardel 686abb0f93cSkardel /* 6872950cc38Schristos * mprintf_clock_stats - write clock statistics to file with 6882950cc38Schristos * msnprintf-style formatting. 6892950cc38Schristos */ 6902950cc38Schristos int 6912950cc38Schristos mprintf_clock_stats( 6922950cc38Schristos sockaddr_u *addr, 6932950cc38Schristos const char *fmt, 6942950cc38Schristos ... 6952950cc38Schristos ) 6962950cc38Schristos { 6972950cc38Schristos va_list ap; 6982950cc38Schristos int rc; 6992950cc38Schristos char msg[512]; 7002950cc38Schristos 7012950cc38Schristos va_start(ap, fmt); 7022950cc38Schristos rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 7032950cc38Schristos va_end(ap); 7042950cc38Schristos if (stats_control) 7052950cc38Schristos record_clock_stats(addr, msg); 7062950cc38Schristos 7072950cc38Schristos return rc; 7082950cc38Schristos } 7092950cc38Schristos 7102950cc38Schristos /* 711abb0f93cSkardel * record_raw_stats - write raw timestamps to file 712abb0f93cSkardel * 713abb0f93cSkardel * file format 714abb0f93cSkardel * day (MJD) 715abb0f93cSkardel * time (s past midnight) 716abb0f93cSkardel * peer ip address 717abb0f93cSkardel * IP address 718abb0f93cSkardel * t1 t2 t3 t4 timestamps 7194eea345dSchristos * leap, version, mode, stratum, ppoll, precision, root delay, root dispersion, REFID 7204eea345dSchristos * length and hex dump of any EFs and any legacy MAC. 721abb0f93cSkardel */ 722abb0f93cSkardel void 723abb0f93cSkardel record_raw_stats( 724abb0f93cSkardel sockaddr_u *srcadr, 725abb0f93cSkardel sockaddr_u *dstadr, 726abb0f93cSkardel l_fp *t1, /* originate timestamp */ 727abb0f93cSkardel l_fp *t2, /* receive timestamp */ 728abb0f93cSkardel l_fp *t3, /* transmit timestamp */ 7292950cc38Schristos l_fp *t4, /* destination timestamp */ 7302950cc38Schristos int leap, 7312950cc38Schristos int version, 7322950cc38Schristos int mode, 7332950cc38Schristos int stratum, 7347476e6e4Schristos int ppoll, 7352950cc38Schristos int precision, 7362950cc38Schristos double root_delay, /* seconds */ 7372950cc38Schristos double root_dispersion,/* seconds */ 7384eea345dSchristos u_int32 refid, 7394eea345dSchristos int len, 7404eea345dSchristos u_char *extra 741abb0f93cSkardel ) 742abb0f93cSkardel { 743abb0f93cSkardel l_fp now; 744abb0f93cSkardel u_long day; 745abb0f93cSkardel 746abb0f93cSkardel if (!stats_control) 747abb0f93cSkardel return; 748abb0f93cSkardel 749*eabc0478Schristos /* 750*eabc0478Schristos * Mode 6 and mode 7 packets do not have the format of normal 751*eabc0478Schristos * NTP packets and will log garbage. So don't. [Bug 3774] 752*eabc0478Schristos */ 753*eabc0478Schristos if (MODE_CONTROL == mode || MODE_PRIVATE == mode) 754*eabc0478Schristos return; 755*eabc0478Schristos 756abb0f93cSkardel get_systime(&now); 757abb0f93cSkardel filegen_setup(&rawstats, now.l_ui); 758abb0f93cSkardel day = now.l_ui / 86400 + MJD_1900; 759abb0f93cSkardel now.l_ui %= 86400; 760abb0f93cSkardel if (rawstats.fp != NULL) { 7614eea345dSchristos fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s", 7622950cc38Schristos day, ulfptoa(&now, 3), 7634eea345dSchristos srcadr ? stoa(srcadr) : "-", 7644eea345dSchristos dstadr ? stoa(dstadr) : "-", 7652950cc38Schristos ulfptoa(t1, 9), ulfptoa(t2, 9), 7662950cc38Schristos ulfptoa(t3, 9), ulfptoa(t4, 9), 7677476e6e4Schristos leap, version, mode, stratum, ppoll, precision, 7682950cc38Schristos root_delay, root_dispersion, refid_str(refid, stratum)); 7694eea345dSchristos if (len > 0) { 7704eea345dSchristos int i; 7714eea345dSchristos 7724eea345dSchristos fprintf(rawstats.fp, " %d: ", len); 7734eea345dSchristos for (i = 0; i < len; ++i) { 7744eea345dSchristos fprintf(rawstats.fp, "%02x", extra[i]); 7754eea345dSchristos } 7764eea345dSchristos } 7774eea345dSchristos fprintf(rawstats.fp, "\n"); 778abb0f93cSkardel fflush(rawstats.fp); 779abb0f93cSkardel } 780abb0f93cSkardel } 781abb0f93cSkardel 782abb0f93cSkardel 783abb0f93cSkardel /* 784abb0f93cSkardel * record_sys_stats - write system statistics to file 785abb0f93cSkardel * 786abb0f93cSkardel * file format 787abb0f93cSkardel * day (MJD) 788abb0f93cSkardel * time (s past midnight) 789abb0f93cSkardel * time since reset 790abb0f93cSkardel * packets recieved 791abb0f93cSkardel * packets for this host 792abb0f93cSkardel * current version 793abb0f93cSkardel * old version 794abb0f93cSkardel * access denied 795abb0f93cSkardel * bad length or format 796abb0f93cSkardel * bad authentication 797abb0f93cSkardel * declined 798abb0f93cSkardel * rate exceeded 799abb0f93cSkardel * KoD sent 800abb0f93cSkardel */ 801abb0f93cSkardel void 802abb0f93cSkardel record_sys_stats(void) 803abb0f93cSkardel { 804abb0f93cSkardel l_fp now; 805abb0f93cSkardel u_long day; 806abb0f93cSkardel 807abb0f93cSkardel if (!stats_control) 808abb0f93cSkardel return; 809abb0f93cSkardel 810abb0f93cSkardel get_systime(&now); 811abb0f93cSkardel filegen_setup(&sysstats, now.l_ui); 812abb0f93cSkardel day = now.l_ui / 86400 + MJD_1900; 813abb0f93cSkardel now.l_ui %= 86400; 814abb0f93cSkardel if (sysstats.fp != NULL) { 815abb0f93cSkardel fprintf(sysstats.fp, 816abb0f93cSkardel "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 817abb0f93cSkardel day, ulfptoa(&now, 3), current_time - sys_stattime, 818abb0f93cSkardel sys_received, sys_processed, sys_newversion, 819abb0f93cSkardel sys_oldversion, sys_restricted, sys_badlength, 820abb0f93cSkardel sys_badauth, sys_declined, sys_limitrejected, 821abb0f93cSkardel sys_kodsent); 822abb0f93cSkardel fflush(sysstats.fp); 823abb0f93cSkardel proto_clr_stats(); 824abb0f93cSkardel } 825abb0f93cSkardel } 826abb0f93cSkardel 827abb0f93cSkardel 828abb0f93cSkardel /* 829abb0f93cSkardel * record_proto_stats - write system statistics to file 830abb0f93cSkardel * 831abb0f93cSkardel * file format 832abb0f93cSkardel * day (MJD) 833abb0f93cSkardel * time (s past midnight) 834abb0f93cSkardel * text message 835abb0f93cSkardel */ 836abb0f93cSkardel void 837abb0f93cSkardel record_proto_stats( 838abb0f93cSkardel char *str /* text string */ 839abb0f93cSkardel ) 840abb0f93cSkardel { 841abb0f93cSkardel l_fp now; 842abb0f93cSkardel u_long day; 843abb0f93cSkardel 844abb0f93cSkardel if (!stats_control) 845abb0f93cSkardel return; 846abb0f93cSkardel 847abb0f93cSkardel get_systime(&now); 848abb0f93cSkardel filegen_setup(&protostats, now.l_ui); 849abb0f93cSkardel day = now.l_ui / 86400 + MJD_1900; 850abb0f93cSkardel now.l_ui %= 86400; 851abb0f93cSkardel if (protostats.fp != NULL) { 852abb0f93cSkardel fprintf(protostats.fp, "%lu %s %s\n", day, 853abb0f93cSkardel ulfptoa(&now, 3), str); 854abb0f93cSkardel fflush(protostats.fp); 855abb0f93cSkardel } 856abb0f93cSkardel } 857abb0f93cSkardel 858abb0f93cSkardel 8592950cc38Schristos #ifdef AUTOKEY 860abb0f93cSkardel /* 861abb0f93cSkardel * record_crypto_stats - write crypto statistics to file 862abb0f93cSkardel * 863abb0f93cSkardel * file format: 864abb0f93cSkardel * day (mjd) 865abb0f93cSkardel * time (s past midnight) 866abb0f93cSkardel * peer ip address 867abb0f93cSkardel * text message 868abb0f93cSkardel */ 869abb0f93cSkardel void 870abb0f93cSkardel record_crypto_stats( 871abb0f93cSkardel sockaddr_u *addr, 872abb0f93cSkardel const char *text /* text message */ 873abb0f93cSkardel ) 874abb0f93cSkardel { 875abb0f93cSkardel l_fp now; 876abb0f93cSkardel u_long day; 877abb0f93cSkardel 878abb0f93cSkardel if (!stats_control) 879abb0f93cSkardel return; 880abb0f93cSkardel 881abb0f93cSkardel get_systime(&now); 882abb0f93cSkardel filegen_setup(&cryptostats, now.l_ui); 883abb0f93cSkardel day = now.l_ui / 86400 + MJD_1900; 884abb0f93cSkardel now.l_ui %= 86400; 885abb0f93cSkardel if (cryptostats.fp != NULL) { 886abb0f93cSkardel if (addr == NULL) 887abb0f93cSkardel fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", 888abb0f93cSkardel day, ulfptoa(&now, 3), text); 889abb0f93cSkardel else 890abb0f93cSkardel fprintf(cryptostats.fp, "%lu %s %s %s\n", 891abb0f93cSkardel day, ulfptoa(&now, 3), stoa(addr), text); 892abb0f93cSkardel fflush(cryptostats.fp); 893abb0f93cSkardel } 894abb0f93cSkardel } 8952950cc38Schristos #endif /* AUTOKEY */ 896abb0f93cSkardel 897abb0f93cSkardel 898abb0f93cSkardel #ifdef DEBUG_TIMING 899abb0f93cSkardel /* 900abb0f93cSkardel * record_timing_stats - write timing statistics to file 901abb0f93cSkardel * 902abb0f93cSkardel * file format: 903abb0f93cSkardel * day (mjd) 904abb0f93cSkardel * time (s past midnight) 905abb0f93cSkardel * text message 906abb0f93cSkardel */ 907abb0f93cSkardel void 908abb0f93cSkardel record_timing_stats( 909abb0f93cSkardel const char *text /* text message */ 910abb0f93cSkardel ) 911abb0f93cSkardel { 912abb0f93cSkardel static unsigned int flshcnt; 913abb0f93cSkardel l_fp now; 914abb0f93cSkardel u_long day; 915abb0f93cSkardel 916abb0f93cSkardel if (!stats_control) 917abb0f93cSkardel return; 918abb0f93cSkardel 919abb0f93cSkardel get_systime(&now); 920abb0f93cSkardel filegen_setup(&timingstats, now.l_ui); 921abb0f93cSkardel day = now.l_ui / 86400 + MJD_1900; 922abb0f93cSkardel now.l_ui %= 86400; 923abb0f93cSkardel if (timingstats.fp != NULL) { 924abb0f93cSkardel fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, 925abb0f93cSkardel 3), text); 926abb0f93cSkardel if (++flshcnt % 100 == 0) 927abb0f93cSkardel fflush(timingstats.fp); 928abb0f93cSkardel } 929abb0f93cSkardel } 930abb0f93cSkardel #endif 931abb0f93cSkardel 932abb0f93cSkardel 933abb0f93cSkardel /* 9342950cc38Schristos * check_leap_file - See if the leapseconds file has been updated. 935abb0f93cSkardel * 936ea66d795Schristos * Returns: n/a 937ea66d795Schristos * 938ea66d795Schristos * Note: This loads a new leapfile on the fly. Currently a leap file 939ea66d795Schristos * without SHA1 signature is accepted, but if there is a signature line, 940*eabc0478Schristos * the signature must be valid unless the ntp.conf leapfile line specified 941*eabc0478Schristos * ignorehash. 942abb0f93cSkardel */ 9432950cc38Schristos void 944ea66d795Schristos check_leap_file( 945ea66d795Schristos int is_daily_check, 946ea66d795Schristos uint32_t ntptime, 947ea66d795Schristos const time_t * systime 948abb0f93cSkardel ) 949abb0f93cSkardel { 950ea66d795Schristos /* just do nothing if there is no leap file */ 951ea66d795Schristos if ( ! (leapfile_name && *leapfile_name)) 952ea66d795Schristos return; 953abb0f93cSkardel 954ea66d795Schristos /* try to load leapfile, force it if no leapfile loaded yet */ 955ea66d795Schristos if (leapsec_load_file( 956ea66d795Schristos leapfile_name, &leapfile_stat, 957cdfa2a7eSchristos !have_leapfile, is_daily_check, chck_leaphash)) 958ea66d795Schristos have_leapfile = TRUE; 959ea66d795Schristos else if (!have_leapfile) 960ea66d795Schristos return; 961abb0f93cSkardel 962ea66d795Schristos check_leap_expiration(is_daily_check, ntptime, systime); 963abb0f93cSkardel } 964ea66d795Schristos 965ea66d795Schristos /* 966ea66d795Schristos * check expiration of a loaded leap table 967ea66d795Schristos */ 968ea66d795Schristos static void 969ea66d795Schristos check_leap_expiration( 970ea66d795Schristos int is_daily_check, 971ea66d795Schristos uint32_t ntptime , 972ea66d795Schristos const time_t *systime 973ea66d795Schristos ) 974ea66d795Schristos { 975ea66d795Schristos static const char * const logPrefix = "leapsecond file"; 976ea66d795Schristos int rc; 977ea66d795Schristos 978ea66d795Schristos /* test the expiration of the leap data and log with proper 979ea66d795Schristos * level and frequency (once/hour or once/day, depending on the 980ea66d795Schristos * state. 981ea66d795Schristos */ 982ea66d795Schristos rc = leapsec_daystolive(ntptime, systime); 983ea66d795Schristos if (rc == 0) { 984ea66d795Schristos msyslog(LOG_WARNING, 985ea66d795Schristos "%s ('%s'): will expire in less than one day", 986ea66d795Schristos logPrefix, leapfile_name); 987ea66d795Schristos } else if (is_daily_check && rc < 28) { 9882950cc38Schristos if (rc < 0) 989ea66d795Schristos msyslog(LOG_ERR, 990cdfa2a7eSchristos "%s ('%s'): expired %d day%s ago", 991ea66d795Schristos logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s")); 992ea66d795Schristos else 993ea66d795Schristos msyslog(LOG_WARNING, 994ea66d795Schristos "%s ('%s'): will expire in less than %d days", 995ea66d795Schristos logPrefix, leapfile_name, 1+rc); 996abb0f93cSkardel } 997abb0f93cSkardel } 998abb0f93cSkardel 999abb0f93cSkardel 1000abb0f93cSkardel /* 1001abb0f93cSkardel * getauthkeys - read the authentication keys from the specified file 1002abb0f93cSkardel */ 1003abb0f93cSkardel void 1004abb0f93cSkardel getauthkeys( 1005abb0f93cSkardel const char *keyfile 1006abb0f93cSkardel ) 1007abb0f93cSkardel { 10088b8da087Schristos size_t len; 1009abb0f93cSkardel 1010abb0f93cSkardel len = strlen(keyfile); 1011abb0f93cSkardel if (!len) 1012abb0f93cSkardel return; 1013abb0f93cSkardel 1014abb0f93cSkardel #ifndef SYS_WINNT 1015abb0f93cSkardel key_file_name = erealloc(key_file_name, len + 1); 10162950cc38Schristos memcpy(key_file_name, keyfile, len + 1); 1017abb0f93cSkardel #else 1018abb0f93cSkardel key_file_name = erealloc(key_file_name, _MAX_PATH); 1019abb0f93cSkardel if (len + 1 > _MAX_PATH) 1020abb0f93cSkardel return; 1021abb0f93cSkardel if (!ExpandEnvironmentStrings(keyfile, key_file_name, 1022abb0f93cSkardel _MAX_PATH)) { 1023abb0f93cSkardel msyslog(LOG_ERR, 1024abb0f93cSkardel "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); 10252950cc38Schristos strlcpy(key_file_name, keyfile, _MAX_PATH); 1026abb0f93cSkardel } 10272950cc38Schristos key_file_name = erealloc(key_file_name, 10282950cc38Schristos 1 + strlen(key_file_name)); 1029abb0f93cSkardel #endif /* SYS_WINNT */ 1030abb0f93cSkardel 1031abb0f93cSkardel authreadkeys(key_file_name); 1032abb0f93cSkardel } 1033abb0f93cSkardel 1034abb0f93cSkardel 1035abb0f93cSkardel /* 1036abb0f93cSkardel * rereadkeys - read the authentication key file over again. 1037abb0f93cSkardel */ 1038abb0f93cSkardel void 1039abb0f93cSkardel rereadkeys(void) 1040abb0f93cSkardel { 1041abb0f93cSkardel if (NULL != key_file_name) 1042abb0f93cSkardel authreadkeys(key_file_name); 1043abb0f93cSkardel } 1044abb0f93cSkardel 1045abb0f93cSkardel 1046abb0f93cSkardel #if notyet 1047abb0f93cSkardel /* 1048abb0f93cSkardel * ntp_exit - document explicitly that ntpd has exited 1049abb0f93cSkardel */ 1050abb0f93cSkardel void 1051abb0f93cSkardel ntp_exit(int retval) 1052abb0f93cSkardel { 1053abb0f93cSkardel msyslog(LOG_ERR, "EXITING with return code %d", retval); 1054abb0f93cSkardel exit(retval); 1055abb0f93cSkardel } 1056abb0f93cSkardel #endif 1057abb0f93cSkardel 1058abb0f93cSkardel /* 1059abb0f93cSkardel * fstostr - prettyprint NTP seconds 1060abb0f93cSkardel */ 1061abb0f93cSkardel char * fstostr( 1062abb0f93cSkardel time_t ntp_stamp 1063abb0f93cSkardel ) 1064abb0f93cSkardel { 10652950cc38Schristos char * buf; 10662950cc38Schristos struct calendar tm; 1067abb0f93cSkardel 10682950cc38Schristos LIB_GETBUF(buf); 10692950cc38Schristos if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0) 10702950cc38Schristos snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error", 10712950cc38Schristos (long)ntp_stamp); 1072abb0f93cSkardel else 10732950cc38Schristos snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d", 10742950cc38Schristos tm.year, tm.month, tm.monthday, 10752950cc38Schristos tm.hour, tm.minute); 10762950cc38Schristos return buf; 10772950cc38Schristos } 1078abb0f93cSkardel 10792950cc38Schristos 10802950cc38Schristos /* 10812950cc38Schristos * ntpd_time_stepped is called back by step_systime(), allowing ntpd 10822950cc38Schristos * to do any one-time processing necessitated by the step. 10832950cc38Schristos */ 10842950cc38Schristos void 10852950cc38Schristos ntpd_time_stepped(void) 10862950cc38Schristos { 10872950cc38Schristos u_int saved_mon_enabled; 10882950cc38Schristos 10892950cc38Schristos /* 10902950cc38Schristos * flush the monitor MRU list which contains l_fp timestamps 10912950cc38Schristos * which should not be compared across the step. 10922950cc38Schristos */ 10932950cc38Schristos if (MON_OFF != mon_enabled) { 10942950cc38Schristos saved_mon_enabled = mon_enabled; 10952950cc38Schristos mon_stop(MON_OFF); 10962950cc38Schristos mon_start(saved_mon_enabled); 10972950cc38Schristos } 10982950cc38Schristos 10992950cc38Schristos /* inform interpolating Windows code to allow time to go back */ 11002950cc38Schristos #ifdef SYS_WINNT 11012950cc38Schristos win_time_stepped(); 11022950cc38Schristos #endif 1103abb0f93cSkardel } 1104*eabc0478Schristos 1105*eabc0478Schristos 1106*eabc0478Schristos #ifdef DEBUG 1107*eabc0478Schristos void 1108*eabc0478Schristos append_flagstr( 1109*eabc0478Schristos char * flagstr, 1110*eabc0478Schristos size_t sz, 1111*eabc0478Schristos const char * text 1112*eabc0478Schristos ) 1113*eabc0478Schristos { 1114*eabc0478Schristos if ('\0' != flagstr[0]) { 1115*eabc0478Schristos strlcat(flagstr, ",", sz); 1116*eabc0478Schristos } 1117*eabc0478Schristos /* bail if we ran out of room */ 1118*eabc0478Schristos INSIST(strlcat(flagstr, text, sz) < sz); 1119*eabc0478Schristos } 1120*eabc0478Schristos #endif /* DEBUG */ 1121