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

Generated by: LCOV version 1.14