Move code related to configuration files in directories to new file
authorMichael Paquier <michael@paquier.xyz>
Mon, 7 Nov 2022 03:31:38 +0000 (12:31 +0900)
committerMichael Paquier <michael@paquier.xyz>
Mon, 7 Nov 2022 03:31:38 +0000 (12:31 +0900)
The code in charge of listing and classifying a set of configuration
files in a directory was located in guc-file.l, being used currently for
GUCs under "include_dir".  This code is planned to be used for an
upcoming feature able to include configuration files for ident and HBA
files from a directory, similarly to GUCs.  In both cases, the file
names, suffixed by ".conf", have to be ordered alphabetically.  This
logic is moved to a new file, called conffiles.c, so as it is easier to
share this facility between GUCs and the HBA/ident parsing logic.

Author: Julien Rouhaud, Michael Paquier
Discussion: https://postgr.es/m/Y2IgaH5YzIq2b+iR@paquier.xyz

src/backend/utils/misc/Makefile
src/backend/utils/misc/conffiles.c [new file with mode: 0644]
src/backend/utils/misc/guc-file.l
src/backend/utils/misc/meson.build
src/include/utils/conffiles.h [new file with mode: 0644]

index 60973090331c02da1c06ff21ab09608a35355ded..b9ee4eb48a5ba0f434748fb6389296fa84253be1 100644 (file)
@@ -15,6 +15,7 @@ include $(top_builddir)/src/Makefile.global
 override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
 
 OBJS = \
+       conffiles.o \
        guc.o \
        guc-file.o \
        guc_funcs.o \
diff --git a/src/backend/utils/misc/conffiles.c b/src/backend/utils/misc/conffiles.c
new file mode 100644 (file)
index 0000000..4a99a19
--- /dev/null
@@ -0,0 +1,164 @@
+/*--------------------------------------------------------------------
+ * conffiles.c
+ *
+ * Utilities related to the handling of configuration files.
+ *
+ * This file contains some generic tools to work on configuration files
+ * used by PostgreSQL, be they related to GUCs or authentication.
+ *
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *       src/backend/utils/misc/conffiles.c
+ *
+ *--------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include <dirent.h>
+
+#include "common/file_utils.h"
+#include "miscadmin.h"
+#include "storage/fd.h"
+#include "utils/conffiles.h"
+
+/*
+ * AbsoluteConfigLocation
+ *
+ * Given a configuration file or directory location that may be a relative
+ * path, return an absolute one.  We consider the location to be relative to
+ * the directory holding the calling file, or to DataDir if no calling file.
+ */
+char *
+AbsoluteConfigLocation(const char *location, const char *calling_file)
+{
+       char            abs_path[MAXPGPATH];
+
+       if (is_absolute_path(location))
+               return pstrdup(location);
+       else
+       {
+               if (calling_file != NULL)
+               {
+                       strlcpy(abs_path, calling_file, sizeof(abs_path));
+                       get_parent_directory(abs_path);
+                       join_path_components(abs_path, abs_path, location);
+                       canonicalize_path(abs_path);
+               }
+               else
+               {
+                       Assert(DataDir);
+                       join_path_components(abs_path, DataDir, location);
+                       canonicalize_path(abs_path);
+               }
+               return pstrdup(abs_path);
+       }
+}
+
+
+/*
+ * GetConfFilesInDir
+ *
+ * Returns the list of config files located in a directory, in alphabetical
+ * order.  On error, returns NULL with details about the error stored in
+ * "err_msg".
+ */
+char     **
+GetConfFilesInDir(const char *includedir, const char *calling_file,
+                                 int elevel, int *num_filenames, char **err_msg)
+{
+       char       *directory;
+       DIR                *d;
+       struct dirent *de;
+       char      **filenames = NULL;
+       int                     size_filenames;
+
+       /*
+        * Reject directory name that is all-blank (including empty), as that
+        * leads to confusion --- we'd read the containing directory, typically
+        * resulting in recursive inclusion of the same file(s).
+        */
+       if (strspn(includedir, " \t\r\n") == strlen(includedir))
+       {
+               ereport(elevel,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("empty configuration directory name: \"%s\"",
+                                               includedir)));
+               *err_msg = "empty configuration directory name";
+               return NULL;
+       }
+
+       directory = AbsoluteConfigLocation(includedir, calling_file);
+       d = AllocateDir(directory);
+       if (d == NULL)
+       {
+               ereport(elevel,
+                               (errcode_for_file_access(),
+                                errmsg("could not open configuration directory \"%s\": %m",
+                                               directory)));
+               *err_msg = psprintf("could not open directory \"%s\"", directory);
+               goto cleanup;
+       }
+
+       /*
+        * Read the directory and put the filenames in an array, so we can sort
+        * them prior to caller processing the contents.
+        */
+       size_filenames = 32;
+       filenames = (char **) palloc(size_filenames * sizeof(char *));
+       *num_filenames = 0;
+
+       while ((de = ReadDir(d, directory)) != NULL)
+       {
+               PGFileType      de_type;
+               char            filename[MAXPGPATH];
+
+               /*
+                * Only parse files with names ending in ".conf".  Explicitly reject
+                * files starting with ".".  This excludes things like "." and "..",
+                * as well as typical hidden files, backup files, and editor debris.
+                */
+               if (strlen(de->d_name) < 6)
+                       continue;
+               if (de->d_name[0] == '.')
+                       continue;
+               if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0)
+                       continue;
+
+               join_path_components(filename, directory, de->d_name);
+               canonicalize_path(filename);
+               de_type = get_dirent_type(filename, de, true, elevel);
+               if (de_type == PGFILETYPE_ERROR)
+               {
+                       *err_msg = psprintf("could not stat file \"%s\"", filename);
+                       pfree(filenames);
+                       filenames = NULL;
+                       goto cleanup;
+               }
+               else if (de_type != PGFILETYPE_DIR)
+               {
+                       /* Add file to array, increasing its size in blocks of 32 */
+                       if (*num_filenames >= size_filenames)
+                       {
+                               size_filenames += 32;
+                               filenames = (char **) repalloc(filenames,
+                                                                                          size_filenames * sizeof(char *));
+                       }
+                       filenames[*num_filenames] = pstrdup(filename);
+                       (*num_filenames)++;
+               }
+       }
+
+       /* Sort the files by name before leaving */
+       if (*num_filenames > 0)
+               qsort(filenames, *num_filenames, sizeof(char *), pg_qsort_strcmp);
+
+cleanup:
+       if (d)
+               FreeDir(d);
+       pfree(directory);
+       return filenames;
+}
index 2aa48ec9697cc7a276082d634bd19d249c407873..88245475d1c8c836f10efbaaabb8a85905278e08 100644 (file)
@@ -17,6 +17,7 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "storage/fd.h"
+#include "utils/conffiles.h"
 #include "utils/memutils.h"
 }
 
