diff options
Diffstat (limited to 'src/backend/utils/misc/conffiles.c')
-rw-r--r-- | src/backend/utils/misc/conffiles.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/backend/utils/misc/conffiles.c b/src/backend/utils/misc/conffiles.c new file mode 100644 index 0000000..376a5c8 --- /dev/null +++ b/src/backend/utils/misc/conffiles.c @@ -0,0 +1,164 @@ +/*-------------------------------------------------------------------- + * conffiles.c + * + * Utilities related to the handling of configuration files. + * + * This file contains some generic tools to work on configuration files + * used by PostgreSQL, be they related to GUCs or authentication. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/misc/conffiles.c + * + *-------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include <dirent.h> + +#include "common/file_utils.h" +#include "miscadmin.h" +#include "storage/fd.h" +#include "utils/conffiles.h" + +/* + * AbsoluteConfigLocation + * + * Given a configuration file or directory location that may be a relative + * path, return an absolute one. We consider the location to be relative to + * the directory holding the calling file, or to DataDir if no calling file. + */ +char * +AbsoluteConfigLocation(const char *location, const char *calling_file) +{ + if (is_absolute_path(location)) + return pstrdup(location); + else + { + char abs_path[MAXPGPATH]; + + if (calling_file != NULL) + { + strlcpy(abs_path, calling_file, sizeof(abs_path)); + get_parent_directory(abs_path); + join_path_components(abs_path, abs_path, location); + canonicalize_path(abs_path); + } + else + { + Assert(DataDir); + join_path_components(abs_path, DataDir, location); + canonicalize_path(abs_path); + } + return pstrdup(abs_path); + } +} + + +/* + * GetConfFilesInDir + * + * Returns the list of config files located in a directory, in alphabetical + * order. On error, returns NULL with details about the error stored in + * "err_msg". + */ +char ** +GetConfFilesInDir(const char *includedir, const char *calling_file, + int elevel, int *num_filenames, char **err_msg) +{ + char *directory; + DIR *d; + struct dirent *de; + char **filenames = NULL; + int size_filenames; + + /* + * Reject directory name that is all-blank (including empty), as that + * leads to confusion --- we'd read the containing directory, typically + * resulting in recursive inclusion of the same file(s). + */ + if (strspn(includedir, " \t\r\n") == strlen(includedir)) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("empty configuration directory name: \"%s\"", + includedir))); + *err_msg = "empty configuration directory name"; + return NULL; + } + + directory = AbsoluteConfigLocation(includedir, calling_file); + d = AllocateDir(directory); + if (d == NULL) + { + ereport(elevel, + (errcode_for_file_access(), + errmsg("could not open configuration directory \"%s\": %m", + directory))); + *err_msg = psprintf("could not open directory \"%s\"", directory); + goto cleanup; + } + + /* + * Read the directory and put the filenames in an array, so we can sort + * them prior to caller processing the contents. + */ + size_filenames = 32; + filenames = (char **) palloc(size_filenames * sizeof(char *)); + *num_filenames = 0; + + while ((de = ReadDir(d, directory)) != NULL) + { + PGFileType de_type; + char filename[MAXPGPATH]; + + /* + * Only parse files with names ending in ".conf". Explicitly reject + * files starting with ".". This excludes things like "." and "..", + * as well as typical hidden files, backup files, and editor debris. + */ + if (strlen(de->d_name) < 6) + continue; + if (de->d_name[0] == '.') + continue; + if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0) + continue; + + join_path_components(filename, directory, de->d_name); + canonicalize_path(filename); + de_type = get_dirent_type(filename, de, true, elevel); + if (de_type == PGFILETYPE_ERROR) + { + *err_msg = psprintf("could not stat file \"%s\"", filename); + pfree(filenames); + filenames = NULL; + goto cleanup; + } + else if (de_type != PGFILETYPE_DIR) + { + /* Add file to array, increasing its size in blocks of 32 */ + if (*num_filenames >= size_filenames) + { + size_filenames += 32; + filenames = (char **) repalloc(filenames, + size_filenames * sizeof(char *)); + } + filenames[*num_filenames] = pstrdup(filename); + (*num_filenames)++; + } + } + + /* Sort the files by name before leaving */ + if (*num_filenames > 0) + qsort(filenames, *num_filenames, sizeof(char *), pg_qsort_strcmp); + +cleanup: + if (d) + FreeDir(d); + pfree(directory); + return filenames; +} |