3030#endif
3131
3232#include "getopt_long.h"
33+ #include "libpq/pqcomm.h" /* needed for UNIXSOCK_PATH() */
34+ #include "libpq/pqsignal.h"
3335#include "pg_config_paths.h"
3436
3537/* for resultmap we need a list of pairs of strings */
@@ -96,6 +98,12 @@ static const char *progname;
9698static char * logfilename ;
9799static FILE * logfile ;
98100static char * difffilename ;
101+ static const char * sockdir ;
102+ #ifdef HAVE_UNIX_SOCKETS
103+ static const char * temp_sockdir ;
104+ static char sockself [MAXPGPATH ];
105+ static char socklock [MAXPGPATH ];
106+ #endif
99107
100108static _resultmap * resultmap = NULL ;
101109
@@ -292,6 +300,81 @@ stop_postmaster(void)
292300 }
293301}
294302
303+ #ifdef HAVE_UNIX_SOCKETS
304+ /*
305+ * Remove the socket temporary directory. pg_regress never waits for a
306+ * postmaster exit, so it is indeterminate whether the postmaster has yet to
307+ * unlink the socket and lock file. Unlink them here so we can proceed to
308+ * remove the directory. Ignore errors; leaking a temporary directory is
309+ * unimportant. This can run from a signal handler. The code is not
310+ * acceptable in a Windows signal handler (see initdb.c:trapsig()), but
311+ * Windows is not a HAVE_UNIX_SOCKETS platform.
312+ */
313+ static void
314+ remove_temp (void )
315+ {
316+ unlink (sockself );
317+ unlink (socklock );
318+ rmdir (temp_sockdir );
319+ }
320+
321+ /*
322+ * Signal handler that calls remove_temp() and reraises the signal.
323+ */
324+ static void
325+ signal_remove_temp (int signum )
326+ {
327+ remove_temp ();
328+
329+ pqsignal (signum , SIG_DFL );
330+ raise (signum );
331+ }
332+
333+ /*
334+ * Create a temporary directory suitable for the server's Unix-domain socket.
335+ * The directory will have mode 0700 or stricter, so no other OS user can open
336+ * our socket to exploit our use of trust authentication. Most systems
337+ * constrain the length of socket paths well below _POSIX_PATH_MAX, so we
338+ * place the directory under /tmp rather than relative to the possibly-deep
339+ * current working directory.
340+ *
341+ * Compared to using the compiled-in DEFAULT_PGSOCKET_DIR, this also permits
342+ * testing to work in builds that relocate it to a directory not writable to
343+ * the build/test user.
344+ */
345+ static const char *
346+ make_temp_sockdir (void )
347+ {
348+ char * template = strdup ("/tmp/pg_regress-XXXXXX" );
349+
350+ temp_sockdir = mkdtemp (template );
351+ if (temp_sockdir == NULL )
352+ {
353+ fprintf (stderr , _ ("%s: could not create directory \"%s\": %s\n" ),
354+ progname , template , strerror (errno ));
355+ exit (2 );
356+ }
357+
358+ /* Stage file names for remove_temp(). Unsafe in a signal handler. */
359+ UNIXSOCK_PATH (sockself , port , temp_sockdir );
360+ snprintf (socklock , sizeof (socklock ), "%s.lock" , sockself );
361+
362+ /* Remove the directory during clean exit. */
363+ atexit (remove_temp );
364+
365+ /*
366+ * Remove the directory before dying to the usual signals. Omit SIGQUIT,
367+ * preserving it as a quick, untidy exit.
368+ */
369+ pqsignal (SIGHUP , signal_remove_temp );
370+ pqsignal (SIGINT , signal_remove_temp );
371+ pqsignal (SIGPIPE , signal_remove_temp );
372+ pqsignal (SIGTERM , signal_remove_temp );
373+
374+ return temp_sockdir ;
375+ }
376+ #endif /* HAVE_UNIX_SOCKETS */
377+
295378/*
296379 * Always exit through here, not through plain exit(), to ensure we make
297380 * an effort to shut down a temp postmaster
@@ -753,8 +836,7 @@ initialize_environment(void)
753836 * the wrong postmaster, or otherwise behave in nondefault ways. (Note
754837 * we also use psql's -X switch consistently, so that ~/.psqlrc files
755838 * won't mess things up.) Also, set PGPORT to the temp port, and set
756- * or unset PGHOST depending on whether we are using TCP or Unix
757- * sockets.
839+ * PGHOST depending on whether we are using TCP or Unix sockets.
758840 */
759841 unsetenv ("PGDATABASE" );
760842 unsetenv ("PGUSER" );
@@ -763,10 +845,19 @@ initialize_environment(void)
763845 unsetenv ("PGREQUIRESSL" );
764846 unsetenv ("PGCONNECT_TIMEOUT" );
765847 unsetenv ("PGDATA" );
848+ #ifdef HAVE_UNIX_SOCKETS
766849 if (hostname != NULL )
767850 doputenv ("PGHOST" , hostname );
768851 else
769- unsetenv ("PGHOST" );
852+ {
853+ sockdir = getenv ("PG_REGRESS_SOCK_DIR" );
854+ if (!sockdir )
855+ sockdir = make_temp_sockdir ();
856+ doputenv ("PGHOST" , sockdir );
857+ }
858+ #else
859+ doputenv ("PGHOST" , hostname );
860+ #endif
770861 unsetenv ("PGHOSTADDR" );
771862 if (port != -1 )
772863 {
@@ -2035,7 +2126,9 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
20352126 /*
20362127 * To reduce chances of interference with parallel installations, use
20372128 * a port number starting in the private range (49152-65535)
2038- * calculated from the version number.
2129+ * calculated from the version number. This aids !HAVE_UNIX_SOCKETS
2130+ * systems; elsewhere, the use of a private socket directory already
2131+ * prevents interference.
20392132 */
20402133 port = 0xC000 | (PG_VERSION_NUM & 0x3FFF );
20412134
@@ -2185,10 +2278,11 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
21852278 */
21862279 header (_ ("starting postmaster" ));
21872280 snprintf (buf , sizeof (buf ),
2188- SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE ,
2189- bindir , temp_install ,
2190- debug ? " -d 5" : "" ,
2191- hostname ? hostname : "" ,
2281+ SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s "
2282+ "-c \"listen_addresses=%s\" -k \"%s\" "
2283+ "> \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE ,
2284+ bindir , temp_install , debug ? " -d 5" : "" ,
2285+ hostname ? hostname : "" , sockdir ? sockdir : "" ,
21922286 outputdir );
21932287 postmaster_pid = spawn_process (buf );
21942288 if (postmaster_pid == INVALID_PID )
0 commit comments