gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet] 02/02: config: extended diagnostics, import cycle detection, d


From: gnunet
Subject: [gnunet] 02/02: config: extended diagnostics, import cycle detection, deterministic load order
Date: Wed, 28 Jul 2021 20:23:01 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository gnunet.

commit 346706b1857dd9ec129cf40897468133f3c6bdd3
Author: Florian Dold <florian@dold.me>
AuthorDate: Wed Jul 28 20:19:38 2021 +0200

    config: extended diagnostics, import cycle detection, deterministic load 
order
---
 src/util/Makefile.am            |   1 -
 src/util/configuration.c        | 297 +++++++++++++++++++++++++++++++++-------
 src/util/configuration_loader.c |  91 ------------
 src/util/disk.c                 |  13 +-
 4 files changed, 257 insertions(+), 145 deletions(-)

diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index e720112be..37eb0508b 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -49,7 +49,6 @@ libgnunetutil_la_SOURCES = \
   common_endian.c \
   common_logging.c \
   configuration.c \
-  configuration_loader.c \
   consttime_memcmp.c \
   container_bloomfilter.c \
   container_heap.c \
diff --git a/src/util/configuration.c b/src/util/configuration.c
index fffe08788..cc71a239d 100644
--- a/src/util/configuration.c
+++ b/src/util/configuration.c
@@ -29,6 +29,7 @@
 #include "gnunet_configuration_lib.h"
 #include "gnunet_disk_lib.h"
 #include "gnunet_buffer_lib.h"
+#include "gnunet_container_lib.h"
 
 #define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
@@ -111,6 +112,23 @@ struct ConfigSection
   unsigned int hint_inlined_from_line;
 };
 
+struct ConfigFile
+{
+  /**
+   * Source filename.
+   */
+  char *source_filename;
+
+  /**
+   * Level in the tree of loaded config files.
+   */
+  unsigned int level;
+
+  struct ConfigFile *prev;
+
+  struct ConfigFile *next;
+};
+
 
 /**
  * @brief configuration data
@@ -122,6 +140,21 @@ struct GNUNET_CONFIGURATION_Handle
    */
   struct ConfigSection *sections;
 
+  /**
+   * Linked list of loaded files.
+   */
+  struct ConfigFile *loaded_files_head;
+
+  /**
+   * Linked list of loaded files.
+   */
+  struct ConfigFile *loaded_files_tail;
+
+  /**
+   * Current nesting level of file loading.
+   */
+  unsigned int current_nest_level;
+
   /**
    * Enable diagnostics.
    */
@@ -134,6 +167,11 @@ struct GNUNET_CONFIGURATION_Handle
    */
   enum GNUNET_GenericReturnValue dirty;
 
+  /**
+   * Was the configuration ever loaded via GNUNET_CONFIGURATION_load?
+   */
+  bool load_called;
+
   /**
    * Name of the entry point configuration file.
    */
@@ -250,9 +288,14 @@ void
 GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   struct ConfigSection *sec;
+  struct ConfigFile *cf;
 
   while (NULL != (sec = cfg->sections))
     GNUNET_CONFIGURATION_remove_section (cfg, sec->name);
+  while (NULL != (cf = cfg->loaded_files_head))
+    GNUNET_CONTAINER_DLL_remove (cfg->loaded_files_head,
+                                 cfg->loaded_files_tail,
+                                 cf);
   GNUNET_free (cfg);
 }
 
