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