LCOV - code coverage report
Current view: top level - src/backend/utils/misc - conffiles.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 74.1 % 54 40
Test Date: 2026-03-03 04:14:52 Functions: 100.0 % 2 2
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*--------------------------------------------------------------------
       2              :  * conffiles.c
       3              :  *
       4              :  * Utilities related to the handling of configuration files.
       5              :  *
       6              :  * This file contains some generic tools to work on configuration files
       7              :  * used by PostgreSQL, be they related to GUCs or authentication.
       8              :  *
       9              :  *
      10              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      11              :  * Portions Copyright (c) 1994, Regents of the University of California
      12              :  *
      13              :  * IDENTIFICATION
      14              :  *    src/backend/utils/misc/conffiles.c
      15              :  *
      16              :  *--------------------------------------------------------------------
      17              :  */
      18              : 
      19              : #include "postgres.h"
      20              : 
      21              : #include <dirent.h>
      22              : 
      23              : #include "common/file_utils.h"
      24              : #include "miscadmin.h"
      25              : #include "storage/fd.h"
      26              : #include "utils/conffiles.h"
      27              : 
      28              : /*
      29              :  * AbsoluteConfigLocation
      30              :  *
      31              :  * Given a configuration file or directory location that may be a relative
      32              :  * path, return an absolute one.  We consider the location to be relative to
      33              :  * the directory holding the calling file, or to DataDir if no calling file.
      34              :  */
      35              : char *
      36         5203 : AbsoluteConfigLocation(const char *location, const char *calling_file)
      37              : {
      38         5203 :     if (is_absolute_path(location))
      39         3134 :         return pstrdup(location);
      40              :     else
      41              :     {
      42              :         char        abs_path[MAXPGPATH];
      43              : 
      44         2069 :         if (calling_file != NULL)
      45              :         {
      46          105 :             strlcpy(abs_path, calling_file, sizeof(abs_path));
      47          105 :             get_parent_directory(abs_path);
      48          105 :             join_path_components(abs_path, abs_path, location);
      49          105 :             canonicalize_path(abs_path);
      50              :         }
      51              :         else
      52              :         {
      53              :             Assert(DataDir);
      54         1964 :             join_path_components(abs_path, DataDir, location);
      55         1964 :             canonicalize_path(abs_path);
      56              :         }
      57         2069 :         return pstrdup(abs_path);
      58              :     }
      59              : }
      60              : 
      61              : 
      62              : /*
      63              :  * GetConfFilesInDir
      64              :  *
      65              :  * Returns the list of config files located in a directory, in alphabetical
      66              :  * order.  On error, returns NULL with details about the error stored in
      67              :  * "err_msg".
      68              :  */
      69              : char      **
      70            4 : GetConfFilesInDir(const char *includedir, const char *calling_file,
      71              :                   int elevel, int *num_filenames, char **err_msg)
      72              : {
      73              :     char       *directory;
      74              :     DIR        *d;
      75              :     struct dirent *de;
      76            4 :     char      **filenames = NULL;
      77              :     int         size_filenames;
      78              : 
      79              :     /*
      80              :      * Reject directory name that is all-blank (including empty), as that
      81              :      * leads to confusion --- we'd read the containing directory, typically
      82              :      * resulting in recursive inclusion of the same file(s).
      83              :      */
      84            4 :     if (strspn(includedir, " \t\r\n") == strlen(includedir))
      85              :     {
      86            0 :         ereport(elevel,
      87              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      88              :                  errmsg("empty configuration directory name: \"%s\"",
      89              :                         includedir)));
      90            0 :         *err_msg = "empty configuration directory name";
      91            0 :         return NULL;
      92              :     }
      93              : 
      94            4 :     directory = AbsoluteConfigLocation(includedir, calling_file);
      95            4 :     d = AllocateDir(directory);
      96            4 :     if (d == NULL)
      97              :     {
      98            0 :         ereport(elevel,
      99              :                 (errcode_for_file_access(),
     100              :                  errmsg("could not open configuration directory \"%s\": %m",
     101              :                         directory)));
     102            0 :         *err_msg = psprintf("could not open directory \"%s\"", directory);
     103            0 :         goto cleanup;
     104              :     }
     105              : 
     106              :     /*
     107              :      * Read the directory and put the filenames in an array, so we can sort
     108              :      * them prior to caller processing the contents.
     109              :      */
     110            4 :     size_filenames = 32;
     111            4 :     filenames = palloc_array(char *, size_filenames);
     112            4 :     *num_filenames = 0;
     113              : 
     114           24 :     while ((de = ReadDir(d, directory)) != NULL)
     115              :     {
     116              :         PGFileType  de_type;
     117              :         char        filename[MAXPGPATH];
     118              : 
     119              :         /*
     120              :          * Only parse files with names ending in ".conf".  Explicitly reject
     121              :          * files starting with ".".  This excludes things like "." and "..",
     122              :          * as well as typical hidden files, backup files, and editor debris.
     123              :          */
     124           20 :         if (strlen(de->d_name) < 6)
     125           12 :             continue;
     126           12 :         if (de->d_name[0] == '.')
     127            0 :             continue;
     128           12 :         if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0)
     129            4 :             continue;
     130              : 
     131            8 :         join_path_components(filename, directory, de->d_name);
     132            8 :         canonicalize_path(filename);
     133            8 :         de_type = get_dirent_type(filename, de, true, elevel);
     134            8 :         if (de_type == PGFILETYPE_ERROR)
     135              :         {
     136            0 :             *err_msg = psprintf("could not stat file \"%s\"", filename);
     137            0 :             pfree(filenames);
     138            0 :             filenames = NULL;
     139            0 :             goto cleanup;
     140              :         }
     141            8 :         else if (de_type != PGFILETYPE_DIR)
     142              :         {
     143              :             /* Add file to array, increasing its size in blocks of 32 */
     144            8 :             if (*num_filenames >= size_filenames)
     145              :             {
     146            0 :                 size_filenames += 32;
     147            0 :                 filenames = (char **) repalloc(filenames,
     148              :                                                size_filenames * sizeof(char *));
     149              :             }
     150            8 :             filenames[*num_filenames] = pstrdup(filename);
     151            8 :             (*num_filenames)++;
     152              :         }
     153              :     }
     154              : 
     155              :     /* Sort the files by name before leaving */
     156            4 :     if (*num_filenames > 0)
     157            4 :         qsort(filenames, *num_filenames, sizeof(char *), pg_qsort_strcmp);
     158              : 
     159            0 : cleanup:
     160            4 :     if (d)
     161            4 :         FreeDir(d);
     162            4 :     pfree(directory);
     163            4 :     return filenames;
     164              : }
        

Generated by: LCOV version 2.0-1