]> granicus.if.org Git - postgresql/blobdiff - src/test/regress/pg_regress.c
Update copyright for 2016
[postgresql] / src / test / regress / pg_regress.c
index 13842231ce14f2b69d8b47c385613247af71dcf2..a1902fe1271648fb3e877da511f1393843e04ee3 100644 (file)
@@ -8,7 +8,7 @@
  *
  * This code is released under the terms of the PostgreSQL License.
  *
- * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/test/regress/pg_regress.c
 #include <sys/resource.h>
 #endif
 
+#include "common/restricted_token.h"
+#include "common/username.h"
 #include "getopt_long.h"
+#include "libpq/pqcomm.h"              /* needed for UNIXSOCK_PATH() */
 #include "pg_config_paths.h"
 
 /* for resultmap we need a list of pairs of strings */
@@ -39,35 +42,20 @@ typedef struct _resultmap
        char       *type;
        char       *resultfile;
        struct _resultmap *next;
-}      _resultmap;
+} _resultmap;
 
 /*
- * Values obtained from pg_config_paths.h and Makefile.  The PG installation
- * paths are only used in temp_install mode: we use these strings to find
- * out where "make install" will put stuff under the temp_install directory.
- * In non-temp_install mode, the only thing we need is the location of psql,
- * which we expect to find in psqldir, or in the PATH if psqldir isn't given.
- *
- * XXX Because pg_regress is not installed in bindir, we can't support
- * this for relocatable trees as it is.  --psqldir would need to be
- * specified in those cases.
+ * Values obtained from Makefile.
  */
-char      *bindir = PGBINDIR;
-char      *libdir = LIBDIR;
-char      *datadir = PGSHAREDIR;
 char      *host_platform = HOST_TUPLE;
 
-#ifndef WIN32_ONLY_COMPILER
-static char *makeprog = MAKEPROG;
-#endif
-
 #ifndef WIN32                                  /* not used in WIN32 case */
 static char *shellprog = SHELLPROG;
 #endif
 
 /*
  * On Windows we use -w in diff switches to avoid problems with inconsistent
- * newline representation.     The actual result files will generally have
+ * newline representation.  The actual result files will generally have
  * Windows-style newlines, but the comparison files might or might not.
  */
 #ifndef WIN32
@@ -83,7 +71,7 @@ _stringlist *dblist = NULL;
 bool           debug = false;
 char      *inputdir = ".";
 char      *outputdir = ".";
-char      *psqldir = PGBINDIR;
+char      *bindir = PGBINDIR;
 char      *launcher = NULL;
 static _stringlist *loadlanguage = NULL;
 static _stringlist *loadextension = NULL;
@@ -91,9 +79,8 @@ static int    max_connections = 0;
 static char *encoding = NULL;
 static _stringlist *schedulelist = NULL;
 static _stringlist *extra_tests = NULL;
-static char *temp_install = NULL;
+static char *temp_instance = NULL;
 static char *temp_config = NULL;
-static char *top_builddir = NULL;
 static bool nolocale = false;
 static bool use_existing = false;
 static char *hostname = NULL;
@@ -102,13 +89,19 @@ static bool port_specified_by_user = false;
 static char *dlpath = PKGLIBDIR;
 static char *user = NULL;
 static _stringlist *extraroles = NULL;
-static _stringlist *extra_install = NULL;
+static char *config_auth_datadir = NULL;
 
 /* internal variables */
 static const char *progname;
 static char *logfilename;
 static FILE *logfile;
 static char *difffilename;
+static const char *sockdir;
+#ifdef HAVE_UNIX_SOCKETS
+static const char *temp_sockdir;
+static char sockself[MAXPGPATH];
+static char socklock[MAXPGPATH];
+#endif
 
 static _resultmap *resultmap = NULL;
 
@@ -122,30 +115,9 @@ static int fail_ignore_count = 0;
 static bool directory_exists(const char *dir);
 static void make_directory(const char *dir);
 
-static void
-header(const char *fmt,...)
-/* This extension allows gcc to check the format string for consistency with
-   the supplied arguments. */
-__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
-static void
-status(const char *fmt,...)
-/* This extension allows gcc to check the format string for consistency with
-   the supplied arguments. */
-__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
-static void
-psql_command(const char *database, const char *query,...)
-/* This extension allows gcc to check the format string for consistency with
-   the supplied arguments. */
-__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
-
-#ifdef WIN32
-typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
-
-/* Windows API define missing from some versions of MingW headers */
-#ifndef  DISABLE_MAX_PRIVILEGE
-#define DISABLE_MAX_PRIVILEGE  0x1
-#endif
-#endif
+static void header(const char *fmt,...) pg_attribute_printf(1, 2);
+static void status(const char *fmt,...) pg_attribute_printf(1, 2);
+static void psql_command(const char *database, const char *query,...) pg_attribute_printf(2, 3);
 
 /*
  * allow core files if possible.
@@ -177,7 +149,7 @@ unlimit_core_size(void)
  * Add an item at the end of a stringlist.
  */
 void
