/* chronyd/chronyc - Programs for keeping computer clocks accurate. ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2001 * Copyright (C) J. Hannken-Illjes 2001 * Copyright (C) Miroslav Lichvar 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 NetBSD and FreeBSD operating system. */ #include "config.h" #include "sysincl.h" #include "sys_netbsd.h" #include "sys_timex.h" #include "logging.h" #include "privops.h" #include "util.h" /* Maximum frequency offset accepted by the kernel (in ppm) */ #define MAX_FREQ 500.0 /* Minimum assumed rate at which the kernel updates the clock frequency */ #define MIN_TICK_RATE 100 /* Interval between kernel updates of the adjtime() offset */ #define ADJTIME_UPDATE_INTERVAL 1.0 /* Maximum adjtime() slew rate (in ppm) */ #define MAX_ADJTIME_SLEWRATE 5000.0 /* Minimum offset adjtime() slews faster than MAX_FREQ */ #define MIN_FASTSLEW_OFFSET 1.0 /* ================================================== */ /* Positive offset means system clock is fast of true time, therefore slew backwards */ static void accrue_offset(double offset, double corr_rate) { struct timeval newadj, oldadj; double doldadj; UTI_DoubleToTimeval(-offset, &newadj); if (PRV_AdjustTime(&newadj, &oldadj) < 0) LOG_FATAL("adjtime() failed"); /* Add the old remaining adjustment if not zero */ doldadj = UTI_TimevalToDouble(&oldadj); if (doldadj != 0.0) { UTI_DoubleToTimeval(-offset + doldadj, &newadj); if (PRV_AdjustTime(&newadj, NULL) < 0) LOG_FATAL("adjtime() failed"); } } /* ================================================== */ static void get_offset_correction(struct timespec *raw, double *corr, double *err) { struct timeval remadj; double adjustment_remaining; #ifdef MACOSX struct timeval tv = {0, 0}; if (PRV_AdjustTime(&tv, &remadj) < 0) LOG_FATAL("adjtime() failed"); if (PRV_AdjustTime(&remadj, NULL) < 0) LOG_FATAL("adjtime() failed"); #else if (PRV_AdjustTime(NULL, &remadj) < 0) LOG_FATAL("adjtime() failed"); #endif adjustment_remaining = UTI_TimevalToDouble(&remadj); *corr = adjustment_remaining; if (err) { if (*corr != 0.0) *err = 1.0e-6 * MAX_ADJTIME_SLEWRATE / ADJTIME_UPDATE_INTERVAL; else *err = 0.0; } } /* ================================================== */ void SYS_NetBSD_Initialise(void) { SYS_Timex_InitialiseWithFunctions(MAX_FREQ, 1.0 / MIN_TICK_RATE, NULL, NULL, NULL, MIN_FASTSLEW_OFFSET, MAX_ADJTIME_SLEWRATE, accrue_offset, get_offset_correction); } /* ================================================== */ void SYS_NetBSD_Finalise(void) { SYS_Timex_Finalise(); } /* ================================================== */ #ifdef FEAT_PRIVDROP void SYS_NetBSD_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context, int clock_control) { #ifdef NETBSD int fd; #endif /* On NetBSD the helper is used only for socket binding, but on FreeBSD it's used also for setting and adjusting the system clock */ if (context == SYS_MAIN_PROCESS) PRV_StartHelper(); UTI_DropRoot(uid, gid); #ifdef NETBSD if (!clock_control) return; /* Check if we have write access to /dev/clockctl */ fd = open("/dev/clockctl", O_WRONLY); if (fd < 0) LOG_FATAL("Can't write to /dev/clockctl"); close(fd); #endif } #endif