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