#include "postgres_fe.h"
#include <unistd.h>
Go to the source code of this file.
Data Structures | |
struct | _stringlist |
Defines | |
#define | PID_TYPE pid_t |
#define | INVALID_PID (-1) |
Typedefs | |
typedef struct _stringlist | _stringlist |
typedef PID_TYPE(* | test_function )(const char *, _stringlist **, _stringlist **, _stringlist **) |
typedef void(* | init_function )(void) |
Functions | |
int | regression_main (int argc, char *argv[], init_function ifunc, test_function tfunc) |
void | add_stringlist_item (_stringlist **listhead, const char *str) |
PID_TYPE | spawn_process (const char *cmdline) |
void | replace_string (char *string, char *replace, char *replacement) |
bool | file_exists (const char *file) |
Variables | |
char * | bindir |
char * | libdir |
char * | datadir |
char * | host_platform |
_stringlist * | dblist |
bool | debug |
char * | inputdir |
char * | outputdir |
char * | launcher |
char * | psqldir |
const char * | basic_diff_opts |
const char * | pretty_diff_opts |
#define INVALID_PID (-1) |
Definition at line 16 of file pg_regress.h.
Referenced by ecpg_start_test(), isolation_start_test(), psql_start_test(), regression_main(), and wait_for_tests().
#define PID_TYPE pid_t |
Definition at line 15 of file pg_regress.h.
Referenced by ecpg_start_test(), isolation_start_test(), psql_start_test(), run_schedule(), run_single_test(), and wait_for_tests().
typedef struct _stringlist _stringlist |
typedef void(* init_function)(void) |
Definition at line 33 of file pg_regress.h.
typedef PID_TYPE(* test_function)(const char *, _stringlist **, _stringlist **, _stringlist **) |
Definition at line 29 of file pg_regress.h.
void add_stringlist_item | ( | _stringlist ** | listhead, | |
const char * | str | |||
) |
Definition at line 180 of file pg_regress.c.
References malloc, _stringlist::next, NULL, and _stringlist::str.
Referenced by ecpg_start_test(), isolation_init(), isolation_start_test(), psql_init(), psql_start_test(), regression_main(), run_schedule(), and split_to_stringlist().
{ _stringlist *newentry = malloc(sizeof(_stringlist)); _stringlist *oldentry; newentry->str = strdup(str); newentry->next = NULL; if (*listhead == NULL) *listhead = newentry; else { for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next) /* skip */ ; oldentry->next = newentry; } }
bool file_exists | ( | const char * | file | ) |
Definition at line 1122 of file pg_regress.c.
{ FILE *f = fopen(file, "r"); if (!f) return false; fclose(f); return true; }
int regression_main | ( | int | argc, | |
char * | argv[], | |||
init_function | ifunc, | |||
test_function | tfunc | |||
) |
Definition at line 1920 of file pg_regress.c.
References _, add_stringlist_item(), bindir, buf, create_database(), create_role(), datadir, debug, DEVNULL, difffilename, directory_exists(), dlpath, doputenv(), drop_database_if_exists(), drop_role_if_exists(), encoding, fail_count, fail_ignore_count, file_size(), free_stringlist(), get_progname(), getopt_long(), header(), help(), hostname, i, initialize_environment(), inputdir, INVALID_PID, launcher, logfile, logfilename, make_absolute_path(), make_directory(), makeprog, max_connections, MAXPGPATH, _stringlist::next, nolocale, NULL, open_result_files(), optarg, optind, outputdir, PG_TEXTDOMAIN, pg_usleep(), port, port_specified_by_user, postmaster_pid, postmaster_running, pretty_diff_opts, progname, psqldir, rmtree(), run_schedule(), run_single_test(), set_pglocale_pgservice(), SIGKILL, snprintf(), spawn_process(), split_to_stringlist(), stop_postmaster(), _stringlist::str, strerror(), success_count, system(), SYSTEMQUOTE, temp_config, temp_install, top_builddir, ULONGPID, unlink(), use_existing, and user.
Referenced by main().
{ static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'}, {"dbname", required_argument, NULL, 1}, {"debug", no_argument, NULL, 2}, {"inputdir", required_argument, NULL, 3}, {"load-language", required_argument, NULL, 4}, {"max-connections", required_argument, NULL, 5}, {"encoding", required_argument, NULL, 6}, {"outputdir", required_argument, NULL, 7}, {"schedule", required_argument, NULL, 8}, {"temp-install", required_argument, NULL, 9}, {"no-locale", no_argument, NULL, 10}, {"top-builddir", required_argument, NULL, 11}, {"host", required_argument, NULL, 13}, {"port", required_argument, NULL, 14}, {"user", required_argument, NULL, 15}, {"psqldir", required_argument, NULL, 16}, {"dlpath", required_argument, NULL, 17}, {"create-role", required_argument, NULL, 18}, {"temp-config", required_argument, NULL, 19}, {"use-existing", no_argument, NULL, 20}, {"launcher", required_argument, NULL, 21}, {"load-extension", required_argument, NULL, 22}, {"extra-install", required_argument, NULL, 23}, {NULL, 0, NULL, 0} }; _stringlist *sl; int c; int i; int option_index; char buf[MAXPGPATH * 4]; char buf2[MAXPGPATH * 4]; progname = get_progname(argv[0]); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress")); atexit(stop_postmaster); #ifndef HAVE_UNIX_SOCKETS /* no unix domain sockets available, so change default */ hostname = "localhost"; #endif /* * We call the initialization function here because that way we can set * default parameters and let them be overwritten by the commandline. */ ifunc(); if (getenv("PG_REGRESS_DIFF_OPTS")) pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS"); while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1) { switch (c) { case 'h': help(); exit(0); case 'V': puts("pg_regress (PostgreSQL) " PG_VERSION); exit(0); case 1: /* * If a default database was specified, we need to remove it * before we add the specified one. */ free_stringlist(&dblist); split_to_stringlist(strdup(optarg), ", ", &dblist); break; case 2: debug = true; break; case 3: inputdir = strdup(optarg); break; case 4: add_stringlist_item(&loadlanguage, optarg); break; case 5: max_connections = atoi(optarg); break; case 6: encoding = strdup(optarg); break; case 7: outputdir = strdup(optarg); break; case 8: add_stringlist_item(&schedulelist, optarg); break; case 9: temp_install = make_absolute_path(optarg); break; case 10: nolocale = true; break; case 11: top_builddir = strdup(optarg); break; case 13: hostname = strdup(optarg); break; case 14: port = atoi(optarg); port_specified_by_user = true; break; case 15: user = strdup(optarg); break; case 16: /* "--psqldir=" should mean to use PATH */ if (strlen(optarg)) psqldir = strdup(optarg); break; case 17: dlpath = strdup(optarg); break; case 18: split_to_stringlist(strdup(optarg), ", ", &extraroles); break; case 19: temp_config = strdup(optarg); break; case 20: use_existing = true; break; case 21: launcher = strdup(optarg); break; case 22: add_stringlist_item(&loadextension, optarg); break; case 23: add_stringlist_item(&extra_install, optarg); break; default: /* getopt_long already emitted a complaint */ fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"), progname); exit(2); } } /* * if we still have arguments, they are extra tests to run */ while (argc - optind >= 1) { add_stringlist_item(&extra_tests, argv[optind]); optind++; } if (temp_install && !port_specified_by_user) /* * To reduce chances of interference with parallel installations, use * a port number starting in the private range (49152-65535) * calculated from the version number. */ port = 0xC000 | (PG_VERSION_NUM & 0x3FFF); inputdir = make_absolute_path(inputdir); outputdir = make_absolute_path(outputdir); dlpath = make_absolute_path(dlpath); /* * Initialization */ open_result_files(); initialize_environment(); #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE) unlimit_core_size(); #endif if (temp_install) { FILE *pg_conf; _stringlist *sl; /* * Prepare the temp installation */ if (!top_builddir) { fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n")); exit(2); } if (directory_exists(temp_install)) { header(_("removing existing temp installation")); rmtree(temp_install, true); } header(_("creating temporary installation")); /* make the temp install top directory */ make_directory(temp_install); /* and a directory for log files */ snprintf(buf, sizeof(buf), "%s/log", outputdir); if (!directory_exists(buf)) make_directory(buf); /* "make install" */ #ifndef WIN32_ONLY_COMPILER snprintf(buf, sizeof(buf), SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE, makeprog, top_builddir, temp_install, outputdir); #else snprintf(buf, sizeof(buf), SYSTEMQUOTE "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE, top_builddir, temp_install, outputdir); #endif if (system(buf)) { fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf); exit(2); } for (sl = extra_install; sl != NULL; sl = sl->next) { #ifndef WIN32_ONLY_COMPILER snprintf(buf, sizeof(buf), SYSTEMQUOTE "\"%s\" -C \"%s/%s\" DESTDIR=\"%s/install\" install >> \"%s/log/install.log\" 2>&1" SYSTEMQUOTE, makeprog, top_builddir, sl->str, temp_install, outputdir); #else fprintf(stderr, _("\n%s: --extra-install option not supported on this platform\n"), progname); exit(2); #endif if (system(buf)) { fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf); exit(2); } } /* initdb */ header(_("initializing database system")); snprintf(buf, sizeof(buf), SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE, bindir, temp_install, datadir, debug ? " --debug" : "", nolocale ? " --no-locale" : "", outputdir); if (system(buf)) { fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf); exit(2); } /* * Adjust the default postgresql.conf as needed for regression * testing. The user can specify a file to be appended; in any case we * set max_prepared_transactions to enable testing of prepared xacts. * (Note: to reduce the probability of unexpected shmmax failures, * don't set max_prepared_transactions any higher than actually needed * by the prepared_xacts regression test.) */ snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install); pg_conf = fopen(buf, "a"); if (pg_conf == NULL) { fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno)); exit(2); } fputs("\n# Configuration added by pg_regress\n\n", pg_conf); fputs("max_prepared_transactions = 2\n", pg_conf); if (temp_config != NULL) { FILE *extra_conf; char line_buf[1024]; extra_conf = fopen(temp_config, "r"); if (extra_conf == NULL) { fprintf(stderr, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname, temp_config, strerror(errno)); exit(2); } while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL) fputs(line_buf, pg_conf); fclose(extra_conf); } fclose(pg_conf); /* * Check if there is a postmaster running already. */ snprintf(buf2, sizeof(buf2), SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE, bindir, DEVNULL, DEVNULL); for (i = 0; i < 16; i++) { if (system(buf2) == 0) { char s[16]; if (port_specified_by_user || i == 15) { fprintf(stderr, _("port %d apparently in use\n"), port); if (!port_specified_by_user) fprintf(stderr, _("%s: could not determine an available port\n"), progname); fprintf(stderr, _("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.\n")); exit(2); } fprintf(stderr, _("port %d apparently in use, trying %d\n"), port, port + 1); port++; sprintf(s, "%d", port); doputenv("PGPORT", s); } else break; } /* * Start the temp postmaster */ header(_("starting postmaster")); snprintf(buf, sizeof(buf), SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE, bindir, temp_install, debug ? " -d 5" : "", hostname ? hostname : "", outputdir); postmaster_pid = spawn_process(buf); if (postmaster_pid == INVALID_PID) { fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"), progname, strerror(errno)); exit(2); } /* * Wait till postmaster is able to accept connections (normally only a * second or so, but Cygwin is reportedly *much* slower). Don't wait * forever, however. */ for (i = 0; i < 60; i++) { /* Done if psql succeeds */ if (system(buf2) == 0) break; /* * Fail immediately if postmaster has exited */ #ifndef WIN32 if (kill(postmaster_pid, 0) != 0) #else if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0) #endif { fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir); exit(2); } pg_usleep(1000000L); } if (i >= 60) { fprintf(stderr, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir); /* * If we get here, the postmaster is probably wedged somewhere in * startup. Try to kill it ungracefully rather than leaving a * stuck postmaster that might interfere with subsequent test * attempts. */ #ifndef WIN32 if (kill(postmaster_pid, SIGKILL) != 0 && errno != ESRCH) fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"), progname, strerror(errno)); #else if (TerminateProcess(postmaster_pid, 255) == 0) fprintf(stderr, _("\n%s: could not kill failed postmaster: error code %lu\n"), progname, GetLastError()); #endif exit(2); } postmaster_running = true; #ifdef WIN64 /* need a series of two casts to convert HANDLE without compiler warning */ #define ULONGPID(x) (unsigned long) (unsigned long long) (x) #else #define ULONGPID(x) (unsigned long) (x) #endif printf(_("running on port %d with PID %lu\n"), port, ULONGPID(postmaster_pid)); } else { /* * Using an existing installation, so may need to get rid of * pre-existing database(s) and role(s) */ if (!use_existing) { for (sl = dblist; sl; sl = sl->next) drop_database_if_exists(sl->str); for (sl = extraroles; sl; sl = sl->next) drop_role_if_exists(sl->str); } } /* * Create the test database(s) and role(s) */ if (!use_existing) { for (sl = dblist; sl; sl = sl->next) create_database(sl->str); for (sl = extraroles; sl; sl = sl->next) create_role(sl->str, dblist); } /* * Ready to run the tests */ header(_("running regression test queries")); for (sl = schedulelist; sl != NULL; sl = sl->next) { run_schedule(sl->str, tfunc); } for (sl = extra_tests; sl != NULL; sl = sl->next) { run_single_test(sl->str, tfunc); } /* * Shut down temp installation's postmaster */ if (temp_install) { header(_("shutting down postmaster")); stop_postmaster(); } fclose(logfile); /* * Emit nice-looking summary message */ if (fail_count == 0 && fail_ignore_count == 0) snprintf(buf, sizeof(buf), _(" All %d tests passed. "), success_count); else if (fail_count == 0) /* fail_count=0, fail_ignore_count>0 */ snprintf(buf, sizeof(buf), _(" %d of %d tests passed, %d failed test(s) ignored. "), success_count, success_count + fail_ignore_count, fail_ignore_count); else if (fail_ignore_count == 0) /* fail_count>0 && fail_ignore_count=0 */ snprintf(buf, sizeof(buf), _(" %d of %d tests failed. "), fail_count, success_count + fail_count); else /* fail_count>0 && fail_ignore_count>0 */ snprintf(buf, sizeof(buf), _(" %d of %d tests failed, %d of these failures ignored. "), fail_count + fail_ignore_count, success_count + fail_count + fail_ignore_count, fail_ignore_count); putchar('\n'); for (i = strlen(buf); i > 0; i--) putchar('='); printf("\n%s\n", buf); for (i = strlen(buf); i > 0; i--) putchar('='); putchar('\n'); putchar('\n'); if (file_size(difffilename) > 0) { printf(_("The differences that caused some tests to fail can be viewed in the\n" "file \"%s\". A copy of the test summary that you see\n" "above is saved in the file \"%s\".\n\n"), difffilename, logfilename); } else { unlink(difffilename); unlink(logfilename); } if (fail_count != 0) exit(1); return 0; }
void replace_string | ( | char * | string, | |
char * | replace, | |||
char * | replacement | |||
) |
Definition at line 388 of file pg_regress.c.
References free, NULL, and strlcpy().
Referenced by convert_sourcefiles_in(), ecpg_filter(), and ecpg_start_test().
PID_TYPE spawn_process | ( | const char * | cmdline | ) |
Definition at line 934 of file pg_regress.c.
References _, BOOL(), free, logfile, malloc, NULL, progname, shellprog, strerror(), and TRUE.
Referenced by ecpg_start_test(), isolation_start_test(), psql_start_test(), and regression_main().
{ #ifndef WIN32 pid_t pid; /* * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here * ... does anyone still care about systems where that doesn't work? */ fflush(stdout); fflush(stderr); if (logfile) fflush(logfile); pid = fork(); if (pid == -1) { fprintf(stderr, _("%s: could not fork: %s\n"), progname, strerror(errno)); exit(2); } if (pid == 0) { /* * In child * * Instead of using system(), exec the shell directly, and tell it to * "exec" the command too. This saves two useless processes per * parallel test case. */ char *cmdline2 = malloc(strlen(cmdline) + 6); sprintf(cmdline2, "exec %s", cmdline); execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL); fprintf(stderr, _("%s: could not exec \"%s\": %s\n"), progname, shellprog, strerror(errno)); _exit(1); /* not exit() here... */ } /* in parent */ return pid; #else char *cmdline2; BOOL b; STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE origToken; HANDLE restrictedToken; SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; SID_AND_ATTRIBUTES dropSids[2]; __CreateRestrictedToken _CreateRestrictedToken = NULL; HANDLE Advapi32Handle; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); Advapi32Handle = LoadLibrary("ADVAPI32.DLL"); if (Advapi32Handle != NULL) { _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken"); } if (_CreateRestrictedToken == NULL) { if (Advapi32Handle != NULL) FreeLibrary(Advapi32Handle); fprintf(stderr, _("%s: cannot create restricted tokens on this platform\n"), progname); exit(2); } /* Open the current token to use as base for the restricted one */ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken)) { fprintf(stderr, _("could not open process token: error code %lu\n"), GetLastError()); exit(2); } /* Allocate list of SIDs to remove */ ZeroMemory(&dropSids, sizeof(dropSids)); if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) || !AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid)) { fprintf(stderr, _("could not allocate SIDs: error code %lu\n"), GetLastError()); exit(2); } b = _CreateRestrictedToken(origToken, DISABLE_MAX_PRIVILEGE, sizeof(dropSids) / sizeof(dropSids[0]), dropSids, 0, NULL, 0, NULL, &restrictedToken); FreeSid(dropSids[1].Sid); FreeSid(dropSids[0].Sid); CloseHandle(origToken); FreeLibrary(Advapi32Handle); if (!b) { fprintf(stderr, _("could not create restricted token: error code %lu\n"), GetLastError()); exit(2); } cmdline2 = malloc(strlen(cmdline) + 8); sprintf(cmdline2, "cmd /c %s", cmdline); #ifndef __CYGWIN__ AddUserToTokenDacl(restrictedToken); #endif if (!CreateProcessAsUser(restrictedToken, NULL, cmdline2, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { fprintf(stderr, _("could not start process for \"%s\": error code %lu\n"), cmdline2, GetLastError()); exit(2); } free(cmdline2); ResumeThread(pi.hThread); CloseHandle(pi.hThread); return pi.hProcess; #endif }
const char* basic_diff_opts |
Definition at line 74 of file pg_regress.c.
Referenced by results_differ().
char* bindir |
Definition at line 55 of file pg_regress.c.
Referenced by initialize_environment(), regression_main(), and stop_postmaster().
char* datadir |
Definition at line 57 of file pg_regress.c.
Referenced by fuzzy_open_file(), initialize_environment(), and regression_main().
Definition at line 82 of file pg_regress.c.
Referenced by do_start_worker(), get_database_list(), isolation_init(), isolation_start_test(), psql_init(), psql_start_test(), and rebuild_database_list().
bool debug |
Definition at line 38 of file pg_archivecleanup.c.
Referenced by bootstrap_template1(), CleanupPriorWALFiles(), CustomizableCleanupPriorWALFiles(), CustomizableNextWALFileReady(), main(), pg_regcomp(), regression_main(), RestoreWALFileForRecovery(), setup_collation(), setup_data_file_paths(), and slice_check().
char* host_platform |
Definition at line 58 of file pg_regress.c.
Referenced by load_resultmap().
char* inputdir |
Definition at line 84 of file pg_regress.c.
Referenced by convert_sourcefiles(), convert_sourcefiles_in(), ecpg_start_test(), isolation_start_test(), load_resultmap(), psql_start_test(), and regression_main().
char* launcher |
Definition at line 87 of file pg_regress.c.
Referenced by isolation_start_test(), psql_start_test(), and regression_main().
char* libdir |
Definition at line 56 of file pg_regress.c.
Referenced by initialize_environment().
char* outputdir |
Definition at line 85 of file pg_regress.c.
Referenced by convert_sourcefiles(), convert_sourcefiles_in(), ecpg_start_test(), isolation_start_test(), open_result_files(), psql_start_test(), and regression_main().
const char* pretty_diff_opts |
Definition at line 75 of file pg_regress.c.
Referenced by regression_main(), and results_differ().
char* psqldir |
Definition at line 86 of file pg_regress.c.
Referenced by initialize_environment(), psql_command(), psql_start_test(), and regression_main().