Home | History | Annotate | Download | only in timers
      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