1c0b746e5SOllivier Robert /* 2c0b746e5SOllivier Robert * ntp_util.c - stuff I didn't have any other place for 3c0b746e5SOllivier Robert */ 4c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 5c0b746e5SOllivier Robert # include <config.h> 6c0b746e5SOllivier Robert #endif 7c0b746e5SOllivier Robert 8c0b746e5SOllivier Robert #include "ntpd.h" 9c0b746e5SOllivier Robert #include "ntp_unixtime.h" 10c0b746e5SOllivier Robert #include "ntp_filegen.h" 11c0b746e5SOllivier Robert #include "ntp_if.h" 12c0b746e5SOllivier Robert #include "ntp_stdlib.h" 132b15cb3dSCy Schubert #include "ntp_assert.h" 142b15cb3dSCy Schubert #include "ntp_calendar.h" 152b15cb3dSCy Schubert #include "ntp_leapsec.h" 16c0b746e5SOllivier Robert 17224ba2bdSOllivier Robert #include <stdio.h> 18224ba2bdSOllivier Robert #include <ctype.h> 19224ba2bdSOllivier Robert #include <sys/types.h> 20224ba2bdSOllivier Robert #ifdef HAVE_SYS_IOCTL_H 21224ba2bdSOllivier Robert # include <sys/ioctl.h> 22224ba2bdSOllivier Robert #endif 232b15cb3dSCy Schubert #ifdef HAVE_UNISTD_H 242b15cb3dSCy Schubert # include <unistd.h> 252b15cb3dSCy Schubert #endif 262b15cb3dSCy Schubert #include <sys/stat.h> 27224ba2bdSOllivier Robert 28224ba2bdSOllivier Robert #ifdef HAVE_IEEEFP_H 29224ba2bdSOllivier Robert # include <ieeefp.h> 30224ba2bdSOllivier Robert #endif 31224ba2bdSOllivier Robert #ifdef HAVE_MATH_H 32224ba2bdSOllivier Robert # include <math.h> 33224ba2bdSOllivier Robert #endif 34224ba2bdSOllivier Robert 35c0b746e5SOllivier Robert #if defined(VMS) 36c0b746e5SOllivier Robert # include <descrip.h> 37c0b746e5SOllivier Robert #endif /* VMS */ 38c0b746e5SOllivier Robert 39c0b746e5SOllivier Robert /* 402b15cb3dSCy Schubert * Defines used by the leapseconds stuff 41c0b746e5SOllivier Robert */ 422b15cb3dSCy Schubert #define MAX_TAI 100 /* max TAI offset (s) */ 432b15cb3dSCy Schubert #define L_DAY 86400UL /* seconds per day */ 442b15cb3dSCy Schubert #define L_YEAR (L_DAY * 365) /* days per year */ 452b15cb3dSCy Schubert #define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */ 462b15cb3dSCy Schubert #define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */ 472b15cb3dSCy Schubert #define L_CENT (L_4YEAR * 25) /* days per century */ 48c0b746e5SOllivier Robert 49c0b746e5SOllivier Robert /* 502b15cb3dSCy Schubert * This contains odds and ends, including the hourly stats, various 512b15cb3dSCy Schubert * configuration items, leapseconds stuff, etc. 52c0b746e5SOllivier Robert */ 532b15cb3dSCy Schubert /* 542b15cb3dSCy Schubert * File names 552b15cb3dSCy Schubert */ 562b15cb3dSCy Schubert static char *key_file_name; /* keys file name */ 572b15cb3dSCy Schubert static char *leapfile_name; /* leapseconds file name */ 582b15cb3dSCy Schubert static struct stat leapfile_stat; /* leapseconds file stat() buffer */ 592b15cb3dSCy Schubert static int /*BOOL*/have_leapfile = FALSE; 602d4e511cSCy Schubert static int /*BOOL*/chck_leaphash = TRUE; 612b15cb3dSCy Schubert char *stats_drift_file; /* frequency file name */ 622b15cb3dSCy Schubert static char *stats_temp_file; /* temp frequency file name */ 632b15cb3dSCy Schubert static double wander_resid; /* last frequency update */ 642b15cb3dSCy Schubert double wander_threshold = 1e-7; /* initial frequency threshold */ 65c0b746e5SOllivier Robert 66c0b746e5SOllivier Robert /* 67c0b746e5SOllivier Robert * Statistics file stuff 68c0b746e5SOllivier Robert */ 69c0b746e5SOllivier Robert #ifndef NTP_VAR 70c0b746e5SOllivier Robert # ifndef SYS_WINNT 71c0b746e5SOllivier Robert # define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ 72c0b746e5SOllivier Robert # else 73c0b746e5SOllivier Robert # define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ 74c0b746e5SOllivier Robert # endif /* SYS_WINNT */ 75c0b746e5SOllivier Robert #endif 76c0b746e5SOllivier Robert 77c0b746e5SOllivier Robert 782b15cb3dSCy Schubert char statsdir[MAXFILENAME] = NTP_VAR; 79c0b746e5SOllivier Robert static FILEGEN peerstats; 80c0b746e5SOllivier Robert static FILEGEN loopstats; 81c0b746e5SOllivier Robert static FILEGEN clockstats; 82c0b746e5SOllivier Robert static FILEGEN rawstats; 839c2daa00SOllivier Robert static FILEGEN sysstats; 842b15cb3dSCy Schubert static FILEGEN protostats; 859c2daa00SOllivier Robert static FILEGEN cryptostats; 862b15cb3dSCy Schubert static FILEGEN timingstats; 87c0b746e5SOllivier Robert 88c0b746e5SOllivier Robert /* 89c0b746e5SOllivier Robert * This controls whether stats are written to the fileset. Provided 90c0b746e5SOllivier Robert * so that ntpdc can turn off stats when the file system fills up. 91c0b746e5SOllivier Robert */ 92c0b746e5SOllivier Robert int stats_control; 93c0b746e5SOllivier Robert 94c0b746e5SOllivier Robert /* 952b15cb3dSCy Schubert * Last frequency written to file. 96ea906c41SOllivier Robert */ 972b15cb3dSCy Schubert static double prev_drift_comp; /* last frequency update */ 98ea906c41SOllivier Robert 99ea906c41SOllivier Robert /* 1002b15cb3dSCy Schubert * Function prototypes 1012b15cb3dSCy Schubert */ 1022b15cb3dSCy Schubert static void record_sys_stats(void); 1032b15cb3dSCy Schubert void ntpd_time_stepped(void); 1042b15cb3dSCy Schubert static void check_leap_expiration(int, uint32_t, const time_t*); 1052b15cb3dSCy Schubert 1062b15cb3dSCy Schubert /* 1072b15cb3dSCy Schubert * Prototypes 1082b15cb3dSCy Schubert */ 1092b15cb3dSCy Schubert #ifdef DEBUG 1102b15cb3dSCy Schubert void uninit_util(void); 1112b15cb3dSCy Schubert #endif 1122b15cb3dSCy Schubert 1132b15cb3dSCy Schubert /* 1142b15cb3dSCy Schubert * uninit_util - free memory allocated by init_util 1152b15cb3dSCy Schubert */ 1162b15cb3dSCy Schubert #ifdef DEBUG 1172b15cb3dSCy Schubert void 1182b15cb3dSCy Schubert uninit_util(void) 1192b15cb3dSCy Schubert { 1202b15cb3dSCy Schubert #if defined(_MSC_VER) && defined (_DEBUG) 1212b15cb3dSCy Schubert _CrtCheckMemory(); 1222b15cb3dSCy Schubert #endif 1232b15cb3dSCy Schubert if (stats_drift_file) { 1242b15cb3dSCy Schubert free(stats_drift_file); 1252b15cb3dSCy Schubert free(stats_temp_file); 1262b15cb3dSCy Schubert stats_drift_file = NULL; 1272b15cb3dSCy Schubert stats_temp_file = NULL; 1282b15cb3dSCy Schubert } 1292b15cb3dSCy Schubert if (key_file_name) { 1302b15cb3dSCy Schubert free(key_file_name); 1312b15cb3dSCy Schubert key_file_name = NULL; 1322b15cb3dSCy Schubert } 1332b15cb3dSCy Schubert filegen_unregister("peerstats"); 1342b15cb3dSCy Schubert filegen_unregister("loopstats"); 1352b15cb3dSCy Schubert filegen_unregister("clockstats"); 1362b15cb3dSCy Schubert filegen_unregister("rawstats"); 1372b15cb3dSCy Schubert filegen_unregister("sysstats"); 1382b15cb3dSCy Schubert filegen_unregister("protostats"); 1392b15cb3dSCy Schubert #ifdef AUTOKEY 1402b15cb3dSCy Schubert filegen_unregister("cryptostats"); 1412b15cb3dSCy Schubert #endif /* AUTOKEY */ 1422b15cb3dSCy Schubert #ifdef DEBUG_TIMING 1432b15cb3dSCy Schubert filegen_unregister("timingstats"); 1442b15cb3dSCy Schubert #endif /* DEBUG_TIMING */ 1452b15cb3dSCy Schubert 1462b15cb3dSCy Schubert #if defined(_MSC_VER) && defined (_DEBUG) 1472b15cb3dSCy Schubert _CrtCheckMemory(); 1482b15cb3dSCy Schubert #endif 1492b15cb3dSCy Schubert } 1502b15cb3dSCy Schubert #endif /* DEBUG */ 1512b15cb3dSCy Schubert 1522b15cb3dSCy Schubert 1532b15cb3dSCy Schubert /* 1542b15cb3dSCy Schubert * init_util - initialize the util module of ntpd 155c0b746e5SOllivier Robert */ 156c0b746e5SOllivier Robert void 157c0b746e5SOllivier Robert init_util(void) 158c0b746e5SOllivier Robert { 1592b15cb3dSCy Schubert filegen_register(statsdir, "peerstats", &peerstats); 1602b15cb3dSCy Schubert filegen_register(statsdir, "loopstats", &loopstats); 1612b15cb3dSCy Schubert filegen_register(statsdir, "clockstats", &clockstats); 1622b15cb3dSCy Schubert filegen_register(statsdir, "rawstats", &rawstats); 1632b15cb3dSCy Schubert filegen_register(statsdir, "sysstats", &sysstats); 1642b15cb3dSCy Schubert filegen_register(statsdir, "protostats", &protostats); 1652b15cb3dSCy Schubert filegen_register(statsdir, "cryptostats", &cryptostats); 1662b15cb3dSCy Schubert filegen_register(statsdir, "timingstats", &timingstats); 1672b15cb3dSCy Schubert /* 1682b15cb3dSCy Schubert * register with libntp ntp_set_tod() to call us back 1692b15cb3dSCy Schubert * when time is stepped. 1702b15cb3dSCy Schubert */ 1712b15cb3dSCy Schubert step_callback = &ntpd_time_stepped; 1722b15cb3dSCy Schubert #ifdef DEBUG 1732b15cb3dSCy Schubert atexit(&uninit_util); 1742b15cb3dSCy Schubert #endif /* DEBUG */ 175c0b746e5SOllivier Robert } 176c0b746e5SOllivier Robert 177c0b746e5SOllivier Robert 178c0b746e5SOllivier Robert /* 179c0b746e5SOllivier Robert * hourly_stats - print some interesting stats 180c0b746e5SOllivier Robert */ 181c0b746e5SOllivier Robert void 182ea906c41SOllivier Robert write_stats(void) 183c0b746e5SOllivier Robert { 184*f5f40dd6SCy Schubert FILE *fp = NULL; 185c0b746e5SOllivier Robert #ifdef DOSYNCTODR 186c0b746e5SOllivier Robert struct timeval tv; 187c0b746e5SOllivier Robert #if !defined(VMS) 188c0b746e5SOllivier Robert int prio_set; 189c0b746e5SOllivier Robert #endif 190c0b746e5SOllivier Robert #ifdef HAVE_GETCLOCK 191c0b746e5SOllivier Robert struct timespec ts; 192c0b746e5SOllivier Robert #endif 193c0b746e5SOllivier Robert int o_prio; 194c0b746e5SOllivier Robert 195c0b746e5SOllivier Robert /* 196c0b746e5SOllivier Robert * Sometimes having a Sun can be a drag. 197c0b746e5SOllivier Robert * 198c0b746e5SOllivier Robert * The kernel variable dosynctodr controls whether the system's 199c0b746e5SOllivier Robert * soft clock is kept in sync with the battery clock. If it 200c0b746e5SOllivier Robert * is zero, then the soft clock is not synced, and the battery 201c0b746e5SOllivier Robert * clock is simply left to rot. That means that when the system 202c0b746e5SOllivier Robert * reboots, the battery clock (which has probably gone wacky) 203c0b746e5SOllivier Robert * sets the soft clock. That means ntpd starts off with a very 204c0b746e5SOllivier Robert * confused idea of what time it is. It then takes a large 205c0b746e5SOllivier Robert * amount of time to figure out just how wacky the battery clock 206c0b746e5SOllivier Robert * has made things drift, etc, etc. The solution is to make the 207c0b746e5SOllivier Robert * battery clock sync up to system time. The way to do THAT is 208c0b746e5SOllivier Robert * to simply set the time of day to the current time of day, but 209c0b746e5SOllivier Robert * as quickly as possible. This may, or may not be a sensible 210c0b746e5SOllivier Robert * thing to do. 211c0b746e5SOllivier Robert * 212c0b746e5SOllivier Robert * CAVEAT: settimeofday() steps the sun clock by about 800 us, 213c0b746e5SOllivier Robert * so setting DOSYNCTODR seems a bad idea in the 214c0b746e5SOllivier Robert * case of us resolution 215c0b746e5SOllivier Robert */ 216c0b746e5SOllivier Robert 217c0b746e5SOllivier Robert #if !defined(VMS) 2182b15cb3dSCy Schubert /* 2192b15cb3dSCy Schubert * (prr) getpriority returns -1 on error, but -1 is also a valid 2209c2daa00SOllivier Robert * return value (!), so instead we have to zero errno before the 2219c2daa00SOllivier Robert * call and check it for non-zero afterwards. 222c0b746e5SOllivier Robert */ 223c0b746e5SOllivier Robert errno = 0; 224c0b746e5SOllivier Robert prio_set = 0; 225c0b746e5SOllivier Robert o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ 226c0b746e5SOllivier Robert 2279c2daa00SOllivier Robert /* 2289c2daa00SOllivier Robert * (prr) if getpriority succeeded, call setpriority to raise 229c0b746e5SOllivier Robert * scheduling priority as high as possible. If that succeeds 230c0b746e5SOllivier Robert * as well, set the prio_set flag so we remember to reset 2319c2daa00SOllivier Robert * priority to its previous value below. Note that on Solaris 2329c2daa00SOllivier Robert * 2.6 (and beyond?), both getpriority and setpriority will fail 2339c2daa00SOllivier Robert * with ESRCH, because sched_setscheduler (called from main) put 2349c2daa00SOllivier Robert * us in the real-time scheduling class which setpriority 2359c2daa00SOllivier Robert * doesn't know about. Being in the real-time class is better 2369c2daa00SOllivier Robert * than anything setpriority can do, anyhow, so this error is 2379c2daa00SOllivier Robert * silently ignored. 238c0b746e5SOllivier Robert */ 239c0b746e5SOllivier Robert if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) 240c0b746e5SOllivier Robert prio_set = 1; /* overdrive */ 241c0b746e5SOllivier Robert #endif /* VMS */ 242c0b746e5SOllivier Robert #ifdef HAVE_GETCLOCK 243c0b746e5SOllivier Robert (void) getclock(TIMEOFDAY, &ts); 244c0b746e5SOllivier Robert tv.tv_sec = ts.tv_sec; 245c0b746e5SOllivier Robert tv.tv_usec = ts.tv_nsec / 1000; 246c0b746e5SOllivier Robert #else /* not HAVE_GETCLOCK */ 247c0b746e5SOllivier Robert GETTIMEOFDAY(&tv,(struct timezone *)NULL); 248c0b746e5SOllivier Robert #endif /* not HAVE_GETCLOCK */ 2492b15cb3dSCy Schubert if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) 250c0b746e5SOllivier Robert msyslog(LOG_ERR, "can't sync battery time: %m"); 251c0b746e5SOllivier Robert #if !defined(VMS) 252c0b746e5SOllivier Robert if (prio_set) 253c0b746e5SOllivier Robert setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ 254c0b746e5SOllivier Robert #endif /* VMS */ 255c0b746e5SOllivier Robert #endif /* DOSYNCTODR */ 2569c2daa00SOllivier Robert record_sys_stats(); 2572b15cb3dSCy Schubert if (stats_drift_file != 0) { 2582b15cb3dSCy Schubert 2592b15cb3dSCy Schubert /* 2602b15cb3dSCy Schubert * When the frequency file is written, initialize the 2612b15cb3dSCy Schubert * prev_drift_comp and wander_resid. Thereafter, 2622b15cb3dSCy Schubert * reduce the wander_resid by half each hour. When 2632b15cb3dSCy Schubert * the difference between the prev_drift_comp and 2642b15cb3dSCy Schubert * drift_comp is less than the wander_resid, update 2652b15cb3dSCy Schubert * the frequncy file. This minimizes the file writes to 2662b15cb3dSCy Schubert * nonvolaile storage. 2672b15cb3dSCy Schubert */ 268*f5f40dd6SCy Schubert DPRINTF(1, ("write_stats: frequency %.6f thresh %.6f, freq %.6f\n", 2692b15cb3dSCy Schubert (prev_drift_comp - drift_comp) * 1e6, wander_resid * 270*f5f40dd6SCy Schubert 1e6, drift_comp * 1e6)); 271*f5f40dd6SCy Schubert 2722b15cb3dSCy Schubert if (fabs(prev_drift_comp - drift_comp) < wander_resid) { 2732b15cb3dSCy Schubert wander_resid *= 0.5; 274ea906c41SOllivier Robert return; 275ea906c41SOllivier Robert } 276ea906c41SOllivier Robert prev_drift_comp = drift_comp; 2772b15cb3dSCy Schubert wander_resid = wander_threshold; 278c0b746e5SOllivier Robert if ((fp = fopen(stats_temp_file, "w")) == NULL) { 2792b15cb3dSCy Schubert msyslog(LOG_ERR, "frequency file %s: %m", 280c0b746e5SOllivier Robert stats_temp_file); 281c0b746e5SOllivier Robert return; 282c0b746e5SOllivier Robert } 283*f5f40dd6SCy Schubert fprintf(fp, "%.6f\n", drift_comp * 1e6); 284c0b746e5SOllivier Robert (void)fclose(fp); 285c0b746e5SOllivier Robert /* atomic */ 286c0b746e5SOllivier Robert #ifdef SYS_WINNT 2872b15cb3dSCy Schubert if (_unlink(stats_drift_file)) /* rename semantics differ under NT */ 2882b15cb3dSCy Schubert msyslog(LOG_WARNING, 2892b15cb3dSCy Schubert "Unable to remove prior drift file %s, %m", 2902b15cb3dSCy Schubert stats_drift_file); 291c0b746e5SOllivier Robert #endif /* SYS_WINNT */ 292c0b746e5SOllivier Robert 293c0b746e5SOllivier Robert #ifndef NO_RENAME 2942b15cb3dSCy Schubert if (rename(stats_temp_file, stats_drift_file)) 2952b15cb3dSCy Schubert msyslog(LOG_WARNING, 2962b15cb3dSCy Schubert "Unable to rename temp drift file %s to %s, %m", 2972b15cb3dSCy Schubert stats_temp_file, stats_drift_file); 298c0b746e5SOllivier Robert #else 299c0b746e5SOllivier Robert /* we have no rename NFS of ftp in use */ 3002b15cb3dSCy Schubert if ((fp = fopen(stats_drift_file, "w")) == 3012b15cb3dSCy Schubert NULL) { 3022b15cb3dSCy Schubert msyslog(LOG_ERR, 3032b15cb3dSCy Schubert "frequency file %s: %m", 304c0b746e5SOllivier Robert stats_drift_file); 305c0b746e5SOllivier Robert return; 306c0b746e5SOllivier Robert } 307c0b746e5SOllivier Robert #endif 308c0b746e5SOllivier Robert 309c0b746e5SOllivier Robert #if defined(VMS) 310c0b746e5SOllivier Robert /* PURGE */ 311c0b746e5SOllivier Robert { 312c0b746e5SOllivier Robert $DESCRIPTOR(oldvers,";-1"); 313c0b746e5SOllivier Robert struct dsc$descriptor driftdsc = { 3142b15cb3dSCy Schubert strlen(stats_drift_file), 0, 0, 3152b15cb3dSCy Schubert stats_drift_file }; 3162b15cb3dSCy Schubert while(lib$delete_file(&oldvers, 3172b15cb3dSCy Schubert &driftdsc) & 1); 318c0b746e5SOllivier Robert } 319c0b746e5SOllivier Robert #endif 320c0b746e5SOllivier Robert } 321c0b746e5SOllivier Robert } 322c0b746e5SOllivier Robert 323c0b746e5SOllivier Robert 324c0b746e5SOllivier Robert /* 325*f5f40dd6SCy Schubert * If an option was given on the command line make sure it takes 326*f5f40dd6SCy Schubert * precedence over the configuration file, as command-line options 327*f5f40dd6SCy Schubert * are processed first. Similarly, if an option is given in the 328*f5f40dd6SCy Schubert * configuration file, do not allow it to be overridden with runtime 329*f5f40dd6SCy Schubert * configuration. Done by simply remembering an option was already 330*f5f40dd6SCy Schubert * seen. 331c0b746e5SOllivier Robert */ 332a466cc55SCy Schubert static int 333a466cc55SCy Schubert allow_config( 334*f5f40dd6SCy Schubert u_int option, 335*f5f40dd6SCy Schubert int/*BOOL*/ cmdopt 336*f5f40dd6SCy Schubert ) 337a466cc55SCy Schubert { 338*f5f40dd6SCy Schubert static u_int seen = 0; /* stat options previously set */ 339*f5f40dd6SCy Schubert u_int mask; 340*f5f40dd6SCy Schubert int retv; 341*f5f40dd6SCy Schubert 342*f5f40dd6SCy Schubert if (cmdopt) { 343*f5f40dd6SCy Schubert DEBUG_REQUIRE(option < sizeof(mask) * 8); 344*f5f40dd6SCy Schubert mask = 1u << option; 345*f5f40dd6SCy Schubert retv = !(seen & mask); 346*f5f40dd6SCy Schubert seen |= mask; 347*f5f40dd6SCy Schubert } else { 348*f5f40dd6SCy Schubert retv = FALSE; 349*f5f40dd6SCy Schubert } 350a466cc55SCy Schubert return retv; 351a466cc55SCy Schubert } 352a466cc55SCy Schubert 353a466cc55SCy Schubert 354*f5f40dd6SCy Schubert /* 355*f5f40dd6SCy Schubert * stats_config - configure the stats operation 356*f5f40dd6SCy Schubert */ 357c0b746e5SOllivier Robert void 358c0b746e5SOllivier Robert stats_config( 359c0b746e5SOllivier Robert int item, 3602d4e511cSCy Schubert const char *invalue, /* only one type so far */ 3612d4e511cSCy Schubert int optflag 362c0b746e5SOllivier Robert ) 363c0b746e5SOllivier Robert { 364*f5f40dd6SCy Schubert FILE *fp = NULL; 365ea906c41SOllivier Robert const char *value; 3663311ff84SXin LI size_t len; 3672b15cb3dSCy Schubert double old_drift; 3682b15cb3dSCy Schubert l_fp now; 3692b15cb3dSCy Schubert time_t ttnow; 370*f5f40dd6SCy Schubert char dirsep_or_nul; 3712b15cb3dSCy Schubert #ifndef VMS 372a466cc55SCy Schubert static const char temp_ext[] = ".TEMP"; 3732b15cb3dSCy Schubert #else 374a466cc55SCy Schubert static const char temp_ext[] = "-TEMP"; 3752b15cb3dSCy Schubert #endif 376c0b746e5SOllivier Robert 3779c2daa00SOllivier Robert /* 3789c2daa00SOllivier Robert * Expand environment strings under Windows NT, since the 3799c2daa00SOllivier Robert * command interpreter doesn't do this, the program must. 380c0b746e5SOllivier Robert */ 381c0b746e5SOllivier Robert #ifdef SYS_WINNT 382c0b746e5SOllivier Robert char newvalue[MAX_PATH], parameter[MAX_PATH]; 383c0b746e5SOllivier Robert 3849c2daa00SOllivier Robert if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { 385c0b746e5SOllivier Robert switch (item) { 386c0b746e5SOllivier Robert case STATS_FREQ_FILE: 3872b15cb3dSCy Schubert strlcpy(parameter, "STATS_FREQ_FILE", 3882b15cb3dSCy Schubert sizeof(parameter)); 389c0b746e5SOllivier Robert break; 3902b15cb3dSCy Schubert 3912b15cb3dSCy Schubert case STATS_LEAP_FILE: 3922b15cb3dSCy Schubert strlcpy(parameter, "STATS_LEAP_FILE", 3932b15cb3dSCy Schubert sizeof(parameter)); 3942b15cb3dSCy Schubert break; 3952b15cb3dSCy Schubert 396c0b746e5SOllivier Robert case STATS_STATSDIR: 3972b15cb3dSCy Schubert strlcpy(parameter, "STATS_STATSDIR", 3982b15cb3dSCy Schubert sizeof(parameter)); 399c0b746e5SOllivier Robert break; 4002b15cb3dSCy Schubert 401c0b746e5SOllivier Robert case STATS_PID_FILE: 4022b15cb3dSCy Schubert strlcpy(parameter, "STATS_PID_FILE", 4032b15cb3dSCy Schubert sizeof(parameter)); 404c0b746e5SOllivier Robert break; 4052b15cb3dSCy Schubert 406c0b746e5SOllivier Robert default: 4072b15cb3dSCy Schubert strlcpy(parameter, "UNKNOWN", 4082b15cb3dSCy Schubert sizeof(parameter)); 409c0b746e5SOllivier Robert break; 410c0b746e5SOllivier Robert } 411c0b746e5SOllivier Robert value = invalue; 412c0b746e5SOllivier Robert msyslog(LOG_ERR, 4132b15cb3dSCy Schubert "ExpandEnvironmentStrings(%s) failed: %m\n", 4142b15cb3dSCy Schubert parameter); 4159c2daa00SOllivier Robert } else { 416c0b746e5SOllivier Robert value = newvalue; 4179c2daa00SOllivier Robert } 418c0b746e5SOllivier Robert #else 419c0b746e5SOllivier Robert value = invalue; 420c0b746e5SOllivier Robert #endif /* SYS_WINNT */ 421c0b746e5SOllivier Robert 422c0b746e5SOllivier Robert switch (item) { 423c0b746e5SOllivier Robert 4242b15cb3dSCy Schubert /* 4252b15cb3dSCy Schubert * Open and read frequency file. 4262b15cb3dSCy Schubert */ 4272b15cb3dSCy Schubert case STATS_FREQ_FILE: 428*f5f40dd6SCy Schubert if (!allow_config(STATS_FREQ_FILE, optflag)) { 429c0b746e5SOllivier Robert break; 430*f5f40dd6SCy Schubert } 431*f5f40dd6SCy Schubert if (!value || 0 == (len = strlen(value))) { 432a466cc55SCy Schubert free(stats_drift_file); 433a466cc55SCy Schubert free(stats_temp_file); 434a466cc55SCy Schubert stats_drift_file = stats_temp_file = NULL; 435*f5f40dd6SCy Schubert } else { 436*f5f40dd6SCy Schubert stats_drift_file = erealloc(stats_drift_file, 437*f5f40dd6SCy Schubert 1 + len); 4382b15cb3dSCy Schubert stats_temp_file = erealloc(stats_temp_file, 439*f5f40dd6SCy Schubert len + sizeof(temp_ext)); 440*f5f40dd6SCy Schubert memcpy(stats_drift_file, value, 1 + len); 441*f5f40dd6SCy Schubert memcpy(stats_temp_file, value, len); 442*f5f40dd6SCy Schubert memcpy(stats_temp_file + len, temp_ext, 443*f5f40dd6SCy Schubert sizeof(temp_ext)); 444a466cc55SCy Schubert } 445c0b746e5SOllivier Robert 446c0b746e5SOllivier Robert /* 4479c2daa00SOllivier Robert * Open drift file and read frequency. If the file is 4489c2daa00SOllivier Robert * missing or contains errors, tell the loop to reset. 449c0b746e5SOllivier Robert */ 450a466cc55SCy Schubert if (NULL == stats_drift_file) { 451*f5f40dd6SCy Schubert goto nofreq; 452a466cc55SCy Schubert } else if ((fp = fopen(stats_drift_file, "r")) == NULL) { 453*f5f40dd6SCy Schubert if (errno != ENOENT) { 454a466cc55SCy Schubert msyslog(LOG_WARNING, 455*f5f40dd6SCy Schubert "cannot read frequency file %s: %m", 456*f5f40dd6SCy Schubert stats_drift_file); 457*f5f40dd6SCy Schubert } 458*f5f40dd6SCy Schubert goto nofreq; 459a466cc55SCy Schubert } else if (fscanf(fp, "%lf", &old_drift) != 1) { 460c0b746e5SOllivier Robert msyslog(LOG_ERR, 4612b15cb3dSCy Schubert "format error frequency file %s", 4622b15cb3dSCy Schubert stats_drift_file); 463*f5f40dd6SCy Schubert nofreq: 464*f5f40dd6SCy Schubert prev_drift_comp = 0.0; 465*f5f40dd6SCy Schubert loop_config(LOOP_NOFREQ, prev_drift_comp); 466a466cc55SCy Schubert } else { 4672b15cb3dSCy Schubert loop_config(LOOP_FREQ, old_drift); 4682b15cb3dSCy Schubert prev_drift_comp = drift_comp; 469a466cc55SCy Schubert msyslog(LOG_INFO, 470*f5f40dd6SCy Schubert "initial drift restored to %.6f", 471a466cc55SCy Schubert old_drift); 472*f5f40dd6SCy Schubert } 473*f5f40dd6SCy Schubert if (NULL != fp) { 474a466cc55SCy Schubert fclose(fp); 475a466cc55SCy Schubert } 4762b15cb3dSCy Schubert break; 4772b15cb3dSCy Schubert 4782b15cb3dSCy Schubert /* 4792b15cb3dSCy Schubert * Specify statistics directory. 4802b15cb3dSCy Schubert */ 4812b15cb3dSCy Schubert case STATS_STATSDIR: 482*f5f40dd6SCy Schubert if (!allow_config(STATS_STATSDIR, optflag)) { 483a466cc55SCy Schubert break; 484c0b746e5SOllivier Robert } 485*f5f40dd6SCy Schubert /* - 2 since value may be missing the DIR_SEP. */ 486*f5f40dd6SCy Schubert len = strlen(value); 487*f5f40dd6SCy Schubert if (len > sizeof(statsdir) - 2) { 488*f5f40dd6SCy Schubert msyslog(LOG_ERR, 489*f5f40dd6SCy Schubert "statsdir %s too long (>%u)", value, 490*f5f40dd6SCy Schubert (u_int)sizeof(statsdir) - 2); 491*f5f40dd6SCy Schubert break; 492*f5f40dd6SCy Schubert } 493*f5f40dd6SCy Schubert /* Add a DIR_SEP unless we already have one. */ 494*f5f40dd6SCy Schubert if (0 == len || DIR_SEP == value[len - 1]) { 495*f5f40dd6SCy Schubert dirsep_or_nul = '\0'; 496*f5f40dd6SCy Schubert } else { 497*f5f40dd6SCy Schubert dirsep_or_nul = DIR_SEP; 498*f5f40dd6SCy Schubert } 499*f5f40dd6SCy Schubert snprintf(statsdir, sizeof(statsdir), "%s%c", 500*f5f40dd6SCy Schubert value, dirsep_or_nul); 501*f5f40dd6SCy Schubert filegen_statsdir(); 502c0b746e5SOllivier Robert break; 503c0b746e5SOllivier Robert 5042b15cb3dSCy Schubert /* 505*f5f40dd6SCy Schubert * Write pid file. 5062b15cb3dSCy Schubert */ 507c0b746e5SOllivier Robert case STATS_PID_FILE: 508*f5f40dd6SCy Schubert if (!allow_config(STATS_PID_FILE, optflag)) { 509c0b746e5SOllivier Robert break; 510c0b746e5SOllivier Robert } 511*f5f40dd6SCy Schubert if ((fp = fopen(value, "w")) == NULL) { 512*f5f40dd6SCy Schubert msyslog(LOG_ERR, "pid file %s: %m", value); 513*f5f40dd6SCy Schubert break; 514*f5f40dd6SCy Schubert } 515*f5f40dd6SCy Schubert fprintf(fp, "%ld", (long)getpid()); 5162b15cb3dSCy Schubert fclose(fp); 5172b15cb3dSCy Schubert break; 5182b15cb3dSCy Schubert 5192b15cb3dSCy Schubert /* 5202b15cb3dSCy Schubert * Read leapseconds file. 5212b15cb3dSCy Schubert * 522*f5f40dd6SCy Schubert * By default a leap file without SHA1 signature is accepted, 523*f5f40dd6SCy Schubert * but if there is a signature line, the signature must be 524*f5f40dd6SCy Schubert * valid or the leapfile line in ntp.conf must have ignorehash. 5252b15cb3dSCy Schubert */ 5262b15cb3dSCy Schubert case STATS_LEAP_FILE: 527*f5f40dd6SCy Schubert if (NULL == value || 0 == (len = strlen(value))) { 5282b15cb3dSCy Schubert break; 529*f5f40dd6SCy Schubert } 5302b15cb3dSCy Schubert leapfile_name = erealloc(leapfile_name, len + 1); 5312b15cb3dSCy Schubert memcpy(leapfile_name, value, len + 1); 5322d4e511cSCy Schubert chck_leaphash = optflag; 5332b15cb3dSCy Schubert 5342b15cb3dSCy Schubert if (leapsec_load_file( 5352d4e511cSCy Schubert leapfile_name, &leapfile_stat, 536*f5f40dd6SCy Schubert TRUE, TRUE, chck_leaphash)) { 5372b15cb3dSCy Schubert leap_signature_t lsig; 5382b15cb3dSCy Schubert 5392b15cb3dSCy Schubert get_systime(&now); 5402b15cb3dSCy Schubert time(&ttnow); 5412b15cb3dSCy Schubert leapsec_getsig(&lsig); 5422b15cb3dSCy Schubert mprintf_event(EVNT_TAI, NULL, 543*f5f40dd6SCy Schubert "%d leap %s expire%s %s", 5442b15cb3dSCy Schubert lsig.taiof, 5452b15cb3dSCy Schubert fstostr(lsig.ttime), 5462b15cb3dSCy Schubert leapsec_expired(now.l_ui, NULL) 547*f5f40dd6SCy Schubert ? "d" 548*f5f40dd6SCy Schubert : "s", 5492b15cb3dSCy Schubert fstostr(lsig.etime)); 5502b15cb3dSCy Schubert 5512b15cb3dSCy Schubert have_leapfile = TRUE; 5522b15cb3dSCy Schubert 5532b15cb3dSCy Schubert /* force an immediate daily expiration check of 5542b15cb3dSCy Schubert * the leap seconds table 5552b15cb3dSCy Schubert */ 5562b15cb3dSCy Schubert check_leap_expiration(TRUE, now.l_ui, &ttnow); 5572b15cb3dSCy Schubert } 558c0b746e5SOllivier Robert break; 559c0b746e5SOllivier Robert 560c0b746e5SOllivier Robert default: 561c0b746e5SOllivier Robert /* oh well */ 562c0b746e5SOllivier Robert break; 563c0b746e5SOllivier Robert } 564c0b746e5SOllivier Robert } 565c0b746e5SOllivier Robert 5662b15cb3dSCy Schubert 567c0b746e5SOllivier Robert /* 568c0b746e5SOllivier Robert * record_peer_stats - write peer statistics to file 569c0b746e5SOllivier Robert * 570c0b746e5SOllivier Robert * file format: 5712b15cb3dSCy Schubert * day (MJD) 572c0b746e5SOllivier Robert * time (s past UTC midnight) 5732b15cb3dSCy Schubert * IP address 5742b15cb3dSCy Schubert * status word (hex) 5752b15cb3dSCy Schubert * offset 5762b15cb3dSCy Schubert * delay 5772b15cb3dSCy Schubert * dispersion 5782b15cb3dSCy Schubert * jitter 579c0b746e5SOllivier Robert */ 580c0b746e5SOllivier Robert void 581c0b746e5SOllivier Robert record_peer_stats( 5822b15cb3dSCy Schubert sockaddr_u * addr, 583c0b746e5SOllivier Robert int status, 584*f5f40dd6SCy Schubert double offset, 585*f5f40dd6SCy Schubert double delay, 586*f5f40dd6SCy Schubert double dispersion, 587*f5f40dd6SCy Schubert double jitter 588c0b746e5SOllivier Robert ) 589c0b746e5SOllivier Robert { 5909c2daa00SOllivier Robert l_fp now; 5919c2daa00SOllivier Robert u_long day; 592c0b746e5SOllivier Robert 593*f5f40dd6SCy Schubert if (!stats_control) { 594c0b746e5SOllivier Robert return; 595*f5f40dd6SCy Schubert } 5969c2daa00SOllivier Robert get_systime(&now); 5979c2daa00SOllivier Robert filegen_setup(&peerstats, now.l_ui); 598*f5f40dd6SCy Schubert if (NULL == peerstats.fp) { 599*f5f40dd6SCy Schubert return; 600*f5f40dd6SCy Schubert } 6019c2daa00SOllivier Robert day = now.l_ui / 86400 + MJD_1900; 6029c2daa00SOllivier Robert now.l_ui %= 86400; 603c0b746e5SOllivier Robert fprintf(peerstats.fp, 6042b15cb3dSCy Schubert "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, 6052b15cb3dSCy Schubert ulfptoa(&now, 3), stoa(addr), status, offset, 6062b15cb3dSCy Schubert delay, dispersion, jitter); 607c0b746e5SOllivier Robert fflush(peerstats.fp); 608c0b746e5SOllivier Robert } 609ea906c41SOllivier Robert 6102b15cb3dSCy Schubert 611c0b746e5SOllivier Robert /* 612c0b746e5SOllivier Robert * record_loop_stats - write loop filter statistics to file 613c0b746e5SOllivier Robert * 614c0b746e5SOllivier Robert * file format: 6152b15cb3dSCy Schubert * day (MJD) 616c0b746e5SOllivier Robert * time (s past midnight) 6172b15cb3dSCy Schubert * offset 6182b15cb3dSCy Schubert * frequency (PPM) 6192b15cb3dSCy Schubert * jitter 6202b15cb3dSCy Schubert * wnder (PPM) 6212b15cb3dSCy Schubert * time constant (log2) 622c0b746e5SOllivier Robert */ 623c0b746e5SOllivier Robert void 624224ba2bdSOllivier Robert record_loop_stats( 6252b15cb3dSCy Schubert double offset, /* offset */ 6262b15cb3dSCy Schubert double freq, /* frequency (PPM) */ 6272b15cb3dSCy Schubert double jitter, /* jitter */ 6282b15cb3dSCy Schubert double wander, /* wander (PPM) */ 6299c2daa00SOllivier Robert int spoll 630224ba2bdSOllivier Robert ) 631c0b746e5SOllivier Robert { 6329c2daa00SOllivier Robert l_fp now; 6339c2daa00SOllivier Robert u_long day; 634c0b746e5SOllivier Robert 635c0b746e5SOllivier Robert if (!stats_control) 636c0b746e5SOllivier Robert return; 637c0b746e5SOllivier Robert 6389c2daa00SOllivier Robert get_systime(&now); 6399c2daa00SOllivier Robert filegen_setup(&loopstats, now.l_ui); 6409c2daa00SOllivier Robert day = now.l_ui / 86400 + MJD_1900; 6419c2daa00SOllivier Robert now.l_ui %= 86400; 642c0b746e5SOllivier Robert if (loopstats.fp != NULL) { 643ea906c41SOllivier Robert fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", 6449c2daa00SOllivier Robert day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, 6452b15cb3dSCy Schubert wander * 1e6, spoll); 646c0b746e5SOllivier Robert fflush(loopstats.fp); 647c0b746e5SOllivier Robert } 648c0b746e5SOllivier Robert } 649c0b746e5SOllivier Robert 6502b15cb3dSCy Schubert 651c0b746e5SOllivier Robert /* 652c0b746e5SOllivier Robert * record_clock_stats - write clock statistics to file 653c0b746e5SOllivier Robert * 654c0b746e5SOllivier Robert * file format: 6552b15cb3dSCy Schubert * day (MJD) 656c0b746e5SOllivier Robert * time (s past midnight) 6572b15cb3dSCy Schubert * IP address 658c0b746e5SOllivier Robert * text message 659c0b746e5SOllivier Robert */ 660c0b746e5SOllivier Robert void 661c0b746e5SOllivier Robert record_clock_stats( 6622b15cb3dSCy Schubert sockaddr_u *addr, 6632b15cb3dSCy Schubert const char *text /* timecode string */ 664c0b746e5SOllivier Robert ) 665c0b746e5SOllivier Robert { 6669c2daa00SOllivier Robert l_fp now; 6679c2daa00SOllivier Robert u_long day; 668c0b746e5SOllivier Robert 669c0b746e5SOllivier Robert if (!stats_control) 670c0b746e5SOllivier Robert return; 671c0b746e5SOllivier Robert 6729c2daa00SOllivier Robert get_systime(&now); 6739c2daa00SOllivier Robert filegen_setup(&clockstats, now.l_ui); 6749c2daa00SOllivier Robert day = now.l_ui / 86400 + MJD_1900; 6759c2daa00SOllivier Robert now.l_ui %= 86400; 676c0b746e5SOllivier Robert if (clockstats.fp != NULL) { 6772b15cb3dSCy Schubert fprintf(clockstats.fp, "%lu %s %s %s\n", day, 6782b15cb3dSCy Schubert ulfptoa(&now, 3), stoa(addr), text); 679c0b746e5SOllivier Robert fflush(clockstats.fp); 680c0b746e5SOllivier Robert } 681c0b746e5SOllivier Robert } 682c0b746e5SOllivier Robert 6832b15cb3dSCy Schubert 6842b15cb3dSCy Schubert /* 6852b15cb3dSCy Schubert * mprintf_clock_stats - write clock statistics to file with 6862b15cb3dSCy Schubert * msnprintf-style formatting. 6872b15cb3dSCy Schubert */ 6882b15cb3dSCy Schubert int 6892b15cb3dSCy Schubert mprintf_clock_stats( 6902b15cb3dSCy Schubert sockaddr_u *addr, 6912b15cb3dSCy Schubert const char *fmt, 6922b15cb3dSCy Schubert ... 6932b15cb3dSCy Schubert ) 6942b15cb3dSCy Schubert { 6952b15cb3dSCy Schubert va_list ap; 6962b15cb3dSCy Schubert int rc; 6972b15cb3dSCy Schubert char msg[512]; 6982b15cb3dSCy Schubert 6992b15cb3dSCy Schubert va_start(ap, fmt); 7002b15cb3dSCy Schubert rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 7012b15cb3dSCy Schubert va_end(ap); 7022b15cb3dSCy Schubert if (stats_control) 7032b15cb3dSCy Schubert record_clock_stats(addr, msg); 7042b15cb3dSCy Schubert 7052b15cb3dSCy Schubert return rc; 7062b15cb3dSCy Schubert } 7072b15cb3dSCy Schubert 708c0b746e5SOllivier Robert /* 709c0b746e5SOllivier Robert * record_raw_stats - write raw timestamps to file 710c0b746e5SOllivier Robert * 711c0b746e5SOllivier Robert * file format 7122b15cb3dSCy Schubert * day (MJD) 713c0b746e5SOllivier Robert * time (s past midnight) 714c0b746e5SOllivier Robert * peer ip address 7152b15cb3dSCy Schubert * IP address 716c0b746e5SOllivier Robert * t1 t2 t3 t4 timestamps 71709100258SXin LI * leap, version, mode, stratum, ppoll, precision, root delay, root dispersion, REFID 71809100258SXin LI * length and hex dump of any EFs and any legacy MAC. 719c0b746e5SOllivier Robert */ 720c0b746e5SOllivier Robert void 721c0b746e5SOllivier Robert record_raw_stats( 7222b15cb3dSCy Schubert sockaddr_u *srcadr, 7232b15cb3dSCy Schubert sockaddr_u *dstadr, 7242b15cb3dSCy Schubert l_fp *t1, /* originate timestamp */ 7252b15cb3dSCy Schubert l_fp *t2, /* receive timestamp */ 7262b15cb3dSCy Schubert l_fp *t3, /* transmit timestamp */ 7272b15cb3dSCy Schubert l_fp *t4, /* destination timestamp */ 7282b15cb3dSCy Schubert int leap, 7292b15cb3dSCy Schubert int version, 7302b15cb3dSCy Schubert int mode, 7312b15cb3dSCy Schubert int stratum, 7322b15cb3dSCy Schubert int ppoll, 7332b15cb3dSCy Schubert int precision, 7342b15cb3dSCy Schubert double root_delay, /* seconds */ 7352b15cb3dSCy Schubert double root_dispersion,/* seconds */ 73609100258SXin LI u_int32 refid, 73709100258SXin LI int len, 73809100258SXin LI u_char *extra 739c0b746e5SOllivier Robert ) 740c0b746e5SOllivier Robert { 7419c2daa00SOllivier Robert l_fp now; 7429c2daa00SOllivier Robert u_long day; 743c0b746e5SOllivier Robert 744c0b746e5SOllivier Robert if (!stats_control) 745c0b746e5SOllivier Robert return; 746c0b746e5SOllivier Robert 747a466cc55SCy Schubert /* 748a466cc55SCy Schubert * Mode 6 and mode 7 packets do not have the format of normal 749a466cc55SCy Schubert * NTP packets and will log garbage. So don't. [Bug 3774] 750a466cc55SCy Schubert */ 751a466cc55SCy Schubert if (MODE_CONTROL == mode || MODE_PRIVATE == mode) 752a466cc55SCy Schubert return; 753a466cc55SCy Schubert 7549c2daa00SOllivier Robert get_systime(&now); 7559c2daa00SOllivier Robert filegen_setup(&rawstats, now.l_ui); 7569c2daa00SOllivier Robert day = now.l_ui / 86400 + MJD_1900; 7579c2daa00SOllivier Robert now.l_ui %= 86400; 758c0b746e5SOllivier Robert if (rawstats.fp != NULL) { 75909100258SXin LI fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s", 7602b15cb3dSCy Schubert day, ulfptoa(&now, 3), 76109100258SXin LI srcadr ? stoa(srcadr) : "-", 76209100258SXin LI dstadr ? stoa(dstadr) : "-", 7632b15cb3dSCy Schubert ulfptoa(t1, 9), ulfptoa(t2, 9), 7642b15cb3dSCy Schubert ulfptoa(t3, 9), ulfptoa(t4, 9), 7652b15cb3dSCy Schubert leap, version, mode, stratum, ppoll, precision, 7662b15cb3dSCy Schubert root_delay, root_dispersion, refid_str(refid, stratum)); 76709100258SXin LI if (len > 0) { 76809100258SXin LI int i; 76909100258SXin LI 77009100258SXin LI fprintf(rawstats.fp, " %d: ", len); 77109100258SXin LI for (i = 0; i < len; ++i) { 77209100258SXin LI fprintf(rawstats.fp, "%02x", extra[i]); 77309100258SXin LI } 77409100258SXin LI } 77509100258SXin LI fprintf(rawstats.fp, "\n"); 776c0b746e5SOllivier Robert fflush(rawstats.fp); 777c0b746e5SOllivier Robert } 778c0b746e5SOllivier Robert } 779c0b746e5SOllivier Robert 7809c2daa00SOllivier Robert 7819c2daa00SOllivier Robert /* 7829c2daa00SOllivier Robert * record_sys_stats - write system statistics to file 7839c2daa00SOllivier Robert * 7849c2daa00SOllivier Robert * file format 7852b15cb3dSCy Schubert * day (MJD) 7869c2daa00SOllivier Robert * time (s past midnight) 7872b15cb3dSCy Schubert * time since reset 7889c2daa00SOllivier Robert * packets recieved 7892b15cb3dSCy Schubert * packets for this host 7909c2daa00SOllivier Robert * current version 7912b15cb3dSCy Schubert * old version 7929c2daa00SOllivier Robert * access denied 7939c2daa00SOllivier Robert * bad length or format 7949c2daa00SOllivier Robert * bad authentication 7952b15cb3dSCy Schubert * declined 7969c2daa00SOllivier Robert * rate exceeded 7972b15cb3dSCy Schubert * KoD sent 7989c2daa00SOllivier Robert */ 7999c2daa00SOllivier Robert void 8009c2daa00SOllivier Robert record_sys_stats(void) 8019c2daa00SOllivier Robert { 8029c2daa00SOllivier Robert l_fp now; 8039c2daa00SOllivier Robert u_long day; 8049c2daa00SOllivier Robert 8059c2daa00SOllivier Robert if (!stats_control) 8069c2daa00SOllivier Robert return; 8079c2daa00SOllivier Robert 8089c2daa00SOllivier Robert get_systime(&now); 8099c2daa00SOllivier Robert filegen_setup(&sysstats, now.l_ui); 8109c2daa00SOllivier Robert day = now.l_ui / 86400 + MJD_1900; 8119c2daa00SOllivier Robert now.l_ui %= 86400; 8129c2daa00SOllivier Robert if (sysstats.fp != NULL) { 8139c2daa00SOllivier Robert fprintf(sysstats.fp, 8142b15cb3dSCy Schubert "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 8152b15cb3dSCy Schubert day, ulfptoa(&now, 3), current_time - sys_stattime, 8162b15cb3dSCy Schubert sys_received, sys_processed, sys_newversion, 8172b15cb3dSCy Schubert sys_oldversion, sys_restricted, sys_badlength, 8182b15cb3dSCy Schubert sys_badauth, sys_declined, sys_limitrejected, 8192b15cb3dSCy Schubert sys_kodsent); 8209c2daa00SOllivier Robert fflush(sysstats.fp); 8219c2daa00SOllivier Robert proto_clr_stats(); 8229c2daa00SOllivier Robert } 8239c2daa00SOllivier Robert } 8249c2daa00SOllivier Robert 8259c2daa00SOllivier Robert 8262b15cb3dSCy Schubert /* 8272b15cb3dSCy Schubert * record_proto_stats - write system statistics to file 8282b15cb3dSCy Schubert * 8292b15cb3dSCy Schubert * file format 8302b15cb3dSCy Schubert * day (MJD) 8312b15cb3dSCy Schubert * time (s past midnight) 8322b15cb3dSCy Schubert * text message 8332b15cb3dSCy Schubert */ 8342b15cb3dSCy Schubert void 8352b15cb3dSCy Schubert record_proto_stats( 8362b15cb3dSCy Schubert char *str /* text string */ 8372b15cb3dSCy Schubert ) 8382b15cb3dSCy Schubert { 8392b15cb3dSCy Schubert l_fp now; 8402b15cb3dSCy Schubert u_long day; 8412b15cb3dSCy Schubert 8422b15cb3dSCy Schubert if (!stats_control) 8432b15cb3dSCy Schubert return; 8442b15cb3dSCy Schubert 8452b15cb3dSCy Schubert get_systime(&now); 8462b15cb3dSCy Schubert filegen_setup(&protostats, now.l_ui); 8472b15cb3dSCy Schubert day = now.l_ui / 86400 + MJD_1900; 8482b15cb3dSCy Schubert now.l_ui %= 86400; 8492b15cb3dSCy Schubert if (protostats.fp != NULL) { 8502b15cb3dSCy Schubert fprintf(protostats.fp, "%lu %s %s\n", day, 8512b15cb3dSCy Schubert ulfptoa(&now, 3), str); 8522b15cb3dSCy Schubert fflush(protostats.fp); 8532b15cb3dSCy Schubert } 8542b15cb3dSCy Schubert } 8552b15cb3dSCy Schubert 8562b15cb3dSCy Schubert 8572b15cb3dSCy Schubert #ifdef AUTOKEY 8589c2daa00SOllivier Robert /* 8599c2daa00SOllivier Robert * record_crypto_stats - write crypto statistics to file 8609c2daa00SOllivier Robert * 8619c2daa00SOllivier Robert * file format: 8629c2daa00SOllivier Robert * day (mjd) 8639c2daa00SOllivier Robert * time (s past midnight) 8642b15cb3dSCy Schubert * peer ip address 8659c2daa00SOllivier Robert * text message 8669c2daa00SOllivier Robert */ 8679c2daa00SOllivier Robert void 8689c2daa00SOllivier Robert record_crypto_stats( 8692b15cb3dSCy Schubert sockaddr_u *addr, 8702b15cb3dSCy Schubert const char *text /* text message */ 8719c2daa00SOllivier Robert ) 8729c2daa00SOllivier Robert { 8739c2daa00SOllivier Robert l_fp now; 8749c2daa00SOllivier Robert u_long day; 8759c2daa00SOllivier Robert 8769c2daa00SOllivier Robert if (!stats_control) 8779c2daa00SOllivier Robert return; 8789c2daa00SOllivier Robert 8799c2daa00SOllivier Robert get_systime(&now); 8809c2daa00SOllivier Robert filegen_setup(&cryptostats, now.l_ui); 8819c2daa00SOllivier Robert day = now.l_ui / 86400 + MJD_1900; 8829c2daa00SOllivier Robert now.l_ui %= 86400; 8839c2daa00SOllivier Robert if (cryptostats.fp != NULL) { 8849c2daa00SOllivier Robert if (addr == NULL) 8852b15cb3dSCy Schubert fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", 8869c2daa00SOllivier Robert day, ulfptoa(&now, 3), text); 8879c2daa00SOllivier Robert else 8889c2daa00SOllivier Robert fprintf(cryptostats.fp, "%lu %s %s %s\n", 8899c2daa00SOllivier Robert day, ulfptoa(&now, 3), stoa(addr), text); 8909c2daa00SOllivier Robert fflush(cryptostats.fp); 8919c2daa00SOllivier Robert } 8929c2daa00SOllivier Robert } 8932b15cb3dSCy Schubert #endif /* AUTOKEY */ 8942b15cb3dSCy Schubert 8959c2daa00SOllivier Robert 896ea906c41SOllivier Robert #ifdef DEBUG_TIMING 897ea906c41SOllivier Robert /* 8982b15cb3dSCy Schubert * record_timing_stats - write timing statistics to file 899ea906c41SOllivier Robert * 900ea906c41SOllivier Robert * file format: 901ea906c41SOllivier Robert * day (mjd) 902ea906c41SOllivier Robert * time (s past midnight) 903ea906c41SOllivier Robert * text message 904ea906c41SOllivier Robert */ 905ea906c41SOllivier Robert void 906ea906c41SOllivier Robert record_timing_stats( 9072b15cb3dSCy Schubert const char *text /* text message */ 908ea906c41SOllivier Robert ) 909ea906c41SOllivier Robert { 910ea906c41SOllivier Robert static unsigned int flshcnt; 911ea906c41SOllivier Robert l_fp now; 912ea906c41SOllivier Robert u_long day; 9139c2daa00SOllivier Robert 914ea906c41SOllivier Robert if (!stats_control) 915ea906c41SOllivier Robert return; 916ea906c41SOllivier Robert 917ea906c41SOllivier Robert get_systime(&now); 918ea906c41SOllivier Robert filegen_setup(&timingstats, now.l_ui); 919ea906c41SOllivier Robert day = now.l_ui / 86400 + MJD_1900; 920ea906c41SOllivier Robert now.l_ui %= 86400; 921ea906c41SOllivier Robert if (timingstats.fp != NULL) { 9222b15cb3dSCy Schubert fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, 9232b15cb3dSCy Schubert 3), text); 924ea906c41SOllivier Robert if (++flshcnt % 100 == 0) 925ea906c41SOllivier Robert fflush(timingstats.fp); 926ea906c41SOllivier Robert } 927ea906c41SOllivier Robert } 928ea906c41SOllivier Robert #endif 9292b15cb3dSCy Schubert 9302b15cb3dSCy Schubert 9312b15cb3dSCy Schubert /* 9322b15cb3dSCy Schubert * check_leap_file - See if the leapseconds file has been updated. 9332b15cb3dSCy Schubert * 9342b15cb3dSCy Schubert * Returns: n/a 9352b15cb3dSCy Schubert * 9362b15cb3dSCy Schubert * Note: This loads a new leapfile on the fly. Currently a leap file 9372b15cb3dSCy Schubert * without SHA1 signature is accepted, but if there is a signature line, 938*f5f40dd6SCy Schubert * the signature must be valid unless the ntp.conf leapfile line specified 939*f5f40dd6SCy Schubert * ignorehash. 9402b15cb3dSCy Schubert */ 9412b15cb3dSCy Schubert void 9422b15cb3dSCy Schubert check_leap_file( 9432b15cb3dSCy Schubert int is_daily_check, 9442b15cb3dSCy Schubert uint32_t ntptime, 9452b15cb3dSCy Schubert const time_t * systime 9462b15cb3dSCy Schubert ) 9472b15cb3dSCy Schubert { 9482b15cb3dSCy Schubert /* just do nothing if there is no leap file */ 9492b15cb3dSCy Schubert if ( ! (leapfile_name && *leapfile_name)) 9502b15cb3dSCy Schubert return; 9512b15cb3dSCy Schubert 9522b15cb3dSCy Schubert /* try to load leapfile, force it if no leapfile loaded yet */ 9532b15cb3dSCy Schubert if (leapsec_load_file( 9542b15cb3dSCy Schubert leapfile_name, &leapfile_stat, 9552d4e511cSCy Schubert !have_leapfile, is_daily_check, chck_leaphash)) 9562b15cb3dSCy Schubert have_leapfile = TRUE; 9572b15cb3dSCy Schubert else if (!have_leapfile) 9582b15cb3dSCy Schubert return; 9592b15cb3dSCy Schubert 9602b15cb3dSCy Schubert check_leap_expiration(is_daily_check, ntptime, systime); 9612b15cb3dSCy Schubert } 9622b15cb3dSCy Schubert 9632b15cb3dSCy Schubert /* 9642b15cb3dSCy Schubert * check expiration of a loaded leap table 9652b15cb3dSCy Schubert */ 9662b15cb3dSCy Schubert static void 9672b15cb3dSCy Schubert check_leap_expiration( 9682b15cb3dSCy Schubert int is_daily_check, 9692b15cb3dSCy Schubert uint32_t ntptime , 9702b15cb3dSCy Schubert const time_t *systime 9712b15cb3dSCy Schubert ) 9722b15cb3dSCy Schubert { 9732b15cb3dSCy Schubert static const char * const logPrefix = "leapsecond file"; 9742b15cb3dSCy Schubert int rc; 9752b15cb3dSCy Schubert 9762b15cb3dSCy Schubert /* test the expiration of the leap data and log with proper 9772b15cb3dSCy Schubert * level and frequency (once/hour or once/day, depending on the 9782b15cb3dSCy Schubert * state. 9792b15cb3dSCy Schubert */ 9802b15cb3dSCy Schubert rc = leapsec_daystolive(ntptime, systime); 9812b15cb3dSCy Schubert if (rc == 0) { 9822b15cb3dSCy Schubert msyslog(LOG_WARNING, 9832b15cb3dSCy Schubert "%s ('%s'): will expire in less than one day", 9842b15cb3dSCy Schubert logPrefix, leapfile_name); 9852b15cb3dSCy Schubert } else if (is_daily_check && rc < 28) { 9862b15cb3dSCy Schubert if (rc < 0) 9872b15cb3dSCy Schubert msyslog(LOG_ERR, 9882d4e511cSCy Schubert "%s ('%s'): expired %d day%s ago", 9892b15cb3dSCy Schubert logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s")); 9902b15cb3dSCy Schubert else 9912b15cb3dSCy Schubert msyslog(LOG_WARNING, 9922b15cb3dSCy Schubert "%s ('%s'): will expire in less than %d days", 9932b15cb3dSCy Schubert logPrefix, leapfile_name, 1+rc); 9942b15cb3dSCy Schubert } 9952b15cb3dSCy Schubert } 9962b15cb3dSCy Schubert 9972b15cb3dSCy Schubert 998c0b746e5SOllivier Robert /* 999c0b746e5SOllivier Robert * getauthkeys - read the authentication keys from the specified file 1000c0b746e5SOllivier Robert */ 1001c0b746e5SOllivier Robert void 1002c0b746e5SOllivier Robert getauthkeys( 1003ea906c41SOllivier Robert const char *keyfile 1004c0b746e5SOllivier Robert ) 1005c0b746e5SOllivier Robert { 10063311ff84SXin LI size_t len; 1007c0b746e5SOllivier Robert 1008c0b746e5SOllivier Robert len = strlen(keyfile); 10092b15cb3dSCy Schubert if (!len) 1010c0b746e5SOllivier Robert return; 1011c0b746e5SOllivier Robert 1012c0b746e5SOllivier Robert #ifndef SYS_WINNT 10132b15cb3dSCy Schubert key_file_name = erealloc(key_file_name, len + 1); 10142b15cb3dSCy Schubert memcpy(key_file_name, keyfile, len + 1); 1015c0b746e5SOllivier Robert #else 10162b15cb3dSCy Schubert key_file_name = erealloc(key_file_name, _MAX_PATH); 10172b15cb3dSCy Schubert if (len + 1 > _MAX_PATH) 10182b15cb3dSCy Schubert return; 10192b15cb3dSCy Schubert if (!ExpandEnvironmentStrings(keyfile, key_file_name, 10202b15cb3dSCy Schubert _MAX_PATH)) { 1021c0b746e5SOllivier Robert msyslog(LOG_ERR, 10222b15cb3dSCy Schubert "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); 10232b15cb3dSCy Schubert strlcpy(key_file_name, keyfile, _MAX_PATH); 1024c0b746e5SOllivier Robert } 10252b15cb3dSCy Schubert key_file_name = erealloc(key_file_name, 10262b15cb3dSCy Schubert 1 + strlen(key_file_name)); 1027c0b746e5SOllivier Robert #endif /* SYS_WINNT */ 1028c0b746e5SOllivier Robert 1029c0b746e5SOllivier Robert authreadkeys(key_file_name); 1030c0b746e5SOllivier Robert } 1031c0b746e5SOllivier Robert 1032c0b746e5SOllivier Robert 1033c0b746e5SOllivier Robert /* 1034c0b746e5SOllivier Robert * rereadkeys - read the authentication key file over again. 1035c0b746e5SOllivier Robert */ 1036c0b746e5SOllivier Robert void 1037c0b746e5SOllivier Robert rereadkeys(void) 1038c0b746e5SOllivier Robert { 10392b15cb3dSCy Schubert if (NULL != key_file_name) 1040c0b746e5SOllivier Robert authreadkeys(key_file_name); 1041c0b746e5SOllivier Robert } 10429c2daa00SOllivier Robert 1043ea906c41SOllivier Robert 1044ea906c41SOllivier Robert #if notyet 1045ea906c41SOllivier Robert /* 1046ea906c41SOllivier Robert * ntp_exit - document explicitly that ntpd has exited 1047ea906c41SOllivier Robert */ 1048ea906c41SOllivier Robert void 1049ea906c41SOllivier Robert ntp_exit(int retval) 1050ea906c41SOllivier Robert { 1051ea906c41SOllivier Robert msyslog(LOG_ERR, "EXITING with return code %d", retval); 1052ea906c41SOllivier Robert exit(retval); 1053ea906c41SOllivier Robert } 1054ea906c41SOllivier Robert #endif 10552b15cb3dSCy Schubert 10562b15cb3dSCy Schubert /* 10572b15cb3dSCy Schubert * fstostr - prettyprint NTP seconds 10582b15cb3dSCy Schubert */ 10592b15cb3dSCy Schubert char * fstostr( 10602b15cb3dSCy Schubert time_t ntp_stamp 10612b15cb3dSCy Schubert ) 10622b15cb3dSCy Schubert { 10632b15cb3dSCy Schubert char * buf; 10642b15cb3dSCy Schubert struct calendar tm; 10652b15cb3dSCy Schubert 10662b15cb3dSCy Schubert LIB_GETBUF(buf); 10672b15cb3dSCy Schubert if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0) 10682b15cb3dSCy Schubert snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error", 10692b15cb3dSCy Schubert (long)ntp_stamp); 10702b15cb3dSCy Schubert else 10712b15cb3dSCy Schubert snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d", 10722b15cb3dSCy Schubert tm.year, tm.month, tm.monthday, 10732b15cb3dSCy Schubert tm.hour, tm.minute); 10742b15cb3dSCy Schubert return buf; 10752b15cb3dSCy Schubert } 10762b15cb3dSCy Schubert 10772b15cb3dSCy Schubert 10782b15cb3dSCy Schubert /* 10792b15cb3dSCy Schubert * ntpd_time_stepped is called back by step_systime(), allowing ntpd 10802b15cb3dSCy Schubert * to do any one-time processing necessitated by the step. 10812b15cb3dSCy Schubert */ 10822b15cb3dSCy Schubert void 10832b15cb3dSCy Schubert ntpd_time_stepped(void) 10842b15cb3dSCy Schubert { 10852b15cb3dSCy Schubert u_int saved_mon_enabled; 10862b15cb3dSCy Schubert 10872b15cb3dSCy Schubert /* 10882b15cb3dSCy Schubert * flush the monitor MRU list which contains l_fp timestamps 10892b15cb3dSCy Schubert * which should not be compared across the step. 10902b15cb3dSCy Schubert */ 10912b15cb3dSCy Schubert if (MON_OFF != mon_enabled) { 10922b15cb3dSCy Schubert saved_mon_enabled = mon_enabled; 10932b15cb3dSCy Schubert mon_stop(MON_OFF); 10942b15cb3dSCy Schubert mon_start(saved_mon_enabled); 10952b15cb3dSCy Schubert } 10962b15cb3dSCy Schubert 10972b15cb3dSCy Schubert /* inform interpolating Windows code to allow time to go back */ 10982b15cb3dSCy Schubert #ifdef SYS_WINNT 10992b15cb3dSCy Schubert win_time_stepped(); 11002b15cb3dSCy Schubert #endif 11012b15cb3dSCy Schubert } 1102*f5f40dd6SCy Schubert 1103*f5f40dd6SCy Schubert 1104*f5f40dd6SCy Schubert #ifdef DEBUG 1105*f5f40dd6SCy Schubert void 1106*f5f40dd6SCy Schubert append_flagstr( 1107*f5f40dd6SCy Schubert char * flagstr, 1108*f5f40dd6SCy Schubert size_t sz, 1109*f5f40dd6SCy Schubert const char * text 1110*f5f40dd6SCy Schubert ) 1111*f5f40dd6SCy Schubert { 1112*f5f40dd6SCy Schubert if ('\0' != flagstr[0]) { 1113*f5f40dd6SCy Schubert strlcat(flagstr, ",", sz); 1114*f5f40dd6SCy Schubert } 1115*f5f40dd6SCy Schubert /* bail if we ran out of room */ 1116*f5f40dd6SCy Schubert INSIST(strlcat(flagstr, text, sz) < sz); 1117*f5f40dd6SCy Schubert } 1118*f5f40dd6SCy Schubert #endif /* DEBUG */ 1119