blob: e1b99bb3f07269b1f64631025aed97129bf733e4 [file] [log] [blame]
/*
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