330 lines · c
1/* valid adjtimex test2 * by: John Stultz <john.stultz@linaro.org>3 * (C) Copyright Linaro 20154 * Licensed under the GPLv25 *6 * This test validates adjtimex interface with valid7 * and invalid test data.8 *9 * Usage: valid-adjtimex10 *11 * To build:12 * $ gcc valid-adjtimex.c -o valid-adjtimex -lrt13 *14 * This program is free software: you can redistribute it and/or modify15 * it under the terms of the GNU General Public License as published by16 * the Free Software Foundation, either version 2 of the License, or17 * (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 of21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the22 * 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 1000000000LL35#define USEC_PER_SEC 1000000LL36 37#define ADJ_SETOFFSET 0x010038 39#include <sys/syscall.h>40int 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 */47int 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 3259#define NUM_FREQ_OUTOFRANGE 460#define NUM_FREQ_INVALID 261 62#define SHIFTED_PPM (1 << 16)63 64long 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 98long 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 108long invalid_freq[NUM_FREQ_INVALID] = {109 LONG_MAX,110 LONG_MIN,111};112 113int 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");185out: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 195int 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 230int 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 250int 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 320int main(int argc, char **argv)321{322 if (validate_freq())323 ksft_exit_fail();324 325 if (validate_set_offset())326 ksft_exit_fail();327 328 ksft_exit_pass();329}330