File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / ntp_util.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>