From 017d6f8f5630071e2a532f58f9513757d94ac7d5 Mon Sep 17 00:00:00 2001 From: Patrick Oppenlander Date: Thu, 8 Feb 2024 14:36:25 +1100 Subject: [PATCH] reference: move leap second source into leapdb Separate out source of leap second data into a new module in preparation for supporting more sources such as leap-seconds.list. --- Makefile.in | 2 +- leapdb.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++ leapdb.h | 37 +++++++++++++ main.c | 3 ++ reference.c | 99 +++-------------------------------- 5 files changed, 194 insertions(+), 94 deletions(-) create mode 100644 leapdb.c create mode 100644 leapdb.h diff --git a/Makefile.in b/Makefile.in index 101e0c69..318109bb 100644 --- a/Makefile.in +++ b/Makefile.in @@ -37,7 +37,7 @@ GETDATE_CFLAGS = @GETDATE_CFLAGS@ EXTRA_OBJS = @EXTRA_OBJS@ -OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o quantiles.o \ +OBJS = array.o cmdparse.o conf.o leapdb.o local.o logging.o main.o memory.o quantiles.o \ reference.o regress.o rtc.o samplefilt.o sched.o socket.o sources.o sourcestats.o \ stubs.o smooth.o sys.o sys_null.o tempcomp.o util.o $(EXTRA_OBJS) diff --git a/leapdb.c b/leapdb.c new file mode 100644 index 00000000..676a0d5d --- /dev/null +++ b/leapdb.c @@ -0,0 +1,147 @@ +/* + chronyd/chronyc - Programs for keeping computer clocks accurate. + + ********************************************************************** + * Copyright (C) Miroslav Lichvar 2009-2018, 2020, 2022 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ********************************************************************** + + ======================================================================= + + This module provides leap second information. */ + +#include "config.h" + +#include "sysincl.h" + +#include "conf.h" +#include "leapdb.h" +#include "logging.h" + +/* ================================================== */ + +/* Name of a system timezone containing leap seconds occuring at midnight */ +static char *leap_tzname; + +/* ================================================== */ + +static NTP_Leap +get_tz_leap(time_t when, int *tai_offset) +{ + static time_t last_tz_leap_check; + static NTP_Leap tz_leap; + static int tz_tai_offset; + + struct tm stm, *tm; + time_t t; + char *tz_env, tz_orig[128]; + + *tai_offset = tz_tai_offset; + + /* Do this check at most twice a day */ + when = when / (12 * 3600) * (12 * 3600); + if (last_tz_leap_check == when) + return tz_leap; + + last_tz_leap_check = when; + tz_leap = LEAP_Normal; + tz_tai_offset = 0; + + tm = gmtime(&when); + if (!tm) + return tz_leap; + + stm = *tm; + + /* Temporarily switch to the timezone containing leap seconds */ + tz_env = getenv("TZ"); + if (tz_env) { + if (strlen(tz_env) >= sizeof (tz_orig)) + return tz_leap; + strcpy(tz_orig, tz_env); + } + setenv("TZ", leap_tzname, 1); + tzset(); + + /* Get the TAI-UTC offset, which started at the epoch at 10 seconds */ + t = mktime(&stm); + if (t != -1) + tz_tai_offset = t - when + 10; + + /* Set the time to 23:59:60 and see how it overflows in mktime() */ + stm.tm_sec = 60; + stm.tm_min = 59; + stm.tm_hour = 23; + + t = mktime(&stm); + + if (tz_env) + setenv("TZ", tz_orig, 1); + else + unsetenv("TZ"); + tzset(); + + if (t == -1) + return tz_leap; + + if (stm.tm_sec == 60) + tz_leap = LEAP_InsertSecond; + else if (stm.tm_sec == 1) + tz_leap = LEAP_DeleteSecond; + + *tai_offset = tz_tai_offset; + + return tz_leap; +} + +/* ================================================== */ + +void +LDB_Initialise(void) +{ + int tai_offset; + + leap_tzname = CNF_GetLeapSecTimezone(); + if (leap_tzname) { + /* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */ + if (get_tz_leap(1341014400, &tai_offset) == LEAP_InsertSecond && tai_offset == 34 && + get_tz_leap(1356912000, &tai_offset) == LEAP_Normal && tai_offset == 35) { + LOG(LOGS_INFO, "Using %s timezone to obtain leap second data", leap_tzname); + } else { + LOG(LOGS_WARN, "Timezone %s failed leap second check, ignoring", leap_tzname); + leap_tzname = NULL; + } + } +} + +/* ================================================== */ + +NTP_Leap +LDB_GetLeap(time_t when, int *tai_offset) +{ + *tai_offset = 0; + if (leap_tzname) + return get_tz_leap(when, tai_offset); + return LEAP_Normal; +} + +/* ================================================== */ + +void +LDB_Finalise(void) +{ + /* Nothing to do */ +} diff --git a/leapdb.h b/leapdb.h new file mode 100644 index 00000000..eab24141 --- /dev/null +++ b/leapdb.h @@ -0,0 +1,37 @@ +/* + chronyd/chronyc - Programs for keeping computer clocks accurate. + + ********************************************************************** + * Copyright (C) Patrick Oppenlander 2023 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ********************************************************************** + + ======================================================================= + + This module provides leap second information. + + */ + +#ifndef GOT_LEAPDB_H +#define GOT_LEAPDB_H + +#include "ntp.h" + +extern void LDB_Initialise(void); +extern NTP_Leap LDB_GetLeap(time_t when, int *tai_offset); +extern void LDB_Finalise(void); + +#endif /* GOT_LEAPDB_H */ diff --git a/main.c b/main.c index 21d0fe7f..cb240640 100644 --- a/main.c +++ b/main.c @@ -32,6 +32,7 @@ #include "main.h" #include "sched.h" +#include "leapdb.h" #include "local.h" #include "sys.h" #include "ntp_io.h" @@ -134,6 +135,7 @@ MAI_CleanupAndExit(void) RCL_Finalise(); SRC_Finalise(); REF_Finalise(); + LDB_Finalise(); RTC_Finalise(); SYS_Finalise(); @@ -655,6 +657,7 @@ int main if (!geteuid()) LOG(LOGS_WARN, "Running with root privileges"); + LDB_Initialise(); REF_Initialise(); SST_Initialise(); NSR_Initialise(); diff --git a/reference.c b/reference.c index 97dfbe98..1ac6cb93 100644 --- a/reference.c +++ b/reference.c @@ -33,6 +33,7 @@ #include "reference.h" #include "util.h" #include "conf.h" +#include "leapdb.h" #include "logging.h" #include "local.h" #include "sched.h" @@ -122,9 +123,6 @@ static int leap_in_progress; /* Timer for the leap second handler */ static SCH_TimeoutID leap_timeout_id; -/* Name of a system timezone containing leap seconds occuring at midnight */ -static char *leap_tzname; - /* ================================================== */ static LOG_FileID logfileid; @@ -155,7 +153,6 @@ static int ref_adjustments; /* ================================================== */ -static NTP_Leap get_tz_leap(time_t when, int *tai_offset); static void update_leap_status(NTP_Leap leap, time_t now, int reset); /* ================================================== */ @@ -195,7 +192,6 @@ REF_Initialise(void) FILE *in; double file_freq_ppm, file_skew_ppm; double our_frequency_ppm; - int tai_offset; mode = REF_ModeNormal; are_we_synchronised = 0; @@ -260,18 +256,6 @@ REF_Initialise(void) if (leap_mode == REF_LeapModeSystem && !LCL_CanSystemLeap()) leap_mode = REF_LeapModeStep; - leap_tzname = CNF_GetLeapSecTimezone(); - if (leap_tzname) { - /* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */ - if (get_tz_leap(1341014400, &tai_offset) == LEAP_InsertSecond && tai_offset == 34 && - get_tz_leap(1356912000, &tai_offset) == LEAP_Normal && tai_offset == 35) { - LOG(LOGS_INFO, "Using %s timezone to obtain leap second data", leap_tzname); - } else { - LOG(LOGS_WARN, "Timezone %s failed leap second check, ignoring", leap_tzname); - leap_tzname = NULL; - } - } - CNF_GetMakeStep(&make_step_limit, &make_step_threshold); CNF_GetMaxChange(&max_offset_delay, &max_offset_ignore, &max_offset); CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user); @@ -593,77 +577,6 @@ is_leap_second_day(time_t when) /* ================================================== */ -static NTP_Leap -get_tz_leap(time_t when, int *tai_offset) -{ - static time_t last_tz_leap_check; - static NTP_Leap tz_leap; - static int tz_tai_offset; - - struct tm stm, *tm; - time_t t; - char *tz_env, tz_orig[128]; - - *tai_offset = tz_tai_offset; - - /* Do this check at most twice a day */ - when = when / (12 * 3600) * (12 * 3600); - if (last_tz_leap_check == when) - return tz_leap; - - last_tz_leap_check = when; - tz_leap = LEAP_Normal; - tz_tai_offset = 0; - - tm = gmtime(&when); - if (!tm) - return tz_leap; - - stm = *tm; - - /* Temporarily switch to the timezone containing leap seconds */ - tz_env = getenv("TZ"); - if (tz_env) { - if (strlen(tz_env) >= sizeof (tz_orig)) - return tz_leap; - strcpy(tz_orig, tz_env); - } - setenv("TZ", leap_tzname, 1); - tzset(); - - /* Get the TAI-UTC offset, which started at the epoch at 10 seconds */ - t = mktime(&stm); - if (t != -1) - tz_tai_offset = t - when + 10; - - /* Set the time to 23:59:60 and see how it overflows in mktime() */ - stm.tm_sec = 60; - stm.tm_min = 59; - stm.tm_hour = 23; - - t = mktime(&stm); - - if (tz_env) - setenv("TZ", tz_orig, 1); - else - unsetenv("TZ"); - tzset(); - - if (t == -1) - return tz_leap; - - if (stm.tm_sec == 60) - tz_leap = LEAP_InsertSecond; - else if (stm.tm_sec == 1) - tz_leap = LEAP_DeleteSecond; - - *tai_offset = tz_tai_offset; - - return tz_leap; -} - -/* ================================================== */ - static void leap_end_timeout(void *arg) { @@ -751,16 +664,16 @@ set_leap_timeout(time_t now) static void update_leap_status(NTP_Leap leap, time_t now, int reset) { - NTP_Leap tz_leap; + NTP_Leap ldb_leap; int leap_sec, tai_offset; leap_sec = 0; tai_offset = 0; - if (leap_tzname && now) { - tz_leap = get_tz_leap(now, &tai_offset); + if (now) { + ldb_leap = LDB_GetLeap(now, &tai_offset); if (leap == LEAP_Normal) - leap = tz_leap; + leap = ldb_leap; } if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) { @@ -1398,7 +1311,7 @@ REF_GetTaiOffset(struct timespec *ts) { int tai_offset; - get_tz_leap(ts->tv_sec, &tai_offset); + LDB_GetLeap(ts->tv_sec, &tai_offset); return tai_offset; }