3030#endif
3131
3232#include "getopt_long.h"
33+ #include "libpq/pqcomm.h" /* needed for UNIXSOCK_PATH() */
3334#include "pg_config_paths.h"
3435
3536/* for resultmap we need a list of pairs of strings */
@@ -109,6 +110,12 @@ static const char *progname;
109110static char * logfilename ;
110111static FILE * logfile ;
111112static char * difffilename ;
113+ static const char * sockdir ;
114+ #ifdef HAVE_UNIX_SOCKETS
115+ static const char * temp_sockdir ;
116+ static char sockself [MAXPGPATH ];
117+ static char socklock [MAXPGPATH ];
118+ #endif
112119
113120static _resultmap * resultmap = NULL ;
114121
@@ -307,6 +314,82 @@ stop_postmaster(void)
307314 }
308315}
309316
317+ #ifdef HAVE_UNIX_SOCKETS
318+ /*
319+ * Remove the socket temporary directory. pg_regress never waits for a
320+ * postmaster exit, so it is indeterminate whether the postmaster has yet to
321+ * unlink the socket and lock file. Unlink them here so we can proceed to
322+ * remove the directory. Ignore errors; leaking a temporary directory is
323+ * unimportant. This can run from a signal handler. The code is not
324+ * acceptable in a Windows signal handler (see initdb.c:trapsig()), but
325+ * Windows is not a HAVE_UNIX_SOCKETS platform.
326+ */
327+ static void
328+ remove_temp (void )
329+ {
330+ Assert (temp_sockdir );
331+ unlink (sockself );
332+ unlink (socklock );
333+ rmdir (temp_sockdir );
334+ }
335+
336+ /*
337+ * Signal handler that calls remove_temp() and reraises the signal.
338+ */
339+ static void
340+ signal_remove_temp (int signum )
341+ {
342+ remove_temp ();
343+
344+ pqsignal (signum , SIG_DFL );
345+ raise (signum );
346+ }
347+
348+ /*
349+ * Create a temporary directory suitable for the server's Unix-domain socket.
350+ * The directory will have mode 0700 or stricter, so no other OS user can open
351+ * our socket to exploit our use of trust authentication. Most systems
352+ * constrain the length of socket paths well below _POSIX_PATH_MAX, so we
353+ * place the directory under /tmp rather than relative to the possibly-deep
354+ * current working directory.
355+ *
356+ * Compared to using the compiled-in DEFAULT_PGSOCKET_DIR, this also permits
357+ * testing to work in builds that relocate it to a directory not writable to
358+ * the build/test user.
359+ */
360+ static const char *
361+ make_temp_sockdir (void )
362+ {
363+ char * template = strdup ("/tmp/pg_regress-XXXXXX" );
364+
365+ temp_sockdir = mkdtemp (template );
366+ if (temp_sockdir == NULL )
367+ {
368+ fprintf (stderr , _ ("%s: could not create directory \"%s\": %s\n" ),
369+ progname , template , strerror (errno ));
370+ exit (2 );
371+ }
372+
373+ /* Stage file names for remove_temp(). Unsafe in a signal handler. */
374+ UNIXSOCK_PATH (sockself , port , temp_sockdir );
375+ snprintf (socklock , sizeof (socklock ), "%s.lock" , sockself );
376+
377+ /* Remove the directory during clean exit. */
378+ atexit (remove_temp );
379+
380+ /*
381+ * Remove the directory before dying to the usual signals. Omit SIGQUIT,
382+ * preserving it as a quick, untidy exit.
383+ */
384+ pqsignal (SIGHUP , signal_remove_temp );
385+ pqsignal (SIGINT , signal_remove_temp );
386+ pqsignal (SIGPIPE , signal_remove_temp );
387+ pqsignal (SIGTERM , signal_remove_temp );
388+
389+ return temp_sockdir ;
390+ }
391+ #endif /* HAVE_UNIX_SOCKETS */
392+
310393/*
311394 * Check whether string matches pattern
312395 *
@@ -759,8 +842,7 @@ initialize_environment(void)
759842 * the wrong postmaster, or otherwise behave in nondefault ways. (Note
760843 * we also use psql's -X switch consistently, so that ~/.psqlrc files
761844 * won't mess things up.) Also, set PGPORT to the temp port, and set
762- * or unset PGHOST depending on whether we are using TCP or Unix
763- * sockets.
845+ * PGHOST depending on whether we are using TCP or Unix sockets.
764846 */
765847 unsetenv ("PGDATABASE" );
766848 unsetenv ("PGUSER" );
@@ -769,10 +851,20 @@ initialize_environment(void)
769851 unsetenv ("PGREQUIRESSL" );
770852 unsetenv ("PGCONNECT_TIMEOUT" );
771853 unsetenv ("PGDATA" );
854+ #ifdef HAVE_UNIX_SOCKETS
772855 if (hostname != NULL )
773856 doputenv ("PGHOST" , hostname );
774857 else
775- unsetenv ("PGHOST" );
858+ {
859+ sockdir = getenv ("PG_REGRESS_SOCK_DIR" );
860+ if (!sockdir )
861+ sockdir = make_temp_sockdir ();
862+ doputenv ("PGHOST" , sockdir );
863+ }
864+ #else
865+ Assert (hostname != NULL );
866+ doputenv ("PGHOST" , hostname );
867+ #endif
776868 unsetenv ("PGHOSTADDR" );
777869 if (port != -1 )
778870 {
@@ -2067,7 +2159,9 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
20672159 /*
20682160 * To reduce chances of interference with parallel installations, use
20692161 * a port number starting in the private range (49152-65535)
2070- * calculated from the version number.
2162+ * calculated from the version number. This aids !HAVE_UNIX_SOCKETS
2163+ * systems; elsewhere, the use of a private socket directory already
2164+ * prevents interference.
20712165 */
20722166 port = 0xC000 | (PG_VERSION_NUM & 0x3FFF );
20732167
@@ -2240,10 +2334,11 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
22402334 */
22412335 header (_ ("starting postmaster" ));
22422336 snprintf (buf , sizeof (buf ),
2243- "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" ,
2244- bindir , temp_install ,
2245- debug ? " -d 5" : "" ,
2246- hostname ? hostname : "" ,
2337+ "\"%s/postgres\" -D \"%s/data\" -F%s "
2338+ "-c \"listen_addresses=%s\" -k \"%s\" "
2339+ "> \"%s/log/postmaster.log\" 2>&1" ,
2340+ bindir , temp_install , debug ? " -d 5" : "" ,
2341+ hostname ? hostname : "" , sockdir ? sockdir : "" ,
22472342 outputdir );
22482343 postmaster_pid = spawn_process (buf );
22492344 if (postmaster_pid == INVALID_PID )
0 commit comments