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