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