Age Owner TLA Line data Source code
1 : %top{
2 : /*
3 : * Scanner for the configuration file
4 : *
5 : * Copyright (c) 2000-2023, PostgreSQL Global Development Group
6 : *
7 : * src/backend/utils/misc/guc-file.l
8 : */
9 :
10 : #include "postgres.h"
11 :
12 : #include <ctype.h>
13 : #include <unistd.h>
14 :
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"
22 : }
23 :
24 :
25 : %{
26 : /*
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.
31 : */
32 : #undef fprintf
33 : #define fprintf(file, fmt, msg) GUC_flex_fatal(msg)
34 :
35 : enum
36 : {
37 : GUC_ID = 1,
38 : GUC_STRING = 2,
39 : GUC_INTEGER = 3,
40 : GUC_REAL = 4,
41 : GUC_EQUALS = 5,
42 : GUC_UNQUOTED_STRING = 6,
43 : GUC_QUALIFIED_ID = 7,
44 : GUC_EOL = 99,
45 : GUC_ERROR = 100
46 : };
47 :
48 : static unsigned int ConfigFileLineno;
49 : static const char *GUC_flex_fatal_errmsg;
50 : static sigjmp_buf *GUC_flex_fatal_jmp;
51 :
52 : static void FreeConfigVariable(ConfigVariable *item);
53 :
54 : static int GUC_flex_fatal(const char *msg);
55 :
56 : /* LCOV_EXCL_START */
57 :
58 : %}
59 :
60 : %option 8bit
61 : %option never-interactive
62 : %option nodefault
63 : %option noinput
64 : %option nounput
65 : %option noyywrap
66 : %option warn
67 : %option prefix="GUC_yy"
68 :
69 :
70 : SIGN ("-"|"+")
71 : DIGIT [0-9]
72 : HEXDIGIT [0-9a-fA-F]
73 :
74 : UNIT_LETTER [a-zA-Z]
75 :
76 : INTEGER {SIGN}?({DIGIT}+|0x{HEXDIGIT}+){UNIT_LETTER}*
77 :
78 : EXPONENT [Ee]{SIGN}?{DIGIT}+
79 : REAL {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}?
80 :
81 : LETTER [A-Za-z_\200-\377]
82 : LETTER_OR_DIGIT [A-Za-z_0-9\200-\377]
83 :
84 : ID {LETTER}{LETTER_OR_DIGIT}*
85 : QUALIFIED_ID {ID}"."{ID}
86 :
87 : UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
88 : STRING \'([^'\\\n]|\\.|\'\')*\'
8348 peter_e 89 ECB :
90 : %%
91 :
4177 peter_e 92 CBC 2331748 : \n ConfigFileLineno++; return GUC_EOL;
4177 peter_e 93 ECB : [ \t\r]+ /* eat whitespace */
4177 peter_e 94 CBC 797778 : #.* /* eat comment (.* matches anything until newline) */
8348 95 1895729 :
4177 96 84451 : {ID} return GUC_ID;
4177 peter_e 97 GBC 41 : {QUALIFIED_ID} return GUC_QUALIFIED_ID;
4177 peter_e 98 CBC 41 : {STRING} return GUC_STRING;
8179 bruce 99 GBC 31804 : {UNQUOTED_STRING} return GUC_UNQUOTED_STRING;
4177 peter_e 100 LBC 0 : {INTEGER} return GUC_INTEGER;
4177 peter_e 101 GBC 19838 : {REAL} return GUC_REAL;
4177 peter_e 102 UIC 0 : = return GUC_EQUALS;
8348 peter_e 103 GBC 68015 :
4177 peter_e 104 UIC 0 : . return GUC_ERROR;
105 :
8348 106 0 : %%
107 :
108 : /* LCOV_EXCL_STOP */
109 :
110 : /*
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
2842 tgl 116 ECB : * errors that prevent just one value from being changed.)
117 : */
118 : void
6795 tgl 119 GIC 4004 : ProcessConfigFile(GucContext context)
120 : {
121 : int elevel;
122 : MemoryContext config_cxt;
123 : MemoryContext caller_cxt;
124 :
125 : /*
2842 tgl 126 ECB : * Config files are processed on startup (by the postmaster only) and on
127 : * SIGHUP (by the postmaster and its children)
128 : */
4207 tgl 129 GIC 4004 : Assert((context == PGC_POSTMASTER && !IsUnderPostmaster) ||
130 : context == PGC_SIGHUP);
131 :
132 : /*
2842 tgl 133 ECB : * To avoid cluttering the log, only the postmaster bleats loudly about
134 : * problems with the config file.
135 : */
4207 tgl 136 GIC 4004 : elevel = IsUnderPostmaster ? DEBUG2 : LOG;
137 :
138 : /*
139 : * This function is usually called within a process-lifespan memory
140 : * context. To ensure that any memory leaked during GUC processing does
2842 tgl 141 ECB : * not accumulate across repeated SIGHUP cycles, do the work in a private
142 : * context that we can free at exit.
143 : */
2842 tgl 144 CBC 4004 : config_cxt = AllocSetContextCreate(CurrentMemoryContext,
145 : "config file processing",
146 : ALLOCSET_DEFAULT_SIZES);
2842 tgl 147 GIC 4004 : caller_cxt = MemoryContextSwitchTo(config_cxt);
148 :
2842 tgl 149 ECB : /*
150 : * Read and apply the config file. We don't need to examine the result.
151 : */
2842 tgl 152 CBC 4004 : (void) ProcessConfigFileInternal(context, true, elevel);
2842 tgl 153 ECB :
154 : /* Clean up */
2842 tgl 155 GIC 4002 : MemoryContextSwitchTo(caller_cxt);
156 4002 : MemoryContextDelete(config_cxt);
157 4002 : }
158 :
159 : /*
160 : * Read and parse a single configuration file. This function recurses
4207 tgl 161 EUB : * to handle "include" directives.
162 : *
163 : * If "strict" is true, treat failure to open the config file as an error,
2996 164 : * otherwise just skip the file.
165 : *
166 : * calling_file/calling_lineno identify the source of the request.
167 : * Pass NULL/0 if not recursing from an inclusion request.
2842 tgl 168 ECB : *
2996 169 : * See ParseConfigFp for further details. This one merely adds opening the
170 : * config file rather than working from a caller-supplied file descriptor,
4207 171 : * and absolute-ifying the path name if necessary.
6245 172 : */
4510 rhaas 173 : bool
2842 tgl 174 GIC 6233 : 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)
179 : {
180 : char *abs_path;
6082 bruce 181 6233 : bool OK = true;
182 : FILE *fp;
183 :
184 : /*
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.
1321 tgl 187 EUB : */
1321 tgl 188 GIC 6233 : if (strspn(config_file, " \t\r\n") == strlen(config_file))
189 : {
1321 tgl 190 UIC 0 : ereport(elevel,
191 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
192 : errmsg("empty configuration file name: \"%s\"",
193 : config_file)));
194 0 : record_config_file_error("empty configuration file name",
195 : calling_file, calling_lineno,
196 : head_p, tail_p);
1321 tgl 197 UBC 0 : return false;
198 : }
199 :
6245 tgl 200 EUB : /*
201 : * Reject too-deep include nesting depth. This is just a safety check to
2842 202 : * avoid dumping core due to stack overflow if an include file loops back
203 : * to itself. The maximum nesting depth is pretty arbitrary.
6245 204 : */
135 michael 205 GNC 6233 : if (depth > CONF_FILE_MAX_DEPTH)
206 : {
6245 tgl 207 UBC 0 : ereport(elevel,
208 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
6245 tgl 209 EUB : errmsg("could not open configuration file \"%s\": maximum nesting depth exceeded",
210 : config_file)));
2842 tgl 211 UIC 0 : record_config_file_error("nesting depth exceeded",
212 : calling_file, calling_lineno,
2842 tgl 213 EUB : head_p, tail_p);
6245 tgl 214 UIC 0 : return false;
215 : }
6245 tgl 216 EUB :
3454 heikki.linnakangas 217 GIC 6233 : abs_path = AbsoluteConfigLocation(config_file, calling_file);
218 :
219 : /*
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
1321 tgl 223 ECB : * makes it more likely that a simple strcmp comparison will match.)
224 : */
1321 tgl 225 GIC 6233 : if (calling_file && strcmp(abs_path, calling_file) == 0)
226 : {
1321 tgl 227 LBC 0 : ereport(elevel,
1321 tgl 228 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
229 : errmsg("configuration file recursion in \"%s\"",
230 : calling_file)));
1321 tgl 231 UIC 0 : record_config_file_error("configuration file recursion",
1321 tgl 232 ECB : calling_file, calling_lineno,
233 : head_p, tail_p);
1321 tgl 234 UIC 0 : pfree(abs_path);
1321 tgl 235 LBC 0 : return false;
236 : }
237 :
3454 heikki.linnakangas 238 GIC 6233 : fp = AllocateFile(abs_path, "r");
6307 tgl 239 6233 : if (!fp)
240 : {
4133 andrew 241 CBC 610 : if (strict)
242 : {
4133 andrew 243 LBC 0 : ereport(elevel,
4133 andrew 244 ECB : (errcode_for_file_access(),
245 : errmsg("could not open configuration file \"%s\": %m",
3454 heikki.linnakangas 246 : abs_path)));
2842 tgl 247 LBC 0 : record_config_file_error(psprintf("could not open file \"%s\"",
2842 tgl 248 EUB : abs_path),
2842 tgl 249 ECB : calling_file, calling_lineno,
250 : head_p, tail_p);
3365 rhaas 251 LBC 0 : OK = false;
4133 andrew 252 ECB : }
253 : else
254 : {
2996 tgl 255 GIC 610 : ereport(LOG,
256 : (errmsg("skipping missing configuration file \"%s\"",
257 : abs_path)));
258 : }
3365 rhaas 259 610 : goto cleanup;
260 : }
261 :
3454 heikki.linnakangas 262 5623 : OK = ParseConfigFp(fp, abs_path, depth, elevel, head_p, tail_p);
263 :
3365 rhaas 264 6233 : cleanup:
265 6233 : if (fp)
266 5623 : FreeFile(fp);
3454 heikki.linnakangas 267 CBC 6233 : pfree(abs_path);
268 :
4510 rhaas 269 GIC 6233 : return OK;
270 : }
271 :
272 : /*
273 : * Capture an error message in the ConfigVariable list returned by
274 : * config file parsing.
2842 tgl 275 ECB : */
276 : void
2842 tgl 277 LBC 0 : record_config_file_error(const char *errmsg,
2842 tgl 278 ECB : const char *config_file,
279 : int lineno,
280 : ConfigVariable **head_p,
281 : ConfigVariable **tail_p)
282 : {
283 : ConfigVariable *item;
284 :
2842 tgl 285 UIC 0 : item = palloc(sizeof *item);
2842 tgl 286 LBC 0 : item->name = NULL;
2842 tgl 287 UIC 0 : item->value = NULL;
2842 tgl 288 LBC 0 : item->errmsg = pstrdup(errmsg);
2842 tgl 289 UIC 0 : item->filename = config_file ? pstrdup(config_file) : NULL;
2842 tgl 290 UBC 0 : item->sourceline = lineno;
291 0 : item->ignore = true;
2842 tgl 292 UIC 0 : item->applied = false;
2842 tgl 293 UBC 0 : item->next = NULL;
294 0 : if (*head_p == NULL)
295 0 : *head_p = item;
2842 tgl 296 EUB : else
2842 tgl 297 UBC 0 : (*tail_p)->next = item;
298 0 : *tail_p = item;
299 0 : }
2842 tgl 300 EUB :
4100 rhaas 301 : /*
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
305 : * copy the message.
306 : *
307 : * We return "int" since this takes the place of calls to fprintf().
308 : */
309 : static int
4100 rhaas 310 UIC 0 : GUC_flex_fatal(const char *msg)
311 : {
312 0 : GUC_flex_fatal_errmsg = msg;
313 0 : siglongjmp(*GUC_flex_fatal_jmp, 1);
314 : return 0; /* keep compiler quiet */
315 : }
316 :
317 : /*
4510 rhaas 318 EUB : * Read and parse a single configuration file. This function recurses
319 : * to handle "include" directives.
320 : *
321 : * Input parameters:
322 : * fp: file pointer from AllocateFile for the configuration file to parse
4207 tgl 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
325 : * call)
326 : * elevel: error logging level to use
327 : * Input/Output parameters:
4510 rhaas 328 : * head_p, tail_p: head and tail of linked list of name/value pairs
329 : *
2842 tgl 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.
4510 rhaas 334 ECB : *
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
4207 tgl 337 : * its own state and release the ConfigVariable list.
338 : *
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.
2842 341 : *
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
346 : * GUCs specifically.
347 : */
4510 rhaas 348 : bool
4510 rhaas 349 GIC 7329 : ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
350 : ConfigVariable **head_p, ConfigVariable **tail_p)
351 : {
4093 tgl 352 7329 : volatile bool OK = true;
4100 rhaas 353 7329 : unsigned int save_ConfigFileLineno = ConfigFileLineno;
354 7329 : sigjmp_buf *save_GUC_flex_fatal_jmp = GUC_flex_fatal_jmp;
355 : sigjmp_buf flex_fatal_jmp;
356 7329 : volatile YY_BUFFER_STATE lex_buffer = NULL;
357 : int errorcount;
358 : int token;
359 :
360 7329 : if (sigsetjmp(flex_fatal_jmp, 1) == 0)
361 7329 : GUC_flex_fatal_jmp = &flex_fatal_jmp;
362 : else
363 : {
364 : /*
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().
368 : */
4100 rhaas 369 UIC 0 : elog(elevel, "%s at file \"%s\" line %u",
370 : GUC_flex_fatal_errmsg, config_file, ConfigFileLineno);
2842 tgl 371 0 : record_config_file_error(GUC_flex_fatal_errmsg,
372 : config_file, ConfigFileLineno,
373 : head_p, tail_p);
4100 rhaas 374 0 : OK = false;
375 0 : goto cleanup;
376 : }
377 :
378 : /*
379 : * Parse
380 : */
6795 tgl 381 GIC 7329 : ConfigFileLineno = 1;
4207 382 7329 : errorcount = 0;
383 :
4100 rhaas 384 7329 : lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
385 7329 : yy_switch_to_buffer(lex_buffer);
386 :
387 : /* This loop iterates once per logical line */
6307 tgl 388 2339077 : while ((token = yylex()))
6795 389 68067 : {
4207 390 2331748 : char *opt_name = NULL;
391 2331748 : char *opt_value = NULL;
392 : ConfigVariable *item;
393 :
6307 394 2331748 : if (token == GUC_EOL) /* empty or comment line */
395 2263681 : continue;
396 :
397 : /* first token on line is option name */
398 68067 : if (token != GUC_ID && token != GUC_QUALIFIED_ID)
6307 tgl 399 UIC 0 : goto parse_error;
6307 tgl 400 GIC 68067 : opt_name = pstrdup(yytext);
401 :
402 : /* next we have an optional equal sign; discard if present */
403 68067 : token = yylex();
404 68067 : if (token == GUC_EQUALS)
405 68015 : token = yylex();
406 :
407 : /* now we must have the option value */
408 68067 : if (token != GUC_ID &&
4520 peter_e 409 19838 : token != GUC_STRING &&
4520 peter_e 410 UIC 0 : token != GUC_INTEGER &&
411 0 : token != GUC_REAL &&
412 : token != GUC_UNQUOTED_STRING)
6307 tgl 413 0 : goto parse_error;
6307 tgl 414 GIC 68067 : if (token == GUC_STRING) /* strip quotes and escapes */
917 415 31804 : opt_value = DeescapeQuotedString(yytext);
416 : else
6307 417 36263 : opt_value = pstrdup(yytext);
418 :
419 : /* now we'd like an end of line, or possibly EOF */
420 68067 : token = yylex();
5113 421 68067 : if (token != GUC_EOL)
422 : {
5113 tgl 423 UIC 0 : if (token != 0)
424 0 : goto parse_error;
425 : /* treat EOF like \n for line numbering purposes, cf bug 4752 */
426 0 : ConfigFileLineno++;
427 : }
428 :
429 : /* OK, process the option name and value */
3849 heikki.linnakangas 430 GIC 68067 : if (guc_name_compare(opt_name, "include_dir") == 0)
431 : {
432 : /*
433 : * An include_dir directive isn't a variable and should be
434 : * processed immediately.
435 : */
2842 tgl 436 UIC 0 : if (!ParseConfigDirectory(opt_value,
437 0 : config_file, ConfigFileLineno - 1,
438 : depth + 1, elevel,
439 : head_p, tail_p))
4133 andrew 440 0 : OK = false;
441 0 : yy_switch_to_buffer(lex_buffer);
442 0 : pfree(opt_name);
443 0 : pfree(opt_value);
444 : }
3849 heikki.linnakangas 445 GIC 68067 : else if (guc_name_compare(opt_name, "include_if_exists") == 0)
446 : {
447 : /*
448 : * An include_if_exists directive isn't a variable and should be
449 : * processed immediately.
450 : */
2842 tgl 451 UIC 0 : if (!ParseConfigFile(opt_value, false,
452 0 : config_file, ConfigFileLineno - 1,
453 : depth + 1, elevel,
454 : head_p, tail_p))
3849 heikki.linnakangas 455 0 : OK = false;
3539 alvherre 456 0 : yy_switch_to_buffer(lex_buffer);
457 0 : pfree(opt_name);
458 0 : pfree(opt_value);
459 : }
4133 andrew 460 GIC 68067 : else if (guc_name_compare(opt_name, "include") == 0)
461 : {
462 : /*
463 : * An include directive isn't a variable and should be processed
464 : * immediately.
465 : */
2842 tgl 466 52 : if (!ParseConfigFile(opt_value, true,
467 52 : config_file, ConfigFileLineno - 1,
468 : depth + 1, elevel,
469 : head_p, tail_p))
6245 tgl 470 UIC 0 : OK = false;
6245 tgl 471 GIC 52 : yy_switch_to_buffer(lex_buffer);
472 52 : pfree(opt_name);
473 52 : pfree(opt_value);
474 : }
475 : else
476 : {
477 : /* ordinary variable, append to list */
6307 478 68015 : item = palloc(sizeof *item);
479 68015 : item->name = opt_name;
480 68015 : item->value = opt_value;
2842 481 68015 : item->errmsg = NULL;
5324 alvherre 482 68015 : item->filename = pstrdup(config_file);
2842 tgl 483 68015 : item->sourceline = ConfigFileLineno - 1;
484 68015 : item->ignore = false;
485 68015 : item->applied = false;
6307 486 68015 : item->next = NULL;
6245 487 68015 : if (*head_p == NULL)
488 4472 : *head_p = item;
489 : else
490 63543 : (*tail_p)->next = item;
491 68015 : *tail_p = item;
492 : }
493 :
494 : /* break out of loop if read EOF, else loop for next line */
6307 495 68067 : if (token == 0)
6307 tgl 496 UIC 0 : break;
4207 tgl 497 GIC 68067 : continue;
498 :
2842 tgl 499 UIC 0 : parse_error:
500 : /* release storage if we allocated any on this line */
4207 501 0 : if (opt_name)
502 0 : pfree(opt_name);
503 0 : if (opt_value)
504 0 : pfree(opt_value);
505 :
506 : /* report the error */
507 0 : if (token == GUC_EOL || token == 0)
508 : {
509 0 : ereport(elevel,
510 : (errcode(ERRCODE_SYNTAX_ERROR),
511 : errmsg("syntax error in file \"%s\" line %u, near end of line",
512 : config_file, ConfigFileLineno - 1)));
2842 513 0 : record_config_file_error("syntax error",
514 0 : config_file, ConfigFileLineno - 1,
515 : head_p, tail_p);
516 : }
517 : else
518 : {
4207 519 0 : ereport(elevel,
520 : (errcode(ERRCODE_SYNTAX_ERROR),
521 : errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
522 : config_file, ConfigFileLineno, yytext)));
2842 523 0 : record_config_file_error("syntax error",
524 : config_file, ConfigFileLineno,
525 : head_p, tail_p);
526 : }
4207 527 0 : OK = false;
528 0 : errorcount++;
529 :
530 : /*
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.)
536 : */
537 0 : if (errorcount >= 100 || elevel <= DEBUG1)
538 : {
539 0 : ereport(elevel,
540 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
541 : errmsg("too many syntax errors found, abandoning file \"%s\"",
542 : config_file)));
543 0 : break;
544 : }
545 :
546 : /* resync to next end-of-line or EOF */
547 0 : while (token != GUC_EOL && token != 0)
548 0 : token = yylex();
549 : /* break out of loop on EOF */
550 0 : if (token == 0)
551 0 : break;
552 : }
553 :
4100 rhaas 554 GIC 7329 : cleanup:
6245 tgl 555 7329 : yy_delete_buffer(lex_buffer);
556 : /* Each recursion level must save and restore these static variables. */
4100 rhaas 557 7329 : ConfigFileLineno = save_ConfigFileLineno;
558 7329 : GUC_flex_fatal_jmp = save_GUC_flex_fatal_jmp;
6245 tgl 559 7329 : return OK;
560 : }
561 :
562 : /*
563 : * Read and parse all config files in a subdirectory in alphabetical order
564 : *
565 : * includedir is the absolute or relative path to the subdirectory to scan.
566 : *
567 : * calling_file/calling_lineno identify the source of the request.
568 : * Pass NULL/0 if not recursing from an inclusion request.
569 : *
570 : * See ParseConfigFp for further details.
571 : */
572 : bool
3849 heikki.linnakangas 573 UIC 0 : 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)
578 : {
579 : char *err_msg;
580 : char **filenames;
581 : int num_filenames;
582 :
153 michael 583 UNC 0 : filenames = GetConfFilesInDir(includedir, calling_file, elevel,
584 : &num_filenames, &err_msg);
585 :
586 0 : if (!filenames)
587 : {
588 0 : record_config_file_error(err_msg, calling_file, calling_lineno, head_p,
589 : tail_p);
153 michael 590 UIC 0 : return false;
591 : }
592 :
153 michael 593 UNC 0 : for (int i = 0; i < num_filenames; i++)
594 : {
595 0 : if (!ParseConfigFile(filenames[i], true,
596 : calling_file, calling_lineno,
597 : depth, elevel,
598 : head_p, tail_p))
599 0 : return false;
600 : }
601 :
602 0 : return true;
603 : }
604 :
605 : /*
606 : * Free a list of ConfigVariables, including the names and the values
607 : */
608 : void
4510 rhaas 609 GIC 1706 : FreeConfigVariables(ConfigVariable *list)
610 : {
611 : ConfigVariable *item;
612 :
6245 tgl 613 1706 : item = list;
614 9920 : while (item)
615 : {
4510 rhaas 616 8214 : ConfigVariable *next = item->next;
617 :
3162 fujii 618 8214 : FreeConfigVariable(item);
6245 tgl 619 8214 : item = next;
620 : }
621 1706 : }
622 :
623 : /*
624 : * Free a single ConfigVariable
625 : */
626 : static void
2996 627 8214 : FreeConfigVariable(ConfigVariable *item)
628 : {
2842 629 8214 : if (item->name)
630 8214 : pfree(item->name);
631 8214 : if (item->value)
632 8214 : pfree(item->value);
633 8214 : if (item->errmsg)
2842 tgl 634 UIC 0 : pfree(item->errmsg);
2842 tgl 635 GIC 8214 : if (item->filename)
636 8214 : pfree(item->filename);
2996 637 8214 : pfree(item);
638 8214 : }
639 :
640 :
641 : /*
642 : * DeescapeQuotedString
643 : *
644 : * Strip the quotes surrounding the given string, and collapse any embedded
645 : * '' sequences and backslash escapes.
646 : *
647 : * The string returned is palloc'd and should eventually be pfree'd by the
648 : * caller.
649 : *
650 : * This is exported because it is also used by the bootstrap scanner.
651 : */
652 : char *
917 653 2201266 : DeescapeQuotedString(const char *s)
654 : {
655 : char *newStr;
656 : int len,
657 : i,
658 : j;
659 :
660 : /* We just Assert that there are leading and trailing quotes */
6409 661 2201266 : Assert(s != NULL && s[0] == '\'');
8179 bruce 662 2201266 : len = strlen(s);
6409 tgl 663 2201266 : Assert(len >= 2);
2842 664 2201266 : Assert(s[len - 1] == '\'');
665 :
666 : /* Skip the leading quote; we'll handle the trailing quote below */
6409 667 2201266 : s++, len--;
668 :
669 : /* Since len still includes trailing quote, this is enough space */
670 2201266 : newStr = palloc(len);
671 :
8179 bruce 672 41322423 : for (i = 0, j = 0; i < len; i++)
673 : {
674 39121157 : if (s[i] == '\\')
675 : {
8179 bruce 676 UIC 0 : i++;
677 0 : switch (s[i])
678 : {
679 0 : case 'b':
680 0 : newStr[j] = '\b';
681 0 : break;
682 0 : case 'f':
683 0 : newStr[j] = '\f';
684 0 : break;
685 0 : case 'n':
686 0 : newStr[j] = '\n';
687 0 : break;
688 0 : case 'r':
689 0 : newStr[j] = '\r';
690 0 : break;
691 0 : case 't':
692 0 : newStr[j] = '\t';
693 0 : break;
694 0 : case '0':
695 : case '1':
696 : case '2':
697 : case '3':
698 : case '4':
699 : case '5':
700 : case '6':
701 : case '7':
702 : {
703 : int k;
704 0 : long octVal = 0;
705 :
706 0 : for (k = 0;
707 0 : s[i + k] >= '0' && s[i + k] <= '7' && k < 3;
708 0 : k++)
709 0 : octVal = (octVal << 3) + (s[i + k] - '0');
710 0 : i += k - 1;
711 0 : newStr[j] = ((char) octVal);
712 : }
713 0 : break;
714 0 : default:
715 0 : newStr[j] = s[i];
716 0 : break;
717 : } /* switch */
718 : }
2842 tgl 719 GIC 39121157 : else if (s[i] == '\'' && s[i + 1] == '\'')
720 : {
721 : /* doubled quote becomes just one quote */
6409 722 14660 : newStr[j] = s[++i];
723 : }
724 : else
8179 bruce 725 39106497 : newStr[j] = s[i];
726 39121157 : j++;
727 : }
728 :
729 : /* We copied the ending quote to newStr, so replace with \0 */
6409 tgl 730 2201266 : Assert(j > 0 && j <= len);
731 2201266 : newStr[--j] = '\0';
732 :
8179 bruce 733 2201266 : return newStr;
734 : }
|