1 /* Demo leapsecond deadlock 2 * by: John Stultz (john.stultz (at) linaro.org) 3 * (C) Copyright IBM 2012 4 * (C) Copyright 2013, 2015 Linaro Limited 5 * Licensed under the GPL 6 * 7 * This test demonstrates leapsecond deadlock that is possibe 8 * on kernels from 2.6.26 to 3.3. 9 * 10 * WARNING: THIS WILL LIKELY HARDHANG SYSTEMS AND MAY LOSE DATA 11 * RUN AT YOUR OWN RISK! 12 * To build: 13 * $ gcc leapcrash.c -o leapcrash -lrt 14 */ 15 16 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <time.h> 21 #include <sys/time.h> 22 #include <sys/timex.h> 23 #include <string.h> 24 #include <signal.h> 25 #ifdef KTEST 26 #include "../kselftest.h" 27 #else 28 static inline int ksft_exit_pass(void) 29 { 30 exit(0); 31 } 32 static inline int ksft_exit_fail(void) 33 { 34 exit(1); 35 } 36 #endif 37 38 39 40 /* clear NTP time_status & time_state */ 41 int clear_time_state(void) 42 { 43 struct timex tx; 44 int ret; 45 46 /* 47 * We have to call adjtime twice here, as kernels 48 * prior to 6b1859dba01c7 (included in 3.5 and 49 * -stable), had an issue with the state machine 50 * and wouldn't clear the STA_INS/DEL flag directly. 51 */ 52 tx.modes = ADJ_STATUS; 53 tx.status = STA_PLL; 54 ret = adjtimex(&tx); 55 56 tx.modes = ADJ_STATUS; 57 tx.status = 0; 58 ret = adjtimex(&tx); 59 60 return ret; 61 } 62 63 /* Make sure we cleanup on ctrl-c */ 64 void handler(int unused) 65 { 66 clear_time_state(); 67 exit(0); 68 } 69 70 71 int main(void) 72 { 73 struct timex tx; 74 struct timespec ts; 75 time_t next_leap; 76 int count = 0; 77 78 setbuf(stdout, NULL); 79 80 signal(SIGINT, handler); 81 signal(SIGKILL, handler); 82 printf("This runs for a few minutes. Press ctrl-c to stop\n"); 83 84 clear_time_state(); 85 86 87 /* Get the current time */ 88 clock_gettime(CLOCK_REALTIME, &ts); 89 90 /* Calculate the next possible leap second 23:59:60 GMT */ 91 next_leap = ts.tv_sec; 92 next_leap += 86400 - (next_leap % 86400); 93 94 for (count = 0; count < 20; count++) { 95 struct timeval tv; 96 97 98 /* set the time to 2 seconds before the leap */ 99 tv.tv_sec = next_leap - 2; 100 tv.tv_usec = 0; 101 if (settimeofday(&tv, NULL)) { 102 printf("Error: You're likely not running with proper (ie: root) permissions\n"); 103 return ksft_exit_fail(); 104 } 105 tx.modes = 0; 106 adjtimex(&tx); 107 108 /* hammer on adjtime w/ STA_INS */ 109 while (tx.time.tv_sec < next_leap + 1) { 110 /* Set the leap second insert flag */ 111 tx.modes = ADJ_STATUS; 112 tx.status = STA_INS; 113 adjtimex(&tx); 114 } 115 clear_time_state(); 116 printf("."); 117 } 118 printf("[OK]\n"); 119 return ksft_exit_pass(); 120 } 121