mirror of https://github.com/postgres/postgres
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.xyzpull/108/head
parent
b0b72c64a0
commit
a1a7bb8f16
@ -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-2022, 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) |
||||||
|
{ |
||||||
|
char abs_path[MAXPGPATH]; |
||||||
|
|
||||||
|
if (is_absolute_path(location)) |
||||||
|
return pstrdup(location); |
||||||
|
else |
||||||
|
{ |
||||||
|
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; |
||||||
|
} |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
/*--------------------------------------------------------------------
|
||||||
|
* conffiles.h |
||||||
|
* |
||||||
|
* Utilities related to configuration files. |
||||||
|
* |
||||||
|
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group |
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California |
||||||
|
* |
||||||
|
* src/include/utils/conffiles.h |
||||||
|
* |
||||||
|
*-------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
#ifndef CONFFILES_H |
||||||
|
#define CONFFILES_H |
||||||
|
|
||||||
|
extern char *AbsoluteConfigLocation(const char *location, |
||||||
|
const char *calling_file); |
||||||
|
extern char **GetConfFilesInDir(const char *includedir, |
||||||
|
const char *calling_file, |
||||||
|
int elevel, int *num_filenames, |
||||||
|
char **err_msg); |
||||||
|
|
||||||
|
#endif /* CONFFILES_H */ |
||||||
Loading…
Reference in new issue