@@ -279,9 +322,9 @@ GNUNET_CONFIGURATION_parse_and_run (const char *filename,
 
 
 /**
- * Closure to inline_glob_cb.
+ * Closure to collect_files_cb.
  */
-struct InlineGlobClosure
+struct CollectFilesContext
 {
   /**
    * Collected files from globbing.
@@ -305,14 +348,10 @@ struct InlineGlobClosure
  *  #GNUNET_SYSERR to abort iteration with error!
  */
 static int
-inline_glob_cb (void *cls,
-                const char *filename)
+collect_files_cb (void *cls,
+                  const char *filename)
 {
-  struct InlineGlobClosure *igc = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Found globbed config file '%s'\n",
-       filename);
+  struct CollectFilesContext *igc = cls;
 
   GNUNET_array_append (igc->files,
                        igc->files_length,
@@ -363,11 +402,12 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
 {
   char *inline_path;
   struct GNUNET_CONFIGURATION_Handle *other_cfg = NULL;
-  struct InlineGlobClosure igc = {
+  struct CollectFilesContext igc = {
     .files = NULL,
     .files_length = 0,
   };
   enum GNUNET_GenericReturnValue fun_ret;
+  unsigned int old_nest_level = cfg->current_nest_level++;
 
   /* We support the section restriction only for non-globs */
   GNUNET_assert (! (path_is_glob && (NULL != restrict_section)));
@@ -419,7 +459,7 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
          "processing config glob '%s'\n",
          inline_path);
 
-    nret = GNUNET_DISK_glob (inline_path, inline_glob_cb, &igc);
+    nret = GNUNET_DISK_glob (inline_path, collect_files_cb, &igc);
     if (-1 == nret)
     {
       fun_ret = GNUNET_SYSERR;
@@ -441,10 +481,10 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
   }
   else if (NULL != restrict_section)
   {
-    enum GNUNET_GenericReturnValue fret;
+    enum GNUNET_GenericReturnValue inner_ret;
     struct ConfigSection *cs;
 
-    fret = GNUNET_DISK_file_test_read (inline_path);
+    inner_ret = GNUNET_DISK_file_test_read (inline_path);
 
     cs = find_section (cfg, restrict_section);
 
@@ -467,7 +507,7 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
       }
     }
 
-    if (GNUNET_OK != fret)
+    if (GNUNET_OK != inner_ret)
     {
       cs->inaccessible = true;
       fun_ret = GNUNET_OK;
@@ -475,10 +515,11 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
     }
 
     other_cfg = GNUNET_CONFIGURATION_create ();
-    if (GNUNET_OK != GNUNET_CONFIGURATION_parse (other_cfg,
-                                                 inline_path))
+    inner_ret = GNUNET_CONFIGURATION_parse (other_cfg,
+                                            inline_path);
+    if (GNUNET_OK != inner_ret)
     {
-      fun_ret = GNUNET_SYSERR;
+      fun_ret = inner_ret;
       goto cleanup;
     }
 
@@ -513,6 +554,7 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
     fun_ret = GNUNET_OK;
   }
   cleanup:
+  cfg->current_nest_level = old_nest_level;
   if (NULL != other_cfg)
     GNUNET_CONFIGURATION_destroy (other_cfg);
   GNUNET_free (inline_path);
@@ -756,11 +798,7 @@ GNUNET_CONFIGURATION_deserialize (struct 
GNUNET_CONFIGURATION_Handle *cfg,
       }
       if (GNUNET_OK != directive_ret)
       {
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             _ ("Bad directive '%s' in line %u\n"),
-             directive,
-             nr);
-        ret = GNUNET_SYSERR;
+        ret = directive_ret;
         break;
       }
       continue;
@@ -845,6 +883,55 @@ GNUNET_CONFIGURATION_parse (struct 
GNUNET_CONFIGURATION_Handle *cfg,
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to parse config file `%s'\n", fn);
   if (NULL == fn)
     return GNUNET_SYSERR;
+
+
+  /* Check for cycles */
+  {
+    unsigned int lvl = cfg->current_nest_level;
+    struct ConfigFile *cf = cfg->loaded_files_tail;
+    struct ConfigFile *parent = NULL;
+
+
+    for (; NULL != cf; parent = cf, cf = cf->prev)
+    {
+      /* Check parents based on level, skipping children of siblings. */
+      if (cf->level >= lvl)
+        continue;
+      lvl = cf->level;
+      if ( (NULL == cf->source_filename) || (NULL == filename))
+        continue;
+      if (0 == strcmp (cf->source_filename, filename))
+      {
+        if (NULL == parent)
+        {
+          LOG (GNUNET_ERROR_TYPE_ERROR,
+               "Forbidden direct cyclic configuration import (%s -> %s)\n",
+               cf->source_filename,
+               filename);
+        }
+        else
+          LOG (GNUNET_ERROR_TYPE_ERROR,
+               "Forbidden indirect cyclic configuration import (%s -> ... -> 
%s -> %s)\n",
+               cf->source_filename,
+               parent->source_filename,
+               filename);
+        return GNUNET_SYSERR;
+      }
+    }
+
+  }
+
+  /* Keep track of loaded files.*/
+  {
+    struct ConfigFile *cf = GNUNET_new (struct ConfigFile);
+
+    cf->level = cfg->current_nest_level;
+    cf->source_filename = GNUNET_strdup (filename ? filename : "<input>");
+    GNUNET_CONTAINER_DLL_insert_tail (cfg->loaded_files_head,
+                                      cfg->loaded_files_tail,
+                                      cf);
+  }
+
   dirty = cfg->dirty; /* back up value! */
   if (GNUNET_SYSERR ==
       GNUNET_DISK_file_size (fn, &fs64, GNUNET_YES, GNUNET_YES))
@@ -876,7 +963,7 @@ GNUNET_CONFIGURATION_parse (struct 
GNUNET_CONFIGURATION_Handle *cfg,
                                           mem,
                                           fs,
                                           fn);
-  if (GNUNET_OK != ret)
+  if (GNUNET_SYSERR == ret)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 _ ("Failed to parse configuration file `%s'\n"),
@@ -1036,6 +1123,36 @@ GNUNET_CONFIGURATION_serialize_diagnostics (const struct
 {
   struct GNUNET_Buffer buf = { 0 };
 
+  GNUNET_buffer_write_fstr (&buf,
+                            "#\n# Configuration file diagnostics\n#\n");
+  GNUNET_buffer_write_fstr (&buf,
+                            "# Entry point: %s\n",
+                            cfg->main_filename ? cfg->main_filename :
+                            "<input>");
+  GNUNET_buffer_write_fstr (&buf,
+                            "#\n# Files Loaded:\n");
+
+  for (struct ConfigFile *cfil = cfg->loaded_files_head;
+       NULL != cfil;
+       cfil = cfil->next)
+  {
+    GNUNET_buffer_write_fstr (&buf,
+                              "# ");
+    for (unsigned int i = 0; i < cfil->level; i++)
+      GNUNET_buffer_write_fstr (&buf,
+                                "+");
+    if (0 != cfil->level)
+      GNUNET_buffer_write_fstr (&buf,
+                                " ");
+
+    GNUNET_buffer_write_fstr (&buf,
+                              "%s\n",
+                              cfil->source_filename);
+  }
+
+  GNUNET_buffer_write_fstr (&buf,
+                            "#\n\n");
+
   for (struct ConfigSection *sec = cfg->sections;
        NULL != sec;
        sec = sec->next)
@@ -2059,41 +2176,51 @@ GNUNET_CONFIGURATION_remove_value_filename (
 }
 
 
-/**
- * Wrapper around #GNUNET_CONFIGURATION_parse.  Called on each
- * file in a directory, we trigger parsing on those files that
- * end with ".conf".
- *
- * @param cls the cfg
- * @param filename file to parse
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-parse_configuration_file (void *cls, const char *filename)
-{
-  struct GNUNET_CONFIGURATION_Handle *cfg = cls;
-  char *ext;
-
-  /* Examine file extension */
-  ext = strrchr (filename, '.');
-  if ((NULL == ext) || (0 != strcmp (ext, ".conf")))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename);
-    return GNUNET_OK;
-  }
-
-  return GNUNET_CONFIGURATION_parse (cfg, filename);
-}
-
-
 enum GNUNET_GenericReturnValue
 GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg,
                                 const char *defaults_d)
 {
+  struct CollectFilesContext files_context = {
+    .files = NULL,
+    .files_length = 0,
+  };
+  enum GNUNET_GenericReturnValue fun_ret;
+
   if (GNUNET_SYSERR ==
-      GNUNET_DISK_directory_scan (defaults_d, &parse_configuration_file, cfg))
+      GNUNET_DISK_directory_scan (defaults_d, &collect_files_cb,
+                                  &files_context))
     return GNUNET_SYSERR; /* no configuration at all found */