-add_stringlist_item(_stringlist ** listhead, const char *str)
+add_stringlist_item(_stringlist **listhead, const char *str)
 {
        _stringlist *newentry = malloc(sizeof(_stringlist));
        _stringlist *oldentry;
@@ -198,7 +170,7 @@ add_stringlist_item(_stringlist ** listhead, const char *str)
  * Free a stringlist.
  */
 static void
-free_stringlist(_stringlist ** listhead)
+free_stringlist(_stringlist **listhead)
 {
        if (listhead == NULL || *listhead == NULL)
                return;
@@ -213,7 +185,7 @@ free_stringlist(_stringlist ** listhead)
  * Split a delimited string into a stringlist
  */
 static void
-split_to_stringlist(const char *s, const char *delim, _stringlist ** listhead)
+split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
 {
        char       *sc = strdup(s);
        char       *token = strtok(sc, delim);
@@ -293,8 +265,10 @@ stop_postmaster(void)
                fflush(stderr);
 
                snprintf(buf, sizeof(buf),
-                                SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE,
-                                bindir, temp_install);
+                                "\"%s%spg_ctl\" stop -D \"%s/data\" -s -m fast",
+                                bindir ? bindir : "",
+                                bindir ? "/" : "",
+                                temp_instance);
                r = system(buf);
                if (r != 0)
                {
@@ -307,6 +281,82 @@ stop_postmaster(void)
        }
 }
 
+#ifdef HAVE_UNIX_SOCKETS
+/*
+ * Remove the socket temporary directory.  pg_regress never waits for a
+ * postmaster exit, so it is indeterminate whether the postmaster has yet to
+ * unlink the socket and lock file.  Unlink them here so we can proceed to
+ * remove the directory.  Ignore errors; leaking a temporary directory is
+ * unimportant.  This can run from a signal handler.  The code is not
+ * acceptable in a Windows signal handler (see initdb.c:trapsig()), but
+ * Windows is not a HAVE_UNIX_SOCKETS platform.
+ */
+static void
+remove_temp(void)
+{
+       Assert(temp_sockdir);
+       unlink(sockself);
+       unlink(socklock);
+       rmdir(temp_sockdir);
+}
+
+/*
+ * Signal handler that calls remove_temp() and reraises the signal.
+ */
+static void
+signal_remove_temp(int signum)
+{
+       remove_temp();
+
+       pqsignal(signum, SIG_DFL);
+       raise(signum);
+}
+
+/*
+ * Create a temporary directory suitable for the server's Unix-domain socket.
+ * The directory will have mode 0700 or stricter, so no other OS user can open
+ * our socket to exploit our use of trust authentication.  Most systems
+ * constrain the length of socket paths well below _POSIX_PATH_MAX, so we
+ * place the directory under /tmp rather than relative to the possibly-deep
+ * current working directory.
+ *
+ * Compared to using the compiled-in DEFAULT_PGSOCKET_DIR, this also permits
+ * testing to work in builds that relocate it to a directory not writable to
+ * the build/test user.
+ */
+static const char *
+make_temp_sockdir(void)
+{
+       char       *template = strdup("/tmp/pg_regress-XXXXXX");
+
+       temp_sockdir = mkdtemp(template);
+       if (temp_sockdir == NULL)
+       {
+               fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
+                               progname, template, strerror(errno));
+               exit(2);
+       }
+
+       /* Stage file names for remove_temp().  Unsafe in a signal handler. */
+       UNIXSOCK_PATH(sockself, port, temp_sockdir);
+       snprintf(socklock, sizeof(socklock), "%s.lock", sockself);
+
+       /* Remove the directory during clean exit. */
+       atexit(remove_temp);
+
+       /*
+        * Remove the directory before dying to the usual signals.  Omit SIGQUIT,
+        * preserving it as a quick, untidy exit.
+        */
+       pqsignal(SIGHUP, signal_remove_temp);
+       pqsignal(SIGINT, signal_remove_temp);
+       pqsignal(SIGPIPE, signal_remove_temp);
+       pqsignal(SIGTERM, signal_remove_temp);
+
+       return temp_sockdir;
+}
+#endif   /* HAVE_UNIX_SOCKETS */
+
 /*
  * Check whether string matches pattern
  *
@@ -381,7 +431,7 @@ string_matches_pattern(const char *str, const char *pattern)
 }
 
 /*
- * Replace all occurances of a string in a string with a different string.
+ * Replace all occurrences of a string in a string with a different string.
  * NOTE: Assumes there is enough room in the target buffer!
  */
 void
@@ -407,7 +457,7 @@ replace_string(char *string, char *replace, char *replacement)
  * the given suffix.
  */
 static void
-convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
+convert_sourcefiles_in(char *source_subdir, char *dest_dir, char *dest_subdir, char *suffix)
 {
        char            testtablespace[MAXPGPATH];
        char            indir[MAXPGPATH];
@@ -450,7 +500,12 @@ convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
         * Windows.  See pgsql-hackers discussion of 2008-01-18.
         */
        if (directory_exists(testtablespace))
-               rmtree(testtablespace, true);
+               if (!rmtree(testtablespace, true))
+               {
+                       fprintf(stderr, _("\n%s: could not remove test tablespace \"%s\"\n"),
+                                       progname, testtablespace);
+                       exit(2);
+               }
        make_directory(testtablespace);
 #endif
 
@@ -475,7 +530,8 @@ convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
                /* build the full actual paths to open */
                snprintf(prefix, strlen(*name) - 6, "%s", *name);
                snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
-               snprintf(destfile, MAXPGPATH, "%s/%s.%s", dest_subdir, prefix, suffix);
+               snprintf(destfile, MAXPGPATH, "%s/%s/%s.%s", dest_dir, dest_subdir,
+                                prefix, suffix);
 
                infile = fopen(srcfile, "r");
                if (!infile)
@@ -522,8 +578,8 @@ convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
 static void
 convert_sourcefiles(void)
 {
-       convert_sourcefiles_in("input", "sql", "sql");
-       convert_sourcefiles_in("output", "expected", "out");
+       convert_sourcefiles_in("input", outputdir, "sql", "sql");
+       convert_sourcefiles_in("output", outputdir, "expected", "out");
 }
 
 /*
@@ -535,7 +591,7 @@ convert_sourcefiles(void)
  * namely, it is a standard regular expression with an implicit ^ at the start.
  * (We currently support only a very limited subset of regular expressions,
  * see string_matches_pattern() above.)  What hostplatformpattern will be
- * matched against is the config.guess output. (In the shell-script version,
+ * matched against is the config.guess output.  (In the shell-script version,
  * we also provided an indication of whether gcc or another compiler was in
  * use, but that facility isn't used anymore.)
  */
@@ -653,44 +709,18 @@ get_expectfile(const char *testname, const char *file)
 static void
 doputenv(const char *var, const char *val)
 {
-       char       *s = malloc(strlen(var) + strlen(val) + 2);
+       char       *s;
 
-       sprintf(s, "%s=%s", var, val);
+       s = psprintf("%s=%s", var, val);
        putenv(s);
 }
 
-/*
- * Set the environment variable "pathname", prepending "addval" to its
- * old value (if any).
- */
-static void
-add_to_path(const char *pathname, char separator, const char *addval)
-{
-       char       *oldval = getenv(pathname);
-       char       *newval;
-
-       if (!oldval || !oldval[0])
-       {
-               /* no previous value */
-               newval = malloc(strlen(pathname) + strlen(addval) + 2);
-               sprintf(newval, "%s=%s", pathname, addval);
-       }
-       else
-       {
-               newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
-               sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval);
-       }
-       putenv(newval);
-}
-
 /*
  * Prepare environment variables for running regression tests
  */
 static void
 initialize_environment(void)
 {
-       char       *tmp;
-
        putenv("PGAPPNAME=pg_regress");
 
        if (nolocale)
@@ -704,9 +734,17 @@ initialize_environment(void)
                unsetenv("LC_NUMERIC");
                unsetenv("LC_TIME");
                unsetenv("LANG");
-               /* On Windows the default locale cannot be English, so force it */
-#if defined(WIN32) || defined(__CYGWIN__)
-               putenv("LANG=en");
+
+               /*
+                * Most platforms have adopted the POSIX locale as their
+                * implementation-defined default locale.  Exceptions include native
+                * Windows, Darwin with --enable-nls, and Cygwin with --enable-nls.
+                * (Use of --enable-nls matters because libintl replaces setlocale().)
+                * Also, PostgreSQL does not support Darwin with locale environment
+                * variables unset; see PostmasterMain().
+                */
+#if defined(WIN32) || defined(__CYGWIN__) || defined(__darwin__)
+               putenv("LANG=C");
 #endif
        }
 
@@ -746,20 +784,19 @@ initialize_environment(void)
 
                if (!old_pgoptions)
                        old_pgoptions = "";
-               new_pgoptions = malloc(strlen(old_pgoptions) + strlen(my_pgoptions) + 12);
-               sprintf(new_pgoptions, "PGOPTIONS=%s %s", old_pgoptions, my_pgoptions);
+               new_pgoptions = psprintf("PGOPTIONS=%s %s",
+                                                                old_pgoptions, my_pgoptions);
                putenv(new_pgoptions);
        }
 
-       if (temp_install)
+       if (temp_instance)
        {
                /*
                 * Clear out any environment vars that might cause psql to connect to
                 * the wrong postmaster, or otherwise behave in nondefault ways. (Note
                 * we also use psql's -X switch consistently, so that ~/.psqlrc files
                 * won't mess things up.)  Also, set PGPORT to the temp port, and set
-                * or unset PGHOST depending on whether we are using TCP or Unix
-                * sockets.
+                * PGHOST depending on whether we are using TCP or Unix sockets.
                 */
                unsetenv("PGDATABASE");
                unsetenv("PGUSER");
@@ -768,10 +805,20 @@ initialize_environment(void)
                unsetenv("PGREQUIRESSL");
                unsetenv("PGCONNECT_TIMEOUT");
                unsetenv("PGDATA");
+#ifdef HAVE_UNIX_SOCKETS
                if (hostname != NULL)
                        doputenv("PGHOST", hostname);
                else
-                       unsetenv("PGHOST");
+               {
+                       sockdir = getenv("PG_REGRESS_SOCK_DIR");
+                       if (!sockdir)
+                               sockdir = make_temp_sockdir();
+                       doputenv("PGHOST", sockdir);
+               }
+#else
+               Assert(hostname != NULL);
+               doputenv("PGHOST", hostname);
+#endif
                unsetenv("PGHOSTADDR");
                if (port != -1)
                {
@@ -780,42 +827,6 @@ initialize_environment(void)
                        sprintf(s, "%d", port);
                        doputenv("PGPORT", s);
                }
-
-               /*
-                * Adjust path variables to point into the temp-install tree
-                */
-               tmp = malloc(strlen(temp_install) + 32 + strlen(bindir));
-               sprintf(tmp, "%s/install/%s", temp_install, bindir);
-               bindir = tmp;
-
-               tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
-               sprintf(tmp, "%s/install/%s", temp_install, libdir);
-               libdir = tmp;
-
-               tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
-               sprintf(tmp, "%s/install/%s", temp_install, datadir);
-               datadir = tmp;
-
-               /* psql will be installed into temp-install bindir */
-               psqldir = bindir;
-
-               /*
-                * Set up shared library paths to include the temp install.
-                *
-                * LD_LIBRARY_PATH covers many platforms.  DYLD_LIBRARY_PATH works on
-                * Darwin, and maybe other Mach-based systems.  LIBPATH is for AIX.
-                * Windows needs shared libraries in PATH (only those linked into
-                * executables, not dlopen'ed ones). Feel free to account for others
-                * as well.
-                */
-               add_to_path("LD_LIBRARY_PATH", ':', libdir);
-               add_to_path("DYLD_LIBRARY_PATH", ':', libdir);
-               add_to_path("LIBPATH", ':', libdir);
-#if defined(WIN32)
-               add_to_path("PATH", ';', libdir);
-#elif defined(__CYGWIN__)
-               add_to_path("PATH", ':', libdir);
-#endif
        }
        else
        {
@@ -865,6 +876,176 @@ initialize_environment(void)
        load_resultmap();
 }
 
