config-directory-v4.patch
text/x-patch
Filename: config-directory-v4.patch
Type: text/x-patch
Part: 0
Message:
Configuration include directory
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v4
| File | + | − |
|---|---|---|
| src/backend/utils/misc/guc.c | 0 | 0 |
| src/backend/utils/misc/guc-file.l | 0 | 0 |
| src/include/utils/guc.h | 0 | 0 |
diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l
index a094c7a..25e1a07 100644
*** a/src/backend/utils/misc/guc-file.l
--- b/src/backend/utils/misc/guc-file.l
*************** ParseConfigFp(FILE *fp, const char *conf
*** 512,518 ****
}
/* OK, process the option name and value */
! if (guc_name_compare(opt_name, "include") == 0)
{
/*
* An include directive isn't a variable and should be processed
--- 512,535 ----
}
/* OK, process the option name and value */
! if (guc_name_compare(opt_name, "includedir") == 0)
! {
! /*
! * An includedir directive isn't a variable and should be processed
! * immediately.
! */
! unsigned int save_ConfigFileLineno = ConfigFileLineno;
!
! if (!ParseConfigDirectory(opt_value, config_file,
! depth + 1, elevel,
! head_p, tail_p))
! OK = false;
! yy_switch_to_buffer(lex_buffer);
! ConfigFileLineno = save_ConfigFileLineno;
! pfree(opt_name);
! pfree(opt_value);
! }
! else if (guc_name_compare(opt_name, "include") == 0)
{
/*
* An include directive isn't a variable and should be processed
*************** ParseConfigFp(FILE *fp, const char *conf
*** 599,604 ****
--- 616,727 ----
return OK;
}
+ static int
+ comparestr(const void *a, const void *b)
+ {
+ return strcmp(*(char **) a, *(char **) b);
+ }
+
+ /*
+ * Read and parse all config files in a subdirectory in alphabetical order
+ */
+ bool
+ ParseConfigDirectory(const char *includedir,
+ const char *calling_file,
+ int depth, int elevel,
+ ConfigVariable **head_p,
+ ConfigVariable **tail_p)
+ {
+ DIR *d;
+ struct dirent *de;
+ char directory[MAXPGPATH];
+ char **filenames = NULL;
+ int num_filenames = 0;
+ int size_filenames = 0;
+ bool status;
+
+ if (is_absolute_path(includedir))
+ sprintf(directory, "%s", includedir);
+ else
+ sprintf(directory, "%s/%s", configdir, includedir);
+ d = AllocateDir(directory);
+ if (d == NULL)
+ {
+ /*
+ * Not finding the configuration directory is not fatal, because we
+ * still have the main postgresql.conf file. Return true so the
+ * complete config parsing doesn't fail in this case. Also avoid
+ * logging this, since it can be a normal situtation.
+ */
+ return true;
+ }
+
+ /*
+ * Read the directory and put the filenames in an array, so we can sort
+ * them prior to processing the contents.
+ */
+ while ((de = ReadDir(d, directory)) != NULL)
+ {
+ struct stat st;
+ char filename[MAXPGPATH];
+
+ /*
+ * Only parse files with names ending in ".conf".
+ * This automatically excludes things like "." and "..", as well
+ * as backup files and editor debris.
+ */
+ if (strlen(de->d_name) < 6)
+ continue;
+ if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0)
+ continue;
+
+ snprintf(filename, MAXPGPATH, "%s/%s", directory, de->d_name);
+ if (stat(filename, &st) == 0)
+ {
+ if (!S_ISDIR(st.st_mode))
+ {
+ /* Add file to list */
+ if (num_filenames == size_filenames)
+ {
+ /* Increase size of array in blocks of 32 */
+ size_filenames += 32;
+ filenames = guc_realloc(elevel, filenames, size_filenames * sizeof(char *));
+ }
+ filenames[num_filenames] = strdup(filename);
+ num_filenames++;
+ }
+ }
+ }
+ if (num_filenames > 0)
+ {
+ int i;
+ qsort(filenames, num_filenames, sizeof(char *), comparestr);
+ for (i = 0; i < num_filenames; i++)
+ {
+ if (!ParseConfigFile(filenames[i], NULL,
+ 0, elevel,head_p, tail_p))
+ {
+ status = false;
+ goto cleanup;
+ }
+ }
+ }
+ status = true;
+
+ cleanup:
+ if (num_filenames > 0)
+ {
+ int i;
+
+ for (i = 0; i < num_filenames; i++)
+ {
+ free(filenames[i]);
+ }
+ free(filenames);
+ }
+ FreeDir(d);
+ return status;
+ }
/*
* Free a list of ConfigVariables, including the names and the values
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index da7b6d4..fc9b376 100644
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** static int effective_io_concurrency;
*** 481,486 ****
--- 481,488 ----
/* should be static, but commands/variable.c needs to get at this */
char *role_string;
+ /* Needed for ProcessConfigFile calls, such as a config reload at SIGHUP */
+ char *configdir;
/*
* Displayable names for context types (enum GucContext)
*************** static bool validate_option_array_item(c
*** 3297,3303 ****
/*
* Some infrastructure for checking malloc/strdup/realloc calls
*/
! static void *
guc_malloc(int elevel, size_t size)
{
void *data;
--- 3299,3305 ----
/*
* Some infrastructure for checking malloc/strdup/realloc calls
*/
! void *
guc_malloc(int elevel, size_t size)
{
void *data;
*************** guc_malloc(int elevel, size_t size)
*** 3310,3316 ****
return data;
}
! static void *
guc_realloc(int elevel, void *old, size_t size)
{
void *data;
--- 3312,3318 ----
return data;
}
! void *
guc_realloc(int elevel, void *old, size_t size)
{
void *data;
*************** InitializeOneGUCOption(struct config_gen
*** 4007,4013 ****
bool
SelectConfigFiles(const char *userDoption, const char *progname)
{
- char *configdir;
char *fname;
struct stat stat_buf;
--- 4009,4014 ----
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 8e3057a..af47e95 100644
*** a/src/include/utils/guc.h
--- b/src/include/utils/guc.h
*************** extern bool ParseConfigFp(FILE *fp, cons
*** 117,122 ****
--- 117,123 ----
int depth, int elevel,
ConfigVariable **head_p, ConfigVariable **tail_p);
extern void FreeConfigVariables(ConfigVariable *list);
+ extern char *configdir;
/*
* The possible values of an enum variable are specified by an array of
*************** extern const char *GetConfigOption(const
*** 302,307 ****
--- 303,313 ----
bool restrict_superuser);
extern const char *GetConfigOptionResetString(const char *name);
extern void ProcessConfigFile(GucContext context);
+ extern bool ParseConfigDirectory(const char *includedir,
+ const char *calling_file,
+ int depth, int elevel,
+ ConfigVariable **head_p,
+ ConfigVariable **tail_p);
extern void InitializeGUCOptions(void);
extern bool SelectConfigFiles(const char *userDoption, const char *progname);
extern void ResetAllOptions(void);
*************** extern void GUC_check_errcode(int sqlerr
*** 360,365 ****
--- 366,377 ----
/*
+ * Functions used for memory allocation in guc.
+ */
+ void *guc_malloc(int elevel, size_t size);
+ void *guc_realloc(int elevel, void *old, size_t size);
+
+ /*
* The following functions are not in guc.c, but are declared here to avoid
* having to include guc.h in some widely used headers that it really doesn't
* belong in.