00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pg_regress.h"
00020
00021 #include <ctype.h>
00022 #include <sys/stat.h>
00023 #include <sys/wait.h>
00024 #include <signal.h>
00025 #include <unistd.h>
00026
00027 #ifdef HAVE_SYS_RESOURCE_H
00028 #include <sys/time.h>
00029 #include <sys/resource.h>
00030 #endif
00031
00032 #include "getopt_long.h"
00033 #include "pg_config_paths.h"
00034
00035
00036 typedef struct _resultmap
00037 {
00038 char *test;
00039 char *type;
00040 char *resultfile;
00041 struct _resultmap *next;
00042 } _resultmap;
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 char *bindir = PGBINDIR;
00056 char *libdir = LIBDIR;
00057 char *datadir = PGSHAREDIR;
00058 char *host_platform = HOST_TUPLE;
00059
00060 #ifndef WIN32_ONLY_COMPILER
00061 static char *makeprog = MAKEPROG;
00062 #endif
00063
00064 #ifndef WIN32
00065 static char *shellprog = SHELLPROG;
00066 #endif
00067
00068
00069
00070
00071
00072
00073 #ifndef WIN32
00074 const char *basic_diff_opts = "";
00075 const char *pretty_diff_opts = "-C3";
00076 #else
00077 const char *basic_diff_opts = "-w";
00078 const char *pretty_diff_opts = "-w -C3";
00079 #endif
00080
00081
00082 _stringlist *dblist = NULL;
00083 bool debug = false;
00084 char *inputdir = ".";
00085 char *outputdir = ".";
00086 char *psqldir = PGBINDIR;
00087 char *launcher = NULL;
00088 static _stringlist *loadlanguage = NULL;
00089 static _stringlist *loadextension = NULL;
00090 static int max_connections = 0;
00091 static char *encoding = NULL;
00092 static _stringlist *schedulelist = NULL;
00093 static _stringlist *extra_tests = NULL;
00094 static char *temp_install = NULL;
00095 static char *temp_config = NULL;
00096 static char *top_builddir = NULL;
00097 static bool nolocale = false;
00098 static bool use_existing = false;
00099 static char *hostname = NULL;
00100 static int port = -1;
00101 static bool port_specified_by_user = false;
00102 static char *dlpath = PKGLIBDIR;
00103 static char *user = NULL;
00104 static _stringlist *extraroles = NULL;
00105 static _stringlist *extra_install = NULL;
00106
00107
00108 static const char *progname;
00109 static char *logfilename;
00110 static FILE *logfile;
00111 static char *difffilename;
00112
00113 static _resultmap *resultmap = NULL;
00114
00115 static PID_TYPE postmaster_pid = INVALID_PID;
00116 static bool postmaster_running = false;
00117
00118 static int success_count = 0;
00119 static int fail_count = 0;
00120 static int fail_ignore_count = 0;
00121
00122 static bool directory_exists(const char *dir);
00123 static void make_directory(const char *dir);
00124
00125 static void
00126 header(const char *fmt,...)
00127
00128
00129 __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
00130 static void
00131 status(const char *fmt,...)
00132
00133
00134 __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
00135 static void
00136 psql_command(const char *database, const char *query,...)
00137
00138
00139 __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
00140
00141 #ifdef WIN32
00142 typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
00143
00144
00145 #ifndef DISABLE_MAX_PRIVILEGE
00146 #define DISABLE_MAX_PRIVILEGE 0x1
00147 #endif
00148 #endif
00149
00150
00151
00152
00153 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
00154 static void
00155 unlimit_core_size(void)
00156 {
00157 struct rlimit lim;
00158
00159 getrlimit(RLIMIT_CORE, &lim);
00160 if (lim.rlim_max == 0)
00161 {
00162 fprintf(stderr,
00163 _("%s: could not set core size: disallowed by hard limit\n"),
00164 progname);
00165 return;
00166 }
00167 else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
00168 {
00169 lim.rlim_cur = lim.rlim_max;
00170 setrlimit(RLIMIT_CORE, &lim);
00171 }
00172 }
00173 #endif
00174
00175
00176
00177
00178
00179 void
00180 add_stringlist_item(_stringlist ** listhead, const char *str)
00181 {
00182 _stringlist *newentry = malloc(sizeof(_stringlist));
00183 _stringlist *oldentry;
00184
00185 newentry->str = strdup(str);
00186 newentry->next = NULL;
00187 if (*listhead == NULL)
00188 *listhead = newentry;
00189 else
00190 {
00191 for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
00192 ;
00193 oldentry->next = newentry;
00194 }
00195 }
00196
00197
00198
00199
00200 static void
00201 free_stringlist(_stringlist ** listhead)
00202 {
00203 if (listhead == NULL || *listhead == NULL)
00204 return;
00205 if ((*listhead)->next != NULL)
00206 free_stringlist(&((*listhead)->next));
00207 free((*listhead)->str);
00208 free(*listhead);
00209 *listhead = NULL;
00210 }
00211
00212
00213
00214
00215 static void
00216 split_to_stringlist(const char *s, const char *delim, _stringlist ** listhead)
00217 {
00218 char *sc = strdup(s);
00219 char *token = strtok(sc, delim);
00220
00221 while (token)
00222 {
00223 add_stringlist_item(listhead, token);
00224 token = strtok(NULL, delim);
00225 }
00226 free(sc);
00227 }
00228
00229
00230
00231
00232 static void
00233 header(const char *fmt,...)
00234 {
00235 char tmp[64];
00236 va_list ap;
00237
00238 va_start(ap, fmt);
00239 vsnprintf(tmp, sizeof(tmp), fmt, ap);
00240 va_end(ap);
00241
00242 fprintf(stdout, "============== %-38s ==============\n", tmp);
00243 fflush(stdout);
00244 }
00245
00246
00247
00248
00249 static void
00250 status(const char *fmt,...)
00251 {
00252 va_list ap;
00253
00254 va_start(ap, fmt);
00255 vfprintf(stdout, fmt, ap);
00256 fflush(stdout);
00257 va_end(ap);
00258
00259 if (logfile)
00260 {
00261 va_start(ap, fmt);
00262 vfprintf(logfile, fmt, ap);
00263 va_end(ap);
00264 }
00265 }
00266
00267
00268
00269
00270 static void
00271 status_end(void)
00272 {
00273 fprintf(stdout, "\n");
00274 fflush(stdout);
00275 if (logfile)
00276 fprintf(logfile, "\n");
00277 }
00278
00279
00280
00281
00282 static void
00283 stop_postmaster(void)
00284 {
00285 if (postmaster_running)
00286 {
00287
00288 char buf[MAXPGPATH * 2];
00289 int r;
00290
00291
00292 fflush(stdout);
00293 fflush(stderr);
00294
00295 snprintf(buf, sizeof(buf),
00296 SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE,
00297 bindir, temp_install);
00298 r = system(buf);
00299 if (r != 0)
00300 {
00301 fprintf(stderr, _("\n%s: could not stop postmaster: exit code was %d\n"),
00302 progname, r);
00303 _exit(2);
00304 }
00305
00306 postmaster_running = false;
00307 }
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 static bool
00323 string_matches_pattern(const char *str, const char *pattern)
00324 {
00325 while (*str && *pattern)
00326 {
00327 if (*pattern == '.' && pattern[1] == '*')
00328 {
00329 pattern += 2;
00330
00331 if (*pattern == '\0')
00332 return true;
00333
00334
00335
00336
00337
00338 while (*str)
00339 {
00340
00341
00342
00343
00344 if (*str == *pattern || *pattern == '.')
00345 {
00346 if (string_matches_pattern(str, pattern))
00347 return true;
00348 }
00349
00350 str++;
00351 }
00352
00353
00354
00355
00356 return false;
00357 }
00358 else if (*pattern != '.' && *str != *pattern)
00359 {
00360
00361
00362
00363
00364 return false;
00365 }
00366
00367 str++;
00368 pattern++;
00369 }
00370
00371 if (*pattern == '\0')
00372 return true;
00373
00374
00375 while (*pattern == '.' && pattern[1] == '*')
00376 pattern += 2;
00377 if (*pattern == '\0')
00378 return true;
00379
00380 return false;
00381 }
00382
00383
00384
00385
00386
00387 void
00388 replace_string(char *string, char *replace, char *replacement)
00389 {
00390 char *ptr;
00391
00392 while ((ptr = strstr(string, replace)) != NULL)
00393 {
00394 char *dup = strdup(string);
00395
00396 strlcpy(string, dup, ptr - string + 1);
00397 strcat(string, replacement);
00398 strcat(string, dup + (ptr - string) + strlen(replace));
00399 free(dup);
00400 }
00401 }
00402
00403
00404
00405
00406
00407
00408
00409 static void
00410 convert_sourcefiles_in(char *source_subdir, char *dest_dir, char *dest_subdir, char *suffix)
00411 {
00412 char testtablespace[MAXPGPATH];
00413 char indir[MAXPGPATH];
00414 struct stat st;
00415 int ret;
00416 char **name;
00417 char **names;
00418 int count = 0;
00419
00420 snprintf(indir, MAXPGPATH, "%s/%s", inputdir, source_subdir);
00421
00422
00423 ret = stat(indir, &st);
00424 if (ret != 0 || !S_ISDIR(st.st_mode))
00425 {
00426
00427
00428
00429
00430 return;
00431 }
00432
00433 names = pgfnames(indir);
00434 if (!names)
00435
00436 exit(2);
00437
00438 snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
00439
00440 #ifdef WIN32
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452 if (directory_exists(testtablespace))
00453 rmtree(testtablespace, true);
00454 make_directory(testtablespace);
00455 #endif
00456
00457
00458 for (name = names; *name; name++)
00459 {
00460 char srcfile[MAXPGPATH];
00461 char destfile[MAXPGPATH];
00462 char prefix[MAXPGPATH];
00463 FILE *infile,
00464 *outfile;
00465 char line[1024];
00466
00467
00468 if (strlen(*name) < 8)
00469 continue;
00470 if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
00471 continue;
00472
00473 count++;
00474
00475
00476 snprintf(prefix, strlen(*name) - 6, "%s", *name);
00477 snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
00478 snprintf(destfile, MAXPGPATH, "%s/%s/%s.%s", dest_dir, dest_subdir,
00479 prefix, suffix);
00480
00481 infile = fopen(srcfile, "r");
00482 if (!infile)
00483 {
00484 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
00485 progname, srcfile, strerror(errno));
00486 exit(2);
00487 }
00488 outfile = fopen(destfile, "w");
00489 if (!outfile)
00490 {
00491 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
00492 progname, destfile, strerror(errno));
00493 exit(2);
00494 }
00495 while (fgets(line, sizeof(line), infile))
00496 {
00497 replace_string(line, "@abs_srcdir@", inputdir);
00498 replace_string(line, "@abs_builddir@", outputdir);
00499 replace_string(line, "@testtablespace@", testtablespace);
00500 replace_string(line, "@libdir@", dlpath);
00501 replace_string(line, "@DLSUFFIX@", DLSUFFIX);
00502 fputs(line, outfile);
00503 }
00504 fclose(infile);
00505 fclose(outfile);
00506 }
00507
00508
00509
00510
00511
00512 if (count <= 0)
00513 {
00514 fprintf(stderr, _("%s: no *.source files found in \"%s\"\n"),
00515 progname, indir);
00516 exit(2);
00517 }
00518
00519 pgfnames_cleanup(names);
00520 }
00521
00522
00523 static void
00524 convert_sourcefiles(void)
00525 {
00526 convert_sourcefiles_in("input", inputdir, "sql", "sql");
00527 convert_sourcefiles_in("output", outputdir, "expected", "out");
00528 }
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 static void
00544 load_resultmap(void)
00545 {
00546 char buf[MAXPGPATH];
00547 FILE *f;
00548
00549
00550 snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
00551 f = fopen(buf, "r");
00552 if (!f)
00553 {
00554
00555 if (errno == ENOENT)
00556 return;
00557 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
00558 progname, buf, strerror(errno));
00559 exit(2);
00560 }
00561
00562 while (fgets(buf, sizeof(buf), f))
00563 {
00564 char *platform;
00565 char *file_type;
00566 char *expected;
00567 int i;
00568
00569
00570 i = strlen(buf);
00571 while (i > 0 && isspace((unsigned char) buf[i - 1]))
00572 buf[--i] = '\0';
00573
00574
00575 file_type = strchr(buf, ':');
00576 if (!file_type)
00577 {
00578 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
00579 buf);
00580 exit(2);
00581 }
00582 *file_type++ = '\0';
00583
00584 platform = strchr(file_type, ':');
00585 if (!platform)
00586 {
00587 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
00588 buf);
00589 exit(2);
00590 }
00591 *platform++ = '\0';
00592 expected = strchr(platform, '=');
00593 if (!expected)
00594 {
00595 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
00596 buf);
00597 exit(2);
00598 }
00599 *expected++ = '\0';
00600
00601
00602
00603
00604
00605
00606
00607 if (string_matches_pattern(host_platform, platform))
00608 {
00609 _resultmap *entry = malloc(sizeof(_resultmap));
00610
00611 entry->test = strdup(buf);
00612 entry->type = strdup(file_type);
00613 entry->resultfile = strdup(expected);
00614 entry->next = resultmap;
00615 resultmap = entry;
00616 }
00617 }
00618 fclose(f);
00619 }
00620
00621
00622
00623
00624 static
00625 const char *
00626 get_expectfile(const char *testname, const char *file)
00627 {
00628 char *file_type;
00629 _resultmap *rm;
00630
00631
00632
00633
00634
00635 if (!file || !(file_type = strrchr(file, '.')))
00636 return NULL;
00637
00638 file_type++;
00639
00640 for (rm = resultmap; rm != NULL; rm = rm->next)
00641 {
00642 if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
00643 {
00644 return rm->resultfile;
00645 }
00646 }
00647
00648 return NULL;
00649 }
00650
00651
00652
00653
00654 static void
00655 doputenv(const char *var, const char *val)
00656 {
00657 char *s = malloc(strlen(var) + strlen(val) + 2);
00658
00659 sprintf(s, "%s=%s", var, val);
00660 putenv(s);
00661 }
00662
00663
00664
00665
00666
00667 static void
00668 add_to_path(const char *pathname, char separator, const char *addval)
00669 {
00670 char *oldval = getenv(pathname);
00671 char *newval;
00672
00673 if (!oldval || !oldval[0])
00674 {
00675
00676 newval = malloc(strlen(pathname) + strlen(addval) + 2);
00677 sprintf(newval, "%s=%s", pathname, addval);
00678 }
00679 else
00680 {
00681 newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
00682 sprintf(newval, "%s=%s%c%s", pathname, addval, separator, oldval);
00683 }
00684 putenv(newval);
00685 }
00686
00687
00688
00689
00690 static void
00691 initialize_environment(void)
00692 {
00693 char *tmp;
00694
00695 putenv("PGAPPNAME=pg_regress");
00696
00697 if (nolocale)
00698 {
00699
00700
00701
00702 unsetenv("LC_COLLATE");
00703 unsetenv("LC_CTYPE");
00704 unsetenv("LC_MONETARY");
00705 unsetenv("LC_NUMERIC");
00706 unsetenv("LC_TIME");
00707 unsetenv("LANG");
00708
00709 #if defined(WIN32) || defined(__CYGWIN__)
00710 putenv("LANG=en");
00711 #endif
00712 }
00713
00714
00715
00716
00717
00718
00719
00720 unsetenv("LANGUAGE");
00721 unsetenv("LC_ALL");
00722 putenv("LC_MESSAGES=C");
00723
00724
00725
00726
00727 if (encoding)
00728 doputenv("PGCLIENTENCODING", encoding);
00729 else
00730 unsetenv("PGCLIENTENCODING");
00731
00732
00733
00734
00735 putenv("PGTZ=PST8PDT");
00736 putenv("PGDATESTYLE=Postgres, MDY");
00737
00738
00739
00740
00741
00742
00743 {
00744 const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
00745 const char *old_pgoptions = getenv("PGOPTIONS");
00746 char *new_pgoptions;
00747
00748 if (!old_pgoptions)
00749 old_pgoptions = "";
00750 new_pgoptions = malloc(strlen(old_pgoptions) + strlen(my_pgoptions) + 12);
00751 sprintf(new_pgoptions, "PGOPTIONS=%s %s", old_pgoptions, my_pgoptions);
00752 putenv(new_pgoptions);
00753 }
00754
00755 if (temp_install)
00756 {
00757
00758
00759
00760
00761
00762
00763
00764
00765 unsetenv("PGDATABASE");
00766 unsetenv("PGUSER");
00767 unsetenv("PGSERVICE");
00768 unsetenv("PGSSLMODE");
00769 unsetenv("PGREQUIRESSL");
00770 unsetenv("PGCONNECT_TIMEOUT");
00771 unsetenv("PGDATA");
00772 if (hostname != NULL)
00773 doputenv("PGHOST", hostname);
00774 else
00775 unsetenv("PGHOST");
00776 unsetenv("PGHOSTADDR");
00777 if (port != -1)
00778 {
00779 char s[16];
00780
00781 sprintf(s, "%d", port);
00782 doputenv("PGPORT", s);
00783 }
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795 unsetenv("MAKEFLAGS");
00796 unsetenv("MAKELEVEL");
00797
00798
00799
00800
00801 tmp = malloc(strlen(temp_install) + 32 + strlen(bindir));
00802 sprintf(tmp, "%s/install/%s", temp_install, bindir);
00803 bindir = tmp;
00804
00805 tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
00806 sprintf(tmp, "%s/install/%s", temp_install, libdir);
00807 libdir = tmp;
00808
00809 tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
00810 sprintf(tmp, "%s/install/%s", temp_install, datadir);
00811 datadir = tmp;
00812
00813
00814 psqldir = bindir;
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825 add_to_path("LD_LIBRARY_PATH", ':', libdir);
00826 add_to_path("DYLD_LIBRARY_PATH", ':', libdir);
00827 add_to_path("LIBPATH", ':', libdir);
00828 #if defined(WIN32)
00829 add_to_path("PATH", ';', libdir);
00830 #elif defined(__CYGWIN__)
00831 add_to_path("PATH", ':', libdir);
00832 #endif
00833 }
00834 else
00835 {
00836 const char *pghost;
00837 const char *pgport;
00838
00839
00840
00841
00842
00843 if (hostname != NULL)
00844 {
00845 doputenv("PGHOST", hostname);
00846 unsetenv("PGHOSTADDR");
00847 }
00848 if (port != -1)
00849 {
00850 char s[16];
00851
00852 sprintf(s, "%d", port);
00853 doputenv("PGPORT", s);
00854 }
00855 if (user != NULL)
00856 doputenv("PGUSER", user);
00857
00858
00859
00860
00861 pghost = getenv("PGHOST");
00862 pgport = getenv("PGPORT");
00863 #ifndef HAVE_UNIX_SOCKETS
00864 if (!pghost)
00865 pghost = "localhost";
00866 #endif
00867
00868 if (pghost && pgport)
00869 printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport);
00870 if (pghost && !pgport)
00871 printf(_("(using postmaster on %s, default port)\n"), pghost);
00872 if (!pghost && pgport)
00873 printf(_("(using postmaster on Unix socket, port %s)\n"), pgport);
00874 if (!pghost && !pgport)
00875 printf(_("(using postmaster on Unix socket, default port)\n"));
00876 }
00877
00878 convert_sourcefiles();
00879 load_resultmap();
00880 }
00881
00882
00883
00884
00885
00886
00887 static void
00888 psql_command(const char *database, const char *query,...)
00889 {
00890 char query_formatted[1024];
00891 char query_escaped[2048];
00892 char psql_cmd[MAXPGPATH + 2048];
00893 va_list args;
00894 char *s;
00895 char *d;
00896
00897
00898 va_start(args, query);
00899 vsnprintf(query_formatted, sizeof(query_formatted), query, args);
00900 va_end(args);
00901
00902
00903 d = query_escaped;
00904 for (s = query_formatted; *s; s++)
00905 {
00906 if (strchr("\\\"$`", *s))
00907 *d++ = '\\';
00908 *d++ = *s;
00909 }
00910 *d = '\0';
00911
00912
00913 snprintf(psql_cmd, sizeof(psql_cmd),
00914 SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE,
00915 psqldir ? psqldir : "",
00916 psqldir ? "/" : "",
00917 query_escaped,
00918 database);
00919
00920 if (system(psql_cmd) != 0)
00921 {
00922
00923 fprintf(stderr, _("command failed: %s\n"), psql_cmd);
00924 exit(2);
00925 }
00926 }
00927
00928
00929
00930
00931
00932
00933 PID_TYPE
00934 spawn_process(const char *cmdline)
00935 {
00936 #ifndef WIN32
00937 pid_t pid;
00938
00939
00940
00941
00942
00943 fflush(stdout);
00944 fflush(stderr);
00945 if (logfile)
00946 fflush(logfile);
00947
00948 pid = fork();
00949 if (pid == -1)
00950 {
00951 fprintf(stderr, _("%s: could not fork: %s\n"),
00952 progname, strerror(errno));
00953 exit(2);
00954 }
00955 if (pid == 0)
00956 {
00957
00958
00959
00960
00961
00962
00963
00964 char *cmdline2 = malloc(strlen(cmdline) + 6);
00965
00966 sprintf(cmdline2, "exec %s", cmdline);
00967 execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
00968 fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
00969 progname, shellprog, strerror(errno));
00970 _exit(1);
00971 }
00972
00973 return pid;
00974 #else
00975 char *cmdline2;
00976 BOOL b;
00977 STARTUPINFO si;
00978 PROCESS_INFORMATION pi;
00979 HANDLE origToken;
00980 HANDLE restrictedToken;
00981 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
00982 SID_AND_ATTRIBUTES dropSids[2];
00983 __CreateRestrictedToken _CreateRestrictedToken = NULL;
00984 HANDLE Advapi32Handle;
00985
00986 ZeroMemory(&si, sizeof(si));
00987 si.cb = sizeof(si);
00988
00989 Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
00990 if (Advapi32Handle != NULL)
00991 {
00992 _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
00993 }
00994
00995 if (_CreateRestrictedToken == NULL)
00996 {
00997 if (Advapi32Handle != NULL)
00998 FreeLibrary(Advapi32Handle);
00999 fprintf(stderr, _("%s: cannot create restricted tokens on this platform\n"),
01000 progname);
01001 exit(2);
01002 }
01003
01004
01005 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
01006 {
01007 fprintf(stderr, _("could not open process token: error code %lu\n"),
01008 GetLastError());
01009 exit(2);
01010 }
01011
01012
01013 ZeroMemory(&dropSids, sizeof(dropSids));
01014 if (!AllocateAndInitializeSid(&NtAuthority, 2,
01015 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &dropSids[0].Sid) ||
01016 !AllocateAndInitializeSid(&NtAuthority, 2,
01017 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &dropSids[1].Sid))
01018 {
01019 fprintf(stderr, _("could not allocate SIDs: error code %lu\n"), GetLastError());
01020 exit(2);
01021 }
01022
01023 b = _CreateRestrictedToken(origToken,
01024 DISABLE_MAX_PRIVILEGE,
01025 sizeof(dropSids) / sizeof(dropSids[0]),
01026 dropSids,
01027 0, NULL,
01028 0, NULL,
01029 &restrictedToken);
01030
01031 FreeSid(dropSids[1].Sid);
01032 FreeSid(dropSids[0].Sid);
01033 CloseHandle(origToken);
01034 FreeLibrary(Advapi32Handle);
01035
01036 if (!b)
01037 {
01038 fprintf(stderr, _("could not create restricted token: error code %lu\n"),
01039 GetLastError());
01040 exit(2);
01041 }
01042
01043 cmdline2 = malloc(strlen(cmdline) + 8);
01044 sprintf(cmdline2, "cmd /c %s", cmdline);
01045
01046 #ifndef __CYGWIN__
01047 AddUserToTokenDacl(restrictedToken);
01048 #endif
01049
01050 if (!CreateProcessAsUser(restrictedToken,
01051 NULL,
01052 cmdline2,
01053 NULL,
01054 NULL,
01055 TRUE,
01056 CREATE_SUSPENDED,
01057 NULL,
01058 NULL,
01059 &si,
01060 &pi))
01061 {
01062 fprintf(stderr, _("could not start process for \"%s\": error code %lu\n"),
01063 cmdline2, GetLastError());
01064 exit(2);
01065 }
01066
01067 free(cmdline2);
01068
01069 ResumeThread(pi.hThread);
01070 CloseHandle(pi.hThread);
01071 return pi.hProcess;
01072 #endif
01073 }
01074
01075
01076
01077
01078 static long
01079 file_size(const char *file)
01080 {
01081 long r;
01082 FILE *f = fopen(file, "r");
01083
01084 if (!f)
01085 {
01086 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
01087 progname, file, strerror(errno));
01088 return -1;
01089 }
01090 fseek(f, 0, SEEK_END);
01091 r = ftell(f);
01092 fclose(f);
01093 return r;
01094 }
01095
01096
01097
01098
01099 static int
01100 file_line_count(const char *file)
01101 {
01102 int c;
01103 int l = 0;
01104 FILE *f = fopen(file, "r");
01105
01106 if (!f)
01107 {
01108 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
01109 progname, file, strerror(errno));
01110 return -1;
01111 }
01112 while ((c = fgetc(f)) != EOF)
01113 {
01114 if (c == '\n')
01115 l++;
01116 }
01117 fclose(f);
01118 return l;
01119 }
01120
01121 bool
01122 file_exists(const char *file)
01123 {
01124 FILE *f = fopen(file, "r");
01125
01126 if (!f)
01127 return false;
01128 fclose(f);
01129 return true;
01130 }
01131
01132 static bool
01133 directory_exists(const char *dir)
01134 {
01135 struct stat st;
01136
01137 if (stat(dir, &st) != 0)
01138 return false;
01139 if (S_ISDIR(st.st_mode))
01140 return true;
01141 return false;
01142 }
01143
01144
01145 static void
01146 make_directory(const char *dir)
01147 {
01148 if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
01149 {
01150 fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
01151 progname, dir, strerror(errno));
01152 exit(2);
01153 }
01154 }
01155
01156
01157
01158
01159 static char *
01160 get_alternative_expectfile(const char *expectfile, int i)
01161 {
01162 char *last_dot;
01163 int ssize = strlen(expectfile) + 2 + 1;
01164 char *tmp = (char *) malloc(ssize);
01165 char *s = (char *) malloc(ssize);
01166
01167 strcpy(tmp, expectfile);
01168 last_dot = strrchr(tmp, '.');
01169 if (!last_dot)
01170 {
01171 free(tmp);
01172 free(s);
01173 return NULL;
01174 }
01175 *last_dot = '\0';
01176 snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
01177 free(tmp);
01178 return s;
01179 }
01180
01181
01182
01183
01184 static int
01185 run_diff(const char *cmd, const char *filename)
01186 {
01187 int r;
01188
01189 r = system(cmd);
01190 if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
01191 {
01192 fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
01193 exit(2);
01194 }
01195 #ifdef WIN32
01196
01197
01198
01199
01200
01201 if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
01202 {
01203 fprintf(stderr, _("diff command not found: %s\n"), cmd);
01204 exit(2);
01205 }
01206 #endif
01207
01208 return WEXITSTATUS(r);
01209 }
01210
01211
01212
01213
01214
01215
01216
01217 static bool
01218 results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
01219 {
01220 char expectfile[MAXPGPATH];
01221 char diff[MAXPGPATH];
01222 char cmd[MAXPGPATH * 3];
01223 char best_expect_file[MAXPGPATH];
01224 FILE *difffile;
01225 int best_line_count;
01226 int i;
01227 int l;
01228 const char *platform_expectfile;
01229
01230
01231
01232
01233
01234 platform_expectfile = get_expectfile(testname, resultsfile);
01235
01236 strcpy(expectfile, default_expectfile);
01237 if (platform_expectfile)
01238 {
01239
01240
01241
01242
01243 char *p = strrchr(expectfile, '/');
01244
01245 if (p)
01246 strcpy(++p, platform_expectfile);
01247 }
01248
01249
01250 snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
01251
01252
01253 snprintf(cmd, sizeof(cmd),
01254 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
01255 basic_diff_opts, expectfile, resultsfile, diff);
01256
01257
01258 if (run_diff(cmd, diff) == 0)
01259 {
01260 unlink(diff);
01261 return false;
01262 }
01263
01264
01265 best_line_count = file_line_count(diff);
01266 strcpy(best_expect_file, expectfile);
01267
01268 for (i = 0; i <= 9; i++)
01269 {
01270 char *alt_expectfile;
01271
01272 alt_expectfile = get_alternative_expectfile(expectfile, i);
01273 if (!file_exists(alt_expectfile))
01274 continue;
01275
01276 snprintf(cmd, sizeof(cmd),
01277 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
01278 basic_diff_opts, alt_expectfile, resultsfile, diff);
01279
01280 if (run_diff(cmd, diff) == 0)
01281 {
01282 unlink(diff);
01283 return false;
01284 }
01285
01286 l = file_line_count(diff);
01287 if (l < best_line_count)
01288 {
01289
01290 best_line_count = l;
01291 strcpy(best_expect_file, alt_expectfile);
01292 }
01293 free(alt_expectfile);
01294 }
01295
01296
01297
01298
01299
01300
01301 if (platform_expectfile)
01302 {
01303 snprintf(cmd, sizeof(cmd),
01304 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
01305 basic_diff_opts, default_expectfile, resultsfile, diff);
01306
01307 if (run_diff(cmd, diff) == 0)
01308 {
01309
01310 unlink(diff);
01311 return false;
01312 }
01313
01314 l = file_line_count(diff);
01315 if (l < best_line_count)
01316 {
01317
01318 best_line_count = l;
01319 strcpy(best_expect_file, default_expectfile);
01320 }
01321 }
01322
01323
01324
01325
01326
01327 snprintf(cmd, sizeof(cmd),
01328 SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE,
01329 pretty_diff_opts, best_expect_file, resultsfile, difffilename);
01330 run_diff(cmd, difffilename);
01331
01332
01333 difffile = fopen(difffilename, "a");
01334 if (difffile)
01335 {
01336 fprintf(difffile,
01337 "\n======================================================================\n\n");
01338 fclose(difffile);
01339 }
01340
01341 unlink(diff);
01342 return true;
01343 }
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353 static void
01354 wait_for_tests(PID_TYPE * pids, int *statuses, char **names, int num_tests)
01355 {
01356 int tests_left;
01357 int i;
01358
01359 #ifdef WIN32
01360 PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE));
01361
01362 memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
01363 #endif
01364
01365 tests_left = num_tests;
01366 while (tests_left > 0)
01367 {
01368 PID_TYPE p;
01369
01370 #ifndef WIN32
01371 int exit_status;
01372
01373 p = wait(&exit_status);
01374
01375 if (p == INVALID_PID)
01376 {
01377 fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
01378 strerror(errno));
01379 exit(2);
01380 }
01381 #else
01382 DWORD exit_status;
01383 int r;
01384
01385 r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
01386 if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
01387 {
01388 fprintf(stderr, _("failed to wait for subprocesses: error code %lu\n"),
01389 GetLastError());
01390 exit(2);
01391 }
01392 p = active_pids[r - WAIT_OBJECT_0];
01393
01394 active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
01395 #endif
01396
01397 for (i = 0; i < num_tests; i++)
01398 {
01399 if (p == pids[i])
01400 {
01401 #ifdef WIN32
01402 GetExitCodeProcess(pids[i], &exit_status);
01403 CloseHandle(pids[i]);
01404 #endif
01405 pids[i] = INVALID_PID;
01406 statuses[i] = (int) exit_status;
01407 if (names)
01408 status(" %s", names[i]);
01409 tests_left--;
01410 break;
01411 }
01412 }
01413 }
01414
01415 #ifdef WIN32
01416 free(active_pids);
01417 #endif
01418 }
01419
01420
01421
01422
01423 static void
01424 log_child_failure(int exitstatus)
01425 {
01426 if (WIFEXITED(exitstatus))
01427 status(_(" (test process exited with exit code %d)"),
01428 WEXITSTATUS(exitstatus));
01429 else if (WIFSIGNALED(exitstatus))
01430 {
01431 #if defined(WIN32)
01432 status(_(" (test process was terminated by exception 0x%X)"),
01433 WTERMSIG(exitstatus));
01434 #elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
01435 status(_(" (test process was terminated by signal %d: %s)"),
01436 WTERMSIG(exitstatus),
01437 WTERMSIG(exitstatus) < NSIG ?
01438 sys_siglist[WTERMSIG(exitstatus)] : "(unknown))");
01439 #else
01440 status(_(" (test process was terminated by signal %d)"),
01441 WTERMSIG(exitstatus));
01442 #endif
01443 }
01444 else
01445 status(_(" (test process exited with unrecognized status %d)"),
01446 exitstatus);
01447 }
01448
01449
01450
01451
01452 static void
01453 run_schedule(const char *schedule, test_function tfunc)
01454 {
01455 #define MAX_PARALLEL_TESTS 100
01456 char *tests[MAX_PARALLEL_TESTS];
01457 _stringlist *resultfiles[MAX_PARALLEL_TESTS];
01458 _stringlist *expectfiles[MAX_PARALLEL_TESTS];
01459 _stringlist *tags[MAX_PARALLEL_TESTS];
01460 PID_TYPE pids[MAX_PARALLEL_TESTS];
01461 int statuses[MAX_PARALLEL_TESTS];
01462 _stringlist *ignorelist = NULL;
01463 char scbuf[1024];
01464 FILE *scf;
01465 int line_num = 0;
01466
01467 memset(resultfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
01468 memset(expectfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
01469 memset(tags, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
01470
01471 scf = fopen(schedule, "r");
01472 if (!scf)
01473 {
01474 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
01475 progname, schedule, strerror(errno));
01476 exit(2);
01477 }
01478
01479 while (fgets(scbuf, sizeof(scbuf), scf))
01480 {
01481 char *test = NULL;
01482 char *c;
01483 int num_tests;
01484 bool inword;
01485 int i;
01486
01487 line_num++;
01488
01489 for (i = 0; i < MAX_PARALLEL_TESTS; i++)
01490 {
01491 if (resultfiles[i] == NULL)
01492 break;
01493 free_stringlist(&resultfiles[i]);
01494 free_stringlist(&expectfiles[i]);
01495 free_stringlist(&tags[i]);
01496 }
01497
01498
01499 i = strlen(scbuf);
01500 while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
01501 scbuf[--i] = '\0';
01502
01503 if (scbuf[0] == '\0' || scbuf[0] == '#')
01504 continue;
01505 if (strncmp(scbuf, "test: ", 6) == 0)
01506 test = scbuf + 6;
01507 else if (strncmp(scbuf, "ignore: ", 8) == 0)
01508 {
01509 c = scbuf + 8;
01510 while (*c && isspace((unsigned char) *c))
01511 c++;
01512 add_stringlist_item(&ignorelist, c);
01513
01514
01515
01516
01517
01518
01519 continue;
01520 }
01521 else
01522 {
01523 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
01524 schedule, line_num, scbuf);
01525 exit(2);
01526 }
01527
01528 num_tests = 0;
01529 inword = false;
01530 for (c = test; *c; c++)
01531 {
01532 if (isspace((unsigned char) *c))
01533 {
01534 *c = '\0';
01535 inword = false;
01536 }
01537 else if (!inword)
01538 {
01539 if (num_tests >= MAX_PARALLEL_TESTS)
01540 {
01541
01542 fprintf(stderr, _("too many parallel tests in schedule file \"%s\", line %d\n"),
01543 schedule, line_num);
01544 exit(2);
01545 }
01546 tests[num_tests] = c;
01547 num_tests++;
01548 inword = true;
01549 }
01550 }
01551
01552 if (num_tests == 0)
01553 {
01554 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
01555 schedule, line_num, scbuf);
01556 exit(2);
01557 }
01558
01559 if (num_tests == 1)
01560 {
01561 status(_("test %-24s ... "), tests[0]);
01562 pids[0] = (tfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
01563 wait_for_tests(pids, statuses, NULL, 1);
01564
01565 }
01566 else if (max_connections > 0 && max_connections < num_tests)
01567 {
01568 int oldest = 0;
01569
01570 status(_("parallel group (%d tests, in groups of %d): "),
01571 num_tests, max_connections);
01572 for (i = 0; i < num_tests; i++)
01573 {
01574 if (i - oldest >= max_connections)
01575 {
01576 wait_for_tests(pids + oldest, statuses + oldest,
01577 tests + oldest, i - oldest);
01578 oldest = i;
01579 }
01580 pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
01581 }
01582 wait_for_tests(pids + oldest, statuses + oldest,
01583 tests + oldest, i - oldest);
01584 status_end();
01585 }
01586 else
01587 {
01588 status(_("parallel group (%d tests): "), num_tests);
01589 for (i = 0; i < num_tests; i++)
01590 {
01591 pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
01592 }
01593 wait_for_tests(pids, statuses, tests, num_tests);
01594 status_end();
01595 }
01596
01597
01598 for (i = 0; i < num_tests; i++)
01599 {
01600 _stringlist *rl,
01601 *el,
01602 *tl;
01603 bool differ = false;
01604
01605 if (num_tests > 1)
01606 status(_(" %-24s ... "), tests[i]);
01607
01608
01609
01610
01611
01612
01613
01614
01615 for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
01616 rl != NULL;
01617 rl = rl->next, el = el->next)
01618 {
01619 bool newdiff;
01620
01621 if (tl)
01622 tl = tl->next;
01623
01624
01625 newdiff = results_differ(tests[i], rl->str, el->str);
01626 if (newdiff && tl)
01627 {
01628 printf("%s ", tl->str);
01629 }
01630 differ |= newdiff;
01631 }
01632
01633 if (differ)
01634 {
01635 bool ignore = false;
01636 _stringlist *sl;
01637
01638 for (sl = ignorelist; sl != NULL; sl = sl->next)
01639 {
01640 if (strcmp(tests[i], sl->str) == 0)
01641 {
01642 ignore = true;
01643 break;
01644 }
01645 }
01646 if (ignore)
01647 {
01648 status(_("failed (ignored)"));
01649 fail_ignore_count++;
01650 }
01651 else
01652 {
01653 status(_("FAILED"));
01654 fail_count++;
01655 }
01656 }
01657 else
01658 {
01659 status(_("ok"));
01660 success_count++;
01661 }
01662
01663 if (statuses[i] != 0)
01664 log_child_failure(statuses[i]);
01665
01666 status_end();
01667 }
01668 }
01669
01670 fclose(scf);
01671 }
01672
01673
01674
01675
01676 static void
01677 run_single_test(const char *test, test_function tfunc)
01678 {
01679 PID_TYPE pid;
01680 int exit_status;
01681 _stringlist *resultfiles = NULL;
01682 _stringlist *expectfiles = NULL;
01683 _stringlist *tags = NULL;
01684 _stringlist *rl,
01685 *el,
01686 *tl;
01687 bool differ = false;
01688
01689 status(_("test %-24s ... "), test);
01690 pid = (tfunc) (test, &resultfiles, &expectfiles, &tags);
01691 wait_for_tests(&pid, &exit_status, NULL, 1);
01692
01693
01694
01695
01696
01697
01698
01699
01700 for (rl = resultfiles, el = expectfiles, tl = tags;
01701 rl != NULL;
01702 rl = rl->next, el = el->next)
01703 {
01704 bool newdiff;
01705
01706 if (tl)
01707 tl = tl->next;
01708
01709
01710 newdiff = results_differ(test, rl->str, el->str);
01711 if (newdiff && tl)
01712 {
01713 printf("%s ", tl->str);
01714 }
01715 differ |= newdiff;
01716 }
01717
01718 if (differ)
01719 {
01720 status(_("FAILED"));
01721 fail_count++;
01722 }
01723 else
01724 {
01725 status(_("ok"));
01726 success_count++;
01727 }
01728
01729 if (exit_status != 0)
01730 log_child_failure(exit_status);
01731
01732 status_end();
01733 }
01734
01735
01736
01737
01738 static void
01739 open_result_files(void)
01740 {
01741 char file[MAXPGPATH];
01742 FILE *difffile;
01743
01744
01745 snprintf(file, sizeof(file), "%s/regression.out", outputdir);
01746 logfilename = strdup(file);
01747 logfile = fopen(logfilename, "w");
01748 if (!logfile)
01749 {
01750 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
01751 progname, logfilename, strerror(errno));
01752 exit(2);
01753 }
01754
01755
01756 snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
01757 difffilename = strdup(file);
01758 difffile = fopen(difffilename, "w");
01759 if (!difffile)
01760 {
01761 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
01762 progname, difffilename, strerror(errno));
01763 exit(2);
01764 }
01765
01766 fclose(difffile);
01767
01768
01769 snprintf(file, sizeof(file), "%s/results", outputdir);
01770 if (!directory_exists(file))
01771 make_directory(file);
01772 }
01773
01774 static void
01775 drop_database_if_exists(const char *dbname)
01776 {
01777 header(_("dropping database \"%s\""), dbname);
01778 psql_command("postgres", "DROP DATABASE IF EXISTS \"%s\"", dbname);
01779 }
01780
01781 static void
01782 create_database(const char *dbname)
01783 {
01784 _stringlist *sl;
01785
01786
01787
01788
01789
01790 header(_("creating database \"%s\""), dbname);
01791 if (encoding)
01792 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
01793 (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
01794 else
01795 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
01796 (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
01797 psql_command(dbname,
01798 "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
01799 "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
01800 "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
01801 "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
01802 "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
01803 dbname, dbname, dbname, dbname, dbname);
01804
01805
01806
01807
01808
01809 for (sl = loadlanguage; sl != NULL; sl = sl->next)
01810 {
01811 header(_("installing %s"), sl->str);
01812 psql_command(dbname, "CREATE OR REPLACE LANGUAGE \"%s\"", sl->str);
01813 }
01814
01815
01816
01817
01818
01819 for (sl = loadextension; sl != NULL; sl = sl->next)
01820 {
01821 header(_("installing %s"), sl->str);
01822 psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
01823 }
01824 }
01825
01826 static void
01827 drop_role_if_exists(const char *rolename)
01828 {
01829 header(_("dropping role \"%s\""), rolename);
01830 psql_command("postgres", "DROP ROLE IF EXISTS \"%s\"", rolename);
01831 }
01832
01833 static void
01834 create_role(const char *rolename, const _stringlist * granted_dbs)
01835 {
01836 header(_("creating role \"%s\""), rolename);
01837 psql_command("postgres", "CREATE ROLE \"%s\" WITH LOGIN", rolename);
01838 for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
01839 {
01840 psql_command("postgres", "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
01841 granted_dbs->str, rolename);
01842 }
01843 }
01844
01845 static char *
01846 make_absolute_path(const char *in)
01847 {
01848 char *result;
01849
01850 if (is_absolute_path(in))
01851 result = strdup(in);
01852 else
01853 {
01854 static char cwdbuf[MAXPGPATH];
01855
01856 if (!cwdbuf[0])
01857 {
01858 if (!getcwd(cwdbuf, sizeof(cwdbuf)))
01859 {
01860 fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
01861 exit(2);
01862 }
01863 }
01864
01865 result = malloc(strlen(cwdbuf) + strlen(in) + 2);
01866 sprintf(result, "%s/%s", cwdbuf, in);
01867 }
01868
01869 canonicalize_path(result);
01870 return result;
01871 }
01872
01873 static void
01874 help(void)
01875 {
01876 printf(_("PostgreSQL regression test driver\n"));
01877 printf(_("\n"));
01878 printf(_("Usage:\n %s [OPTION]... [EXTRA-TEST]...\n"), progname);
01879 printf(_("\n"));
01880 printf(_("Options:\n"));
01881 printf(_(" --create-role=ROLE create the specified role before testing\n"));
01882 printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
01883 printf(_(" --debug turn on debug mode in programs that are run\n"));
01884 printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
01885 printf(_(" --encoding=ENCODING use ENCODING as the encoding\n"));
01886 printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
01887 printf(_(" --launcher=CMD use CMD as launcher of psql\n"));
01888 printf(_(" --load-extension=EXT load the named extension before running the\n"));
01889 printf(_(" tests; can appear multiple times\n"));
01890 printf(_(" --load-language=LANG load the named language before running the\n"));
01891 printf(_(" tests; can appear multiple times\n"));
01892 printf(_(" --max-connections=N maximum number of concurrent connections\n"));
01893 printf(_(" (default is 0, meaning unlimited)\n"));
01894 printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
01895 printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
01896 printf(_(" (can be used multiple times to concatenate)\n"));
01897 printf(_(" --temp-install=DIR create a temporary installation in DIR\n"));
01898 printf(_(" --use-existing use an existing installation\n"));
01899 printf(_("\n"));
01900 printf(_("Options for \"temp-install\" mode:\n"));
01901 printf(_(" --extra-install=DIR additional directory to install (e.g., contrib)\n"));
01902 printf(_(" --no-locale use C locale\n"));
01903 printf(_(" --port=PORT start postmaster on PORT\n"));
01904 printf(_(" --temp-config=FILE append contents of FILE to temporary config\n"));
01905 printf(_(" --top-builddir=DIR (relative) path to top level build directory\n"));
01906 printf(_("\n"));
01907 printf(_("Options for using an existing installation:\n"));
01908 printf(_(" --host=HOST use postmaster running on HOST\n"));
01909 printf(_(" --port=PORT use postmaster running at PORT\n"));
01910 printf(_(" --user=USER connect as USER\n"));
01911 printf(_(" --psqldir=DIR use psql in DIR (default: configured bindir)\n"));
01912 printf(_("\n"));
01913 printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
01914 printf(_("if the tests could not be run for some reason.\n"));
01915 printf(_("\n"));
01916 printf(_("Report bugs to <[email protected]>.\n"));
01917 }
01918
01919 int
01920 regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc)
01921 {
01922 static struct option long_options[] = {
01923 {"help", no_argument, NULL, 'h'},
01924 {"version", no_argument, NULL, 'V'},
01925 {"dbname", required_argument, NULL, 1},
01926 {"debug", no_argument, NULL, 2},
01927 {"inputdir", required_argument, NULL, 3},
01928 {"load-language", required_argument, NULL, 4},
01929 {"max-connections", required_argument, NULL, 5},
01930 {"encoding", required_argument, NULL, 6},
01931 {"outputdir", required_argument, NULL, 7},
01932 {"schedule", required_argument, NULL, 8},
01933 {"temp-install", required_argument, NULL, 9},
01934 {"no-locale", no_argument, NULL, 10},
01935 {"top-builddir", required_argument, NULL, 11},
01936 {"host", required_argument, NULL, 13},
01937 {"port", required_argument, NULL, 14},
01938 {"user", required_argument, NULL, 15},
01939 {"psqldir", required_argument, NULL, 16},
01940 {"dlpath", required_argument, NULL, 17},
01941 {"create-role", required_argument, NULL, 18},
01942 {"temp-config", required_argument, NULL, 19},
01943 {"use-existing", no_argument, NULL, 20},
01944 {"launcher", required_argument, NULL, 21},
01945 {"load-extension", required_argument, NULL, 22},
01946 {"extra-install", required_argument, NULL, 23},
01947 {NULL, 0, NULL, 0}
01948 };
01949
01950 _stringlist *sl;
01951 int c;
01952 int i;
01953 int option_index;
01954 char buf[MAXPGPATH * 4];
01955 char buf2[MAXPGPATH * 4];
01956
01957 progname = get_progname(argv[0]);
01958 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
01959
01960 atexit(stop_postmaster);
01961
01962 #ifndef HAVE_UNIX_SOCKETS
01963
01964 hostname = "localhost";
01965 #endif
01966
01967
01968
01969
01970
01971 ifunc();
01972
01973 if (getenv("PG_REGRESS_DIFF_OPTS"))
01974 pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS");
01975
01976 while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
01977 {
01978 switch (c)
01979 {
01980 case 'h':
01981 help();
01982 exit(0);
01983 case 'V':
01984 puts("pg_regress (PostgreSQL) " PG_VERSION);
01985 exit(0);
01986 case 1:
01987
01988
01989
01990
01991
01992 free_stringlist(&dblist);
01993 split_to_stringlist(strdup(optarg), ", ", &dblist);
01994 break;
01995 case 2:
01996 debug = true;
01997 break;
01998 case 3:
01999 inputdir = strdup(optarg);
02000 break;
02001 case 4:
02002 add_stringlist_item(&loadlanguage, optarg);
02003 break;
02004 case 5:
02005 max_connections = atoi(optarg);
02006 break;
02007 case 6:
02008 encoding = strdup(optarg);
02009 break;
02010 case 7:
02011 outputdir = strdup(optarg);
02012 break;
02013 case 8:
02014 add_stringlist_item(&schedulelist, optarg);
02015 break;
02016 case 9:
02017 temp_install = make_absolute_path(optarg);
02018 break;
02019 case 10:
02020 nolocale = true;
02021 break;
02022 case 11:
02023 top_builddir = strdup(optarg);
02024 break;
02025 case 13:
02026 hostname = strdup(optarg);
02027 break;
02028 case 14:
02029 port = atoi(optarg);
02030 port_specified_by_user = true;
02031 break;
02032 case 15:
02033 user = strdup(optarg);
02034 break;
02035 case 16:
02036
02037 if (strlen(optarg))
02038 psqldir = strdup(optarg);
02039 break;
02040 case 17:
02041 dlpath = strdup(optarg);
02042 break;
02043 case 18:
02044 split_to_stringlist(strdup(optarg), ", ", &extraroles);
02045 break;
02046 case 19:
02047 temp_config = strdup(optarg);
02048 break;
02049 case 20:
02050 use_existing = true;
02051 break;
02052 case 21:
02053 launcher = strdup(optarg);
02054 break;
02055 case 22:
02056 add_stringlist_item(&loadextension, optarg);
02057 break;
02058 case 23:
02059 add_stringlist_item(&extra_install, optarg);
02060 break;
02061 default:
02062
02063 fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
02064 progname);
02065 exit(2);
02066 }
02067 }
02068
02069
02070
02071
02072 while (argc - optind >= 1)
02073 {
02074 add_stringlist_item(&extra_tests, argv[optind]);
02075 optind++;
02076 }
02077
02078 if (temp_install && !port_specified_by_user)
02079
02080
02081
02082
02083
02084
02085 port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
02086
02087 inputdir = make_absolute_path(inputdir);
02088 outputdir = make_absolute_path(outputdir);
02089 dlpath = make_absolute_path(dlpath);
02090
02091
02092
02093
02094 open_result_files();
02095
02096 initialize_environment();
02097
02098 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
02099 unlimit_core_size();
02100 #endif
02101
02102 if (temp_install)
02103 {
02104 FILE *pg_conf;
02105 _stringlist *sl;
02106
02107
02108
02109
02110 if (!top_builddir)
02111 {
02112 fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
02113 exit(2);
02114 }
02115
02116 if (directory_exists(temp_install))
02117 {
02118 header(_("removing existing temp installation"));
02119 rmtree(temp_install, true);
02120 }
02121
02122 header(_("creating temporary installation"));
02123
02124
02125 make_directory(temp_install);
02126
02127
02128 snprintf(buf, sizeof(buf), "%s/log", outputdir);
02129 if (!directory_exists(buf))
02130 make_directory(buf);
02131
02132
02133 #ifndef WIN32_ONLY_COMPILER
02134 snprintf(buf, sizeof(buf),
02135 SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
02136 makeprog, top_builddir, temp_install, outputdir);
02137 #else
02138 snprintf(buf, sizeof(buf),
02139 SYSTEMQUOTE "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
02140 top_builddir, temp_install, outputdir);
02141 #endif
02142 if (system(buf))
02143 {
02144 fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
02145 exit(2);
02146 }
02147
02148 for (sl = extra_install; sl != NULL; sl = sl->next)
02149 {
02150 #ifndef WIN32_ONLY_COMPILER
02151 snprintf(buf, sizeof(buf),
02152 SYSTEMQUOTE "\"%s\" -C \"%s/%s\" DESTDIR=\"%s/install\" install >> \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
02153 makeprog, top_builddir, sl->str, temp_install, outputdir);
02154 #else
02155 fprintf(stderr, _("\n%s: --extra-install option not supported on this platform\n"), progname);
02156 exit(2);
02157 #endif
02158
02159 if (system(buf))
02160 {
02161 fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
02162 exit(2);
02163 }
02164 }
02165
02166
02167 header(_("initializing database system"));
02168 snprintf(buf, sizeof(buf),
02169 SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
02170 bindir, temp_install, datadir,
02171 debug ? " --debug" : "",
02172 nolocale ? " --no-locale" : "",
02173 outputdir);
02174 if (system(buf))
02175 {
02176 fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
02177 exit(2);
02178 }
02179
02180
02181
02182
02183
02184
02185
02186
02187
02188 snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install);
02189 pg_conf = fopen(buf, "a");
02190 if (pg_conf == NULL)
02191 {
02192 fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno));
02193 exit(2);
02194 }
02195 fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
02196 fputs("max_prepared_transactions = 2\n", pg_conf);
02197
02198 if (temp_config != NULL)
02199 {
02200 FILE *extra_conf;
02201 char line_buf[1024];
02202
02203 extra_conf = fopen(temp_config, "r");
02204 if (extra_conf == NULL)
02205 {
02206 fprintf(stderr, _("\n%s: could not open \"%s\" to read extra config: %s\n"), progname, temp_config, strerror(errno));
02207 exit(2);
02208 }
02209 while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
02210 fputs(line_buf, pg_conf);
02211 fclose(extra_conf);
02212 }
02213
02214 fclose(pg_conf);
02215
02216
02217
02218
02219 snprintf(buf2, sizeof(buf2),
02220 SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE,
02221 bindir, DEVNULL, DEVNULL);
02222
02223 for (i = 0; i < 16; i++)
02224 {
02225 if (system(buf2) == 0)
02226 {
02227 char s[16];
02228
02229 if (port_specified_by_user || i == 15)
02230 {
02231 fprintf(stderr, _("port %d apparently in use\n"), port);
02232 if (!port_specified_by_user)
02233 fprintf(stderr, _("%s: could not determine an available port\n"), progname);
02234 fprintf(stderr, _("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.\n"));
02235 exit(2);
02236 }
02237
02238 fprintf(stderr, _("port %d apparently in use, trying %d\n"), port, port + 1);
02239 port++;
02240 sprintf(s, "%d", port);
02241 doputenv("PGPORT", s);
02242 }
02243 else
02244 break;
02245 }
02246
02247
02248
02249
02250 header(_("starting postmaster"));
02251 snprintf(buf, sizeof(buf),
02252 SYSTEMQUOTE "\"%s/postgres\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
02253 bindir, temp_install,
02254 debug ? " -d 5" : "",
02255 hostname ? hostname : "",
02256 outputdir);
02257 postmaster_pid = spawn_process(buf);
02258 if (postmaster_pid == INVALID_PID)
02259 {
02260 fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
02261 progname, strerror(errno));
02262 exit(2);
02263 }
02264
02265
02266
02267
02268
02269
02270 for (i = 0; i < 60; i++)
02271 {
02272
02273 if (system(buf2) == 0)
02274 break;
02275
02276
02277
02278
02279 #ifndef WIN32
02280 if (kill(postmaster_pid, 0) != 0)
02281 #else
02282 if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
02283 #endif
02284 {
02285 fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
02286 exit(2);
02287 }
02288
02289 pg_usleep(1000000L);
02290 }
02291 if (i >= 60)
02292 {
02293 fprintf(stderr, _("\n%s: postmaster did not respond within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
02294
02295
02296
02297
02298
02299
02300
02301 #ifndef WIN32
02302 if (kill(postmaster_pid, SIGKILL) != 0 &&
02303 errno != ESRCH)
02304 fprintf(stderr, _("\n%s: could not kill failed postmaster: %s\n"),
02305 progname, strerror(errno));
02306 #else
02307 if (TerminateProcess(postmaster_pid, 255) == 0)
02308 fprintf(stderr, _("\n%s: could not kill failed postmaster: error code %lu\n"),
02309 progname, GetLastError());
02310 #endif
02311
02312 exit(2);
02313 }
02314
02315 postmaster_running = true;
02316
02317 #ifdef WIN64
02318
02319 #define ULONGPID(x) (unsigned long) (unsigned long long) (x)
02320 #else
02321 #define ULONGPID(x) (unsigned long) (x)
02322 #endif
02323 printf(_("running on port %d with PID %lu\n"),
02324 port, ULONGPID(postmaster_pid));
02325 }
02326 else
02327 {
02328
02329
02330
02331
02332 if (!use_existing)
02333 {
02334 for (sl = dblist; sl; sl = sl->next)
02335 drop_database_if_exists(sl->str);
02336 for (sl = extraroles; sl; sl = sl->next)
02337 drop_role_if_exists(sl->str);
02338 }
02339 }
02340
02341
02342
02343
02344 if (!use_existing)
02345 {
02346 for (sl = dblist; sl; sl = sl->next)
02347 create_database(sl->str);
02348 for (sl = extraroles; sl; sl = sl->next)
02349 create_role(sl->str, dblist);
02350 }
02351
02352
02353
02354
02355 header(_("running regression test queries"));
02356
02357 for (sl = schedulelist; sl != NULL; sl = sl->next)
02358 {
02359 run_schedule(sl->str, tfunc);
02360 }
02361
02362 for (sl = extra_tests; sl != NULL; sl = sl->next)
02363 {
02364 run_single_test(sl->str, tfunc);
02365 }
02366
02367
02368
02369
02370 if (temp_install)
02371 {
02372 header(_("shutting down postmaster"));
02373 stop_postmaster();
02374 }
02375
02376 fclose(logfile);
02377
02378
02379
02380
02381 if (fail_count == 0 && fail_ignore_count == 0)
02382 snprintf(buf, sizeof(buf),
02383 _(" All %d tests passed. "),
02384 success_count);
02385 else if (fail_count == 0)
02386 snprintf(buf, sizeof(buf),
02387 _(" %d of %d tests passed, %d failed test(s) ignored. "),
02388 success_count,
02389 success_count + fail_ignore_count,
02390 fail_ignore_count);
02391 else if (fail_ignore_count == 0)
02392 snprintf(buf, sizeof(buf),
02393 _(" %d of %d tests failed. "),
02394 fail_count,
02395 success_count + fail_count);
02396 else
02397
02398 snprintf(buf, sizeof(buf),
02399 _(" %d of %d tests failed, %d of these failures ignored. "),
02400 fail_count + fail_ignore_count,
02401 success_count + fail_count + fail_ignore_count,
02402 fail_ignore_count);
02403
02404 putchar('\n');
02405 for (i = strlen(buf); i > 0; i--)
02406 putchar('=');
02407 printf("\n%s\n", buf);
02408 for (i = strlen(buf); i > 0; i--)
02409 putchar('=');
02410 putchar('\n');
02411 putchar('\n');
02412
02413 if (file_size(difffilename) > 0)
02414 {
02415 printf(_("The differences that caused some tests to fail can be viewed in the\n"
02416 "file \"%s\". A copy of the test summary that you see\n"
02417 "above is saved in the file \"%s\".\n\n"),
02418 difffilename, logfilename);
02419 }
02420 else
02421 {
02422 unlink(difffilename);
02423 unlink(logfilename);
02424 }
02425
02426 if (fail_count != 0)
02427 exit(1);
02428
02429 return 0;
02430 }