LCOV - code coverage report
Current view: top level - src/backend/utils/misc - guc-file.l (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 187 357 52.4 %
Date: 2019-06-18 07:06:57 Functions: 8 11 72.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*-pgsql-c-*- */
       2             : /*
       3             :  * Scanner for the configuration file
       4             :  *
       5             :  * Copyright (c) 2000-2019, PostgreSQL Global Development Group
       6             :  *
       7             :  * src/backend/utils/misc/guc-file.l
       8             :  */
       9             : 
      10             : %{
      11             : 
      12             : #include "postgres.h"
      13             : 
      14             : #include <ctype.h>
      15             : #include <unistd.h>
      16             : 
      17             : #include "mb/pg_wchar.h"
      18             : #include "miscadmin.h"
      19             : #include "storage/fd.h"
      20             : #include "utils/guc.h"
      21             : 
      22             : 
      23             : /*
      24             :  * flex emits a yy_fatal_error() function that it calls in response to
      25             :  * critical errors like malloc failure, file I/O errors, and detection of
      26             :  * internal inconsistency.  That function prints a message and calls exit().
      27             :  * Mutate it to instead call our handler, which jumps out of the parser.
      28             :  */
      29             : #undef fprintf
      30             : #define fprintf(file, fmt, msg) GUC_flex_fatal(msg)
      31             : 
      32             : enum
      33             : {
      34             :     GUC_ID = 1,
      35             :     GUC_STRING = 2,
      36             :     GUC_INTEGER = 3,
      37             :     GUC_REAL = 4,
      38             :     GUC_EQUALS = 5,
      39             :     GUC_UNQUOTED_STRING = 6,
      40             :     GUC_QUALIFIED_ID = 7,
      41             :     GUC_EOL = 99,
      42             :     GUC_ERROR = 100
      43             : };
      44             : 
      45             : static unsigned int ConfigFileLineno;
      46             : static const char *GUC_flex_fatal_errmsg;
      47             : static sigjmp_buf *GUC_flex_fatal_jmp;
      48             : 
      49             : static void FreeConfigVariable(ConfigVariable *item);
      50             : 
      51             : static void record_config_file_error(const char *errmsg,
      52             :                          const char *config_file,
      53             :                          int lineno,
      54             :                          ConfigVariable **head_p,
      55             :                          ConfigVariable **tail_p);
      56             : 
      57             : static int  GUC_flex_fatal(const char *msg);
      58             : static char *GUC_scanstr(const char *s);
      59             : 
      60             : /* LCOV_EXCL_START */
      61             : 
      62             : %}
      63             : 
      64             : %option 8bit
      65             : %option never-interactive
      66             : %option nodefault
      67             : %option noinput
      68             : %option nounput
      69             : %option noyywrap
      70             : %option warn
      71             : %option prefix="GUC_yy"
      72             : 
      73             : 
      74             : SIGN            ("-"|"+")
      75             : DIGIT           [0-9]
      76             : HEXDIGIT        [0-9a-fA-F]
      77             : 
      78             : UNIT_LETTER     [a-zA-Z]
      79             : 
      80             : INTEGER         {SIGN}?({DIGIT}+|0x{HEXDIGIT}+){UNIT_LETTER}*
      81             : 
      82             : EXPONENT        [Ee]{SIGN}?{DIGIT}+
      83             : REAL            {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}?
      84             : 
      85             : LETTER          [A-Za-z_\200-\377]
      86             : LETTER_OR_DIGIT [A-Za-z_0-9\200-\377]
      87             : 
      88             : ID              {LETTER}{LETTER_OR_DIGIT}*
      89             : QUALIFIED_ID    {ID}"."{ID}
      90             : 
      91             : UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
      92             : STRING          \'([^'\\\n]|\\.|\'\')*\'
      93             : 
      94             : %%
      95             : 
      96             : \n              ConfigFileLineno++; return GUC_EOL;
      97             : [ \t\r]+        /* eat whitespace */
      98             : #.*             /* eat comment (.* matches anything until newline) */
      99             : 
     100             : {ID}            return GUC_ID;
     101             : {QUALIFIED_ID}  return GUC_QUALIFIED_ID;
     102             : {STRING}        return GUC_STRING;
     103             : {UNQUOTED_STRING} return GUC_UNQUOTED_STRING;
     104             : {INTEGER}       return GUC_INTEGER;
     105             : {REAL}          return GUC_REAL;
     106             : =               return GUC_EQUALS;
     107             : 
     108             : .               return GUC_ERROR;
     109             : 
     110             : %%
     111             : 
     112             : /* LCOV_EXCL_STOP */
     113             : 
     114             : /*
     115             :  * Exported function to read and process the configuration file. The
     116             :  * parameter indicates in what context the file is being read --- either
     117             :  * postmaster startup (including standalone-backend startup) or SIGHUP.
     118             :  * All options mentioned in the configuration file are set to new values.
     119             :  * If a hard error occurs, no values will be changed.  (There can also be
     120             :  * errors that prevent just one value from being changed.)
     121             :  */
     122             : void
     123             : ProcessConfigFile(GucContext context)
     124        3888 : {
     125             :     int         elevel;
     126             :     MemoryContext config_cxt;
     127             :     MemoryContext caller_cxt;
     128             : 
     129             :     /*
     130             :      * Config files are processed on startup (by the postmaster only) and on
     131             :      * SIGHUP (by the postmaster and its children)
     132             :      */
     133             :     Assert((context == PGC_POSTMASTER && !IsUnderPostmaster) ||
     134             :            context == PGC_SIGHUP);
     135             : 
     136             :     /*
     137             :      * To avoid cluttering the log, only the postmaster bleats loudly about
     138             :      * problems with the config file.
     139             :      */
     140             :     elevel = IsUnderPostmaster ? DEBUG2 : LOG;
     141        3888 : 
     142             :     /*
     143             :      * This function is usually called within a process-lifespan memory
     144             :      * context.  To ensure that any memory leaked during GUC processing does
     145             :      * not accumulate across repeated SIGHUP cycles, do the work in a private
     146             :      * context that we can free at exit.
     147             :      */
     148             :     config_cxt = AllocSetContextCreate(CurrentMemoryContext,
     149        3888 :                                        "config file processing",
     150             :                                        ALLOCSET_DEFAULT_SIZES);
     151             :     caller_cxt = MemoryContextSwitchTo(config_cxt);
     152        3888 : 
     153             :     /*
     154             :      * Read and apply the config file.  We don't need to examine the result.
     155             :      */
     156             :     (void) ProcessConfigFileInternal(context, true, elevel);
     157        3888 : 
     158             :     /* Clean up */
     159             :     MemoryContextSwitchTo(caller_cxt);
     160        3886 :     MemoryContextDelete(config_cxt);
     161        3886 : }
     162        3886 : 
     163             : /*
     164             :  * This function handles both actual config file (re)loads and execution of
     165             :  * show_all_file_settings() (i.e., the pg_file_settings view).  In the latter
     166             :  * case we don't apply any of the settings, but we make all the usual validity
     167             :  * checks, and we return the ConfigVariable list so that it can be printed out
     168             :  * by show_all_file_settings().
     169             :  */
     170             : static ConfigVariable *
     171             : ProcessConfigFileInternal(GucContext context, bool applySettings, int elevel)
     172        3892 : {
     173             :     bool        error = false;
     174        3892 :     bool        applying = false;
     175        3892 :     const char *ConfFileWithError;
     176             :     ConfigVariable *item,
     177             :                *head,
     178             :                *tail;
     179             :     int         i;
     180             : 
     181             :     /* Parse the main config file into a list of option names and values */
     182             :     ConfFileWithError = ConfigFileName;
     183        3892 :     head = tail = NULL;
     184        3892 : 
     185             :     if (!ParseConfigFile(ConfigFileName, true,
     186        3892 :                          NULL, 0, 0, elevel,
     187             :                          &head, &tail))
     188             :     {
     189             :         /* Syntax error(s) detected in the file, so bail out */
     190             :         error = true;
     191           0 :         goto bail_out;
     192           0 :     }
     193             : 
     194             :     /*
     195             :      * Parse the PG_AUTOCONF_FILENAME file, if present, after the main file to
     196             :      * replace any parameters set by ALTER SYSTEM command.  Because this file
     197             :      * is in the data directory, we can't read it until the DataDir has been
     198             :      * set.
     199             :      */
     200             :     if (DataDir)
     201        3892 :     {
     202             :         if (!ParseConfigFile(PG_AUTOCONF_FILENAME, false,
     203        2038 :                              NULL, 0, 0, elevel,
     204             :                              &head, &tail))
     205             :         {
     206             :             /* Syntax error(s) detected in the file, so bail out */
     207             :             error = true;
     208           0 :             ConfFileWithError = PG_AUTOCONF_FILENAME;
     209           0 :             goto bail_out;
     210           0 :         }
     211             :     }
     212             :     else
     213             :     {
     214             :         /*
     215             :          * If DataDir is not set, the PG_AUTOCONF_FILENAME file cannot be
     216             :          * read.  In this case, we don't want to accept any settings but
     217             :          * data_directory from postgresql.conf, because they might be
     218             :          * overwritten with settings in the PG_AUTOCONF_FILENAME file which
     219             :          * will be read later. OTOH, since data_directory isn't allowed in the
     220             :          * PG_AUTOCONF_FILENAME file, it will never be overwritten later.
     221             :          */
     222             :         ConfigVariable *newlist = NULL;
     223        1854 : 
     224             :         /*
     225             :          * Prune all items except the last "data_directory" from the list.
     226             :          */
     227             :         for (item = head; item; item = item->next)
     228       26488 :         {
     229             :             if (!item->ignore &&
     230       49268 :                 strcmp(item->name, "data_directory") == 0)
     231       24634 :                 newlist = item;
     232           0 :         }
     233             : 
     234             :         if (newlist)
     235        1854 :             newlist->next = NULL;
     236           0 :         head = tail = newlist;
     237        1854 : 
     238             :         /*
     239             :          * Quick exit if data_directory is not present in file.
     240             :          *
     241             :          * We need not do any further processing, in particular we don't set
     242             :          * PgReloadTime; that will be set soon by subsequent full loading of
     243             :          * the config file.
     244             :          */
     245             :         if (head == NULL)
     246        1854 :             goto bail_out;
     247        1854 :     }
     248             : 
     249             :     /*
     250             :      * Mark all extant GUC variables as not present in the config file. We
     251             :      * need this so that we can tell below which ones have been removed from
     252             :      * the file since we last processed it.
     253             :      */
     254             :     for (i = 0; i < num_guc_variables; i++)
     255      656300 :     {
     256             :         struct config_generic *gconf = guc_variables[i];
     257      654262 : 
     258             :         gconf->status &= ~GUC_IS_IN_FILE;
     259      654262 :     }
     260             : 
     261             :     /*
     262             :      * Check if all the supplied option names are valid, as an additional
     263             :      * quasi-syntactic check on the validity of the config file.  It is
     264             :      * important that the postmaster and all backends agree on the results of
     265             :      * this phase, else we will have strange inconsistencies about which
     266             :      * processes accept a config file update and which don't.  Hence, unknown
     267             :      * custom variable names have to be accepted without complaint.  For the
     268             :      * same reason, we don't attempt to validate the options' values here.
     269             :      *
     270             :      * In addition, the GUC_IS_IN_FILE flag is set on each existing GUC
     271             :      * variable mentioned in the file; and we detect duplicate entries in the
     272             :      * file and mark the earlier occurrences as ignorable.
     273             :      */
     274             :     for (item = head; item; item = item->next)
     275       32362 :     {
     276             :         struct config_generic *record;
     277             : 
     278             :         /* Ignore anything already marked as ignorable */
     279             :         if (item->ignore)
     280       30324 :             continue;
     281           0 : 
     282             :         /*
     283             :          * Try to find the variable; but do not create a custom placeholder if
     284             :          * it's not there already.
     285             :          */
     286             :         record = find_option(item->name, false, elevel);
     287       30324 : 
     288             :         if (record)
     289       30324 :         {
     290             :             /* If it's already marked, then this is a duplicate entry */
     291             :             if (record->status & GUC_IS_IN_FILE)
     292       30322 :             {
     293             :                 /*
     294             :                  * Mark the earlier occurrence(s) as dead/ignorable.  We could
     295             :                  * avoid the O(N^2) behavior here with some additional state,
     296             :                  * but it seems unlikely to be worth the trouble.
     297             :                  */
     298             :                 ConfigVariable *pitem;
     299             : 
     300             :                 for (pitem = head; pitem != item; pitem = pitem->next)
     301       50126 :                 {
     302             :                     if (!pitem->ignore &&
     303       93560 :                         strcmp(pitem->name, item->name) == 0)
     304       45228 :                         pitem->ignore = true;
     305        1794 :                 }
     306             :             }
     307             :             /* Now mark it as present in file */
     308             :             record->status |= GUC_IS_IN_FILE;
     309       30322 :         }
     310             :         else if (strchr(item->name, GUC_QUALIFIER_SEPARATOR) == NULL)
     311           2 :         {
     312             :             /* Invalid non-custom variable, so complain */
     313             :             ereport(elevel,
     314           0 :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     315             :                      errmsg("unrecognized configuration parameter \"%s\" in file \"%s\" line %u",
     316             :                             item->name,
     317             :                             item->filename, item->sourceline)));
     318             :             item->errmsg = pstrdup("unrecognized configuration parameter");
     319           0 :             error = true;
     320           0 :             ConfFileWithError = item->filename;
     321           0 :         }
     322             :     }
     323             : 
     324             :     /*
     325             :      * If we've detected any errors so far, we don't want to risk applying any
     326             :      * changes.
     327             :      */
     328             :     if (error)
     329        2038 :         goto bail_out;
     330           0 : 
     331             :     /* Otherwise, set flag that we're beginning to apply changes */
     332             :     applying = true;
     333        2038 : 
     334             :     /*
     335             :      * Check for variables having been removed from the config file, and
     336             :      * revert their reset values (and perhaps also effective values) to the
     337             :      * boot-time defaults.  If such a variable can't be changed after startup,
     338             :      * report that and continue.
     339             :      */
     340             :     for (i = 0; i < num_guc_variables; i++)
     341      656300 :     {
     342             :         struct config_generic *gconf = guc_variables[i];
     343      654262 :         GucStack   *stack;
     344             : 
     345             :         if (gconf->reset_source != PGC_S_FILE ||
     346      659326 :             (gconf->status & GUC_IS_IN_FILE))
     347        5064 :             continue;
     348      654262 :         if (gconf->context < PGC_SIGHUP)
     349           0 :         {
     350             :             ereport(elevel,
     351           0 :                     (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
     352             :                      errmsg("parameter \"%s\" cannot be changed without restarting the server",
     353             :                             gconf->name)));
     354             :             record_config_file_error(psprintf("parameter \"%s\" cannot be changed without restarting the server",
     355           0 :                                               gconf->name),
     356             :                                      NULL, 0,
     357             :                                      &head, &tail);
     358             :             error = true;
     359           0 :             continue;
     360           0 :         }
     361             : 
     362             :         /* No more to do if we're just doing show_all_file_settings() */
     363             :         if (!applySettings)
     364           0 :             continue;
     365           0 : 
     366             :         /*
     367             :          * Reset any "file" sources to "default", else set_config_option will
     368             :          * not override those settings.
     369             :          */
     370             :         if (gconf->reset_source == PGC_S_FILE)
     371           0 :             gconf->reset_source = PGC_S_DEFAULT;
     372           0 :         if (gconf->source == PGC_S_FILE)
     373           0 :             gconf->source = PGC_S_DEFAULT;
     374           0 :         for (stack = gconf->stack; stack; stack = stack->prev)
     375           0 :         {
     376             :             if (stack->source == PGC_S_FILE)
     377           0 :                 stack->source = PGC_S_DEFAULT;
     378           0 :         }
     379             : 
     380             :         /* Now we can re-apply the wired-in default (i.e., the boot_val) */
     381             :         if (set_config_option(gconf->name, NULL,
     382           0 :                               context, PGC_S_DEFAULT,
     383             :                               GUC_ACTION_SET, true, 0, false) > 0)
     384             :         {
     385             :             /* Log the change if appropriate */
     386             :             if (context == PGC_SIGHUP)
     387           0 :                 ereport(elevel,
     388           0 :                         (errmsg("parameter \"%s\" removed from configuration file, reset to default",
     389             :                                 gconf->name)));
     390             :         }
     391             :     }
     392             : 
     393             :     /*
     394             :      * Restore any variables determined by environment variables or
     395             :      * dynamically-computed defaults.  This is a no-op except in the case
     396             :      * where one of these had been in the config file and is now removed.
     397             :      *
     398             :      * In particular, we *must not* do this during the postmaster's initial
     399             :      * loading of the file, since the timezone functions in particular should
     400             :      * be run only after initialization is complete.
     401             :      *
     402             :      * XXX this is an unmaintainable crock, because we have to know how to set
     403             :      * (or at least what to call to set) every variable that could potentially
     404             :      * have PGC_S_DYNAMIC_DEFAULT or PGC_S_ENV_VAR source. However, there's no
     405             :      * time to redesign it for 9.1.
     406             :      */
     407             :     if (context == PGC_SIGHUP && applySettings)
     408        2038 :     {
     409             :         InitializeGUCOptionsFromEnvironment();
     410         180 :         pg_timezone_abbrev_initialize();
     411         180 :         /* this selects SQL_ASCII in processes not connected to a database */
     412             :         SetConfigOption("client_encoding", GetDatabaseEncodingName(),
     413         180 :                         PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT);
     414             :     }
     415             : 
     416             :     /*
     417             :      * Now apply the values from the config file.
     418             :      */
     419             :     for (item = head; item; item = item->next)
     420       32360 :     {
     421             :         char       *pre_value = NULL;
     422       30324 :         int         scres;
     423             : 
     424             :         /* Ignore anything marked as ignorable */
     425             :         if (item->ignore)
     426       30324 :             continue;
     427        1794 : 
     428             :         /* In SIGHUP cases in the postmaster, we want to report changes */
     429             :         if (context == PGC_SIGHUP && applySettings && !IsUnderPostmaster)
     430       28530 :         {
     431             :             const char *preval = GetConfigOption(item->name, true, false);
     432        1366 : 
     433             :             /* If option doesn't exist yet or is NULL, treat as empty string */
     434             :             if (!preval)
     435        1366 :                 preval = "";
     436           0 :             /* must dup, else might have dangling pointer below */
     437             :             pre_value = pstrdup(preval);
     438        1366 :         }
     439             : 
     440             :         scres = set_config_option(item->name, item->value,
     441       28530 :                                   context, PGC_S_FILE,
     442             :                                   GUC_ACTION_SET, applySettings, 0, false);
     443             :         if (scres > 0)
     444       28528 :         {
     445             :             /* variable was updated, so log the change if appropriate */
     446             :             if (pre_value)
     447       26548 :             {
     448             :                 const char *post_value = GetConfigOption(item->name, true, false);
     449         860 : 
     450             :                 if (!post_value)
     451         860 :                     post_value = "";
     452           0 :                 if (strcmp(pre_value, post_value) != 0)
     453         860 :                     ereport(elevel,
     454          36 :                             (errmsg("parameter \"%s\" changed to \"%s\"",
     455             :                                     item->name, item->value)));
     456             :             }
     457             :             item->applied = true;
     458       26548 :         }
     459             :         else if (scres == 0)
     460        1980 :         {
     461             :             error = true;
     462           0 :             item->errmsg = pstrdup("setting could not be applied");
     463           0 :             ConfFileWithError = item->filename;
     464           0 :         }
     465             :         else
     466             :         {
     467             :             /* no error, but variable's active value was not changed */
     468             :             item->applied = true;
     469        1980 :         }
     470             : 
     471             :         /*
     472             :          * We should update source location unless there was an error, since
     473             :          * even if the active value didn't change, the reset value might have.
     474             :          * (In the postmaster, there won't be a difference, but it does matter
     475             :          * in backends.)
     476             :          */
     477             :         if (scres != 0 && applySettings)
     478       28528 :             set_config_sourcefile(item->name, item->filename,
     479       28462 :                                   item->sourceline);
     480             : 
     481             :         if (pre_value)
     482       28528 :             pfree(pre_value);
     483        1366 :     }
     484             : 
     485             :     /* Remember when we last successfully loaded the config file. */
     486             :     if (applySettings)
     487        2036 :         PgReloadTime = GetCurrentTimestamp();
     488        2032 : 
     489             : bail_out:
     490             :     if (error && applySettings)
     491        3890 :     {
     492             :         /* During postmaster startup, any error is fatal */
     493             :         if (context == PGC_POSTMASTER)
     494           0 :             ereport(ERROR,
     495           0 :                     (errcode(ERRCODE_CONFIG_FILE_ERROR),
     496             :                      errmsg("configuration file \"%s\" contains errors",
     497             :                             ConfFileWithError)));
     498             :         else if (applying)
     499           0 :             ereport(elevel,
     500           0 :                     (errcode(ERRCODE_CONFIG_FILE_ERROR),
     501             :                      errmsg("configuration file \"%s\" contains errors; unaffected changes were applied",
     502             :                             ConfFileWithError)));
     503             :         else
     504             :             ereport(elevel,
     505           0 :                     (errcode(ERRCODE_CONFIG_FILE_ERROR),
     506             :                      errmsg("configuration file \"%s\" contains errors; no changes were applied",
     507             :                             ConfFileWithError)));
     508             :     }
     509             : 
     510             :     /* Successful or otherwise, return the collected data list */
     511             :     return head;
     512        3890 : }
     513             : 
     514             : /*
     515             :  * Given a configuration file or directory location that may be a relative
     516             :  * path, return an absolute one.  We consider the location to be relative to
     517             :  * the directory holding the calling file, or to DataDir if no calling file.
     518             :  */
     519             : static char *
     520             : AbsoluteConfigLocation(const char *location, const char *calling_file)
     521        5978 : {
     522             :     char        abs_path[MAXPGPATH];
     523             : 
     524             :     if (is_absolute_path(location))
     525        5978 :         return pstrdup(location);
     526        3892 :     else
     527             :     {
     528             :         if (calling_file != NULL)
     529        2086 :         {
     530             :             strlcpy(abs_path, calling_file, sizeof(abs_path));
     531          48 :             get_parent_directory(abs_path);
     532          48 :             join_path_components(abs_path, abs_path, location);
     533          48 :             canonicalize_path(abs_path);
     534          48 :         }
     535             :         else
     536             :         {
     537             :             AssertState(DataDir);
     538             :             join_path_components(abs_path, DataDir, location);
     539        2038 :             canonicalize_path(abs_path);
     540        2038 :         }
     541             :         return pstrdup(abs_path);
     542        2086 :     }
     543             : }
     544             : 
     545             : /*
     546             :  * Read and parse a single configuration file.  This function recurses
     547             :  * to handle "include" directives.
     548             :  *
     549             :  * If "strict" is true, treat failure to open the config file as an error,
     550             :  * otherwise just skip the file.
     551             :  *
     552             :  * calling_file/calling_lineno identify the source of the request.
     553             :  * Pass NULL/0 if not recursing from an inclusion request.
     554             :  *
     555             :  * See ParseConfigFp for further details.  This one merely adds opening the
     556             :  * config file rather than working from a caller-supplied file descriptor,
     557             :  * and absolute-ifying the path name if necessary.
     558             :  */
     559             : bool
     560             : ParseConfigFile(const char *config_file, bool strict,
     561        5978 :                 const char *calling_file, int calling_lineno,
     562             :                 int depth, int elevel,
     563             :                 ConfigVariable **head_p,
     564             :                 ConfigVariable **tail_p)
     565             : {
     566             :     char       *abs_path;
     567             :     bool        OK = true;
     568        5978 :     FILE       *fp;
     569             : 
     570             :     /*
     571             :      * Reject too-deep include nesting depth.  This is just a safety check to
     572             :      * avoid dumping core due to stack overflow if an include file loops back
     573             :      * to itself.  The maximum nesting depth is pretty arbitrary.
     574             :      */
     575             :     if (depth > 10)
     576        5978 :     {
     577             :         ereport(elevel,
     578           0 :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     579             :                  errmsg("could not open configuration file \"%s\": maximum nesting depth exceeded",
     580             :                         config_file)));
     581             :         record_config_file_error("nesting depth exceeded",
     582           0 :                                  calling_file, calling_lineno,
     583             :                                  head_p, tail_p);
     584             :         return false;
     585           0 :     }
     586             : 
     587             :     abs_path = AbsoluteConfigLocation(config_file, calling_file);
     588        5978 :     fp = AllocateFile(abs_path, "r");
     589        5978 :     if (!fp)
     590        5978 :     {
     591             :         if (strict)
     592         636 :         {
     593             :             ereport(elevel,
     594           0 :                     (errcode_for_file_access(),
     595             :                      errmsg("could not open configuration file \"%s\": %m",
     596             :                             abs_path)));
     597             :             record_config_file_error(psprintf("could not open file \"%s\"",
     598           0 :                                               abs_path),
     599             :                                      calling_file, calling_lineno,
     600             :                                      head_p, tail_p);
     601             :             OK = false;
     602           0 :         }
     603             :         else
     604             :         {
     605             :             ereport(LOG,
     606         636 :                     (errmsg("skipping missing configuration file \"%s\"",
     607             :                             abs_path)));
     608             :         }
     609             :         goto cleanup;
     610         636 :     }
     611             : 
     612             :     OK = ParseConfigFp(fp, abs_path, depth, elevel, head_p, tail_p);
     613        5342 : 
     614             : cleanup:
     615             :     if (fp)
     616        5978 :         FreeFile(fp);
     617        5342 :     pfree(abs_path);
     618        5978 : 
     619             :     return OK;
     620        5978 : }
     621             : 
     622             : /*
     623             :  * Capture an error message in the ConfigVariable list returned by
     624             :  * config file parsing.
     625             :  */
     626             : static void
     627             : record_config_file_error(const char *errmsg,
     628           0 :                          const char *config_file,
     629             :                          int lineno,
     630             :                          ConfigVariable **head_p,
     631             :                          ConfigVariable **tail_p)
     632             : {
     633             :     ConfigVariable *item;
     634             : 
     635             :     item = palloc(sizeof *item);
     636           0 :     item->name = NULL;
     637           0 :     item->value = NULL;
     638           0 :     item->errmsg = pstrdup(errmsg);
     639           0 :     item->filename = config_file ? pstrdup(config_file) : NULL;
     640           0 :     item->sourceline = lineno;
     641           0 :     item->ignore = true;
     642           0 :     item->applied = false;
     643           0 :     item->next = NULL;
     644           0 :     if (*head_p == NULL)
     645           0 :         *head_p = item;
     646           0 :     else
     647             :         (*tail_p)->next = item;
     648           0 :     *tail_p = item;
     649           0 : }
     650           0 : 
     651             : /*
     652             :  * Flex fatal errors bring us here.  Stash the error message and jump back to
     653             :  * ParseConfigFp().  Assume all msg arguments point to string constants; this
     654             :  * holds for flex 2.5.31 (earliest we support) and flex 2.5.35 (latest as of
     655             :  * this writing).  Otherwise, we would need to copy the message.
     656             :  *
     657             :  * We return "int" since this takes the place of calls to fprintf().
     658             : */
     659             : static int
     660             : GUC_flex_fatal(const char *msg)
     661           0 : {
     662             :     GUC_flex_fatal_errmsg = msg;
     663           0 :     siglongjmp(*GUC_flex_fatal_jmp, 1);
     664           0 :     return 0;                   /* keep compiler quiet */
     665             : }
     666             : 
     667             : /*
     668             :  * Read and parse a single configuration file.  This function recurses
     669             :  * to handle "include" directives.
     670             :  *
     671             :  * Input parameters:
     672             :  *  fp: file pointer from AllocateFile for the configuration file to parse
     673             :  *  config_file: absolute or relative path name of the configuration file
     674             :  *  depth: recursion depth (should be 0 in the outermost call)
     675             :  *  elevel: error logging level to use
     676             :  * Input/Output parameters:
     677             :  *  head_p, tail_p: head and tail of linked list of name/value pairs
     678             :  *
     679             :  * *head_p and *tail_p must be initialized, either to NULL or valid pointers
     680             :  * to a ConfigVariable list, before calling the outer recursion level.  Any
     681             :  * name-value pairs read from the input file(s) will be appended to the list.
     682             :  * Error reports will also be appended to the list, if elevel < ERROR.
     683             :  *
     684             :  * Returns TRUE if successful, FALSE if an error occurred.  The error has
     685             :  * already been ereport'd, it is only necessary for the caller to clean up
     686             :  * its own state and release the ConfigVariable list.
     687             :  *
     688             :  * Note: if elevel >= ERROR then an error will not return control to the
     689             :  * caller, so there is no need to check the return value in that case.
     690             :  *
     691             :  * Note: this function is used to parse not only postgresql.conf, but
     692             :  * various other configuration files that use the same "name = value"
     693             :  * syntax.  Hence, do not do anything here or in the subsidiary routines
     694             :  * ParseConfigFile/ParseConfigDirectory that assumes we are processing
     695             :  * GUCs specifically.
     696             :  */
     697             : bool
     698             : ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
     699        6562 :               ConfigVariable **head_p, ConfigVariable **tail_p)
     700             : {
     701             :     volatile bool OK = true;
     702        6562 :     unsigned int save_ConfigFileLineno = ConfigFileLineno;
     703        6562 :     sigjmp_buf *save_GUC_flex_fatal_jmp = GUC_flex_fatal_jmp;
     704        6562 :     sigjmp_buf  flex_fatal_jmp;
     705             :     volatile YY_BUFFER_STATE lex_buffer = NULL;
     706        6562 :     int         errorcount;
     707             :     int         token;
     708             : 
     709             :     if (sigsetjmp(flex_fatal_jmp, 1) == 0)
     710        6562 :         GUC_flex_fatal_jmp = &flex_fatal_jmp;
     711        6562 :     else
     712             :     {
     713             :         /*
     714             :          * Regain control after a fatal, internal flex error.  It may have
     715             :          * corrupted parser state.  Consequently, abandon the file, but trust
     716             :          * that the state remains sane enough for yy_delete_buffer().
     717             :          */
     718             :         elog(elevel, "%s at file \"%s\" line %u",
     719           0 :              GUC_flex_fatal_errmsg, config_file, ConfigFileLineno);
     720             :         record_config_file_error(GUC_flex_fatal_errmsg,
     721           0 :                                  config_file, ConfigFileLineno,
     722             :                                  head_p, tail_p);
     723             :         OK = false;
     724           0 :         goto cleanup;
     725           0 :     }
     726             : 
     727             :     /*
     728             :      * Parse
     729             :      */
     730             :     ConfigFileLineno = 1;
     731        6562 :     errorcount = 0;
     732        6562 : 
     733             :     lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
     734        6562 :     yy_switch_to_buffer(lex_buffer);
     735        6562 : 
     736             :     /* This loop iterates once per logical line */
     737             :     while ((token = yylex()))
     738     2018782 :     {
     739             :         char       *opt_name = NULL;
     740     2005706 :         char       *opt_value = NULL;
     741     2005706 :         ConfigVariable *item;
     742             : 
     743             :         if (token == GUC_EOL)   /* empty or comment line */
     744     2005706 :             continue;
     745     1944976 : 
     746             :         /* first token on line is option name */
     747             :         if (token != GUC_ID && token != GUC_QUALIFIED_ID)
     748       60730 :             goto parse_error;
     749           0 :         opt_name = pstrdup(yytext);
     750       60730 : 
     751             :         /* next we have an optional equal sign; discard if present */
     752             :         token = yylex();
     753       60730 :         if (token == GUC_EQUALS)
     754       60730 :             token = yylex();
     755       60682 : 
     756             :         /* now we must have the option value */
     757             :         if (token != GUC_ID &&
     758       60730 :             token != GUC_STRING &&
     759       16946 :             token != GUC_INTEGER &&
     760           8 :             token != GUC_REAL &&
     761           0 :             token != GUC_UNQUOTED_STRING)
     762             :             goto parse_error;
     763           0 :         if (token == GUC_STRING)    /* strip quotes and escapes */
     764       60730 :             opt_value = GUC_scanstr(yytext);
     765       31326 :         else
     766             :             opt_value = pstrdup(yytext);
     767       29404 : 
     768             :         /* now we'd like an end of line, or possibly EOF */
     769             :         token = yylex();
     770       60730 :         if (token != GUC_EOL)
     771       60730 :         {
     772             :             if (token != 0)
     773          48 :                 goto parse_error;
     774           0 :             /* treat EOF like \n for line numbering purposes, cf bug 4752 */
     775             :             ConfigFileLineno++;
     776          48 :         }
     777             : 
     778             :         /* OK, process the option name and value */
     779             :         if (guc_name_compare(opt_name, "include_dir") == 0)
     780       60730 :         {
     781             :             /*
     782             :              * An include_dir directive isn't a variable and should be
     783             :              * processed immediately.
     784             :              */
     785             :             if (!ParseConfigDirectory(opt_value,
     786           0 :                                       config_file, ConfigFileLineno - 1,
     787           0 :                                       depth + 1, elevel,
     788             :                                       head_p, tail_p))
     789             :                 OK = false;
     790           0 :             yy_switch_to_buffer(lex_buffer);
     791           0 :             pfree(opt_name);
     792           0 :             pfree(opt_value);
     793           0 :         }
     794             :         else if (guc_name_compare(opt_name, "include_if_exists") == 0)
     795       60730 :         {
     796             :             /*
     797             :              * An include_if_exists directive isn't a variable and should be
     798             :              * processed immediately.
     799             :              */
     800             :             if (!ParseConfigFile(opt_value, false,
     801           0 :                                  config_file, ConfigFileLineno - 1,
     802           0 :                                  depth + 1, elevel,
     803             :                                  head_p, tail_p))
     804             :                 OK = false;
     805           0 :             yy_switch_to_buffer(lex_buffer);
     806           0 :             pfree(opt_name);
     807           0 :             pfree(opt_value);
     808           0 :         }
     809             :         else if (guc_name_compare(opt_name, "include") == 0)
     810       60730 :         {
     811             :             /*
     812             :              * An include directive isn't a variable and should be processed
     813             :              * immediately.
     814             :              */
     815             :             if (!ParseConfigFile(opt_value, true,
     816          96 :                                  config_file, ConfigFileLineno - 1,
     817          48 :                                  depth + 1, elevel,
     818             :                                  head_p, tail_p))
     819             :                 OK = false;
     820           0 :             yy_switch_to_buffer(lex_buffer);
     821          48 :             pfree(opt_name);
     822          48 :             pfree(opt_value);
     823          48 :         }
     824             :         else
     825             :         {
     826             :             /* ordinary variable, append to list */
     827             :             item = palloc(sizeof *item);
     828       60682 :             item->name = opt_name;
     829       60682 :             item->value = opt_value;
     830       60682 :             item->errmsg = NULL;
     831       60682 :             item->filename = pstrdup(config_file);
     832       60682 :             item->sourceline = ConfigFileLineno - 1;
     833       60682 :             item->ignore = false;
     834       60682 :             item->applied = false;
     835       60682 :             item->next = NULL;
     836       60682 :             if (*head_p == NULL)
     837       60682 :                 *head_p = item;
     838        3832 :             else
     839             :                 (*tail_p)->next = item;
     840       56850 :             *tail_p = item;
     841       60682 :         }
     842             : 
     843             :         /* break out of loop if read EOF, else loop for next line */
     844             :         if (token == 0)
     845       60730 :             break;
     846          48 :         continue;
     847       60682 : 
     848             : parse_error:
     849             :         /* release storage if we allocated any on this line */
     850             :         if (opt_name)
     851           0 :             pfree(opt_name);
     852           0 :         if (opt_value)
     853           0 :             pfree(opt_value);
     854           0 : 
     855             :         /* report the error */
     856             :         if (token == GUC_EOL || token == 0)
     857           0 :         {
     858             :             ereport(elevel,
     859           0 :                     (errcode(ERRCODE_SYNTAX_ERROR),
     860             :               errmsg("syntax error in file \"%s\" line %u, near end of line",
     861             :                      config_file, ConfigFileLineno - 1)));
     862             :             record_config_file_error("syntax error",
     863           0 :                                      config_file, ConfigFileLineno - 1,
     864           0 :                                      head_p, tail_p);
     865             :         }
     866             :         else
     867             :         {
     868             :             ereport(elevel,
     869           0 :                     (errcode(ERRCODE_SYNTAX_ERROR),
     870             :              errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
     871             :                     config_file, ConfigFileLineno, yytext)));
     872             :             record_config_file_error("syntax error",
     873           0 :                                      config_file, ConfigFileLineno,
     874             :                                      head_p, tail_p);
     875             :         }
     876             :         OK = false;
     877           0 :         errorcount++;
     878           0 : 
     879             :         /*
     880             :          * To avoid producing too much noise when fed a totally bogus file,
     881             :          * give up after 100 syntax errors per file (an arbitrary number).
     882             :          * Also, if we're only logging the errors at DEBUG level anyway, might
     883             :          * as well give up immediately.  (This prevents postmaster children
     884             :          * from bloating the logs with duplicate complaints.)
     885             :          */
     886             :         if (errorcount >= 100 || elevel <= DEBUG1)
     887           0 :         {
     888             :             ereport(elevel,
     889           0 :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     890             :                errmsg("too many syntax errors found, abandoning file \"%s\"",
     891             :                       config_file)));
     892             :             break;
     893           0 :         }
     894             : 
     895             :         /* resync to next end-of-line or EOF */
     896             :         while (token != GUC_EOL && token != 0)
     897           0 :             token = yylex();
     898           0 :         /* break out of loop on EOF */
     899             :         if (token == 0)
     900           0 :             break;
     901           0 :     }
     902             : 
     903             : cleanup:
     904             :     yy_delete_buffer(lex_buffer);
     905        6562 :     /* Each recursion level must save and restore these static variables. */
     906             :     ConfigFileLineno = save_ConfigFileLineno;
     907        6562 :     GUC_flex_fatal_jmp = save_GUC_flex_fatal_jmp;
     908        6562 :     return OK;
     909        6562 : }
     910             : 
     911             : /*
     912             :  * Read and parse all config files in a subdirectory in alphabetical order
     913             :  *
     914             :  * includedir is the absolute or relative path to the subdirectory to scan.
     915             :  *
     916             :  * calling_file/calling_lineno identify the source of the request.
     917             :  * Pass NULL/0 if not recursing from an inclusion request.
     918             :  *
     919             :  * See ParseConfigFp for further details.
     920             :  */
     921             : bool
     922             : ParseConfigDirectory(const char *includedir,
     923           0 :                      const char *calling_file, int calling_lineno,
     924             :                      int depth, int elevel,
     925             :                      ConfigVariable **head_p,
     926             :                      ConfigVariable **tail_p)
     927             : {
     928             :     char       *directory;
     929             :     DIR        *d;
     930             :     struct dirent *de;
     931             :     char      **filenames;
     932             :     int         num_filenames;
     933             :     int         size_filenames;
     934             :     bool        status;
     935             : 
     936             :     directory = AbsoluteConfigLocation(includedir, calling_file);
     937           0 :     d = AllocateDir(directory);
     938           0 :     if (d == NULL)
     939           0 :     {
     940             :         ereport(elevel,
     941           0 :                 (errcode_for_file_access(),
     942             :                  errmsg("could not open configuration directory \"%s\": %m",
     943             :                         directory)));
     944             :         record_config_file_error(psprintf("could not open directory \"%s\"",
     945           0 :                                           directory),
     946             :                                  calling_file, calling_lineno,
     947             :                                  head_p, tail_p);
     948             :         status = false;
     949           0 :         goto cleanup;
     950           0 :     }
     951             : 
     952             :     /*
     953             :      * Read the directory and put the filenames in an array, so we can sort
     954             :      * them prior to processing the contents.
     955             :      */
     956             :     size_filenames = 32;
     957           0 :     filenames = (char **) palloc(size_filenames * sizeof(char *));
     958           0 :     num_filenames = 0;
     959           0 : 
     960             :     while ((de = ReadDir(d, directory)) != NULL)
     961           0 :     {
     962             :         struct stat st;
     963             :         char        filename[MAXPGPATH];
     964             : 
     965             :         /*
     966             :          * Only parse files with names ending in ".conf".  Explicitly reject
     967             :          * files starting with ".".  This excludes things like "." and "..",
     968             :          * as well as typical hidden files, backup files, and editor debris.
     969             :          */
     970             :         if (strlen(de->d_name) < 6)
     971           0 :             continue;
     972           0 :         if (de->d_name[0] == '.')
     973           0 :             continue;
     974           0 :         if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0)
     975           0 :             continue;
     976           0 : 
     977             :         join_path_components(filename, directory, de->d_name);
     978           0 :         canonicalize_path(filename);
     979           0 :         if (stat(filename, &st) == 0)
     980           0 :         {
     981             :             if (!S_ISDIR(st.st_mode))
     982           0 :             {
     983             :                 /* Add file to array, increasing its size in blocks of 32 */
     984             :                 if (num_filenames >= size_filenames)
     985           0 :                 {
     986             :                     size_filenames += 32;
     987           0 :                     filenames = (char **) repalloc(filenames,
     988           0 :                                             size_filenames * sizeof(char *));
     989             :                 }
     990             :                 filenames[num_filenames] = pstrdup(filename);
     991           0 :                 num_filenames++;
     992           0 :             }
     993             :         }
     994             :         else
     995             :         {
     996             :             /*
     997             :              * stat does not care about permissions, so the most likely reason
     998             :              * a file can't be accessed now is if it was removed between the
     999             :              * directory listing and now.
    1000             :              */
    1001             :             ereport(elevel,
    1002           0 :                     (errcode_for_file_access(),
    1003             :                      errmsg("could not stat file \"%s\": %m",
    1004             :                             filename)));
    1005             :             record_config_file_error(psprintf("could not stat file \"%s\"",
    1006           0 :                                               filename),
    1007             :                                      calling_file, calling_lineno,
    1008             :                                      head_p, tail_p);
    1009             :             status = false;
    1010           0 :             goto cleanup;
    1011           0 :         }
    1012             :     }
    1013             : 
    1014             :     if (num_filenames > 0)
    1015           0 :     {
    1016             :         int         i;
    1017             : 
    1018             :         qsort(filenames, num_filenames, sizeof(char *), pg_qsort_strcmp);
    1019           0 :         for (i = 0; i < num_filenames; i++)
    1020           0 :         {
    1021             :             if (!ParseConfigFile(filenames[i], true,
    1022           0 :                                  calling_file, calling_lineno,
    1023             :                                  depth, elevel,
    1024             :                                  head_p, tail_p))
    1025             :             {
    1026             :                 status = false;
    1027           0 :                 goto cleanup;
    1028           0 :             }
    1029             :         }
    1030             :     }
    1031             :     status = true;
    1032           0 : 
    1033             : cleanup:
    1034             :     if (d)
    1035           0 :         FreeDir(d);
    1036           0 :     pfree(directory);
    1037           0 :     return status;
    1038           0 : }
    1039             : 
    1040             : /*
    1041             :  * Free a list of ConfigVariables, including the names and the values
    1042             :  */
    1043             : void
    1044             : FreeConfigVariables(ConfigVariable *list)
    1045        1220 : {
    1046             :     ConfigVariable *item;
    1047             : 
    1048             :     item = list;
    1049        1220 :     while (item)
    1050        8174 :     {
    1051             :         ConfigVariable *next = item->next;
    1052        5734 : 
    1053             :         FreeConfigVariable(item);
    1054        5734 :         item = next;
    1055        5734 :     }
    1056             : }
    1057        1220 : 
    1058             : /*
    1059             :  * Free a single ConfigVariable
    1060             :  */
    1061             : static void
    1062             : FreeConfigVariable(ConfigVariable *item)
    1063        5734 : {
    1064             :     if (item->name)
    1065        5734 :         pfree(item->name);
    1066        5734 :     if (item->value)
    1067        5734 :         pfree(item->value);
    1068        5734 :     if (item->errmsg)
    1069        5734 :         pfree(item->errmsg);
    1070           0 :     if (item->filename)
    1071        5734 :         pfree(item->filename);
    1072        5734 :     pfree(item);
    1073        5734 : }
    1074        5734 : 
    1075             : 
    1076             : /*
    1077             :  *      scanstr
    1078             :  *
    1079             :  * Strip the quotes surrounding the given string, and collapse any embedded
    1080             :  * '' sequences and backslash escapes.
    1081             :  *
    1082             :  * the string returned is palloc'd and should eventually be pfree'd by the
    1083             :  * caller.
    1084             :  */
    1085             : static char *
    1086             : GUC_scanstr(const char *s)
    1087       31326 : {
    1088             :     char       *newStr;
    1089             :     int         len,
    1090             :                 i,
    1091             :                 j;
    1092             : 
    1093             :     Assert(s != NULL && s[0] == '\'');
    1094             :     len = strlen(s);
    1095       31326 :     Assert(len >= 2);
    1096             :     Assert(s[len - 1] == '\'');
    1097             : 
    1098             :     /* Skip the leading quote; we'll handle the trailing quote below */
    1099             :     s++, len--;
    1100       31326 : 
    1101             :     /* Since len still includes trailing quote, this is enough space */
    1102             :     newStr = palloc(len);
    1103       31326 : 
    1104             :     for (i = 0, j = 0; i < len; i++)
    1105      399310 :     {
    1106             :         if (s[i] == '\\')
    1107      367984 :         {
    1108             :             i++;
    1109           0 :             switch (s[i])
    1110           0 :             {
    1111             :                 case 'b':
    1112             :                     newStr[j] = '\b';
    1113           0 :                     break;
    1114           0 :                 case 'f':
    1115             :                     newStr[j] = '\f';
    1116           0 :                     break;
    1117           0 :                 case 'n':
    1118             :                     newStr[j] = '\n';
    1119           0 :                     break;
    1120           0 :                 case 'r':
    1121             :                     newStr[j] = '\r';
    1122           0 :                     break;
    1123           0 :                 case 't':
    1124             :                     newStr[j] = '\t';
    1125           0 :                     break;
    1126           0 :                 case '0':
    1127             :                 case '1':
    1128             :                 case '2':
    1129             :                 case '3':
    1130             :                 case '4':
    1131             :                 case '5':
    1132             :                 case '6':
    1133             :                 case '7':
    1134             :                     {
    1135             :                         int         k;
    1136             :                         long        octVal = 0;
    1137           0 : 
    1138             :                         for (k = 0;
    1139           0 :                              s[i + k] >= '0' && s[i + k] <= '7' && k < 3;
    1140           0 :                              k++)
    1141           0 :                             octVal = (octVal << 3) + (s[i + k] - '0');
    1142           0 :                         i += k - 1;
    1143           0 :                         newStr[j] = ((char) octVal);
    1144           0 :                     }
    1145             :                     break;
    1146           0 :                 default:
    1147             :                     newStr[j] = s[i];
    1148           0 :                     break;
    1149           0 :             }                   /* switch */
    1150             :         }
    1151             :         else if (s[i] == '\'' && s[i + 1] == '\'')
    1152      367984 :         {
    1153             :             /* doubled quote becomes just one quote */
    1154             :             newStr[j] = s[++i];
    1155           0 :         }
    1156             :         else
    1157             :             newStr[j] = s[i];
    1158      367984 :         j++;
    1159      367984 :     }
    1160             : 
    1161             :     /* We copied the ending quote to newStr, so replace with \0 */
    1162             :     Assert(j > 0 && j <= len);
    1163             :     newStr[--j] = '\0';
    1164       31326 : 
    1165             :     return newStr;
    1166       31326 : }

Generated by: LCOV version 1.13