Annotation of embedaddon/ntp/ntpd/ntp_util.c, revision 1.1
1.1 ! misho 1: /*
! 2: * ntp_util.c - stuff I didn't have any other place for
! 3: */
! 4: #ifdef HAVE_CONFIG_H
! 5: # include <config.h>
! 6: #endif
! 7:
! 8: #include "ntpd.h"
! 9: #include "ntp_io.h"
! 10: #include "ntp_unixtime.h"
! 11: #include "ntp_filegen.h"
! 12: #include "ntp_if.h"
! 13: #include "ntp_stdlib.h"
! 14: #include "ntp_assert.h"
! 15:
! 16: #include <stdio.h>
! 17: #include <ctype.h>
! 18: #include <sys/types.h>
! 19: #ifdef HAVE_SYS_IOCTL_H
! 20: # include <sys/ioctl.h>
! 21: #endif
! 22:
! 23: #ifdef HAVE_IEEEFP_H
! 24: # include <ieeefp.h>
! 25: #endif
! 26: #ifdef HAVE_MATH_H
! 27: # include <math.h>
! 28: #endif
! 29:
! 30: #ifdef DOSYNCTODR
! 31: # if !defined(VMS)
! 32: # include <sys/resource.h>
! 33: # endif /* VMS */
! 34: #endif
! 35:
! 36: #if defined(VMS)
! 37: # include <descrip.h>
! 38: #endif /* VMS */
! 39:
! 40: /*
! 41: * Defines used by the leapseconds stuff
! 42: */
! 43: #define MAX_TAI 100 /* max TAI offset (s) */
! 44: #define L_DAY 86400UL /* seconds per day */
! 45: #define L_YEAR (L_DAY * 365) /* days per year */
! 46: #define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */
! 47: #define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */
! 48: #define L_CENT (L_4YEAR * 25) /* days per century */
! 49:
! 50: /*
! 51: * This contains odds and ends, including the hourly stats, various
! 52: * configuration items, leapseconds stuff, etc.
! 53: */
! 54: /*
! 55: * File names
! 56: */
! 57: static char *key_file_name; /* keys file name */
! 58: char *leapseconds_file_name; /* leapseconds file name */
! 59: char *stats_drift_file; /* frequency file name */
! 60: static char *stats_temp_file; /* temp frequency file name */
! 61: double wander_resid; /* wander threshold */
! 62: double wander_threshold = 1e-7; /* initial wander threshold */
! 63: int drift_file_sw; /* clock update switch */
! 64:
! 65: /*
! 66: * Statistics file stuff
! 67: */
! 68: #ifndef NTP_VAR
! 69: # ifndef SYS_WINNT
! 70: # define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */
! 71: # else
! 72: # define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */
! 73: # endif /* SYS_WINNT */
! 74: #endif
! 75:
! 76: #ifndef MAXPATHLEN
! 77: # define MAXPATHLEN 256
! 78: #endif
! 79:
! 80: #ifdef DEBUG_TIMING
! 81: static FILEGEN timingstats;
! 82: #endif
! 83: #ifdef OPENSSL
! 84: static FILEGEN cryptostats;
! 85: #endif /* OPENSSL */
! 86:
! 87: static char statsdir[MAXPATHLEN] = NTP_VAR;
! 88: static FILEGEN peerstats;
! 89: static FILEGEN loopstats;
! 90: static FILEGEN clockstats;
! 91: static FILEGEN rawstats;
! 92: static FILEGEN sysstats;
! 93: static FILEGEN protostats;
! 94:
! 95: /*
! 96: * This controls whether stats are written to the fileset. Provided
! 97: * so that ntpdc can turn off stats when the file system fills up.
! 98: */
! 99: int stats_control;
! 100:
! 101: /*
! 102: * Initial frequency offset later passed to the loopfilter.
! 103: */
! 104: double old_drift = 1e9; /* current frequency */
! 105: static double prev_drift_comp; /* last frequency update */
! 106:
! 107: /*
! 108: * Static prototypes
! 109: */
! 110: static int leap_file(FILE *);
! 111: static void record_sys_stats(void);
! 112:
! 113: /*
! 114: * Prototypes
! 115: */
! 116: #ifdef DEBUG
! 117: void uninit_util(void);
! 118: #endif
! 119:
! 120:
! 121: /*
! 122: * uninit_util - free memory allocated by init_util
! 123: */
! 124: #ifdef DEBUG
! 125: void
! 126: uninit_util(void)
! 127: {
! 128: #if defined(_MSC_VER) && defined (_DEBUG)
! 129: _CrtCheckMemory();
! 130: #endif
! 131: if (stats_drift_file) {
! 132: free(stats_drift_file);
! 133: free(stats_temp_file);
! 134: stats_drift_file = NULL;
! 135: stats_temp_file = NULL;
! 136: }
! 137: if (key_file_name) {
! 138: free(key_file_name);
! 139: key_file_name = NULL;
! 140: }
! 141: filegen_unregister("peerstats");
! 142: filegen_unregister("loopstats");
! 143: filegen_unregister("clockstats");
! 144: filegen_unregister("rawstats");
! 145: filegen_unregister("sysstats");
! 146: filegen_unregister("protostats");
! 147: #ifdef OPENSSL
! 148: filegen_unregister("cryptostats");
! 149: #endif /* OPENSSL */
! 150: #ifdef DEBUG_TIMING
! 151: filegen_unregister("timingstats");
! 152: #endif /* DEBUG_TIMING */
! 153:
! 154: #if defined(_MSC_VER) && defined (_DEBUG)
! 155: _CrtCheckMemory();
! 156: #endif
! 157: }
! 158: #endif /* DEBUG */
! 159:
! 160:
! 161: /*
! 162: * init_util - initialize the utilities (ntpd included)
! 163: */
! 164: void
! 165: init_util(void)
! 166: {
! 167: stats_drift_file = NULL;
! 168: stats_temp_file = NULL;
! 169: key_file_name = NULL;
! 170: filegen_register(statsdir, "peerstats", &peerstats);
! 171: filegen_register(statsdir, "loopstats", &loopstats);
! 172: filegen_register(statsdir, "clockstats", &clockstats);
! 173: filegen_register(statsdir, "rawstats", &rawstats);
! 174: filegen_register(statsdir, "sysstats", &sysstats);
! 175: filegen_register(statsdir, "protostats", &protostats);
! 176: #ifdef OPENSSL
! 177: filegen_register(statsdir, "cryptostats", &cryptostats);
! 178: #endif /* OPENSSL */
! 179: #ifdef DEBUG_TIMING
! 180: filegen_register(statsdir, "timingstats", &timingstats);
! 181: #endif /* DEBUG_TIMING */
! 182: #ifdef DEBUG
! 183: atexit(uninit_util);
! 184: #endif /* DEBUG */
! 185: }
! 186:
! 187:
! 188: /*
! 189: * hourly_stats - print some interesting stats
! 190: */
! 191: void
! 192: write_stats(void)
! 193: {
! 194: FILE *fp;
! 195: double ftemp;
! 196: #ifdef DOSYNCTODR
! 197: struct timeval tv;
! 198: #if !defined(VMS)
! 199: int prio_set;
! 200: #endif
! 201: #ifdef HAVE_GETCLOCK
! 202: struct timespec ts;
! 203: #endif
! 204: int o_prio;
! 205:
! 206: /*
! 207: * Sometimes having a Sun can be a drag.
! 208: *
! 209: * The kernel variable dosynctodr controls whether the system's
! 210: * soft clock is kept in sync with the battery clock. If it
! 211: * is zero, then the soft clock is not synced, and the battery
! 212: * clock is simply left to rot. That means that when the system
! 213: * reboots, the battery clock (which has probably gone wacky)
! 214: * sets the soft clock. That means ntpd starts off with a very
! 215: * confused idea of what time it is. It then takes a large
! 216: * amount of time to figure out just how wacky the battery clock
! 217: * has made things drift, etc, etc. The solution is to make the
! 218: * battery clock sync up to system time. The way to do THAT is
! 219: * to simply set the time of day to the current time of day, but
! 220: * as quickly as possible. This may, or may not be a sensible
! 221: * thing to do.
! 222: *
! 223: * CAVEAT: settimeofday() steps the sun clock by about 800 us,
! 224: * so setting DOSYNCTODR seems a bad idea in the
! 225: * case of us resolution
! 226: */
! 227:
! 228: #if !defined(VMS)
! 229: /*
! 230: * (prr) getpriority returns -1 on error, but -1 is also a valid
! 231: * return value (!), so instead we have to zero errno before the
! 232: * call and check it for non-zero afterwards.
! 233: */
! 234: errno = 0;
! 235: prio_set = 0;
! 236: o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */
! 237:
! 238: /*
! 239: * (prr) if getpriority succeeded, call setpriority to raise
! 240: * scheduling priority as high as possible. If that succeeds
! 241: * as well, set the prio_set flag so we remember to reset
! 242: * priority to its previous value below. Note that on Solaris
! 243: * 2.6 (and beyond?), both getpriority and setpriority will fail
! 244: * with ESRCH, because sched_setscheduler (called from main) put
! 245: * us in the real-time scheduling class which setpriority
! 246: * doesn't know about. Being in the real-time class is better
! 247: * than anything setpriority can do, anyhow, so this error is
! 248: * silently ignored.
! 249: */
! 250: if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0))
! 251: prio_set = 1; /* overdrive */
! 252: #endif /* VMS */
! 253: #ifdef HAVE_GETCLOCK
! 254: (void) getclock(TIMEOFDAY, &ts);
! 255: tv.tv_sec = ts.tv_sec;
! 256: tv.tv_usec = ts.tv_nsec / 1000;
! 257: #else /* not HAVE_GETCLOCK */
! 258: GETTIMEOFDAY(&tv,(struct timezone *)NULL);
! 259: #endif /* not HAVE_GETCLOCK */
! 260: if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0)
! 261: msyslog(LOG_ERR, "can't sync battery time: %m");
! 262: #if !defined(VMS)
! 263: if (prio_set)
! 264: setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
! 265: #endif /* VMS */
! 266: #endif /* DOSYNCTODR */
! 267: record_sys_stats();
! 268: ftemp = fabs(prev_drift_comp - drift_comp);
! 269: prev_drift_comp = drift_comp;
! 270: if (ftemp > clock_phi)
! 271: return;
! 272:
! 273: if (stats_drift_file != 0 && drift_file_sw) {
! 274:
! 275: /*
! 276: * When the frequency file is written, initialize the
! 277: * wander threshold to a configured initial value.
! 278: * Thereafter reduce it by a factor of 0.5. When it
! 279: * drops below the frequency wander, write the frequency
! 280: * file. This adapts to the prevailing wander yet
! 281: * minimizes the file writes.
! 282: */
! 283: drift_file_sw = FALSE;
! 284: wander_resid *= 0.5;
! 285: #ifdef DEBUG
! 286: if (debug)
! 287: printf("write_stats: wander %.6lf thresh %.6lf, freq %.6lf\n",
! 288: clock_stability * 1e6, wander_resid * 1e6,
! 289: drift_comp * 1e6);
! 290: #endif
! 291: if (sys_leap != LEAP_NOTINSYNC && clock_stability >
! 292: wander_resid) {
! 293: wander_resid = wander_threshold;
! 294: if ((fp = fopen(stats_temp_file, "w")) == NULL)
! 295: {
! 296: msyslog(LOG_ERR,
! 297: "frequency file %s: %m",
! 298: stats_temp_file);
! 299: return;
! 300: }
! 301: fprintf(fp, "%.3f\n", drift_comp * 1e6);
! 302: (void)fclose(fp);
! 303: /* atomic */
! 304: #ifdef SYS_WINNT
! 305: if (_unlink(stats_drift_file)) /* rename semantics differ under NT */
! 306: msyslog(LOG_WARNING,
! 307: "Unable to remove prior drift file %s, %m",
! 308: stats_drift_file);
! 309: #endif /* SYS_WINNT */
! 310:
! 311: #ifndef NO_RENAME
! 312: if (rename(stats_temp_file, stats_drift_file))
! 313: msyslog(LOG_WARNING,
! 314: "Unable to rename temp drift file %s to %s, %m",
! 315: stats_temp_file, stats_drift_file);
! 316: #else
! 317: /* we have no rename NFS of ftp in use */
! 318: if ((fp = fopen(stats_drift_file, "w")) ==
! 319: NULL) {
! 320: msyslog(LOG_ERR,
! 321: "frequency file %s: %m",
! 322: stats_drift_file);
! 323: return;
! 324: }
! 325: #endif
! 326:
! 327: #if defined(VMS)
! 328: /* PURGE */
! 329: {
! 330: $DESCRIPTOR(oldvers,";-1");
! 331: struct dsc$descriptor driftdsc = {
! 332: strlen(stats_drift_file), 0, 0,
! 333: stats_drift_file };
! 334: while(lib$delete_file(&oldvers,
! 335: &driftdsc) & 1);
! 336: }
! 337: #endif
! 338: } else {
! 339: /* XXX: Log a message at INFO level */
! 340: }
! 341: }
! 342: }
! 343:
! 344:
! 345: /*
! 346: * stats_config - configure the stats operation
! 347: */
! 348: void
! 349: stats_config(
! 350: int item,
! 351: const char *invalue /* only one type so far */
! 352: )
! 353: {
! 354: FILE *fp;
! 355: const char *value;
! 356: int len;
! 357: char tbuf[80];
! 358: char str1[20], str2[20];
! 359: #ifndef VMS
! 360: const char temp_ext[] = ".TEMP";
! 361: #else
! 362: const char temp_ext[] = "-TEMP";
! 363: #endif
! 364:
! 365: /*
! 366: * Expand environment strings under Windows NT, since the
! 367: * command interpreter doesn't do this, the program must.
! 368: */
! 369: #ifdef SYS_WINNT
! 370: char newvalue[MAX_PATH], parameter[MAX_PATH];
! 371:
! 372: if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) {
! 373: switch(item) {
! 374: case STATS_FREQ_FILE:
! 375: strcpy(parameter,"STATS_FREQ_FILE");
! 376: break;
! 377:
! 378: case STATS_LEAP_FILE:
! 379: strcpy(parameter,"STATS_LEAP_FILE");
! 380: break;
! 381:
! 382: case STATS_STATSDIR:
! 383: strcpy(parameter,"STATS_STATSDIR");
! 384: break;
! 385:
! 386: case STATS_PID_FILE:
! 387: strcpy(parameter,"STATS_PID_FILE");
! 388: break;
! 389:
! 390: default:
! 391: strcpy(parameter,"UNKNOWN");
! 392: break;
! 393: }
! 394: value = invalue;
! 395: msyslog(LOG_ERR,
! 396: "ExpandEnvironmentStrings(%s) failed: %m\n",
! 397: parameter);
! 398: } else {
! 399: value = newvalue;
! 400: }
! 401: #else
! 402: value = invalue;
! 403: #endif /* SYS_WINNT */
! 404:
! 405: switch(item) {
! 406:
! 407: /*
! 408: * Open and read frequency file.
! 409: */
! 410: case STATS_FREQ_FILE:
! 411: if (!value || (len = strlen(value)) == 0)
! 412: break;
! 413:
! 414: stats_drift_file = erealloc(stats_drift_file, len + 1);
! 415: stats_temp_file = erealloc(stats_temp_file,
! 416: len + sizeof(".TEMP"));
! 417:
! 418: memcpy(stats_drift_file, value, (unsigned)(len+1));
! 419: memcpy(stats_temp_file, value, (unsigned)len);
! 420: memcpy(stats_temp_file + len, temp_ext,
! 421: sizeof(temp_ext));
! 422:
! 423: /*
! 424: * Open drift file and read frequency. If the file is
! 425: * missing or contains errors, tell the loop to reset.
! 426: */
! 427: if ((fp = fopen(stats_drift_file, "r")) == NULL)
! 428: break;
! 429:
! 430: if (fscanf(fp, "%lf", &old_drift) != 1) {
! 431: msyslog(LOG_ERR,
! 432: "format error frequency file %s",
! 433: stats_drift_file);
! 434: fclose(fp);
! 435: break;
! 436:
! 437: }
! 438: fclose(fp);
! 439: old_drift /= 1e6;
! 440: prev_drift_comp = old_drift;
! 441: break;
! 442:
! 443: /*
! 444: * Specify statistics directory.
! 445: */
! 446: case STATS_STATSDIR:
! 447:
! 448: /*
! 449: * HMS: the following test is insufficient:
! 450: * - value may be missing the DIR_SEP
! 451: * - we still need the filename after it
! 452: */
! 453: if (strlen(value) >= sizeof(statsdir)) {
! 454: msyslog(LOG_ERR,
! 455: "statsdir too long (>%d, sigh)",
! 456: (int)sizeof(statsdir) - 1);
! 457: } else {
! 458: l_fp now;
! 459: int add_dir_sep;
! 460: int value_l = strlen(value);
! 461:
! 462: /* Add a DIR_SEP unless we already have one. */
! 463: if (value_l == 0)
! 464: add_dir_sep = 0;
! 465: else
! 466: add_dir_sep = (DIR_SEP !=
! 467: value[value_l - 1]);
! 468:
! 469: if (add_dir_sep)
! 470: snprintf(statsdir, sizeof(statsdir),
! 471: "%s%c", value, DIR_SEP);
! 472: else
! 473: snprintf(statsdir, sizeof(statsdir),
! 474: "%s", value);
! 475:
! 476: get_systime(&now);
! 477: if(peerstats.prefix == &statsdir[0] &&
! 478: peerstats.fp != NULL) {
! 479: fclose(peerstats.fp);
! 480: peerstats.fp = NULL;
! 481: filegen_setup(&peerstats, now.l_ui);
! 482: }
! 483: if(loopstats.prefix == &statsdir[0] &&
! 484: loopstats.fp != NULL) {
! 485: fclose(loopstats.fp);
! 486: loopstats.fp = NULL;
! 487: filegen_setup(&loopstats, now.l_ui);
! 488: }
! 489: if(clockstats.prefix == &statsdir[0] &&
! 490: clockstats.fp != NULL) {
! 491: fclose(clockstats.fp);
! 492: clockstats.fp = NULL;
! 493: filegen_setup(&clockstats, now.l_ui);
! 494: }
! 495: if(rawstats.prefix == &statsdir[0] &&
! 496: rawstats.fp != NULL) {
! 497: fclose(rawstats.fp);
! 498: rawstats.fp = NULL;
! 499: filegen_setup(&rawstats, now.l_ui);
! 500: }
! 501: if(sysstats.prefix == &statsdir[0] &&
! 502: sysstats.fp != NULL) {
! 503: fclose(sysstats.fp);
! 504: sysstats.fp = NULL;
! 505: filegen_setup(&sysstats, now.l_ui);
! 506: }
! 507: if(protostats.prefix == &statsdir[0] &&
! 508: protostats.fp != NULL) {
! 509: fclose(protostats.fp);
! 510: protostats.fp = NULL;
! 511: filegen_setup(&protostats, now.l_ui);
! 512: }
! 513: #ifdef OPENSSL
! 514: if(cryptostats.prefix == &statsdir[0] &&
! 515: cryptostats.fp != NULL) {
! 516: fclose(cryptostats.fp);
! 517: cryptostats.fp = NULL;
! 518: filegen_setup(&cryptostats, now.l_ui);
! 519: }
! 520: #endif /* OPENSSL */
! 521: #ifdef DEBUG_TIMING
! 522: if(timingstats.prefix == &statsdir[0] &&
! 523: timingstats.fp != NULL) {
! 524: fclose(timingstats.fp);
! 525: timingstats.fp = NULL;
! 526: filegen_setup(&timingstats, now.l_ui);
! 527: }
! 528: #endif /* DEBUG_TIMING */
! 529: }
! 530: break;
! 531:
! 532: /*
! 533: * Open pid file.
! 534: */
! 535: case STATS_PID_FILE:
! 536: if ((fp = fopen(value, "w")) == NULL) {
! 537: msyslog(LOG_ERR, "pid file %s: %m",
! 538: value);
! 539: break;
! 540: }
! 541: fprintf(fp, "%d", (int)getpid());
! 542: fclose(fp);;
! 543: break;
! 544:
! 545: /*
! 546: * Read leapseconds file.
! 547: */
! 548: case STATS_LEAP_FILE:
! 549: if ((fp = fopen(value, "r")) == NULL) {
! 550: msyslog(LOG_ERR, "leapseconds file %s: %m",
! 551: value);
! 552: break;
! 553: }
! 554:
! 555: if (leap_file(fp) < 0) {
! 556: msyslog(LOG_ERR,
! 557: "format error leapseconds file %s",
! 558: value);
! 559: } else {
! 560: strcpy(str1, fstostr(leap_sec));
! 561: strcpy(str2, fstostr(leap_expire));
! 562: snprintf(tbuf, sizeof(tbuf),
! 563: "%d leap %s expire %s", leap_tai, str1,
! 564: str2);
! 565: report_event(EVNT_TAI, NULL, tbuf);
! 566: }
! 567: fclose(fp);
! 568: break;
! 569:
! 570: default:
! 571: /* oh well */
! 572: break;
! 573: }
! 574: }
! 575:
! 576:
! 577: /*
! 578: * record_peer_stats - write peer statistics to file
! 579: *
! 580: * file format:
! 581: * day (MJD)
! 582: * time (s past UTC midnight)
! 583: * IP address
! 584: * status word (hex)
! 585: * offset
! 586: * delay
! 587: * dispersion
! 588: * jitter
! 589: */
! 590: void
! 591: record_peer_stats(
! 592: sockaddr_u *addr,
! 593: int status,
! 594: double offset, /* offset */
! 595: double delay, /* delay */
! 596: double dispersion, /* dispersion */
! 597: double jitter /* jitter */
! 598: )
! 599: {
! 600: l_fp now;
! 601: u_long day;
! 602:
! 603: if (!stats_control)
! 604: return;
! 605:
! 606: get_systime(&now);
! 607: filegen_setup(&peerstats, now.l_ui);
! 608: day = now.l_ui / 86400 + MJD_1900;
! 609: now.l_ui %= 86400;
! 610: if (peerstats.fp != NULL) {
! 611: fprintf(peerstats.fp,
! 612: "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day,
! 613: ulfptoa(&now, 3), stoa(addr), status, offset,
! 614: delay, dispersion, jitter);
! 615: fflush(peerstats.fp);
! 616: }
! 617: }
! 618:
! 619:
! 620: /*
! 621: * record_loop_stats - write loop filter statistics to file
! 622: *
! 623: * file format:
! 624: * day (MJD)
! 625: * time (s past midnight)
! 626: * offset
! 627: * frequency (PPM)
! 628: * jitter
! 629: * wnder (PPM)
! 630: * time constant (log2)
! 631: */
! 632: void
! 633: record_loop_stats(
! 634: double offset, /* offset */
! 635: double freq, /* frequency (PPM) */
! 636: double jitter, /* jitter */
! 637: double wander, /* wander (PPM) */
! 638: int spoll
! 639: )
! 640: {
! 641: l_fp now;
! 642: u_long day;
! 643:
! 644: if (!stats_control)
! 645: return;
! 646:
! 647: get_systime(&now);
! 648: filegen_setup(&loopstats, now.l_ui);
! 649: day = now.l_ui / 86400 + MJD_1900;
! 650: now.l_ui %= 86400;
! 651: if (loopstats.fp != NULL) {
! 652: fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n",
! 653: day, ulfptoa(&now, 3), offset, freq * 1e6, jitter,
! 654: wander * 1e6, spoll);
! 655: fflush(loopstats.fp);
! 656: }
! 657: }
! 658:
! 659:
! 660: /*
! 661: * record_clock_stats - write clock statistics to file
! 662: *
! 663: * file format:
! 664: * day (MJD)
! 665: * time (s past midnight)
! 666: * IP address
! 667: * text message
! 668: */
! 669: void
! 670: record_clock_stats(
! 671: sockaddr_u *addr,
! 672: const char *text /* timecode string */
! 673: )
! 674: {
! 675: l_fp now;
! 676: u_long day;
! 677:
! 678: if (!stats_control)
! 679: return;
! 680:
! 681: get_systime(&now);
! 682: filegen_setup(&clockstats, now.l_ui);
! 683: day = now.l_ui / 86400 + MJD_1900;
! 684: now.l_ui %= 86400;
! 685: if (clockstats.fp != NULL) {
! 686: fprintf(clockstats.fp, "%lu %s %s %s\n", day,
! 687: ulfptoa(&now, 3), stoa(addr), text);
! 688: fflush(clockstats.fp);
! 689: }
! 690: }
! 691:
! 692:
! 693: /*
! 694: * record_raw_stats - write raw timestamps to file
! 695: *
! 696: * file format
! 697: * day (MJD)
! 698: * time (s past midnight)
! 699: * peer ip address
! 700: * IP address
! 701: * t1 t2 t3 t4 timestamps
! 702: */
! 703: void
! 704: record_raw_stats(
! 705: sockaddr_u *srcadr,
! 706: sockaddr_u *dstadr,
! 707: l_fp *t1, /* originate timestamp */
! 708: l_fp *t2, /* receive timestamp */
! 709: l_fp *t3, /* transmit timestamp */
! 710: l_fp *t4 /* destination timestamp */
! 711: )
! 712: {
! 713: l_fp now;
! 714: u_long day;
! 715:
! 716: if (!stats_control)
! 717: return;
! 718:
! 719: get_systime(&now);
! 720: filegen_setup(&rawstats, now.l_ui);
! 721: day = now.l_ui / 86400 + MJD_1900;
! 722: now.l_ui %= 86400;
! 723: if (rawstats.fp != NULL) {
! 724: fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n", day,
! 725: ulfptoa(&now, 3), stoa(srcadr), dstadr ?
! 726: stoa(dstadr) : "-", ulfptoa(t1, 9), ulfptoa(t2, 9),
! 727: ulfptoa(t3, 9), ulfptoa(t4, 9));
! 728: fflush(rawstats.fp);
! 729: }
! 730: }
! 731:
! 732:
! 733: /*
! 734: * record_sys_stats - write system statistics to file
! 735: *
! 736: * file format
! 737: * day (MJD)
! 738: * time (s past midnight)
! 739: * time since reset
! 740: * packets recieved
! 741: * packets for this host
! 742: * current version
! 743: * old version
! 744: * access denied
! 745: * bad length or format
! 746: * bad authentication
! 747: * declined
! 748: * rate exceeded
! 749: * KoD sent
! 750: */
! 751: void
! 752: record_sys_stats(void)
! 753: {
! 754: l_fp now;
! 755: u_long day;
! 756:
! 757: if (!stats_control)
! 758: return;
! 759:
! 760: get_systime(&now);
! 761: filegen_setup(&sysstats, now.l_ui);
! 762: day = now.l_ui / 86400 + MJD_1900;
! 763: now.l_ui %= 86400;
! 764: if (sysstats.fp != NULL) {
! 765: fprintf(sysstats.fp,
! 766: "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
! 767: day, ulfptoa(&now, 3), current_time - sys_stattime,
! 768: sys_received, sys_processed, sys_newversion,
! 769: sys_oldversion, sys_restricted, sys_badlength,
! 770: sys_badauth, sys_declined, sys_limitrejected,
! 771: sys_kodsent);
! 772: fflush(sysstats.fp);
! 773: proto_clr_stats();
! 774: }
! 775: }
! 776:
! 777:
! 778: /*
! 779: * record_proto_stats - write system statistics to file
! 780: *
! 781: * file format
! 782: * day (MJD)
! 783: * time (s past midnight)
! 784: * text message
! 785: */
! 786: void
! 787: record_proto_stats(
! 788: char *str /* text string */
! 789: )
! 790: {
! 791: l_fp now;
! 792: u_long day;
! 793:
! 794: if (!stats_control)
! 795: return;
! 796:
! 797: get_systime(&now);
! 798: filegen_setup(&protostats, now.l_ui);
! 799: day = now.l_ui / 86400 + MJD_1900;
! 800: now.l_ui %= 86400;
! 801: if (protostats.fp != NULL) {
! 802: fprintf(protostats.fp, "%lu %s %s\n", day,
! 803: ulfptoa(&now, 3), str);
! 804: fflush(protostats.fp);
! 805: }
! 806: }
! 807:
! 808:
! 809: #ifdef OPENSSL
! 810: /*
! 811: * record_crypto_stats - write crypto statistics to file
! 812: *
! 813: * file format:
! 814: * day (mjd)
! 815: * time (s past midnight)
! 816: * peer ip address
! 817: * text message
! 818: */
! 819: void
! 820: record_crypto_stats(
! 821: sockaddr_u *addr,
! 822: const char *text /* text message */
! 823: )
! 824: {
! 825: l_fp now;
! 826: u_long day;
! 827:
! 828: if (!stats_control)
! 829: return;
! 830:
! 831: get_systime(&now);
! 832: filegen_setup(&cryptostats, now.l_ui);
! 833: day = now.l_ui / 86400 + MJD_1900;
! 834: now.l_ui %= 86400;
! 835: if (cryptostats.fp != NULL) {
! 836: if (addr == NULL)
! 837: fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n",
! 838: day, ulfptoa(&now, 3), text);
! 839: else
! 840: fprintf(cryptostats.fp, "%lu %s %s %s\n",
! 841: day, ulfptoa(&now, 3), stoa(addr), text);
! 842: fflush(cryptostats.fp);
! 843: }
! 844: }
! 845: #endif /* OPENSSL */
! 846:
! 847:
! 848: #ifdef DEBUG_TIMING
! 849: /*
! 850: * record_timing_stats - write timing statistics to file
! 851: *
! 852: * file format:
! 853: * day (mjd)
! 854: * time (s past midnight)
! 855: * text message
! 856: */
! 857: void
! 858: record_timing_stats(
! 859: const char *text /* text message */
! 860: )
! 861: {
! 862: static unsigned int flshcnt;
! 863: l_fp now;
! 864: u_long day;
! 865:
! 866: if (!stats_control)
! 867: return;
! 868:
! 869: get_systime(&now);
! 870: filegen_setup(&timingstats, now.l_ui);
! 871: day = now.l_ui / 86400 + MJD_1900;
! 872: now.l_ui %= 86400;
! 873: if (timingstats.fp != NULL) {
! 874: fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now,
! 875: 3), text);
! 876: if (++flshcnt % 100 == 0)
! 877: fflush(timingstats.fp);
! 878: }
! 879: }
! 880: #endif
! 881:
! 882:
! 883: /*
! 884: * leap_file - read leapseconds file
! 885: *
! 886: * Read the ERTS leapsecond file in NIST text format and extract the
! 887: * NTP seconds of the latest leap and TAI offset after the leap.
! 888: */
! 889: static int
! 890: leap_file(
! 891: FILE *fp /* file handle */
! 892: )
! 893: {
! 894: char buf[NTP_MAXSTRLEN]; /* file line buffer */
! 895: u_long leap; /* NTP time at leap */
! 896: u_long expire; /* NTP time when file expires */
! 897: int offset; /* TAI offset at leap (s) */
! 898: int i;
! 899:
! 900: /*
! 901: * Read and parse the leapseconds file. Empty lines and comments
! 902: * are ignored. A line beginning with #@ contains the file
! 903: * expiration time in NTP seconds. Other lines begin with two
! 904: * integers followed by junk or comments. The first integer is
! 905: * the NTP seconds at the leap, the second is the TAI offset
! 906: * after the leap.
! 907: */
! 908: offset = 0;
! 909: leap = 0;
! 910: expire = 0;
! 911: i = 10;
! 912: while (fgets(buf, NTP_MAXSTRLEN - 1, fp) != NULL) {
! 913: if (strlen(buf) < 1)
! 914: continue;
! 915:
! 916: if (buf[0] == '#') {
! 917: if (strlen(buf) < 3)
! 918: continue;
! 919:
! 920: /*
! 921: * Note the '@' flag was used only in the 2006
! 922: * table; previious to that the flag was '$'.
! 923: */
! 924: if (buf[1] == '@' || buf[1] == '$') {
! 925: if (sscanf(&buf[2], "%lu", &expire) !=
! 926: 1)
! 927: return (-1);
! 928:
! 929: continue;
! 930: }
! 931: }
! 932: if (sscanf(buf, "%lu %d", &leap, &offset) == 2) {
! 933:
! 934: /*
! 935: * Valid offsets must increase by one for each
! 936: * leap.
! 937: */
! 938: if (i++ != offset)
! 939: return (-1);
! 940: }
! 941: }
! 942:
! 943: /*
! 944: * There must be at least one leap.
! 945: */
! 946: if (i == 10)
! 947: return (-1);
! 948:
! 949: leap_tai = offset;
! 950: leap_sec = leap;
! 951: leap_expire = expire;
! 952: return (0);
! 953: }
! 954:
! 955:
! 956: /*
! 957: * leap_month - returns seconds until the end of the month.
! 958: */
! 959: u_long
! 960: leap_month(
! 961: u_long sec /* current NTP second */
! 962: )
! 963: {
! 964: u_long ltemp;
! 965: u_long *ptr;
! 966: u_long year[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,
! 967: 31};
! 968: u_long lyear[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30,
! 969: 31};
! 970:
! 971: /*
! 972: * Find current leap cycle.
! 973: */
! 974: ltemp = sec;
! 975: while (ltemp >= L_CENT)
! 976: ltemp -= L_CENT;
! 977: while (ltemp >= L_4YEAR)
! 978: ltemp -= L_4YEAR;
! 979:
! 980: /*
! 981: * We are within four years of the target. If in leap year, use
! 982: * leap year month table; otherwise, use year month table.
! 983: */
! 984: if (ltemp < L_LYEAR) {
! 985: ptr = lyear;
! 986: } else {
! 987: ptr = year;
! 988: ltemp -= L_LYEAR;
! 989: while (ltemp >= L_YEAR)
! 990: ltemp -= L_YEAR;
! 991: }
! 992:
! 993: /*
! 994: * We are within one year of the target. Find the month of the
! 995: * leap.
! 996: */
! 997: while (ltemp >= *ptr * L_DAY)
! 998: ltemp -= *ptr++ * L_DAY;
! 999:
! 1000: /*
! 1001: * The result is the number of seconds until the end of the
! 1002: * month when the leap is to occur.
! 1003: */
! 1004: return (*ptr * L_DAY - ltemp - L_DAY);
! 1005: }
! 1006:
! 1007:
! 1008: /*
! 1009: * getauthkeys - read the authentication keys from the specified file
! 1010: */
! 1011: void
! 1012: getauthkeys(
! 1013: const char *keyfile
! 1014: )
! 1015: {
! 1016: int len;
! 1017:
! 1018: len = strlen(keyfile);
! 1019: if (!len)
! 1020: return;
! 1021:
! 1022: #ifndef SYS_WINNT
! 1023: key_file_name = erealloc(key_file_name, len + 1);
! 1024: memmove(key_file_name, keyfile, len + 1);
! 1025: #else
! 1026: key_file_name = erealloc(key_file_name, _MAX_PATH);
! 1027: if (len + 1 > _MAX_PATH)
! 1028: return;
! 1029: if (!ExpandEnvironmentStrings(keyfile, key_file_name,
! 1030: _MAX_PATH)) {
! 1031: msyslog(LOG_ERR,
! 1032: "ExpandEnvironmentStrings(KEY_FILE) failed: %m");
! 1033: strncpy(key_file_name, keyfile, _MAX_PATH);
! 1034: }
! 1035: #endif /* SYS_WINNT */
! 1036:
! 1037: authreadkeys(key_file_name);
! 1038: }
! 1039:
! 1040:
! 1041: /*
! 1042: * rereadkeys - read the authentication key file over again.
! 1043: */
! 1044: void
! 1045: rereadkeys(void)
! 1046: {
! 1047: if (NULL != key_file_name)
! 1048: authreadkeys(key_file_name);
! 1049: }
! 1050:
! 1051:
! 1052: /*
! 1053: * sock_hash - hash a sockaddr_u structure
! 1054: */
! 1055: u_short
! 1056: sock_hash(
! 1057: sockaddr_u *addr
! 1058: )
! 1059: {
! 1060: u_int hashVal;
! 1061: u_int j;
! 1062: size_t len;
! 1063: u_char *pch;
! 1064: hashVal = 0;
! 1065: len = 0;
! 1066:
! 1067: /*
! 1068: * We can't just hash the whole thing because there are hidden
! 1069: * fields in sockaddr_in6 that might be filled in by recvfrom(),
! 1070: * so just use the family, port and address.
! 1071: */
! 1072: pch = (u_char *)&AF(addr);
! 1073: hashVal = 37 * hashVal + *pch;
! 1074: if (sizeof(AF(addr)) > 1) {
! 1075: pch++;
! 1076: hashVal = 37 * hashVal + *pch;
! 1077: }
! 1078: switch(AF(addr)) {
! 1079: case AF_INET:
! 1080: pch = (u_char *)&SOCK_ADDR4(addr);
! 1081: len = sizeof(SOCK_ADDR4(addr));
! 1082: break;
! 1083:
! 1084: case AF_INET6:
! 1085: pch = (u_char *)&SOCK_ADDR6(addr);
! 1086: len = sizeof(SOCK_ADDR6(addr));
! 1087: break;
! 1088: }
! 1089:
! 1090: for (j = 0; j < len ; j++)
! 1091: hashVal = 37 * hashVal + pch[j];
! 1092:
! 1093: hashVal = hashVal & NTP_HASH_MASK;
! 1094:
! 1095: return (u_short)hashVal;
! 1096: }
! 1097:
! 1098:
! 1099: #if notyet
! 1100: /*
! 1101: * ntp_exit - document explicitly that ntpd has exited
! 1102: */
! 1103: void
! 1104: ntp_exit(int retval)
! 1105: {
! 1106: msyslog(LOG_ERR, "EXITING with return code %d", retval);
! 1107: exit(retval);
! 1108: }
! 1109: #endif
! 1110:
! 1111: /*
! 1112: * fstostr - prettyprint NTP seconds
! 1113: */
! 1114: char * fstostr(
! 1115: time_t ntp_stamp
! 1116: )
! 1117: {
! 1118: static char str[20];
! 1119: struct tm * tm;
! 1120: time_t unix_stamp;
! 1121:
! 1122: unix_stamp = ntp_stamp - JAN_1970;
! 1123: tm = gmtime(&unix_stamp);
! 1124: if (NULL != tm)
! 1125: snprintf(str, sizeof(str),
! 1126: "%04d%02d%02d%02d%02d",
! 1127: tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
! 1128: tm->tm_hour, tm->tm_min);
! 1129: else
! 1130: strcpy(str, "gmtime() error");
! 1131:
! 1132: return str;
! 1133: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>