Skip to content

Commit a1a7bb8

Browse files
committed
Move code related to configuration files in directories to new file
The code in charge of listing and classifying a set of configuration files in a directory was located in guc-file.l, being used currently for GUCs under "include_dir". This code is planned to be used for an upcoming feature able to include configuration files for ident and HBA files from a directory, similarly to GUCs. In both cases, the file names, suffixed by ".conf", have to be ordered alphabetically. This logic is moved to a new file, called conffiles.c, so as it is easier to share this facility between GUCs and the HBA/ident parsing logic. Author: Julien Rouhaud, Michael Paquier Discussion: https://postgr.es/m/Y2IgaH5YzIq2b+iR@paquier.xyz
1 parent b0b72c6 commit a1a7bb8

File tree

5 files changed

+204
-142
lines changed

5 files changed

+204
-142
lines changed

src/backend/utils/misc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ include $(top_builddir)/src/Makefile.global
1515
override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
1616

1717
OBJS = \
18+
conffiles.o \
1819
guc.o \
1920
guc-file.o \
2021
guc_funcs.o \

src/backend/utils/misc/conffiles.c

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
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-2022, 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+
{
38+
char abs_path[MAXPGPATH];
39+
40+
if (is_absolute_path(location))
41+
return pstrdup(location);
42+
else
43+
{
44+
if (calling_file != NULL)
45+
{
46+
strlcpy(abs_path, calling_file, sizeof(abs_path));
47+
get_parent_directory(abs_path);
48+
join_path_components(abs_path, abs_path, location);
49+
canonicalize_path(abs_path);
50+
}
51+
else
52+
{
53+
Assert(DataDir);
54+
join_path_components(abs_path, DataDir, location);
55+
canonicalize_path(abs_path);
56+
}
57+
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+
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+
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+
if (strspn(includedir, " \t\r\n") == strlen(includedir))
85+
{
86+
ereport(elevel,
87+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
88+
errmsg("empty configuration directory name: \"%s\"",
89+
includedir)));
90+
*err_msg = "empty configuration directory name";
91+
return NULL;
92+
}
93+
94+
directory = AbsoluteConfigLocation(includedir, calling_file);
95+
d = AllocateDir(directory);
96+
if (d == NULL)
97+
{
98+
ereport(elevel,
99+
(errcode_for_file_access(),
100+
errmsg("could not open configuration directory \"%s\": %m",
101+
directory)));
102+
*err_msg = psprintf("could not open directory \"%s\"", directory);
103+
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+
size_filenames = 32;
111+
filenames = (char **) palloc(size_filenames * sizeof(char *));
112+
*num_filenames = 0;
113+
114+
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+
if (strlen(de->d_name) < 6)
125+
continue;
126+
if (de->d_name[0] == '.')
127+
continue;
128+
if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0)
129+
continue;
130+
131+
join_path_components(filename, directory, de->d_name);
132+
canonicalize_path(filename);
133+
de_type = get_dirent_type(filename, de, true, elevel);
134+
if (de_type == PGFILETYPE_ERROR)
135+
{
136+
*err_msg = psprintf("could not stat file \"%s\"", filename);
137+
pfree(filenames);
138+
filenames = NULL;
139+
goto cleanup;
140+
}
141+
else if (de_type != PGFILETYPE_DIR)
142+
{
143+
/* Add file to array, increasing its size in blocks of 32 */
144+
if (*num_filenames >= size_filenames)
145+
{
146+
size_filenames += 32;
147+
filenames = (char **) repalloc(filenames,
148+
size_filenames * sizeof(char *));
149+
}
150+
filenames[*num_filenames] = pstrdup(filename);
151+
(*num_filenames)++;
152+
}
153+
}
154+
155+
/* Sort the files by name before leaving */
156+
if (*num_filenames > 0)
157+
qsort(filenames, *num_filenames, sizeof(char *), pg_qsort_strcmp);
158+
159+
cleanup:
160+
if (d)
161+
FreeDir(d);
162+
pfree(directory);
163+
return filenames;
164+
}

src/backend/utils/misc/guc-file.l

Lines changed: 15 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "mb/pg_wchar.h"
1818
#include "miscadmin.h"
1919
#include "storage/fd.h"
20+
#include "utils/conffiles.h"
2021
#include "utils/memutils.h"
2122
}
2223

@@ -155,37 +156,6 @@ ProcessConfigFile(GucContext context)
155156
MemoryContextDelete(config_cxt);
156157
}
157158