-  return GNUNET_OK;
+  qsort (files_context.files,
+         files_context.files_length,
+         sizeof (char *),
+         pstrcmp);
+  for (unsigned int i = 0; i < files_context.files_length; i++)
+  {
+    char *ext;
+    const char *filename = files_context.files[i];
+
+    /* Examine file extension */
+    ext = strrchr (filename, '.');
+    if ((NULL == ext) || (0 != strcmp (ext, ".conf")))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename);
+      fun_ret = GNUNET_OK;
+      goto cleanup;
+    }
+    fun_ret = GNUNET_CONFIGURATION_parse (cfg, filename);
+    if (fun_ret != GNUNET_OK)
+      break;
+  }
+  cleanup:
+  if (files_context.files_length > 0)
+  {
+    for (size_t i = 0; i < files_context.files_length; i++)
+      GNUNET_free (files_context.files[i]);
+    GNUNET_array_grow (files_context.files,
+                       files_context.files_length,
+                       0);
+  }
+  return fun_ret;
 }
 
 
@@ -2158,5 +2285,71 @@ GNUNET_CONFIGURATION_default (void)
   return cfg;
 }
 
+/**
+ * Load configuration (starts with defaults, then loads
+ * system-specific configuration).
+ *
+ * @param cfg configuration to update
+ * @param filename name of the configuration file, NULL to load defaults
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
+                           const char *filename)
+{
+  char *baseconfig;
+  const char *base_config_varname;
+
+  if (cfg->load_called)
+  {
+    /* FIXME:  Make this a GNUNET_assert later */
+    GNUNET_break (0);
+    GNUNET_free (cfg->main_filename);
+  }
+  cfg->load_called = true;
+  if (NULL != filename)
+    cfg->main_filename = GNUNET_strdup (filename);
+
+  base_config_varname = GNUNET_OS_project_data_get ()->base_config_varname;
+
+  if ((NULL != base_config_varname)
+      && (NULL != (baseconfig = getenv (base_config_varname))))
+  {
+    baseconfig = GNUNET_strdup (baseconfig);
+  }
+  else
+  {
+    char *ipath;
+
+    ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
+    if (NULL == ipath)
+      return GNUNET_SYSERR;
+    GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d");
+    GNUNET_free (ipath);
+  }
+
+  char *dname = GNUNET_STRINGS_filename_expand (baseconfig);
+  GNUNET_free (baseconfig);
+
+  if ((GNUNET_YES == GNUNET_DISK_directory_test (dname, GNUNET_YES))&&
+      (GNUNET_SYSERR == GNUNET_CONFIGURATION_load_from (cfg, dname)))
+  {
+    GNUNET_free (dname);
+    return GNUNET_SYSERR;       /* no configuration at all found */
+  }
+  GNUNET_free (dname);
+  if ((NULL != filename) &&
+      (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)))
+  {
+    /* specified configuration not found */
+    return GNUNET_SYSERR;
+  }
+  if (((GNUNET_YES !=
+        GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
+      (filename != NULL))
+    GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
+                                           filename);
+  return GNUNET_OK;
+}
 
 /* end of configuration.c */