+#ifdef ENABLE_SSPI
+/*
+ * Get account and domain/realm names for the current user.  This is based on
+ * pg_SSPI_recvauth().  The returned strings use static storage.
+ */
+static void
+current_windows_user(const char **acct, const char **dom)
+{
+       static char accountname[MAXPGPATH];
+       static char domainname[MAXPGPATH];
+       HANDLE          token;
+       TOKEN_USER *tokenuser;
+       DWORD           retlen;
+       DWORD           accountnamesize = sizeof(accountname);
+       DWORD           domainnamesize = sizeof(domainname);
+       SID_NAME_USE accountnameuse;
+
+       if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token))
+       {
+               fprintf(stderr,
+                               _("%s: could not open process token: error code %lu\n"),
+                               progname, GetLastError());
+               exit(2);
+       }
+
+       if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && GetLastError() != 122)
+       {
+               fprintf(stderr,
+                               _("%s: could not get token user size: error code %lu\n"),
+                               progname, GetLastError());
+               exit(2);
+       }
+       tokenuser = malloc(retlen);
+       if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen))
+       {
+               fprintf(stderr,
+                               _("%s: could not get token user: error code %lu\n"),
+                               progname, GetLastError());
+               exit(2);
+       }
+
+       if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, &accountnamesize,
+                                                 domainname, &domainnamesize, &accountnameuse))
+       {
+               fprintf(stderr,
+                               _("%s: could not look up account SID: error code %lu\n"),
+                               progname, GetLastError());
+               exit(2);
+       }
+
+       free(tokenuser);
+
+       *acct = accountname;
+       *dom = domainname;
+}
+
+/*
+ * Rewrite pg_hba.conf and pg_ident.conf to use SSPI authentication.  Permit
+ * the current OS user to authenticate as the bootstrap superuser and as any
+ * user named in a --create-role option.
+ */
+static void
+config_sspi_auth(const char *pgdata)
+{
+       const char *accountname,
+                          *domainname;
+       const char *username;
+       char       *errstr;
+       bool            have_ipv6;
+       char            fname[MAXPGPATH];
+       int                     res;
+       FILE       *hba,
+                          *ident;
+       _stringlist *sl;
+
+       /*
+        * "username", the initdb-chosen bootstrap superuser name, may always
+        * match "accountname", the value SSPI authentication discovers.  The
+        * underlying system functions do not clearly guarantee that.
+        */
+       current_windows_user(&accountname, &domainname);
+       username = get_user_name(&errstr);
+       if (username == NULL)
+       {
+               fprintf(stderr, "%s: %s\n", progname, errstr);
+               exit(2);
+       }
+
+       /*
+        * Like initdb.c:setup_config(), determine whether the platform recognizes
+        * ::1 (IPv6 loopback) as a numeric host address string.
+        */
+       {
+               struct addrinfo *gai_result;
+               struct addrinfo hints;
+               WSADATA         wsaData;
+
+               hints.ai_flags = AI_NUMERICHOST;
+               hints.ai_family = AF_UNSPEC;
+               hints.ai_socktype = 0;
+               hints.ai_protocol = 0;
+               hints.ai_addrlen = 0;
+               hints.ai_canonname = NULL;
+               hints.ai_addr = NULL;
+               hints.ai_next = NULL;
+
+               have_ipv6 = (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0 &&
+                                        getaddrinfo("::1", NULL, &hints, &gai_result) == 0);
+       }
+
+       /* Check a Write outcome and report any error. */
+#define CW(cond)       \
+       do { \
+               if (!(cond)) \
+               { \
+                       fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"), \
+                                       progname, fname, strerror(errno)); \
+                       exit(2); \
+               } \
+       } while (0)
+
+       res = snprintf(fname, sizeof(fname), "%s/pg_hba.conf", pgdata);
+       if (res < 0 || res >= sizeof(fname) - 1)
+       {
+               /*
+                * Truncating this name is a fatal error, because we must not fail to
+                * overwrite an original trust-authentication pg_hba.conf.
+                */
+               fprintf(stderr, _("%s: directory name too long\n"), progname);
+               exit(2);
+       }
+       hba = fopen(fname, "w");
+       if (hba == NULL)
+       {
+               fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
+                               progname, fname, strerror(errno));
+               exit(2);
+       }
+       CW(fputs("# Configuration written by config_sspi_auth()\n", hba) >= 0);
+       CW(fputs("host all all 127.0.0.1/32  sspi include_realm=1 map=regress\n",
+                        hba) >= 0);
+       if (have_ipv6)
+               CW(fputs("host all all ::1/128  sspi include_realm=1 map=regress\n",
+                                hba) >= 0);
+       CW(fclose(hba) == 0);
+
+       snprintf(fname, sizeof(fname), "%s/pg_ident.conf", pgdata);
+       ident = fopen(fname, "w");
+       if (ident == NULL)
+       {
+               fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
+                               progname, fname, strerror(errno));
+               exit(2);
+       }
+       CW(fputs("# Configuration written by config_sspi_auth()\n", ident) >= 0);
+
+       /*
+        * Double-quote for the benefit of account names containing whitespace or
+        * '#'.  Windows forbids the double-quote character itself, so don't
+        * bother escaping embedded double-quote characters.
+        */
+       CW(fprintf(ident, "regress  \"%s@%s\"  \"%s\"\n",
+                          accountname, domainname, username) >= 0);
+       for (sl = extraroles; sl; sl = sl->next)
+               CW(fprintf(ident, "regress  \"%s@%s\"  \"%s\"\n",
+                                  accountname, domainname, sl->str) >= 0);
+       CW(fclose(ident) == 0);
+}
+#endif
+
 /*
  * Issue a command via psql, connecting to the specified database
  *
@@ -897,9 +1078,9 @@ psql_command(const char *database, const char *query,...)
 
        /* And now we can build and execute the shell command */
        snprintf(psql_cmd, sizeof(psql_cmd),
-                        SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE,
-                        psqldir ? psqldir : "",
-                        psqldir ? "/" : "",
+                        "\"%s%spsql\" -X -c \"%s\" \"%s\"",
+                        bindir ? bindir : "",
+                        bindir ? "/" : "",
                         query_escaped,
                         database);
 
