3 * Scanner for the configuration file
5 * Copyright (c) 2000-2006, PostgreSQL Global Development Group
7 * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.45 2006/08/14 02:27:26 momjian Exp $
17 #include "miscadmin.h"
18 #include "storage/fd.h"
19 #include "utils/guc.h"
22 /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
24 #define fprintf(file, fmt, msg) ereport(ERROR, (errmsg_internal("%s", msg)))
32 GUC_UNQUOTED_STRING = 6,
38 struct name_value_pair
42 struct name_value_pair *next;
45 static unsigned int ConfigFileLineno;
47 /* flex fails to supply a prototype for yylex, so provide one */
50 static bool ParseConfigFile(const char *config_file, const char *calling_file,
51 int depth, GucContext context, int elevel,
52 struct name_value_pair **head_p,
53 struct name_value_pair **tail_p);
54 static void free_name_value_list(struct name_value_pair * list);
55 static char *GUC_scanstr(const char *s);
60 %option never-interactive
64 %option prefix="GUC_yy"
73 INTEGER {SIGN}?({DIGIT}+|0x{HEXDIGIT}+){UNIT_LETTER}*
75 EXPONENT [Ee]{SIGN}?{DIGIT}+
76 REAL {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}?
78 LETTER [A-Za-z_\200-\377]
79 LETTER_OR_DIGIT [A-Za-z_0-9\200-\377]
81 ID {LETTER}{LETTER_OR_DIGIT}*
82 QUALIFIED_ID {ID}"."{ID}
84 UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
85 STRING \'([^'\\\n]|\\.|\'\')*\'
89 \n ConfigFileLineno++; return GUC_EOL;
90 [ \t\r]+ /* eat whitespace */
91 #.* /* eat comment (.* matches anything until newline) */
94 {QUALIFIED_ID} return GUC_QUALIFIED_ID;
95 {STRING} return GUC_STRING;
96 {UNQUOTED_STRING} return GUC_UNQUOTED_STRING;
97 {INTEGER} return GUC_INTEGER;
98 {REAL} return GUC_REAL;
108 * Exported function to read and process the configuration file. The
109 * parameter indicates in what context the file is being read --- either
110 * postmaster startup (including standalone-backend startup) or SIGHUP.
111 * All options mentioned in the configuration file are set to new values.
112 * If an error occurs, no values will be changed.
115 ProcessConfigFile(GucContext context)
118 struct name_value_pair *item, *head, *tail;
120 Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
122 if (context == PGC_SIGHUP)
125 * To avoid cluttering the log, only the postmaster bleats loudly
126 * about problems with the config file.
128 elevel = IsUnderPostmaster ? DEBUG2 : LOG;
135 if (!ParseConfigFile(ConfigFileName, NULL,
140 /* Check if all options are valid */
141 for (item = head; item; item = item->next)
143 if (!set_config_option(item->name, item->value, context,
144 PGC_S_FILE, false, false))
148 /* If we got here all the options checked out okay, so apply them. */
149 for (item = head; item; item = item->next)
151 set_config_option(item->name, item->value, context,
152 PGC_S_FILE, false, true);
156 free_name_value_list(head);
161 * Read and parse a single configuration file. This function recurses
162 * to handle "include" directives.
165 * config_file: absolute or relative path of file to read
166 * calling_file: absolute path of file containing the "include" directive,
167 * or NULL at outer level (config_file must be absolute at outer level)
168 * depth: recursion depth (used only to prevent infinite recursion)
169 * context: GucContext passed to ProcessConfigFile()
170 * elevel: error logging level determined by ProcessConfigFile()
172 * head_p, tail_p: head and tail of linked list of name/value pairs
174 * *head_p and *tail_p must be initialized to NULL before calling the outer
175 * recursion level. On exit, they contain a list of name-value pairs read
176 * from the input file(s).
178 * Returns TRUE if successful, FALSE if an error occurred. The error has
179 * already been ereport'd, it is only necessary for the caller to clean up
180 * its own state and release the name/value pairs list.
182 * Note: if elevel >= ERROR then an error will not return control to the
183 * caller, and internal state such as open files will not be cleaned up.
184 * This case occurs only during postmaster or standalone-backend startup,
185 * where an error will lead to immediate process exit anyway; so there is
186 * no point in contorting the code so it can clean up nicely.
189 ParseConfigFile(const char *config_file, const char *calling_file,
190 int depth, GucContext context, int elevel,
191 struct name_value_pair **head_p,
192 struct name_value_pair **tail_p)
195 char abs_path[MAXPGPATH];
197 YY_BUFFER_STATE lex_buffer;
201 * Reject too-deep include nesting depth. This is just a safety check
202 * to avoid dumping core due to stack overflow if an include file loops
203 * back to itself. The maximum nesting depth is pretty arbitrary.
208 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
209 errmsg("could not open configuration file \"%s\": maximum nesting depth exceeded",
215 * If config_file is a relative path, convert to absolute. We consider
216 * it to be relative to the directory holding the calling file.
218 if (!is_absolute_path(config_file))
220 Assert(calling_file != NULL);
221 StrNCpy(abs_path, calling_file, MAXPGPATH);
222 get_parent_directory(abs_path);
223 join_path_components(abs_path, abs_path, config_file);
224 canonicalize_path(abs_path);
225 config_file = abs_path;
228 fp = AllocateFile(config_file, "r");
232 (errcode_for_file_access(),
233 errmsg("could not open configuration file \"%s\": %m",
241 lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
242 yy_switch_to_buffer(lex_buffer);
244 ConfigFileLineno = 1;
246 /* This loop iterates once per logical line */
247 while ((token = yylex()))
249 char *opt_name, *opt_value;
251 if (token == GUC_EOL) /* empty or comment line */
254 /* first token on line is option name */
255 if (token != GUC_ID && token != GUC_QUALIFIED_ID)
257 opt_name = pstrdup(yytext);
259 /* next we have an optional equal sign; discard if present */
261 if (token == GUC_EQUALS)
264 /* now we must have the option value */
265 if (token != GUC_ID &&
266 token != GUC_STRING &&
267 token != GUC_INTEGER &&
269 token != GUC_UNQUOTED_STRING)
271 if (token == GUC_STRING) /* strip quotes and escapes */
272 opt_value = GUC_scanstr(yytext);
274 opt_value = pstrdup(yytext);
276 /* now we'd like an end of line, or possibly EOF */
278 if (token != GUC_EOL && token != 0)
281 /* OK, process the option name and value */
282 if (pg_strcasecmp(opt_name, "include") == 0)
285 * An include directive isn't a variable and should be processed
288 unsigned int save_ConfigFileLineno = ConfigFileLineno;
290 if (!ParseConfigFile(opt_value, config_file,
291 depth + 1, context, elevel,
299 yy_switch_to_buffer(lex_buffer);
300 ConfigFileLineno = save_ConfigFileLineno;
304 else if (pg_strcasecmp(opt_name, "custom_variable_classes") == 0)
307 * This variable must be processed first as it controls
308 * the validity of other variables; so apply immediately.
310 if (!set_config_option(opt_name, opt_value, context,
311 PGC_S_FILE, false, true))
315 /* we assume error message was logged already */
325 struct name_value_pair *item;
327 item = palloc(sizeof *item);
328 item->name = opt_name;
329 item->value = opt_value;
334 (*tail_p)->next = item;
338 /* break out of loop if read EOF, else loop for next line */
343 /* successful completion of parsing */
347 if (token == GUC_EOL || token == 0)
349 (errcode(ERRCODE_SYNTAX_ERROR),
350 errmsg("syntax error in file \"%s\" line %u, near end of line",
351 config_file, ConfigFileLineno - 1)));
354 (errcode(ERRCODE_SYNTAX_ERROR),
355 errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
356 config_file, ConfigFileLineno, yytext)));
360 yy_delete_buffer(lex_buffer);
367 * Free a list of name/value pairs, including the names and the values
370 free_name_value_list(struct name_value_pair *list)
372 struct name_value_pair *item;
377 struct name_value_pair *next = item->next;
390 * Strip the quotes surrounding the given string, and collapse any embedded
391 * '' sequences and backslash escapes.
393 * the string returned is palloc'd and should eventually be pfree'd by the
397 GUC_scanstr(const char *s)
404 Assert(s != NULL && s[0] == '\'');
407 Assert(s[len-1] == '\'');
409 /* Skip the leading quote; we'll handle the trailing quote below */
412 /* Since len still includes trailing quote, this is enough space */
413 newStr = palloc(len);
415 for (i = 0, j = 0; i < len; i++)
450 s[i + k] >= '0' && s[i + k] <= '7' && k < 3;
452 octVal = (octVal << 3) + (s[i + k] - '0');
454 newStr[j] = ((char) octVal);
462 else if (s[i] == '\'' && s[i+1] == '\'')
464 /* doubled quote becomes just one quote */
472 /* We copied the ending quote to newStr, so replace with \0 */
473 Assert(j > 0 && j <= len);