diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml index 3a6a31cb53..85d3b7eb3f 100644 --- a/doc/src/sgml/recovery-config.sgml +++ b/doc/src/sgml/recovery-config.sgml @@ -1,4 +1,4 @@ - + Recovery Configuration @@ -18,6 +18,14 @@ be changed once recovery has begun. + + Settings in recovery.conf are specified in the format + name = 'value'. One parameter is specified per line. + Hash marks (#) designate the rest of the + line as a comment. To embed a single quote in a parameter + value, write two quotes (''). + + Archive recovery settings diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 592419d356..12392f8cfc 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.390 2010/04/07 06:12:52 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.391 2010/04/07 10:58:49 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -4893,6 +4893,100 @@ str_time(pg_time_t tnow) return buf; } +/* + * Parse one line from recovery.conf. 'cmdline' is the raw line from the + * file. If the line is parsed successfully, returns true, false indicates + * syntax error. On success, *key_p and *value_p are set to the parameter + * name and value on the line, respectively. If the line is an empty line, + * consisting entirely of whitespace and comments, function returns true + * and *keyp_p and *value_p are set to NULL. + * + * The pointers returned in *key_p and *value_p point to an internal buffer + * that is valid only until the next call of parseRecoveryCommandFile(). + */ +static bool +parseRecoveryCommandFileLine(char *cmdline, char **key_p, char **value_p) +{ + char *ptr; + char *bufp; + char *key; + char *value; + static char *buf = NULL; + + *key_p = *value_p = NULL; + + /* + * Allocate the buffer on first use. It's used to hold both the + * parameter name and value. + */ + if (buf == NULL) + buf = malloc(MAXPGPATH + 1); + bufp = buf; + + /* Skip any whitespace at the beginning of line */ + for (ptr = cmdline; *ptr; ptr++) + { + if (!isspace((unsigned char) *ptr)) + break; + } + /* Ignore empty lines */ + if (*ptr == '\0' || *ptr == '#') + return true; + + /* Read the parameter name */ + key = bufp; + while (*ptr && !isspace((unsigned char) *ptr) && + *ptr != '=' && *ptr != '\'') + *(bufp++) = *(ptr++); + *(bufp++) = '\0'; + + /* Skip to the beginning quote of the parameter value */ + ptr = strchr(ptr, '\''); + if (!ptr) + return false; + ptr++; + + /* Read the parameter value to *bufp. Collapse any '' escapes as we go. */ + value = bufp; + for (;;) + { + if (*ptr == '\'') + { + ptr++; + if (*ptr == '\'') + *(bufp++) = '\''; + else + { + /* end of parameter */ + *bufp = '\0'; + break; + } + } + else if (*ptr == '\0') + return false; /* unterminated quoted string */ + else + *(bufp++) = *ptr; + + ptr++; + } + *(bufp++) = '\0'; + + /* Check that there's no garbage after the value */ + while (*ptr) + { + if (*ptr == '#') + break; + if (!isspace((unsigned char) *ptr)) + return false; + ptr++; + } + + /* Success! */ + *key_p = key; + *value_p = value; + return true; +} + /* * See if there is a recovery command file (recovery.conf), and if so * read in parameters for archive recovery and XLOG streaming. @@ -4926,40 +5020,17 @@ readRecoveryCommandFile(void) */ while (fgets(cmdline, sizeof(cmdline), fd) != NULL) { - /* skip leading whitespace and check for # comment */ - char *ptr; char *tok1; char *tok2; - for (ptr = cmdline; *ptr; ptr++) + if (!parseRecoveryCommandFileLine(cmdline, &tok1, &tok2)) { - if (!isspace((unsigned char) *ptr)) - break; + syntaxError = true; + break; } - if (*ptr == '\0' || *ptr == '#') + if (tok1 == NULL) continue; - /* identify the quoted parameter value */ - tok1 = strtok(ptr, "'"); - if (!tok1) - { - syntaxError = true; - break; - } - tok2 = strtok(NULL, "'"); - if (!tok2) - { - syntaxError = true; - break; - } - /* reparse to get just the parameter name */ - tok1 = strtok(ptr, " \t="); - if (!tok1) - { - syntaxError = true; - break; - } - if (strcmp(tok1, "restore_command") == 0) { recoveryRestoreCommand = pstrdup(tok2);