@@ -923,7 +1104,7 @@ spawn_process(const char *cmdline)
        pid_t           pid;
 
        /*
-        * Must flush I/O buffers before fork.  Ideally we'd use fflush(NULL) here
+        * Must flush I/O buffers before fork.  Ideally we'd use fflush(NULL) here
         * ... does anyone still care about systems where that doesn't work?
         */
        fflush(stdout);
@@ -944,12 +1125,12 @@ spawn_process(const char *cmdline)
                 * In child
                 *
                 * Instead of using system(), exec the shell directly, and tell it to
-                * "exec" the command too.      This saves two useless processes per
+                * "exec" the command too.  This saves two useless processes per
                 * parallel test case.
                 */
-               char       *cmdline2 = malloc(strlen(cmdline) + 6);
+               char       *cmdline2;
 
-               sprintf(cmdline2, "exec %s", cmdline);
+               cmdline2 = psprintf("exec %s", cmdline);
                execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
                fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
                                progname, shellprog, strerror(errno));
@@ -958,101 +1139,17 @@ spawn_process(const char *cmdline)
        /* in parent */
        return pid;
 #else
-       char       *cmdline2;
-       BOOL            b;
-       STARTUPINFO si;
        PROCESS_INFORMATION pi;
-       HANDLE          origToken;
+       char       *cmdline2;
        HANDLE          restrictedToken;
-       SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
-       SID_AND_ATTRIBUTES dropSids[2];
-       __CreateRestrictedToken _CreateRestrictedToken = NULL;
-       HANDLE          Advapi32Handle;
-
-       ZeroMemory(&si, sizeof(si));
-       si.cb = sizeof(si);
-
-       Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
-       if (Advapi32Handle != NULL)
-       {
-               _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
-       }
-
-       if (_CreateRestrictedToken == NULL)
-       {
-               if (Advapi32Handle != NULL)
-                       FreeLibrary(Advapi32Handle);
-               fprintf(stderr, _("%s: cannot create restricted tokens on this platform\n"),
-                               progname);
-               exit(2);
-       }
-
-       /* Open the current token to use as base for the restricted one */
-       if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
-       {
-               fprintf(stderr, _("could not open process token: error code %lu\n"),
-                               GetLastError());
-               exit(2);
-       }
-
-       /* Allocate list of SIDs to remove */
-       ZeroMemory(&dropSids, sizeof(dropSids));
-       if (!AllocateAndInitializeSid(&NtAuthority, 2,
-                                                                 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) ||
-               !AllocateAndInitializeSid(&NtAuthority, 2,
-                                                                 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid))
-       {
-               fprintf(stderr, _("could not allocate SIDs: error code %lu\n"), GetLastError());
-               exit(2);
-       }
 
-       b = _CreateRestrictedToken(origToken,
-                                                          DISABLE_MAX_PRIVILEGE,
-                                                          sizeof(dropSids) / sizeof(dropSids[0]),
-                                                          dropSids,
-                                                          0, NULL,
-                                                          0, NULL,
-                                                          &restrictedToken);
+       memset(&pi, 0, sizeof(pi));
+       cmdline2 = psprintf("cmd /c \"%s\"", cmdline);
 
-       FreeSid(dropSids[1].Sid);
-       FreeSid(dropSids[0].Sid);
-       CloseHandle(origToken);
-       FreeLibrary(Advapi32Handle);
-
-       if (!b)
-       {
-               fprintf(stderr, _("could not create restricted token: error code %lu\n"),
-                               GetLastError());
+       if ((restrictedToken =
+                CreateRestrictedProcess(cmdline2, &pi, progname)) == 0)
                exit(2);
-       }
-
-       cmdline2 = malloc(strlen(cmdline) + 8);
-       sprintf(cmdline2, "cmd /c %s", cmdline);
-
-#ifndef __CYGWIN__
-       AddUserToTokenDacl(restrictedToken);
-#endif
-
-       if (!CreateProcessAsUser(restrictedToken,
-                                                        NULL,
-                                                        cmdline2,
-                                                        NULL,
-                                                        NULL,
-                                                        TRUE,
-                                                        CREATE_SUSPENDED,
-                                                        NULL,
-                                                        NULL,
-                                                        &si,
-                                                        &pi))
-       {
-               fprintf(stderr, _("could not start process for \"%s\": error code %lu\n"),
-                               cmdline2, GetLastError());
-               exit(2);
-       }
 
-       free(cmdline2);
-
-       ResumeThread(pi.hThread);
        CloseHandle(pi.hThread);
        return pi.hProcess;
 #endif
