1 /* valid adjtimex test
2 * by: John Stultz <john.stultz@linaro.org>
3 * (C) Copyright Linaro 2015
4 * Licensed under the GPLv2
5 *
6 * This test validates adjtimex interface with valid
7 * and invalid test data.
8 *
9 * Usage: valid-adjtimex
10 *
11 * To build:
12 * $ gcc valid-adjtimex.c -o valid-adjtimex -lrt
13 *
14 * This program is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <time.h>
27 #include <sys/time.h>
28 #include <sys/timex.h>
29 #include <string.h>
30 #include <signal.h>
31 #include <unistd.h>
32 #include "../kselftest.h"
33
34 #define NSEC_PER_SEC 1000000000LL
35 #define USEC_PER_SEC 1000000LL
36
37 #define ADJ_SETOFFSET 0x0100
38
39 #include <sys/syscall.h>
clock_adjtime(clockid_t id,struct timex * tx)40 int clock_adjtime(clockid_t id, struct timex *tx)
41 {
42 return syscall(__NR_clock_adjtime, id, tx);
43 }
44
45
46 /* clear NTP time_status & time_state */
clear_time_state(void)47 int clear_time_state(void)
48 {
49 struct timex tx;
50 int ret;
51
52 tx.modes = ADJ_STATUS;
53 tx.status = 0;
54 ret = adjtimex(&tx);
55 return ret;
56 }
57
58 #define NUM_FREQ_VALID 32
59 #define NUM_FREQ_OUTOFRANGE 4
60 #define NUM_FREQ_INVALID 2
61
62 #define SHIFTED_PPM (1 << 16)
63
64 long valid_freq[NUM_FREQ_VALID] = {
65 -499 * SHIFTED_PPM,
66 -450 * SHIFTED_PPM,
67 -400 * SHIFTED_PPM,
68 -350 * SHIFTED_PPM,
69 -300 * SHIFTED_PPM,
70 -250 * SHIFTED_PPM,
71 -200 * SHIFTED_PPM,
72 -150 * SHIFTED_PPM,
73 -100 * SHIFTED_PPM,
74 -75 * SHIFTED_PPM,
75 -50 * SHIFTED_PPM,
76 -25 * SHIFTED_PPM,
77 -10 * SHIFTED_PPM,
78 -5 * SHIFTED_PPM,
79 -1 * SHIFTED_PPM,
80 -1000,
81 1 * SHIFTED_PPM,
82 5 * SHIFTED_PPM,
83 10 * SHIFTED_PPM,
84 25 * SHIFTED_PPM,
85 50 * SHIFTED_PPM,
86 75 * SHIFTED_PPM,
87 100 * SHIFTED_PPM,
88 150 * SHIFTED_PPM,
89 200 * SHIFTED_PPM,
90 250 * SHIFTED_PPM,
91 300 * SHIFTED_PPM,
92 350 * SHIFTED_PPM,
93 400 * SHIFTED_PPM,
94 450 * SHIFTED_PPM,
95 499 * SHIFTED_PPM,
96 };
97
98 long outofrange_freq[NUM_FREQ_OUTOFRANGE] = {
99 -1000 * SHIFTED_PPM,
100 -550 * SHIFTED_PPM,
101 550 * SHIFTED_PPM,
102 1000 * SHIFTED_PPM,
103 };
104
105 #ifndef LONG_MAX
106 #define LONG_MAX (~0UL>>1)
107 #endif
108 #ifndef LONG_MIN
109 #define LONG_MIN (-LONG_MAX - 1)
110 #endif
111
112 long invalid_freq[NUM_FREQ_INVALID] = {
113 LONG_MAX,
114 LONG_MIN,
115 };
116
validate_freq(void)117 int validate_freq(void)
118 {
119 struct timex tx;
120 int ret, pass = 0;
121 int i;
122
123 clear_time_state();
124
125 memset(&tx, 0, sizeof(struct timex));
126 /* Set the leap second insert flag */
127
128 printf("Testing ADJ_FREQ... ");
129 fflush(stdout);
130 for (i = 0; i < NUM_FREQ_VALID; i++) {
131 tx.modes = ADJ_FREQUENCY;
132 tx.freq = valid_freq[i];
133
134 ret = adjtimex(&tx);
135 if (ret < 0) {
136 printf("[FAIL]\n");
137 printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n",
138 valid_freq[i], valid_freq[i]>>16);
139 pass = -1;
140 goto out;
141 }
142 tx.modes = 0;
143 ret = adjtimex(&tx);
144 if (tx.freq != valid_freq[i]) {
145 printf("Warning: freq value %ld not what we set it (%ld)!\n",
146 tx.freq, valid_freq[i]);
147 }
148 }
149 for (i = 0; i < NUM_FREQ_OUTOFRANGE; i++) {
150 tx.modes = ADJ_FREQUENCY;
151 tx.freq = outofrange_freq[i];
152
153 ret = adjtimex(&tx);
154 if (ret < 0) {
155 printf("[FAIL]\n");
156 printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n",
157 outofrange_freq[i], outofrange_freq[i]>>16);
158 pass = -1;
159 goto out;
160 }
161 tx.modes = 0;
162 ret = adjtimex(&tx);
163 if (tx.freq == outofrange_freq[i]) {
164 printf("[FAIL]\n");
165 printf("ERROR: out of range value %ld actually set!\n",
166 tx.freq);
167 pass = -1;
168 goto out;
169 }
170 }
171
172
173 if (sizeof(long) == 8) { /* this case only applies to 64bit systems */
174 for (i = 0; i < NUM_FREQ_INVALID; i++) {
175 tx.modes = ADJ_FREQUENCY;
176 tx.freq = invalid_freq[i];
177 ret = adjtimex(&tx);
178 if (ret >= 0) {
179 printf("[FAIL]\n");
180 printf("Error: No failure on invalid ADJ_FREQUENCY %ld\n",
181 invalid_freq[i]);
182 pass = -1;
183 goto out;
184 }
185 }
186 }
187
188 printf("[OK]\n");
189 out:
190 /* reset freq to zero */
191 tx.modes = ADJ_FREQUENCY;
192 tx.freq = 0;
193 ret = adjtimex(&tx);
194
195 return pass;
196 }
197
198
set_offset(long long offset,int use_nano)199 int set_offset(long long offset, int use_nano)
200 {
201 struct timex tmx = {};
202 int ret;
203
204 tmx.modes = ADJ_SETOFFSET;
205 if (use_nano) {
206 tmx.modes |= ADJ_NANO;
207
208 tmx.time.tv_sec = offset / NSEC_PER_SEC;
209 tmx.time.tv_usec = offset % NSEC_PER_SEC;
210
211 if (offset < 0 && tmx.time.tv_usec) {
212 tmx.time.tv_sec -= 1;
213 tmx.time.tv_usec += NSEC_PER_SEC;
214 }
215 } else {
216 tmx.time.tv_sec = offset / USEC_PER_SEC;
217 tmx.time.tv_usec = offset % USEC_PER_SEC;
218
219 if (offset < 0 && tmx.time.tv_usec) {
220 tmx.time.tv_sec -= 1;
221 tmx.time.tv_usec += USEC_PER_SEC;
222 }
223 }
224
225 ret = clock_adjtime(CLOCK_REALTIME, &tmx);
226 if (ret < 0) {
227 printf("(sec: %ld usec: %ld) ", tmx.time.tv_sec, tmx.time.tv_usec);
228 printf("[FAIL]\n");
229 return -1;
230 }
231 return 0;
232 }
233
set_bad_offset(long sec,long usec,int use_nano)234 int set_bad_offset(long sec, long usec, int use_nano)
235 {
236 struct timex tmx = {};
237 int ret;
238
239 tmx.modes = ADJ_SETOFFSET;
240 if (use_nano)
241 tmx.modes |= ADJ_NANO;
242
243 tmx.time.tv_sec = sec;
244 tmx.time.tv_usec = usec;
245 ret = clock_adjtime(CLOCK_REALTIME, &tmx);
246 if (ret >= 0) {
247 printf("Invalid (sec: %ld usec: %ld) did not fail! ", tmx.time.tv_sec, tmx.time.tv_usec);
248 printf("[FAIL]\n");
249 return -1;
250 }
251 return 0;
252 }
253
validate_set_offset(void)254 int validate_set_offset(void)
255 {
256 printf("Testing ADJ_SETOFFSET... ");
257 fflush(stdout);
258
259 /* Test valid values */
260 if (set_offset(NSEC_PER_SEC - 1, 1))
261 return -1;
262
263 if (set_offset(-NSEC_PER_SEC + 1, 1))
264 return -1;
265
266 if (set_offset(-NSEC_PER_SEC - 1, 1))
267 return -1;
268
269 if (set_offset(5 * NSEC_PER_SEC, 1))
270 return -1;
271
272 if (set_offset(-5 * NSEC_PER_SEC, 1))
273 return -1;
274
275 if (set_offset(5 * NSEC_PER_SEC + NSEC_PER_SEC / 2, 1))
276 return -1;
277
278 if (set_offset(-5 * NSEC_PER_SEC - NSEC_PER_SEC / 2, 1))
279 return -1;
280
281 if (set_offset(USEC_PER_SEC - 1, 0))
282 return -1;
283
284 if (set_offset(-USEC_PER_SEC + 1, 0))
285 return -1;
286
287 if (set_offset(-USEC_PER_SEC - 1, 0))
288 return -1;
289
290 if (set_offset(5 * USEC_PER_SEC, 0))
291 return -1;
292
293 if (set_offset(-5 * USEC_PER_SEC, 0))
294 return -1;
295
296 if (set_offset(5 * USEC_PER_SEC + USEC_PER_SEC / 2, 0))
297 return -1;
298
299 if (set_offset(-5 * USEC_PER_SEC - USEC_PER_SEC / 2, 0))
300 return -1;
301
302 /* Test invalid values */
303 if (set_bad_offset(0, -1, 1))
304 return -1;
305 if (set_bad_offset(0, -1, 0))
306 return -1;
307 if (set_bad_offset(0, 2 * NSEC_PER_SEC, 1))
308 return -1;
309 if (set_bad_offset(0, 2 * USEC_PER_SEC, 0))
310 return -1;
311 if (set_bad_offset(0, NSEC_PER_SEC, 1))
312 return -1;
313 if (set_bad_offset(0, USEC_PER_SEC, 0))
314 return -1;
315 if (set_bad_offset(0, -NSEC_PER_SEC, 1))
316 return -1;
317 if (set_bad_offset(0, -USEC_PER_SEC, 0))
318 return -1;
319
320 printf("[OK]\n");
321 return 0;
322 }
323
main(int argc,char ** argv)324 int main(int argc, char **argv)
325 {
326 if (validate_freq())
327 ksft_exit_fail();
328
329 if (validate_set_offset())
330 ksft_exit_fail();
331
332 ksft_exit_pass();
333 }
334