ntp_util.c revision 290000
1228692Sdes/* 2236109Sdes * ntp_util.c - stuff I didn't have any other place for 3228692Sdes */ 4228692Sdes#ifdef HAVE_CONFIG_H 5174832Sdes# include <config.h> 6236109Sdes#endif 7228692Sdes 8228692Sdes#include "ntpd.h" 9228692Sdes#include "ntp_unixtime.h" 10228692Sdes#include "ntp_filegen.h" 11117610Sdes#include "ntp_if.h" 12117610Sdes#include "ntp_stdlib.h" 13117610Sdes#include "ntp_assert.h" 14117610Sdes#include "ntp_calendar.h" 15228692Sdes#include "ntp_leapsec.h" 16228692Sdes#include "lib_strbuf.h" 17228692Sdes 18228692Sdes#include <stdio.h> 19228692Sdes#include <ctype.h> 20228692Sdes#include <sys/types.h> 21117610Sdes#ifdef HAVE_SYS_IOCTL_H 22117610Sdes# include <sys/ioctl.h> 23117610Sdes#endif 24117610Sdes#ifdef HAVE_UNISTD_H 25117610Sdes# include <unistd.h> 26228692Sdes#endif 27228692Sdes#include <sys/stat.h> 28228692Sdes 29228692Sdes#ifdef HAVE_IEEEFP_H 30228692Sdes# include <ieeefp.h> 31228692Sdes#endif 32117610Sdes#ifdef HAVE_MATH_H 33228692Sdes# include <math.h> 34228692Sdes#endif 35228692Sdes 36228692Sdes#if defined(VMS) 37228692Sdes# include <descrip.h> 38228692Sdes#endif /* VMS */ 39228692Sdes 40228692Sdes/* 41228692Sdes * Defines used by the leapseconds stuff 42228692Sdes */ 43228692Sdes#define MAX_TAI 100 /* max TAI offset (s) */ 44236109Sdes#define L_DAY 86400UL /* seconds per day */ 45228692Sdes#define L_YEAR (L_DAY * 365) /* days per year */ 46228692Sdes#define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */ 47228692Sdes#define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */ 48228692Sdes#define L_CENT (L_4YEAR * 25) /* days per century */ 49228692Sdes 50228692Sdes/* 51228692Sdes * This contains odds and ends, including the hourly stats, various 52228692Sdes * configuration items, leapseconds stuff, etc. 53228692Sdes */ 54228692Sdes/* 55228692Sdes * File names 56228692Sdes */ 57228692Sdesstatic char *key_file_name; /* keys file name */ 58228692Sdesstatic char *leapfile_name; /* leapseconds file name */ 59228692Sdesstatic struct stat leapfile_stat; /* leapseconds file stat() buffer */ 60228692Sdesstatic int /*BOOL*/have_leapfile = FALSE; 61228692Sdeschar *stats_drift_file; /* frequency file name */ 62228692Sdesstatic char *stats_temp_file; /* temp frequency file name */ 63228692Sdesstatic double wander_resid; /* last frequency update */ 64228692Sdesdouble wander_threshold = 1e-7; /* initial frequency threshold */ 65228692Sdes 66228692Sdes/* 67228692Sdes * Statistics file stuff 68228692Sdes */ 69228692Sdes#ifndef NTP_VAR 70228692Sdes# ifndef SYS_WINNT 71228692Sdes# define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ 72228692Sdes# else 73236109Sdes# define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ 74228692Sdes# endif /* SYS_WINNT */ 75228692Sdes#endif 76228692Sdes 77228692Sdes 78228692Sdeschar statsdir[MAXFILENAME] = NTP_VAR; 79228692Sdesstatic FILEGEN peerstats; 80117610Sdesstatic FILEGEN loopstats; 81228692Sdesstatic FILEGEN clockstats; 82141098Sdesstatic FILEGEN rawstats; 83236109Sdesstatic FILEGEN sysstats; 84228692Sdesstatic FILEGEN protostats; 85236109Sdesstatic FILEGEN cryptostats; 86141098Sdesstatic FILEGEN timingstats; 87228692Sdes 88174832Sdes/* 89174832Sdes * This controls whether stats are written to the fileset. Provided 90174832Sdes * so that ntpdc can turn off stats when the file system fills up. 91174832Sdes */ 92174832Sdesint stats_control; 93174832Sdes 94141098Sdes/* 95174832Sdes * Last frequency written to file. 96174832Sdes */ 97141098Sdesstatic double prev_drift_comp; /* last frequency update */ 98174832Sdes 99174832Sdes/* 100141098Sdes * Function prototypes 101228692Sdes */ 102228692Sdesstatic void record_sys_stats(void); 103228692Sdes void ntpd_time_stepped(void); 104228692Sdesstatic void check_leap_expiration(int, uint32_t, const time_t*); 105228692Sdes 106228692Sdes/* 107228692Sdes * Prototypes 108117610Sdes */ 109228692Sdes#ifdef DEBUG 110228692Sdesvoid uninit_util(void); 111228692Sdes#endif 112228692Sdes 113174832Sdes/* 114174832Sdes * uninit_util - free memory allocated by init_util 115228692Sdes */ 116228692Sdes#ifdef DEBUG 117174832Sdesvoid 118228692Sdesuninit_util(void) 119228692Sdes{ 120174832Sdes#if defined(_MSC_VER) && defined (_DEBUG) 121174832Sdes _CrtCheckMemory(); 122228692Sdes#endif 123228692Sdes if (stats_drift_file) { 124228692Sdes free(stats_drift_file); 125117610Sdes free(stats_temp_file); 126228692Sdes stats_drift_file = NULL; 127228692Sdes stats_temp_file = NULL; 128228692Sdes } 129228692Sdes if (key_file_name) { 130228692Sdes free(key_file_name); 131228692Sdes key_file_name = NULL; 132228692Sdes } 133228692Sdes filegen_unregister("peerstats"); 134228692Sdes filegen_unregister("loopstats"); 135228692Sdes filegen_unregister("clockstats"); 136228692Sdes filegen_unregister("rawstats"); 137228692Sdes filegen_unregister("sysstats"); 138228692Sdes filegen_unregister("protostats"); 139228692Sdes#ifdef AUTOKEY 140228692Sdes filegen_unregister("cryptostats"); 141228692Sdes#endif /* AUTOKEY */ 142228692Sdes#ifdef DEBUG_TIMING 143228692Sdes filegen_unregister("timingstats"); 144228692Sdes#endif /* DEBUG_TIMING */ 145228692Sdes 146228692Sdes#if defined(_MSC_VER) && defined (_DEBUG) 147228692Sdes _CrtCheckMemory(); 148228692Sdes#endif 149228692Sdes} 150228692Sdes#endif /* DEBUG */ 151228692Sdes 152228692Sdes 153228692Sdes/* 154228692Sdes * init_util - initialize the util module of ntpd 155125647Sdes */ 156174832Sdesvoid 157174832Sdesinit_util(void) 158174832Sdes{ 159117610Sdes filegen_register(statsdir, "peerstats", &peerstats); 160228692Sdes filegen_register(statsdir, "loopstats", &loopstats); 161228692Sdes filegen_register(statsdir, "clockstats", &clockstats); 162117610Sdes filegen_register(statsdir, "rawstats", &rawstats); 163228692Sdes filegen_register(statsdir, "sysstats", &sysstats); 164228692Sdes filegen_register(statsdir, "protostats", &protostats); 165228692Sdes filegen_register(statsdir, "cryptostats", &cryptostats); 166228692Sdes filegen_register(statsdir, "timingstats", &timingstats); 167228692Sdes /* 168228692Sdes * register with libntp ntp_set_tod() to call us back 169228692Sdes * when time is stepped. 170228692Sdes */ 171228692Sdes step_callback = &ntpd_time_stepped; 172228692Sdes#ifdef DEBUG 173228692Sdes atexit(&uninit_util); 174228692Sdes#endif /* DEBUG */ 175117610Sdes} 176141098Sdes 177228692Sdes 178228692Sdes/* 179228692Sdes * hourly_stats - print some interesting stats 180228692Sdes */ 181228692Sdesvoid 182228692Sdeswrite_stats(void) 183228692Sdes{ 184228692Sdes FILE *fp; 185228692Sdes#ifdef DOSYNCTODR 186228692Sdes struct timeval tv; 187228692Sdes#if !defined(VMS) 188228692Sdes int prio_set; 189228692Sdes#endif 190228692Sdes#ifdef HAVE_GETCLOCK 191228692Sdes struct timespec ts; 192228692Sdes#endif 193228692Sdes int o_prio; 194228692Sdes 195228692Sdes /* 196228692Sdes * Sometimes having a Sun can be a drag. 197228692Sdes * 198228692Sdes * The kernel variable dosynctodr controls whether the system's 199228692Sdes * soft clock is kept in sync with the battery clock. If it 200228692Sdes * is zero, then the soft clock is not synced, and the battery 201228692Sdes * clock is simply left to rot. That means that when the system 202228692Sdes * reboots, the battery clock (which has probably gone wacky) 203228692Sdes * sets the soft clock. That means ntpd starts off with a very 204228692Sdes * confused idea of what time it is. It then takes a large 205228692Sdes * amount of time to figure out just how wacky the battery clock 206228692Sdes * has made things drift, etc, etc. The solution is to make the 207228692Sdes * battery clock sync up to system time. The way to do THAT is 208228692Sdes * to simply set the time of day to the current time of day, but 209228692Sdes * as quickly as possible. This may, or may not be a sensible 210228692Sdes * thing to do. 211228692Sdes * 212228692Sdes * CAVEAT: settimeofday() steps the sun clock by about 800 us, 213228692Sdes * so setting DOSYNCTODR seems a bad idea in the 214228692Sdes * case of us resolution 215228692Sdes */ 216228692Sdes 217228692Sdes#if !defined(VMS) 218228692Sdes /* 219228692Sdes * (prr) getpriority returns -1 on error, but -1 is also a valid 220228692Sdes * return value (!), so instead we have to zero errno before the 221228692Sdes * call and check it for non-zero afterwards. 222228692Sdes */ 223228692Sdes errno = 0; 224228692Sdes prio_set = 0; 225228692Sdes o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ 226228692Sdes 227228692Sdes /* 228228692Sdes * (prr) if getpriority succeeded, call setpriority to raise 229228692Sdes * scheduling priority as high as possible. If that succeeds 230228692Sdes * as well, set the prio_set flag so we remember to reset 231228692Sdes * priority to its previous value below. Note that on Solaris 232228692Sdes * 2.6 (and beyond?), both getpriority and setpriority will fail 233228692Sdes * with ESRCH, because sched_setscheduler (called from main) put 234228692Sdes * us in the real-time scheduling class which setpriority 235228692Sdes * doesn't know about. Being in the real-time class is better 236228692Sdes * than anything setpriority can do, anyhow, so this error is 237228692Sdes * silently ignored. 238228692Sdes */ 239228692Sdes if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) 240228692Sdes prio_set = 1; /* overdrive */ 241228692Sdes#endif /* VMS */ 242228692Sdes#ifdef HAVE_GETCLOCK 243228692Sdes (void) getclock(TIMEOFDAY, &ts); 244228692Sdes tv.tv_sec = ts.tv_sec; 245228692Sdes tv.tv_usec = ts.tv_nsec / 1000; 246228692Sdes#else /* not HAVE_GETCLOCK */ 247228692Sdes GETTIMEOFDAY(&tv,(struct timezone *)NULL); 248228692Sdes#endif /* not HAVE_GETCLOCK */ 249228692Sdes if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) 250228692Sdes msyslog(LOG_ERR, "can't sync battery time: %m"); 251228692Sdes#if !defined(VMS) 252228692Sdes if (prio_set) 253228692Sdes setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ 254228692Sdes#endif /* VMS */ 255228692Sdes#endif /* DOSYNCTODR */ 256228692Sdes record_sys_stats(); 257228692Sdes if (stats_drift_file != 0) { 258228692Sdes 259228692Sdes /* 260228692Sdes * When the frequency file is written, initialize the 261228692Sdes * prev_drift_comp and wander_resid. Thereafter, 262228692Sdes * reduce the wander_resid by half each hour. When 263228692Sdes * the difference between the prev_drift_comp and 264228692Sdes * drift_comp is less than the wander_resid, update 265228692Sdes * the frequncy file. This minimizes the file writes to 266228692Sdes * nonvolaile storage. 267228692Sdes */ 268228692Sdes#ifdef DEBUG 269228692Sdes if (debug) 270228692Sdes printf("write_stats: frequency %.6lf thresh %.6lf, freq %.6lf\n", 271228692Sdes (prev_drift_comp - drift_comp) * 1e6, wander_resid * 272228692Sdes 1e6, drift_comp * 1e6); 273228692Sdes#endif 274228692Sdes if (fabs(prev_drift_comp - drift_comp) < wander_resid) { 275228692Sdes wander_resid *= 0.5; 276228692Sdes return; 277228692Sdes } 278228692Sdes prev_drift_comp = drift_comp; 279228692Sdes wander_resid = wander_threshold; 280228692Sdes if ((fp = fopen(stats_temp_file, "w")) == NULL) { 281228692Sdes msyslog(LOG_ERR, "frequency file %s: %m", 282228692Sdes stats_temp_file); 283228692Sdes return; 284228692Sdes } 285228692Sdes fprintf(fp, "%.3f\n", drift_comp * 1e6); 286228692Sdes (void)fclose(fp); 287228692Sdes /* atomic */ 288228692Sdes#ifdef SYS_WINNT 289228692Sdes if (_unlink(stats_drift_file)) /* rename semantics differ under NT */ 290228692Sdes msyslog(LOG_WARNING, 291228692Sdes "Unable to remove prior drift file %s, %m", 292228692Sdes stats_drift_file); 293228692Sdes#endif /* SYS_WINNT */ 294228692Sdes 295228692Sdes#ifndef NO_RENAME 296228692Sdes if (rename(stats_temp_file, stats_drift_file)) 297228692Sdes msyslog(LOG_WARNING, 298228692Sdes "Unable to rename temp drift file %s to %s, %m", 299228692Sdes stats_temp_file, stats_drift_file); 300228692Sdes#else 301228692Sdes /* we have no rename NFS of ftp in use */ 302228692Sdes if ((fp = fopen(stats_drift_file, "w")) == 303228692Sdes NULL) { 304228692Sdes msyslog(LOG_ERR, 305228692Sdes "frequency file %s: %m", 306228692Sdes stats_drift_file); 307228692Sdes return; 308228692Sdes } 309228692Sdes#endif 310228692Sdes 311228692Sdes#if defined(VMS) 312228692Sdes /* PURGE */ 313228692Sdes { 314228692Sdes $DESCRIPTOR(oldvers,";-1"); 315228692Sdes struct dsc$descriptor driftdsc = { 316228692Sdes strlen(stats_drift_file), 0, 0, 317228692Sdes stats_drift_file }; 318228692Sdes while(lib$delete_file(&oldvers, 319228692Sdes &driftdsc) & 1); 320228692Sdes } 321228692Sdes#endif 322228692Sdes } 323228692Sdes} 324228692Sdes 325228692Sdes 326228692Sdes/* 327228692Sdes * stats_config - configure the stats operation 328228692Sdes */ 329228692Sdesvoid 330228692Sdesstats_config( 331228692Sdes int item, 332228692Sdes const char *invalue /* only one type so far */ 333228692Sdes ) 334228692Sdes{ 335228692Sdes FILE *fp; 336228692Sdes const char *value; 337228692Sdes int len; 338228692Sdes double old_drift; 339228692Sdes l_fp now; 340228692Sdes time_t ttnow; 341228692Sdes#ifndef VMS 342228692Sdes const char temp_ext[] = ".TEMP"; 343228692Sdes#else 344228692Sdes const char temp_ext[] = "-TEMP"; 345228692Sdes#endif 346228692Sdes 347228692Sdes /* 348228692Sdes * Expand environment strings under Windows NT, since the 349228692Sdes * command interpreter doesn't do this, the program must. 350228692Sdes */ 351228692Sdes#ifdef SYS_WINNT 352228692Sdes char newvalue[MAX_PATH], parameter[MAX_PATH]; 353228692Sdes 354228692Sdes if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { 355228692Sdes switch (item) { 356228692Sdes case STATS_FREQ_FILE: 357228692Sdes strlcpy(parameter, "STATS_FREQ_FILE", 358228692Sdes sizeof(parameter)); 359228692Sdes break; 360228692Sdes 361228692Sdes case STATS_LEAP_FILE: 362228692Sdes strlcpy(parameter, "STATS_LEAP_FILE", 363228692Sdes sizeof(parameter)); 364228692Sdes break; 365228692Sdes 366228692Sdes case STATS_STATSDIR: 367228692Sdes strlcpy(parameter, "STATS_STATSDIR", 368228692Sdes sizeof(parameter)); 369228692Sdes break; 370228692Sdes 371228692Sdes case STATS_PID_FILE: 372228692Sdes strlcpy(parameter, "STATS_PID_FILE", 373228692Sdes sizeof(parameter)); 374228692Sdes break; 375228692Sdes 376228692Sdes default: 377228692Sdes strlcpy(parameter, "UNKNOWN", 378228692Sdes sizeof(parameter)); 379228692Sdes break; 380228692Sdes } 381228692Sdes value = invalue; 382228692Sdes msyslog(LOG_ERR, 383228692Sdes "ExpandEnvironmentStrings(%s) failed: %m\n", 384228692Sdes parameter); 385228692Sdes } else { 386236109Sdes value = newvalue; 387228692Sdes } 388228692Sdes#else 389228692Sdes value = invalue; 390228692Sdes#endif /* SYS_WINNT */ 391228692Sdes 392228692Sdes switch (item) { 393228692Sdes 394228692Sdes /* 395228692Sdes * Open and read frequency file. 396228692Sdes */ 397228692Sdes case STATS_FREQ_FILE: 398228692Sdes if (!value || (len = strlen(value)) == 0) 399228692Sdes break; 400228692Sdes 401228692Sdes stats_drift_file = erealloc(stats_drift_file, len + 1); 402228692Sdes stats_temp_file = erealloc(stats_temp_file, 403228692Sdes len + sizeof(".TEMP")); 404228692Sdes memcpy(stats_drift_file, value, (size_t)(len+1)); 405228692Sdes memcpy(stats_temp_file, value, (size_t)len); 406228692Sdes memcpy(stats_temp_file + len, temp_ext, sizeof(temp_ext)); 407228692Sdes 408228692Sdes /* 409228692Sdes * Open drift file and read frequency. If the file is 410228692Sdes * missing or contains errors, tell the loop to reset. 411228692Sdes */ 412228692Sdes if ((fp = fopen(stats_drift_file, "r")) == NULL) 413228692Sdes break; 414228692Sdes 415228692Sdes if (fscanf(fp, "%lf", &old_drift) != 1) { 416228692Sdes msyslog(LOG_ERR, 417228692Sdes "format error frequency file %s", 418228692Sdes stats_drift_file); 419228692Sdes fclose(fp); 420228692Sdes break; 421228692Sdes 422228692Sdes } 423228692Sdes fclose(fp); 424228692Sdes loop_config(LOOP_FREQ, old_drift); 425228692Sdes prev_drift_comp = drift_comp; 426228692Sdes break; 427228692Sdes 428228692Sdes /* 429228692Sdes * Specify statistics directory. 430228692Sdes */ 431228692Sdes case STATS_STATSDIR: 432228692Sdes 433228692Sdes /* - 1 since value may be missing the DIR_SEP. */ 434228692Sdes if (strlen(value) >= sizeof(statsdir) - 1) { 435228692Sdes msyslog(LOG_ERR, 436228692Sdes "statsdir too long (>%d, sigh)", 437228692Sdes (int)sizeof(statsdir) - 2); 438228692Sdes } else { 439228692Sdes int add_dir_sep; 440228692Sdes int value_l; 441228692Sdes 442228692Sdes /* Add a DIR_SEP unless we already have one. */ 443228692Sdes value_l = strlen(value); 444228692Sdes if (0 == value_l) 445228692Sdes add_dir_sep = FALSE; 446228692Sdes else 447228692Sdes add_dir_sep = (DIR_SEP != 448228692Sdes value[value_l - 1]); 449228692Sdes 450228692Sdes if (add_dir_sep) 451228692Sdes snprintf(statsdir, sizeof(statsdir), 452228692Sdes "%s%c", value, DIR_SEP); 453228692Sdes else 454228692Sdes snprintf(statsdir, sizeof(statsdir), 455228692Sdes "%s", value); 456228692Sdes filegen_statsdir(); 457228692Sdes } 458228692Sdes break; 459228692Sdes 460228692Sdes /* 461228692Sdes * Open pid file. 462228692Sdes */ 463228692Sdes case STATS_PID_FILE: 464228692Sdes if ((fp = fopen(value, "w")) == NULL) { 465228692Sdes msyslog(LOG_ERR, "pid file %s: %m", 466228692Sdes value); 467228692Sdes break; 468228692Sdes } 469228692Sdes fprintf(fp, "%d", (int)getpid()); 470228692Sdes fclose(fp); 471228692Sdes break; 472228692Sdes 473228692Sdes /* 474228692Sdes * Read leapseconds file. 475228692Sdes * 476228692Sdes * Note: Currently a leap file without SHA1 signature is 477228692Sdes * accepted, but if there is a signature line, the signature 478228692Sdes * must be valid or the file is rejected. 479228692Sdes */ 480228692Sdes case STATS_LEAP_FILE: 481228692Sdes if (!value || (len = strlen(value)) == 0) 482228692Sdes break; 483228692Sdes 484228692Sdes leapfile_name = erealloc(leapfile_name, len + 1); 485228692Sdes memcpy(leapfile_name, value, len + 1); 486228692Sdes 487228692Sdes if (leapsec_load_file( 488228692Sdes leapfile_name, &leapfile_stat, TRUE, TRUE)) 489228692Sdes { 490228692Sdes leap_signature_t lsig; 491228692Sdes 492228692Sdes get_systime(&now); 493228692Sdes time(&ttnow); 494228692Sdes leapsec_getsig(&lsig); 495228692Sdes mprintf_event(EVNT_TAI, NULL, 496228692Sdes "%d leap %s %s %s", 497228692Sdes lsig.taiof, 498228692Sdes fstostr(lsig.ttime), 499228692Sdes leapsec_expired(now.l_ui, NULL) 500228692Sdes ? "expired" 501228692Sdes : "expires", 502228692Sdes fstostr(lsig.etime)); 503228692Sdes 504228692Sdes have_leapfile = TRUE; 505228692Sdes 506228692Sdes /* force an immediate daily expiration check of 507228692Sdes * the leap seconds table 508228692Sdes */ 509228692Sdes check_leap_expiration(TRUE, now.l_ui, &ttnow); 510228692Sdes } 511228692Sdes break; 512228692Sdes 513228692Sdes default: 514228692Sdes /* oh well */ 515228692Sdes break; 516228692Sdes } 517228692Sdes} 518228692Sdes 519228692Sdes 520228692Sdes/* 521228692Sdes * record_peer_stats - write peer statistics to file 522228692Sdes * 523228692Sdes * file format: 524228692Sdes * day (MJD) 525228692Sdes * time (s past UTC midnight) 526228692Sdes * IP address 527228692Sdes * status word (hex) 528228692Sdes * offset 529228692Sdes * delay 530228692Sdes * dispersion 531228692Sdes * jitter 532228692Sdes*/ 533228692Sdesvoid 534228692Sdesrecord_peer_stats( 535228692Sdes sockaddr_u *addr, 536228692Sdes int status, 537228692Sdes double offset, /* offset */ 538228692Sdes double delay, /* delay */ 539228692Sdes double dispersion, /* dispersion */ 540228692Sdes double jitter /* jitter */ 541228692Sdes ) 542228692Sdes{ 543228692Sdes l_fp now; 544228692Sdes u_long day; 545228692Sdes 546228692Sdes if (!stats_control) 547228692Sdes return; 548228692Sdes 549228692Sdes get_systime(&now); 550228692Sdes filegen_setup(&peerstats, now.l_ui); 551228692Sdes day = now.l_ui / 86400 + MJD_1900; 552228692Sdes now.l_ui %= 86400; 553174832Sdes if (peerstats.fp != NULL) { 554174832Sdes fprintf(peerstats.fp, 555174832Sdes "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, 556174832Sdes ulfptoa(&now, 3), stoa(addr), status, offset, 557174832Sdes delay, dispersion, jitter); 558174832Sdes fflush(peerstats.fp); 559174832Sdes } 560174832Sdes} 561228692Sdes 562174832Sdes 563174832Sdes/* 564174832Sdes * record_loop_stats - write loop filter statistics to file 565174832Sdes * 566174832Sdes * file format: 567174832Sdes * day (MJD) 568174832Sdes * time (s past midnight) 569174832Sdes * offset 570228692Sdes * frequency (PPM) 571228692Sdes * jitter 572174832Sdes * wnder (PPM) 573228692Sdes * time constant (log2) 574228692Sdes */ 575228692Sdesvoid 576228692Sdesrecord_loop_stats( 577174832Sdes double offset, /* offset */ 578174832Sdes double freq, /* frequency (PPM) */ 579174832Sdes double jitter, /* jitter */ 580228692Sdes double wander, /* wander (PPM) */ 581228692Sdes int spoll 582174832Sdes ) 583174832Sdes{ 584228692Sdes l_fp now; 585174832Sdes u_long day; 586174832Sdes 587174832Sdes if (!stats_control) 588228692Sdes return; 589228692Sdes 590228692Sdes get_systime(&now); 591228692Sdes filegen_setup(&loopstats, now.l_ui); 592228692Sdes day = now.l_ui / 86400 + MJD_1900; 593228692Sdes now.l_ui %= 86400; 594228692Sdes if (loopstats.fp != NULL) { 595147455Sdes fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", 596228692Sdes day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, 597228692Sdes wander * 1e6, spoll); 598228692Sdes fflush(loopstats.fp); 599228692Sdes } 600228692Sdes} 601228692Sdes 602228692Sdes 603228692Sdes/* 604228692Sdes * record_clock_stats - write clock statistics to file 605228692Sdes * 606228692Sdes * file format: 607228692Sdes * day (MJD) 608228692Sdes * time (s past midnight) 609228692Sdes * IP address 610228692Sdes * text message 611228692Sdes */ 612228692Sdesvoid 613228692Sdesrecord_clock_stats( 614228692Sdes sockaddr_u *addr, 615228692Sdes const char *text /* timecode string */ 616228692Sdes ) 617228692Sdes{ 618228692Sdes l_fp now; 619228692Sdes u_long day; 620228692Sdes 621228692Sdes if (!stats_control) 622228692Sdes return; 623228692Sdes 624228692Sdes get_systime(&now); 625228692Sdes filegen_setup(&clockstats, now.l_ui); 626228692Sdes day = now.l_ui / 86400 + MJD_1900; 627228692Sdes now.l_ui %= 86400; 628228692Sdes if (clockstats.fp != NULL) { 629228692Sdes fprintf(clockstats.fp, "%lu %s %s %s\n", day, 630228692Sdes ulfptoa(&now, 3), stoa(addr), text); 631228692Sdes fflush(clockstats.fp); 632228692Sdes } 633228692Sdes} 634228692Sdes 635228692Sdes 636228692Sdes/* 637228692Sdes * mprintf_clock_stats - write clock statistics to file with 638228692Sdes * msnprintf-style formatting. 639228692Sdes */ 640228692Sdesint 641228692Sdesmprintf_clock_stats( 642228692Sdes sockaddr_u *addr, 643228692Sdes const char *fmt, 644228692Sdes ... 645228692Sdes ) 646228692Sdes{ 647228692Sdes va_list ap; 648228692Sdes int rc; 649228692Sdes char msg[512]; 650228692Sdes 651228692Sdes va_start(ap, fmt); 652228692Sdes rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 653228692Sdes va_end(ap); 654228692Sdes if (stats_control) 655228692Sdes record_clock_stats(addr, msg); 656228692Sdes 657228692Sdes return rc; 658228692Sdes} 659228692Sdes 660228692Sdes/* 661228692Sdes * record_raw_stats - write raw timestamps to file 662228692Sdes * 663228692Sdes * file format 664228692Sdes * day (MJD) 665141098Sdes * time (s past midnight) 666228692Sdes * peer ip address 667228692Sdes * IP address 668228692Sdes * t1 t2 t3 t4 timestamps 669228692Sdes */ 670228692Sdesvoid 671228692Sdesrecord_raw_stats( 672228692Sdes sockaddr_u *srcadr, 673228692Sdes sockaddr_u *dstadr, 674228692Sdes l_fp *t1, /* originate timestamp */ 675228692Sdes l_fp *t2, /* receive timestamp */ 676228692Sdes l_fp *t3, /* transmit timestamp */ 677228692Sdes l_fp *t4, /* destination timestamp */ 678228692Sdes int leap, 679228692Sdes int version, 680228692Sdes int mode, 681228692Sdes int stratum, 682228692Sdes int ppoll, 683228692Sdes int precision, 684228692Sdes double root_delay, /* seconds */ 685228692Sdes double root_dispersion,/* seconds */ 686228692Sdes u_int32 refid 687228692Sdes ) 688228692Sdes{ 689228692Sdes l_fp now; 690228692Sdes u_long day; 691228692Sdes 692228692Sdes if (!stats_control) 693228692Sdes return; 694228692Sdes 695228692Sdes get_systime(&now); 696228692Sdes filegen_setup(&rawstats, now.l_ui); 697228692Sdes day = now.l_ui / 86400 + MJD_1900; 698228692Sdes now.l_ui %= 86400; 699228692Sdes if (rawstats.fp != NULL) { 700228692Sdes fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s\n", 701228692Sdes day, ulfptoa(&now, 3), 702228692Sdes stoa(srcadr), dstadr ? stoa(dstadr) : "-", 703228692Sdes ulfptoa(t1, 9), ulfptoa(t2, 9), 704141098Sdes ulfptoa(t3, 9), ulfptoa(t4, 9), 705228692Sdes leap, version, mode, stratum, ppoll, precision, 706228692Sdes root_delay, root_dispersion, refid_str(refid, stratum)); 707141098Sdes fflush(rawstats.fp); 708228692Sdes } 709228692Sdes} 710228692Sdes 711228692Sdes 712228692Sdes/* 713228692Sdes * record_sys_stats - write system statistics to file 714228692Sdes * 715228692Sdes * file format 716228692Sdes * day (MJD) 717228692Sdes * time (s past midnight) 718228692Sdes * time since reset 719228692Sdes * packets recieved 720228692Sdes * packets for this host 721228692Sdes * current version 722228692Sdes * old version 723228692Sdes * access denied 724228692Sdes * bad length or format 725228692Sdes * bad authentication 726228692Sdes * declined 727228692Sdes * rate exceeded 728228692Sdes * KoD sent 729228692Sdes */ 730228692Sdesvoid 731228692Sdesrecord_sys_stats(void) 732228692Sdes{ 733228692Sdes l_fp now; 734228692Sdes u_long day; 735228692Sdes 736228692Sdes if (!stats_control) 737228692Sdes return; 738228692Sdes 739228692Sdes get_systime(&now); 740228692Sdes filegen_setup(&sysstats, now.l_ui); 741228692Sdes day = now.l_ui / 86400 + MJD_1900; 742228692Sdes now.l_ui %= 86400; 743228692Sdes if (sysstats.fp != NULL) { 744228692Sdes fprintf(sysstats.fp, 745228692Sdes "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 746228692Sdes day, ulfptoa(&now, 3), current_time - sys_stattime, 747228692Sdes sys_received, sys_processed, sys_newversion, 748228692Sdes sys_oldversion, sys_restricted, sys_badlength, 749228692Sdes sys_badauth, sys_declined, sys_limitrejected, 750228692Sdes sys_kodsent); 751228692Sdes fflush(sysstats.fp); 752228692Sdes proto_clr_stats(); 753228692Sdes } 754228692Sdes} 755228692Sdes 756228692Sdes 757228692Sdes/* 758228692Sdes * record_proto_stats - write system statistics to file 759228692Sdes * 760228692Sdes * file format 761228692Sdes * day (MJD) 762228692Sdes * time (s past midnight) 763228692Sdes * text message 764228692Sdes */ 765228692Sdesvoid 766228692Sdesrecord_proto_stats( 767228692Sdes char *str /* text string */ 768228692Sdes ) 769228692Sdes{ 770236109Sdes l_fp now; 771236109Sdes u_long day; 772228692Sdes 773228692Sdes if (!stats_control) 774228692Sdes return; 775228692Sdes 776228692Sdes get_systime(&now); 777228692Sdes filegen_setup(&protostats, now.l_ui); 778228692Sdes day = now.l_ui / 86400 + MJD_1900; 779228692Sdes now.l_ui %= 86400; 780228692Sdes if (protostats.fp != NULL) { 781228692Sdes fprintf(protostats.fp, "%lu %s %s\n", day, 782228692Sdes ulfptoa(&now, 3), str); 783228692Sdes fflush(protostats.fp); 784228692Sdes } 785228692Sdes} 786228692Sdes 787228692Sdes 788228692Sdes#ifdef AUTOKEY 789228692Sdes/* 790228692Sdes * record_crypto_stats - write crypto statistics to file 791228692Sdes * 792228692Sdes * file format: 793228692Sdes * day (mjd) 794228692Sdes * time (s past midnight) 795228692Sdes * peer ip address 796228692Sdes * text message 797228692Sdes */ 798228692Sdesvoid 799228692Sdesrecord_crypto_stats( 800228692Sdes sockaddr_u *addr, 801228692Sdes const char *text /* text message */ 802228692Sdes ) 803228692Sdes{ 804228692Sdes l_fp now; 805228692Sdes u_long day; 806228692Sdes 807228692Sdes if (!stats_control) 808228692Sdes return; 809228692Sdes 810228692Sdes get_systime(&now); 811228692Sdes filegen_setup(&cryptostats, now.l_ui); 812228692Sdes day = now.l_ui / 86400 + MJD_1900; 813228692Sdes now.l_ui %= 86400; 814228692Sdes if (cryptostats.fp != NULL) { 815228692Sdes if (addr == NULL) 816228692Sdes fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", 817228692Sdes day, ulfptoa(&now, 3), text); 818228692Sdes else 819228692Sdes fprintf(cryptostats.fp, "%lu %s %s %s\n", 820228692Sdes day, ulfptoa(&now, 3), stoa(addr), text); 821228692Sdes fflush(cryptostats.fp); 822228692Sdes } 823228692Sdes} 824228692Sdes#endif /* AUTOKEY */ 825228692Sdes 826228692Sdes 827228692Sdes#ifdef DEBUG_TIMING 828228692Sdes/* 829228692Sdes * record_timing_stats - write timing statistics to file 830228692Sdes * 831228692Sdes * file format: 832228692Sdes * day (mjd) 833228692Sdes * time (s past midnight) 834228692Sdes * text message 835228692Sdes */ 836228692Sdesvoid 837228692Sdesrecord_timing_stats( 838228692Sdes const char *text /* text message */ 839228692Sdes ) 840228692Sdes{ 841228692Sdes static unsigned int flshcnt; 842228692Sdes l_fp now; 843228692Sdes u_long day; 844228692Sdes 845228692Sdes if (!stats_control) 846228692Sdes return; 847228692Sdes 848228692Sdes get_systime(&now); 849228692Sdes filegen_setup(&timingstats, now.l_ui); 850228692Sdes day = now.l_ui / 86400 + MJD_1900; 851228692Sdes now.l_ui %= 86400; 852228692Sdes if (timingstats.fp != NULL) { 853228692Sdes fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, 854228692Sdes 3), text); 855228692Sdes if (++flshcnt % 100 == 0) 856228692Sdes fflush(timingstats.fp); 857228692Sdes } 858228692Sdes} 859228692Sdes#endif 860228692Sdes 861228692Sdes 862228692Sdes/* 863228692Sdes * check_leap_file - See if the leapseconds file has been updated. 864228692Sdes * 865228692Sdes * Returns: n/a 866228692Sdes * 867228692Sdes * Note: This loads a new leapfile on the fly. Currently a leap file 868228692Sdes * without SHA1 signature is accepted, but if there is a signature line, 869228692Sdes * the signature must be valid or the file is rejected. 870228692Sdes */ 871228692Sdesvoid 872228692Sdescheck_leap_file( 873228692Sdes int is_daily_check, 874228692Sdes uint32_t ntptime , 875228692Sdes const time_t *systime 876228692Sdes ) 877228692Sdes{ 878228692Sdes /* just do nothing if there is no leap file */ 879228692Sdes if ( ! (leapfile_name && *leapfile_name)) 880228692Sdes return; 881228692Sdes 882228692Sdes /* try to load leapfile, force it if no leapfile loaded yet */ 883228692Sdes if (leapsec_load_file( 884228692Sdes leapfile_name, &leapfile_stat, 885228692Sdes !have_leapfile, is_daily_check)) 886228692Sdes have_leapfile = TRUE; 887228692Sdes else if (!have_leapfile) 888228692Sdes return; 889228692Sdes 890228692Sdes check_leap_expiration(is_daily_check, ntptime, systime); 891228692Sdes} 892228692Sdes 893228692Sdes/* 894228692Sdes * check expiration of a loaded leap table 895228692Sdes */ 896228692Sdesstatic void 897228692Sdescheck_leap_expiration( 898228692Sdes int is_daily_check, 899228692Sdes uint32_t ntptime , 900228692Sdes const time_t *systime 901228692Sdes ) 902228692Sdes{ 903228692Sdes static const char * const logPrefix = "leapsecond file"; 904228692Sdes int rc; 905228692Sdes 906228692Sdes /* test the expiration of the leap data and log with proper 907228692Sdes * level and frequency (once/hour or once/day, depending on the 908228692Sdes * state. 909228692Sdes */ 910228692Sdes rc = leapsec_daystolive(ntptime, systime); 911228692Sdes if (rc == 0) { 912228692Sdes msyslog(LOG_WARNING, 913228692Sdes "%s ('%s'): will expire in less than one day", 914228692Sdes logPrefix, leapfile_name); 915228692Sdes } else if (is_daily_check && rc < 28) { 916228692Sdes if (rc < 0) 917228692Sdes msyslog(LOG_ERR, 918228692Sdes "%s ('%s'): expired less than %d day%s ago", 919228692Sdes logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s")); 920228692Sdes else 921228692Sdes msyslog(LOG_WARNING, 922228692Sdes "%s ('%s'): will expire in less than %d days", 923228692Sdes logPrefix, leapfile_name, 1+rc); 924228692Sdes } 925228692Sdes} 926228692Sdes 927228692Sdes 928228692Sdes/* 929228692Sdes * getauthkeys - read the authentication keys from the specified file 930228692Sdes */ 931228692Sdesvoid 932228692Sdesgetauthkeys( 933228692Sdes const char *keyfile 934228692Sdes ) 935228692Sdes{ 936228692Sdes int len; 937228692Sdes 938228692Sdes len = strlen(keyfile); 939228692Sdes if (!len) 940228692Sdes return; 941228692Sdes 942228692Sdes#ifndef SYS_WINNT 943228692Sdes key_file_name = erealloc(key_file_name, len + 1); 944228692Sdes memcpy(key_file_name, keyfile, len + 1); 945228692Sdes#else 946228692Sdes key_file_name = erealloc(key_file_name, _MAX_PATH); 947228692Sdes if (len + 1 > _MAX_PATH) 948228692Sdes return; 949228692Sdes if (!ExpandEnvironmentStrings(keyfile, key_file_name, 950228692Sdes _MAX_PATH)) { 951228692Sdes msyslog(LOG_ERR, 952228692Sdes "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); 953228692Sdes strlcpy(key_file_name, keyfile, _MAX_PATH); 954141098Sdes } 955228692Sdes key_file_name = erealloc(key_file_name, 956228692Sdes 1 + strlen(key_file_name)); 957228692Sdes#endif /* SYS_WINNT */ 958228692Sdes 959228692Sdes authreadkeys(key_file_name); 960228692Sdes} 961228692Sdes 962228692Sdes 963228692Sdes/* 964228692Sdes * rereadkeys - read the authentication key file over again. 965228692Sdes */ 966228692Sdesvoid 967228692Sdesrereadkeys(void) 968228692Sdes{ 969228692Sdes if (NULL != key_file_name) 970228692Sdes authreadkeys(key_file_name); 971228692Sdes} 972228692Sdes 973228692Sdes 974228692Sdes#if notyet 975228692Sdes/* 976228692Sdes * ntp_exit - document explicitly that ntpd has exited 977228692Sdes */ 978228692Sdesvoid 979228692Sdesntp_exit(int retval) 980228692Sdes{ 981228692Sdes msyslog(LOG_ERR, "EXITING with return code %d", retval); 982228692Sdes exit(retval); 983228692Sdes} 984228692Sdes#endif 985228692Sdes 986228692Sdes/* 987228692Sdes * fstostr - prettyprint NTP seconds 988228692Sdes */ 989228692Sdeschar * fstostr( 990228692Sdes time_t ntp_stamp 991228692Sdes ) 992228692Sdes{ 993228692Sdes char * buf; 994228692Sdes struct calendar tm; 995228692Sdes 996228692Sdes LIB_GETBUF(buf); 997228692Sdes if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0) 998228692Sdes snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error", 999228692Sdes (long)ntp_stamp); 1000228692Sdes else 1001228692Sdes snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d", 1002228692Sdes tm.year, tm.month, tm.monthday, 1003228692Sdes tm.hour, tm.minute); 1004228692Sdes return buf; 1005228692Sdes} 1006228692Sdes 1007228692Sdes 1008228692Sdes/* 1009228692Sdes * ntpd_time_stepped is called back by step_systime(), allowing ntpd 1010228692Sdes * to do any one-time processing necessitated by the step. 1011228692Sdes */ 1012228692Sdesvoid 1013228692Sdesntpd_time_stepped(void) 1014228692Sdes{ 1015228692Sdes u_int saved_mon_enabled; 1016228692Sdes 1017228692Sdes /* 1018228692Sdes * flush the monitor MRU list which contains l_fp timestamps 1019228692Sdes * which should not be compared across the step. 1020228692Sdes */ 1021228692Sdes if (MON_OFF != mon_enabled) { 1022228692Sdes saved_mon_enabled = mon_enabled; 1023228692Sdes mon_stop(MON_OFF); 1024228692Sdes mon_start(saved_mon_enabled); 1025228692Sdes } 1026228692Sdes 1027228692Sdes /* inform interpolating Windows code to allow time to go back */ 1028228692Sdes#ifdef SYS_WINNT 1029228692Sdes win_time_stepped(); 1030228692Sdes#endif 1031228692Sdes} 1032228692Sdes