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