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 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 fflush(stdout); 127 for (i = 0; i < NUM_FREQ_VALID; i++) { 128 tx.modes = ADJ_FREQUENCY; 129 tx.freq = valid_freq[i]; 130 131 ret = adjtimex(&tx); 132 if (ret < 0) { 133 printf("[FAIL]\n"); 134 printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n", 135 valid_freq[i], valid_freq[i]>>16); 136 pass = -1; 137 goto out; 138 } 139 tx.modes = 0; 140 ret = adjtimex(&tx); 141 if (tx.freq != valid_freq[i]) { 142 printf("Warning: freq value %ld not what we set it (%ld)!\n", 143 tx.freq, valid_freq[i]); 144 } 145 } 146 for (i = 0; i < NUM_FREQ_OUTOFRANGE; i++) { 147 tx.modes = ADJ_FREQUENCY; 148 tx.freq = outofrange_freq[i]; 149 150 ret = adjtimex(&tx); 151 if (ret < 0) { 152 printf("[FAIL]\n"); 153 printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n", 154 outofrange_freq[i], outofrange_freq[i]>>16); 155 pass = -1; 156 goto out; 157 } 158 tx.modes = 0; 159 ret = adjtimex(&tx); 160 if (tx.freq == outofrange_freq[i]) { 161 printf("[FAIL]\n"); 162 printf("ERROR: out of range value %ld actually set!\n", 163 tx.freq); 164 pass = -1; 165 goto out; 166 } 167 } 168 169 170 if (sizeof(long) == 8) { /* this case only applies to 64bit systems */ 171 for (i = 0; i < NUM_FREQ_INVALID; i++) { 172 tx.modes = ADJ_FREQUENCY; 173 tx.freq = invalid_freq[i]; 174 ret = adjtimex(&tx); 175 if (ret >= 0) { 176 printf("[FAIL]\n"); 177 printf("Error: No failure on invalid ADJ_FREQUENCY %ld\n", 178 invalid_freq[i]); 179 pass = -1; 180 goto out; 181 } 182 } 183 } 184 185 printf("[OK]\n"); 186 out: 187 /* reset freq to zero */ 188 tx.modes = ADJ_FREQUENCY; 189 tx.freq = 0; 190 ret = adjtimex(&tx); 191 192 return pass; 193 } 194 195 196 int set_offset(long long offset, int use_nano) 197 { 198 struct timex tmx = {}; 199 int ret; 200 201 tmx.modes = ADJ_SETOFFSET; 202 if (use_nano) { 203 tmx.modes |= ADJ_NANO; 204 205 tmx.time.tv_sec = offset / NSEC_PER_SEC; 206 tmx.time.tv_usec = offset % NSEC_PER_SEC; 207 208 if (offset < 0 && tmx.time.tv_usec) { 209 tmx.time.tv_sec -= 1; 210 tmx.time.tv_usec += NSEC_PER_SEC; 211 } 212 } else { 213 tmx.time.tv_sec = offset / USEC_PER_SEC; 214 tmx.time.tv_usec = offset % USEC_PER_SEC; 215 216 if (offset < 0 && tmx.time.tv_usec) { 217 tmx.time.tv_sec -= 1; 218 tmx.time.tv_usec += USEC_PER_SEC; 219 } 220 } 221 222 ret = clock_adjtime(CLOCK_REALTIME, &tmx); 223 if (ret < 0) { 224 printf("(sec: %ld usec: %ld) ", tmx.time.tv_sec, tmx.time.tv_usec); 225 printf("[FAIL]\n"); 226 return -1; 227 } 228 return 0; 229 } 230 231 int set_bad_offset(long sec, long usec, int use_nano) 232 { 233 struct timex tmx = {}; 234 int ret; 235 236 tmx.modes = ADJ_SETOFFSET; 237 if (use_nano) 238 tmx.modes |= ADJ_NANO; 239 240 tmx.time.tv_sec = sec; 241 tmx.time.tv_usec = usec; 242 ret = clock_adjtime(CLOCK_REALTIME, &tmx); 243 if (ret >= 0) { 244 printf("Invalid (sec: %ld usec: %ld) did not fail! ", tmx.time.tv_sec, tmx.time.tv_usec); 245 printf("[FAIL]\n"); 246 return -1; 247 } 248 return 0; 249 } 250 251 int validate_set_offset(void) 252 { 253 printf("Testing ADJ_SETOFFSET... "); 254 fflush(stdout); 255 256 /* Test valid values */ 257 if (set_offset(NSEC_PER_SEC - 1, 1)) 258 return -1; 259 260 if (set_offset(-NSEC_PER_SEC + 1, 1)) 261 return -1; 262 263 if (set_offset(-NSEC_PER_SEC - 1, 1)) 264 return -1; 265 266 if (set_offset(5 * NSEC_PER_SEC, 1)) 267 return -1; 268 269 if (set_offset(-5 * NSEC_PER_SEC, 1)) 270 return -1; 271 272 if (set_offset(5 * NSEC_PER_SEC + NSEC_PER_SEC / 2, 1)) 273 return -1; 274 275 if (set_offset(-5 * NSEC_PER_SEC - NSEC_PER_SEC / 2, 1)) 276 return -1; 277 278 if (set_offset(USEC_PER_SEC - 1, 0)) 279 return -1; 280 281 if (set_offset(-USEC_PER_SEC + 1, 0)) 282 return -1; 283 284 if (set_offset(-USEC_PER_SEC - 1, 0)) 285 return -1; 286 287 if (set_offset(5 * USEC_PER_SEC, 0)) 288 return -1; 289 290 if (set_offset(-5 * USEC_PER_SEC, 0)) 291 return -1; 292 293 if (set_offset(5 * USEC_PER_SEC + USEC_PER_SEC / 2, 0)) 294 return -1; 295 296 if (set_offset(-5 * USEC_PER_SEC - USEC_PER_SEC / 2, 0)) 297 return -1; 298 299 /* Test invalid values */ 300 if (set_bad_offset(0, -1, 1)) 301 return -1; 302 if (set_bad_offset(0, -1, 0)) 303 return -1; 304 if (set_bad_offset(0, 2 * NSEC_PER_SEC, 1)) 305 return -1; 306 if (set_bad_offset(0, 2 * USEC_PER_SEC, 0)) 307 return -1; 308 if (set_bad_offset(0, NSEC_PER_SEC, 1)) 309 return -1; 310 if (set_bad_offset(0, USEC_PER_SEC, 0)) 311 return -1; 312 if (set_bad_offset(0, -NSEC_PER_SEC, 1)) 313 return -1; 314 if (set_bad_offset(0, -USEC_PER_SEC, 0)) 315 return -1; 316 317 printf("[OK]\n"); 318 return 0; 319 } 320 321 int main(int argc, char **argv) 322 { 323 if (validate_freq()) 324 return ksft_exit_fail(); 325 326 if (validate_set_offset()) 327 return ksft_exit_fail(); 328 329 return ksft_exit_pass(); 330 } 331