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 } 329