forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
330 lines
6.4 KiB
330 lines
6.4 KiB
/* valid adjtimex test |
|
* by: John Stultz <[email protected]> |
|
* (C) Copyright Linaro 2015 |
|
* Licensed under the GPLv2 |
|
* |
|
* This test validates adjtimex interface with valid |
|
* and invalid test data. |
|
* |
|
* Usage: valid-adjtimex |
|
* |
|
* To build: |
|
* $ gcc valid-adjtimex.c -o valid-adjtimex -lrt |
|
* |
|
* This program is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation, either version 2 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
*/ |
|
|
|
|
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <time.h> |
|
#include <sys/time.h> |
|
#include <sys/timex.h> |
|
#include <string.h> |
|
#include <signal.h> |
|
#include <unistd.h> |
|
#include "../kselftest.h" |
|
|
|
#define NSEC_PER_SEC 1000000000LL |
|
#define USEC_PER_SEC 1000000LL |
|
|
|
#define ADJ_SETOFFSET 0x0100 |
|
|
|
#include <sys/syscall.h> |
|
static int clock_adjtime(clockid_t id, struct timex *tx) |
|
{ |
|
return syscall(__NR_clock_adjtime, id, tx); |
|
} |
|
|
|
|
|
/* clear NTP time_status & time_state */ |
|
int clear_time_state(void) |
|
{ |
|
struct timex tx; |
|
int ret; |
|
|
|
tx.modes = ADJ_STATUS; |
|
tx.status = 0; |
|
ret = adjtimex(&tx); |
|
return ret; |
|
} |
|
|
|
#define NUM_FREQ_VALID 32 |
|
#define NUM_FREQ_OUTOFRANGE 4 |
|
#define NUM_FREQ_INVALID 2 |
|
|
|
long valid_freq[NUM_FREQ_VALID] = { |
|
-499<<16, |
|
-450<<16, |
|
-400<<16, |
|
-350<<16, |
|
-300<<16, |
|
-250<<16, |
|
-200<<16, |
|
-150<<16, |
|
-100<<16, |
|
-75<<16, |
|
-50<<16, |
|
-25<<16, |
|
-10<<16, |
|
-5<<16, |
|
-1<<16, |
|
-1000, |
|
1<<16, |
|
5<<16, |
|
10<<16, |
|
25<<16, |
|
50<<16, |
|
75<<16, |
|
100<<16, |
|
150<<16, |
|
200<<16, |
|
250<<16, |
|
300<<16, |
|
350<<16, |
|
400<<16, |
|
450<<16, |
|
499<<16, |
|
}; |
|
|
|
long outofrange_freq[NUM_FREQ_OUTOFRANGE] = { |
|
-1000<<16, |
|
-550<<16, |
|
550<<16, |
|
1000<<16, |
|
}; |
|
|
|
#define LONG_MAX (~0UL>>1) |
|
#define LONG_MIN (-LONG_MAX - 1) |
|
|
|
long invalid_freq[NUM_FREQ_INVALID] = { |
|
LONG_MAX, |
|
LONG_MIN, |
|
}; |
|
|
|
int validate_freq(void) |
|
{ |
|
struct timex tx; |
|
int ret, pass = 0; |
|
int i; |
|
|
|
clear_time_state(); |
|
|
|
memset(&tx, 0, sizeof(struct timex)); |
|
/* Set the leap second insert flag */ |
|
|
|
printf("Testing ADJ_FREQ... "); |
|
fflush(stdout); |
|
for (i = 0; i < NUM_FREQ_VALID; i++) { |
|
tx.modes = ADJ_FREQUENCY; |
|
tx.freq = valid_freq[i]; |
|
|
|
ret = adjtimex(&tx); |
|
if (ret < 0) { |
|
printf("[FAIL]\n"); |
|
printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n", |
|
valid_freq[i], valid_freq[i]>>16); |
|
pass = -1; |
|
goto out; |
|
} |
|
tx.modes = 0; |
|
ret = adjtimex(&tx); |
|
if (tx.freq != valid_freq[i]) { |
|
printf("Warning: freq value %ld not what we set it (%ld)!\n", |
|
tx.freq, valid_freq[i]); |
|
} |
|
} |
|
for (i = 0; i < NUM_FREQ_OUTOFRANGE; i++) { |
|
tx.modes = ADJ_FREQUENCY; |
|
tx.freq = outofrange_freq[i]; |
|
|
|
ret = adjtimex(&tx); |
|
if (ret < 0) { |
|
printf("[FAIL]\n"); |
|
printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n", |
|
outofrange_freq[i], outofrange_freq[i]>>16); |
|
pass = -1; |
|
goto out; |
|
} |
|
tx.modes = 0; |
|
ret = adjtimex(&tx); |
|
if (tx.freq == outofrange_freq[i]) { |
|
printf("[FAIL]\n"); |
|
printf("ERROR: out of range value %ld actually set!\n", |
|
tx.freq); |
|
pass = -1; |
|
goto out; |
|
} |
|
} |
|
|
|
|
|
if (sizeof(long) == 8) { /* this case only applies to 64bit systems */ |
|
for (i = 0; i < NUM_FREQ_INVALID; i++) { |
|
tx.modes = ADJ_FREQUENCY; |
|
tx.freq = invalid_freq[i]; |
|
ret = adjtimex(&tx); |
|
if (ret >= 0) { |
|
printf("[FAIL]\n"); |
|
printf("Error: No failure on invalid ADJ_FREQUENCY %ld\n", |
|
invalid_freq[i]); |
|
pass = -1; |
|
goto out; |
|
} |
|
} |
|
} |
|
|
|
printf("[OK]\n"); |
|
out: |
|
/* reset freq to zero */ |
|
tx.modes = ADJ_FREQUENCY; |
|
tx.freq = 0; |
|
ret = adjtimex(&tx); |
|
|
|
return pass; |
|
} |
|
|
|
|
|
int set_offset(long long offset, int use_nano) |
|
{ |
|
struct timex tmx = {}; |
|
int ret; |
|
|
|
tmx.modes = ADJ_SETOFFSET; |
|
if (use_nano) { |
|
tmx.modes |= ADJ_NANO; |
|
|
|
tmx.time.tv_sec = offset / NSEC_PER_SEC; |
|
tmx.time.tv_usec = offset % NSEC_PER_SEC; |
|
|
|
if (offset < 0 && tmx.time.tv_usec) { |
|
tmx.time.tv_sec -= 1; |
|
tmx.time.tv_usec += NSEC_PER_SEC; |
|
} |
|
} else { |
|
tmx.time.tv_sec = offset / USEC_PER_SEC; |
|
tmx.time.tv_usec = offset % USEC_PER_SEC; |
|
|
|
if (offset < 0 && tmx.time.tv_usec) { |
|
tmx.time.tv_sec -= 1; |
|
tmx.time.tv_usec += USEC_PER_SEC; |
|
} |
|
} |
|
|
|
ret = clock_adjtime(CLOCK_REALTIME, &tmx); |
|
if (ret < 0) { |
|
printf("(sec: %ld usec: %ld) ", tmx.time.tv_sec, tmx.time.tv_usec); |
|
printf("[FAIL]\n"); |
|
return -1; |
|
} |
|
return 0; |
|
} |
|
|
|
int set_bad_offset(long sec, long usec, int use_nano) |
|
{ |
|
struct timex tmx = {}; |
|
int ret; |
|
|
|
tmx.modes = ADJ_SETOFFSET; |
|
if (use_nano) |
|
tmx.modes |= ADJ_NANO; |
|
|
|
tmx.time.tv_sec = sec; |
|
tmx.time.tv_usec = usec; |
|
ret = clock_adjtime(CLOCK_REALTIME, &tmx); |
|
if (ret >= 0) { |
|
printf("Invalid (sec: %ld usec: %ld) did not fail! ", tmx.time.tv_sec, tmx.time.tv_usec); |
|
printf("[FAIL]\n"); |
|
return -1; |
|
} |
|
return 0; |
|
} |
|
|
|
int validate_set_offset(void) |
|
{ |
|
printf("Testing ADJ_SETOFFSET... "); |
|
fflush(stdout); |
|
|
|
/* Test valid values */ |
|
if (set_offset(NSEC_PER_SEC - 1, 1)) |
|
return -1; |
|
|
|
if (set_offset(-NSEC_PER_SEC + 1, 1)) |
|
return -1; |
|
|
|
if (set_offset(-NSEC_PER_SEC - 1, 1)) |
|
return -1; |
|
|
|
if (set_offset(5 * NSEC_PER_SEC, 1)) |
|
return -1; |
|
|
|
if (set_offset(-5 * NSEC_PER_SEC, 1)) |
|
return -1; |
|
|
|
if (set_offset(5 * NSEC_PER_SEC + NSEC_PER_SEC / 2, 1)) |
|
return -1; |
|
|
|
if (set_offset(-5 * NSEC_PER_SEC - NSEC_PER_SEC / 2, 1)) |
|
return -1; |
|
|
|
if (set_offset(USEC_PER_SEC - 1, 0)) |
|
return -1; |
|
|
|
if (set_offset(-USEC_PER_SEC + 1, 0)) |
|
return -1; |
|
|
|
if (set_offset(-USEC_PER_SEC - 1, 0)) |
|
return -1; |
|
|
|
if (set_offset(5 * USEC_PER_SEC, 0)) |
|
return -1; |
|
|
|
if (set_offset(-5 * USEC_PER_SEC, 0)) |
|
return -1; |
|
|
|
if (set_offset(5 * USEC_PER_SEC + USEC_PER_SEC / 2, 0)) |
|
return -1; |
|
|
|
if (set_offset(-5 * USEC_PER_SEC - USEC_PER_SEC / 2, 0)) |
|
return -1; |
|
|
|
/* Test invalid values */ |
|
if (set_bad_offset(0, -1, 1)) |
|
return -1; |
|
if (set_bad_offset(0, -1, 0)) |
|
return -1; |
|
if (set_bad_offset(0, 2 * NSEC_PER_SEC, 1)) |
|
return -1; |
|
if (set_bad_offset(0, 2 * USEC_PER_SEC, 0)) |
|
return -1; |
|
if (set_bad_offset(0, NSEC_PER_SEC, 1)) |
|
return -1; |
|
if (set_bad_offset(0, USEC_PER_SEC, 0)) |
|
return -1; |
|
if (set_bad_offset(0, -NSEC_PER_SEC, 1)) |
|
return -1; |
|
if (set_bad_offset(0, -USEC_PER_SEC, 0)) |
|
return -1; |
|
|
|
printf("[OK]\n"); |
|
return 0; |
|
} |
|
|
|
int main(int argc, char **argv) |
|
{ |
|
if (validate_freq()) |
|
return ksft_exit_fail(); |
|
|
|
if (validate_set_offset()) |
|
return ksft_exit_fail(); |
|
|
|
return ksft_exit_pass(); |
|
}
|
|
|