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