diff --git a/src/util/configuration_loader.c b/src/util/configuration_loader.c
deleted file mode 100644
index a59477b25..000000000
--- a/src/util/configuration_loader.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2006, 2007, 2008, 2009, 2013 GNUnet e.V.
-
-     GNUnet is free software: you can redistribute it and/or modify it
-     under the terms of the GNU Affero General Public License as published
-     by the Free Software Foundation, either version 3 of the License,
-     or (at your option) any later version.
-
-     GNUnet 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
-     Affero General Public License for more details.
-
-     You should have received a copy of the GNU Affero General Public License
-     along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-     SPDX-License-Identifier: AGPL3.0-or-later
- */
-
-/**
- * @file src/util/configuration_loader.c
- * @brief configuration loading
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define LOG(kind, ...) GNUNET_log_from (kind, "util-configuration", 
__VA_ARGS__)
-
-
-/**
- * Load configuration (starts with defaults, then loads
- * system-specific configuration).
- *
- * @param cfg configuration to update
- * @param filename name of the configuration file, NULL to load defaults
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-int
-GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
-                           const char *filename)
-{
-  char *baseconfig;
-  const char *base_config_varname;
-
-  base_config_varname = GNUNET_OS_project_data_get ()->base_config_varname;
-
-  if (NULL != base_config_varname
-      && NULL != (baseconfig = getenv (base_config_varname)))
-  {
-    baseconfig = GNUNET_strdup (baseconfig);
-  }
-  else
-  {
-    char *ipath;
-
-    ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
-    if (NULL == ipath)
-      return GNUNET_SYSERR;
-    GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d");
-    GNUNET_free (ipath);
-  }
-
-  char *dname = GNUNET_STRINGS_filename_expand (baseconfig);
-  GNUNET_free (baseconfig);
-
-  if (GNUNET_YES == GNUNET_DISK_directory_test (dname, GNUNET_YES) &&
-      GNUNET_SYSERR == GNUNET_CONFIGURATION_load_from (cfg, dname))
-  {
-    GNUNET_free (dname);
-    return GNUNET_SYSERR;       /* no configuration at all found */
-  }
-  GNUNET_free (dname);
-  if ((NULL != filename) &&
-      (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)))
-  {
-    /* specified configuration not found */
-    return GNUNET_SYSERR;
-  }
-  if (((GNUNET_YES !=
-        GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
-      (filename != NULL))
-    GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
-                                           filename);
-  return GNUNET_OK;
-}
-
-
-/* end of configuration_loader.c */
diff --git a/src/util/disk.c b/src/util/disk.c
index f68b32db5..1b6934082 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -434,7 +434,7 @@ GNUNET_DISK_directory_test (const char *fil, int 
is_readable)
 
 /**
  * Check if fil can be accessed using amode.
- * 
+ *
  * @param fil file to check for
  * @param amode access mode
  * @returns GNUnet error code
@@ -1002,6 +1002,17 @@ GNUNET_DISK_glob (const char *glob_pattern,
   char *sep;
   int ret;
 
+  if ( (NULL != strrchr (glob_pattern, '+')) ||
+       (NULL != strrchr (glob_pattern, '[')) ||
+       (NULL != strrchr (glob_pattern, '+')) ||
+       (NULL != strrchr (glob_pattern, '~')) )
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         "unsupported glob pattern: '%s'\n",
+         glob_pattern);
+    return -1;
+  }
+
   sep = strrchr (mypat, DIR_SEPARATOR);
   if (NULL == sep)
   {

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]