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> 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 */ 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 #define LONG_MAX (~0UL>>1) 106 #define LONG_MIN (-LONG_MAX - 1) 107 108 long invalid_freq[NUM_FREQ_INVALID] = { 109 LONG_MAX, 110 LONG_MIN, 111 }; 112 113 int validate_freq(void) 114 { 115 struct timex tx; 116 int ret, pass = 0; 117 int i; 118 119 clear_time_state(); 120 121 memset(&tx, 0, sizeof(struct timex)); 122 /* Set the leap second insert flag */ 123 124 printf("Testing ADJ_FREQ... "); 125 fflush(stdout); 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 fflush(stdout); 254 255 /* Test valid values */ 256 if (set_offset(NSEC_PER_SEC - 1, 1)) 257 return -1; 258 259 if (set_offset(-NSEC_PER_SEC + 1, 1)) 260 return -1; 261 262 if (set_offset(-NSEC_PER_SEC - 1, 1)) 263 return -1; 264 265 if (set_offset(5 * NSEC_PER_SEC, 1)) 266 return -1; 267 268 if (set_offset(-5 * NSEC_PER_SEC, 1)) 269 return -1; 270 271 if (set_offset(5 * NSEC_PER_SEC + NSEC_PER_SEC / 2, 1)) 272 return -1; 273 274 if (set_offset(-5 * NSEC_PER_SEC - NSEC_PER_SEC / 2, 1)) 275 return -1; 276 277 if (set_offset(USEC_PER_SEC - 1, 0)) 278 return -1; 279 280 if (set_offset(-USEC_PER_SEC + 1, 0)) 281 return -1; 282 283 if (set_offset(-USEC_PER_SEC - 1, 0)) 284 return -1; 285 286 if (set_offset(5 * USEC_PER_SEC, 0)) 287 return -1; 288 289 if (set_offset(-5 * USEC_PER_SEC, 0)) 290 return -1; 291 292 if (set_offset(5 * USEC_PER_SEC + USEC_PER_SEC / 2, 0)) 293 return -1; 294 295 if (set_offset(-5 * USEC_PER_SEC - USEC_PER_SEC / 2, 0)) 296 return -1; 297 298 /* Test invalid values */ 299 if (set_bad_offset(0, -1, 1)) 300 return -1; 301 if (set_bad_offset(0, -1, 0)) 302 return -1; 303 if (set_bad_offset(0, 2 * NSEC_PER_SEC, 1)) 304 return -1; 305 if (set_bad_offset(0, 2 * USEC_PER_SEC, 0)) 306 return -1; 307 if (set_bad_offset(0, NSEC_PER_SEC, 1)) 308 return -1; 309 if (set_bad_offset(0, 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 316 printf("[OK]\n"); 317 return 0; 318 } 319 320 int main(int argc, char **argv) 321 { 322 if (validate_freq()) 323 return ksft_exit_fail(); 324 325 if (validate_set_offset()) 326 return ksft_exit_fail(); 327 328 return ksft_exit_pass(); 329 } 330