@@ -1147,8 +1244,17 @@ get_alternative_expectfile(const char *expectfile, int i)
 {
        char       *last_dot;
        int                     ssize = strlen(expectfile) + 2 + 1;
-       char       *tmp = (char *) malloc(ssize);
-       char       *s = (char *) malloc(ssize);
+       char       *tmp;
+       char       *s;
+
+       if (!(tmp = (char *) malloc(ssize)))
+               return NULL;
+
+       if (!(s = (char *) malloc(ssize)))
+       {
+               free(tmp);
+               return NULL;
+       }
 
        strcpy(tmp, expectfile);
        last_dot = strrchr(tmp, '.');
@@ -1219,7 +1325,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
         */
        platform_expectfile = get_expectfile(testname, resultsfile);
 
-       strcpy(expectfile, default_expectfile);
+       strlcpy(expectfile, default_expectfile, sizeof(expectfile));
        if (platform_expectfile)
        {
                /*
@@ -1237,7 +1343,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
 
        /* OK, run the diff */
        snprintf(cmd, sizeof(cmd),
-                        SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
+                        "diff %s \"%s\" \"%s\" > \"%s\"",
                         basic_diff_opts, expectfile, resultsfile, diff);
 
        /* Is the diff file empty? */
@@ -1256,16 +1362,27 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
                char       *alt_expectfile;
 
                alt_expectfile = get_alternative_expectfile(expectfile, i);
+               if (!alt_expectfile)
+               {
+                       fprintf(stderr, _("Unable to check secondary comparison files: %s\n"),
+                                       strerror(errno));
+                       exit(2);
+               }
+
                if (!file_exists(alt_expectfile))
+               {
+                       free(alt_expectfile);
                        continue;
+               }
 
                snprintf(cmd, sizeof(cmd),
-                                SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
+                                "diff %s \"%s\" \"%s\" > \"%s\"",
                                 basic_diff_opts, alt_expectfile, resultsfile, diff);
 
                if (run_diff(cmd, diff) == 0)
                {
                        unlink(diff);
+                       free(alt_expectfile);
                        return false;
                }
 
@@ -1274,7 +1391,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
                {
                        /* This diff was a better match than the last one */
                        best_line_count = l;
-                       strcpy(best_expect_file, alt_expectfile);
+                       strlcpy(best_expect_file, alt_expectfile, sizeof(best_expect_file));
                }
                free(alt_expectfile);
        }
@@ -1287,7 +1404,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
        if (platform_expectfile)
        {
                snprintf(cmd, sizeof(cmd),
-                                SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
+                                "diff %s \"%s\" \"%s\" > \"%s\"",
                                 basic_diff_opts, default_expectfile, resultsfile, diff);
 
                if (run_diff(cmd, diff) == 0)
@@ -1302,7 +1419,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
                {
                        /* This diff was a better match than the last one */
                        best_line_count = l;
-                       strcpy(best_expect_file, default_expectfile);
+                       strlcpy(best_expect_file, default_expectfile, sizeof(best_expect_file));
                }
        }
 
@@ -1311,7 +1428,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
         * append to the diffs summary file.
         */
        snprintf(cmd, sizeof(cmd),
-                        SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE,
+                        "diff %s \"%s\" \"%s\" >> \"%s\"",
                         pretty_diff_opts, best_expect_file, resultsfile, difffilename);
        run_diff(cmd, difffilename);
 
@@ -1653,6 +1770,8 @@ run_schedule(const char *schedule, test_function tfunc)
                }
        }
 
+       free_stringlist(&ignorelist);
+
        fclose(scf);
 }
 
@@ -1789,7 +1908,7 @@ create_database(const char *dbname)
                                 dbname, dbname, dbname, dbname, dbname);
 
        /*
-        * Install any requested procedural languages.  We use CREATE OR REPLACE
+        * Install any requested procedural languages.  We use CREATE OR REPLACE
         * so that this will work whether or not the language is preinstalled.
         */
        for (sl = loadlanguage; sl != NULL; sl = sl->next)
@@ -1817,7 +1936,7 @@ drop_role_if_exists(const char *rolename)
 }
 
 static void
-create_role(const char *rolename, const _stringlist * granted_dbs)
+create_role(const char *rolename, const _stringlist *granted_dbs)
 {
        header(_("creating role \"%s\""), rolename);
        psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename);
@@ -1828,34 +1947,6 @@ create_role(const char *rolename, const _stringlist * granted_dbs)
        }
 }
 
