diff options
Diffstat (limited to 'contrib/ntp/ntpd/ntp_util.c')
-rw-r--r-- | contrib/ntp/ntpd/ntp_util.c | 1118 |
1 files changed, 1118 insertions, 0 deletions
diff --git a/contrib/ntp/ntpd/ntp_util.c b/contrib/ntp/ntpd/ntp_util.c new file mode 100644 index 000000000000..e7b374fc346f --- /dev/null +++ b/contrib/ntp/ntpd/ntp_util.c @@ -0,0 +1,1118 @@ +/* + * ntp_util.c - stuff I didn't have any other place for + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ntpd.h" +#include "ntp_unixtime.h" +#include "ntp_filegen.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" +#include "ntp_assert.h" +#include "ntp_calendar.h" +#include "ntp_leapsec.h" + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <sys/stat.h> + +#ifdef HAVE_IEEEFP_H +# include <ieeefp.h> +#endif +#ifdef HAVE_MATH_H +# include <math.h> +#endif + +#if defined(VMS) +# include <descrip.h> +#endif /* VMS */ + +/* + * Defines used by the leapseconds stuff + */ +#define MAX_TAI 100 /* max TAI offset (s) */ +#define L_DAY 86400UL /* seconds per day */ +#define L_YEAR (L_DAY * 365) /* days per year */ +#define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */ +#define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */ +#define L_CENT (L_4YEAR * 25) /* days per century */ + +/* + * This contains odds and ends, including the hourly stats, various + * configuration items, leapseconds stuff, etc. + */ +/* + * File names + */ +static char *key_file_name; /* keys file name */ +static char *leapfile_name; /* leapseconds file name */ +static struct stat leapfile_stat; /* leapseconds file stat() buffer */ +static int /*BOOL*/have_leapfile = FALSE; +static int /*BOOL*/chck_leaphash = TRUE; +char *stats_drift_file; /* frequency file name */ +static char *stats_temp_file; /* temp frequency file name */ +static double wander_resid; /* last frequency update */ +double wander_threshold = 1e-7; /* initial frequency threshold */ + +/* + * Statistics file stuff + */ +#ifndef NTP_VAR +# ifndef SYS_WINNT +# define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ +# else +# define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ +# endif /* SYS_WINNT */ +#endif + + +char statsdir[MAXFILENAME] = NTP_VAR; +static FILEGEN peerstats; +static FILEGEN loopstats; +static FILEGEN clockstats; +static FILEGEN rawstats; +static FILEGEN sysstats; +static FILEGEN protostats; +static FILEGEN cryptostats; +static FILEGEN timingstats; + +/* + * This controls whether stats are written to the fileset. Provided + * so that ntpdc can turn off stats when the file system fills up. + */ +int stats_control; + +/* + * Last frequency written to file. + */ +static double prev_drift_comp; /* last frequency update */ + +/* + * Function prototypes + */ +static void record_sys_stats(void); + void ntpd_time_stepped(void); +static void check_leap_expiration(int, uint32_t, const time_t*); + +/* + * Prototypes + */ +#ifdef DEBUG +void uninit_util(void); +#endif + +/* + * uninit_util - free memory allocated by init_util + */ +#ifdef DEBUG +void +uninit_util(void) +{ +#if defined(_MSC_VER) && defined (_DEBUG) + _CrtCheckMemory(); +#endif + if (stats_drift_file) { + free(stats_drift_file); + free(stats_temp_file); + stats_drift_file = NULL; + stats_temp_file = NULL; + } + if (key_file_name) { + free(key_file_name); + key_file_name = NULL; + } + filegen_unregister("peerstats"); + filegen_unregister("loopstats"); + filegen_unregister("clockstats"); + filegen_unregister("rawstats"); + filegen_unregister("sysstats"); + filegen_unregister("protostats"); +#ifdef AUTOKEY + filegen_unregister("cryptostats"); +#endif /* AUTOKEY */ +#ifdef DEBUG_TIMING + filegen_unregister("timingstats"); +#endif /* DEBUG_TIMING */ + +#if defined(_MSC_VER) && defined (_DEBUG) + _CrtCheckMemory(); +#endif +} +#endif /* DEBUG */ + + +/* + * init_util - initialize the util module of ntpd + */ +void +init_util(void) +{ + filegen_register(statsdir, "peerstats", &peerstats); + filegen_register(statsdir, "loopstats", &loopstats); + filegen_register(statsdir, "clockstats", &clockstats); + filegen_register(statsdir, "rawstats", &rawstats); + filegen_register(statsdir, "sysstats", &sysstats); + filegen_register(statsdir, "protostats", &protostats); + filegen_register(statsdir, "cryptostats", &cryptostats); + filegen_register(statsdir, "timingstats", &timingstats); + /* + * register with libntp ntp_set_tod() to call us back + * when time is stepped. + */ + step_callback = &ntpd_time_stepped; +#ifdef DEBUG + atexit(&uninit_util); +#endif /* DEBUG */ +} + + +/* + * hourly_stats - print some interesting stats + */ +void +write_stats(void) +{ + FILE *fp = NULL; +#ifdef DOSYNCTODR + struct timeval tv; +#if !defined(VMS) + int prio_set; +#endif +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif + int o_prio; + + /* + * Sometimes having a Sun can be a drag. + * + * The kernel variable dosynctodr controls whether the system's + * soft clock is kept in sync with the battery clock. If it + * is zero, then the soft clock is not synced, and the battery + * clock is simply left to rot. That means that when the system + * reboots, the battery clock (which has probably gone wacky) + * sets the soft clock. That means ntpd starts off with a very + * confused idea of what time it is. It then takes a large + * amount of time to figure out just how wacky the battery clock + * has made things drift, etc, etc. The solution is to make the + * battery clock sync up to system time. The way to do THAT is + * to simply set the time of day to the current time of day, but + * as quickly as possible. This may, or may not be a sensible + * thing to do. + * + * CAVEAT: settimeofday() steps the sun clock by about 800 us, + * so setting DOSYNCTODR seems a bad idea in the + * case of us resolution + */ + +#if !defined(VMS) + /* + * (prr) getpriority returns -1 on error, but -1 is also a valid + * return value (!), so instead we have to zero errno before the + * call and check it for non-zero afterwards. + */ + errno = 0; + prio_set = 0; + o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ + + /* + * (prr) if getpriority succeeded, call setpriority to raise + * scheduling priority as high as possible. If that succeeds + * as well, set the prio_set flag so we remember to reset + * priority to its previous value below. Note that on Solaris + * 2.6 (and beyond?), both getpriority and setpriority will fail + * with ESRCH, because sched_setscheduler (called from main) put + * us in the real-time scheduling class which setpriority + * doesn't know about. Being in the real-time class is better + * than anything setpriority can do, anyhow, so this error is + * silently ignored. + */ + if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) + prio_set = 1; /* overdrive */ +#endif /* VMS */ +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tv,(struct timezone *)NULL); +#endif /* not HAVE_GETCLOCK */ + if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) + msyslog(LOG_ERR, "can't sync battery time: %m"); +#if !defined(VMS) + if (prio_set) + setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ +#endif /* VMS */ +#endif /* DOSYNCTODR */ + record_sys_stats(); + if (stats_drift_file != 0) { + + /* + * When the frequency file is written, initialize the + * prev_drift_comp and wander_resid. Thereafter, + * reduce the wander_resid by half each hour. When + * the difference between the prev_drift_comp and + * drift_comp is less than the wander_resid, update + * the frequncy file. This minimizes the file writes to + * nonvolaile storage. + */ + DPRINTF(1, ("write_stats: frequency %.6f thresh %.6f, freq %.6f\n", + (prev_drift_comp - drift_comp) * 1e6, wander_resid * + 1e6, drift_comp * 1e6)); + + if (fabs(prev_drift_comp - drift_comp) < wander_resid) { + wander_resid *= 0.5; + return; + } + prev_drift_comp = drift_comp; + wander_resid = wander_threshold; + if ((fp = fopen(stats_temp_file, "w")) == NULL) { + msyslog(LOG_ERR, "frequency file %s: %m", + stats_temp_file); + return; + } + fprintf(fp, "%.6f\n", drift_comp * 1e6); + (void)fclose(fp); + /* atomic */ +#ifdef SYS_WINNT + if (_unlink(stats_drift_file)) /* rename semantics differ under NT */ + msyslog(LOG_WARNING, + "Unable to remove prior drift file %s, %m", + stats_drift_file); +#endif /* SYS_WINNT */ + +#ifndef NO_RENAME + if (rename(stats_temp_file, stats_drift_file)) + msyslog(LOG_WARNING, + "Unable to rename temp drift file %s to %s, %m", + stats_temp_file, stats_drift_file); +#else + /* we have no rename NFS of ftp in use */ + if ((fp = fopen(stats_drift_file, "w")) == + NULL) { + msyslog(LOG_ERR, + "frequency file %s: %m", + stats_drift_file); + return; + } +#endif + +#if defined(VMS) + /* PURGE */ + { + $DESCRIPTOR(oldvers,";-1"); + struct dsc$descriptor driftdsc = { + strlen(stats_drift_file), 0, 0, + stats_drift_file }; + while(lib$delete_file(&oldvers, + &driftdsc) & 1); + } +#endif + } +} + + +/* + * If an option was given on the command line make sure it takes + * precedence over the configuration file, as command-line options + * are processed first. Similarly, if an option is given in the + * configuration file, do not allow it to be overridden with runtime + * configuration. Done by simply remembering an option was already + * seen. + */ +static int +allow_config( + u_int option, + int/*BOOL*/ cmdopt + ) +{ + static u_int seen = 0; /* stat options previously set */ + u_int mask; + int retv; + + if (cmdopt) { + DEBUG_REQUIRE(option < sizeof(mask) * 8); + mask = 1u << option; + retv = !(seen & mask); + seen |= mask; + } else { + retv = FALSE; + } + return retv; +} + + +/* + * stats_config - configure the stats operation + */ +void +stats_config( + int item, + const char *invalue, /* only one type so far */ + int optflag + ) +{ + FILE *fp = NULL; + const char *value; + size_t len; + double old_drift; + l_fp now; + time_t ttnow; + char dirsep_or_nul; +#ifndef VMS + static const char temp_ext[] = ".TEMP"; +#else + static const char temp_ext[] = "-TEMP"; +#endif + + /* + * Expand environment strings under Windows NT, since the + * command interpreter doesn't do this, the program must. + */ +#ifdef SYS_WINNT + char newvalue[MAX_PATH], parameter[MAX_PATH]; + + if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { + switch (item) { + case STATS_FREQ_FILE: + strlcpy(parameter, "STATS_FREQ_FILE", + sizeof(parameter)); + break; + + case STATS_LEAP_FILE: + strlcpy(parameter, "STATS_LEAP_FILE", + sizeof(parameter)); + break; + + case STATS_STATSDIR: + strlcpy(parameter, "STATS_STATSDIR", + sizeof(parameter)); + break; + + case STATS_PID_FILE: + strlcpy(parameter, "STATS_PID_FILE", + sizeof(parameter)); + break; + + default: + strlcpy(parameter, "UNKNOWN", + sizeof(parameter)); + break; + } + value = invalue; + msyslog(LOG_ERR, + "ExpandEnvironmentStrings(%s) failed: %m\n", + parameter); + } else { + value = newvalue; + } +#else + value = invalue; +#endif /* SYS_WINNT */ + + switch (item) { + + /* + * Open and read frequency file. + */ + case STATS_FREQ_FILE: + if (!allow_config(STATS_FREQ_FILE, optflag)) { + break; + } + if (!value || 0 == (len = strlen(value))) { + free(stats_drift_file); + free(stats_temp_file); + stats_drift_file = stats_temp_file = NULL; + } else { + stats_drift_file = erealloc(stats_drift_file, + 1 + len); + stats_temp_file = erealloc(stats_temp_file, + len + sizeof(temp_ext)); + memcpy(stats_drift_file, value, 1 + len); + memcpy(stats_temp_file, value, len); + memcpy(stats_temp_file + len, temp_ext, + sizeof(temp_ext)); + } + + /* + * Open drift file and read frequency. If the file is + * missing or contains errors, tell the loop to reset. + */ + if (NULL == stats_drift_file) { + goto nofreq; + } else if ((fp = fopen(stats_drift_file, "r")) == NULL) { + if (errno != ENOENT) { + msyslog(LOG_WARNING, + "cannot read frequency file %s: %m", + stats_drift_file); + } + goto nofreq; + } else if (fscanf(fp, "%lf", &old_drift) != 1) { + msyslog(LOG_ERR, + "format error frequency file %s", + stats_drift_file); + nofreq: + prev_drift_comp = 0.0; + loop_config(LOOP_NOFREQ, prev_drift_comp); + } else { + loop_config(LOOP_FREQ, old_drift); + prev_drift_comp = drift_comp; + msyslog(LOG_INFO, + "initial drift restored to %.6f", + old_drift); + } + if (NULL != fp) { + fclose(fp); + } + break; + + /* + * Specify statistics directory. + */ + case STATS_STATSDIR: + if (!allow_config(STATS_STATSDIR, optflag)) { + break; + } + /* - 2 since value may be missing the DIR_SEP. */ + len = strlen(value); + if (len > sizeof(statsdir) - 2) { + msyslog(LOG_ERR, + "statsdir %s too long (>%u)", value, + (u_int)sizeof(statsdir) - 2); + break; + } + /* Add a DIR_SEP unless we already have one. */ + if (0 == len || DIR_SEP == value[len - 1]) { + dirsep_or_nul = '\0'; + } else { + dirsep_or_nul = DIR_SEP; + } + snprintf(statsdir, sizeof(statsdir), "%s%c", + value, dirsep_or_nul); + filegen_statsdir(); + break; + + /* + * Write pid file. + */ + case STATS_PID_FILE: + if (!allow_config(STATS_PID_FILE, optflag)) { + break; + } + if ((fp = fopen(value, "w")) == NULL) { + msyslog(LOG_ERR, "pid file %s: %m", value); + break; + } + fprintf(fp, "%ld", (long)getpid()); + fclose(fp); + break; + + /* + * Read leapseconds file. + * + * By default a leap file without SHA1 signature is accepted, + * but if there is a signature line, the signature must be + * valid or the leapfile line in ntp.conf must have ignorehash. + */ + case STATS_LEAP_FILE: + if (NULL == value || 0 == (len = strlen(value))) { + break; + } + leapfile_name = erealloc(leapfile_name, len + 1); + memcpy(leapfile_name, value, len + 1); + chck_leaphash = optflag; + + if (leapsec_load_file( + leapfile_name, &leapfile_stat, + TRUE, TRUE, chck_leaphash)) { + leap_signature_t lsig; + + get_systime(&now); + time(&ttnow); + leapsec_getsig(&lsig); + mprintf_event(EVNT_TAI, NULL, + "%d leap %s expire%s %s", + lsig.taiof, + fstostr(lsig.ttime), + leapsec_expired(now.l_ui, NULL) + ? "d" + : "s", + fstostr(lsig.etime)); + + have_leapfile = TRUE; + + /* force an immediate daily expiration check of + * the leap seconds table + */ + check_leap_expiration(TRUE, now.l_ui, &ttnow); + } + break; + + default: + /* oh well */ + break; + } +} + + +/* + * record_peer_stats - write peer statistics to file + * + * file format: + * day (MJD) + * time (s past UTC midnight) + * IP address + * status word (hex) + * offset + * delay + * dispersion + * jitter +*/ +void +record_peer_stats( + sockaddr_u * addr, + int status, + double offset, + double delay, + double dispersion, + double jitter + ) +{ + l_fp now; + u_long day; + + if (!stats_control) { + return; + } + get_systime(&now); + filegen_setup(&peerstats, now.l_ui); + if (NULL == peerstats.fp) { + return; + } + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; + fprintf(peerstats.fp, + "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, + ulfptoa(&now, 3), stoa(addr), status, offset, + delay, dispersion, jitter); + fflush(peerstats.fp); +} + + +/* + * record_loop_stats - write loop filter statistics to file + * + * file format: + * day (MJD) + * time (s past midnight) + * offset + * frequency (PPM) + * jitter + * wnder (PPM) + * time constant (log2) + */ +void +record_loop_stats( + double offset, /* offset */ + double freq, /* frequency (PPM) */ + double jitter, /* jitter */ + double wander, /* wander (PPM) */ + int spoll + ) +{ + l_fp now; + u_long day; + + if (!stats_control) + return; + + get_systime(&now); + filegen_setup(&loopstats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; + if (loopstats.fp != NULL) { + fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", + day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, + wander * 1e6, spoll); + fflush(loopstats.fp); + } +} + + +/* + * record_clock_stats - write clock statistics to file + * + * file format: + * day (MJD) + * time (s past midnight) + * IP address + * text message + */ +void +record_clock_stats( + sockaddr_u *addr, + const char *text /* timecode string */ + ) +{ + l_fp now; + u_long day; + + if (!stats_control) + return; + + get_systime(&now); + filegen_setup(&clockstats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; + if (clockstats.fp != NULL) { + fprintf(clockstats.fp, "%lu %s %s %s\n", day, + ulfptoa(&now, 3), stoa(addr), text); + fflush(clockstats.fp); + } +} + + +/* + * mprintf_clock_stats - write clock statistics to file with + * msnprintf-style formatting. + */ +int +mprintf_clock_stats( + sockaddr_u *addr, + const char *fmt, + ... + ) +{ + va_list ap; + int rc; + char msg[512]; + + va_start(ap, fmt); + rc = mvsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + if (stats_control) + record_clock_stats(addr, msg); + + return rc; +} + +/* + * record_raw_stats - write raw timestamps to file + * + * file format + * day (MJD) + * time (s past midnight) + * peer ip address + * IP address + * t1 t2 t3 t4 timestamps + * leap, version, mode, stratum, ppoll, precision, root delay, root dispersion, REFID + * length and hex dump of any EFs and any legacy MAC. + */ +void +record_raw_stats( + sockaddr_u *srcadr, + sockaddr_u *dstadr, + l_fp *t1, /* originate timestamp */ + l_fp *t2, /* receive timestamp */ + l_fp *t3, /* transmit timestamp */ + l_fp *t4, /* destination timestamp */ + int leap, + int version, + int mode, + int stratum, + int ppoll, + int precision, + double root_delay, /* seconds */ + double root_dispersion,/* seconds */ + u_int32 refid, + int len, + u_char *extra + ) +{ + l_fp now; + u_long day; + + if (!stats_control) + return; + + /* + * Mode 6 and mode 7 packets do not have the format of normal + * NTP packets and will log garbage. So don't. [Bug 3774] + */ + if (MODE_CONTROL == mode || MODE_PRIVATE == mode) + return; + + get_systime(&now); + filegen_setup(&rawstats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; + if (rawstats.fp != NULL) { + fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s", + day, ulfptoa(&now, 3), + srcadr ? stoa(srcadr) : "-", + dstadr ? stoa(dstadr) : "-", + ulfptoa(t1, 9), ulfptoa(t2, 9), + ulfptoa(t3, 9), ulfptoa(t4, 9), + leap, version, mode, stratum, ppoll, precision, + root_delay, root_dispersion, refid_str(refid, stratum)); + if (len > 0) { + int i; + + fprintf(rawstats.fp, " %d: ", len); + for (i = 0; i < len; ++i) { + fprintf(rawstats.fp, "%02x", extra[i]); + } + } + fprintf(rawstats.fp, "\n"); + fflush(rawstats.fp); + } +} + + +/* + * record_sys_stats - write system statistics to file + * + * file format + * day (MJD) + * time (s past midnight) + * time since reset + * packets recieved + * packets for this host + * current version + * old version + * access denied + * bad length or format + * bad authentication + * declined + * rate exceeded + * KoD sent + */ +void +record_sys_stats(void) +{ + l_fp now; + u_long day; + + if (!stats_control) + return; + + get_systime(&now); + filegen_setup(&sysstats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; + if (sysstats.fp != NULL) { + fprintf(sysstats.fp, + "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", + day, ulfptoa(&now, 3), current_time - sys_stattime, + sys_received, sys_processed, sys_newversion, + sys_oldversion, sys_restricted, sys_badlength, + sys_badauth, sys_declined, sys_limitrejected, + sys_kodsent); + fflush(sysstats.fp); + proto_clr_stats(); + } +} + + +/* + * record_proto_stats - write system statistics to file + * + * file format + * day (MJD) + * time (s past midnight) + * text message + */ +void +record_proto_stats( + char *str /* text string */ + ) +{ + l_fp now; + u_long day; + + if (!stats_control) + return; + + get_systime(&now); + filegen_setup(&protostats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; + if (protostats.fp != NULL) { + fprintf(protostats.fp, "%lu %s %s\n", day, + ulfptoa(&now, 3), str); + fflush(protostats.fp); + } +} + + +#ifdef AUTOKEY +/* + * record_crypto_stats - write crypto statistics to file + * + * file format: + * day (mjd) + * time (s past midnight) + * peer ip address + * text message + */ +void +record_crypto_stats( + sockaddr_u *addr, + const char *text /* text message */ + ) +{ + l_fp now; + u_long day; + + if (!stats_control) + return; + + get_systime(&now); + filegen_setup(&cryptostats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; + if (cryptostats.fp != NULL) { + if (addr == NULL) + fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", + day, ulfptoa(&now, 3), text); + else + fprintf(cryptostats.fp, "%lu %s %s %s\n", + day, ulfptoa(&now, 3), stoa(addr), text); + fflush(cryptostats.fp); + } +} +#endif /* AUTOKEY */ + + +#ifdef DEBUG_TIMING +/* + * record_timing_stats - write timing statistics to file + * + * file format: + * day (mjd) + * time (s past midnight) + * text message + */ +void +record_timing_stats( + const char *text /* text message */ + ) +{ + static unsigned int flshcnt; + l_fp now; + u_long day; + + if (!stats_control) + return; + + get_systime(&now); + filegen_setup(&timingstats, now.l_ui); + day = now.l_ui / 86400 + MJD_1900; + now.l_ui %= 86400; + if (timingstats.fp != NULL) { + fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, + 3), text); + if (++flshcnt % 100 == 0) + fflush(timingstats.fp); + } +} +#endif + + +/* + * check_leap_file - See if the leapseconds file has been updated. + * + * Returns: n/a + * + * Note: This loads a new leapfile on the fly. Currently a leap file + * without SHA1 signature is accepted, but if there is a signature line, + * the signature must be valid unless the ntp.conf leapfile line specified + * ignorehash. + */ +void +check_leap_file( + int is_daily_check, + uint32_t ntptime, + const time_t * systime + ) +{ + /* just do nothing if there is no leap file */ + if ( ! (leapfile_name && *leapfile_name)) + return; + + /* try to load leapfile, force it if no leapfile loaded yet */ + if (leapsec_load_file( + leapfile_name, &leapfile_stat, + !have_leapfile, is_daily_check, chck_leaphash)) + have_leapfile = TRUE; + else if (!have_leapfile) + return; + + check_leap_expiration(is_daily_check, ntptime, systime); +} + +/* + * check expiration of a loaded leap table + */ +static void +check_leap_expiration( + int is_daily_check, + uint32_t ntptime , + const time_t *systime + ) +{ + static const char * const logPrefix = "leapsecond file"; + int rc; + + /* test the expiration of the leap data and log with proper + * level and frequency (once/hour or once/day, depending on the + * state. + */ + rc = leapsec_daystolive(ntptime, systime); + if (rc == 0) { + msyslog(LOG_WARNING, + "%s ('%s'): will expire in less than one day", + logPrefix, leapfile_name); + } else if (is_daily_check && rc < 28) { + if (rc < 0) + msyslog(LOG_ERR, + "%s ('%s'): expired %d day%s ago", + logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s")); + else + msyslog(LOG_WARNING, + "%s ('%s'): will expire in less than %d days", + logPrefix, leapfile_name, 1+rc); + } +} + + +/* + * getauthkeys - read the authentication keys from the specified file + */ +void +getauthkeys( + const char *keyfile + ) +{ + size_t len; + + len = strlen(keyfile); + if (!len) + return; + +#ifndef SYS_WINNT + key_file_name = erealloc(key_file_name, len + 1); + memcpy(key_file_name, keyfile, len + 1); +#else + key_file_name = erealloc(key_file_name, _MAX_PATH); + if (len + 1 > _MAX_PATH) + return; + if (!ExpandEnvironmentStrings(keyfile, key_file_name, + _MAX_PATH)) { + msyslog(LOG_ERR, + "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); + strlcpy(key_file_name, keyfile, _MAX_PATH); + } + key_file_name = erealloc(key_file_name, + 1 + strlen(key_file_name)); +#endif /* SYS_WINNT */ + + authreadkeys(key_file_name); +} + + +/* + * rereadkeys - read the authentication key file over again. + */ +void +rereadkeys(void) +{ + if (NULL != key_file_name) + authreadkeys(key_file_name); +} + + +#if notyet +/* + * ntp_exit - document explicitly that ntpd has exited + */ +void +ntp_exit(int retval) +{ + msyslog(LOG_ERR, "EXITING with return code %d", retval); + exit(retval); +} +#endif + +/* + * fstostr - prettyprint NTP seconds + */ +char * fstostr( + time_t ntp_stamp + ) +{ + char * buf; + struct calendar tm; + + LIB_GETBUF(buf); + if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0) + snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error", + (long)ntp_stamp); + else + snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d", + tm.year, tm.month, tm.monthday, + tm.hour, tm.minute); + return buf; +} + + +/* + * ntpd_time_stepped is called back by step_systime(), allowing ntpd + * to do any one-time processing necessitated by the step. + */ +void +ntpd_time_stepped(void) +{ + u_int saved_mon_enabled; + + /* + * flush the monitor MRU list which contains l_fp timestamps + * which should not be compared across the step. + */ + if (MON_OFF != mon_enabled) { + saved_mon_enabled = mon_enabled; + mon_stop(MON_OFF); + mon_start(saved_mon_enabled); + } + + /* inform interpolating Windows code to allow time to go back */ +#ifdef SYS_WINNT + win_time_stepped(); +#endif +} + + +#ifdef DEBUG +void +append_flagstr( + char * flagstr, + size_t sz, + const char * text +) +{ + if ('\0' != flagstr[0]) { + strlcat(flagstr, ",", sz); + } + /* bail if we ran out of room */ + INSIST(strlcat(flagstr, text, sz) < sz); +} +#endif /* DEBUG */ |