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-2024, 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 7586 : AbsoluteConfigLocation(const char *location, const char *calling_file)
37 : {
38 7586 : if (is_absolute_path(location))
39 4686 : return pstrdup(location);
40 : else
41 : {
42 : char abs_path[MAXPGPATH];
43 :
44 2900 : if (calling_file != NULL)
45 : {
46 164 : strlcpy(abs_path, calling_file, sizeof(abs_path));
47 164 : get_parent_directory(abs_path);
48 164 : join_path_components(abs_path, abs_path, location);
49 164 : canonicalize_path(abs_path);
50 : }
51 : else
52 : {
53 : Assert(DataDir);
54 2736 : join_path_components(abs_path, DataDir, location);
55 2736 : canonicalize_path(abs_path);
56 : }
57 2900 : 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 8 : 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 8 : 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 8 : 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 8 : directory = AbsoluteConfigLocation(includedir, calling_file);
95 8 : d = AllocateDir(directory);
96 8 : 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 8 : size_filenames = 32;
111 8 : filenames = (char **) palloc(size_filenames * sizeof(char *));
112 8 : *num_filenames = 0;
113 :
114 48 : 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 40 : if (strlen(de->d_name) < 6)
125 24 : continue;
126 24 : if (de->d_name[0] == '.')
127 0 : continue;
128 24 : if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0)
129 8 : continue;
130 :
131 16 : join_path_components(filename, directory, de->d_name);
132 16 : canonicalize_path(filename);
133 16 : de_type = get_dirent_type(filename, de, true, elevel);
134 16 : 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 16 : else if (de_type != PGFILETYPE_DIR)
142 : {
143 : /* Add file to array, increasing its size in blocks of 32 */
144 16 : if (*num_filenames >= size_filenames)
145 : {
146 0 : size_filenames += 32;
147 0 : filenames = (char **) repalloc(filenames,
148 : size_filenames * sizeof(char *));
149 : }
150 16 : filenames[*num_filenames] = pstrdup(filename);
151 16 : (*num_filenames)++;
152 : }
153 : }
154 :
155 : /* Sort the files by name before leaving */
156 8 : if (*num_filenames > 0)
157 8 : qsort(filenames, *num_filenames, sizeof(char *), pg_qsort_strcmp);
158 :
159 0 : cleanup:
160 8 : if (d)
161 8 : FreeDir(d);
162 8 : pfree(directory);
163 8 : return filenames;
164 : }
|