* rtcdevice directive:: Specify name of enhanced RTC device (if not /dev/rtc)
* rtcfile directive:: Specify the file where real-time clock data is stored
* rtconutc directive:: Specify that the real time clock keeps UTC not local time
+* rtcsync directive:: Specify that RTC should be automatically synchronised by kernel
* server directive:: Specify an NTP server
* sched_priority directive:: Require real-time scheduling and specify a priority for it.
* lock_all directive:: Require that chronyd be locked into RAM.
to keep UTC. The directive takes no arguments. It is equivalent to
specifying the @code{-u} switch to the Linux @file{/sbin/clock} program.
@c }}}
+@c {{{ rtcsync
+@node rtcsync directive
+@subsection rtcsync
+
+The @code{rtcsync} directive will enable a kernel mode where the
+system time is copied to the real time clock (RTC) every 11 minutes.
+
+This directive is supported only on Linux and cannot be used when the
+normal RTC tracking is enabled, i.e. when the @code{rtcfile} directive
+is used.
+@c }}}
@c {{{ sched_priority
@node sched_priority directive
@subsection sched_priority
};
#define ADJ_FREQUENCY 0x0002 /* frequency offset */
+#define ADJ_MAXERROR 0x0004 /* maximum time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
static void parse_cmddeny(const char *);
static void parse_cmdport(const char *);
static void parse_rtconutc(const char *);
+static void parse_rtcsync(const char *);
static void parse_noclientlog(const char *);
static void parse_clientloglimit(const char *);
static void parse_fallbackdrift(const char *);
incl. daylight saving). */
static int rtc_on_utc = 0;
+/* Flag set if the RTC should be automatically synchronised by kernel */
+static int rtc_sync = 0;
+
/* Limit and threshold for clock stepping */
static int make_step_limit = 0;
static double make_step_threshold = 0.0;
{"cmddeny", 7, parse_cmddeny},
{"cmdport", 7, parse_cmdport},
{"rtconutc", 8, parse_rtconutc},
+ {"rtcsync", 7, parse_rtcsync},
{"noclientlog", 11, parse_noclientlog},
{"clientloglimit", 14, parse_clientloglimit},
{"fallbackdrift", 13, parse_fallbackdrift},
/* ================================================== */
+static void
+parse_rtcsync(const char *line)
+{
+ rtc_sync = 1;
+}
+
+/* ================================================== */
+
static void
parse_noclientlog(const char *line)
{
/* ================================================== */
+int
+CNF_GetRTCSync(void)
+{
+ return rtc_sync;
+}
+
+/* ================================================== */
+
void
CNF_GetMakeStep(int *limit, double *threshold)
{
extern int CNF_GetManualEnabled(void);
extern int CNF_GetCommandPort(void);
extern int CNF_GetRTCOnUTC(void);
+extern int CNF_GetRTCSync(void);
extern void CNF_GetMakeStep(int *limit, double *threshold);
extern void CNF_GetLogChange(int *enabled, double *threshold);
extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
file_name = CNF_GetRtcFile();
if (file_name) {
+ if (CNF_GetRTCSync()) {
+ LOG_FATAL(LOGF_Rtc, "rtcfile directive cannot be used with rtcsync");
+ }
+
if (driver.init) {
if ((driver.init)()) {
ok = 1;
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction, set_leap);
+
+ TMX_SetSync(CNF_GetRTCSync());
}
/* ================================================== */
#include "chrony_timex.h"
#include "wrap_adjtimex.h"
-/* Save leap status between calls */
-static int leap_status = 0;
+static int status = 0;
int
TMX_SetTick(long tick)
txc.freq = (long)(*freq * (double)(1 << SHIFT_USEC));
*freq = txc.freq / (double)(1 << SHIFT_USEC);
txc.tick = tick;
- txc.status = STA_UNSYNC; /* Prevent any of the FLL/PLL stuff coming
- up */
- txc.status |= leap_status; /* Preserve leap bits */
+
+ /* Prevent any of the FLL/PLL stuff coming up */
+ txc.status = status;
+
+ if (!(status & STA_UNSYNC)) {
+ /* maxerror has to be reset periodically to prevent kernel
+ from enabling UNSYNC flag */
+ txc.modes |= ADJ_MAXERROR;
+ txc.maxerror = 0;
+ }
return adjtimex(&txc);
}
{
struct timex txc;
+ status &= ~(STA_INS | STA_DEL);
+
if (leap > 0) {
- leap_status = STA_INS;
+ status |= STA_INS;
} else if (leap < 0) {
- leap_status = STA_DEL;
- } else {
- leap_status = 0;
+ status |= STA_DEL;
}
txc.modes = ADJ_STATUS;
- txc.status = STA_UNSYNC | leap_status;
+ txc.status = status;
+
+ return adjtimex(&txc);
+}
+
+int TMX_SetSync(int sync)
+{
+ struct timex txc;
+
+ if (sync) {
+ status &= ~STA_UNSYNC;
+ } else {
+ status |= STA_UNSYNC;
+ }
+
+ txc.modes = ADJ_STATUS;
+ txc.status = status;
return adjtimex(&txc);
}
int TMX_GetOffsetLeft(long *offset);
int TMX_ReadCurrentParams(struct tmx_params *params);
int TMX_SetLeap(int leap);
+int TMX_SetSync(int sync);
#endif /* GOT_WRAP_ADJTIMEX_H */