]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
refclock: add option to ignore driver initialization errors master
authorMiroslav Lichvar <mlichvar@redhat.com>
Mon, 13 Jul 2026 14:38:00 +0000 (16:38 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Tue, 14 Jul 2026 09:24:20 +0000 (11:24 +0200)
Add "optional" option to the refclock directive to skip the refclock if
it cannot be initialized due to a missing device or feature, etc.

conf.c
doc/chrony.conf.adoc
refclock.c
refclock.h
test/simulation/106-refclock

diff --git a/conf.c b/conf.c
index 01528c4736e585b69fa010fa934f418e8bffae83..7164c9f66c1254282c770976758fd27816f16e75 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -969,12 +969,13 @@ static void
 parse_refclock(char *line)
 {
   int n, poll, dpoll, filter_length, pps_rate, min_samples_, max_samples_, sel_options;
-  int local, max_lock_age, max_unreach, pps_forced, sel_option, stratum, tai;
+  int local, max_lock_age, max_unreach, pps_forced, sel_option, stratum, tai, optional;
   uint32_t ref_id, lock_ref_id;
   double offset, delay, precision, max_dispersion, pulse_width;
   char *p, *cmd, *name, *param;
   RefclockParameters *refclock;
 
+  optional = 0;
   poll = 4;
   dpoll = 0;
   filter_length = 64;
@@ -1054,6 +1055,9 @@ parse_refclock(char *line)
     } else if (!strcasecmp(cmd, "offset")) {
       if (sscanf(line, "%lf%n", &offset, &n) != 1)
         break;
+    } else if (!strcasecmp(cmd, "optional")) {
+      n = 0;
+      optional = 1;
     } else if (!strcasecmp(cmd, "delay")) {
       if (sscanf(line, "%lf%n", &delay, &n) != 1)
         break;
@@ -1094,6 +1098,7 @@ parse_refclock(char *line)
   refclock->driver_parameter = param;
   refclock->driver_poll = dpoll;
   refclock->poll = poll;
+  refclock->optional = optional;
   refclock->filter_length = filter_length;
   refclock->local = local;
   refclock->pps_forced = pps_forced;
index 414c9c51b519b8c6d9a6315bbdb3897c316348b0..3d2efb43d3d3331dcb6a673680aecf7a6057f4be 100644 (file)
@@ -751,6 +751,10 @@ selected for synchronisation when it is unreachable (i.e. no valid sample was
 received in the last 8 polls). Only sources with at least one sample more
 recent than the oldest sample of all reachable sources can be selected.
 The default is 100000.
+*optional*:::
+This option indicates that the refclock device might be missing and *chronyd*
+is allowed to start even if the driver fails to initialise, causing the source
+to be ignored as if it was not specified in the configuration file.
 
 [[manual]]*manual*::
 The *manual* directive enables support at run-time for the
index d73e3c01e079b23387f56d9ddb6178decd03628d..3816d1249dc5b8e9cb17a6213292f2b09c8aa50f 100644 (file)
@@ -151,7 +151,6 @@ RCL_AddRefclock(RefclockParameters *params)
   RCL_Instance inst;
 
   inst = MallocNew(struct RCL_Instance_Record);
-  *(RCL_Instance *)ARR_GetNewElement(refclocks) = inst;
 
   if (strcmp(params->driver_name, "SHM") == 0) {
     inst->driver = &RCL_SHM_driver;
@@ -213,7 +212,7 @@ RCL_AddRefclock(RefclockParameters *params)
     inst->ref_id = params->ref_id;
   else {
     unsigned char ref[5] = { 0, 0, 0, 0, 0 };
-    unsigned int index = ARR_GetSize(refclocks) - 1;
+    unsigned int index = ARR_GetSize(refclocks);
 
     snprintf((char *)ref, sizeof (ref), "%3.3s", params->driver_name);
     ref[3] = index % 10 + '0';
@@ -235,8 +234,13 @@ RCL_AddRefclock(RefclockParameters *params)
       inst->driver_poll = inst->poll;
   }
 
-  if (inst->driver->init && !inst->driver->init(inst))
-    LOG_FATAL("refclock %s initialisation failed", params->driver_name);
+  if (inst->driver->init && !inst->driver->init(inst)) {
+    LOG(params->optional ? LOGS_ERR : LOGS_FATAL, "Could not initialise refclock %s %s",
+        params->driver_name, params->driver_parameter);
+    Free(inst->driver_parameter);
+    Free(inst);
+    return 0;
+  }
 
   /* Don't require more than one sample per poll and combine 60% of the
      samples closest to the median offset */
@@ -250,6 +254,8 @@ RCL_AddRefclock(RefclockParameters *params)
       params->driver_name, UTI_RefidToString(inst->ref_id),
       inst->poll, inst->driver_poll, params->filter_length);
 
+  *(RCL_Instance *)ARR_GetNewElement(refclocks) = inst;
+
   return 1;
 }
 
index 37d1ef382a00874fe2ceb43747435c4fa0135db0..a2228e99e2e73342d26953b532cffb88bba4805d 100644 (file)
@@ -36,6 +36,7 @@ typedef struct {
   char *driver_parameter;
   int driver_poll;
   int poll;
+  int optional;
   int filter_length;
   int local;
   int pps_forced;
index dcbe3812675ab590d271eb5d88ff9f04952c3988..4eca020631c5ef8a9077da639a0e3e6aa401d660 100755 (executable)
@@ -207,4 +207,29 @@ check_file_messages "20.* PHC0 .* - ? " 2499 2501 refclocks.log || test_fail
 check_file_messages "20.* PHC0 " 0 0 tracking.log || test_fail
 rm -f tmp/refclocks.log tmp/tracking.log
 
+reset_test_options
+
+cmdmon_unix=0
+client_conf="
+refclock PHC tmp/nosuch/ptp0 optional
+refclock SOCK tmp/nosuch/sock optional
+"
+num_refclocks=2
+if check_config_h 'FEAT_PPS 1'; then
+       client_conf+="refclock PPS tmp/nosuch/pps optional
+       "
+       num_refclocks=$[num_refclocks + 1]
+fi
+if check_config_h 'FEAT_RTC 1'; then
+       client_conf+="refclock RTC tmp/nosuch/rtc optional
+       "
+       num_refclocks=$[num_refclocks + 1]
+fi
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_sync || test_fail
+check_log_messages "Could not initialise refclock \(PHC\|PPS\|RTC\|SOCK\)" \
+       $num_refclocks $num_refclocks || test_fail
+
 test_pass