]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
conf: add better support for fragmented configuration
authorMiroslav Lichvar <mlichvar@redhat.com>
Thu, 7 May 2020 11:04:26 +0000 (13:04 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 14 May 2020 13:37:38 +0000 (15:37 +0200)
Add a confdirs directive to include *.conf files from multiple
directories. If a file with the same name exists in multiple
directories, only the first one in the order of the specified
directories will be included.

conf.c
doc/chrony.conf.adoc

diff --git a/conf.c b/conf.c
index b32e4ff85d28aec59ec9775453bcf6f2ca01ce7e..bfab31c2e415a4aee75d07ca5cc349ae03ee2c33 100644 (file)
--- a/conf.c
+++ b/conf.c
 #include "cmdparse.h"
 #include "util.h"
 
+/* ================================================== */
+
+#define MAX_LINE_LENGTH 2048
+#define MAX_CONF_DIRS 10
+
 /* ================================================== */
 /* Forward prototypes */
 
@@ -57,6 +62,7 @@ static void parse_bindaddress(char *);
 static void parse_bindcmdaddress(char *);
 static void parse_broadcast(char *);
 static void parse_clientloglimit(char *);
+static void parse_confdirs(char *);
 static void parse_fallbackdrift(char *);
 static void parse_hwtimestamp(char *);
 static void parse_include(char *);
@@ -424,7 +430,7 @@ void
 CNF_ReadFile(const char *filename)
 {
   FILE *in;
-  char line[2048];
+  char line[MAX_LINE_LENGTH];
   int i;
 
   in = UTI_OpenFile(NULL, filename, NULL, 'R', 0);
@@ -486,6 +492,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
                     &cmd_ratelimit_burst, &cmd_ratelimit_leak);
   } else if (!strcasecmp(command, "combinelimit")) {
     parse_double(p, &combine_limit);
+  } else if (!strcasecmp(command, "confdirs")) {
+    parse_confdirs(p);
   } else if (!strcasecmp(command, "corrtimeratio")) {
     parse_double(p, &correction_time_ratio);
   } else if (!strcasecmp(command, "deny")) {
@@ -1407,6 +1415,77 @@ parse_hwtimestamp(char *line)
 
 /* ================================================== */
 
+static const char *
+get_basename(const char *path)
+{
+  const char *b = strrchr(path, '/');
+  return b ? b + 1 : path;
+}
+
+/* ================================================== */
+
+static int
+compare_basenames(const void *a, const void *b)
+{
+  return strcmp(get_basename(*(const char * const *)a),
+                get_basename(*(const char * const *)b));
+}
+
+/* ================================================== */
+
+static void
+parse_confdirs(char *line)
+{
+  char *dirs[MAX_CONF_DIRS], buf[MAX_LINE_LENGTH], *path;
+  size_t i, j, k, locations, n_dirs;
+  glob_t gl;
+
+  n_dirs = UTI_SplitString(line, dirs, MAX_CONF_DIRS);
+  if (n_dirs < 1 || n_dirs > MAX_CONF_DIRS) {
+    command_parse_error();
+    return;
+  }
+
+  /* Get the paths of all config files in the specified directories */
+  for (i = 0; i < n_dirs; i++) {
+    if (snprintf(buf, sizeof (buf), "%s/%s", dirs[i], "*.conf") >= sizeof (buf))
+      assert(0);
+    if (glob(buf, GLOB_NOSORT | (i > 0 ? GLOB_APPEND : 0), NULL, &gl) != 0)
+      ;
+  }
+
+  if (gl.gl_pathc > 0) {
+    /* Sort the paths by filenames */
+    qsort(gl.gl_pathv, gl.gl_pathc, sizeof (gl.gl_pathv[0]), compare_basenames);
+
+    for (i = 0; i < gl.gl_pathc; i += locations) {
+      /* Count directories containing files with this name */
+      for (j = i + 1, locations = 1; j < gl.gl_pathc; j++, locations++) {
+        if (compare_basenames(&gl.gl_pathv[i], &gl.gl_pathv[j]) != 0)
+          break;
+      }
+
+      /* Read the first file of this name in the order of the directive */
+      for (j = 0; j < n_dirs; j++) {
+        for (k = 0; k < locations; k++) {
+          path = gl.gl_pathv[i + k];
+          if (strncmp(path, dirs[j], strlen(dirs[j])) == 0 &&
+              strlen(dirs[j]) + 1 + strlen(get_basename(path)) == strlen(path)) {
+            CNF_ReadFile(path);
+            break;
+          }
+        }
+        if (k < locations)
+          break;
+      }
+    }
+  }
+
+  globfree(&gl);
+}
+
+/* ================================================== */
+
 static void
 parse_include(char *line)
 {
index 462e98f230ec612ea434781ac462b9bf454b260b..8687bc490d10928ec23917d2602a0b1bdb6c8509 100644 (file)
@@ -2121,6 +2121,32 @@ sendmail binary.
 
 === Miscellaneous
 
+[[confdirs]]*confdirs* _directory_...::
+The *confdirs* directive includes configuration files with the _.conf_ suffix
+from up to 10 directories. The files are included in the lexicographical order
+(ignoring the names of the directories). If multiple directories contain a file
+with the same name, only the first file in the order of the specified
+directories will be included. This enables a fragmented configuration, where
+existing fragments can be replaced by adding files to a different directory.
++
+An example of the directive is:
++
+----
+confdirs @SYSCONFDIR@/chrony.d /var/run/chrony.d /usr/lib/chrony.d
+----
+
+[[include]]*include* _pattern_::
+The *include* directive includes a configuration file, or multiple configuration
+files if a wildcard pattern is specified. Unlike with the *confdirs* directive,
+the full name of the files needs to be specified and at least one file is
+required to exist.
++
+An example of the directive is:
++
+----
+include @SYSCONFDIR@/chrony.d/*.conf
+----
+
 [[hwtimestamp]]*hwtimestamp* _interface_ [_option_]...::
 This directive enables hardware timestamping of NTP packets sent to and
 received from the specified network interface. The network interface controller
@@ -2208,17 +2234,6 @@ hwtimestamp eth1 txcomp 300e-9 rxcomp 645e-9
 hwtimestamp *
 ----
 
-[[include]]*include* _pattern_::
-The *include* directive includes a configuration file or multiple configuration
-files if a wildcard pattern is specified. This can be useful when maintaining
-configuration on multiple hosts to keep the differences in separate files.
-+
-An example of the directive is:
-+
-----
-include @SYSCONFDIR@/chrony.d/*.conf
-----
-
 [[keyfile]]*keyfile* _file_::
 This directive is used to specify the location of the file containing symmetric
 keys which are shared between NTP servers and clients, or peers, in order to