-static char *
-make_absolute_path(const char *in)
-{
-       char       *result;
-
-       if (is_absolute_path(in))
-               result = strdup(in);
-       else
-       {
-               static char cwdbuf[MAXPGPATH];
-
-               if (!cwdbuf[0])
-               {
-                       if (!getcwd(cwdbuf, sizeof(cwdbuf)))
-                       {
-                               fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
-                               exit(2);
-                       }
-               }
-
-               result = malloc(strlen(cwdbuf) + strlen(in) + 2);
-               sprintf(result, "%s/%s", cwdbuf, in);
-       }
-
-       canonicalize_path(result);
-       return result;
-}
-
 static void
 help(void)
 {
@@ -1864,6 +1955,7 @@ help(void)
        printf(_("Usage:\n  %s [OPTION]... [EXTRA-TEST]...\n"), progname);
        printf(_("\n"));
        printf(_("Options:\n"));
+       printf(_("  --config-auth=DATADIR     update authentication settings for DATADIR\n"));
        printf(_("  --create-role=ROLE        create the specified role before testing\n"));
        printf(_("  --dbname=DB               use database DB (default \"regression\")\n"));
        printf(_("  --debug                   turn on debug mode in programs that are run\n"));
@@ -1880,21 +1972,18 @@ help(void)
        printf(_("  --outputdir=DIR           place output files in DIR (default \".\")\n"));
        printf(_("  --schedule=FILE           use test ordering schedule from FILE\n"));
        printf(_("                            (can be used multiple times to concatenate)\n"));
-       printf(_("  --temp-install=DIR        create a temporary installation in DIR\n"));
+       printf(_("  --temp-instance=DIR       create a temporary instance in DIR\n"));
        printf(_("  --use-existing            use an existing installation\n"));
        printf(_("\n"));
-       printf(_("Options for \"temp-install\" mode:\n"));
-       printf(_("  --extra-install=DIR       additional directory to install (e.g., contrib)\n"));
+       printf(_("Options for \"temp-instance\" mode:\n"));
        printf(_("  --no-locale               use C locale\n"));
        printf(_("  --port=PORT               start postmaster on PORT\n"));
        printf(_("  --temp-config=FILE        append contents of FILE to temporary config\n"));
-       printf(_("  --top-builddir=DIR        (relative) path to top level build directory\n"));
        printf(_("\n"));
        printf(_("Options for using an existing installation:\n"));
        printf(_("  --host=HOST               use postmaster running on HOST\n"));
        printf(_("  --port=PORT               use postmaster running at PORT\n"));
        printf(_("  --user=USER               connect as USER\n"));
-       printf(_("  --psqldir=DIR             use psql in DIR (default: configured bindir)\n"));
        printf(_("\n"));
        printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
        printf(_("if the tests could not be run for some reason.\n"));
@@ -1905,13 +1994,6 @@ help(void)
 int
 regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc)
 {
-       _stringlist *sl;
-       int                     c;
-       int                     i;
-       int                     option_index;
-       char            buf[MAXPGPATH * 4];
-       char            buf2[MAXPGPATH * 4];
-
        static struct option long_options[] = {
                {"help", no_argument, NULL, 'h'},
                {"version", no_argument, NULL, 'V'},
@@ -1923,23 +2005,29 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                {"encoding", required_argument, NULL, 6},
                {"outputdir", required_argument, NULL, 7},
                {"schedule", required_argument, NULL, 8},
-               {"temp-install", required_argument, NULL, 9},
+               {"temp-instance", required_argument, NULL, 9},
                {"no-locale", no_argument, NULL, 10},
-               {"top-builddir", required_argument, NULL, 11},
                {"host", required_argument, NULL, 13},
                {"port", required_argument, NULL, 14},
                {"user", required_argument, NULL, 15},
-               {"psqldir", required_argument, NULL, 16},
+               {"bindir", required_argument, NULL, 16},
                {"dlpath", required_argument, NULL, 17},
                {"create-role", required_argument, NULL, 18},
                {"temp-config", required_argument, NULL, 19},
                {"use-existing", no_argument, NULL, 20},
                {"launcher", required_argument, NULL, 21},
                {"load-extension", required_argument, NULL, 22},
-               {"extra-install", required_argument, NULL, 23},
+               {"config-auth", required_argument, NULL, 24},
                {NULL, 0, NULL, 0}
        };
 
+       _stringlist *sl;
+       int                     c;
+       int                     i;
+       int                     option_index;
+       char            buf[MAXPGPATH * 4];
+       char            buf2[MAXPGPATH * 4];
+
        progname = get_progname(argv[0]);
        set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
 
@@ -1954,7 +2042,10 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
         * We call the initialization function here because that way we can set
         * default parameters and let them be overwritten by the commandline.
         */
-       ifunc();
+       ifunc(argc, argv);
+
+       if (getenv("PG_REGRESS_DIFF_OPTS"))
+               pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS");
 
        while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
        {
@@ -1997,14 +2088,11 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                                add_stringlist_item(&schedulelist, optarg);
                                break;
                        case 9:
-                               temp_install = make_absolute_path(optarg);
+                               temp_instance = make_absolute_path(optarg);
                                break;
                        case 10:
                                nolocale = true;
                                break;
-                       case 11:
-                               top_builddir = strdup(optarg);
-                               break;
                        case 13:
                                hostname = strdup(optarg);
                                break;
@@ -2016,9 +2104,11 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                                user = strdup(optarg);
                                break;
                        case 16:
-                               /* "--psqldir=" should mean to use PATH */
+                               /* "--bindir=" means to use PATH */
                                if (strlen(optarg))
-                                       psqldir = strdup(optarg);
+                                       bindir = strdup(optarg);
+                               else
+                                       bindir = NULL;
                                break;
                        case 17:
                                dlpath = strdup(optarg);
@@ -2038,8 +2128,8 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                        case 22:
                                add_stringlist_item(&loadextension, optarg);
                                break;
-                       case 23:
-                               add_stringlist_item(&extra_install, optarg);
+                       case 24:
+                               config_auth_datadir = pstrdup(optarg);
                                break;
                        default:
                                /* getopt_long already emitted a complaint */
@@ -2058,12 +2148,22 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                optind++;
        }
 
-       if (temp_install && !port_specified_by_user)
+       if (config_auth_datadir)
+       {
+#ifdef ENABLE_SSPI
+               config_sspi_auth(config_auth_datadir);
+#endif
+               exit(0);
+       }
+
+       if (temp_instance && !port_specified_by_user)
 
                /*
                 * To reduce chances of interference with parallel installations, use
                 * a port number starting in the private range (49152-65535)
-                * calculated from the version number.
+                * calculated from the version number.  This aids !HAVE_UNIX_SOCKETS
+                * systems; elsewhere, the use of a private socket directory already
+                * prevents interference.
                 */
                port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
 
@@ -2082,75 +2182,42 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
        unlimit_core_size();
 #endif
 
-       if (temp_install)
+       if (temp_instance)
        {
                FILE       *pg_conf;
-               _stringlist *sl;
 
                /*
-                * Prepare the temp installation
+                * Prepare the temp instance
                 */
-               if (!top_builddir)
-               {
-                       fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
-                       exit(2);
-               }
 
-               if (directory_exists(temp_install))
+               if (directory_exists(temp_instance))
                {
-                       header(_("removing existing temp installation"));
-                       rmtree(temp_install, true);
+                       header(_("removing existing temp instance"));
+                       if (!rmtree(temp_instance, true))
+                       {
+                               fprintf(stderr, _("\n%s: could not remove temp instance \"%s\"\n"),
+                                               progname, temp_instance);
+                               exit(2);
+                       }
                }
 
-               header(_("creating temporary installation"));
+               header(_("creating temporary instance"));
 
-               /* make the temp install top directory */
-               make_directory(temp_install);
+               /* make the temp instance top directory */
+               make_directory(temp_instance);
 
                /* and a directory for log files */
                snprintf(buf, sizeof(buf), "%s/log", outputdir);
                if (!directory_exists(buf))
                        make_directory(buf);
 
-               /* "make install" */
-#ifndef WIN32_ONLY_COMPILER
-               snprintf(buf, sizeof(buf),
-                                SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
-                                makeprog, top_builddir, temp_install, outputdir);
-#else
-               snprintf(buf, sizeof(buf),
-                                SYSTEMQUOTE "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
-                                top_builddir, temp_install, outputdir);
-#endif
-               if (system(buf))
-               {
-                       fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
-                       exit(2);
-               }
-
-               for (sl = extra_install; sl != NULL; sl = sl->next)
-               {
-#ifndef WIN32_ONLY_COMPILER
-                       snprintf(buf, sizeof(buf),
-                                        SYSTEMQUOTE "\"%s\" -C \"%s/%s\" DESTDIR=\"%s/install\" install >> \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
-                                  makeprog, top_builddir, sl->str, temp_install, outputdir);
-#else
-                       fprintf(stderr, _("\n%s: --extra-install option not supported on this platform\n"), progname);
-                       exit(2);
-#endif
-
-                       if (system(buf))
-                       {
-                               fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
-                               exit(2);
-                       }
-               }
-
                /* initdb */
                header(_("initializing database system"));
                snprintf(buf, sizeof(buf),
-                                SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
-                                bindir, temp_install, datadir,
+                                "\"%s%sinitdb\" -D \"%s/data\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1",
+                                bindir ? bindir : "",
+                                bindir ? "/" : "",
+                                temp_instance,
                                 debug ? " --debug" : "",
                                 nolocale ? " --no-locale" : "",
                                 outputdir);
@@ -2161,14 +2228,14 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                }
 
                /*
-                * Adjust the default postgresql.conf as needed for regression
-                * testing. The user can specify a file to be appended; in any case we
-                * set max_prepared_transactions to enable testing of prepared xacts.
-                * (Note: to reduce the probability of unexpected shmmax failures,
-                * don't set max_prepared_transactions any higher than actually needed
-                * by the prepared_xacts regression test.)
+                * Adjust the default postgresql.conf for regression testing. The user
+                * can specify a file to be appended; in any case we expand logging
+                * and set max_prepared_transactions to enable testing of prepared
+                * xacts.  (Note: to reduce the probability of unexpected shmmax
+                * failures, don't set max_prepared_transactions any higher than
+                * actually needed by the prepared_xacts regression test.)
                 */
-               snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install);
+               snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance);
                pg_conf = fopen(buf, "a");
                if (pg_conf == NULL)
                {
@@ -2176,6 +2243,10 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                        exit(2);
                }
                fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
