aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/protocol.sgml5
-rw-r--r--src/backend/postmaster/postmaster.c3
-rw-r--r--src/backend/utils/init/postinit.c52
3 files changed, 43 insertions, 17 deletions
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index e519ff96b90..a8a09e4f0ec 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -4734,7 +4734,10 @@ StartupMessage (F)
set at backend start time might be listed. Such settings
will be applied during backend start (after parsing the
command-line options if any). The values will act as
- session defaults.
+ session defaults. Spaces in option values need to be escaped
+ with a backslash (<literal>\</>). A literal backslash can be
+ passed by escaping it with another backslash
+ (i.e <literal>\\</>).
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index b190cf51136..14535c8b35a 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -4083,8 +4083,7 @@ BackendRun(Port *port)
/*
* Pass any backend switches specified with -o on the postmaster's own
- * command line. We assume these are secure. (It's OK to mangle
- * ExtraOptions now, since we're safely inside a subprocess.)
+ * command line. We assume these are secure.
*/
pg_split_opts(av, &ac, ExtraOptions);
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index a5b98217739..304be047892 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -409,32 +409,57 @@ InitCommunication(void)
/*
* pg_split_opts -- split a string of options and append it to an argv array
*
- * NB: the input string is destructively modified! Also, caller is responsible
- * for ensuring the argv array is large enough. The maximum possible number
- * of arguments added by this routine is (strlen(optstr) + 1) / 2.
+ * The caller is responsible for ensuring the argv array is large enough. The
+ * maximum possible number of arguments added by this routine is
+ * (strlen(optstr) + 1) / 2.
*
- * Since no current POSTGRES arguments require any quoting characters,
- * we can use the simple-minded tactic of assuming each set of space-
- * delimited characters is a separate argv element.
- *
- * If you don't like that, well, we *used* to pass the whole option string
- * as ONE argument to execl(), which was even less intelligent...
+ * Because some option values can contain spaces we allow escaping using
+ * backslashes, with \\ representing a literal backslash.
*/
void
pg_split_opts(char **argv, int *argcp, char *optstr)
{
+ StringInfoData s;
+
+ initStringInfo(&s);
+
while (*optstr)
{
+ bool last_was_escape = false;
+
+ resetStringInfo(&s);
+
+ /* skip over leading space */
while (isspace((unsigned char) *optstr))
optstr++;
+
if (*optstr == '\0')
break;
- argv[(*argcp)++] = optstr;
- while (*optstr && !isspace((unsigned char) *optstr))
+
+ /*
+ * Parse a single option + value, stopping at the first space, unless
+ * it's escaped.
+ */
+ while (*optstr)
+ {
+ if (isspace(*optstr) && !last_was_escape)
+ break;
+
+ if (!last_was_escape && *optstr == '\\')
+ last_was_escape = true;
+ else
+ {
+ last_was_escape = false;
+ appendStringInfoChar(&s, *optstr);
+ }
+
optstr++;
- if (*optstr)
- *optstr++ = '\0';
+ }
+
+ /* now store the option */
+ argv[(*argcp)++] = pstrdup(s.data);
}
+ resetStringInfo(&s);
}
/*
@@ -981,7 +1006,6 @@ process_startup_options(Port *port, bool am_superuser)
av[ac++] = "postgres";
- /* Note this mangles port->cmdline_options */
pg_split_opts(av, &ac, port->cmdline_options);
av[ac] = NULL;