Age Owner Branch data TLA 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 *
524 michael@paquier.xyz 36 :CBC 4416 : AbsoluteConfigLocation(const char *location, const char *calling_file)
37 : : {
38 [ + + ]: 4416 : if (is_absolute_path(location))
39 : 2625 : return pstrdup(location);
40 : : else
41 : : {
42 : : char abs_path[MAXPGPATH];
43 : :
44 [ + + ]: 1791 : if (calling_file != NULL)
45 : : {
46 : 78 : strlcpy(abs_path, calling_file, sizeof(abs_path));
47 : 78 : get_parent_directory(abs_path);
48 : 78 : join_path_components(abs_path, abs_path, location);
49 : 78 : canonicalize_path(abs_path);
50 : : }
51 : : else
52 : : {
53 [ - + ]: 1713 : Assert(DataDir);
54 : 1713 : join_path_components(abs_path, DataDir, location);
55 : 1713 : canonicalize_path(abs_path);
56 : : }
57 : 1791 : 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 : : {
524 michael@paquier.xyz 86 [ # # ]:UBC 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 : :
524 michael@paquier.xyz 94 :CBC 4 : directory = AbsoluteConfigLocation(includedir, calling_file);
95 : 4 : d = AllocateDir(directory);
96 [ - + ]: 4 : if (d == NULL)
97 : : {
524 michael@paquier.xyz 98 [ # # ]:UBC 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 : : */
524 michael@paquier.xyz 110 :CBC 4 : size_filenames = 32;
111 : 4 : filenames = (char **) palloc(size_filenames * sizeof(char *));
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] == '.')
524 michael@paquier.xyz 127 :UBC 0 : continue;
524 michael@paquier.xyz 128 [ + + ]:CBC 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 : : {
524 michael@paquier.xyz 136 :UBC 0 : *err_msg = psprintf("could not stat file \"%s\"", filename);
137 : 0 : pfree(filenames);
138 : 0 : filenames = NULL;
139 : 0 : goto cleanup;
140 : : }
524 michael@paquier.xyz 141 [ + - ]:CBC 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 : : {
524 michael@paquier.xyz 146 :UBC 0 : size_filenames += 32;
147 : 0 : filenames = (char **) repalloc(filenames,
148 : : size_filenames * sizeof(char *));
149 : : }
524 michael@paquier.xyz 150 :CBC 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 : :
524 michael@paquier.xyz 159 :UBC 0 : cleanup:
524 michael@paquier.xyz 160 [ + - ]:CBC 4 : if (d)
161 : 4 : FreeDir(d);
162 : 4 : pfree(directory);
163 : 4 : return filenames;
164 : : }
|