3 * Scanner for the configuration file
5 * Copyright (c) 2000-2024, PostgreSQL Global Development Group
7 * src/backend/utils/misc/guc-file.l
15 #include "common/file_utils.h"
16 #include "guc_internal.h"
17 #include "mb/pg_wchar.h"
18 #include "miscadmin.h"
19 #include "storage/fd.h"
20 #include "utils/conffiles.h"
21 #include "utils/memutils.h"
27 * flex emits a yy_fatal_error() function that it calls in response to
28 * critical errors like malloc failure, file I/O errors, and detection of
29 * internal inconsistency. That function prints a message and calls exit().
30 * Mutate it to instead call our handler, which jumps out of the parser.
33 #define fprintf(file, fmt, msg) GUC_flex_fatal(msg)
42 GUC_UNQUOTED_STRING = 6,
48 static unsigned int ConfigFileLineno;
49 static const char *GUC_flex_fatal_errmsg;
50 static sigjmp_buf *GUC_flex_fatal_jmp;
52 static void FreeConfigVariable(ConfigVariable *item);
54 static int GUC_flex_fatal(const char *msg);
61 %option never-interactive
67 %option prefix="GUC_yy"
76 INTEGER {SIGN}?({DIGIT}+|0x{HEXDIGIT}+){UNIT_LETTER}*
78 EXPONENT [Ee]{SIGN}?{DIGIT}+
79 REAL {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}?
81 LETTER [A-Za-z_\200-\377]
82 LETTER_OR_DIGIT [A-Za-z_0-9\200-\377]
84 ID {LETTER}{LETTER_OR_DIGIT}*
85 QUALIFIED_ID {ID}"."{ID}
87 UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
88 STRING \'([^'\\\n]|\\.|\'\')*\'
92 \n ConfigFileLineno++; return GUC_EOL;
93 [ \t\r]+ /* eat whitespace */
94 #.* /* eat comment (.* matches anything until newline) */
97 {QUALIFIED_ID} return GUC_QUALIFIED_ID;
98 {STRING} return GUC_STRING;
99 {UNQUOTED_STRING} return GUC_UNQUOTED_STRING;
100 {INTEGER} return GUC_INTEGER;
101 {REAL} return GUC_REAL;
111 * Exported function to read and process the configuration file. The
112 * parameter indicates in what context the file is being read --- either
113 * postmaster startup (including standalone-backend startup) or SIGHUP.
114 * All options mentioned in the configuration file are set to new values.
115 * If a hard error occurs, no values will be changed. (There can also be
116 * errors that prevent just one value from being changed.)
119 ProcessConfigFile(GucContext context)
122 MemoryContext config_cxt;
123 MemoryContext caller_cxt;
126 * Config files are processed on startup (by the postmaster only) and on
127 * SIGHUP (by the postmaster and its children)
129 Assert((context == PGC_POSTMASTER && !IsUnderPostmaster) ||
130 context == PGC_SIGHUP);
133 * To avoid cluttering the log, only the postmaster bleats loudly about
134 * problems with the config file.
136 elevel = IsUnderPostmaster ? DEBUG2 : LOG;
139 * This function is usually called within a process-lifespan memory
140 * context. To ensure that any memory leaked during GUC processing does
141 * not accumulate across repeated SIGHUP cycles, do the work in a private
142 * context that we can free at exit.
144 config_cxt = AllocSetContextCreate(CurrentMemoryContext,
145 "config file processing",
146 ALLOCSET_DEFAULT_SIZES);
147 caller_cxt = MemoryContextSwitchTo(config_cxt);
150 * Read and apply the config file. We don't need to examine the result.
152 (void) ProcessConfigFileInternal(context, true, elevel);
155 MemoryContextSwitchTo(caller_cxt);
156 MemoryContextDelete(config_cxt);
160 * Read and parse a single configuration file. This function recurses
161 * to handle "include" directives.
163 * If "strict" is true, treat failure to open the config file as an error,
164 * otherwise just skip the file.
166 * calling_file/calling_lineno identify the source of the request.
167 * Pass NULL/0 if not recursing from an inclusion request.
169 * See ParseConfigFp for further details. This one merely adds opening the
170 * config file rather than working from a caller-supplied file descriptor,
171 * and absolute-ifying the path name if necessary.
174 ParseConfigFile(const char *config_file, bool strict,
175 const char *calling_file, int calling_lineno,
176 int depth, int elevel,
177 ConfigVariable **head_p,
178 ConfigVariable **tail_p)
185 * Reject file name that is all-blank (including empty), as that leads to
186 * confusion --- we'd try to read the containing directory as a file.
188 if (strspn(config_file, " \t\r\n") == strlen(config_file))
191 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
192 errmsg("empty configuration file name: \"%s\"",
194 record_config_file_error("empty configuration file name",
195 calling_file, calling_lineno,
201 * Reject too-deep include nesting depth. This is just a safety check to
202 * avoid dumping core due to stack overflow if an include file loops back
203 * to itself. The maximum nesting depth is pretty arbitrary.
205 if (depth > CONF_FILE_MAX_DEPTH)
208 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
209 errmsg("could not open configuration file \"%s\": maximum nesting depth exceeded",
211 record_config_file_error("nesting depth exceeded",
212 calling_file, calling_lineno,
217 abs_path = AbsoluteConfigLocation(config_file, calling_file);
220 * Reject direct recursion. Indirect recursion is also possible, but it's
221 * harder to detect and so doesn't seem worth the trouble. (We test at
222 * this step because the canonicalization done by AbsoluteConfigLocation
223 * makes it more likely that a simple strcmp comparison will match.)
225 if (calling_file && strcmp(abs_path, calling_file) == 0)
228 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
229 errmsg("configuration file recursion in \"%s\"",
231 record_config_file_error("configuration file recursion",
232 calling_file, calling_lineno,
238 fp = AllocateFile(abs_path, "r");
244 (errcode_for_file_access(),
245 errmsg("could not open configuration file \"%s\": %m",
247 record_config_file_error(psprintf("could not open file \"%s\"",
249 calling_file, calling_lineno,
256 (errmsg("skipping missing configuration file \"%s\"",
262 OK = ParseConfigFp(fp, abs_path, depth, elevel, head_p, tail_p);
273 * Capture an error message in the ConfigVariable list returned by
274 * config file parsing.
277 record_config_file_error(const char *errmsg,
278 const char *config_file,
280 ConfigVariable **head_p,
281 ConfigVariable **tail_p)
283 ConfigVariable *item;
285 item = palloc(sizeof *item);
288 item->errmsg = pstrdup(errmsg);
289 item->filename = config_file ? pstrdup(config_file) : NULL;
290 item->sourceline = lineno;
292 item->applied = false;
297 (*tail_p)->next = item;
302 * Flex fatal errors bring us here. Stash the error message and jump back to
303 * ParseConfigFp(). Assume all msg arguments point to string constants; this
304 * holds for flex 2.5.35 (earliest we support). Otherwise, we would need to
307 * We return "int" since this takes the place of calls to fprintf().
310 GUC_flex_fatal(const char *msg)
312 GUC_flex_fatal_errmsg = msg;
313 siglongjmp(*GUC_flex_fatal_jmp, 1);
314 return 0; /* keep compiler quiet */
318 * Read and parse a single configuration file. This function recurses
319 * to handle "include" directives.
322 * fp: file pointer from AllocateFile for the configuration file to parse
323 * config_file: absolute or relative path name of the configuration file
324 * depth: recursion depth (should be CONF_FILE_START_DEPTH in the outermost
326 * elevel: error logging level to use
327 * Input/Output parameters:
328 * head_p, tail_p: head and tail of linked list of name/value pairs
330 * *head_p and *tail_p must be initialized, either to NULL or valid pointers
331 * to a ConfigVariable list, before calling the outer recursion level. Any
332 * name-value pairs read from the input file(s) will be appended to the list.
333 * Error reports will also be appended to the list, if elevel < ERROR.
335 * Returns TRUE if successful, FALSE if an error occurred. The error has
336 * already been ereport'd, it is only necessary for the caller to clean up
337 * its own state and release the ConfigVariable list.
339 * Note: if elevel >= ERROR then an error will not return control to the
340 * caller, so there is no need to check the return value in that case.
342 * Note: this function is used to parse not only postgresql.conf, but
343 * various other configuration files that use the same "name = value"
344 * syntax. Hence, do not do anything here or in the subsidiary routines
345 * ParseConfigFile/ParseConfigDirectory that assumes we are processing
349 ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
350 ConfigVariable **head_p, ConfigVariable **tail_p)
352 volatile bool OK = true;
353 unsigned int save_ConfigFileLineno = ConfigFileLineno;
354 sigjmp_buf *save_GUC_flex_fatal_jmp = GUC_flex_fatal_jmp;
355 sigjmp_buf flex_fatal_jmp;
356 volatile YY_BUFFER_STATE lex_buffer = NULL;
360 if (sigsetjmp(flex_fatal_jmp, 1) == 0)
361 GUC_flex_fatal_jmp = &flex_fatal_jmp;
365 * Regain control after a fatal, internal flex error. It may have
366 * corrupted parser state. Consequently, abandon the file, but trust
367 * that the state remains sane enough for yy_delete_buffer().
369 elog(elevel, "%s at file \"%s\" line %u",
370 GUC_flex_fatal_errmsg, config_file, ConfigFileLineno);
371 record_config_file_error(GUC_flex_fatal_errmsg,
372 config_file, ConfigFileLineno,
381 ConfigFileLineno = 1;
384 lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
385 yy_switch_to_buffer(lex_buffer);
387 /* This loop iterates once per logical line */
388 while ((token = yylex()))
390 char *opt_name = NULL;
391 char *opt_value = NULL;
392 ConfigVariable *item;
394 if (token == GUC_EOL) /* empty or comment line */
397 /* first token on line is option name */
398 if (token != GUC_ID && token != GUC_QUALIFIED_ID)
400 opt_name = pstrdup(yytext);
402 /* next we have an optional equal sign; discard if present */
404 if (token == GUC_EQUALS)
407 /* now we must have the option value */
408 if (token != GUC_ID &&
409 token != GUC_STRING &&
410 token != GUC_INTEGER &&
412 token != GUC_UNQUOTED_STRING)
414 if (token == GUC_STRING) /* strip quotes and escapes */
415 opt_value = DeescapeQuotedString(yytext);
417 opt_value = pstrdup(yytext);
419 /* now we'd like an end of line, or possibly EOF */
421 if (token != GUC_EOL)
425 /* treat EOF like \n for line numbering purposes, cf bug 4752 */
429 /* OK, process the option name and value */
430 if (guc_name_compare(opt_name, "include_dir") == 0)
433 * An include_dir directive isn't a variable and should be
434 * processed immediately.
436 if (!ParseConfigDirectory(opt_value,
437 config_file, ConfigFileLineno - 1,
441 yy_switch_to_buffer(lex_buffer);
445 else if (guc_name_compare(opt_name, "include_if_exists") == 0)
448 * An include_if_exists directive isn't a variable and should be
449 * processed immediately.
451 if (!ParseConfigFile(opt_value, false,
452 config_file, ConfigFileLineno - 1,
456 yy_switch_to_buffer(lex_buffer);
460 else if (guc_name_compare(opt_name, "include") == 0)
463 * An include directive isn't a variable and should be processed
466 if (!ParseConfigFile(opt_value, true,
467 config_file, ConfigFileLineno - 1,
471 yy_switch_to_buffer(lex_buffer);
477 /* ordinary variable, append to list */
478 item = palloc(sizeof *item);
479 item->name = opt_name;
480 item->value = opt_value;
482 item->filename = pstrdup(config_file);
483 item->sourceline = ConfigFileLineno - 1;
484 item->ignore = false;
485 item->applied = false;
490 (*tail_p)->next = item;
494 /* break out of loop if read EOF, else loop for next line */
500 /* release storage if we allocated any on this line */
506 /* report the error */
507 if (token == GUC_EOL || token == 0)
510 (errcode(ERRCODE_SYNTAX_ERROR),
511 errmsg("syntax error in file \"%s\" line %u, near end of line",
512 config_file, ConfigFileLineno - 1)));
513 record_config_file_error("syntax error",
514 config_file, ConfigFileLineno - 1,
520 (errcode(ERRCODE_SYNTAX_ERROR),
521 errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
522 config_file, ConfigFileLineno, yytext)));
523 record_config_file_error("syntax error",
524 config_file, ConfigFileLineno,
531 * To avoid producing too much noise when fed a totally bogus file,
532 * give up after 100 syntax errors per file (an arbitrary number).
533 * Also, if we're only logging the errors at DEBUG level anyway, might
534 * as well give up immediately. (This prevents postmaster children
535 * from bloating the logs with duplicate complaints.)
537 if (errorcount >= 100 || elevel <= DEBUG1)
540 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
541 errmsg("too many syntax errors found, abandoning file \"%s\"",
546 /* resync to next end-of-line or EOF */
547 while (token != GUC_EOL && token != 0)
549 /* break out of loop on EOF */
555 yy_delete_buffer(lex_buffer);
556 /* Each recursion level must save and restore these static variables. */
557 ConfigFileLineno = save_ConfigFileLineno;
558 GUC_flex_fatal_jmp = save_GUC_flex_fatal_jmp;
563 * Read and parse all config files in a subdirectory in alphabetical order
565 * includedir is the absolute or relative path to the subdirectory to scan.
567 * calling_file/calling_lineno identify the source of the request.
568 * Pass NULL/0 if not recursing from an inclusion request.
570 * See ParseConfigFp for further details.
573 ParseConfigDirectory(const char *includedir,
574 const char *calling_file, int calling_lineno,
575 int depth, int elevel,
576 ConfigVariable **head_p,
577 ConfigVariable **tail_p)
583 filenames = GetConfFilesInDir(includedir, calling_file, elevel,
584 &num_filenames, &err_msg);
588 record_config_file_error(err_msg, calling_file, calling_lineno, head_p,
593 for (int i = 0; i < num_filenames; i++)
595 if (!ParseConfigFile(filenames[i], true,
596 calling_file, calling_lineno,
606 * Free a list of ConfigVariables, including the names and the values
609 FreeConfigVariables(ConfigVariable *list)
611 ConfigVariable *item;
616 ConfigVariable *next = item->next;
618 FreeConfigVariable(item);
624 * Free a single ConfigVariable
627 FreeConfigVariable(ConfigVariable *item)
636 pfree(item->filename);
642 * DeescapeQuotedString
644 * Strip the quotes surrounding the given string, and collapse any embedded
645 * '' sequences and backslash escapes.
647 * The string returned is palloc'd and should eventually be pfree'd by the
650 * This is exported because it is also used by the bootstrap scanner.
653 DeescapeQuotedString(const char *s)
660 /* We just Assert that there are leading and trailing quotes */
661 Assert(s != NULL && s[0] == '\'');
664 Assert(s[len - 1] == '\'');
666 /* Skip the leading quote; we'll handle the trailing quote below */
669 /* Since len still includes trailing quote, this is enough space */
670 newStr = palloc(len);
672 for (i = 0, j = 0; i < len; i++)
707 s[i + k] >= '0' && s[i + k] <= '7' && k < 3;
709 octVal = (octVal << 3) + (s[i + k] - '0');
711 newStr[j] = ((char) octVal);
719 else if (s[i] == '\'' && s[i + 1] == '\'')
721 /* doubled quote becomes just one quote */
729 /* We copied the ending quote to newStr, so replace with \0 */
730 Assert(j > 0 && j <= len);