30
30
#endif
31
31
32
32
#include "getopt_long.h"
33
+ #include "libpq/pqcomm.h" /* needed for UNIXSOCK_PATH() */
34
+ #include "libpq/pqsignal.h"
33
35
#include "pg_config_paths.h"
34
36
35
37
/* for resultmap we need a list of pairs of strings */
@@ -106,6 +108,12 @@ static const char *progname;
106
108
static char * logfilename ;
107
109
static FILE * logfile ;
108
110
static char * difffilename ;
111
+ static const char * sockdir ;
112
+ #ifdef HAVE_UNIX_SOCKETS
113
+ static const char * temp_sockdir ;
114
+ static char sockself [MAXPGPATH ];
115
+ static char socklock [MAXPGPATH ];
116
+ #endif
109
117
110
118
static _resultmap * resultmap = NULL ;
111
119
@@ -302,6 +310,81 @@ stop_postmaster(void)
302
310
}
303
311
}
304
312
313
+ #ifdef HAVE_UNIX_SOCKETS
314
+ /*
315
+ * Remove the socket temporary directory. pg_regress never waits for a
316
+ * postmaster exit, so it is indeterminate whether the postmaster has yet to
317
+ * unlink the socket and lock file. Unlink them here so we can proceed to
318
+ * remove the directory. Ignore errors; leaking a temporary directory is
319
+ * unimportant. This can run from a signal handler. The code is not
320
+ * acceptable in a Windows signal handler (see initdb.c:trapsig()), but
321
+ * Windows is not a HAVE_UNIX_SOCKETS platform.
322
+ */
323
+ static void
324
+ remove_temp (void )
325
+ {
326
+ unlink (sockself );
327
+ unlink (socklock );
328
+ rmdir (temp_sockdir );
329
+ }
330
+
331
+ /*
332
+ * Signal handler that calls remove_temp() and reraises the signal.
333
+ */
334
+ static void
335
+ signal_remove_temp (int signum )
336
+ {
337
+ remove_temp ();
338
+
339
+ pqsignal (signum , SIG_DFL );
340
+ raise (signum );
341
+ }
342
+
343
+ /*
344
+ * Create a temporary directory suitable for the server's Unix-domain socket.
345
+ * The directory will have mode 0700 or stricter, so no other OS user can open
346
+ * our socket to exploit our use of trust authentication. Most systems
347
+ * constrain the length of socket paths well below _POSIX_PATH_MAX, so we
348
+ * place the directory under /tmp rather than relative to the possibly-deep
349
+ * current working directory.
350
+ *
351
+ * Compared to using the compiled-in DEFAULT_PGSOCKET_DIR, this also permits
352
+ * testing to work in builds that relocate it to a directory not writable to
353
+ * the build/test user.
354
+ */
355
+ static const char *
356
+ make_temp_sockdir (void )
357
+ {
358
+ char * template = strdup ("/tmp/pg_regress-XXXXXX" );
359
+
360
+ temp_sockdir = mkdtemp (template );
361
+ if (temp_sockdir == NULL )
362
+ {
363
+ fprintf (stderr , _ ("%s: could not create directory \"%s\": %s\n" ),
364
+ progname , template , strerror (errno ));
365
+ exit (2 );
366
+ }
367
+
368
+ /* Stage file names for remove_temp(). Unsafe in a signal handler. */
369
+ UNIXSOCK_PATH (sockself , port , temp_sockdir );
370
+ snprintf (socklock , sizeof (socklock ), "%s.lock" , sockself );
371
+
372
+ /* Remove the directory during clean exit. */
373
+ atexit (remove_temp );
374
+
375
+ /*
376
+ * Remove the directory before dying to the usual signals. Omit SIGQUIT,
377
+ * preserving it as a quick, untidy exit.
378
+ */
379
+ pqsignal (SIGHUP , signal_remove_temp );
380
+ pqsignal (SIGINT , signal_remove_temp );
381
+ pqsignal (SIGPIPE , signal_remove_temp );
382
+ pqsignal (SIGTERM , signal_remove_temp );
383
+
384
+ return temp_sockdir ;
385
+ }
386
+ #endif /* HAVE_UNIX_SOCKETS */
387
+
305
388
/*
306
389
* Always exit through here, not through plain exit(), to ensure we make
307
390
* an effort to shut down a temp postmaster
@@ -763,8 +846,7 @@ initialize_environment(void)
763
846
* the wrong postmaster, or otherwise behave in nondefault ways. (Note
764
847
* we also use psql's -X switch consistently, so that ~/.psqlrc files
765
848
* won't mess things up.) Also, set PGPORT to the temp port, and set
766
- * or unset PGHOST depending on whether we are using TCP or Unix
767
- * sockets.
849
+ * PGHOST depending on whether we are using TCP or Unix sockets.
768
850
*/
769
851
unsetenv ("PGDATABASE" );
770
852
unsetenv ("PGUSER" );
@@ -773,10 +855,19 @@ initialize_environment(void)
773
855
unsetenv ("PGREQUIRESSL" );
774
856
unsetenv ("PGCONNECT_TIMEOUT" );
775
857
unsetenv ("PGDATA" );
858
+ #ifdef HAVE_UNIX_SOCKETS
776
859
if (hostname != NULL )
777
860
doputenv ("PGHOST" , hostname );
778
861
else
779
- unsetenv ("PGHOST" );
862
+ {
863
+ sockdir = getenv ("PG_REGRESS_SOCK_DIR" );
864
+ if (!sockdir )
865
+ sockdir = make_temp_sockdir ();
866
+ doputenv ("PGHOST" , sockdir );
867
+ }
868
+ #else
869
+ doputenv ("PGHOST" , hostname );
870
+ #endif
780
871
unsetenv ("PGHOSTADDR" );
781
872
if (port != -1 )
782
873
{
@@ -2053,7 +2144,9 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
2053
2144
/*
2054
2145
* To reduce chances of interference with parallel installations, use
2055
2146
* a port number starting in the private range (49152-65535)
2056
- * calculated from the version number.
2147
+ * calculated from the version number. This aids !HAVE_UNIX_SOCKETS
2148
+ * systems; elsewhere, the use of a private socket directory already
2149
+ * prevents interference.
2057
2150
*/
2058
2151
port = 0xC000 | (PG_VERSION_NUM & 0x3FFF );
2059
2152
@@ -2203,10 +2296,11 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
2203
2296
*/
2204
2297
header (_ ("starting postmaster" ));
2205
2298
snprintf (buf , sizeof (buf ),
2206
- SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE ,
2207
- bindir , temp_install ,
2208
- debug ? " -d 5" : "" ,
2209
- hostname ? hostname : "" ,
2299
+ SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s "
2300
+ "-c \"listen_addresses=%s\" -k \"%s\" "
2301
+ "> \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE ,
2302
+ bindir , temp_install , debug ? " -d 5" : "" ,
2303
+ hostname ? hostname : "" , sockdir ? sockdir : "" ,
2210
2304
outputdir );
2211
2305
postmaster_pid = spawn_process (buf );
2212
2306
if (postmaster_pid == INVALID_PID )
0 commit comments