xref: /dflybsd-src/usr.sbin/dntpd/system.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino  * Copyright (c) 2005 The DragonFly Project.  All rights reserved.
3*86d7f5d3SJohn Marino  *
4*86d7f5d3SJohn Marino  * This code is derived from software contributed to The DragonFly Project
5*86d7f5d3SJohn Marino  * by Matthew Dillon <dillon@backplane.com>
6*86d7f5d3SJohn Marino  *
7*86d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
8*86d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions
9*86d7f5d3SJohn Marino  * are met:
10*86d7f5d3SJohn Marino  *
11*86d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
12*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
13*86d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
14*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in
15*86d7f5d3SJohn Marino  *    the documentation and/or other materials provided with the
16*86d7f5d3SJohn Marino  *    distribution.
17*86d7f5d3SJohn Marino  * 3. Neither the name of The DragonFly Project nor the names of its
18*86d7f5d3SJohn Marino  *    contributors may be used to endorse or promote products derived
19*86d7f5d3SJohn Marino  *    from this software without specific, prior written permission.
20*86d7f5d3SJohn Marino  *
21*86d7f5d3SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*86d7f5d3SJohn Marino  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*86d7f5d3SJohn Marino  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*86d7f5d3SJohn Marino  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25*86d7f5d3SJohn Marino  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*86d7f5d3SJohn Marino  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*86d7f5d3SJohn Marino  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28*86d7f5d3SJohn Marino  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29*86d7f5d3SJohn Marino  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30*86d7f5d3SJohn Marino  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31*86d7f5d3SJohn Marino  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*86d7f5d3SJohn Marino  * SUCH DAMAGE.
33*86d7f5d3SJohn Marino  *
34*86d7f5d3SJohn Marino  * $DragonFly: src/usr.sbin/dntpd/system.c,v 1.9 2007/07/11 00:18:00 swildner Exp $
35*86d7f5d3SJohn Marino  */
36*86d7f5d3SJohn Marino 
37*86d7f5d3SJohn Marino #include "defs.h"
38*86d7f5d3SJohn Marino #include <sys/sysctl.h>
39*86d7f5d3SJohn Marino #include <sys/timex.h>
40*86d7f5d3SJohn Marino 
41*86d7f5d3SJohn Marino /*
42*86d7f5d3SJohn Marino  * If a system has multiple independant time-correcting mechanisms, this
43*86d7f5d3SJohn Marino  * function should clear out any corrections on those mechanisms that we
44*86d7f5d3SJohn Marino  * will NOT be using.  We can leave a prior correction intact on the
45*86d7f5d3SJohn Marino  * mechanism that we ARE using.
46*86d7f5d3SJohn Marino  *
47*86d7f5d3SJohn Marino  * However, it is usually a good idea to clean out any offset correction
48*86d7f5d3SJohn Marino  * that is still in progress anyway.  We leave the frequency correction
49*86d7f5d3SJohn Marino  * intact.
50*86d7f5d3SJohn Marino  */
51*86d7f5d3SJohn Marino void
sysntp_clear_alternative_corrections(void)52*86d7f5d3SJohn Marino sysntp_clear_alternative_corrections(void)
53*86d7f5d3SJohn Marino {
54*86d7f5d3SJohn Marino     struct timex ntp;
55*86d7f5d3SJohn Marino     int64_t offset;
56*86d7f5d3SJohn Marino 
57*86d7f5d3SJohn Marino     if (no_update_opt)
58*86d7f5d3SJohn Marino 	return;
59*86d7f5d3SJohn Marino 
60*86d7f5d3SJohn Marino     /*
61*86d7f5d3SJohn Marino      * Clear the ntp interface.  We will use the sysctl interface
62*86d7f5d3SJohn Marino      * (XXX)
63*86d7f5d3SJohn Marino      */
64*86d7f5d3SJohn Marino     bzero(&ntp, sizeof(ntp));
65*86d7f5d3SJohn Marino     ntp.modes = MOD_OFFSET | MOD_FREQUENCY;
66*86d7f5d3SJohn Marino     ntp.offset = 0;
67*86d7f5d3SJohn Marino     ntp.freq = 0;
68*86d7f5d3SJohn Marino     ntp_adjtime(&ntp);
69*86d7f5d3SJohn Marino 
70*86d7f5d3SJohn Marino     /*
71*86d7f5d3SJohn Marino      * Clean out any offset still being applied to real time.  Leave
72*86d7f5d3SJohn Marino      * any prior frequency correction intact.
73*86d7f5d3SJohn Marino      */
74*86d7f5d3SJohn Marino     offset = 0;
75*86d7f5d3SJohn Marino     sysctlbyname("kern.ntp.delta", NULL, 0, &offset, sizeof(offset));
76*86d7f5d3SJohn Marino }
77*86d7f5d3SJohn Marino 
78*86d7f5d3SJohn Marino /*
79*86d7f5d3SJohn Marino  * Obtain a timestamp that contains ONLY corrections made by the system
80*86d7f5d3SJohn Marino  * to the base time.  The actual value of the timestamp is not relevant,
81*86d7f5d3SJohn Marino  * only the delta from two queries to this routine.
82*86d7f5d3SJohn Marino  *
83*86d7f5d3SJohn Marino  * This is used by DNTPD to determine what corrections the system has made
84*86d7f5d3SJohn Marino  * to the system's real time so DNTPD can uncorrect them for the purpose
85*86d7f5d3SJohn Marino  * of calculating the linear regression.
86*86d7f5d3SJohn Marino  */
87*86d7f5d3SJohn Marino void
sysntp_getbasetime(struct timeval * tvp)88*86d7f5d3SJohn Marino sysntp_getbasetime(struct timeval *tvp)
89*86d7f5d3SJohn Marino {
90*86d7f5d3SJohn Marino     struct timespec ts;
91*86d7f5d3SJohn Marino     int error;
92*86d7f5d3SJohn Marino     size_t ts_size;
93*86d7f5d3SJohn Marino 
94*86d7f5d3SJohn Marino     ts_size = sizeof(ts);
95*86d7f5d3SJohn Marino     error = sysctlbyname("kern.basetime", &ts, &ts_size, NULL, 0);
96*86d7f5d3SJohn Marino     if (error < 0) {
97*86d7f5d3SJohn Marino 	logerr("sysctlbyname(\"kern.basetime\") failed, cannot continue");
98*86d7f5d3SJohn Marino 	exit(1);
99*86d7f5d3SJohn Marino     }
100*86d7f5d3SJohn Marino     ts_to_tv(&ts, tvp);
101*86d7f5d3SJohn Marino }
102*86d7f5d3SJohn Marino 
103*86d7f5d3SJohn Marino /*
104*86d7f5d3SJohn Marino  * Return 1 if an offset correction is still running, 0 if it isn't.
105*86d7f5d3SJohn Marino  */
106*86d7f5d3SJohn Marino int
sysntp_offset_correction_is_running(void)107*86d7f5d3SJohn Marino sysntp_offset_correction_is_running(void)
108*86d7f5d3SJohn Marino {
109*86d7f5d3SJohn Marino     int64_t delta;
110*86d7f5d3SJohn Marino     size_t delta_len;
111*86d7f5d3SJohn Marino 
112*86d7f5d3SJohn Marino     delta_len = sizeof(delta);
113*86d7f5d3SJohn Marino     if (sysctlbyname("kern.ntp.delta", &delta, &delta_len, NULL, 0) == 0) {
114*86d7f5d3SJohn Marino 	if (delta != 0)
115*86d7f5d3SJohn Marino 	    return(1);
116*86d7f5d3SJohn Marino     }
117*86d7f5d3SJohn Marino     return(0);
118*86d7f5d3SJohn Marino }
119*86d7f5d3SJohn Marino 
120*86d7f5d3SJohn Marino /*
121*86d7f5d3SJohn Marino  * The offset error is passed as seconds per second.  Only fairly small
122*86d7f5d3SJohn Marino  * offsets are passed to this function (see sysntp_correct_course_offset()
123*86d7f5d3SJohn Marino  * for large corrections).  This function may request that the offset
124*86d7f5d3SJohn Marino  * be corrected by shifting the frequency by returning the frequency shift
125*86d7f5d3SJohn Marino  * (usually a small number in the 1E-6 range) (NOT YET IMPLEMENTED).
126*86d7f5d3SJohn Marino  *
127*86d7f5d3SJohn Marino  * The 64 bit delta is calculated as nanoseconds per second.  Since we are
128*86d7f5d3SJohn Marino  * passed an offset error we must negate the result to correct the error.
129*86d7f5d3SJohn Marino  *
130*86d7f5d3SJohn Marino  * Because offset corrections skew the accuracy of the clock while the
131*86d7f5d3SJohn Marino  * correction is in progress, we do not want to use them once we are
132*86d7f5d3SJohn Marino  * reasonably well synchronized.  We can make small offset corrections
133*86d7f5d3SJohn Marino  * by shifting the frequency a bit.  XXX
134*86d7f5d3SJohn Marino  */
135*86d7f5d3SJohn Marino double
sysntp_correct_offset(double offset)136*86d7f5d3SJohn Marino sysntp_correct_offset(double offset)
137*86d7f5d3SJohn Marino {
138*86d7f5d3SJohn Marino     int64_t delta;
139*86d7f5d3SJohn Marino 
140*86d7f5d3SJohn Marino     /*
141*86d7f5d3SJohn Marino      * Course correction
142*86d7f5d3SJohn Marino      */
143*86d7f5d3SJohn Marino     if (offset < -0.001 || offset > 0.001) {
144*86d7f5d3SJohn Marino 	logdebug(1, "issuing offset adjustment: %7.6fs", -offset);
145*86d7f5d3SJohn Marino 	if (no_update_opt)
146*86d7f5d3SJohn Marino 	    logdebug(1, " (UPDATES DISABLED)");
147*86d7f5d3SJohn Marino 	logdebug(1, "\n");
148*86d7f5d3SJohn Marino 	delta = -(int64_t)(offset * 1.0E+9);
149*86d7f5d3SJohn Marino 	if (no_update_opt == 0)
150*86d7f5d3SJohn Marino 	    sysctlbyname("kern.ntp.delta", NULL, 0, &delta, sizeof(delta));
151*86d7f5d3SJohn Marino 	return(0.0);
152*86d7f5d3SJohn Marino     }
153*86d7f5d3SJohn Marino 
154*86d7f5d3SJohn Marino     /*
155*86d7f5d3SJohn Marino      * Fine correction - do it by adjusting the frequency.
156*86d7f5d3SJohn Marino      * XXX
157*86d7f5d3SJohn Marino      */
158*86d7f5d3SJohn Marino     return(0.0);
159*86d7f5d3SJohn Marino }
160*86d7f5d3SJohn Marino 
161*86d7f5d3SJohn Marino /*
162*86d7f5d3SJohn Marino  * This function is used for what should be a one-time correction on
163*86d7f5d3SJohn Marino  * startup.
164*86d7f5d3SJohn Marino  */
165*86d7f5d3SJohn Marino double
sysntp_correct_course_offset(double offset)166*86d7f5d3SJohn Marino sysntp_correct_course_offset(double offset)
167*86d7f5d3SJohn Marino {
168*86d7f5d3SJohn Marino     struct timeval tv;
169*86d7f5d3SJohn Marino     struct tm *tp;
170*86d7f5d3SJohn Marino     time_t t;
171*86d7f5d3SJohn Marino     char buf[64];
172*86d7f5d3SJohn Marino 
173*86d7f5d3SJohn Marino     offset = -offset;	/* if we are ahead, correct backwards, and vise versa*/
174*86d7f5d3SJohn Marino     if (gettimeofday(&tv, NULL) == 0) {
175*86d7f5d3SJohn Marino 	tv_add_offset(&tv, offset);
176*86d7f5d3SJohn Marino 	if (no_update_opt == 0 && settimeofday(&tv, NULL) < 0) {
177*86d7f5d3SJohn Marino 	    logerr("settimeofday");
178*86d7f5d3SJohn Marino 	} else {
179*86d7f5d3SJohn Marino 	    logdebug(1, "issuing COARSE offset adjustment: %7.6fs, ",
180*86d7f5d3SJohn Marino 		    offset);
181*86d7f5d3SJohn Marino 	    t = tv.tv_sec;
182*86d7f5d3SJohn Marino 	    tp = localtime(&t);
183*86d7f5d3SJohn Marino 	    strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", tp);
184*86d7f5d3SJohn Marino 	    logdebug(1, "%s.%03ld", buf, tv.tv_usec / 1000);
185*86d7f5d3SJohn Marino 	    if (no_update_opt)
186*86d7f5d3SJohn Marino 		logdebug(1, " (UPDATES DISABLED)");
187*86d7f5d3SJohn Marino 	    if (quickset_opt)
188*86d7f5d3SJohn Marino 		logdebug(1, " (ONE-TIME QUICKSET)");
189*86d7f5d3SJohn Marino 	    logdebug(1, "\n");
190*86d7f5d3SJohn Marino 	}
191*86d7f5d3SJohn Marino     } else {
192*86d7f5d3SJohn Marino 	logerr("gettimeofday");
193*86d7f5d3SJohn Marino     }
194*86d7f5d3SJohn Marino     return(0.0);
195*86d7f5d3SJohn Marino }
196*86d7f5d3SJohn Marino 
197*86d7f5d3SJohn Marino /*
198*86d7f5d3SJohn Marino  * freq is passed as seconds per second.
199*86d7f5d3SJohn Marino  *
200*86d7f5d3SJohn Marino  * The calculated 64 bit correction is nanoseconds per second shifted
201*86d7f5d3SJohn Marino  * left 32.
202*86d7f5d3SJohn Marino  *
203*86d7f5d3SJohn Marino  * Frequency errors greater then 1 second per second will not be corrected.
204*86d7f5d3SJohn Marino  * It doesn't hurt to continue correcting the frequency.
205*86d7f5d3SJohn Marino  */
206*86d7f5d3SJohn Marino void
sysntp_correct_freq(double freq)207*86d7f5d3SJohn Marino sysntp_correct_freq(double freq)
208*86d7f5d3SJohn Marino {
209*86d7f5d3SJohn Marino     static double last_freq;
210*86d7f5d3SJohn Marino     int64_t delta;
211*86d7f5d3SJohn Marino     int loglevel;
212*86d7f5d3SJohn Marino 
213*86d7f5d3SJohn Marino     if (last_freq == 0.0 || fabs(freq - last_freq) >= 20.0E-6)
214*86d7f5d3SJohn Marino 	loglevel = 1;
215*86d7f5d3SJohn Marino     else if (fabs(freq - last_freq) >= 5.0E-6)
216*86d7f5d3SJohn Marino 	loglevel = 2;
217*86d7f5d3SJohn Marino     else
218*86d7f5d3SJohn Marino 	loglevel = 3;
219*86d7f5d3SJohn Marino     last_freq = freq;
220*86d7f5d3SJohn Marino 
221*86d7f5d3SJohn Marino     if (freq >= -1.0 && freq < 1.0) {
222*86d7f5d3SJohn Marino 	logdebug(loglevel, "issuing frequency adjustment: %6.3fppm",
223*86d7f5d3SJohn Marino 		-freq * 1000000.0);
224*86d7f5d3SJohn Marino 	if (no_update_opt)
225*86d7f5d3SJohn Marino 		logdebug(loglevel, " (UPDATES DISABLED)");
226*86d7f5d3SJohn Marino 	logdebug(loglevel, "\n");
227*86d7f5d3SJohn Marino 	delta = -((int64_t)(freq * 1.0E+9) << 32);
228*86d7f5d3SJohn Marino 	if (no_update_opt == 0)
229*86d7f5d3SJohn Marino 	    sysctlbyname("kern.ntp.permanent", NULL, 0, &delta, sizeof(delta));
230*86d7f5d3SJohn Marino     }
231*86d7f5d3SJohn Marino }
232*86d7f5d3SJohn Marino 
233