Branch data 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 : 20 : AbsoluteConfigLocation(const char *location, const char *calling_file)
37 : : {
38 [ + + ]: 20 : if (is_absolute_path(location))
39 : 13 : return pstrdup(location);
40 : : else
41 : : {
42 : 7 : char abs_path[MAXPGPATH];
43 : :
44 [ - + ]: 7 : if (calling_file != NULL)
45 : : {
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 : : else
52 : : {
53 [ + - ]: 7 : Assert(DataDir);
54 : 7 : join_path_components(abs_path, DataDir, location);
55 : 7 : canonicalize_path(abs_path);
56 : : }
57 : 7 : return pstrdup(abs_path);
58 : 7 : }
59 : 20 : }
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 : 0 : GetConfFilesInDir(const char *includedir, const char *calling_file,
71 : : int elevel, int *num_filenames, char **err_msg)
72 : : {
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 : : {
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 : 0 : directory = AbsoluteConfigLocation(includedir, calling_file);
95 : 0 : d = AllocateDir(directory);
96 [ # # ]: 0 : 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 : 0 : size_filenames = 32;
111 : 0 : filenames = palloc_array(char *, size_filenames);
112 : 0 : *num_filenames = 0;
113 : :
114 [ # # ]: 0 : while ((de = ReadDir(d, directory)) != NULL)
115 : : {
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 : : {
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 [ # # ]: 0 : else if (de_type != PGFILETYPE_DIR)
142 : : {
143 : : /* Add file to array, increasing its size in blocks of 32 */
144 [ # # ]: 0 : if (*num_filenames >= size_filenames)
145 : : {
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 : : cleanup:
160 [ # # ]: 0 : if (d)
161 : 0 : FreeDir(d);
162 : 0 : pfree(directory);
163 : 0 : return filenames;
164 : 0 : }
|