diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/test/regress/.gitignore | 2 | ||||
-rw-r--r-- | src/test/regress/GNUmakefile | 9 | ||||
-rw-r--r-- | src/test/regress/pg_regress.c | 110 |
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) |