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        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
 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
 319int 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