aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin/pg_basebackup/pg_basebackup.c101
1 files changed, 89 insertions, 12 deletions
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 45585069a5e..84c34979228 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -1107,7 +1107,71 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
}
/*
- * Escape single quotes used in connection parameters
+ * Escape a parameter value so that it can be used as part of a libpq
+ * connection string, e.g. in:
+ *
+ * application_name=<value>
+ *
+ * The returned string is malloc'd. Return NULL on out-of-memory.
+ */
+static char *
+escapeConnectionParameter(const char *src)
+{
+ bool need_quotes = false;
+ bool need_escaping = false;
+ const char *p;
+ char *dstbuf;
+ char *dst;
+
+ /*
+ * First check if quoting is needed. Any quote (') or backslash (\)
+ * characters need to be escaped. Parameters are separated by whitespace,
+ * so any string containing whitespace characters need to be quoted. An
+ * empty string is represented by ''.
+ */
+ if (strchr(src, '\'') != NULL || strchr(src, '\\') != NULL)
+ need_escaping = true;
+
+ for (p = src; *p; p++)
+ {
+ if (isspace(*p))
+ {
+ need_quotes = true;
+ break;
+ }
+ }
+
+ if (*src == '\0')
+ return pg_strdup("''");
+
+ if (!need_quotes && !need_escaping)
+ return pg_strdup(src); /* no quoting or escaping needed */
+
+ /*
+ * Allocate a buffer large enough for the worst case that all the source
+ * characters need to be escaped, plus quotes.
+ */
+ dstbuf = pg_malloc(strlen(src) * 2 + 2 + 1);
+
+ dst = dstbuf;
+ if (need_quotes)
+ *(dst++) = '\'';
+ for (; *src; src++)
+ {
+ if (*src == '\'' || *src == '\\')
+ *(dst++) = '\\';
+ *(dst++) = *src;
+ }
+ if (need_quotes)
+ *(dst++) = '\'';
+ *dst = '\0';
+
+ return dstbuf;
+}
+
+/*
+ * Escape a string so that it can be used as a value in a key-value pair
+ * a configuration file.
*/
static char *
escape_quotes(const char *src)
@@ -1130,6 +1194,8 @@ GenerateRecoveryConf(PGconn *conn)
{
PQconninfoOption *connOptions;
PQconninfoOption *option;
+ PQExpBufferData conninfo_buf;
+ char *escaped;
recoveryconfcontents = createPQExpBuffer();
if (!recoveryconfcontents)
@@ -1146,12 +1212,10 @@ GenerateRecoveryConf(PGconn *conn)
}
appendPQExpBufferStr(recoveryconfcontents, "standby_mode = 'on'\n");
- appendPQExpBufferStr(recoveryconfcontents, "primary_conninfo = '");
+ initPQExpBuffer(&conninfo_buf);
for (option = connOptions; option && option->keyword; option++)
{
- char *escaped;
-
/*
* Do not emit this setting if: - the setting is "replication",
* "dbname" or "fallback_application_name", since these would be
@@ -1165,24 +1229,37 @@ GenerateRecoveryConf(PGconn *conn)
(option->val != NULL && option->val[0] == '\0'))
continue;
+ /* Separate key-value pairs with spaces */
+ if (conninfo_buf.len != 0)
+ appendPQExpBufferStr(&conninfo_buf, " ");
+
/*
- * Write "keyword='value'" pieces, the value string is escaped if
- * necessary and doubled single quotes around the value string.
+ * Write "keyword=value" pieces, the value string is escaped and/or
+ * quoted if necessary.
*/
- escaped = escape_quotes(option->val);
-
- appendPQExpBuffer(recoveryconfcontents, "%s=''%s'' ", option->keyword, escaped);
-
+ escaped = escapeConnectionParameter(option->val);
+ appendPQExpBuffer(&conninfo_buf, "%s=%s", option->keyword, escaped);
free(escaped);
}
- appendPQExpBufferStr(recoveryconfcontents, "'\n");
- if (PQExpBufferBroken(recoveryconfcontents))
+ /*
+ * Escape the connection string, so that it can be put in the config file.
+ * Note that this is different from the escaping of individual connection
+ * options above!
+ */
+ escaped = escape_quotes(conninfo_buf.data);
+ appendPQExpBuffer(recoveryconfcontents, "primary_conninfo = '%s'\n", escaped);
+ free(escaped);
+
+ if (PQExpBufferBroken(recoveryconfcontents) ||
+ PQExpBufferDataBroken(conninfo_buf))
{
fprintf(stderr, _("%s: out of memory\n"), progname);
disconnect_and_exit(1);
}
+ termPQExpBuffer(&conninfo_buf);
+
PQconninfoFree(connOptions);
}