aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/test/regress/.gitignore2
-rw-r--r--src/test/regress/GNUmakefile9
-rw-r--r--src/test/regress/pg_regress.c110
3 files changed, 111 insertions, 10 deletions
diff --git a/src/test/regress/.gitignore b/src/test/regress/.gitignore
index 7573addc94d..86a85f7eb73 100644
--- a/src/test/regress/.gitignore
+++ b/src/test/regress/.gitignore
@@ -1,3 +1,5 @@
+/pqsignal.c
+
# Local binaries
/pg_regress
diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile
index 90aea6cc82a..a4e15d2a110 100644
--- a/src/test/regress/GNUmakefile
+++ b/src/test/regress/GNUmakefile
@@ -43,13 +43,18 @@ EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \
all: pg_regress$(X)
-pg_regress$(X): pg_regress.o pg_regress_main.o | submake-libpgport
+pg_regress$(X): pg_regress.o pg_regress_main.o pqsignal.o | submake-libpgport
$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@
# dependencies ensure that path changes propagate
pg_regress.o: pg_regress.c $(top_builddir)/src/port/pg_config_paths.h
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(top_builddir)/src/port $(EXTRADEFS) -c -o $@ $<
+# Pull in pqsignal like initdb does.
+pqsignal.c: % : $(top_srcdir)/src/interfaces/libpq/%
+ rm -f $@ && $(LN_S) $< .
+pqsignal.o: override CPPFLAGS += -I$(libpq_srcdir)
+
$(top_builddir)/src/port/pg_config_paths.h: $(top_builddir)/src/Makefile.global
$(MAKE) -C $(top_builddir)/src/port pg_config_paths.h
@@ -166,7 +171,7 @@ bigcheck: all tablespace-setup
clean distclean maintainer-clean: clean-lib
# things built by `all' target
rm -f $(OBJS) refint$(DLSUFFIX) autoinc$(DLSUFFIX) dummy_seclabel$(DLSUFFIX)
- rm -f pg_regress_main.o pg_regress.o pg_regress$(X)
+ rm -f pqsignal.c pg_regress_main.o pg_regress.o pqsignal.o pg_regress$(X)
# things created by various check targets
rm -f $(output_files) $(input_files)
rm -rf testtablespace
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index 19fc3f209dd..39bc4d20fa0 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -30,6 +30,8 @@
#endif
#include "getopt_long.h"
+#include "libpq/pqcomm.h" /* needed for UNIXSOCK_PATH() */
+#include "libpq/pqsignal.h"
#include "pg_config_paths.h"
/* for resultmap we need a list of pairs of strings */
@@ -109,6 +111,12 @@ 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;
@@ -307,6 +315,81 @@ 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)
+{
+ 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 */
+
/*
* Always exit through here, not through plain exit(), to ensure we make
* an effort to shut down a temp postmaster
@@ -768,8 +851,7 @@ initialize_environment(void)
* 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");
@@ -778,10 +860,19 @@ 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
+ doputenv("PGHOST", hostname);
+#endif
unsetenv("PGHOSTADDR");
if (port != -1)
{
@@ -2084,7 +2175,9 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
/*
* 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);
@@ -2253,10 +2346,11 @@ 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 : "",
+ SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s "
+ "-c \"listen_addresses=%s\" -k \"%s\" "
+ "> \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
+ bindir, temp_install, debug ? " -d 5" : "",
+ hostname ? hostname : "", sockdir ? sockdir : "",
outputdir);
postmaster_pid = spawn_process(buf);
if (postmaster_pid == INVALID_PID)