+ head = tail = NULL;
+
+ if (!ParseConfigFile(ConfigFileName, NULL,
+ 0, context, elevel,
+ &head, &tail))
+ goto cleanup_list;
+
+ /* Check if all options are valid */
+ for (item = head; item; item = item->next)
+ {
+ if (!set_config_option(item->name, item->value, context,
+ PGC_S_FILE, false, false))
+ goto cleanup_list;
+ }
+
+ /* If we got here all the options checked out okay, so apply them. */
+ for (item = head; item; item = item->next)
+ {
+ set_config_option(item->name, item->value, context,
+ PGC_S_FILE, false, true);
+ }
+
+ cleanup_list:
+ free_name_value_list(head);
+}
+
+
+/*
+ * Read and parse a single configuration file. This function recurses
+ * to handle "include" directives.
+ *
+ * Input parameters:
+ * config_file: absolute or relative path of file to read
+ * calling_file: absolute path of file containing the "include" directive,
+ * or NULL at outer level (config_file must be absolute at outer level)
+ * depth: recursion depth (used only to prevent infinite recursion)
+ * context: GucContext passed to ProcessConfigFile()
+ * elevel: error logging level determined by ProcessConfigFile()
+ * Output parameters:
+ * head_p, tail_p: head and tail of linked list of name/value pairs
+ *
+ * *head_p and *tail_p must be initialized to NULL before calling the outer
+ * recursion level. On exit, they contain a list of name-value pairs read
+ * from the input file(s).
+ *
+ * Returns TRUE if successful, FALSE if an error occurred. The error has
+ * already been ereport'd, it is only necessary for the caller to clean up
+ * its own state and release the name/value pairs list.
+ *
+ * Note: if elevel >= ERROR then an error will not return control to the
+ * caller, and internal state such as open files will not be cleaned up.
+ * This case occurs only during postmaster or standalone-backend startup,
+ * where an error will lead to immediate process exit anyway; so there is
+ * no point in contorting the code so it can clean up nicely.
+ */
+static bool
+ParseConfigFile(const char *config_file, const char *calling_file,
+ int depth, GucContext context, int elevel,
+ struct name_value_pair **head_p,
+ struct name_value_pair **tail_p)
+{
+ bool OK = true;
+ char abs_path[MAXPGPATH];
+ FILE *fp;
+ YY_BUFFER_STATE lex_buffer;
+ int token;
+
+ /*
+ * Reject too-deep include nesting depth. This is just a safety check
+ * to avoid dumping core due to stack overflow if an include file loops
+ * back to itself. The maximum nesting depth is pretty arbitrary.
+ */
+ if (depth > 10)
+ {
+ ereport(elevel,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("could not open configuration file \"%s\": maximum nesting depth exceeded",
+ config_file)));
+ return false;
+ }
+
+ /*
+ * If config_file is a relative path, convert to absolute. We consider
+ * it to be relative to the directory holding the calling file.
+ */
+ if (!is_absolute_path(config_file))
+ {
+ Assert(calling_file != NULL);
+ StrNCpy(abs_path, calling_file, MAXPGPATH);
+ get_parent_directory(abs_path);
+ join_path_components(abs_path, abs_path, config_file);
+ canonicalize_path(abs_path);
+ config_file = abs_path;
+ }
+
+ fp = AllocateFile(config_file, "r");