Commit | Line | Data |
---|---|---|
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 | */ | |
51 | void | |
a4c90f86 | 52 | sysntp_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 |
87 | void |
88 | sysntp_getbasetime(struct timeval *tvp) | |
89 | { | |
90 | struct timespec ts; | |
91 | int error; | |
3b779073 | 92 | size_t ts_size; |
e0163549 MD |
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 | */ | |
106 | int | |
107 | sysntp_offset_correction_is_running(void) | |
108 | { | |
109 | int64_t delta; | |
3b779073 | 110 | size_t delta_len; |
c32f1362 MD |
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 | */ | |
135 | double | |
136 | sysntp_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 | */ | |
165 | double | |
166 | sysntp_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 | */ | |
206 | void | |
207 | sysntp_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 |