158-
/*
159-
* Given a configuration file or directory location that may be a relative
160-
* path, return an absolute one. We consider the location to be relative to
161-
* the directory holding the calling file, or to DataDir if no calling file.
162-
*/
163-
static char *
164-
AbsoluteConfigLocation(const char *location, const char *calling_file)
165-
{
166-
char abs_path[MAXPGPATH];
167-
168-
if (is_absolute_path(location))
169-
return pstrdup(location);
170-
else
171-
{
172-
if (calling_file != NULL)
173-
{
174-
strlcpy(abs_path, calling_file, sizeof(abs_path));
175-
get_parent_directory(abs_path);
176-
join_path_components(abs_path, abs_path, location);
177-
canonicalize_path(abs_path);
178-
}
179-
else
180-
{
181-
Assert(DataDir);
182-
join_path_components(abs_path, DataDir, location);
183-
canonicalize_path(abs_path);
184-
}
185-
return pstrdup(abs_path);
186-
}
187-
}
188-
189159
/*
190160
* Read and parse a single configuration file. This function recurses
191161
* to handle "include" directives.
@@ -605,127 +575,30 @@ ParseConfigDirectory(const char *includedir,
605575
ConfigVariable **head_p,
606576
ConfigVariable **tail_p)
607577
{
608-
char *directory;
609-
DIR *d;
610-
struct dirent *de;
578+
char *err_msg;
611579
char **filenames;
612580
int num_filenames;
613-
int size_filenames;
614-
bool status;
615-
616-
/*
617-
* Reject directory name that is all-blank (including empty), as that
618-
* leads to confusion --- we'd read the containing directory, typically
619-
* resulting in recursive inclusion of the same file(s).
620-
*/
621-
if (strspn(includedir, " \t\r\n") == strlen(includedir))
622-
{
623-
ereport(elevel,
624-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
625-
errmsg("empty configuration directory name: \"%s\"",
626-
includedir)));
627-
record_config_file_error("empty configuration directory name",
628-
calling_file, calling_lineno,
629-
head_p, tail_p);
630-
return false;
631-
}
632-
633-
/*
634-
* We don't check for recursion or too-deep nesting depth here; the
635-
* subsequent calls to ParseConfigFile will take care of that.
636-
*/
637-
638-
directory = AbsoluteConfigLocation(includedir, calling_file);
639-
d = AllocateDir(directory);
640-
if (d == NULL)
641-
{
642-
ereport(elevel,
643-
(errcode_for_file_access(),
644-
errmsg("could not open configuration directory \"%s\": %m",
645-
directory)));
646-
record_config_file_error(psprintf("could not open directory \"%s\"",
647-
directory),
648-
calling_file, calling_lineno,
649-
head_p, tail_p);
650-
status = false;
651-
goto cleanup;
652-
}
653581

654-
/*
655-
* Read the directory and put the filenames in an array, so we can sort
656-
* them prior to processing the contents.
657-
*/
658-
size_filenames = 32;
659-
filenames = (char **) palloc(size_filenames * sizeof(char *));
660-
num_filenames = 0;
582+
filenames = GetConfFilesInDir(includedir, calling_file, elevel,
583+
&num_filenames, &err_msg);
661584

662-
while ((de = ReadDir(d, directory)) != NULL)
585+
if (!filenames)
663586
{
664-
PGFileType de_type;
665-
char filename[MAXPGPATH];
666-
667-
/*
668-
* Only parse files with names ending in ".conf". Explicitly reject
669-
* files starting with ".". This excludes things like "." and "..",
670-
* as well as typical hidden files, backup files, and editor debris.
671-
*/
672-
if (strlen(de->d_name) < 6)
673-
continue;
674-
if (de->d_name[0] == '.')
675-
continue;
676-
if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0)
677-
continue;
678-
679-
join_path_components(filename, directory, de->d_name);
680-
canonicalize_path(filename);
681-
de_type = get_dirent_type(filename, de, true, elevel);
682-
if (de_type == PGFILETYPE_ERROR)
683-
{
684-
record_config_file_error(psprintf("could not stat file \"%s\"",
685-
filename),
686-
calling_file, calling_lineno,
687-
head_p, tail_p);
688-
status = false;
689-
goto cleanup;
690-
}
691-
else if (de_type != PGFILETYPE_DIR)
692-
{
693-
/* Add file to array, increasing its size in blocks of 32 */
694-
if (num_filenames >= size_filenames)
695-
{
696-
size_filenames += 32;
697-
filenames = (char **) repalloc(filenames,
698-
size_filenames * sizeof(char *));
699-
}
700-
filenames[num_filenames] = pstrdup(filename);
701-
num_filenames++;
702-
}
587+
record_config_file_error(err_msg, calling_file, calling_lineno, head_p,
588+
tail_p);
589+
return false;
703590
}
704591

705-
if (num_filenames > 0)
592+
for (int i = 0; i < num_filenames; i++)
706593
{
707-
int i;
708-
709-
qsort(filenames, num_filenames, sizeof(char *), pg_qsort_strcmp);
710-
for (i = 0; i < num_filenames; i++)
711-
{
712-
if (!ParseConfigFile(filenames[i], true,
713-
calling_file, calling_lineno,
714-
depth, elevel,
715-
head_p, tail_p))
716-
{
717-
status = false;
718-
goto cleanup;
719-
}
720-
}
594+
if (!ParseConfigFile(filenames[i], true,
595+
calling_file, calling_lineno,
596+
depth, elevel,
597+
head_p, tail_p))
598+
return false;
721599
}
722-
status = true;
723600

724-
cleanup:
725-
if (d)
726-
FreeDir(d);
727-
pfree(directory);
728-
return status;
601+
return true;
729602
}
730603

731604
/*

src/backend/utils/misc/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
backend_sources += files(
2+
'conffiles.c',
23
'guc.c',
34
'guc_funcs.c',
45
'guc_tables.c',

src/include/utils/conffiles.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*--------------------------------------------------------------------
2+
* conffiles.h
3+
*
4+
* Utilities related to configuration files.
5+
*
6+
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
* src/include/utils/conffiles.h
10+
*
11+
*--------------------------------------------------------------------
12+
*/
13+
#ifndef CONFFILES_H
14+
#define CONFFILES_H
15+
16+
extern char *AbsoluteConfigLocation(const char *location,
17+
const char *calling_file);
18+
extern char **GetConfFilesInDir(const char *includedir,
19+
const char *calling_file,
20+
int elevel, int *num_filenames,
21+
char **err_msg);
22+
23+
#endif /* CONFFILES_H */

0 commit comments

Comments
 (0)