LCOV - code coverage report
Current view: top level - src/test/regress - pg_regress.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 667 909 73.4 %
Date: 2023-12-11 15:11:28 Functions: 35 41 85.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_regress --- regression test driver
       4             :  *
       5             :  * This is a C implementation of the previous shell script for running
       6             :  * the regression tests, and should be mostly compatible with it.
       7             :  * Initial author of C translation: Magnus Hagander
       8             :  *
       9             :  * This code is released under the terms of the PostgreSQL License.
      10             :  *
      11             :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
      12             :  * Portions Copyright (c) 1994, Regents of the University of California
      13             :  *
      14             :  * src/test/regress/pg_regress.c
      15             :  *
      16             :  *-------------------------------------------------------------------------
      17             :  */
      18             : 
      19             : #include "postgres_fe.h"
      20             : 
      21             : #include <ctype.h>
      22             : #include <sys/resource.h>
      23             : #include <sys/stat.h>
      24             : #include <sys/time.h>
      25             : #include <sys/wait.h>
      26             : #include <signal.h>
      27             : #include <unistd.h>
      28             : 
      29             : #include "common/logging.h"
      30             : #include "common/restricted_token.h"
      31             : #include "common/string.h"
      32             : #include "common/username.h"
      33             : #include "getopt_long.h"
      34             : #include "lib/stringinfo.h"
      35             : #include "libpq-fe.h"
      36             : #include "libpq/pqcomm.h"     /* needed for UNIXSOCK_PATH() */
      37             : #include "pg_config_paths.h"
      38             : #include "pg_regress.h"
      39             : #include "portability/instr_time.h"
      40             : 
      41             : /* for resultmap we need a list of pairs of strings */
      42             : typedef struct _resultmap
      43             : {
      44             :     char       *test;
      45             :     char       *type;
      46             :     char       *resultfile;
      47             :     struct _resultmap *next;
      48             : } _resultmap;
      49             : 
      50             : /*
      51             :  * Values obtained from Makefile.
      52             :  */
      53             : char       *host_platform = HOST_TUPLE;
      54             : 
      55             : #ifndef WIN32                   /* not used in WIN32 case */
      56             : static char *shellprog = SHELLPROG;
      57             : #endif
      58             : 
      59             : /*
      60             :  * On Windows we use -w in diff switches to avoid problems with inconsistent
      61             :  * newline representation.  The actual result files will generally have
      62             :  * Windows-style newlines, but the comparison files might or might not.
      63             :  */
      64             : #ifndef WIN32
      65             : const char *basic_diff_opts = "";
      66             : const char *pretty_diff_opts = "-U3";
      67             : #else
      68             : const char *basic_diff_opts = "-w";
      69             : const char *pretty_diff_opts = "-w -U3";
      70             : #endif
      71             : 
      72             : /*
      73             :  * The width of the testname field when printing to ensure vertical alignment
      74             :  * of test runtimes. This number is somewhat arbitrarily chosen to match the
      75             :  * older pre-TAP output format.
      76             :  */
      77             : #define TESTNAME_WIDTH 36
      78             : 
      79             : /*
      80             :  * The number times per second that pg_regress checks to see if the test
      81             :  * instance server has started and is available for connection.
      82             :  */
      83             : #define WAIT_TICKS_PER_SECOND 20
      84             : 
      85             : typedef enum TAPtype
      86             : {
      87             :     DIAG = 0,
      88             :     BAIL,
      89             :     NOTE,
      90             :     NOTE_DETAIL,
      91             :     NOTE_END,
      92             :     TEST_STATUS,
      93             :     PLAN,
      94             :     NONE,
      95             : } TAPtype;
      96             : 
      97             : /* options settable from command line */
      98             : _stringlist *dblist = NULL;
      99             : bool        debug = false;
     100             : char       *inputdir = ".";
     101             : char       *outputdir = ".";
     102             : char       *expecteddir = ".";
     103             : char       *bindir = PGBINDIR;
     104             : char       *launcher = NULL;
     105             : static _stringlist *loadextension = NULL;
     106             : static int  max_connections = 0;
     107             : static int  max_concurrent_tests = 0;
     108             : static char *encoding = NULL;
     109             : static _stringlist *schedulelist = NULL;
     110             : static _stringlist *extra_tests = NULL;
     111             : static char *temp_instance = NULL;
     112             : static _stringlist *temp_configs = NULL;
     113             : static bool nolocale = false;
     114             : static bool use_existing = false;
     115             : static char *hostname = NULL;
     116             : static int  port = -1;
     117             : static char portstr[16];
     118             : static bool port_specified_by_user = false;
     119             : static char *dlpath = PKGLIBDIR;
     120             : static char *user = NULL;
     121             : static _stringlist *extraroles = NULL;
     122             : static char *config_auth_datadir = NULL;
     123             : 
     124             : /* internal variables */
     125             : static const char *progname;
     126             : static char *logfilename;
     127             : static FILE *logfile;
     128             : static char *difffilename;
     129             : static const char *sockdir;
     130             : static const char *temp_sockdir;
     131             : static char sockself[MAXPGPATH];
     132             : static char socklock[MAXPGPATH];
     133             : static StringInfo failed_tests = NULL;
     134             : static bool in_note = false;
     135             : 
     136             : static _resultmap *resultmap = NULL;
     137             : 
     138             : static PID_TYPE postmaster_pid = INVALID_PID;
     139             : static bool postmaster_running = false;
     140             : 
     141             : static int  success_count = 0;
     142             : static int  fail_count = 0;
     143             : 
     144             : static bool directory_exists(const char *dir);
     145             : static void make_directory(const char *dir);
     146             : 
     147             : static void test_status_print(bool ok, const char *testname, double runtime, bool parallel);
     148             : static void test_status_ok(const char *testname, double runtime, bool parallel);
     149             : static void test_status_failed(const char *testname, double runtime, bool parallel);
     150             : static void bail_out(bool noatexit, const char *fmt,...) pg_attribute_printf(2, 3);
     151             : static void emit_tap_output(TAPtype type, const char *fmt,...) pg_attribute_printf(2, 3);
     152             : static void emit_tap_output_v(TAPtype type, const char *fmt, va_list argp) pg_attribute_printf(2, 0);
     153             : 
     154             : static StringInfo psql_start_command(void);
     155             : static void psql_add_command(StringInfo buf, const char *query,...) pg_attribute_printf(2, 3);
     156             : static void psql_end_command(StringInfo buf, const char *database);
     157             : 
     158             : /*
     159             :  * Convenience macros for printing TAP output with a more shorthand syntax
     160             :  * aimed at making the code more readable.
     161             :  */
     162             : #define plan(x)             emit_tap_output(PLAN, "1..%i", (x))
     163             : #define note(...)           emit_tap_output(NOTE, __VA_ARGS__)
     164             : #define note_detail(...)    emit_tap_output(NOTE_DETAIL, __VA_ARGS__)
     165             : #define diag(...)           emit_tap_output(DIAG, __VA_ARGS__)
     166             : #define note_end()          emit_tap_output(NOTE_END, "\n");
     167             : #define bail_noatexit(...)  bail_out(true, __VA_ARGS__)
     168             : #define bail(...)           bail_out(false, __VA_ARGS__)
     169             : 
     170             : /*
     171             :  * allow core files if possible.
     172             :  */
     173             : #if defined(HAVE_GETRLIMIT)
     174             : static void
     175         166 : unlimit_core_size(void)
     176             : {
     177             :     struct rlimit lim;
     178             : 
     179         166 :     getrlimit(RLIMIT_CORE, &lim);
     180         166 :     if (lim.rlim_max == 0)
     181             :     {
     182           0 :         diag("could not set core size: disallowed by hard limit");
     183           0 :         return;
     184             :     }
     185         166 :     else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
     186             :     {
     187         166 :         lim.rlim_cur = lim.rlim_max;
     188         166 :         setrlimit(RLIMIT_CORE, &lim);
     189             :     }
     190             : }
     191             : #endif
     192             : 
     193             : 
     194             : /*
     195             :  * Add an item at the end of a stringlist.
     196             :  */
     197             : void
     198        7984 : add_stringlist_item(_stringlist **listhead, const char *str)
     199             : {
     200        7984 :     _stringlist *newentry = pg_malloc(sizeof(_stringlist));
     201             :     _stringlist *oldentry;
     202             : 
     203        7984 :     newentry->str = pg_strdup(str);
     204        7984 :     newentry->next = NULL;
     205        7984 :     if (*listhead == NULL)
     206        6008 :         *listhead = newentry;
     207             :     else
     208             :     {
     209        6494 :         for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
     210             :              /* skip */ ;
     211        1976 :         oldentry->next = newentry;
     212             :     }
     213        7984 : }
     214             : 
     215             : /*
     216             :  * Free a stringlist.
     217             :  */
     218             : static void
     219        6956 : free_stringlist(_stringlist **listhead)
     220             : {
     221        6956 :     if (listhead == NULL || *listhead == NULL)
     222        1526 :         return;
     223        5430 :     if ((*listhead)->next != NULL)
     224        1488 :         free_stringlist(&((*listhead)->next));
     225        5430 :     free((*listhead)->str);
     226        5430 :     free(*listhead);
     227        5430 :     *listhead = NULL;
     228             : }
     229             : 
     230             : /*
     231             :  * Split a delimited string into a stringlist
     232             :  */
     233             : static void
     234         202 : split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
     235             : {
     236         202 :     char       *sc = pg_strdup(s);
     237         202 :     char       *token = strtok(sc, delim);
     238             : 
     239         418 :     while (token)
     240             :     {
     241         216 :         add_stringlist_item(listhead, token);
     242         216 :         token = strtok(NULL, delim);
     243             :     }
     244         202 :     free(sc);
     245         202 : }
     246             : 
     247             : /*
     248             :  * Bailing out is for unrecoverable errors which prevents further testing to
     249             :  * occur and after which the test run should be aborted. By passing noatexit
     250             :  * as true the process will terminate with _exit(2) and skipping registered
     251             :  * exit handlers, thus avoid any risk of bottomless recursion calls to exit.
     252             :  */
     253             : static void
     254           0 : bail_out(bool noatexit, const char *fmt,...)
     255             : {
     256             :     va_list     ap;
     257             : 
     258           0 :     va_start(ap, fmt);
     259           0 :     emit_tap_output_v(BAIL, fmt, ap);
     260           0 :     va_end(ap);
     261             : 
     262           0 :     if (noatexit)
     263           0 :         _exit(2);
     264             : 
     265           0 :     exit(2);
     266             : }
     267             : 
     268             : /*
     269             :  * Print the result of a test run and associated metadata like runtime. Care
     270             :  * is taken to align testnames and runtimes vertically to ensure the output
     271             :  * is human readable while still TAP compliant. Tests run in parallel are
     272             :  * prefixed with a '+' and sequential tests with a '-'. This distinction was
     273             :  * previously indicated by 'test' prefixing sequential tests while parallel
     274             :  * tests were indented by four leading spaces. The meson TAP parser consumes
     275             :  * leading space however, so a non-whitespace prefix of the same length is
     276             :  * required for both.
     277             :  */
     278             : static void
     279        2366 : test_status_print(bool ok, const char *testname, double runtime, bool parallel)
     280             : {
     281        2366 :     int         testnumber = fail_count + success_count;
     282             : 
     283             :     /*
     284             :      * Testnumbers are padded to 5 characters to ensure that testnames align
     285             :      * vertically (assuming at most 9999 tests).  Testnames are prefixed with
     286             :      * a leading character to indicate being run in parallel or not. A leading
     287             :      * '+' indicates a parallel test, '-' indicates a single test.
     288             :      */
     289        2366 :     emit_tap_output(TEST_STATUS, "%sok %-5i%*s %c %-*s %8.0f ms",
     290             :                     (ok ? "" : "not "),
     291             :                     testnumber,
     292             :     /* If ok, indent with four spaces matching "not " */
     293             :                     (ok ? (int) strlen("not ") : 0), "",
     294             :     /* Prefix a parallel test '+' and a single test with '-' */
     295             :                     (parallel ? '+' : '-'),
     296             :     /* Testnames are padded to align runtimes */
     297             :                     TESTNAME_WIDTH, testname,
     298             :                     runtime);
     299        2366 : }
     300             : 
     301             : static void
     302        2366 : test_status_ok(const char *testname, double runtime, bool parallel)
     303             : {
     304        2366 :     success_count++;
     305             : 
     306        2366 :     test_status_print(true, testname, runtime, parallel);
     307        2366 : }
     308             : 
     309             : static void
     310           0 : test_status_failed(const char *testname, double runtime, bool parallel)
     311             : {
     312             :     /*
     313             :      * Save failed tests in a buffer such that we can print a summary at the
     314             :      * end with diag() to ensure it's shown even under test harnesses.
     315             :      */
     316           0 :     if (!failed_tests)
     317           0 :         failed_tests = makeStringInfo();
     318             :     else
     319           0 :         appendStringInfoChar(failed_tests, ',');
     320             : 
     321           0 :     appendStringInfo(failed_tests, " %s", testname);
     322             : 
     323           0 :     fail_count++;
     324             : 
     325           0 :     test_status_print(false, testname, runtime, parallel);
     326           0 : }
     327             : 
     328             : 
     329             : static void
     330        4490 : emit_tap_output(TAPtype type, const char *fmt,...)
     331             : {
     332             :     va_list     argp;
     333             : 
     334        4490 :     va_start(argp, fmt);
     335        4490 :     emit_tap_output_v(type, fmt, argp);
     336        4490 :     va_end(argp);
     337        4490 : }
     338             : 
     339             : static void
     340        4490 : emit_tap_output_v(TAPtype type, const char *fmt, va_list argp)
     341             : {
     342             :     va_list     argp_logfile;
     343             :     FILE       *fp;
     344             : 
     345             :     /*
     346             :      * Diagnostic output will be hidden by prove unless printed to stderr. The
     347             :      * Bail message is also printed to stderr to aid debugging under a harness
     348             :      * which might otherwise not emit such an important message.
     349             :      */
     350        4490 :     if (type == DIAG || type == BAIL)
     351           0 :         fp = stderr;
     352             :     else
     353        4490 :         fp = stdout;
     354             : 
     355             :     /*
     356             :      * If we are ending a note_detail line we can avoid further processing and
     357             :      * immediately return following a newline.
     358             :      */
     359        4490 :     if (type == NOTE_END)
     360             :     {
     361         108 :         in_note = false;
     362         108 :         fprintf(fp, "\n");
     363         108 :         if (logfile)
     364         108 :             fprintf(logfile, "\n");
     365         108 :         return;
     366             :     }
     367             : 
     368             :     /* Make a copy of the va args for printing to the logfile */
     369        4382 :     va_copy(argp_logfile, argp);
     370             : 
     371             :     /*
     372             :      * Non-protocol output such as diagnostics or notes must be prefixed by a
     373             :      * '#' character. We print the Bail message like this too.
     374             :      */
     375        4382 :     if ((type == NOTE || type == DIAG || type == BAIL)
     376        3888 :         || (type == NOTE_DETAIL && !in_note))
     377             :     {
     378         602 :         fprintf(fp, "# ");
     379         602 :         if (logfile)
     380         602 :             fprintf(logfile, "# ");
     381             :     }
     382        4382 :     vfprintf(fp, fmt, argp);
     383        4382 :     if (logfile)
     384        4382 :         vfprintf(logfile, fmt, argp_logfile);
     385             : 
     386             :     /*
     387             :      * If we are entering into a note with more details to follow, register
     388             :      * that the leading '#' has been printed such that subsequent details
     389             :      * aren't prefixed as well.
     390             :      */
     391        4382 :     if (type == NOTE_DETAIL)
     392        1356 :         in_note = true;
     393             : 
     394             :     /*
     395             :      * If this was a Bail message, the bail protocol message must go to stdout
     396             :      * separately.
     397             :      */
     398        4382 :     if (type == BAIL)
     399             :     {
     400           0 :         fprintf(stdout, "Bail out!");
     401           0 :         if (logfile)
     402           0 :             fprintf(logfile, "Bail out!");
     403             :     }
     404             : 
     405        4382 :     va_end(argp_logfile);
     406             : 
     407        4382 :     if (type != NOTE_DETAIL)
     408             :     {
     409        3026 :         fprintf(fp, "\n");
     410        3026 :         if (logfile)
     411        3026 :             fprintf(logfile, "\n");
     412             :     }
     413        4382 :     fflush(NULL);
     414             : }
     415             : 
     416             : /*
     417             :  * shut down temp postmaster
     418             :  */
     419             : static void
     420         790 : stop_postmaster(void)
     421             : {
     422         790 :     if (postmaster_running)
     423             :     {
     424             :         /* We use pg_ctl to issue the kill and wait for stop */
     425             :         char        buf[MAXPGPATH * 2];
     426             :         int         r;
     427             : 
     428         324 :         snprintf(buf, sizeof(buf),
     429             :                  "\"%s%spg_ctl\" stop -D \"%s/data\" -s",
     430         162 :                  bindir ? bindir : "",
     431         162 :                  bindir ? "/" : "",
     432             :                  temp_instance);
     433         162 :         fflush(NULL);
     434         162 :         r = system(buf);
     435         162 :         if (r != 0)
     436             :         {
     437             :             /* Not using the normal bail() as we want _exit */
     438           0 :             bail_noatexit(_("could not stop postmaster: exit code was %d"), r);
     439             :         }
     440             : 
     441         162 :         postmaster_running = false;
     442             :     }
     443         790 : }
     444             : 
     445             : /*
     446             :  * Remove the socket temporary directory.  pg_regress never waits for a
     447             :  * postmaster exit, so it is indeterminate whether the postmaster has yet to
     448             :  * unlink the socket and lock file.  Unlink them here so we can proceed to
     449             :  * remove the directory.  Ignore errors; leaking a temporary directory is
     450             :  * unimportant.  This can run from a signal handler.  The code is not
     451             :  * acceptable in a Windows signal handler (see initdb.c:trapsig()), but
     452             :  * on Windows, pg_regress does not use Unix sockets by default.
     453             :  */
     454             : static void
     455         160 : remove_temp(void)
     456             : {
     457             :     Assert(temp_sockdir);
     458         160 :     unlink(sockself);
     459         160 :     unlink(socklock);
     460         160 :     rmdir(temp_sockdir);
     461         160 : }
     462             : 
     463             : /*
     464             :  * Signal handler that calls remove_temp() and reraises the signal.
     465             :  */
     466             : static void
     467           0 : signal_remove_temp(SIGNAL_ARGS)
     468             : {
     469           0 :     remove_temp();
     470             : 
     471           0 :     pqsignal(postgres_signal_arg, SIG_DFL);
     472           0 :     raise(postgres_signal_arg);
     473           0 : }
     474             : 
     475             : /*
     476             :  * Create a temporary directory suitable for the server's Unix-domain socket.
     477             :  * The directory will have mode 0700 or stricter, so no other OS user can open
     478             :  * our socket to exploit our use of trust authentication.  Most systems
     479             :  * constrain the length of socket paths well below _POSIX_PATH_MAX, so we
     480             :  * place the directory under /tmp rather than relative to the possibly-deep
     481             :  * current working directory.
     482             :  *
     483             :  * Compared to using the compiled-in DEFAULT_PGSOCKET_DIR, this also permits
     484             :  * testing to work in builds that relocate it to a directory not writable to
     485             :  * the build/test user.
     486             :  */
     487             : static const char *
     488         160 : make_temp_sockdir(void)
     489             : {
     490         160 :     char       *template = psprintf("%s/pg_regress-XXXXXX",
     491         160 :                                     getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
     492             : 
     493         160 :     temp_sockdir = mkdtemp(template);
     494         160 :     if (temp_sockdir == NULL)
     495             :     {
     496           0 :         bail("could not create directory \"%s\": %s",
     497             :              template, strerror(errno));
     498             :     }
     499             : 
     500             :     /* Stage file names for remove_temp().  Unsafe in a signal handler. */
     501         160 :     UNIXSOCK_PATH(sockself, port, temp_sockdir);
     502         160 :     snprintf(socklock, sizeof(socklock), "%s.lock", sockself);
     503             : 
     504             :     /* Remove the directory during clean exit. */
     505         160 :     atexit(remove_temp);
     506             : 
     507             :     /*
     508             :      * Remove the directory before dying to the usual signals.  Omit SIGQUIT,
     509             :      * preserving it as a quick, untidy exit.
     510             :      */
     511         160 :     pqsignal(SIGHUP, signal_remove_temp);
     512         160 :     pqsignal(SIGINT, signal_remove_temp);
     513         160 :     pqsignal(SIGPIPE, signal_remove_temp);
     514         160 :     pqsignal(SIGTERM, signal_remove_temp);
     515             : 
     516         160 :     return temp_sockdir;
     517             : }
     518             : 
     519             : /*
     520             :  * Check whether string matches pattern
     521             :  *
     522             :  * In the original shell script, this function was implemented using expr(1),
     523             :  * which provides basic regular expressions restricted to match starting at
     524             :  * the string start (in conventional regex terms, there's an implicit "^"
     525             :  * at the start of the pattern --- but no implicit "$" at the end).
     526             :  *
     527             :  * For now, we only support "." and ".*" as non-literal metacharacters,
     528             :  * because that's all that anyone has found use for in resultmap.  This
     529             :  * code could be extended if more functionality is needed.
     530             :  */
     531             : static bool
     532          84 : string_matches_pattern(const char *str, const char *pattern)
     533             : {
     534         156 :     while (*str && *pattern)
     535             :     {
     536         156 :         if (*pattern == '.' && pattern[1] == '*')
     537             :         {
     538          48 :             pattern += 2;
     539             :             /* Trailing .* matches everything. */
     540          48 :             if (*pattern == '\0')
     541           0 :                 return true;
     542             : 
     543             :             /*
     544             :              * Otherwise, scan for a text position at which we can match the
     545             :              * rest of the pattern.
     546             :              */
     547         564 :             while (*str)
     548             :             {
     549             :                 /*
     550             :                  * Optimization to prevent most recursion: don't recurse
     551             :                  * unless first pattern char might match this text char.
     552             :                  */
     553         516 :                 if (*str == *pattern || *pattern == '.')
     554             :                 {
     555          72 :                     if (string_matches_pattern(str, pattern))
     556           0 :                         return true;
     557             :                 }
     558             : 
     559         516 :                 str++;
     560             :             }
     561             : 
     562             :             /*
     563             :              * End of text with no match.
     564             :              */
     565          48 :             return false;
     566             :         }
     567         108 :         else if (*pattern != '.' && *str != *pattern)
     568             :         {
     569             :             /*
     570             :              * Not the single-character wildcard and no explicit match? Then
     571             :              * time to quit...
     572             :              */
     573          36 :             return false;
     574             :         }
     575             : 
     576          72 :         str++;
     577          72 :         pattern++;
     578             :     }
     579             : 
     580           0 :     if (*pattern == '\0')
     581           0 :         return true;            /* end of pattern, so declare match */
     582             : 
     583             :     /* End of input string.  Do we have matching pattern remaining? */
     584           0 :     while (*pattern == '.' && pattern[1] == '*')
     585           0 :         pattern += 2;
     586           0 :     if (*pattern == '\0')
     587           0 :         return true;            /* end of pattern, so declare match */
     588             : 
     589           0 :     return false;
     590             : }
     591             : 
     592             : /*
     593             :  * Scan resultmap file to find which platform-specific expected files to use.
     594             :  *
     595             :  * The format of each line of the file is
     596             :  *         testname/hostplatformpattern=substitutefile
     597             :  * where the hostplatformpattern is evaluated per the rules of expr(1),
     598             :  * namely, it is a standard regular expression with an implicit ^ at the start.
     599             :  * (We currently support only a very limited subset of regular expressions,
     600             :  * see string_matches_pattern() above.)  What hostplatformpattern will be
     601             :  * matched against is the config.guess output.  (In the shell-script version,
     602             :  * we also provided an indication of whether gcc or another compiler was in
     603             :  * use, but that facility isn't used anymore.)
     604             :  */
     605             : static void
     606         166 : load_resultmap(void)
     607             : {
     608             :     char        buf[MAXPGPATH];
     609             :     FILE       *f;
     610             : 
     611             :     /* scan the file ... */
     612         166 :     snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
     613         166 :     f = fopen(buf, "r");
     614         166 :     if (!f)
     615             :     {
     616             :         /* OK if it doesn't exist, else complain */
     617         160 :         if (errno == ENOENT)
     618         160 :             return;
     619           0 :         bail("could not open file \"%s\" for reading: %s",
     620             :              buf, strerror(errno));
     621             :     }
     622             : 
     623          18 :     while (fgets(buf, sizeof(buf), f))
     624             :     {
     625             :         char       *platform;
     626             :         char       *file_type;
     627             :         char       *expected;
     628             :         int         i;
     629             : 
     630             :         /* strip trailing whitespace, especially the newline */
     631          12 :         i = strlen(buf);
     632          24 :         while (i > 0 && isspace((unsigned char) buf[i - 1]))
     633          12 :             buf[--i] = '\0';
     634             : 
     635             :         /* parse out the line fields */
     636          12 :         file_type = strchr(buf, ':');
     637          12 :         if (!file_type)
     638             :         {
     639           0 :             bail("incorrectly formatted resultmap entry: %s", buf);
     640             :         }
     641          12 :         *file_type++ = '\0';
     642             : 
     643          12 :         platform = strchr(file_type, ':');
     644          12 :         if (!platform)
     645             :         {
     646           0 :             bail("incorrectly formatted resultmap entry: %s", buf);
     647             :         }
     648          12 :         *platform++ = '\0';
     649          12 :         expected = strchr(platform, '=');
     650          12 :         if (!expected)
     651             :         {
     652           0 :             bail("incorrectly formatted resultmap entry: %s", buf);
     653             :         }
     654          12 :         *expected++ = '\0';
     655             : 
     656             :         /*
     657             :          * if it's for current platform, save it in resultmap list. Note: by
     658             :          * adding at the front of the list, we ensure that in ambiguous cases,
     659             :          * the last match in the resultmap file is used. This mimics the
     660             :          * behavior of the old shell script.
     661             :          */
     662          12 :         if (string_matches_pattern(host_platform, platform))
     663             :         {
     664           0 :             _resultmap *entry = pg_malloc(sizeof(_resultmap));
     665             : 
     666           0 :             entry->test = pg_strdup(buf);
     667           0 :             entry->type = pg_strdup(file_type);
     668           0 :             entry->resultfile = pg_strdup(expected);
     669           0 :             entry->next = resultmap;
     670           0 :             resultmap = entry;
     671             :         }
     672             :     }
     673           6 :     fclose(f);
     674             : }
     675             : 
     676             : /*
     677             :  * Check in resultmap if we should be looking at a different file
     678             :  */
     679             : static
     680             : const char *
     681        2874 : get_expectfile(const char *testname, const char *file)
     682             : {
     683             :     char       *file_type;
     684             :     _resultmap *rm;
     685             : 
     686             :     /*
     687             :      * Determine the file type from the file name. This is just what is
     688             :      * following the last dot in the file name.
     689             :      */
     690        2874 :     if (!file || !(file_type = strrchr(file, '.')))
     691           0 :         return NULL;
     692             : 
     693        2874 :     file_type++;
     694             : 
     695        2874 :     for (rm = resultmap; rm != NULL; rm = rm->next)
     696             :     {
     697           0 :         if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
     698             :         {
     699           0 :             return rm->resultfile;
     700             :         }
     701             :     }
     702             : 
     703        2874 :     return NULL;
     704             : }
     705             : 
     706             : /*
     707             :  * Prepare environment variables for running regression tests
     708             :  */
     709             : static void
     710         166 : initialize_environment(void)
     711             : {
     712             :     /*
     713             :      * Set default application_name.  (The test_start_function may choose to
     714             :      * override this, but if it doesn't, we have something useful in place.)
     715             :      */
     716         166 :     setenv("PGAPPNAME", "pg_regress", 1);
     717             : 
     718             :     /*
     719             :      * Set variables that the test scripts may need to refer to.
     720             :      */
     721         166 :     setenv("PG_ABS_SRCDIR", inputdir, 1);
     722         166 :     setenv("PG_ABS_BUILDDIR", outputdir, 1);
     723         166 :     setenv("PG_LIBDIR", dlpath, 1);
     724         166 :     setenv("PG_DLSUFFIX", DLSUFFIX, 1);
     725             : 
     726         166 :     if (nolocale)
     727             :     {
     728             :         /*
     729             :          * Clear out any non-C locale settings
     730             :          */
     731           4 :         unsetenv("LC_COLLATE");
     732           4 :         unsetenv("LC_CTYPE");
     733           4 :         unsetenv("LC_MONETARY");
     734           4 :         unsetenv("LC_NUMERIC");
     735           4 :         unsetenv("LC_TIME");
     736           4 :         unsetenv("LANG");
     737             : 
     738             :         /*
     739             :          * Most platforms have adopted the POSIX locale as their
     740             :          * implementation-defined default locale.  Exceptions include native
     741             :          * Windows, macOS with --enable-nls, and Cygwin with --enable-nls.
     742             :          * (Use of --enable-nls matters because libintl replaces setlocale().)
     743             :          * Also, PostgreSQL does not support macOS with locale environment
     744             :          * variables unset; see PostmasterMain().
     745             :          */
     746             : #if defined(WIN32) || defined(__CYGWIN__) || defined(__darwin__)
     747             :         setenv("LANG", "C", 1);
     748             : #endif
     749             :     }
     750             : 
     751             :     /*
     752             :      * Set translation-related settings to English; otherwise psql will
     753             :      * produce translated messages and produce diffs.  (XXX If we ever support
     754             :      * translation of pg_regress, this needs to be moved elsewhere, where psql
     755             :      * is actually called.)
     756             :      */
     757         166 :     unsetenv("LANGUAGE");
     758         166 :     unsetenv("LC_ALL");
     759         166 :     setenv("LC_MESSAGES", "C", 1);
     760             : 
     761             :     /*
     762             :      * Set encoding as requested
     763             :      */
     764         166 :     if (encoding)
     765           2 :         setenv("PGCLIENTENCODING", encoding, 1);
     766             :     else
     767         164 :         unsetenv("PGCLIENTENCODING");
     768             : 
     769             :     /*
     770             :      * Set timezone and datestyle for datetime-related tests
     771             :      */
     772         166 :     setenv("PGTZ", "PST8PDT", 1);
     773         166 :     setenv("PGDATESTYLE", "Postgres, MDY", 1);
     774             : 
     775             :     /*
     776             :      * Likewise set intervalstyle to ensure consistent results.  This is a bit
     777             :      * more painful because we must use PGOPTIONS, and we want to preserve the
     778             :      * user's ability to set other variables through that.
     779             :      */
     780             :     {
     781         166 :         const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
     782         166 :         const char *old_pgoptions = getenv("PGOPTIONS");
     783             :         char       *new_pgoptions;
     784             : 
     785         166 :         if (!old_pgoptions)
     786         166 :             old_pgoptions = "";
     787         166 :         new_pgoptions = psprintf("%s %s",
     788             :                                  old_pgoptions, my_pgoptions);
     789         166 :         setenv("PGOPTIONS", new_pgoptions, 1);
     790         166 :         free(new_pgoptions);
     791             :     }
     792             : 
     793         166 :     if (temp_instance)
     794             :     {
     795             :         /*
     796             :          * Clear out any environment vars that might cause psql to connect to
     797             :          * the wrong postmaster, or otherwise behave in nondefault ways. (Note
     798             :          * we also use psql's -X switch consistently, so that ~/.psqlrc files
     799             :          * won't mess things up.)  Also, set PGPORT to the temp port, and set
     800             :          * PGHOST depending on whether we are using TCP or Unix sockets.
     801             :          *
     802             :          * This list should be kept in sync with PostgreSQL/Test/Utils.pm.
     803             :          */
     804         162 :         unsetenv("PGCHANNELBINDING");
     805             :         /* PGCLIENTENCODING, see above */
     806         162 :         unsetenv("PGCONNECT_TIMEOUT");
     807         162 :         unsetenv("PGDATA");
     808         162 :         unsetenv("PGDATABASE");
     809         162 :         unsetenv("PGGSSDELEGATION");
     810         162 :         unsetenv("PGGSSENCMODE");
     811         162 :         unsetenv("PGGSSLIB");
     812             :         /* PGHOSTADDR, see below */
     813         162 :         unsetenv("PGKRBSRVNAME");
     814         162 :         unsetenv("PGPASSFILE");
     815         162 :         unsetenv("PGPASSWORD");
     816         162 :         unsetenv("PGREQUIREPEER");
     817         162 :         unsetenv("PGREQUIRESSL");
     818         162 :         unsetenv("PGSERVICE");
     819         162 :         unsetenv("PGSERVICEFILE");
     820         162 :         unsetenv("PGSSLCERT");
     821         162 :         unsetenv("PGSSLCRL");
     822         162 :         unsetenv("PGSSLCRLDIR");
     823         162 :         unsetenv("PGSSLKEY");
     824         162 :         unsetenv("PGSSLMAXPROTOCOLVERSION");
     825         162 :         unsetenv("PGSSLMINPROTOCOLVERSION");
     826         162 :         unsetenv("PGSSLMODE");
     827         162 :         unsetenv("PGSSLROOTCERT");
     828         162 :         unsetenv("PGSSLSNI");
     829         162 :         unsetenv("PGTARGETSESSIONATTRS");
     830         162 :         unsetenv("PGUSER");
     831             :         /* PGPORT, see below */
     832             :         /* PGHOST, see below */
     833             : 
     834         162 :         if (hostname != NULL)
     835           2 :             setenv("PGHOST", hostname, 1);
     836             :         else
     837             :         {
     838         160 :             sockdir = getenv("PG_REGRESS_SOCK_DIR");
     839         160 :             if (!sockdir)
     840         160 :                 sockdir = make_temp_sockdir();
     841         160 :             setenv("PGHOST", sockdir, 1);
     842             :         }
     843         162 :         unsetenv("PGHOSTADDR");
     844         162 :         if (port != -1)
     845             :         {
     846             :             char        s[16];
     847             : 
     848         162 :             snprintf(s, sizeof(s), "%d", port);
     849         162 :             setenv("PGPORT", s, 1);
     850             :         }
     851             :     }
     852             :     else
     853             :     {
     854             :         const char *pghost;
     855             :         const char *pgport;
     856             : 
     857             :         /*
     858             :          * When testing an existing install, we honor existing environment
     859             :          * variables, except if they're overridden by command line options.
     860             :          */
     861           4 :         if (hostname != NULL)
     862             :         {
     863           4 :             setenv("PGHOST", hostname, 1);
     864           4 :             unsetenv("PGHOSTADDR");
     865             :         }
     866           4 :         if (port != -1)
     867             :         {
     868             :             char        s[16];
     869             : 
     870           4 :             snprintf(s, sizeof(s), "%d", port);
     871           4 :             setenv("PGPORT", s, 1);
     872             :         }
     873           4 :         if (user != NULL)
     874           0 :             setenv("PGUSER", user, 1);
     875             : 
     876             :         /*
     877             :          * However, we *don't* honor PGDATABASE, since we certainly don't wish
     878             :          * to connect to whatever database the user might like as default.
     879             :          * (Most tests override PGDATABASE anyway, but there are some ECPG
     880             :          * test cases that don't.)
     881             :          */
     882           4 :         unsetenv("PGDATABASE");
     883             : 
     884             :         /*
     885             :          * Report what we're connecting to
     886             :          */
     887           4 :         pghost = getenv("PGHOST");
     888           4 :         pgport = getenv("PGPORT");
     889           4 :         if (!pghost)
     890             :         {
     891             :             /* Keep this bit in sync with libpq's default host location: */
     892           0 :             if (DEFAULT_PGSOCKET_DIR[0])
     893             :                  /* do nothing, we'll print "Unix socket" below */ ;
     894             :             else
     895           0 :                 pghost = "localhost"; /* DefaultHost in fe-connect.c */
     896             :         }
     897             : 
     898           4 :         if (pghost && pgport)
     899           4 :             note("using postmaster on %s, port %s", pghost, pgport);
     900           4 :         if (pghost && !pgport)
     901           0 :             note("using postmaster on %s, default port", pghost);
     902           4 :         if (!pghost && pgport)
     903           0 :             note("using postmaster on Unix socket, port %s", pgport);
     904           4 :         if (!pghost && !pgport)
     905           0 :             note("using postmaster on Unix socket, default port");
     906             :     }
     907             : 
     908         166 :     load_resultmap();
     909         166 : }
     910             : 
     911             : #ifdef ENABLE_SSPI
     912             : 
     913             : /* support for config_sspi_auth() */
     914             : static const char *
     915             : fmtHba(const char *raw)
     916             : {
     917             :     static char *ret;
     918             :     const char *rp;
     919             :     char       *wp;
     920             : 
     921             :     wp = ret = pg_realloc(ret, 3 + strlen(raw) * 2);
     922             : 
     923             :     *wp++ = '"';
     924             :     for (rp = raw; *rp; rp++)
     925             :     {
     926             :         if (*rp == '"')
     927             :             *wp++ = '"';
     928             :         *wp++ = *rp;
     929             :     }
     930             :     *wp++ = '"';
     931             :     *wp++ = '\0';
     932             : 
     933             :     return ret;
     934             : }
     935             : 
     936             : /*
     937             :  * Get account and domain/realm names for the current user.  This is based on
     938             :  * pg_SSPI_recvauth().  The returned strings use static storage.
     939             :  */
     940             : static void
     941             : current_windows_user(const char **acct, const char **dom)
     942             : {
     943             :     static char accountname[MAXPGPATH];
     944             :     static char domainname[MAXPGPATH];
     945             :     HANDLE      token;
     946             :     TOKEN_USER *tokenuser;
     947             :     DWORD       retlen;
     948             :     DWORD       accountnamesize = sizeof(accountname);
     949             :     DWORD       domainnamesize = sizeof(domainname);
     950             :     SID_NAME_USE accountnameuse;
     951             : 
     952             :     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token))
     953             :     {
     954             :         bail("could not open process token: error code %lu", GetLastError());
     955             :     }
     956             : 
     957             :     if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && GetLastError() != 122)
     958             :     {
     959             :         bail("could not get token information buffer size: error code %lu",
     960             :              GetLastError());
     961             :     }
     962             :     tokenuser = pg_malloc(retlen);
     963             :     if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen))
     964             :     {
     965             :         bail("could not get token information: error code %lu",
     966             :              GetLastError());
     967             :     }
     968             : 
     969             :     if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, &accountnamesize,
     970             :                           domainname, &domainnamesize, &accountnameuse))
     971             :     {
     972             :         bail("could not look up account SID: error code %lu",
     973             :              GetLastError());
     974             :     }
     975             : 
     976             :     free(tokenuser);
     977             : 
     978             :     *acct = accountname;
     979             :     *dom = domainname;
     980             : }
     981             : 
     982             : /*
     983             :  * Rewrite pg_hba.conf and pg_ident.conf to use SSPI authentication.  Permit
     984             :  * the current OS user to authenticate as the bootstrap superuser and as any
     985             :  * user named in a --create-role option.
     986             :  *
     987             :  * In --config-auth mode, the --user switch can be used to specify the
     988             :  * bootstrap superuser's name, otherwise we assume it is the default.
     989             :  */
     990             : static void
     991             : config_sspi_auth(const char *pgdata, const char *superuser_name)
     992             : {
     993             :     const char *accountname,
     994             :                *domainname;
     995             :     char       *errstr;
     996             :     bool        have_ipv6;
     997             :     char        fname[MAXPGPATH];
     998             :     int         res;
     999             :     FILE       *hba,
    1000             :                *ident;
    1001             :     _stringlist *sl;
    1002             : 
    1003             :     /* Find out the name of the current OS user */
    1004             :     current_windows_user(&accountname, &domainname);
    1005             : 
    1006             :     /* Determine the bootstrap superuser's name */
    1007             :     if (superuser_name == NULL)
    1008             :     {
    1009             :         /*
    1010             :          * Compute the default superuser name the same way initdb does.
    1011             :          *
    1012             :          * It's possible that this result always matches "accountname", the
    1013             :          * value SSPI authentication discovers.  But the underlying system
    1014             :          * functions do not clearly guarantee that.
    1015             :          */
    1016             :         superuser_name = get_user_name(&errstr);
    1017             :         if (superuser_name == NULL)
    1018             :         {
    1019             :             bail("%s", errstr);
    1020             :         }
    1021             :     }
    1022             : 
    1023             :     /*
    1024             :      * Like initdb.c:setup_config(), determine whether the platform recognizes
    1025             :      * ::1 (IPv6 loopback) as a numeric host address string.
    1026             :      */
    1027             :     {
    1028             :         struct addrinfo *gai_result;
    1029             :         struct addrinfo hints;
    1030             :         WSADATA     wsaData;
    1031             : 
    1032             :         hints.ai_flags = AI_NUMERICHOST;
    1033             :         hints.ai_family = AF_UNSPEC;
    1034             :         hints.ai_socktype = 0;
    1035             :         hints.ai_protocol = 0;
    1036             :         hints.ai_addrlen = 0;
    1037             :         hints.ai_canonname = NULL;
    1038             :         hints.ai_addr = NULL;
    1039             :         hints.ai_next = NULL;
    1040             : 
    1041             :         have_ipv6 = (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0 &&
    1042             :                      getaddrinfo("::1", NULL, &hints, &gai_result) == 0);
    1043             :     }
    1044             : 
    1045             :     /* Check a Write outcome and report any error. */
    1046             : #define CW(cond)    \
    1047             :     do { \
    1048             :         if (!(cond)) \
    1049             :         { \
    1050             :             bail("could not write to file \"%s\": %s", \
    1051             :                  fname, strerror(errno)); \
    1052             :         } \
    1053             :     } while (0)
    1054             : 
    1055             :     res = snprintf(fname, sizeof(fname), "%s/pg_hba.conf", pgdata);
    1056             :     if (res < 0 || res >= sizeof(fname))
    1057             :     {
    1058             :         /*
    1059             :          * Truncating this name is a fatal error, because we must not fail to
    1060             :          * overwrite an original trust-authentication pg_hba.conf.
    1061             :          */
    1062             :         bail("directory name too long");
    1063             :     }
    1064             :     hba = fopen(fname, "w");
    1065             :     if (hba == NULL)
    1066             :     {
    1067             :         bail("could not open file \"%s\" for writing: %s",
    1068             :              fname, strerror(errno));
    1069             :     }
    1070             :     CW(fputs("# Configuration written by config_sspi_auth()\n", hba) >= 0);
    1071             :     CW(fputs("host all all 127.0.0.1/32  sspi include_realm=1 map=regress\n",
    1072             :              hba) >= 0);
    1073             :     if (have_ipv6)
    1074             :         CW(fputs("host all all ::1/128  sspi include_realm=1 map=regress\n",
    1075             :                  hba) >= 0);
    1076             :     CW(fclose(hba) == 0);
    1077             : 
    1078             :     snprintf(fname, sizeof(fname), "%s/pg_ident.conf", pgdata);
    1079             :     ident = fopen(fname, "w");
    1080             :     if (ident == NULL)
    1081             :     {
    1082             :         bail("could not open file \"%s\" for writing: %s",
    1083             :              fname, strerror(errno));
    1084             :     }
    1085             :     CW(fputs("# Configuration written by config_sspi_auth()\n", ident) >= 0);
    1086             : 
    1087             :     /*
    1088             :      * Double-quote for the benefit of account names containing whitespace or
    1089             :      * '#'.  Windows forbids the double-quote character itself, so don't
    1090             :      * bother escaping embedded double-quote characters.
    1091             :      */
    1092             :     CW(fprintf(ident, "regress  \"%s@%s\"  %s\n",
    1093             :                accountname, domainname, fmtHba(superuser_name)) >= 0);
    1094             :     for (sl = extraroles; sl; sl = sl->next)
    1095             :         CW(fprintf(ident, "regress  \"%s@%s\"  %s\n",
    1096             :                    accountname, domainname, fmtHba(sl->str)) >= 0);
    1097             :     CW(fclose(ident) == 0);
    1098             : }
    1099             : 
    1100             : #endif                          /* ENABLE_SSPI */
    1101             : 
    1102             : /*
    1103             :  * psql_start_command, psql_add_command, psql_end_command
    1104             :  *
    1105             :  * Issue one or more commands within one psql call.
    1106             :  * Set up with psql_start_command, then add commands one at a time
    1107             :  * with psql_add_command, and finally execute with psql_end_command.
    1108             :  *
    1109             :  * Since we use system(), this doesn't return until the operation finishes
    1110             :  */
    1111             : static StringInfo
    1112         192 : psql_start_command(void)
    1113             : {
    1114         192 :     StringInfo  buf = makeStringInfo();
    1115             : 
    1116         384 :     appendStringInfo(buf,
    1117             :                      "\"%s%spsql\" -X -q",
    1118         192 :                      bindir ? bindir : "",
    1119         192 :                      bindir ? "/" : "");
    1120         192 :     return buf;
    1121             : }
    1122             : 
    1123             : static void
    1124         382 : psql_add_command(StringInfo buf, const char *query,...)
    1125             : {
    1126             :     StringInfoData cmdbuf;
    1127             :     const char *cmdptr;
    1128             : 
    1129             :     /* Add each command as a -c argument in the psql call */
    1130         382 :     appendStringInfoString(buf, " -c \"");
    1131             : 
    1132             :     /* Generate the query with insertion of sprintf arguments */
    1133         382 :     initStringInfo(&cmdbuf);
    1134             :     for (;;)
    1135           0 :     {
    1136             :         va_list     args;
    1137             :         int         needed;
    1138             : 
    1139         382 :         va_start(args, query);
    1140         382 :         needed = appendStringInfoVA(&cmdbuf, query, args);
    1141         382 :         va_end(args);
    1142         382 :         if (needed == 0)
    1143         382 :             break;              /* success */
    1144           0 :         enlargeStringInfo(&cmdbuf, needed);
    1145             :     }
    1146             : 
    1147             :     /* Now escape any shell double-quote metacharacters */
    1148       74010 :     for (cmdptr = cmdbuf.data; *cmdptr; cmdptr++)
    1149             :     {
    1150       73628 :         if (strchr("\\\"$`", *cmdptr))
    1151        2488 :             appendStringInfoChar(buf, '\\');
    1152       73628 :         appendStringInfoChar(buf, *cmdptr);
    1153             :     }
    1154             : 
    1155         382 :     appendStringInfoChar(buf, '"');
    1156             : 
    1157         382 :     pfree(cmdbuf.data);
    1158         382 : }
    1159             : 
    1160             : static void
    1161         192 : psql_end_command(StringInfo buf, const char *database)
    1162             : {
    1163             :     /* Add the database name --- assume it needs no extra escaping */
    1164         192 :     appendStringInfo(buf,
    1165             :                      " \"%s\"",
    1166             :                      database);
    1167             : 
    1168             :     /* And now we can execute the shell command */
    1169         192 :     fflush(NULL);
    1170         192 :     if (system(buf->data) != 0)
    1171             :     {
    1172             :         /* psql probably already reported the error */
    1173           0 :         bail("command failed: %s", buf->data);
    1174             :     }
    1175             : 
    1176             :     /* Clean up */
    1177         192 :     pfree(buf->data);
    1178         192 :     pfree(buf);
    1179         192 : }
    1180             : 
    1181             : /*
    1182             :  * Shorthand macro for the common case of a single command
    1183             :  */
    1184             : #define psql_command(database, ...) \
    1185             :     do { \
    1186             :         StringInfo cmdbuf = psql_start_command(); \
    1187             :         psql_add_command(cmdbuf, __VA_ARGS__); \
    1188             :         psql_end_command(cmdbuf, database); \
    1189             :     } while (0)
    1190             : 
    1191             : /*
    1192             :  * Spawn a process to execute the given shell command; don't wait for it
    1193             :  *
    1194             :  * Returns the process ID (or HANDLE) so we can wait for it later
    1195             :  */
    1196             : PID_TYPE
    1197        2528 : spawn_process(const char *cmdline)
    1198             : {
    1199             : #ifndef WIN32
    1200             :     pid_t       pid;
    1201             : 
    1202             :     /*
    1203             :      * Must flush I/O buffers before fork.
    1204             :      */
    1205        2528 :     fflush(NULL);
    1206             : 
    1207             : #ifdef EXEC_BACKEND
    1208             :     pg_disable_aslr();
    1209             : #endif
    1210             : 
    1211        2528 :     pid = fork();
    1212        5056 :     if (pid == -1)
    1213             :     {
    1214           0 :         bail("could not fork: %s", strerror(errno));
    1215             :     }
    1216        5056 :     if (pid == 0)
    1217             :     {
    1218             :         /*
    1219             :          * In child
    1220             :          *
    1221             :          * Instead of using system(), exec the shell directly, and tell it to
    1222             :          * "exec" the command too.  This saves two useless processes per
    1223             :          * parallel test case.
    1224             :          */
    1225             :         char       *cmdline2;
    1226             : 
    1227        2528 :         cmdline2 = psprintf("exec %s", cmdline);
    1228        2528 :         execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
    1229             :         /* Not using the normal bail() here as we want _exit */
    1230        2528 :         bail_noatexit("could not exec \"%s\": %s", shellprog, strerror(errno));
    1231             :     }
    1232             :     /* in parent */
    1233        2528 :     return pid;
    1234             : #else
    1235             :     PROCESS_INFORMATION pi;
    1236             :     char       *cmdline2;
    1237             :     const char *comspec;
    1238             : 
    1239             :     /* Find CMD.EXE location using COMSPEC, if it's set */
    1240             :     comspec = getenv("COMSPEC");
    1241             :     if (comspec == NULL)
    1242             :         comspec = "CMD";
    1243             : 
    1244             :     memset(&pi, 0, sizeof(pi));
    1245             :     cmdline2 = psprintf("\"%s\" /c \"%s\"", comspec, cmdline);
    1246             : 
    1247             :     if (!CreateRestrictedProcess(cmdline2, &pi))
    1248             :         exit(2);
    1249             : 
    1250             :     CloseHandle(pi.hThread);
    1251             :     return pi.hProcess;
    1252             : #endif
    1253             : }
    1254             : 
    1255             : /*
    1256             :  * Count bytes in file
    1257             :  */
    1258             : static long
    1259         166 : file_size(const char *file)
    1260             : {
    1261             :     long        r;
    1262         166 :     FILE       *f = fopen(file, "r");
    1263             : 
    1264         166 :     if (!f)
    1265             :     {
    1266           0 :         diag("could not open file \"%s\" for reading: %s",
    1267             :              file, strerror(errno));
    1268           0 :         return -1;
    1269             :     }
    1270         166 :     fseek(f, 0, SEEK_END);
    1271         166 :     r = ftell(f);
    1272         166 :     fclose(f);
    1273         166 :     return r;
    1274             : }
    1275             : 
    1276             : /*
    1277             :  * Count lines in file
    1278             :  */
    1279             : static int
    1280          70 : file_line_count(const char *file)
    1281             : {
    1282             :     int         c;
    1283          70 :     int         l = 0;
    1284          70 :     FILE       *f = fopen(file, "r");
    1285             : 
    1286          70 :     if (!f)
    1287             :     {
    1288           0 :         diag("could not open file \"%s\" for reading: %s",
    1289             :              file, strerror(errno));
    1290           0 :         return -1;
    1291             :     }
    1292      674540 :     while ((c = fgetc(f)) != EOF)
    1293             :     {
    1294      674470 :         if (c == '\n')
    1295       24132 :             l++;
    1296             :     }
    1297          70 :     fclose(f);
    1298          70 :     return l;
    1299             : }
    1300             : 
    1301             : bool
    1302        4380 : file_exists(const char *file)
    1303             : {
    1304        4380 :     FILE       *f = fopen(file, "r");
    1305             : 
    1306        4380 :     if (!f)
    1307        2330 :         return false;
    1308        2050 :     fclose(f);
    1309        2050 :     return true;
    1310             : }
    1311             : 
    1312             : static bool
    1313         656 : directory_exists(const char *dir)
    1314             : {
    1315             :     struct stat st;
    1316             : 
    1317         656 :     if (stat(dir, &st) != 0)
    1318         498 :         return false;
    1319         158 :     if (S_ISDIR(st.st_mode))
    1320         158 :         return true;
    1321           0 :     return false;
    1322             : }
    1323             : 
    1324             : /* Create a directory */
    1325             : static void
    1326         498 : make_directory(const char *dir)
    1327             : {
    1328         498 :     if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
    1329             :     {
    1330           0 :         bail("could not create directory \"%s\": %s", dir, strerror(errno));
    1331             :     }
    1332         498 : }
    1333             : 
    1334             : /*
    1335             :  * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
    1336             :  */
    1337             : static char *
    1338         156 : get_alternative_expectfile(const char *expectfile, int i)
    1339             : {
    1340             :     char       *last_dot;
    1341         156 :     int         ssize = strlen(expectfile) + 2 + 1;
    1342             :     char       *tmp;
    1343             :     char       *s;
    1344             : 
    1345         156 :     if (!(tmp = (char *) malloc(ssize)))
    1346           0 :         return NULL;
    1347             : 
    1348         156 :     if (!(s = (char *) malloc(ssize)))
    1349             :     {
    1350           0 :         free(tmp);
    1351           0 :         return NULL;
    1352             :     }
    1353             : 
    1354         156 :     strcpy(tmp, expectfile);
    1355         156 :     last_dot = strrchr(tmp, '.');
    1356         156 :     if (!last_dot)
    1357             :     {
    1358           0 :         free(tmp);
    1359           0 :         free(s);
    1360           0 :         return NULL;
    1361             :     }
    1362         156 :     *last_dot = '\0';
    1363         156 :     snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
    1364         156 :     free(tmp);
    1365         156 :     return s;
    1366             : }
    1367             : 
    1368             : /*
    1369             :  * Run a "diff" command and also check that it didn't crash
    1370             :  */
    1371             : static int
    1372        2944 : run_diff(const char *cmd, const char *filename)
    1373             : {
    1374             :     int         r;
    1375             : 
    1376        2944 :     fflush(NULL);
    1377        2944 :     r = system(cmd);
    1378        2944 :     if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
    1379             :     {
    1380           0 :         bail("diff command failed with status %d: %s", r, cmd);
    1381             :     }
    1382             : #ifdef WIN32
    1383             : 
    1384             :     /*
    1385             :      * On WIN32, if the 'diff' command cannot be found, system() returns 1,
    1386             :      * but produces nothing to stdout, so we check for that here.
    1387             :      */
    1388             :     if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
    1389             :     {
    1390             :         bail("diff command not found: %s", cmd);
    1391             :     }
    1392             : #endif
    1393             : 
    1394        2944 :     return WEXITSTATUS(r);
    1395             : }
    1396             : 
    1397             : /*
    1398             :  * Check the actual result file for the given test against expected results
    1399             :  *
    1400             :  * Returns true if different (failure), false if correct match found.
    1401             :  * In the true case, the diff is appended to the diffs file.
    1402             :  */
    1403             : static bool
    1404        2874 : results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
    1405             : {
    1406             :     char        expectfile[MAXPGPATH];
    1407             :     char        diff[MAXPGPATH];
    1408             :     char        cmd[MAXPGPATH * 3];
    1409             :     char        best_expect_file[MAXPGPATH];
    1410             :     FILE       *difffile;
    1411             :     int         best_line_count;
    1412             :     int         i;
    1413             :     int         l;
    1414             :     const char *platform_expectfile;
    1415             : 
    1416             :     /*
    1417             :      * We can pass either the resultsfile or the expectfile, they should have
    1418             :      * the same type (filename.type) anyway.
    1419             :      */
    1420        2874 :     platform_expectfile = get_expectfile(testname, resultsfile);
    1421             : 
    1422        2874 :     strlcpy(expectfile, default_expectfile, sizeof(expectfile));
    1423        2874 :     if (platform_expectfile)
    1424             :     {
    1425             :         /*
    1426             :          * Replace everything after the last slash in expectfile with what the
    1427             :          * platform_expectfile contains.
    1428             :          */
    1429           0 :         char       *p = strrchr(expectfile, '/');
    1430             : 
    1431           0 :         if (p)
    1432           0 :             strcpy(++p, platform_expectfile);
    1433             :     }
    1434             : 
    1435             :     /* Name to use for temporary diff file */
    1436        2874 :     snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
    1437             : 
    1438             :     /* OK, run the diff */
    1439        2874 :     snprintf(cmd, sizeof(cmd),
    1440             :              "diff %s \"%s\" \"%s\" > \"%s\"",
    1441             :              basic_diff_opts, expectfile, resultsfile, diff);
    1442             : 
    1443             :     /* Is the diff file empty? */
    1444        2874 :     if (run_diff(cmd, diff) == 0)
    1445             :     {
    1446        2808 :         unlink(diff);
    1447        2808 :         return false;
    1448             :     }
    1449             : 
    1450             :     /* There may be secondary comparison files that match better */
    1451          66 :     best_line_count = file_line_count(diff);
    1452          66 :     strcpy(best_expect_file, expectfile);
    1453             : 
    1454         156 :     for (i = 0; i <= 9; i++)
    1455             :     {
    1456             :         char       *alt_expectfile;
    1457             : 
    1458         156 :         alt_expectfile = get_alternative_expectfile(expectfile, i);
    1459         156 :         if (!alt_expectfile)
    1460             :         {
    1461           0 :             bail("Unable to check secondary comparison files: %s",
    1462             :                  strerror(errno));
    1463             :         }
    1464             : 
    1465         156 :         if (!file_exists(alt_expectfile))
    1466             :         {
    1467          86 :             free(alt_expectfile);
    1468          86 :             continue;
    1469             :         }
    1470             : 
    1471          70 :         snprintf(cmd, sizeof(cmd),
    1472             :                  "diff %s \"%s\" \"%s\" > \"%s\"",
    1473             :                  basic_diff_opts, alt_expectfile, resultsfile, diff);
    1474             : 
    1475          70 :         if (run_diff(cmd, diff) == 0)
    1476             :         {
    1477          66 :             unlink(diff);
    1478          66 :             free(alt_expectfile);
    1479          66 :             return false;
    1480             :         }
    1481             : 
    1482           4 :         l = file_line_count(diff);
    1483           4 :         if (l < best_line_count)
    1484             :         {
    1485             :             /* This diff was a better match than the last one */
    1486           4 :             best_line_count = l;
    1487           4 :             strlcpy(best_expect_file, alt_expectfile, sizeof(best_expect_file));
    1488             :         }
    1489           4 :         free(alt_expectfile);
    1490             :     }
    1491             : 
    1492             :     /*
    1493             :      * fall back on the canonical results file if we haven't tried it yet and
    1494             :      * haven't found a complete match yet.
    1495             :      */
    1496             : 
    1497           0 :     if (platform_expectfile)
    1498             :     {
    1499           0 :         snprintf(cmd, sizeof(cmd),
    1500             :                  "diff %s \"%s\" \"%s\" > \"%s\"",
    1501             :                  basic_diff_opts, default_expectfile, resultsfile, diff);
    1502             : 
    1503           0 :         if (run_diff(cmd, diff) == 0)
    1504             :         {
    1505             :             /* No diff = no changes = good */
    1506           0 :             unlink(diff);
    1507           0 :             return false;
    1508             :         }
    1509             : 
    1510           0 :         l = file_line_count(diff);
    1511           0 :         if (l < best_line_count)
    1512             :         {
    1513             :             /* This diff was a better match than the last one */
    1514           0 :             best_line_count = l;
    1515           0 :             strlcpy(best_expect_file, default_expectfile, sizeof(best_expect_file));
    1516             :         }
    1517             :     }
    1518             : 
    1519             :     /*
    1520             :      * Use the best comparison file to generate the "pretty" diff, which we
    1521             :      * append to the diffs summary file.
    1522             :      */
    1523             : 
    1524             :     /* Write diff header */
    1525           0 :     difffile = fopen(difffilename, "a");
    1526           0 :     if (difffile)
    1527             :     {
    1528           0 :         fprintf(difffile,
    1529             :                 "diff %s %s %s\n",
    1530             :                 pretty_diff_opts, best_expect_file, resultsfile);
    1531           0 :         fclose(difffile);
    1532             :     }
    1533             : 
    1534             :     /* Run diff */
    1535           0 :     snprintf(cmd, sizeof(cmd),
    1536             :              "diff %s \"%s\" \"%s\" >> \"%s\"",
    1537             :              pretty_diff_opts, best_expect_file, resultsfile, difffilename);
    1538           0 :     run_diff(cmd, difffilename);
    1539             : 
    1540           0 :     unlink(diff);
    1541           0 :     return true;
    1542             : }
    1543             : 
    1544             : /*
    1545             :  * Wait for specified subprocesses to finish, and return their exit
    1546             :  * statuses into statuses[] and stop times into stoptimes[]
    1547             :  *
    1548             :  * If names isn't NULL, print each subprocess's name as it finishes
    1549             :  *
    1550             :  * Note: it's OK to scribble on the pids array, but not on the names array
    1551             :  */
    1552             : static void
    1553        1226 : wait_for_tests(PID_TYPE * pids, int *statuses, instr_time *stoptimes,
    1554             :                char **names, int num_tests)
    1555             : {
    1556             :     int         tests_left;
    1557             :     int         i;
    1558             : 
    1559             : #ifdef WIN32
    1560             :     PID_TYPE   *active_pids = pg_malloc(num_tests * sizeof(PID_TYPE));
    1561             : 
    1562             :     memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
    1563             : #endif
    1564             : 
    1565        1226 :     tests_left = num_tests;
    1566        3592 :     while (tests_left > 0)
    1567             :     {
    1568             :         PID_TYPE    p;
    1569             : 
    1570             : #ifndef WIN32
    1571             :         int         exit_status;
    1572             : 
    1573        2366 :         p = wait(&exit_status);
    1574             : 
    1575        2366 :         if (p == INVALID_PID)
    1576             :         {
    1577           0 :             bail("failed to wait for subprocesses: %s", strerror(errno));
    1578             :         }
    1579             : #else
    1580             :         DWORD       exit_status;
    1581             :         int         r;
    1582             : 
    1583             :         r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
    1584             :         if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
    1585             :         {
    1586             :             bail("failed to wait for subprocesses: error code %lu",
    1587             :                  GetLastError());
    1588             :         }
    1589             :         p = active_pids[r - WAIT_OBJECT_0];
    1590             :         /* compact the active_pids array */
    1591             :         active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
    1592             : #endif                          /* WIN32 */
    1593             : 
    1594       11408 :         for (i = 0; i < num_tests; i++)
    1595             :         {
    1596       11408 :             if (p == pids[i])
    1597             :             {
    1598             : #ifdef WIN32
    1599             :                 GetExitCodeProcess(pids[i], &exit_status);
    1600             :                 CloseHandle(pids[i]);
    1601             : #endif
    1602        2366 :                 pids[i] = INVALID_PID;
    1603        2366 :                 statuses[i] = (int) exit_status;
    1604        2366 :                 INSTR_TIME_SET_CURRENT(stoptimes[i]);
    1605        2366 :                 if (names)
    1606        1248 :                     note_detail(" %s", names[i]);
    1607        2366 :                 tests_left--;
    1608        2366 :                 break;
    1609             :             }
    1610             :         }
    1611             :     }
    1612             : 
    1613             : #ifdef WIN32
    1614             :     free(active_pids);
    1615             : #endif
    1616        1226 : }
    1617             : 
    1618             : /*
    1619             :  * report nonzero exit code from a test process
    1620             :  */
    1621             : static void
    1622           0 : log_child_failure(int exitstatus)
    1623             : {
    1624           0 :     if (WIFEXITED(exitstatus))
    1625           0 :         diag("(test process exited with exit code %d)",
    1626             :              WEXITSTATUS(exitstatus));
    1627           0 :     else if (WIFSIGNALED(exitstatus))
    1628             :     {
    1629             : #if defined(WIN32)
    1630             :         diag("(test process was terminated by exception 0x%X)",
    1631             :              WTERMSIG(exitstatus));
    1632             : #else
    1633           0 :         diag("(test process was terminated by signal %d: %s)",
    1634             :              WTERMSIG(exitstatus), pg_strsignal(WTERMSIG(exitstatus)));
    1635             : #endif
    1636             :     }
    1637             :     else
    1638           0 :         diag("(test process exited with unrecognized status %d)", exitstatus);
    1639           0 : }
    1640             : 
    1641             : /*
    1642             :  * Run all the tests specified in one schedule file
    1643             :  */
    1644             : static void
    1645          12 : run_schedule(const char *schedule, test_start_function startfunc,
    1646             :              postprocess_result_function postfunc)
    1647             : {
    1648             : #define MAX_PARALLEL_TESTS 100
    1649             :     char       *tests[MAX_PARALLEL_TESTS];
    1650             :     _stringlist *resultfiles[MAX_PARALLEL_TESTS];
    1651             :     _stringlist *expectfiles[MAX_PARALLEL_TESTS];
    1652             :     _stringlist *tags[MAX_PARALLEL_TESTS];
    1653             :     PID_TYPE    pids[MAX_PARALLEL_TESTS];
    1654             :     instr_time  starttimes[MAX_PARALLEL_TESTS];
    1655             :     instr_time  stoptimes[MAX_PARALLEL_TESTS];
    1656             :     int         statuses[MAX_PARALLEL_TESTS];
    1657             :     char        scbuf[1024];
    1658             :     FILE       *scf;
    1659          12 :     int         line_num = 0;
    1660             : 
    1661          12 :     memset(tests, 0, sizeof(tests));
    1662          12 :     memset(resultfiles, 0, sizeof(resultfiles));
    1663          12 :     memset(expectfiles, 0, sizeof(expectfiles));
    1664          12 :     memset(tags, 0, sizeof(tags));
    1665             : 
    1666          12 :     scf = fopen(schedule, "r");
    1667          12 :     if (!scf)
    1668             :     {
    1669           0 :         bail("could not open file \"%s\" for reading: %s",
    1670             :              schedule, strerror(errno));
    1671             :     }
    1672             : 
    1673        1314 :     while (fgets(scbuf, sizeof(scbuf), scf))
    1674             :     {
    1675        1302 :         char       *test = NULL;
    1676             :         char       *c;
    1677             :         int         num_tests;
    1678             :         bool        inword;
    1679             :         int         i;
    1680             : 
    1681        1302 :         line_num++;
    1682             : 
    1683             :         /* strip trailing whitespace, especially the newline */
    1684        1302 :         i = strlen(scbuf);
    1685        2604 :         while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
    1686        1302 :             scbuf[--i] = '\0';
    1687             : 
    1688        1302 :         if (scbuf[0] == '\0' || scbuf[0] == '#')
    1689         672 :             continue;
    1690         630 :         if (strncmp(scbuf, "test: ", 6) == 0)
    1691         630 :             test = scbuf + 6;
    1692             :         else
    1693             :         {
    1694           0 :             bail("syntax error in schedule file \"%s\" line %d: %s",
    1695             :                  schedule, line_num, scbuf);
    1696             :         }
    1697             : 
    1698         630 :         num_tests = 0;
    1699         630 :         inword = false;
    1700       21498 :         for (c = test;; c++)
    1701             :         {
    1702       21498 :             if (*c == '\0' || isspace((unsigned char) *c))
    1703             :             {
    1704        1770 :                 if (inword)
    1705             :                 {
    1706             :                     /* Reached end of a test name */
    1707             :                     char        sav;
    1708             : 
    1709        1770 :                     if (num_tests >= MAX_PARALLEL_TESTS)
    1710             :                     {
    1711           0 :                         bail("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s",
    1712             :                              MAX_PARALLEL_TESTS, schedule, line_num, scbuf);
    1713             :                     }
    1714        1770 :                     sav = *c;
    1715        1770 :                     *c = '\0';
    1716        1770 :                     tests[num_tests] = pg_strdup(test);
    1717        1770 :                     num_tests++;
    1718        1770 :                     *c = sav;
    1719        1770 :                     inword = false;
    1720             :                 }
    1721        1770 :                 if (*c == '\0')
    1722         630 :                     break;      /* loop exit is here */
    1723             :             }
    1724       19728 :             else if (!inword)
    1725             :             {
    1726             :                 /* Start of a test name */
    1727        1770 :                 test = c;
    1728        1770 :                 inword = true;
    1729             :             }
    1730             :         }
    1731             : 
    1732         630 :         if (num_tests == 0)
    1733             :         {
    1734           0 :             bail("syntax error in schedule file \"%s\" line %d: %s",
    1735             :                  schedule, line_num, scbuf);
    1736             :         }
    1737             : 
    1738         630 :         if (num_tests == 1)
    1739             :         {
    1740         522 :             pids[0] = (startfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
    1741         522 :             INSTR_TIME_SET_CURRENT(starttimes[0]);
    1742         522 :             wait_for_tests(pids, statuses, stoptimes, NULL, 1);
    1743             :             /* status line is finished below */
    1744             :         }
    1745         108 :         else if (max_concurrent_tests > 0 && max_concurrent_tests < num_tests)
    1746             :         {
    1747           0 :             bail("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s",
    1748             :                  max_concurrent_tests, schedule, line_num, scbuf);
    1749             :         }
    1750         108 :         else if (max_connections > 0 && max_connections < num_tests)
    1751           0 :         {
    1752           0 :             int         oldest = 0;
    1753             : 
    1754           0 :             note_detail("parallel group (%d tests, in groups of %d): ",
    1755             :                         num_tests, max_connections);
    1756           0 :             for (i = 0; i < num_tests; i++)
    1757             :             {
    1758           0 :                 if (i - oldest >= max_connections)
    1759             :                 {
    1760           0 :                     wait_for_tests(pids + oldest, statuses + oldest,
    1761           0 :                                    stoptimes + oldest,
    1762           0 :                                    tests + oldest, i - oldest);
    1763           0 :                     oldest = i;
    1764             :                 }
    1765           0 :                 pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
    1766           0 :                 INSTR_TIME_SET_CURRENT(starttimes[i]);
    1767             :             }
    1768           0 :             wait_for_tests(pids + oldest, statuses + oldest,
    1769           0 :                            stoptimes + oldest,
    1770           0 :                            tests + oldest, i - oldest);
    1771           0 :             note_end();
    1772             :         }
    1773             :         else
    1774             :         {
    1775         108 :             note_detail("parallel group (%d tests): ", num_tests);
    1776        1356 :             for (i = 0; i < num_tests; i++)
    1777             :             {
    1778        1248 :                 pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
    1779        1248 :                 INSTR_TIME_SET_CURRENT(starttimes[i]);
    1780             :             }
    1781         108 :             wait_for_tests(pids, statuses, stoptimes, tests, num_tests);
    1782         108 :             note_end();
    1783             :         }
    1784             : 
    1785             :         /* Check results for all tests */
    1786        2400 :         for (i = 0; i < num_tests; i++)
    1787             :         {
    1788             :             _stringlist *rl,
    1789             :                        *el,
    1790             :                        *tl;
    1791        1770 :             bool        differ = false;
    1792             : 
    1793        1770 :             INSTR_TIME_SUBTRACT(stoptimes[i], starttimes[i]);
    1794             : 
    1795             :             /*
    1796             :              * Advance over all three lists simultaneously.
    1797             :              *
    1798             :              * Compare resultfiles[j] with expectfiles[j] always. Tags are
    1799             :              * optional but if there are tags, the tag list has the same
    1800             :              * length as the other two lists.
    1801             :              */
    1802        4036 :             for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
    1803             :                  rl != NULL;    /* rl and el have the same length */
    1804        2266 :                  rl = rl->next, el = el->next,
    1805        2266 :                  tl = tl ? tl->next : NULL)
    1806             :             {
    1807             :                 bool        newdiff;
    1808             : 
    1809        2266 :                 if (postfunc)
    1810         744 :                     (*postfunc) (rl->str);
    1811        2266 :                 newdiff = results_differ(tests[i], rl->str, el->str);
    1812        2266 :                 if (newdiff && tl)
    1813             :                 {
    1814           0 :                     diag("tag: %s", tl->str);
    1815             :                 }
    1816        2266 :                 differ |= newdiff;
    1817             :             }
    1818             : 
    1819        1770 :             if (statuses[i] != 0)
    1820             :             {
    1821           0 :                 test_status_failed(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
    1822           0 :                 log_child_failure(statuses[i]);
    1823             :             }
    1824             :             else
    1825             :             {
    1826        1770 :                 if (differ)
    1827             :                 {
    1828           0 :                     test_status_failed(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
    1829             :                 }
    1830             :                 else
    1831             :                 {
    1832        1770 :                     test_status_ok(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
    1833             :                 }
    1834             :             }
    1835             :         }
    1836             : 
    1837        2400 :         for (i = 0; i < num_tests; i++)
    1838             :         {
    1839        1770 :             pg_free(tests[i]);
    1840        1770 :             tests[i] = NULL;
    1841        1770 :             free_stringlist(&resultfiles[i]);
    1842        1770 :             free_stringlist(&expectfiles[i]);
    1843        1770 :             free_stringlist(&tags[i]);
    1844             :         }
    1845             :     }
    1846             : 
    1847          12 :     fclose(scf);
    1848          12 : }
    1849             : 
    1850             : /*
    1851             :  * Run a single test
    1852             :  */
    1853             : static void
    1854         596 : run_single_test(const char *test, test_start_function startfunc,
    1855             :                 postprocess_result_function postfunc)
    1856             : {
    1857             :     PID_TYPE    pid;
    1858             :     instr_time  starttime;
    1859             :     instr_time  stoptime;
    1860             :     int         exit_status;
    1861         596 :     _stringlist *resultfiles = NULL;
    1862         596 :     _stringlist *expectfiles = NULL;
    1863         596 :     _stringlist *tags = NULL;
    1864             :     _stringlist *rl,
    1865             :                *el,
    1866             :                *tl;
    1867         596 :     bool        differ = false;
    1868             : 
    1869         596 :     pid = (startfunc) (test, &resultfiles, &expectfiles, &tags);
    1870         596 :     INSTR_TIME_SET_CURRENT(starttime);
    1871         596 :     wait_for_tests(&pid, &exit_status, &stoptime, NULL, 1);
    1872             : 
    1873             :     /*
    1874             :      * Advance over all three lists simultaneously.
    1875             :      *
    1876             :      * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
    1877             :      * but if there are tags, the tag list has the same length as the other
    1878             :      * two lists.
    1879             :      */
    1880        1204 :     for (rl = resultfiles, el = expectfiles, tl = tags;
    1881             :          rl != NULL;            /* rl and el have the same length */
    1882         608 :          rl = rl->next, el = el->next,
    1883         608 :          tl = tl ? tl->next : NULL)
    1884             :     {
    1885             :         bool        newdiff;
    1886             : 
    1887         608 :         if (postfunc)
    1888          18 :             (*postfunc) (rl->str);
    1889         608 :         newdiff = results_differ(test, rl->str, el->str);
    1890         608 :         if (newdiff && tl)
    1891             :         {
    1892           0 :             diag("tag: %s", tl->str);
    1893             :         }
    1894         608 :         differ |= newdiff;
    1895             :     }
    1896             : 
    1897         596 :     INSTR_TIME_SUBTRACT(stoptime, starttime);
    1898             : 
    1899         596 :     if (exit_status != 0)
    1900             :     {
    1901           0 :         test_status_failed(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
    1902           0 :         log_child_failure(exit_status);
    1903             :     }
    1904             :     else
    1905             :     {
    1906         596 :         if (differ)
    1907             :         {
    1908           0 :             test_status_failed(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
    1909             :         }
    1910             :         else
    1911             :         {
    1912         596 :             test_status_ok(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
    1913             :         }
    1914             :     }
    1915         596 : }
    1916             : 
    1917             : /*
    1918             :  * Create the summary-output files (making them empty if already existing)
    1919             :  */
    1920             : static void
    1921         166 : open_result_files(void)
    1922             : {
    1923             :     char        file[MAXPGPATH];
    1924             :     FILE       *difffile;
    1925             : 
    1926             :     /* create outputdir directory if not present */
    1927         166 :     if (!directory_exists(outputdir))
    1928          12 :         make_directory(outputdir);
    1929             : 
    1930             :     /* create the log file (copy of running status output) */
    1931         166 :     snprintf(file, sizeof(file), "%s/regression.out", outputdir);
    1932         166 :     logfilename = pg_strdup(file);
    1933         166 :     logfile = fopen(logfilename, "w");
    1934         166 :     if (!logfile)
    1935             :     {
    1936           0 :         bail("could not open file \"%s\" for writing: %s",
    1937             :              logfilename, strerror(errno));
    1938             :     }
    1939             : 
    1940             :     /* create the diffs file as empty */
    1941         166 :     snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
    1942         166 :     difffilename = pg_strdup(file);
    1943         166 :     difffile = fopen(difffilename, "w");
    1944         166 :     if (!difffile)
    1945             :     {
    1946           0 :         bail("could not open file \"%s\" for writing: %s",
    1947             :              difffilename, strerror(errno));
    1948             :     }
    1949             :     /* we don't keep the diffs file open continuously */
    1950         166 :     fclose(difffile);
    1951             : 
    1952             :     /* also create the results directory if not present */
    1953         166 :     snprintf(file, sizeof(file), "%s/results", outputdir);
    1954         166 :     if (!directory_exists(file))
    1955         164 :         make_directory(file);
    1956         166 : }
    1957             : 
    1958             : static void
    1959           4 : drop_database_if_exists(const char *dbname)
    1960             : {
    1961           4 :     StringInfo  buf = psql_start_command();
    1962             : 
    1963             :     /* Set warning level so we don't see chatter about nonexistent DB */
    1964           4 :     psql_add_command(buf, "SET client_min_messages = warning");
    1965           4 :     psql_add_command(buf, "DROP DATABASE IF EXISTS \"%s\"", dbname);
    1966           4 :     psql_end_command(buf, "postgres");
    1967           4 : }
    1968             : 
    1969             : static void
    1970         170 : create_database(const char *dbname)
    1971             : {
    1972         170 :     StringInfo  buf = psql_start_command();
    1973             :     _stringlist *sl;
    1974             : 
    1975             :     /*
    1976             :      * We use template0 so that any installation-local cruft in template1 will
    1977             :      * not mess up the tests.
    1978             :      */
    1979         170 :     if (encoding)
    1980           2 :         psql_add_command(buf, "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
    1981           2 :                          (nolocale) ? " LOCALE='C'" : "");
    1982             :     else
    1983         168 :         psql_add_command(buf, "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
    1984         168 :                          (nolocale) ? " LOCALE='C'" : "");
    1985         170 :     psql_add_command(buf,
    1986             :                      "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
    1987             :                      "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
    1988             :                      "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
    1989             :                      "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
    1990             :                      "ALTER DATABASE \"%s\" SET bytea_output TO 'hex';"
    1991             :                      "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
    1992             :                      dbname, dbname, dbname, dbname, dbname, dbname);
    1993         170 :     psql_end_command(buf, "postgres");
    1994             : 
    1995             :     /*
    1996             :      * Install any requested extensions.  We use CREATE IF NOT EXISTS so that
    1997             :      * this will work whether or not the extension is preinstalled.
    1998             :      */
    1999         180 :     for (sl = loadextension; sl != NULL; sl = sl->next)
    2000          10 :         psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
    2001         170 : }
    2002             : 
    2003             : static void
    2004           0 : drop_role_if_exists(const char *rolename)
    2005             : {
    2006           0 :     StringInfo  buf = psql_start_command();
    2007             : 
    2008             :     /* Set warning level so we don't see chatter about nonexistent role */
    2009           0 :     psql_add_command(buf, "SET client_min_messages = warning");
    2010           0 :     psql_add_command(buf, "DROP ROLE IF EXISTS \"%s\"", rolename);
    2011           0 :     psql_end_command(buf, "postgres");
    2012           0 : }
    2013             : 
    2014             : static void
    2015           8 : create_role(const char *rolename, const _stringlist *granted_dbs)
    2016             : {
    2017           8 :     StringInfo  buf = psql_start_command();
    2018             : 
    2019           8 :     psql_add_command(buf, "CREATE ROLE \"%s\" WITH LOGIN", rolename);
    2020          24 :     for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
    2021             :     {
    2022          16 :         psql_add_command(buf, "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
    2023             :                          granted_dbs->str, rolename);
    2024             :     }
    2025           8 :     psql_end_command(buf, "postgres");
    2026           8 : }
    2027             : 
    2028             : static void
    2029           0 : help(void)
    2030             : {
    2031           0 :     printf(_("PostgreSQL regression test driver\n"));
    2032           0 :     printf(_("\n"));
    2033           0 :     printf(_("Usage:\n  %s [OPTION]... [EXTRA-TEST]...\n"), progname);
    2034           0 :     printf(_("\n"));
    2035           0 :     printf(_("Options:\n"));
    2036           0 :     printf(_("      --bindir=BINPATH          use BINPATH for programs that are run;\n"));
    2037           0 :     printf(_("                                if empty, use PATH from the environment\n"));
    2038           0 :     printf(_("      --config-auth=DATADIR     update authentication settings for DATADIR\n"));
    2039           0 :     printf(_("      --create-role=ROLE        create the specified role before testing\n"));
    2040           0 :     printf(_("      --dbname=DB               use database DB (default \"regression\")\n"));
    2041           0 :     printf(_("      --debug                   turn on debug mode in programs that are run\n"));
    2042           0 :     printf(_("      --dlpath=DIR              look for dynamic libraries in DIR\n"));
    2043           0 :     printf(_("      --encoding=ENCODING       use ENCODING as the encoding\n"));
    2044           0 :     printf(_("      --expecteddir=DIR         take expected files from DIR (default \".\")\n"));
    2045           0 :     printf(_("  -h, --help                    show this help, then exit\n"));
    2046           0 :     printf(_("      --inputdir=DIR            take input files from DIR (default \".\")\n"));
    2047           0 :     printf(_("      --launcher=CMD            use CMD as launcher of psql\n"));
    2048           0 :     printf(_("      --load-extension=EXT      load the named extension before running the\n"));
    2049           0 :     printf(_("                                tests; can appear multiple times\n"));
    2050           0 :     printf(_("      --max-connections=N       maximum number of concurrent connections\n"));
    2051           0 :     printf(_("                                (default is 0, meaning unlimited)\n"));
    2052           0 :     printf(_("      --max-concurrent-tests=N  maximum number of concurrent tests in schedule\n"));
    2053           0 :     printf(_("                                (default is 0, meaning unlimited)\n"));
    2054           0 :     printf(_("      --outputdir=DIR           place output files in DIR (default \".\")\n"));
    2055           0 :     printf(_("      --schedule=FILE           use test ordering schedule from FILE\n"));
    2056           0 :     printf(_("                                (can be used multiple times to concatenate)\n"));
    2057           0 :     printf(_("      --temp-instance=DIR       create a temporary instance in DIR\n"));
    2058           0 :     printf(_("      --use-existing            use an existing installation\n"));
    2059           0 :     printf(_("  -V, --version                 output version information, then exit\n"));
    2060           0 :     printf(_("\n"));
    2061           0 :     printf(_("Options for \"temp-instance\" mode:\n"));
    2062           0 :     printf(_("      --no-locale               use C locale\n"));
    2063           0 :     printf(_("      --port=PORT               start postmaster on PORT\n"));
    2064           0 :     printf(_("      --temp-config=FILE        append contents of FILE to temporary config\n"));
    2065           0 :     printf(_("\n"));
    2066           0 :     printf(_("Options for using an existing installation:\n"));
    2067           0 :     printf(_("      --host=HOST               use postmaster running on HOST\n"));
    2068           0 :     printf(_("      --port=PORT               use postmaster running at PORT\n"));
    2069           0 :     printf(_("      --user=USER               connect as USER\n"));
    2070           0 :     printf(_("\n"));
    2071           0 :     printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
    2072           0 :     printf(_("if the tests could not be run for some reason.\n"));
    2073           0 :     printf(_("\n"));
    2074           0 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    2075           0 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    2076           0 : }
    2077             : 
    2078             : int
    2079         628 : regression_main(int argc, char *argv[],
    2080             :                 init_function ifunc,
    2081             :                 test_start_function startfunc,
    2082             :                 postprocess_result_function postfunc)
    2083             : {
    2084             :     static struct option long_options[] = {
    2085             :         {"help", no_argument, NULL, 'h'},
    2086             :         {"version", no_argument, NULL, 'V'},
    2087             :         {"dbname", required_argument, NULL, 1},
    2088             :         {"debug", no_argument, NULL, 2},
    2089             :         {"inputdir", required_argument, NULL, 3},
    2090             :         {"max-connections", required_argument, NULL, 5},
    2091             :         {"encoding", required_argument, NULL, 6},
    2092             :         {"outputdir", required_argument, NULL, 7},
    2093             :         {"schedule", required_argument, NULL, 8},
    2094             :         {"temp-instance", required_argument, NULL, 9},
    2095             :         {"no-locale", no_argument, NULL, 10},
    2096             :         {"host", required_argument, NULL, 13},
    2097             :         {"port", required_argument, NULL, 14},
    2098             :         {"user", required_argument, NULL, 15},
    2099             :         {"bindir", required_argument, NULL, 16},
    2100             :         {"dlpath", required_argument, NULL, 17},
    2101             :         {"create-role", required_argument, NULL, 18},
    2102             :         {"temp-config", required_argument, NULL, 19},
    2103             :         {"use-existing", no_argument, NULL, 20},
    2104             :         {"launcher", required_argument, NULL, 21},
    2105             :         {"load-extension", required_argument, NULL, 22},
    2106             :         {"config-auth", required_argument, NULL, 24},
    2107             :         {"max-concurrent-tests", required_argument, NULL, 25},
    2108             :         {"expecteddir", required_argument, NULL, 26},
    2109             :         {NULL, 0, NULL, 0}
    2110             :     };
    2111             : 
    2112             :     bool        use_unix_sockets;
    2113             :     _stringlist *sl;
    2114             :     int         c;
    2115             :     int         i;
    2116             :     int         option_index;
    2117             :     char        buf[MAXPGPATH * 4];
    2118             : 
    2119         628 :     pg_logging_init(argv[0]);
    2120         628 :     progname = get_progname(argv[0]);
    2121         628 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
    2122             : 
    2123         628 :     get_restricted_token();
    2124             : 
    2125         628 :     atexit(stop_postmaster);
    2126             : 
    2127             : #if defined(WIN32)
    2128             : 
    2129             :     /*
    2130             :      * We don't use Unix-domain sockets on Windows by default (see comment at
    2131             :      * remove_temp() for a reason).  Override at your own risk.
    2132             :      */
    2133             :     use_unix_sockets = getenv("PG_TEST_USE_UNIX_SOCKETS") ? true : false;
    2134             : #else
    2135         628 :     use_unix_sockets = true;
    2136             : #endif
    2137             : 
    2138         628 :     if (!use_unix_sockets)
    2139           0 :         hostname = "localhost";
    2140             : 
    2141             :     /*
    2142             :      * We call the initialization function here because that way we can set
    2143             :      * default parameters and let them be overwritten by the commandline.
    2144             :      */
    2145         628 :     ifunc(argc, argv);
    2146             : 
    2147         628 :     if (getenv("PG_REGRESS_DIFF_OPTS"))
    2148           0 :         pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS");
    2149             : 
    2150        1876 :     while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
    2151             :     {
    2152        1248 :         switch (c)
    2153             :         {
    2154           0 :             case 'h':
    2155           0 :                 help();
    2156           0 :                 exit(0);
    2157           0 :             case 'V':
    2158           0 :                 puts("pg_regress (PostgreSQL) " PG_VERSION);
    2159           0 :                 exit(0);
    2160         158 :             case 1:
    2161             : 
    2162             :                 /*
    2163             :                  * If a default database was specified, we need to remove it
    2164             :                  * before we add the specified one.
    2165             :                  */
    2166         158 :                 free_stringlist(&dblist);
    2167         158 :                 split_to_stringlist(optarg, ",", &dblist);
    2168         158 :                 break;
    2169           0 :             case 2:
    2170           0 :                 debug = true;
    2171           0 :                 break;
    2172         162 :             case 3:
    2173         162 :                 inputdir = pg_strdup(optarg);
    2174         162 :                 break;
    2175           0 :             case 5:
    2176           0 :                 max_connections = atoi(optarg);
    2177           0 :                 break;
    2178           2 :             case 6:
    2179           2 :                 encoding = pg_strdup(optarg);
    2180           2 :                 break;
    2181          16 :             case 7:
    2182          16 :                 outputdir = pg_strdup(optarg);
    2183          16 :                 break;
    2184          12 :             case 8:
    2185          12 :                 add_stringlist_item(&schedulelist, optarg);
    2186          12 :                 break;
    2187         162 :             case 9:
    2188         162 :                 temp_instance = make_absolute_path(optarg);
    2189         162 :                 break;
    2190           4 :             case 10:
    2191           4 :                 nolocale = true;
    2192           4 :                 break;
    2193           6 :             case 13:
    2194           6 :                 hostname = pg_strdup(optarg);
    2195           6 :                 break;
    2196           4 :             case 14:
    2197           4 :                 port = atoi(optarg);
    2198           4 :                 port_specified_by_user = true;
    2199           4 :                 break;
    2200           6 :             case 15:
    2201           6 :                 user = pg_strdup(optarg);
    2202           6 :                 break;
    2203         166 :             case 16:
    2204             :                 /* "--bindir=" means to use PATH */
    2205         166 :                 if (strlen(optarg))
    2206           0 :                     bindir = pg_strdup(optarg);
    2207             :                 else
    2208         166 :                     bindir = NULL;
    2209         166 :                 break;
    2210           8 :             case 17:
    2211           8 :                 dlpath = pg_strdup(optarg);
    2212           8 :                 break;
    2213          44 :             case 18:
    2214          44 :                 split_to_stringlist(optarg, ",", &extraroles);
    2215          44 :                 break;
    2216          16 :             case 19:
    2217          16 :                 add_stringlist_item(&temp_configs, optarg);
    2218          16 :                 break;
    2219           0 :             case 20:
    2220           0 :                 use_existing = true;
    2221           0 :                 break;
    2222           0 :             case 21:
    2223           0 :                 launcher = pg_strdup(optarg);
    2224           0 :                 break;
    2225          10 :             case 22:
    2226          10 :                 add_stringlist_item(&loadextension, optarg);
    2227          10 :                 break;
    2228         462 :             case 24:
    2229         462 :                 config_auth_datadir = pg_strdup(optarg);
    2230         462 :                 break;
    2231           6 :             case 25:
    2232           6 :                 max_concurrent_tests = atoi(optarg);
    2233           6 :                 break;
    2234           4 :             case 26:
    2235           4 :                 expecteddir = pg_strdup(optarg);
    2236           4 :                 break;
    2237           0 :             default:
    2238             :                 /* getopt_long already emitted a complaint */
    2239           0 :                 pg_log_error_hint("Try \"%s --help\" for more information.",
    2240             :                                   progname);
    2241           0 :                 exit(2);
    2242             :         }
    2243             :     }
    2244             : 
    2245             :     /*
    2246             :      * if we still have arguments, they are extra tests to run
    2247             :      */
    2248        1224 :     while (argc - optind >= 1)
    2249             :     {
    2250         596 :         add_stringlist_item(&extra_tests, argv[optind]);
    2251         596 :         optind++;
    2252             :     }
    2253             : 
    2254             :     /*
    2255             :      * We must have a database to run the tests in; either a default name, or
    2256             :      * one supplied by the --dbname switch.
    2257             :      */
    2258         628 :     if (!(dblist && dblist->str && dblist->str[0]))
    2259             :     {
    2260           0 :         bail("no database name was specified");
    2261             :     }
    2262             : 
    2263         628 :     if (config_auth_datadir)
    2264             :     {
    2265             : #ifdef ENABLE_SSPI
    2266             :         if (!use_unix_sockets)
    2267             :             config_sspi_auth(config_auth_datadir, user);
    2268             : #endif
    2269         462 :         exit(0);
    2270             :     }
    2271             : 
    2272         166 :     if (temp_instance && !port_specified_by_user)
    2273             : 
    2274             :         /*
    2275             :          * To reduce chances of interference with parallel installations, use
    2276             :          * a port number starting in the private range (49152-65535)
    2277             :          * calculated from the version number.  This aids non-Unix socket mode
    2278             :          * systems; elsewhere, the use of a private socket directory already
    2279             :          * prevents interference.
    2280             :          */
    2281         162 :         port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
    2282             : 
    2283         166 :     inputdir = make_absolute_path(inputdir);
    2284         166 :     outputdir = make_absolute_path(outputdir);
    2285         166 :     expecteddir = make_absolute_path(expecteddir);
    2286         166 :     dlpath = make_absolute_path(dlpath);
    2287             : 
    2288             :     /*
    2289             :      * Initialization
    2290             :      */
    2291         166 :     open_result_files();
    2292             : 
    2293         166 :     initialize_environment();
    2294             : 
    2295             : #if defined(HAVE_GETRLIMIT)
    2296         166 :     unlimit_core_size();
    2297             : #endif
    2298             : 
    2299         166 :     if (temp_instance)
    2300             :     {
    2301             :         StringInfoData cmd;
    2302             :         FILE       *pg_conf;
    2303             :         const char *env_wait;
    2304             :         int         wait_seconds;
    2305             :         const char *initdb_template_dir;
    2306             :         const char *keywords[4];
    2307             :         const char *values[4];
    2308             :         PGPing      rv;
    2309             : 
    2310             :         /*
    2311             :          * Prepare the temp instance
    2312             :          */
    2313             : 
    2314         162 :         if (directory_exists(temp_instance))
    2315             :         {
    2316           0 :             if (!rmtree(temp_instance, true))
    2317             :             {
    2318           0 :                 bail("could not remove temp instance \"%s\"", temp_instance);
    2319             :             }
    2320             :         }
    2321             : 
    2322             :         /* make the temp instance top directory */
    2323         162 :         make_directory(temp_instance);
    2324             : 
    2325             :         /* and a directory for log files */
    2326         162 :         snprintf(buf, sizeof(buf), "%s/log", outputdir);
    2327         162 :         if (!directory_exists(buf))
    2328         160 :             make_directory(buf);
    2329             : 
    2330         162 :         initStringInfo(&cmd);
    2331             : 
    2332             :         /*
    2333             :          * Create data directory.
    2334             :          *
    2335             :          * If available, use a previously initdb'd cluster as a template by
    2336             :          * copying it. For a lot of tests, that's substantially cheaper.
    2337             :          *
    2338             :          * There's very similar code in Cluster.pm, but we can't easily de
    2339             :          * duplicate it until we require perl at build time.
    2340             :          */
    2341         162 :         initdb_template_dir = getenv("INITDB_TEMPLATE");
    2342         162 :         if (initdb_template_dir == NULL || nolocale || debug)
    2343             :         {
    2344           4 :             note("initializing database system by running initdb");
    2345             : 
    2346           8 :             appendStringInfo(&cmd,
    2347             :                              "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync",
    2348           4 :                              bindir ? bindir : "",
    2349           4 :                              bindir ? "/" : "",
    2350             :                              temp_instance);
    2351           4 :             if (debug)
    2352           0 :                 appendStringInfoString(&cmd, " --debug");
    2353           4 :             if (nolocale)
    2354           4 :                 appendStringInfoString(&cmd, " --no-locale");
    2355           4 :             appendStringInfo(&cmd, " > \"%s/log/initdb.log\" 2>&1", outputdir);
    2356           4 :             fflush(NULL);
    2357           4 :             if (system(cmd.data))
    2358             :             {
    2359           0 :                 bail("initdb failed\n"
    2360             :                      "# Examine \"%s/log/initdb.log\" for the reason.\n"
    2361             :                      "# Command was: %s",
    2362             :                      outputdir, cmd.data);
    2363             :             }
    2364             :         }
    2365             :         else
    2366             :         {
    2367             : #ifndef WIN32
    2368         158 :             const char *copycmd = "cp -RPp \"%s\" \"%s/data\"";
    2369         158 :             int         expected_exitcode = 0;
    2370             : #else
    2371             :             const char *copycmd = "robocopy /E /NJS /NJH /NFL /NDL /NP \"%s\" \"%s/data\"";
    2372             :             int         expected_exitcode = 1;  /* 1 denotes files were copied */
    2373             : #endif
    2374             : 
    2375         158 :             note("initializing database system by copying initdb template");
    2376             : 
    2377         158 :             appendStringInfo(&cmd,
    2378             :                              copycmd,
    2379             :                              initdb_template_dir,
    2380             :                              temp_instance);
    2381         158 :             appendStringInfo(&cmd, " > \"%s/log/initdb.log\" 2>&1", outputdir);
    2382         158 :             fflush(NULL);
    2383         158 :             if (system(cmd.data) != expected_exitcode)
    2384             :             {
    2385           0 :                 bail("copying of initdb template failed\n"
    2386             :                      "# Examine \"%s/log/initdb.log\" for the reason.\n"
    2387             :                      "# Command was: %s",
    2388             :                      outputdir, cmd.data);
    2389             :             }
    2390             :         }
    2391             : 
    2392         162 :         pfree(cmd.data);
    2393             : 
    2394             :         /*
    2395             :          * Adjust the default postgresql.conf for regression testing. The user
    2396             :          * can specify a file to be appended; in any case we expand logging
    2397             :          * and set max_prepared_transactions to enable testing of prepared
    2398             :          * xacts.  (Note: to reduce the probability of unexpected shmmax
    2399             :          * failures, don't set max_prepared_transactions any higher than
    2400             :          * actually needed by the prepared_xacts regression test.)
    2401             :          */
    2402         162 :         snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance);
    2403         162 :         pg_conf = fopen(buf, "a");
    2404         162 :         if (pg_conf == NULL)
    2405             :         {
    2406           0 :             bail("could not open \"%s\" for adding extra config: %s",
    2407             :                  buf, strerror(errno));
    2408             :         }
    2409         162 :         fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
    2410         162 :         fputs("log_autovacuum_min_duration = 0\n", pg_conf);
    2411         162 :         fputs("log_checkpoints = on\n", pg_conf);
    2412         162 :         fputs("log_line_prefix = '%m %b[%p] %q%a '\n", pg_conf);
    2413         162 :         fputs("log_lock_waits = on\n", pg_conf);
    2414         162 :         fputs("log_temp_files = 128kB\n", pg_conf);
    2415         162 :         fputs("max_prepared_transactions = 2\n", pg_conf);
    2416             : 
    2417         178 :         for (sl = temp_configs; sl != NULL; sl = sl->next)
    2418             :         {
    2419          16 :             char       *temp_config = sl->str;
    2420             :             FILE       *extra_conf;
    2421             :             char        line_buf[1024];
    2422             : 
    2423          16 :             extra_conf = fopen(temp_config, "r");
    2424          16 :             if (extra_conf == NULL)
    2425             :             {
    2426           0 :                 bail("could not open \"%s\" to read extra config: %s",
    2427             :                      temp_config, strerror(errno));
    2428             :             }
    2429          54 :             while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
    2430          38 :                 fputs(line_buf, pg_conf);
    2431          16 :             fclose(extra_conf);
    2432             :         }
    2433             : 
    2434         162 :         fclose(pg_conf);
    2435             : 
    2436             : #ifdef ENABLE_SSPI
    2437             :         if (!use_unix_sockets)
    2438             :         {
    2439             :             /*
    2440             :              * Since we successfully used the same buffer for the much-longer
    2441             :              * "initdb" command, this can't truncate.
    2442             :              */
    2443             :             snprintf(buf, sizeof(buf), "%s/data", temp_instance);
    2444             :             config_sspi_auth(buf, NULL);
    2445             :         }
    2446             : #endif
    2447             : 
    2448             :         /*
    2449             :          * Prepare the connection params for checking the state of the server
    2450             :          * before starting the tests.
    2451             :          */
    2452         162 :         sprintf(portstr, "%d", port);
    2453         162 :         keywords[0] = "dbname";
    2454         162 :         values[0] = "postgres";
    2455         162 :         keywords[1] = "port";
    2456         162 :         values[1] = portstr;
    2457         162 :         keywords[2] = "host";
    2458         162 :         values[2] = hostname ? hostname : sockdir;
    2459         162 :         keywords[3] = NULL;
    2460         162 :         values[3] = NULL;
    2461             : 
    2462             :         /*
    2463             :          * Check if there is a postmaster running already.
    2464             :          */
    2465         162 :         for (i = 0; i < 16; i++)
    2466             :         {
    2467         162 :             rv = PQpingParams(keywords, values, 1);
    2468             : 
    2469         162 :             if (rv == PQPING_OK)
    2470             :             {
    2471           0 :                 if (port_specified_by_user || i == 15)
    2472             :                 {
    2473           0 :                     note("port %d apparently in use", port);
    2474           0 :                     if (!port_specified_by_user)
    2475           0 :                         note("could not determine an available port");
    2476           0 :                     bail("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.");
    2477             :                 }
    2478             : 
    2479           0 :                 note("port %d apparently in use, trying %d", port, port + 1);
    2480           0 :                 port++;
    2481           0 :                 sprintf(portstr, "%d", port);
    2482           0 :                 setenv("PGPORT", portstr, 1);
    2483             :             }
    2484             :             else
    2485         162 :                 break;
    2486             :         }
    2487             : 
    2488             :         /*
    2489             :          * Start the temp postmaster
    2490             :          */
    2491         810 :         snprintf(buf, sizeof(buf),
    2492             :                  "\"%s%spostgres\" -D \"%s/data\" -F%s "
    2493             :                  "-c \"listen_addresses=%s\" -k \"%s\" "
    2494             :                  "> \"%s/log/postmaster.log\" 2>&1",
    2495         162 :                  bindir ? bindir : "",
    2496         162 :                  bindir ? "/" : "",
    2497         162 :                  temp_instance, debug ? " -d 5" : "",
    2498         324 :                  hostname ? hostname : "", sockdir ? sockdir : "",
    2499             :                  outputdir);
    2500         162 :         postmaster_pid = spawn_process(buf);
    2501         162 :         if (postmaster_pid == INVALID_PID)
    2502           0 :             bail("could not spawn postmaster: %s", strerror(errno));
    2503             : 
    2504             :         /*
    2505             :          * Wait till postmaster is able to accept connections; normally takes
    2506             :          * only a fraction of a second or so, but Cygwin is reportedly *much*
    2507             :          * slower, and test builds using Valgrind or similar tools might be
    2508             :          * too.  Hence, allow the default timeout of 60 seconds to be
    2509             :          * overridden from the PGCTLTIMEOUT environment variable.
    2510             :          */
    2511         162 :         env_wait = getenv("PGCTLTIMEOUT");
    2512         162 :         if (env_wait != NULL)
    2513             :         {
    2514           0 :             wait_seconds = atoi(env_wait);
    2515           0 :             if (wait_seconds <= 0)
    2516           0 :                 wait_seconds = 60;
    2517             :         }
    2518             :         else
    2519         162 :             wait_seconds = 60;
    2520             : 
    2521         422 :         for (i = 0; i < wait_seconds * WAIT_TICKS_PER_SECOND; i++)
    2522             :         {
    2523             :             /*
    2524             :              * It's fairly unlikely that the server is responding immediately
    2525             :              * so we start with sleeping before checking instead of the other
    2526             :              * way around.
    2527             :              */
    2528         422 :             pg_usleep(1000000L / WAIT_TICKS_PER_SECOND);
    2529             : 
    2530         422 :             rv = PQpingParams(keywords, values, 1);
    2531             : 
    2532             :             /* Done if the server is running and accepts connections */
    2533         422 :             if (rv == PQPING_OK)
    2534         162 :                 break;
    2535             : 
    2536         260 :             if (rv == PQPING_NO_ATTEMPT)
    2537           0 :                 bail("attempting to connect to postmaster failed");
    2538             : 
    2539             :             /*
    2540             :              * Fail immediately if postmaster has exited
    2541             :              */
    2542             : #ifndef WIN32
    2543         260 :             if (waitpid(postmaster_pid, NULL, WNOHANG) == postmaster_pid)
    2544             : #else
    2545             :             if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
    2546             : #endif
    2547             :             {
    2548           0 :                 bail("postmaster failed, examine \"%s/log/postmaster.log\" for the reason",
    2549             :                      outputdir);
    2550             :             }
    2551             :         }
    2552         162 :         if (i >= wait_seconds * WAIT_TICKS_PER_SECOND)
    2553             :         {
    2554           0 :             diag("postmaster did not respond within %d seconds, examine \"%s/log/postmaster.log\" for the reason",
    2555             :                  wait_seconds, outputdir);
    2556             : 
    2557             :             /*
    2558             :              * If we get here, the postmaster is probably wedged somewhere in
    2559             :              * startup.  Try to kill it ungracefully rather than leaving a
    2560             :              * stuck postmaster that might interfere with subsequent test
    2561             :              * attempts.
    2562             :              */
    2563             : #ifndef WIN32
    2564           0 :             if (kill(postmaster_pid, SIGKILL) != 0 && errno != ESRCH)
    2565           0 :                 bail("could not kill failed postmaster: %s", strerror(errno));
    2566             : #else
    2567             :             if (TerminateProcess(postmaster_pid, 255) == 0)
    2568             :                 bail("could not kill failed postmaster: error code %lu",
    2569             :                      GetLastError());
    2570             : #endif
    2571           0 :             bail("postmaster failed");
    2572             :         }
    2573             : 
    2574         162 :         postmaster_running = true;
    2575             : 
    2576             : #ifdef _WIN64
    2577             : /* need a series of two casts to convert HANDLE without compiler warning */
    2578             : #define ULONGPID(x) (unsigned long) (unsigned long long) (x)
    2579             : #else
    2580             : #define ULONGPID(x) (unsigned long) (x)
    2581             : #endif
    2582         162 :         note("using temp instance on port %d with PID %lu",
    2583             :              port, ULONGPID(postmaster_pid));
    2584             :     }
    2585             :     else
    2586             :     {
    2587             :         /*
    2588             :          * Using an existing installation, so may need to get rid of
    2589             :          * pre-existing database(s) and role(s)
    2590             :          */
    2591           4 :         if (!use_existing)
    2592             :         {
    2593           8 :             for (sl = dblist; sl; sl = sl->next)
    2594           4 :                 drop_database_if_exists(sl->str);
    2595           4 :             for (sl = extraroles; sl; sl = sl->next)
    2596           0 :                 drop_role_if_exists(sl->str);
    2597             :         }
    2598             :     }
    2599             : 
    2600             :     /*
    2601             :      * Create the test database(s) and role(s)
    2602             :      */
    2603         166 :     if (!use_existing)
    2604             :     {
    2605         336 :         for (sl = dblist; sl; sl = sl->next)
    2606         170 :             create_database(sl->str);
    2607         174 :         for (sl = extraroles; sl; sl = sl->next)
    2608           8 :             create_role(sl->str, dblist);
    2609             :     }
    2610             : 
    2611             :     /*
    2612             :      * Ready to run the tests
    2613             :      */
    2614         178 :     for (sl = schedulelist; sl != NULL; sl = sl->next)
    2615             :     {
    2616          12 :         run_schedule(sl->str, startfunc, postfunc);
    2617             :     }
    2618             : 
    2619         762 :     for (sl = extra_tests; sl != NULL; sl = sl->next)
    2620             :     {
    2621         596 :         run_single_test(sl->str, startfunc, postfunc);
    2622             :     }
    2623             : 
    2624             :     /*
    2625             :      * Shut down temp installation's postmaster
    2626             :      */
    2627         166 :     if (temp_instance)
    2628             :     {
    2629         162 :         stop_postmaster();
    2630             :     }
    2631             : 
    2632             :     /*
    2633             :      * If there were no errors, remove the temp instance immediately to
    2634             :      * conserve disk space.  (If there were errors, we leave the instance in
    2635             :      * place for possible manual investigation.)
    2636             :      */
    2637         166 :     if (temp_instance && fail_count == 0)
    2638             :     {
    2639         162 :         if (!rmtree(temp_instance, true))
    2640           0 :             diag("could not remove temp instance \"%s\"",
    2641             :                  temp_instance);
    2642             :     }
    2643             : 
    2644             :     /*
    2645             :      * Emit a TAP compliant Plan
    2646             :      */
    2647         166 :     plan(fail_count + success_count);
    2648             : 
    2649             :     /*
    2650             :      * Emit nice-looking summary message
    2651             :      */
    2652         166 :     if (fail_count == 0)
    2653         166 :         note("All %d tests passed.", success_count);
    2654             :     else
    2655           0 :         diag("%d of %d tests failed.", fail_count, success_count + fail_count);
    2656             : 
    2657         166 :     if (file_size(difffilename) > 0)
    2658             :     {
    2659           0 :         diag("The differences that caused some tests to fail can be viewed in the file \"%s\".",
    2660             :              difffilename);
    2661           0 :         diag("A copy of the test summary that you see above is saved in the file \"%s\".",
    2662             :              logfilename);
    2663             :     }
    2664             :     else
    2665             :     {
    2666         166 :         unlink(difffilename);
    2667         166 :         unlink(logfilename);
    2668             :     }
    2669             : 
    2670         166 :     fclose(logfile);
    2671         166 :     logfile = NULL;
    2672             : 
    2673         166 :     if (fail_count != 0)
    2674           0 :         exit(1);
    2675             : 
    2676         166 :     return 0;
    2677             : }

Generated by: LCOV version 1.14