|  | /* Demo leapsecond deadlock | 
|  | *              by: John Stultz (john.stultz@linaro.org) | 
|  | *              (C) Copyright IBM 2012 | 
|  | *              (C) Copyright 2013, 2015 Linaro Limited | 
|  | *              Licensed under the GPL | 
|  | * | 
|  | * This test demonstrates leapsecond deadlock that is possibe | 
|  | * on kernels from 2.6.26 to 3.3. | 
|  | * | 
|  | * WARNING: THIS WILL LIKELY HARDHANG SYSTEMS AND MAY LOSE DATA | 
|  | * RUN AT YOUR OWN RISK! | 
|  | *  To build: | 
|  | *	$ gcc leapcrash.c -o leapcrash -lrt | 
|  | */ | 
|  |  | 
|  |  | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <time.h> | 
|  | #include <sys/time.h> | 
|  | #include <sys/timex.h> | 
|  | #include <string.h> | 
|  | #include <signal.h> | 
|  | #include "../kselftest.h" | 
|  |  | 
|  | /* clear NTP time_status & time_state */ | 
|  | int clear_time_state(void) | 
|  | { | 
|  | struct timex tx; | 
|  | int ret; | 
|  |  | 
|  | /* | 
|  | * We have to call adjtime twice here, as kernels | 
|  | * prior to 6b1859dba01c7 (included in 3.5 and | 
|  | * -stable), had an issue with the state machine | 
|  | * and wouldn't clear the STA_INS/DEL flag directly. | 
|  | */ | 
|  | tx.modes = ADJ_STATUS; | 
|  | tx.status = STA_PLL; | 
|  | ret = adjtimex(&tx); | 
|  |  | 
|  | tx.modes = ADJ_STATUS; | 
|  | tx.status = 0; | 
|  | ret = adjtimex(&tx); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Make sure we cleanup on ctrl-c */ | 
|  | void handler(int unused) | 
|  | { | 
|  | clear_time_state(); | 
|  | exit(0); | 
|  | } | 
|  |  | 
|  |  | 
|  | int main(void) | 
|  | { | 
|  | struct timex tx; | 
|  | struct timespec ts; | 
|  | time_t next_leap; | 
|  | int count = 0; | 
|  |  | 
|  | setbuf(stdout, NULL); | 
|  |  | 
|  | signal(SIGINT, handler); | 
|  | signal(SIGKILL, handler); | 
|  | printf("This runs for a few minutes. Press ctrl-c to stop\n"); | 
|  |  | 
|  | clear_time_state(); | 
|  |  | 
|  |  | 
|  | /* Get the current time */ | 
|  | clock_gettime(CLOCK_REALTIME, &ts); | 
|  |  | 
|  | /* Calculate the next possible leap second 23:59:60 GMT */ | 
|  | next_leap = ts.tv_sec; | 
|  | next_leap += 86400 - (next_leap % 86400); | 
|  |  | 
|  | for (count = 0; count < 20; count++) { | 
|  | struct timeval tv; | 
|  |  | 
|  |  | 
|  | /* set the time to 2 seconds before the leap */ | 
|  | tv.tv_sec = next_leap - 2; | 
|  | tv.tv_usec = 0; | 
|  | if (settimeofday(&tv, NULL)) { | 
|  | printf("Error: You're likely not running with proper (ie: root) permissions\n"); | 
|  | return ksft_exit_fail(); | 
|  | } | 
|  | tx.modes = 0; | 
|  | adjtimex(&tx); | 
|  |  | 
|  | /* hammer on adjtime w/ STA_INS */ | 
|  | while (tx.time.tv_sec < next_leap + 1) { | 
|  | /* Set the leap second insert flag */ | 
|  | tx.modes = ADJ_STATUS; | 
|  | tx.status = STA_INS; | 
|  | adjtimex(&tx); | 
|  | } | 
|  | clear_time_state(); | 
|  | printf("."); | 
|  | } | 
|  | printf("[OK]\n"); | 
|  | return ksft_exit_pass(); | 
|  | } |