+               fputs("log_autovacuum_min_duration = 0\n", pg_conf);
+               fputs("log_checkpoints = on\n", pg_conf);
+               fputs("log_lock_waits = on\n", pg_conf);
+               fputs("log_temp_files = 128kB\n", pg_conf);
                fputs("max_prepared_transactions = 2\n", pg_conf);
 
                if (temp_config != NULL)
@@ -2196,12 +2267,26 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 
                fclose(pg_conf);
 
+#ifdef ENABLE_SSPI
+
+               /*
+                * Since we successfully used the same buffer for the much-longer
+                * "initdb" command, this can't truncate.
+                */
+               snprintf(buf, sizeof(buf), "%s/data", temp_instance);
+               config_sspi_auth(buf);
+#elif !defined(HAVE_UNIX_SOCKETS)
+#error Platform has no means to secure the test installation.
+#endif
+
                /*
                 * Check if there is a postmaster running already.
                 */
                snprintf(buf2, sizeof(buf2),
-                                SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE,
-                                bindir, DEVNULL, DEVNULL);
+                                "\"%s%spsql\" -X postgres <%s 2>%s",
+                                bindir ? bindir : "",
+                                bindir ? "/" : "",
+                                DEVNULL, DEVNULL);
 
                for (i = 0; i < 16; i++)
                {
@@ -2232,10 +2317,13 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
                 */
                header(_("starting postmaster"));
                snprintf(buf, sizeof(buf),
-                                SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
-                                bindir, temp_install,
-                                debug ? " -d 5" : "",
-                                hostname ? hostname : "",
+                                "\"%s%spostgres\" -D \"%s/data\" -F%s "
+                                "-c \"listen_addresses=%s\" -k \"%s\" "
+                                "> \"%s/log/postmaster.log\" 2>&1",
+                                bindir ? bindir : "",
+                                bindir ? "/" : "",
+                                temp_instance, debug ? " -d 5" : "",
+                                hostname ? hostname : "", sockdir ? sockdir : "",
                                 outputdir);
                postmaster_pid = spawn_process(buf);
                if (postmaster_pid == INVALID_PID)
@@ -2350,12 +2438,25 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
        /*
         * Shut down temp installation's postmaster
         */
-       if (temp_install)
+       if (temp_instance)
        {
                header(_("shutting down postmaster"));
                stop_postmaster();
        }
 
+       /*
+        * If there were no errors, remove the temp instance immediately to
+        * conserve disk space.  (If there were errors, we leave the instance in
+        * place for possible manual investigation.)
+        */
+       if (temp_instance && fail_count == 0 && fail_ignore_count == 0)
+       {
+               header(_("removing temporary instance"));
+               if (!rmtree(temp_instance, true))
+                       fprintf(stderr, _("\n%s: could not remove temp instance \"%s\"\n"),
+                                       progname, temp_instance);
+       }
+
        fclose(logfile);
 
        /*