@@ -155,37 +156,6 @@ ProcessConfigFile(GucContext context)
        MemoryContextDelete(config_cxt);
 }
 
-/*
- * Given a configuration file or directory location that may be a relative
- * path, return an absolute one.  We consider the location to be relative to
- * the directory holding the calling file, or to DataDir if no calling file.
- */
-static char *
-AbsoluteConfigLocation(const char *location, const char *calling_file)
-{
-       char            abs_path[MAXPGPATH];
-
-       if (is_absolute_path(location))
-               return pstrdup(location);
-       else
-       {
-               if (calling_file != NULL)
-               {
-                       strlcpy(abs_path, calling_file, sizeof(abs_path));
-                       get_parent_directory(abs_path);
-                       join_path_components(abs_path, abs_path, location);
-                       canonicalize_path(abs_path);
-               }
-               else
-               {
-                       Assert(DataDir);
-                       join_path_components(abs_path, DataDir, location);
-                       canonicalize_path(abs_path);
-               }
-               return pstrdup(abs_path);
-       }
-}
-
 /*
  * Read and parse a single configuration file.  This function recurses
  * to handle "include" directives.
@@ -605,127 +575,30 @@ ParseConfigDirectory(const char *includedir,
                                         ConfigVariable **head_p,
                                         ConfigVariable **tail_p)
 {
-       char       *directory;
-       DIR                *d;
-       struct dirent *de;
+       char       *err_msg;
        char      **filenames;
        int                     num_filenames;
-       int                     size_filenames;
-       bool            status;
-
-       /*
-        * Reject directory name that is all-blank (including empty), as that
-        * leads to confusion --- we'd read the containing directory, typically
-        * resulting in recursive inclusion of the same file(s).
-        */
-       if (strspn(includedir, " \t\r\n") == strlen(includedir))
-       {
-               ereport(elevel,
-                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                errmsg("empty configuration directory name: \"%s\"",
-                                               includedir)));
-               record_config_file_error("empty configuration directory name",
-                                                                calling_file, calling_lineno,
-                                                                head_p, tail_p);
-               return false;
-       }
-
-       /*
-        * We don't check for recursion or too-deep nesting depth here; the
-        * subsequent calls to ParseConfigFile will take care of that.
-        */
-
-       directory = AbsoluteConfigLocation(includedir, calling_file);
-       d = AllocateDir(directory);
-       if (d == NULL)
-       {
-               ereport(elevel,
-                               (errcode_for_file_access(),
-                                errmsg("could not open configuration directory \"%s\": %m",
-                                               directory)));
-               record_config_file_error(psprintf("could not open directory \"%s\"",
-                                                                                 directory),
-                                                                calling_file, calling_lineno,
-                                                                head_p, tail_p);
-               status = false;
-               goto cleanup;
-       }
 
