Coverage Report

Created: 2025-10-09 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/misc/conffiles.c
Line
Count
Source
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-2025, 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
AbsoluteConfigLocation(const char *location, const char *calling_file)
37
0
{
38
0
  if (is_absolute_path(location))
39
0
    return pstrdup(location);
40
0
  else
41
0
  {
42
0
    char    abs_path[MAXPGPATH];
43
44
0
    if (calling_file != NULL)
45
0
    {
46
0
      strlcpy(abs_path, calling_file, sizeof(abs_path));
47
0
      get_parent_directory(abs_path);
48
0
      join_path_components(abs_path, abs_path, location);
49
0
      canonicalize_path(abs_path);
50
0
    }
51
0
    else
52
0
    {
53
0
      Assert(DataDir);
54
0
      join_path_components(abs_path, DataDir, location);
55
0
      canonicalize_path(abs_path);
56
0
    }
57
0
    return pstrdup(abs_path);
58
0
  }
59
0
}
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
GetConfFilesInDir(const char *includedir, const char *calling_file,
71
          int elevel, int *num_filenames, char **err_msg)
72
0
{
73
0
  char     *directory;
74
0
  DIR      *d;
75
0
  struct dirent *de;
76
0
  char    **filenames = NULL;
77
0
  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
0
  if (strspn(includedir, " \t\r\n") == strlen(includedir))
85
0
  {
86
0
    ereport(elevel,
87
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
88
0
         errmsg("empty configuration directory name: \"%s\"",
89
0
            includedir)));
90
0
    *err_msg = "empty configuration directory name";
91
0
    return NULL;
92
0
  }
93
94
0
  directory = AbsoluteConfigLocation(includedir, calling_file);
95
0
  d = AllocateDir(directory);
96
0
  if (d == NULL)
97
0
  {
98
0
    ereport(elevel,
99
0
        (errcode_for_file_access(),
100
0
         errmsg("could not open configuration directory \"%s\": %m",
101
0
            directory)));
102
0
    *err_msg = psprintf("could not open directory \"%s\"", directory);
103
0
    goto cleanup;
104
0
  }
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
0
  size_filenames = 32;
111
0
  filenames = (char **) palloc(size_filenames * sizeof(char *));
112
0
  *num_filenames = 0;
113
114
0
  while ((de = ReadDir(d, directory)) != NULL)
115
0
  {
116
0
    PGFileType  de_type;
117
0
    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
0
    if (strlen(de->d_name) < 6)
125
0
      continue;
126
0
    if (de->d_name[0] == '.')
127
0
      continue;
128
0
    if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0)
129
0
      continue;
130
131
0
    join_path_components(filename, directory, de->d_name);
132
0
    canonicalize_path(filename);
133
0
    de_type = get_dirent_type(filename, de, true, elevel);
134
0
    if (de_type == PGFILETYPE_ERROR)
135
0
    {
136
0
      *err_msg = psprintf("could not stat file \"%s\"", filename);
137
0
      pfree(filenames);
138
0
      filenames = NULL;
139
0
      goto cleanup;
140
0
    }
141
0
    else if (de_type != PGFILETYPE_DIR)
142
0
    {
143
      /* Add file to array, increasing its size in blocks of 32 */
144
0
      if (*num_filenames >= size_filenames)
145
0
      {
146
0
        size_filenames += 32;
147
0
        filenames = (char **) repalloc(filenames,
148
0
                         size_filenames * sizeof(char *));
149
0
      }
150
0
      filenames[*num_filenames] = pstrdup(filename);
151
0
      (*num_filenames)++;
152
0
    }
153
0
  }
154
155
  /* Sort the files by name before leaving */
156
0
  if (*num_filenames > 0)
157
0
    qsort(filenames, *num_filenames, sizeof(char *), pg_qsort_strcmp);
158
159
0
cleanup:
160
0
  if (d)
161
0
    FreeDir(d);
162
0
  pfree(directory);
163
0
  return filenames;
164
0
}