diff --git a/.gitignore b/.gitignore index fb24b58..9c42552 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ .vimrc *.o *.swp +*.dSYM +*.DS_Store RELEASES Makefile chrony.conf.5 diff --git a/Makefile.in b/Makefile.in index 557e2f4..a031ba3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -73,12 +73,14 @@ $(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ)) $(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $< distclean : clean + -rm -f .DS_Store -rm -f Makefile -rm -f chrony.conf.5 chrony.texi chronyc.1 chronyd.8 clean : -rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt -rm -rf .deps + -rm -rf *.dSYM getdate.c : bison -o getdate.c getdate.y diff --git a/configure b/configure index b05b32b..d069c65 100755 --- a/configure +++ b/configure @@ -404,6 +404,13 @@ case $SYSTEM in SYSDEFS="" echo "Configuring for $SYSTEM" ;; + Darwin-* ) + EXTRA_OBJECTS="sys_macosx.o" + EXTRA_LIBS="-lresolv" + EXTRA_CLI_LIBS="-lresolv" + add_def MACOSX + echo "Configuring for MacOS X (" $SYSTEM "MacOS X version" $VERSION ")" + ;; SunOS-i86pc* ) # Doug Woodward reported that this configuration # works for Solaris 2.8 / SunOS 5.8 on x86 platforms diff --git a/logging.h b/logging.h index 6dfb774..b4b4d18 100644 --- a/logging.h +++ b/logging.h @@ -94,6 +94,7 @@ typedef enum { LOGF_Sys, LOGF_SysGeneric, LOGF_SysLinux, + LOGF_SysMacOSX, LOGF_SysNetBSD, LOGF_SysSolaris, LOGF_SysSunOS, diff --git a/sys.c b/sys.c index 6b6aff4..f0c81df 100644 --- a/sys.c +++ b/sys.c @@ -46,6 +46,10 @@ #include "sys_netbsd.h" #endif +#if defined (MACOSX) +#include "sys_macosx.h" +#endif + /* ================================================== */ void @@ -68,6 +72,10 @@ SYS_Initialise(void) SYS_NetBSD_Initialise(); #endif +#if defined(MACOSX) + SYS_MacOSX_Initialise(); +#endif + } /* ================================================== */ @@ -91,6 +99,10 @@ SYS_Finalise(void) #if defined(__NetBSD__) SYS_NetBSD_Finalise(); #endif + +#if defined(MACOSX) + SYS_MacOSX_Finalise(); +#endif } /* ================================================== */ diff --git a/sys_macosx.c b/sys_macosx.c new file mode 100644 index 0000000..30945a4 --- /dev/null +++ b/sys_macosx.c @@ -0,0 +1,314 @@ +/* + chronyd/chronyc - Programs for keeping computer clocks accurate. + + ********************************************************************** + * Copyright (C) Richard P. Curnow 1997-2001 + * Copyright (C) J. Hannken-Illjes 2001 + * Copyright (C) Bryan Christianson 2015 + * + * 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. + * + ********************************************************************** + + ======================================================================= + + Driver file for the MacOS X operating system. + + */ + +#include "config.h" + +#ifdef MACOSX + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "sys_macosx.h" +#include "localp.h" +#include "logging.h" +#include "util.h" + +/* ================================================== */ + +/* This register contains the number of seconds by which the local + clock was estimated to be fast of reference time at the epoch when + gettimeofday() returned T0 */ + +static double offset_register; + +/* This register contains the epoch to which the offset is referenced */ + +static struct timeval T0; + +/* This register contains the current estimate of the system + frequency, in absolute (NOT ppm) */ + +static double current_freq; + +/* This register contains the number of seconds of adjustment that + were passed to adjtime last time it was called. */ + +static double adjustment_requested; + +/* Kernel parameters to calculate adjtime error. */ + +static int kern_tickadj; +static long kern_bigadj; + +/* ================================================== */ + +static void +clock_initialise(void) +{ + struct timeval newadj, oldadj; + + offset_register = 0.0; + adjustment_requested = 0.0; + current_freq = 0.0; + + if (gettimeofday(&T0, NULL) < 0) { + LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed"); + } + + newadj.tv_sec = 0; + newadj.tv_usec = 0; + + if (adjtime(&newadj, &oldadj) < 0) { + LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed"); + } +} + +/* ================================================== */ + +static void +clock_finalise(void) +{ + /* Nothing to do yet */ +} + +/* ================================================== */ + +static void +start_adjust(void) +{ + struct timeval newadj, oldadj; + struct timeval T1; + double elapsed, accrued_error; + double adjust_required; + struct timeval exact_newadj; + long delta, tickdelta; + double rounding_error; + double old_adjust_remaining; + + /* Determine the amount of error built up since the last adjustment */ + if (gettimeofday(&T1, NULL) < 0) { + LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed"); + } + + UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0); + accrued_error = elapsed * current_freq; + + adjust_required = - (accrued_error + offset_register); + + UTI_DoubleToTimeval(adjust_required, &exact_newadj); + + /* At this point, we need to round the required adjustment the + same way the kernel does. */ + + delta = exact_newadj.tv_sec * 1000000 + exact_newadj.tv_usec; + if (delta > kern_bigadj || delta < -kern_bigadj) + tickdelta = 10 * kern_tickadj; + else + tickdelta = kern_tickadj; + if (delta % tickdelta) + delta = delta / tickdelta * tickdelta; + newadj.tv_sec = 0; + newadj.tv_usec = (int)delta; + UTI_NormaliseTimeval(&newadj); + + /* Add rounding error back onto offset register. */ + UTI_DiffTimevalsToDouble(&rounding_error, &newadj, &exact_newadj); + + if (adjtime(&newadj, &oldadj) < 0) { + LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed"); + } + + UTI_TimevalToDouble(&oldadj, &old_adjust_remaining); + + offset_register = rounding_error - old_adjust_remaining; + + T0 = T1; + UTI_TimevalToDouble(&newadj, &adjustment_requested); +} + +/* ================================================== */ + +static void +stop_adjust(void) +{ + struct timeval T1; + struct timeval zeroadj, remadj; + double adjustment_remaining, adjustment_achieved; + double elapsed, elapsed_plus_adjust; + + zeroadj.tv_sec = 0; + zeroadj.tv_usec = 0; + + if (adjtime(&zeroadj, &remadj) < 0) { + LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed"); + } + + if (gettimeofday(&T1, NULL) < 0) { + LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed"); + } + + UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0); + UTI_TimevalToDouble(&remadj, &adjustment_remaining); + + adjustment_achieved = adjustment_requested - adjustment_remaining; + elapsed_plus_adjust = elapsed - adjustment_achieved; + + offset_register += current_freq * elapsed_plus_adjust - adjustment_remaining; + + adjustment_requested = 0.0; + T0 = T1; +} + +/* ================================================== */ + +/* Positive offset means system clock is fast of true time, therefore + slew backwards */ + +static void +accrue_offset(double offset, double corr_rate) +{ + stop_adjust(); + offset_register += offset; + start_adjust(); +} + +/* ================================================== */ + +/* Positive offset means system clock is fast of true time, therefore + step backwards */ + +static int +apply_step_offset(double offset) +{ + struct timeval old_time, new_time, T1; + + stop_adjust(); + + if (gettimeofday(&old_time, NULL) < 0) { + LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed"); + } + + UTI_AddDoubleToTimeval(&old_time, -offset, &new_time); + + if (settimeofday(&new_time, NULL) < 0) { + DEBUG_LOG(LOGF_SysMacOSX, "settimeofday() failed"); + return 0; + } + + UTI_AddDoubleToTimeval(&T0, offset, &T1); + T0 = T1; + + start_adjust(); + + return 1; +} + +/* ================================================== */ + +static double +set_frequency(double new_freq_ppm) +{ + stop_adjust(); + current_freq = new_freq_ppm * 1.0e-6; + start_adjust(); + + return current_freq * 1.0e6; +} + +/* ================================================== */ + +static double +read_frequency(void) +{ + return current_freq * 1.0e6; +} + +/* ================================================== */ + +static void +get_offset_correction(struct timeval *raw, + double *corr, double *err) +{ + stop_adjust(); + *corr = -offset_register; + start_adjust(); + if (err) + *err = 0.0; +} + +/* ================================================== */ + +void +SYS_MacOSX_Initialise(void) +{ + int result; + size_t len; + struct clockinfo clockinfo; + int mib[2]; + + mib[0] = CTL_KERN; + mib[1] = KERN_CLOCKRATE; + + len = sizeof(clockinfo); + result = sysctl(mib, 2, &clockinfo, &len, NULL, 0); + + if(result < 0) { + LOG_FATAL(LOGF_SysMacOSX, "Cannot read clockinfo"); + } + kern_tickadj = clockinfo.tickadj; + kern_bigadj = clockinfo.tick; + + clock_initialise(); + + lcl_RegisterSystemDrivers(read_frequency, set_frequency, + accrue_offset, apply_step_offset, + get_offset_correction, + NULL /* set_leap */, + NULL /* set_sync_status */); +} + +/* ================================================== */ + +void +SYS_MacOSX_Finalise(void) +{ + clock_finalise(); +} + +/* ================================================== */ + +#endif diff --git a/sys_macosx.h b/sys_macosx.h new file mode 100644 index 0000000..b579415 --- /dev/null +++ b/sys_macosx.h @@ -0,0 +1,37 @@ +/* + chronyd/chronyc - Programs for keeping computer clocks accurate. + + ********************************************************************** + * Copyright (C) Richard P. Curnow 1997-2001 + * Copyright (C) J. Hannken-Illjes 2001 + * Copyright (C) Bryan Christianson 2015 + * + * 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. + * + ********************************************************************** + + ======================================================================= + + Header file for MacOS X driver + + */ + +#ifndef GOT_SYS_MACOSX_H +#define GOT_SYS_MACOSX_H + +void SYS_MacOSX_Initialise(void); + +void SYS_MacOSX_Finalise(void); + +#endif diff --git a/sysincl.h b/sysincl.h index b0f587c..5c1fb37 100644 --- a/sysincl.h +++ b/sysincl.h @@ -29,9 +29,9 @@ #ifndef GOT_SYSINCL_H #define GOT_SYSINCL_H -#if defined (SOLARIS) || defined(SUNOS) || defined(LINUX) || defined(__NetBSD__) +#if defined (SOLARIS) || defined(SUNOS) || defined(LINUX) || defined(__NetBSD__) || defined (MACOSX) -#if !defined(__NetBSD__) && !defined(__FreeBSD__) +#if !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(MACOSX) #include #endif #include @@ -39,7 +39,7 @@ #include #include #include -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(MACOSX) #include #endif #include