-       /*
-        * Read the directory and put the filenames in an array, so we can sort
-        * them prior to processing the contents.
-        */
-       size_filenames = 32;
-       filenames = (char **) palloc(size_filenames * sizeof(char *));
-       num_filenames = 0;
+       filenames = GetConfFilesInDir(includedir, calling_file, elevel,
+                                                          &num_filenames, &err_msg);
 
-       while ((de = ReadDir(d, directory)) != NULL)
+       if (!filenames)
        {
-               PGFileType      de_type;
-               char            filename[MAXPGPATH];
-
-               /*
-                * Only parse files with names ending in ".conf".  Explicitly reject
-                * files starting with ".".  This excludes things like "." and "..",
-                * as well as typical hidden files, backup files, and editor debris.
-                */
-               if (strlen(de->d_name) < 6)
-                       continue;
-               if (de->d_name[0] == '.')
-                       continue;
-               if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0)
-                       continue;
-
-               join_path_components(filename, directory, de->d_name);
-               canonicalize_path(filename);
-               de_type = get_dirent_type(filename, de, true, elevel);
-               if (de_type == PGFILETYPE_ERROR)
-               {
-                       record_config_file_error(psprintf("could not stat file \"%s\"",
-                                                                                         filename),
-                                                                        calling_file, calling_lineno,
-                                                                        head_p, tail_p);
-                       status = false;
-                       goto cleanup;
-               }
-               else if (de_type != PGFILETYPE_DIR)
-               {
-                       /* Add file to array, increasing its size in blocks of 32 */
-                       if (num_filenames >= size_filenames)
-                       {
-                               size_filenames += 32;
-                               filenames = (char **) repalloc(filenames,
-                                                                                          size_filenames * sizeof(char *));
-                       }
-                       filenames[num_filenames] = pstrdup(filename);
-                       num_filenames++;
-               }
+               record_config_file_error(err_msg, calling_file, calling_lineno, head_p,
+                                                                tail_p);
+               return false;
        }
 
-       if (num_filenames > 0)
+       for (int i = 0; i < num_filenames; i++)
        {
-               int                     i;
-
-               qsort(filenames, num_filenames, sizeof(char *), pg_qsort_strcmp);
-               for (i = 0; i < num_filenames; i++)
-               {
-                       if (!ParseConfigFile(filenames[i], true,
-                                                                calling_file, calling_lineno,
-                                                                depth, elevel,
-                                                                head_p, tail_p))
-                       {
-                               status = false;
-                               goto cleanup;
-                       }
-               }
+               if (!ParseConfigFile(filenames[i], true,
+                                                        calling_file, calling_lineno,
+                                                        depth, elevel,
+                                                        head_p, tail_p))
+                       return false;
        }
-       status = true;
 
-cleanup:
-       if (d)
-               FreeDir(d);
-       pfree(directory);
-       return status;
+       return true;
 }
 
 /*
index db4de225e181696d0b88b62cfaf6342aba16138c..e7a9730229d3fd94c972de6842c6619ba4153825 100644 (file)
@@ -1,4 +1,5 @@
 backend_sources += files(
+  'conffiles.c',
   'guc.c',
   'guc_funcs.c',
   'guc_tables.c',
diff --git a/src/include/utils/conffiles.h b/src/include/utils/conffiles.h
new file mode 100644 (file)
index 0000000..3f23a2a
--- /dev/null
@@ -0,0 +1,23 @@
+/*--------------------------------------------------------------------
+ * conffiles.h
+ *
+ * Utilities related to configuration files.
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/utils/conffiles.h
+ *
+ *--------------------------------------------------------------------
+ */
+#ifndef CONFFILES_H
+#define CONFFILES_H
+
+extern char *AbsoluteConfigLocation(const char *location,
+                                                                       const char *calling_file);
+extern char **GetConfFilesInDir(const char *includedir,
+                                                               const char *calling_file,
+                                                               int elevel, int *num_filenames,
+                                                               char **err_msg);
+
+#endif                                                 /* CONFFILES_H */