Skip to content

Commit 0f11ed5

Browse files
committed
Allow quotes to be escaped in recovery.conf, by doubling them. This patch
also makes the parsing a little bit stricter, rejecting garbage after the parameter value and values with missing ending quotes, for example.
1 parent 370f770 commit 0f11ed5

File tree

2 files changed

+107
-28
lines changed

2 files changed

+107
-28
lines changed

doc/src/sgml/recovery-config.sgml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/recovery-config.sgml,v 2.3 2010/03/18 09:17:18 heikki Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/recovery-config.sgml,v 2.4 2010/04/07 10:58:49 heikki Exp $ -->
22

33
<chapter Id="recovery-config">
44
<title>Recovery Configuration</title>
@@ -18,6 +18,14 @@
1818
be changed once recovery has begun.
1919
</para>
2020

21+
<para>
22+
Settings in <filename>recovery.conf</> are specified in the format
23+
<literal>name = 'value'</>. One parameter is specified per line.
24+
Hash marks (<literal>#</literal>) designate the rest of the
25+
line as a comment. To embed a single quote in a parameter
26+
value, write two quotes (<literal>''</>).
27+
</para>
28+
2129
<sect1 id="archive-recovery-settings">
2230

2331
<title>Archive recovery settings</title>

src/backend/access/transam/xlog.c

Lines changed: 98 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.390 2010/04/07 06:12:52 heikki Exp $
10+
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.391 2010/04/07 10:58:49 heikki Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -4893,6 +4893,100 @@ str_time(pg_time_t tnow)
48934893
return buf;
48944894
}
48954895

4896+
/*
4897+
* Parse one line from recovery.conf. 'cmdline' is the raw line from the
4898+
* file. If the line is parsed successfully, returns true, false indicates
4899+
* syntax error. On success, *key_p and *value_p are set to the parameter
4900+
* name and value on the line, respectively. If the line is an empty line,
4901+
* consisting entirely of whitespace and comments, function returns true
4902+
* and *keyp_p and *value_p are set to NULL.
4903+
*
4904+
* The pointers returned in *key_p and *value_p point to an internal buffer
4905+
* that is valid only until the next call of parseRecoveryCommandFile().
4906+
*/
4907+
static bool
4908+
parseRecoveryCommandFileLine(char *cmdline, char **key_p, char **value_p)
4909+
{
4910+
char *ptr;
4911+
char *bufp;
4912+
char *key;
4913+
char *value;
4914+
static char *buf = NULL;
4915+
4916+
*key_p = *value_p = NULL;
4917+
4918+
/*
4919+
* Allocate the buffer on first use. It's used to hold both the
4920+
* parameter name and value.
4921+
*/
4922+
if (buf == NULL)
4923+
buf = malloc(MAXPGPATH + 1);
4924+
bufp = buf;
4925+
4926+
/* Skip any whitespace at the beginning of line */
4927+
for (ptr = cmdline; *ptr; ptr++)
4928+
{
4929+
if (!isspace((unsigned char) *ptr))
4930+
break;
4931+
}
4932+
/* Ignore empty lines */
4933+
if (*ptr == '\0' || *ptr == '#')
4934+
return true;
4935+
4936+
/* Read the parameter name */
4937+
key = bufp;
4938+
while (*ptr && !isspace((unsigned char) *ptr) &&
4939+
*ptr != '=' && *ptr != '\'')
4940+
*(bufp++) = *(ptr++);
4941+
*(bufp++) = '\0';
4942+
4943+
/* Skip to the beginning quote of the parameter value */
4944+
ptr = strchr(ptr, '\'');
4945+
if (!ptr)
4946+
return false;
4947+
ptr++;
4948+
4949+
/* Read the parameter value to *bufp. Collapse any '' escapes as we go. */
4950+
value = bufp;
4951+
for (;;)
4952+
{
4953+
if (*ptr == '\'')
4954+
{
4955+
ptr++;
4956+
if (*ptr == '\'')
4957+
*(bufp++) = '\'';
4958+
else
4959+
{
4960+
/* end of parameter */
4961+
*bufp = '\0';
4962+
break;
4963+
}
4964+
}
4965+
else if (*ptr == '\0')
4966+
return false; /* unterminated quoted string */
4967+
else
4968+
*(bufp++) = *ptr;
4969+
4970+
ptr++;
4971+
}
4972+
*(bufp++) = '\0';
4973+
4974+
/* Check that there's no garbage after the value */
4975+
while (*ptr)
4976+
{
4977+
if (*ptr == '#')
4978+
break;
4979+
if (!isspace((unsigned char) *ptr))
4980+
return false;
4981+
ptr++;
4982+
}
4983+
4984+
/* Success! */
4985+
*key_p = key;
4986+
*value_p = value;
4987+
return true;
4988+
}
4989+
48964990
/*
48974991
* See if there is a recovery command file (recovery.conf), and if so
48984992
* read in parameters for archive recovery and XLOG streaming.
@@ -4926,39 +5020,16 @@ readRecoveryCommandFile(void)
49265020
*/
49275021
while (fgets(cmdline, sizeof(cmdline), fd) != NULL)
49285022
{
4929-
/* skip leading whitespace and check for # comment */
4930-
char *ptr;
49315023
char *tok1;
49325024
char *tok2;
49335025

4934-
for (ptr = cmdline; *ptr; ptr++)
4935-
{
4936-
if (!isspace((unsigned char) *ptr))
4937-
break;
4938-
}
4939-
if (*ptr == '\0' || *ptr == '#')
4940-
continue;
4941-
4942-
/* identify the quoted parameter value */
4943-
tok1 = strtok(ptr, "'");
4944-
if (!tok1)
4945-
{
4946-
syntaxError = true;
4947-
break;
4948-
}
4949-
tok2 = strtok(NULL, "'");
4950-
if (!tok2)
4951-
{
4952-
syntaxError = true;
4953-
break;
4954-
}
4955-
/* reparse to get just the parameter name */
4956-
tok1 = strtok(ptr, " \t=");
4957-
if (!tok1)
5026+
if (!parseRecoveryCommandFileLine(cmdline, &tok1, &tok2))
49585027
{
49595028
syntaxError = true;
49605029
break;
49615030
}
5031+
if (tok1 == NULL)
5032+
continue;
49625033

49635034
if (strcmp(tok1, "restore_command") == 0)
49645035
{

0 commit comments

Comments
 (0)