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