1 /* valid adjtimex test 2 * by: John Stultz <john.stultz (at) 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 #ifndef __ANDROID__ 54 #include <sys/syscall.h> 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 */ 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 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 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 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 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 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