linux/tools/testing/selftests/timers/valid-adjtimex.c
<<
>>
Prefs
   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>
  43static 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 */
  50int 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
  65long 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
  99long 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
 109long invalid_freq[NUM_FREQ_INVALID] = {
 110        LONG_MAX,
 111        LONG_MIN,
 112};
 113
 114int 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");
 186out:
 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
 196int 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
 231int 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
 251int 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
 321int 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