154359Sroberto/* 254359Sroberto * ntp_util.c - stuff I didn't have any other place for 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 582498Sroberto# include <config.h> 654359Sroberto#endif 754359Sroberto 854359Sroberto#include "ntpd.h" 954359Sroberto#include "ntp_unixtime.h" 1054359Sroberto#include "ntp_filegen.h" 1154359Sroberto#include "ntp_if.h" 1254359Sroberto#include "ntp_stdlib.h" 13280849Scy#include "ntp_assert.h" 14280849Scy#include "ntp_calendar.h" 15280849Scy#include "ntp_leapsec.h" 16280849Scy#include "lib_strbuf.h" 1754359Sroberto 1882498Sroberto#include <stdio.h> 1982498Sroberto#include <ctype.h> 2082498Sroberto#include <sys/types.h> 2182498Sroberto#ifdef HAVE_SYS_IOCTL_H 2282498Sroberto# include <sys/ioctl.h> 2382498Sroberto#endif 24280849Scy#ifdef HAVE_UNISTD_H 25280849Scy# include <unistd.h> 26280849Scy#endif 27280849Scy#include <sys/stat.h> 2882498Sroberto 2982498Sroberto#ifdef HAVE_IEEEFP_H 3082498Sroberto# include <ieeefp.h> 3182498Sroberto#endif 3282498Sroberto#ifdef HAVE_MATH_H 3382498Sroberto# include <math.h> 3482498Sroberto#endif 3582498Sroberto 3654359Sroberto#if defined(VMS) 37182007Sroberto# include <descrip.h> 3854359Sroberto#endif /* VMS */ 3954359Sroberto 4054359Sroberto/* 41280849Scy * Defines used by the leapseconds stuff 4254359Sroberto */ 43280849Scy#define MAX_TAI 100 /* max TAI offset (s) */ 44280849Scy#define L_DAY 86400UL /* seconds per day */ 45280849Scy#define L_YEAR (L_DAY * 365) /* days per year */ 46280849Scy#define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */ 47280849Scy#define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */ 48280849Scy#define L_CENT (L_4YEAR * 25) /* days per century */ 49280849Scy 5054359Sroberto/* 51280849Scy * This contains odds and ends, including the hourly stats, various 52280849Scy * configuration items, leapseconds stuff, etc. 5354359Sroberto */ 5454359Sroberto/* 55280849Scy * File names 5654359Sroberto */ 57280849Scystatic char *key_file_name; /* keys file name */ 58280849Scystatic char *leapfile_name; /* leapseconds file name */ 59280849Scystatic struct stat leapfile_stat; /* leapseconds file stat() buffer */ 60280849Scystatic int /*BOOL*/have_leapfile = FALSE; 61358659Scystatic int /*BOOL*/chck_leaphash = TRUE; 62280849Scychar *stats_drift_file; /* frequency file name */ 63280849Scystatic char *stats_temp_file; /* temp frequency file name */ 64280849Scystatic double wander_resid; /* last frequency update */ 65280849Scydouble wander_threshold = 1e-7; /* initial frequency threshold */ 6654359Sroberto 6754359Sroberto/* 6854359Sroberto * Statistics file stuff 6954359Sroberto */ 7054359Sroberto#ifndef NTP_VAR 71182007Sroberto# ifndef SYS_WINNT 72182007Sroberto# define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ 73182007Sroberto# else 74280849Scy# define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ 75182007Sroberto# endif /* SYS_WINNT */ 7654359Sroberto#endif 7754359Sroberto 7854359Sroberto 79280849Scychar statsdir[MAXFILENAME] = NTP_VAR; 8054359Srobertostatic FILEGEN peerstats; 8154359Srobertostatic FILEGEN loopstats; 8254359Srobertostatic FILEGEN clockstats; 8354359Srobertostatic FILEGEN rawstats; 84132451Srobertostatic FILEGEN sysstats; 85280849Scystatic FILEGEN protostats; 86280849Scystatic FILEGEN cryptostats; 87182007Srobertostatic FILEGEN timingstats; 8854359Sroberto 8954359Sroberto/* 9054359Sroberto * This controls whether stats are written to the fileset. Provided 91358659Scy * so that ntpdc can turn off stats when the file system fills up. 9254359Sroberto */ 9354359Srobertoint stats_control; 9454359Sroberto 9554359Sroberto/* 96280849Scy * Last frequency written to file. 97182007Sroberto */ 98280849Scystatic double prev_drift_comp; /* last frequency update */ 99182007Sroberto 100182007Sroberto/* 101280849Scy * Function prototypes 10254359Sroberto */ 103280849Scystatic void record_sys_stats(void); 104280849Scy void ntpd_time_stepped(void); 105280849Scystatic void check_leap_expiration(int, uint32_t, const time_t*); 106280849Scy 107358659Scy/* 108280849Scy * Prototypes 109280849Scy */ 110280849Scy#ifdef DEBUG 111280849Scyvoid uninit_util(void); 112280849Scy#endif 113280849Scy 114280849Scy/* 115280849Scy * uninit_util - free memory allocated by init_util 116280849Scy */ 117280849Scy#ifdef DEBUG 11854359Srobertovoid 119280849Scyuninit_util(void) 12054359Sroberto{ 121280849Scy#if defined(_MSC_VER) && defined (_DEBUG) 122280849Scy _CrtCheckMemory(); 123280849Scy#endif 124280849Scy if (stats_drift_file) { 125280849Scy free(stats_drift_file); 126280849Scy free(stats_temp_file); 127280849Scy stats_drift_file = NULL; 128280849Scy stats_temp_file = NULL; 129280849Scy } 130280849Scy if (key_file_name) { 131280849Scy free(key_file_name); 132280849Scy key_file_name = NULL; 133280849Scy } 134280849Scy filegen_unregister("peerstats"); 135280849Scy filegen_unregister("loopstats"); 136280849Scy filegen_unregister("clockstats"); 137280849Scy filegen_unregister("rawstats"); 138280849Scy filegen_unregister("sysstats"); 139280849Scy filegen_unregister("protostats"); 140280849Scy#ifdef AUTOKEY 141280849Scy filegen_unregister("cryptostats"); 142280849Scy#endif /* AUTOKEY */ 143280849Scy#ifdef DEBUG_TIMING 144280849Scy filegen_unregister("timingstats"); 145280849Scy#endif /* DEBUG_TIMING */ 14654359Sroberto 147280849Scy#if defined(_MSC_VER) && defined (_DEBUG) 148280849Scy _CrtCheckMemory(); 149280849Scy#endif 150280849Scy} 151280849Scy#endif /* DEBUG */ 152132451Sroberto 15354359Sroberto 154280849Scy/* 155280849Scy * init_util - initialize the util module of ntpd 156280849Scy */ 157280849Scyvoid 158280849Scyinit_util(void) 159280849Scy{ 160280849Scy filegen_register(statsdir, "peerstats", &peerstats); 161280849Scy filegen_register(statsdir, "loopstats", &loopstats); 162280849Scy filegen_register(statsdir, "clockstats", &clockstats); 163280849Scy filegen_register(statsdir, "rawstats", &rawstats); 164280849Scy filegen_register(statsdir, "sysstats", &sysstats); 165280849Scy filegen_register(statsdir, "protostats", &protostats); 166280849Scy filegen_register(statsdir, "cryptostats", &cryptostats); 167280849Scy filegen_register(statsdir, "timingstats", &timingstats); 168280849Scy /* 169280849Scy * register with libntp ntp_set_tod() to call us back 170280849Scy * when time is stepped. 171280849Scy */ 172280849Scy step_callback = &ntpd_time_stepped; 173280849Scy#ifdef DEBUG 174280849Scy atexit(&uninit_util); 175280849Scy#endif /* DEBUG */ 17654359Sroberto} 17754359Sroberto 17854359Sroberto 17954359Sroberto/* 18054359Sroberto * hourly_stats - print some interesting stats 18154359Sroberto */ 18254359Srobertovoid 183182007Srobertowrite_stats(void) 18454359Sroberto{ 185280849Scy FILE *fp; 18654359Sroberto#ifdef DOSYNCTODR 18754359Sroberto struct timeval tv; 18854359Sroberto#if !defined(VMS) 189280849Scy int prio_set; 19054359Sroberto#endif 19154359Sroberto#ifdef HAVE_GETCLOCK 192280849Scy struct timespec ts; 19354359Sroberto#endif 194280849Scy int o_prio; 19554359Sroberto 19654359Sroberto /* 19754359Sroberto * Sometimes having a Sun can be a drag. 19854359Sroberto * 19954359Sroberto * The kernel variable dosynctodr controls whether the system's 20054359Sroberto * soft clock is kept in sync with the battery clock. If it 20154359Sroberto * is zero, then the soft clock is not synced, and the battery 20254359Sroberto * clock is simply left to rot. That means that when the system 20354359Sroberto * reboots, the battery clock (which has probably gone wacky) 20454359Sroberto * sets the soft clock. That means ntpd starts off with a very 20554359Sroberto * confused idea of what time it is. It then takes a large 20654359Sroberto * amount of time to figure out just how wacky the battery clock 20754359Sroberto * has made things drift, etc, etc. The solution is to make the 20854359Sroberto * battery clock sync up to system time. The way to do THAT is 20954359Sroberto * to simply set the time of day to the current time of day, but 21054359Sroberto * as quickly as possible. This may, or may not be a sensible 21154359Sroberto * thing to do. 21254359Sroberto * 21354359Sroberto * CAVEAT: settimeofday() steps the sun clock by about 800 us, 214280849Scy * so setting DOSYNCTODR seems a bad idea in the 215280849Scy * case of us resolution 21654359Sroberto */ 21754359Sroberto 21854359Sroberto#if !defined(VMS) 219280849Scy /* 220280849Scy * (prr) getpriority returns -1 on error, but -1 is also a valid 221132451Sroberto * return value (!), so instead we have to zero errno before the 222132451Sroberto * call and check it for non-zero afterwards. 22354359Sroberto */ 22454359Sroberto errno = 0; 22554359Sroberto prio_set = 0; 22654359Sroberto o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ 22754359Sroberto 228132451Sroberto /* 229132451Sroberto * (prr) if getpriority succeeded, call setpriority to raise 23054359Sroberto * scheduling priority as high as possible. If that succeeds 23154359Sroberto * as well, set the prio_set flag so we remember to reset 232132451Sroberto * priority to its previous value below. Note that on Solaris 233132451Sroberto * 2.6 (and beyond?), both getpriority and setpriority will fail 234132451Sroberto * with ESRCH, because sched_setscheduler (called from main) put 235132451Sroberto * us in the real-time scheduling class which setpriority 236132451Sroberto * doesn't know about. Being in the real-time class is better 237132451Sroberto * than anything setpriority can do, anyhow, so this error is 238132451Sroberto * silently ignored. 23954359Sroberto */ 24054359Sroberto if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) 241132451Sroberto prio_set = 1; /* overdrive */ 24254359Sroberto#endif /* VMS */ 24354359Sroberto#ifdef HAVE_GETCLOCK 244280849Scy (void) getclock(TIMEOFDAY, &ts); 245280849Scy tv.tv_sec = ts.tv_sec; 246280849Scy tv.tv_usec = ts.tv_nsec / 1000; 24754359Sroberto#else /* not HAVE_GETCLOCK */ 24854359Sroberto GETTIMEOFDAY(&tv,(struct timezone *)NULL); 24954359Sroberto#endif /* not HAVE_GETCLOCK */ 250280849Scy if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) 25154359Sroberto msyslog(LOG_ERR, "can't sync battery time: %m"); 25254359Sroberto#if !defined(VMS) 25354359Sroberto if (prio_set) 254132451Sroberto setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ 25554359Sroberto#endif /* VMS */ 25654359Sroberto#endif /* DOSYNCTODR */ 257132451Sroberto record_sys_stats(); 25854359Sroberto if (stats_drift_file != 0) { 259280849Scy 260280849Scy /* 261280849Scy * When the frequency file is written, initialize the 262280849Scy * prev_drift_comp and wander_resid. Thereafter, 263280849Scy * reduce the wander_resid by half each hour. When 264280849Scy * the difference between the prev_drift_comp and 265280849Scy * drift_comp is less than the wander_resid, update 266280849Scy * the frequncy file. This minimizes the file writes to 267280849Scy * nonvolaile storage. 268280849Scy */ 269280849Scy#ifdef DEBUG 270280849Scy if (debug) 271280849Scy printf("write_stats: frequency %.6lf thresh %.6lf, freq %.6lf\n", 272280849Scy (prev_drift_comp - drift_comp) * 1e6, wander_resid * 273280849Scy 1e6, drift_comp * 1e6); 274280849Scy#endif 275280849Scy if (fabs(prev_drift_comp - drift_comp) < wander_resid) { 276280849Scy wander_resid *= 0.5; 277280849Scy return; 278280849Scy } 279280849Scy prev_drift_comp = drift_comp; 280280849Scy wander_resid = wander_threshold; 28154359Sroberto if ((fp = fopen(stats_temp_file, "w")) == NULL) { 282280849Scy msyslog(LOG_ERR, "frequency file %s: %m", 28354359Sroberto stats_temp_file); 28454359Sroberto return; 28554359Sroberto } 28654359Sroberto fprintf(fp, "%.3f\n", drift_comp * 1e6); 28754359Sroberto (void)fclose(fp); 28854359Sroberto /* atomic */ 28954359Sroberto#ifdef SYS_WINNT 290280849Scy if (_unlink(stats_drift_file)) /* rename semantics differ under NT */ 291358659Scy msyslog(LOG_WARNING, 292358659Scy "Unable to remove prior drift file %s, %m", 293280849Scy stats_drift_file); 29454359Sroberto#endif /* SYS_WINNT */ 29554359Sroberto 29654359Sroberto#ifndef NO_RENAME 297280849Scy if (rename(stats_temp_file, stats_drift_file)) 298358659Scy msyslog(LOG_WARNING, 299358659Scy "Unable to rename temp drift file %s to %s, %m", 300280849Scy stats_temp_file, stats_drift_file); 30154359Sroberto#else 302182007Sroberto /* we have no rename NFS of ftp in use */ 303280849Scy if ((fp = fopen(stats_drift_file, "w")) == 304280849Scy NULL) { 305280849Scy msyslog(LOG_ERR, 306280849Scy "frequency file %s: %m", 30754359Sroberto stats_drift_file); 30854359Sroberto return; 30954359Sroberto } 31054359Sroberto#endif 31154359Sroberto 31254359Sroberto#if defined(VMS) 31354359Sroberto /* PURGE */ 31454359Sroberto { 31554359Sroberto $DESCRIPTOR(oldvers,";-1"); 31654359Sroberto struct dsc$descriptor driftdsc = { 317280849Scy strlen(stats_drift_file), 0, 0, 318280849Scy stats_drift_file }; 319280849Scy while(lib$delete_file(&oldvers, 320280849Scy &driftdsc) & 1); 32154359Sroberto } 32254359Sroberto#endif 32354359Sroberto } 32454359Sroberto} 32554359Sroberto 32654359Sroberto 32754359Sroberto/* 32854359Sroberto * stats_config - configure the stats operation 32954359Sroberto */ 33054359Srobertovoid 33154359Srobertostats_config( 33254359Sroberto int item, 333358659Scy const char *invalue, /* only one type so far */ 334358659Scy int optflag 33554359Sroberto ) 33654359Sroberto{ 337280849Scy FILE *fp; 338182007Sroberto const char *value; 339293423Sdelphij size_t len; 340280849Scy double old_drift; 341280849Scy l_fp now; 342280849Scy time_t ttnow; 343280849Scy#ifndef VMS 344280849Scy const char temp_ext[] = ".TEMP"; 345280849Scy#else 346280849Scy const char temp_ext[] = "-TEMP"; 347280849Scy#endif 34854359Sroberto 349132451Sroberto /* 350132451Sroberto * Expand environment strings under Windows NT, since the 351132451Sroberto * command interpreter doesn't do this, the program must. 35254359Sroberto */ 35354359Sroberto#ifdef SYS_WINNT 35454359Sroberto char newvalue[MAX_PATH], parameter[MAX_PATH]; 35554359Sroberto 356132451Sroberto if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { 357280849Scy switch (item) { 358280849Scy case STATS_FREQ_FILE: 359280849Scy strlcpy(parameter, "STATS_FREQ_FILE", 360280849Scy sizeof(parameter)); 36154359Sroberto break; 362280849Scy 363280849Scy case STATS_LEAP_FILE: 364280849Scy strlcpy(parameter, "STATS_LEAP_FILE", 365280849Scy sizeof(parameter)); 36654359Sroberto break; 367280849Scy 368280849Scy case STATS_STATSDIR: 369280849Scy strlcpy(parameter, "STATS_STATSDIR", 370280849Scy sizeof(parameter)); 37154359Sroberto break; 372280849Scy 373280849Scy case STATS_PID_FILE: 374280849Scy strlcpy(parameter, "STATS_PID_FILE", 375280849Scy sizeof(parameter)); 37654359Sroberto break; 377280849Scy 378280849Scy default: 379280849Scy strlcpy(parameter, "UNKNOWN", 380280849Scy sizeof(parameter)); 381280849Scy break; 38254359Sroberto } 38354359Sroberto value = invalue; 38454359Sroberto msyslog(LOG_ERR, 385280849Scy "ExpandEnvironmentStrings(%s) failed: %m\n", 386280849Scy parameter); 387132451Sroberto } else { 388132451Sroberto value = newvalue; 38954359Sroberto } 390358659Scy#else 39154359Sroberto value = invalue; 39254359Sroberto#endif /* SYS_WINNT */ 39354359Sroberto 394280849Scy switch (item) { 39554359Sroberto 396280849Scy /* 397280849Scy * Open and read frequency file. 398280849Scy */ 399280849Scy case STATS_FREQ_FILE: 400280849Scy if (!value || (len = strlen(value)) == 0) 401280849Scy break; 40254359Sroberto 403280849Scy stats_drift_file = erealloc(stats_drift_file, len + 1); 404358659Scy stats_temp_file = erealloc(stats_temp_file, 405280849Scy len + sizeof(".TEMP")); 406280849Scy memcpy(stats_drift_file, value, (size_t)(len+1)); 407280849Scy memcpy(stats_temp_file, value, (size_t)len); 408280849Scy memcpy(stats_temp_file + len, temp_ext, sizeof(temp_ext)); 40954359Sroberto 41054359Sroberto /* 411132451Sroberto * Open drift file and read frequency. If the file is 412132451Sroberto * missing or contains errors, tell the loop to reset. 41354359Sroberto */ 414280849Scy if ((fp = fopen(stats_drift_file, "r")) == NULL) 41554359Sroberto break; 416280849Scy 41754359Sroberto if (fscanf(fp, "%lf", &old_drift) != 1) { 418280849Scy msyslog(LOG_ERR, 419358659Scy "format error frequency file %s", 420280849Scy stats_drift_file); 421132451Sroberto fclose(fp); 42254359Sroberto break; 423280849Scy 42454359Sroberto } 425132451Sroberto fclose(fp); 426280849Scy loop_config(LOOP_FREQ, old_drift); 427280849Scy prev_drift_comp = drift_comp; 42854359Sroberto break; 429280849Scy 430280849Scy /* 431280849Scy * Specify statistics directory. 432280849Scy */ 433280849Scy case STATS_STATSDIR: 434280849Scy 435280849Scy /* - 1 since value may be missing the DIR_SEP. */ 436280849Scy if (strlen(value) >= sizeof(statsdir) - 1) { 43754359Sroberto msyslog(LOG_ERR, 438280849Scy "statsdir too long (>%d, sigh)", 439280849Scy (int)sizeof(statsdir) - 2); 44054359Sroberto } else { 441280849Scy int add_dir_sep; 442293423Sdelphij size_t value_l; 44354359Sroberto 444280849Scy /* Add a DIR_SEP unless we already have one. */ 445280849Scy value_l = strlen(value); 446280849Scy if (0 == value_l) 447280849Scy add_dir_sep = FALSE; 448280849Scy else 449280849Scy add_dir_sep = (DIR_SEP != 450280849Scy value[value_l - 1]); 451280849Scy 452280849Scy if (add_dir_sep) 453280849Scy snprintf(statsdir, sizeof(statsdir), 454280849Scy "%s%c", value, DIR_SEP); 455280849Scy else 456280849Scy snprintf(statsdir, sizeof(statsdir), 457280849Scy "%s", value); 458280849Scy filegen_statsdir(); 45954359Sroberto } 46054359Sroberto break; 46154359Sroberto 462280849Scy /* 463280849Scy * Open pid file. 464280849Scy */ 465280849Scy case STATS_PID_FILE: 46654359Sroberto if ((fp = fopen(value, "w")) == NULL) { 467280849Scy msyslog(LOG_ERR, "pid file %s: %m", 468280849Scy value); 46954359Sroberto break; 47054359Sroberto } 471280849Scy fprintf(fp, "%d", (int)getpid()); 472280849Scy fclose(fp); 47354359Sroberto break; 47454359Sroberto 475280849Scy /* 476280849Scy * Read leapseconds file. 477280849Scy * 478280849Scy * Note: Currently a leap file without SHA1 signature is 479280849Scy * accepted, but if there is a signature line, the signature 480280849Scy * must be valid or the file is rejected. 481280849Scy */ 482280849Scy case STATS_LEAP_FILE: 483280849Scy if (!value || (len = strlen(value)) == 0) 484280849Scy break; 485280849Scy 486280849Scy leapfile_name = erealloc(leapfile_name, len + 1); 487280849Scy memcpy(leapfile_name, value, len + 1); 488358659Scy chck_leaphash = optflag; 489280849Scy 490280849Scy if (leapsec_load_file( 491358659Scy leapfile_name, &leapfile_stat, 492358659Scy TRUE, TRUE, chck_leaphash)) 493280849Scy { 494280849Scy leap_signature_t lsig; 495280849Scy 496280849Scy get_systime(&now); 497280849Scy time(&ttnow); 498280849Scy leapsec_getsig(&lsig); 499280849Scy mprintf_event(EVNT_TAI, NULL, 500280849Scy "%d leap %s %s %s", 501280849Scy lsig.taiof, 502280849Scy fstostr(lsig.ttime), 503280849Scy leapsec_expired(now.l_ui, NULL) 504280849Scy ? "expired" 505280849Scy : "expires", 506280849Scy fstostr(lsig.etime)); 507280849Scy 508280849Scy have_leapfile = TRUE; 509280849Scy 510280849Scy /* force an immediate daily expiration check of 511280849Scy * the leap seconds table 512280849Scy */ 513280849Scy check_leap_expiration(TRUE, now.l_ui, &ttnow); 514280849Scy } 515280849Scy break; 516280849Scy 517280849Scy default: 51854359Sroberto /* oh well */ 51954359Sroberto break; 52054359Sroberto } 52154359Sroberto} 52254359Sroberto 523280849Scy 52454359Sroberto/* 52554359Sroberto * record_peer_stats - write peer statistics to file 52654359Sroberto * 52754359Sroberto * file format: 528280849Scy * day (MJD) 52954359Sroberto * time (s past UTC midnight) 530280849Scy * IP address 531280849Scy * status word (hex) 532280849Scy * offset 533280849Scy * delay 534280849Scy * dispersion 535280849Scy * jitter 53654359Sroberto*/ 53754359Srobertovoid 53854359Srobertorecord_peer_stats( 539280849Scy sockaddr_u *addr, 540132451Sroberto int status, 541280849Scy double offset, /* offset */ 542280849Scy double delay, /* delay */ 543280849Scy double dispersion, /* dispersion */ 544280849Scy double jitter /* jitter */ 54554359Sroberto ) 54654359Sroberto{ 547132451Sroberto l_fp now; 548132451Sroberto u_long day; 54954359Sroberto 55054359Sroberto if (!stats_control) 55154359Sroberto return; 55254359Sroberto 553132451Sroberto get_systime(&now); 554132451Sroberto filegen_setup(&peerstats, now.l_ui); 555132451Sroberto day = now.l_ui / 86400 + MJD_1900; 556132451Sroberto now.l_ui %= 86400; 55754359Sroberto if (peerstats.fp != NULL) { 55854359Sroberto fprintf(peerstats.fp, 559280849Scy "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, 560280849Scy ulfptoa(&now, 3), stoa(addr), status, offset, 561280849Scy delay, dispersion, jitter); 56254359Sroberto fflush(peerstats.fp); 56354359Sroberto } 56454359Sroberto} 565182007Sroberto 566280849Scy 56754359Sroberto/* 56854359Sroberto * record_loop_stats - write loop filter statistics to file 56954359Sroberto * 57054359Sroberto * file format: 571280849Scy * day (MJD) 57254359Sroberto * time (s past midnight) 573280849Scy * offset 574280849Scy * frequency (PPM) 575280849Scy * jitter 576280849Scy * wnder (PPM) 577280849Scy * time constant (log2) 57854359Sroberto */ 57954359Srobertovoid 58082498Srobertorecord_loop_stats( 581280849Scy double offset, /* offset */ 582280849Scy double freq, /* frequency (PPM) */ 583280849Scy double jitter, /* jitter */ 584280849Scy double wander, /* wander (PPM) */ 585132451Sroberto int spoll 58682498Sroberto ) 58754359Sroberto{ 588132451Sroberto l_fp now; 589132451Sroberto u_long day; 59054359Sroberto 59154359Sroberto if (!stats_control) 59254359Sroberto return; 59354359Sroberto 594132451Sroberto get_systime(&now); 595132451Sroberto filegen_setup(&loopstats, now.l_ui); 596132451Sroberto day = now.l_ui / 86400 + MJD_1900; 597132451Sroberto now.l_ui %= 86400; 59854359Sroberto if (loopstats.fp != NULL) { 599182007Sroberto fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", 600132451Sroberto day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, 601280849Scy wander * 1e6, spoll); 60254359Sroberto fflush(loopstats.fp); 60354359Sroberto } 60454359Sroberto} 60554359Sroberto 606280849Scy 60754359Sroberto/* 60854359Sroberto * record_clock_stats - write clock statistics to file 60954359Sroberto * 61054359Sroberto * file format: 611280849Scy * day (MJD) 61254359Sroberto * time (s past midnight) 613280849Scy * IP address 61454359Sroberto * text message 61554359Sroberto */ 61654359Srobertovoid 61754359Srobertorecord_clock_stats( 618280849Scy sockaddr_u *addr, 619280849Scy const char *text /* timecode string */ 62054359Sroberto ) 62154359Sroberto{ 622132451Sroberto l_fp now; 623132451Sroberto u_long day; 62454359Sroberto 62554359Sroberto if (!stats_control) 62654359Sroberto return; 62754359Sroberto 628132451Sroberto get_systime(&now); 629132451Sroberto filegen_setup(&clockstats, now.l_ui); 630132451Sroberto day = now.l_ui / 86400 + MJD_1900; 631132451Sroberto now.l_ui %= 86400; 63254359Sroberto if (clockstats.fp != NULL) { 633280849Scy fprintf(clockstats.fp, "%lu %s %s %s\n", day, 634280849Scy ulfptoa(&now, 3), stoa(addr), text); 63554359Sroberto fflush(clockstats.fp); 63654359Sroberto } 63754359Sroberto} 63854359Sroberto 639280849Scy 64054359Sroberto/* 641280849Scy * mprintf_clock_stats - write clock statistics to file with 642280849Scy * msnprintf-style formatting. 643280849Scy */ 644280849Scyint 645280849Scymprintf_clock_stats( 646280849Scy sockaddr_u *addr, 647280849Scy const char *fmt, 648280849Scy ... 649280849Scy ) 650280849Scy{ 651280849Scy va_list ap; 652280849Scy int rc; 653280849Scy char msg[512]; 654280849Scy 655280849Scy va_start(ap, fmt); 656280849Scy rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 657280849Scy va_end(ap); 658280849Scy if (stats_control) 659280849Scy record_clock_stats(addr, msg); 660280849Scy 661280849Scy return rc; 662280849Scy} 663280849Scy 664280849Scy/* 66554359Sroberto * record_raw_stats - write raw timestamps to file 66654359Sroberto * 66754359Sroberto * file format 668280849Scy * day (MJD) 66954359Sroberto * time (s past midnight) 67054359Sroberto * peer ip address 671280849Scy * IP address 67254359Sroberto * t1 t2 t3 t4 timestamps 673330106Sdelphij * leap, version, mode, stratum, ppoll, precision, root delay, root dispersion, REFID 674330106Sdelphij * length and hex dump of any EFs and any legacy MAC. 67554359Sroberto */ 67654359Srobertovoid 67754359Srobertorecord_raw_stats( 678280849Scy sockaddr_u *srcadr, 679280849Scy sockaddr_u *dstadr, 680280849Scy l_fp *t1, /* originate timestamp */ 681280849Scy l_fp *t2, /* receive timestamp */ 682280849Scy l_fp *t3, /* transmit timestamp */ 683280849Scy l_fp *t4, /* destination timestamp */ 684280849Scy int leap, 685280849Scy int version, 686280849Scy int mode, 687280849Scy int stratum, 688280849Scy int ppoll, 689280849Scy int precision, 690280849Scy double root_delay, /* seconds */ 691280849Scy double root_dispersion,/* seconds */ 692330106Sdelphij u_int32 refid, 693330106Sdelphij int len, 694330106Sdelphij u_char *extra 69554359Sroberto ) 69654359Sroberto{ 697132451Sroberto l_fp now; 698132451Sroberto u_long day; 69954359Sroberto 70054359Sroberto if (!stats_control) 70154359Sroberto return; 70254359Sroberto 703132451Sroberto get_systime(&now); 704132451Sroberto filegen_setup(&rawstats, now.l_ui); 705132451Sroberto day = now.l_ui / 86400 + MJD_1900; 706132451Sroberto now.l_ui %= 86400; 70754359Sroberto if (rawstats.fp != NULL) { 708330106Sdelphij fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s", 709280849Scy day, ulfptoa(&now, 3), 710330106Sdelphij srcadr ? stoa(srcadr) : "-", 711330106Sdelphij dstadr ? stoa(dstadr) : "-", 712280849Scy ulfptoa(t1, 9), ulfptoa(t2, 9), 713280849Scy ulfptoa(t3, 9), ulfptoa(t4, 9), 714280849Scy leap, version, mode, stratum, ppoll, precision, 715280849Scy root_delay, root_dispersion, refid_str(refid, stratum)); 716330106Sdelphij if (len > 0) { 717330106Sdelphij int i; 718330106Sdelphij 719330106Sdelphij fprintf(rawstats.fp, " %d: ", len); 720330106Sdelphij for (i = 0; i < len; ++i) { 721330106Sdelphij fprintf(rawstats.fp, "%02x", extra[i]); 722330106Sdelphij } 723330106Sdelphij } 724330106Sdelphij fprintf(rawstats.fp, "\n"); 72554359Sroberto fflush(rawstats.fp); 72654359Sroberto } 72754359Sroberto} 72854359Sroberto 729132451Sroberto 73054359Sroberto/* 731132451Sroberto * record_sys_stats - write system statistics to file 732132451Sroberto * 733132451Sroberto * file format 734280849Scy * day (MJD) 735132451Sroberto * time (s past midnight) 736280849Scy * time since reset 737132451Sroberto * packets recieved 738280849Scy * packets for this host 739132451Sroberto * current version 740280849Scy * old version 741132451Sroberto * access denied 742132451Sroberto * bad length or format 743132451Sroberto * bad authentication 744280849Scy * declined 745132451Sroberto * rate exceeded 746280849Scy * KoD sent 747132451Sroberto */ 748132451Srobertovoid 749132451Srobertorecord_sys_stats(void) 750132451Sroberto{ 751132451Sroberto l_fp now; 752132451Sroberto u_long day; 753132451Sroberto 754132451Sroberto if (!stats_control) 755132451Sroberto return; 756132451Sroberto 757132451Sroberto get_systime(&now); 758132451Sroberto filegen_setup(&sysstats, now.l_ui); 759132451Sroberto day = now.l_ui / 86400 + MJD_1900; 760132451Sroberto now.l_ui %= 86400; 761132451Sroberto if (sysstats.fp != NULL) { 762280849Scy fprintf(sysstats.fp, 763280849Scy "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 764280849Scy day, ulfptoa(&now, 3), current_time - sys_stattime, 765280849Scy sys_received, sys_processed, sys_newversion, 766280849Scy sys_oldversion, sys_restricted, sys_badlength, 767280849Scy sys_badauth, sys_declined, sys_limitrejected, 768280849Scy sys_kodsent); 769132451Sroberto fflush(sysstats.fp); 770132451Sroberto proto_clr_stats(); 771132451Sroberto } 772132451Sroberto} 773132451Sroberto 774132451Sroberto 775132451Sroberto/* 776280849Scy * record_proto_stats - write system statistics to file 777280849Scy * 778280849Scy * file format 779280849Scy * day (MJD) 780280849Scy * time (s past midnight) 781280849Scy * text message 782280849Scy */ 783280849Scyvoid 784280849Scyrecord_proto_stats( 785280849Scy char *str /* text string */ 786280849Scy ) 787280849Scy{ 788280849Scy l_fp now; 789280849Scy u_long day; 790280849Scy 791280849Scy if (!stats_control) 792280849Scy return; 793280849Scy 794280849Scy get_systime(&now); 795280849Scy filegen_setup(&protostats, now.l_ui); 796280849Scy day = now.l_ui / 86400 + MJD_1900; 797280849Scy now.l_ui %= 86400; 798280849Scy if (protostats.fp != NULL) { 799280849Scy fprintf(protostats.fp, "%lu %s %s\n", day, 800280849Scy ulfptoa(&now, 3), str); 801280849Scy fflush(protostats.fp); 802280849Scy } 803280849Scy} 804280849Scy 805280849Scy 806280849Scy#ifdef AUTOKEY 807280849Scy/* 808132451Sroberto * record_crypto_stats - write crypto statistics to file 809132451Sroberto * 810132451Sroberto * file format: 811132451Sroberto * day (mjd) 812132451Sroberto * time (s past midnight) 813280849Scy * peer ip address 814132451Sroberto * text message 815132451Sroberto */ 816132451Srobertovoid 817132451Srobertorecord_crypto_stats( 818280849Scy sockaddr_u *addr, 819280849Scy const char *text /* text message */ 820132451Sroberto ) 821132451Sroberto{ 822132451Sroberto l_fp now; 823132451Sroberto u_long day; 824132451Sroberto 825132451Sroberto if (!stats_control) 826132451Sroberto return; 827132451Sroberto 828132451Sroberto get_systime(&now); 829132451Sroberto filegen_setup(&cryptostats, now.l_ui); 830132451Sroberto day = now.l_ui / 86400 + MJD_1900; 831132451Sroberto now.l_ui %= 86400; 832132451Sroberto if (cryptostats.fp != NULL) { 833132451Sroberto if (addr == NULL) 834280849Scy fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", 835132451Sroberto day, ulfptoa(&now, 3), text); 836132451Sroberto else 837132451Sroberto fprintf(cryptostats.fp, "%lu %s %s %s\n", 838132451Sroberto day, ulfptoa(&now, 3), stoa(addr), text); 839132451Sroberto fflush(cryptostats.fp); 840132451Sroberto } 841132451Sroberto} 842280849Scy#endif /* AUTOKEY */ 843132451Sroberto 844280849Scy 845182007Sroberto#ifdef DEBUG_TIMING 846182007Sroberto/* 847280849Scy * record_timing_stats - write timing statistics to file 848182007Sroberto * 849182007Sroberto * file format: 850182007Sroberto * day (mjd) 851182007Sroberto * time (s past midnight) 852182007Sroberto * text message 853182007Sroberto */ 854182007Srobertovoid 855182007Srobertorecord_timing_stats( 856280849Scy const char *text /* text message */ 857182007Sroberto ) 858182007Sroberto{ 859182007Sroberto static unsigned int flshcnt; 860182007Sroberto l_fp now; 861182007Sroberto u_long day; 862132451Sroberto 863182007Sroberto if (!stats_control) 864182007Sroberto return; 865182007Sroberto 866182007Sroberto get_systime(&now); 867182007Sroberto filegen_setup(&timingstats, now.l_ui); 868182007Sroberto day = now.l_ui / 86400 + MJD_1900; 869182007Sroberto now.l_ui %= 86400; 870182007Sroberto if (timingstats.fp != NULL) { 871280849Scy fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, 872280849Scy 3), text); 873182007Sroberto if (++flshcnt % 100 == 0) 874182007Sroberto fflush(timingstats.fp); 875182007Sroberto } 876182007Sroberto} 877182007Sroberto#endif 878280849Scy 879280849Scy 880132451Sroberto/* 881280849Scy * check_leap_file - See if the leapseconds file has been updated. 882280849Scy * 883280849Scy * Returns: n/a 884280849Scy * 885280849Scy * Note: This loads a new leapfile on the fly. Currently a leap file 886280849Scy * without SHA1 signature is accepted, but if there is a signature line, 887280849Scy * the signature must be valid or the file is rejected. 888280849Scy */ 889280849Scyvoid 890280849Scycheck_leap_file( 891280849Scy int is_daily_check, 892280849Scy uint32_t ntptime , 893280849Scy const time_t *systime 894280849Scy ) 895280849Scy{ 896280849Scy /* just do nothing if there is no leap file */ 897280849Scy if ( ! (leapfile_name && *leapfile_name)) 898280849Scy return; 899358659Scy 900280849Scy /* try to load leapfile, force it if no leapfile loaded yet */ 901280849Scy if (leapsec_load_file( 902280849Scy leapfile_name, &leapfile_stat, 903358659Scy !have_leapfile, is_daily_check, chck_leaphash)) 904280849Scy have_leapfile = TRUE; 905280849Scy else if (!have_leapfile) 906280849Scy return; 907280849Scy 908280849Scy check_leap_expiration(is_daily_check, ntptime, systime); 909280849Scy} 910280849Scy 911280849Scy/* 912280849Scy * check expiration of a loaded leap table 913280849Scy */ 914280849Scystatic void 915280849Scycheck_leap_expiration( 916280849Scy int is_daily_check, 917280849Scy uint32_t ntptime , 918280849Scy const time_t *systime 919280849Scy ) 920280849Scy{ 921280849Scy static const char * const logPrefix = "leapsecond file"; 922280849Scy int rc; 923280849Scy 924280849Scy /* test the expiration of the leap data and log with proper 925280849Scy * level and frequency (once/hour or once/day, depending on the 926280849Scy * state. 927280849Scy */ 928358659Scy rc = leapsec_daystolive(ntptime, systime); 929280849Scy if (rc == 0) { 930280849Scy msyslog(LOG_WARNING, 931280849Scy "%s ('%s'): will expire in less than one day", 932280849Scy logPrefix, leapfile_name); 933280849Scy } else if (is_daily_check && rc < 28) { 934280849Scy if (rc < 0) 935280849Scy msyslog(LOG_ERR, 936358659Scy "%s ('%s'): expired %d day%s ago", 937280849Scy logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s")); 938280849Scy else 939280849Scy msyslog(LOG_WARNING, 940280849Scy "%s ('%s'): will expire in less than %d days", 941280849Scy logPrefix, leapfile_name, 1+rc); 942280849Scy } 943280849Scy} 944280849Scy 945280849Scy 946280849Scy/* 94754359Sroberto * getauthkeys - read the authentication keys from the specified file 94854359Sroberto */ 94954359Srobertovoid 95054359Srobertogetauthkeys( 951182007Sroberto const char *keyfile 95254359Sroberto ) 95354359Sroberto{ 954293423Sdelphij size_t len; 95554359Sroberto 95654359Sroberto len = strlen(keyfile); 957280849Scy if (!len) 95854359Sroberto return; 959358659Scy 96054359Sroberto#ifndef SYS_WINNT 961280849Scy key_file_name = erealloc(key_file_name, len + 1); 962280849Scy memcpy(key_file_name, keyfile, len + 1); 96354359Sroberto#else 964280849Scy key_file_name = erealloc(key_file_name, _MAX_PATH); 965280849Scy if (len + 1 > _MAX_PATH) 966280849Scy return; 967280849Scy if (!ExpandEnvironmentStrings(keyfile, key_file_name, 968280849Scy _MAX_PATH)) { 96954359Sroberto msyslog(LOG_ERR, 970280849Scy "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); 971280849Scy strlcpy(key_file_name, keyfile, _MAX_PATH); 97254359Sroberto } 973280849Scy key_file_name = erealloc(key_file_name, 974280849Scy 1 + strlen(key_file_name)); 97554359Sroberto#endif /* SYS_WINNT */ 97654359Sroberto 97754359Sroberto authreadkeys(key_file_name); 97854359Sroberto} 97954359Sroberto 98054359Sroberto 98154359Sroberto/* 98254359Sroberto * rereadkeys - read the authentication key file over again. 98354359Sroberto */ 98454359Srobertovoid 98554359Srobertorereadkeys(void) 98654359Sroberto{ 987280849Scy if (NULL != key_file_name) 988280849Scy authreadkeys(key_file_name); 98954359Sroberto} 990132451Sroberto 991280849Scy 992280849Scy#if notyet 993132451Sroberto/* 994280849Scy * ntp_exit - document explicitly that ntpd has exited 995132451Sroberto */ 996280849Scyvoid 997280849Scyntp_exit(int retval) 998280849Scy{ 999280849Scy msyslog(LOG_ERR, "EXITING with return code %d", retval); 1000280849Scy exit(retval); 1001280849Scy} 1002280849Scy#endif 1003280849Scy 1004280849Scy/* 1005280849Scy * fstostr - prettyprint NTP seconds 1006280849Scy */ 1007280849Scychar * fstostr( 1008280849Scy time_t ntp_stamp 1009132451Sroberto ) 1010132451Sroberto{ 1011280849Scy char * buf; 1012280849Scy struct calendar tm; 1013132451Sroberto 1014280849Scy LIB_GETBUF(buf); 1015280849Scy if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0) 1016280849Scy snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error", 1017280849Scy (long)ntp_stamp); 1018280849Scy else 1019280849Scy snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d", 1020280849Scy tm.year, tm.month, tm.monthday, 1021280849Scy tm.hour, tm.minute); 1022280849Scy return buf; 1023280849Scy} 1024132451Sroberto 1025132451Sroberto 1026182007Sroberto/* 1027280849Scy * ntpd_time_stepped is called back by step_systime(), allowing ntpd 1028280849Scy * to do any one-time processing necessitated by the step. 1029182007Sroberto */ 1030182007Srobertovoid 1031280849Scyntpd_time_stepped(void) 1032182007Sroberto{ 1033280849Scy u_int saved_mon_enabled; 1034280849Scy 1035280849Scy /* 1036280849Scy * flush the monitor MRU list which contains l_fp timestamps 1037280849Scy * which should not be compared across the step. 1038280849Scy */ 1039280849Scy if (MON_OFF != mon_enabled) { 1040280849Scy saved_mon_enabled = mon_enabled; 1041280849Scy mon_stop(MON_OFF); 1042280849Scy mon_start(saved_mon_enabled); 1043280849Scy } 1044280849Scy 1045280849Scy /* inform interpolating Windows code to allow time to go back */ 1046280849Scy#ifdef SYS_WINNT 1047280849Scy win_time_stepped(); 1048280849Scy#endif 1049182007Sroberto} 1050