diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c new file mode 100644 index e412d71..1aea485 *** a/src/bin/pg_ctl/pg_ctl.c --- b/src/bin/pg_ctl/pg_ctl.c *************** static void do_promote(void); *** 134,139 **** --- 134,140 ---- static void do_kill(pgpid_t pid); static void print_msg(const char *msg); static void adjust_data_dir(void); + static char *strip_datadirs(char *orig_post_opts); #if defined(WIN32) || defined(__CYGWIN__) static bool pgwin32_IsInstalled(SC_HANDLE); *************** read_post_opts(void) *** 719,724 **** --- 720,726 ---- int len; char *optline; char *arg1; + char *orig_post_opts = NULL; optline = optlines[0]; /* trim off line endings */ *************** read_post_opts(void) *** 733,742 **** { *arg1 = '\0'; /* terminate so we get only program * name */ ! post_opts = arg1 + 1; /* point past whitespace */ } if (exec_path == NULL) exec_path = optline; } } } --- 735,748 ---- { *arg1 = '\0'; /* terminate so we get only program * name */ ! orig_post_opts = arg1 + 1; /* point past whitespace */ } if (exec_path == NULL) exec_path = optline; + + if (orig_post_opts) { + post_opts = strip_datadirs(orig_post_opts); + } } } } *************** do_start(void) *** 819,826 **** read_post_opts(); ! /* No -D or -D already added during server start */ ! if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL) pgdata_opt = ""; if (exec_path == NULL) --- 825,831 ---- read_post_opts(); ! if (pgdata_opt == NULL) pgdata_opt = ""; if (exec_path == NULL) *************** adjust_data_dir(void) *** 1994,1999 **** --- 1999,2065 ---- } + /* + * Remove any "-D" "/path/to/datadir" specifications. We don't want to + * preserve these during a restart, since the user will be providing + * a possibly-conflicting datadir which should take precedence over + * the old value(s). Get rid of all such datadir specifications in + * the string, since a user might have manually launched the postmaster + * with redundant specifications, e.g. + * postgres -D /some/dir/ -D /some/dir/ ... + * + * Note, the simple parsing here won't cope with path specifications + * containing embedded quotes, such as + * "-D" "/foo \" bar/" + * but such paths seem to be currently unsupported for other reasons + * anyway, since `pg_ctl start` / `pg_ctl stop` have inconsistent + * handling of such paths. + */ + static char * + strip_datadirs(char *orig_post_opts) + { + char *datadir; + char *trailing_quote; + char *tmp = NULL; + char *post_opts = pg_strdup(orig_post_opts); + + #define DATADIR_SPEC "\"-D\" \"" + + datadir = strstr(post_opts, DATADIR_SPEC); + + while (datadir != NULL) { + trailing_quote = strchr(datadir + sizeof(DATADIR_SPEC), '"'); + if (trailing_quote) { + *datadir = '\0'; + + /* + * If there are any options after the -D ... + * specification, preserve them by concatenating. + * post_opts must have enough space for strcat(), + * since it is the same size as post_opts, but with + * an '\0' inserted at *datadir. + */ + if (*(trailing_quote + 1) != '\0') { + tmp = pg_strdup(trailing_quote + 1); + strcat(post_opts, tmp); + } + + datadir = strstr(post_opts, DATADIR_SPEC); + } + else { + write_stderr(_("%s: unable to parse post_opts: %s"), + progname, orig_post_opts); + post_opts = orig_post_opts; + break; + } + } + + free(tmp); + return post_opts; + } + + + int main(int argc, char **argv) {