main.c revision 238856
1/* 2 * Copyright (c) 2003-2009 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "test.h" 27#ifdef HAVE_SYS_IOCTL_H 28#include <sys/ioctl.h> 29#endif 30#ifdef HAVE_SYS_TIME_H 31#include <sys/time.h> 32#endif 33#include <errno.h> 34#ifdef HAVE_ICONV_H 35#include <iconv.h> 36#endif 37/* 38 * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. 39 * As the include guards don't agree, the order of include is important. 40 */ 41#ifdef HAVE_LINUX_EXT2_FS_H 42#include <linux/ext2_fs.h> /* for Linux file flags */ 43#endif 44#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) 45#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ 46#endif 47#include <limits.h> 48#include <locale.h> 49#ifdef HAVE_SIGNAL_H 50#include <signal.h> 51#endif 52#include <stdarg.h> 53#include <time.h> 54 55/* 56 * This same file is used pretty much verbatim for all test harnesses. 57 * 58 * The next few lines are the only differences. 59 * TODO: Move this into a separate configuration header, have all test 60 * suites share one copy of this file. 61 */ 62__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/test/main.c 238856 2012-07-28 06:38:44Z mm $"); 63#define KNOWNREF "test_compat_gtar_1.tar.uu" 64#define ENVBASE "LIBARCHIVE" /* Prefix for environment variables. */ 65#undef PROGRAM /* Testing a library, not a program. */ 66#define LIBRARY "libarchive" 67#define EXTRA_DUMP(x) archive_error_string((struct archive *)(x)) 68#define EXTRA_ERRNO(x) archive_errno((struct archive *)(x)) 69#define EXTRA_VERSION archive_version_string() 70 71/* 72 * 73 * Windows support routines 74 * 75 * Note: Configuration is a tricky issue. Using HAVE_* feature macros 76 * in the test harness is dangerous because they cover up 77 * configuration errors. The classic example of this is omitting a 78 * configure check. If libarchive and libarchive_test both look for 79 * the same feature macro, such errors are hard to detect. Platform 80 * macros (e.g., _WIN32 or __GNUC__) are a little better, but can 81 * easily lead to very messy code. It's best to limit yourself 82 * to only the most generic programming techniques in the test harness 83 * and thus avoid conditionals altogether. Where that's not possible, 84 * try to minimize conditionals by grouping platform-specific tests in 85 * one place (e.g., test_acl_freebsd) or by adding new assert() 86 * functions (e.g., assertMakeHardlink()) to cover up platform 87 * differences. Platform-specific coding in libarchive_test is often 88 * a symptom that some capability is missing from libarchive itself. 89 */ 90#if defined(_WIN32) && !defined(__CYGWIN__) 91#include <io.h> 92#include <windows.h> 93#ifndef F_OK 94#define F_OK (0) 95#endif 96#ifndef S_ISDIR 97#define S_ISDIR(m) ((m) & _S_IFDIR) 98#endif 99#ifndef S_ISREG 100#define S_ISREG(m) ((m) & _S_IFREG) 101#endif 102#if !defined(__BORLANDC__) 103#define access _access 104#undef chdir 105#define chdir _chdir 106#endif 107#ifndef fileno 108#define fileno _fileno 109#endif 110/*#define fstat _fstat64*/ 111#if !defined(__BORLANDC__) 112#define getcwd _getcwd 113#endif 114#define lstat stat 115/*#define lstat _stat64*/ 116/*#define stat _stat64*/ 117#define rmdir _rmdir 118#if !defined(__BORLANDC__) 119#define strdup _strdup 120#define umask _umask 121#endif 122#define int64_t __int64 123#endif 124 125#if defined(HAVE__CrtSetReportMode) 126# include <crtdbg.h> 127#endif 128 129#if defined(_WIN32) && !defined(__CYGWIN__) 130static void *GetFunctionKernel32(const char *); 131static int my_CreateSymbolicLinkA(const char *, const char *, int); 132static int my_CreateHardLinkA(const char *, const char *); 133static int my_GetFileInformationByName(const char *, 134 BY_HANDLE_FILE_INFORMATION *); 135 136static void * 137GetFunctionKernel32(const char *name) 138{ 139 static HINSTANCE lib; 140 static int set; 141 if (!set) { 142 set = 1; 143 lib = LoadLibrary("kernel32.dll"); 144 } 145 if (lib == NULL) { 146 fprintf(stderr, "Can't load kernel32.dll?!\n"); 147 exit(1); 148 } 149 return (void *)GetProcAddress(lib, name); 150} 151 152static int 153my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags) 154{ 155 static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD); 156 static int set; 157 if (!set) { 158 set = 1; 159 f = GetFunctionKernel32("CreateSymbolicLinkA"); 160 } 161 return f == NULL ? 0 : (*f)(linkname, target, flags); 162} 163 164static int 165my_CreateHardLinkA(const char *linkname, const char *target) 166{ 167 static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES); 168 static int set; 169 if (!set) { 170 set = 1; 171 f = GetFunctionKernel32("CreateHardLinkA"); 172 } 173 return f == NULL ? 0 : (*f)(linkname, target, NULL); 174} 175 176static int 177my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi) 178{ 179 HANDLE h; 180 int r; 181 182 memset(bhfi, 0, sizeof(*bhfi)); 183 h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL, 184 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 185 if (h == INVALID_HANDLE_VALUE) 186 return (0); 187 r = GetFileInformationByHandle(h, bhfi); 188 CloseHandle(h); 189 return (r); 190} 191#endif 192 193#if defined(HAVE__CrtSetReportMode) 194static void 195invalid_parameter_handler(const wchar_t * expression, 196 const wchar_t * function, const wchar_t * file, 197 unsigned int line, uintptr_t pReserved) 198{ 199 /* nop */ 200} 201#endif 202 203/* 204 * 205 * OPTIONS FLAGS 206 * 207 */ 208 209/* Enable core dump on failure. */ 210static int dump_on_failure = 0; 211/* Default is to remove temp dirs and log data for successful tests. */ 212static int keep_temp_files = 0; 213/* Default is to run the specified tests once and report errors. */ 214static int until_failure = 0; 215/* Default is to just report pass/fail for each test. */ 216static int verbosity = 0; 217#define VERBOSITY_SUMMARY_ONLY -1 /* -q */ 218#define VERBOSITY_PASSFAIL 0 /* Default */ 219#define VERBOSITY_LIGHT_REPORT 1 /* -v */ 220#define VERBOSITY_FULL 2 /* -vv */ 221/* A few places generate even more output for verbosity > VERBOSITY_FULL, 222 * mostly for debugging the test harness itself. */ 223/* Cumulative count of assertion failures. */ 224static int failures = 0; 225/* Cumulative count of reported skips. */ 226static int skips = 0; 227/* Cumulative count of assertions checked. */ 228static int assertions = 0; 229 230/* Directory where uuencoded reference files can be found. */ 231static const char *refdir; 232 233/* 234 * Report log information selectively to console and/or disk log. 235 */ 236static int log_console = 0; 237static FILE *logfile; 238static void 239vlogprintf(const char *fmt, va_list ap) 240{ 241#ifdef va_copy 242 va_list lfap; 243 va_copy(lfap, ap); 244#endif 245 if (log_console) 246 vfprintf(stdout, fmt, ap); 247 if (logfile != NULL) 248#ifdef va_copy 249 vfprintf(logfile, fmt, lfap); 250 va_end(lfap); 251#else 252 vfprintf(logfile, fmt, ap); 253#endif 254} 255 256static void 257logprintf(const char *fmt, ...) 258{ 259 va_list ap; 260 va_start(ap, fmt); 261 vlogprintf(fmt, ap); 262 va_end(ap); 263} 264 265/* Set up a message to display only if next assertion fails. */ 266static char msgbuff[4096]; 267static const char *msg, *nextmsg; 268void 269failure(const char *fmt, ...) 270{ 271 va_list ap; 272 if (fmt == NULL) { 273 nextmsg = NULL; 274 } else { 275 va_start(ap, fmt); 276 vsprintf(msgbuff, fmt, ap); 277 va_end(ap); 278 nextmsg = msgbuff; 279 } 280} 281 282/* 283 * Copy arguments into file-local variables. 284 * This was added to permit vararg assert() functions without needing 285 * variadic wrapper macros. Turns out that the vararg capability is almost 286 * never used, so almost all of the vararg assertions can be simplified 287 * by removing the vararg capability and reworking the wrapper macro to 288 * pass __FILE__, __LINE__ directly into the function instead of using 289 * this hook. I suspect this machinery is used so rarely that we 290 * would be better off just removing it entirely. That would simplify 291 * the code here noticeably. 292 */ 293static const char *skipping_filename; 294static int skipping_line; 295void skipping_setup(const char *filename, int line) 296{ 297 skipping_filename = filename; 298 skipping_line = line; 299} 300 301/* Called at the beginning of each assert() function. */ 302static void 303assertion_count(const char *file, int line) 304{ 305 (void)file; /* UNUSED */ 306 (void)line; /* UNUSED */ 307 ++assertions; 308 /* Proper handling of "failure()" message. */ 309 msg = nextmsg; 310 nextmsg = NULL; 311 /* Uncomment to print file:line after every assertion. 312 * Verbose, but occasionally useful in tracking down crashes. */ 313 /* printf("Checked %s:%d\n", file, line); */ 314} 315 316/* 317 * For each test source file, we remember how many times each 318 * assertion was reported. Cleared before each new test, 319 * used by test_summarize(). 320 */ 321static struct line { 322 int count; 323 int skip; 324} failed_lines[10000]; 325const char *failed_filename; 326 327/* Count this failure, setup up log destination and handle initial report. */ 328static void 329failure_start(const char *filename, int line, const char *fmt, ...) 330{ 331 va_list ap; 332 333 /* Record another failure for this line. */ 334 ++failures; 335 failed_filename = filename; 336 failed_lines[line].count++; 337 338 /* Determine whether to log header to console. */ 339 switch (verbosity) { 340 case VERBOSITY_LIGHT_REPORT: 341 log_console = (failed_lines[line].count < 2); 342 break; 343 default: 344 log_console = (verbosity >= VERBOSITY_FULL); 345 } 346 347 /* Log file:line header for this failure */ 348 va_start(ap, fmt); 349#if _MSC_VER 350 logprintf("%s(%d): ", filename, line); 351#else 352 logprintf("%s:%d: ", filename, line); 353#endif 354 vlogprintf(fmt, ap); 355 va_end(ap); 356 logprintf("\n"); 357 358 if (msg != NULL && msg[0] != '\0') { 359 logprintf(" Description: %s\n", msg); 360 msg = NULL; 361 } 362 363 /* Determine whether to log details to console. */ 364 if (verbosity == VERBOSITY_LIGHT_REPORT) 365 log_console = 0; 366} 367 368/* Complete reporting of failed tests. */ 369/* 370 * The 'extra' hook here is used by libarchive to include libarchive 371 * error messages with assertion failures. It could also be used 372 * to add strerror() output, for example. Just define the EXTRA_DUMP() 373 * macro appropriately. 374 */ 375static void 376failure_finish(void *extra) 377{ 378 (void)extra; /* UNUSED (maybe) */ 379#ifdef EXTRA_DUMP 380 if (extra != NULL) { 381 logprintf(" errno: %d\n", EXTRA_ERRNO(extra)); 382 logprintf(" detail: %s\n", EXTRA_DUMP(extra)); 383 } 384#endif 385 386 if (dump_on_failure) { 387 fprintf(stderr, 388 " *** forcing core dump so failure can be debugged ***\n"); 389 abort(); 390 exit(1); 391 } 392} 393 394/* Inform user that we're skipping some checks. */ 395void 396test_skipping(const char *fmt, ...) 397{ 398 char buff[1024]; 399 va_list ap; 400 401 va_start(ap, fmt); 402 vsprintf(buff, fmt, ap); 403 va_end(ap); 404 /* Use failure() message if set. */ 405 msg = nextmsg; 406 nextmsg = NULL; 407 /* failure_start() isn't quite right, but is awfully convenient. */ 408 failure_start(skipping_filename, skipping_line, "SKIPPING: %s", buff); 409 --failures; /* Undo failures++ in failure_start() */ 410 /* Don't failure_finish() here. */ 411 /* Mark as skip, so doesn't count as failed test. */ 412 failed_lines[skipping_line].skip = 1; 413 ++skips; 414} 415 416/* 417 * 418 * ASSERTIONS 419 * 420 */ 421 422/* Generic assert() just displays the failed condition. */ 423int 424assertion_assert(const char *file, int line, int value, 425 const char *condition, void *extra) 426{ 427 assertion_count(file, line); 428 if (!value) { 429 failure_start(file, line, "Assertion failed: %s", condition); 430 failure_finish(extra); 431 } 432 return (value); 433} 434 435/* chdir() and report any errors */ 436int 437assertion_chdir(const char *file, int line, const char *pathname) 438{ 439 assertion_count(file, line); 440 if (chdir(pathname) == 0) 441 return (1); 442 failure_start(file, line, "chdir(\"%s\")", pathname); 443 failure_finish(NULL); 444 return (0); 445 446} 447 448/* Verify two integers are equal. */ 449int 450assertion_equal_int(const char *file, int line, 451 long long v1, const char *e1, long long v2, const char *e2, void *extra) 452{ 453 assertion_count(file, line); 454 if (v1 == v2) 455 return (1); 456 failure_start(file, line, "%s != %s", e1, e2); 457 logprintf(" %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1); 458 logprintf(" %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2); 459 failure_finish(extra); 460 return (0); 461} 462 463/* 464 * Utility to convert a single UTF-8 sequence. 465 */ 466static int 467_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) 468{ 469 static const char utf8_count[256] = { 470 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */ 471 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */ 472 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */ 473 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */ 474 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */ 475 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */ 476 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */ 477 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */ 478 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */ 479 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */ 480 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */ 481 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */ 482 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */ 483 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */ 484 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */ 485 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ 486 }; 487 int ch; 488 int cnt; 489 uint32_t wc; 490 491 *pwc = 0; 492 493 /* Sanity check. */ 494 if (n == 0) 495 return (0); 496 /* 497 * Decode 1-4 bytes depending on the value of the first byte. 498 */ 499 ch = (unsigned char)*s; 500 if (ch == 0) 501 return (0); /* Standard: return 0 for end-of-string. */ 502 cnt = utf8_count[ch]; 503 504 /* Invalide sequence or there are not plenty bytes. */ 505 if (n < (size_t)cnt) 506 return (-1); 507 508 /* Make a Unicode code point from a single UTF-8 sequence. */ 509 switch (cnt) { 510 case 1: /* 1 byte sequence. */ 511 *pwc = ch & 0x7f; 512 return (cnt); 513 case 2: /* 2 bytes sequence. */ 514 if ((s[1] & 0xc0) != 0x80) return (-1); 515 *pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f); 516 return (cnt); 517 case 3: /* 3 bytes sequence. */ 518 if ((s[1] & 0xc0) != 0x80) return (-1); 519 if ((s[2] & 0xc0) != 0x80) return (-1); 520 wc = ((ch & 0x0f) << 12) 521 | ((s[1] & 0x3f) << 6) 522 | (s[2] & 0x3f); 523 if (wc < 0x800) 524 return (-1);/* Overlong sequence. */ 525 break; 526 case 4: /* 4 bytes sequence. */ 527 if (n < 4) 528 return (-1); 529 if ((s[1] & 0xc0) != 0x80) return (-1); 530 if ((s[2] & 0xc0) != 0x80) return (-1); 531 if ((s[3] & 0xc0) != 0x80) return (-1); 532 wc = ((ch & 0x07) << 18) 533 | ((s[1] & 0x3f) << 12) 534 | ((s[2] & 0x3f) << 6) 535 | (s[3] & 0x3f); 536 if (wc < 0x10000) 537 return (-1);/* Overlong sequence. */ 538 break; 539 default: 540 return (-1); 541 } 542 543 /* The code point larger than 0x10FFFF is not leagal 544 * Unicode values. */ 545 if (wc > 0x10FFFF) 546 return (-1); 547 /* Correctly gets a Unicode, returns used bytes. */ 548 *pwc = wc; 549 return (cnt); 550} 551 552static void strdump(const char *e, const char *p, int ewidth, int utf8) 553{ 554 const char *q = p; 555 556 logprintf(" %*s = ", ewidth, e); 557 if (p == NULL) { 558 logprintf("NULL\n"); 559 return; 560 } 561 logprintf("\""); 562 while (*p != '\0') { 563 unsigned int c = 0xff & *p++; 564 switch (c) { 565 case '\a': printf("\a"); break; 566 case '\b': printf("\b"); break; 567 case '\n': printf("\n"); break; 568 case '\r': printf("\r"); break; 569 default: 570 if (c >= 32 && c < 127) 571 logprintf("%c", c); 572 else 573 logprintf("\\x%02X", c); 574 } 575 } 576 logprintf("\""); 577 logprintf(" (length %d)", q == NULL ? -1 : (int)strlen(q)); 578 579 /* 580 * If the current string is UTF-8, dump its code points. 581 */ 582 if (utf8) { 583 size_t len; 584 uint32_t uc; 585 int n; 586 int cnt = 0; 587 588 p = q; 589 len = strlen(p); 590 logprintf(" ["); 591 while ((n = _utf8_to_unicode(&uc, p, len)) > 0) { 592 if (p != q) 593 logprintf(" "); 594 logprintf("%04X", uc); 595 p += n; 596 len -= n; 597 cnt++; 598 } 599 logprintf("]"); 600 logprintf(" (count %d", cnt); 601 if (n < 0) { 602 logprintf(",unknown %d bytes", len); 603 } 604 logprintf(")"); 605 606 } 607 logprintf("\n"); 608} 609 610/* Verify two strings are equal, dump them if not. */ 611int 612assertion_equal_string(const char *file, int line, 613 const char *v1, const char *e1, 614 const char *v2, const char *e2, 615 void *extra, int utf8) 616{ 617 int l1, l2; 618 619 assertion_count(file, line); 620 if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0)) 621 return (1); 622 failure_start(file, line, "%s != %s", e1, e2); 623 l1 = strlen(e1); 624 l2 = strlen(e2); 625 if (l1 < l2) 626 l1 = l2; 627 strdump(e1, v1, l1, utf8); 628 strdump(e2, v2, l1, utf8); 629 failure_finish(extra); 630 return (0); 631} 632 633static void 634wcsdump(const char *e, const wchar_t *w) 635{ 636 logprintf(" %s = ", e); 637 if (w == NULL) { 638 logprintf("(null)"); 639 return; 640 } 641 logprintf("\""); 642 while (*w != L'\0') { 643 unsigned int c = *w++; 644 if (c >= 32 && c < 127) 645 logprintf("%c", c); 646 else if (c < 256) 647 logprintf("\\x%02X", c); 648 else if (c < 0x10000) 649 logprintf("\\u%04X", c); 650 else 651 logprintf("\\U%08X", c); 652 } 653 logprintf("\"\n"); 654} 655 656#ifndef HAVE_WCSCMP 657static int 658wcscmp(const wchar_t *s1, const wchar_t *s2) 659{ 660 661 while (*s1 == *s2++) { 662 if (*s1++ == L'\0') 663 return 0; 664 } 665 if (*s1 > *--s2) 666 return 1; 667 else 668 return -1; 669} 670#endif 671 672/* Verify that two wide strings are equal, dump them if not. */ 673int 674assertion_equal_wstring(const char *file, int line, 675 const wchar_t *v1, const char *e1, 676 const wchar_t *v2, const char *e2, 677 void *extra) 678{ 679 assertion_count(file, line); 680 if (v1 == v2) 681 return (1); 682 if (v1 != NULL && v2 != NULL && wcscmp(v1, v2) == 0) 683 return (1); 684 failure_start(file, line, "%s != %s", e1, e2); 685 wcsdump(e1, v1); 686 wcsdump(e2, v2); 687 failure_finish(extra); 688 return (0); 689} 690 691/* 692 * Pretty standard hexdump routine. As a bonus, if ref != NULL, then 693 * any bytes in p that differ from ref will be highlighted with '_' 694 * before and after the hex value. 695 */ 696static void 697hexdump(const char *p, const char *ref, size_t l, size_t offset) 698{ 699 size_t i, j; 700 char sep; 701 702 if (p == NULL) { 703 logprintf("(null)\n"); 704 return; 705 } 706 for(i=0; i < l; i+=16) { 707 logprintf("%04x", (unsigned)(i + offset)); 708 sep = ' '; 709 for (j = 0; j < 16 && i + j < l; j++) { 710 if (ref != NULL && p[i + j] != ref[i + j]) 711 sep = '_'; 712 logprintf("%c%02x", sep, 0xff & (int)p[i+j]); 713 if (ref != NULL && p[i + j] == ref[i + j]) 714 sep = ' '; 715 } 716 for (; j < 16; j++) { 717 logprintf("%c ", sep); 718 sep = ' '; 719 } 720 logprintf("%c", sep); 721 for (j=0; j < 16 && i + j < l; j++) { 722 int c = p[i + j]; 723 if (c >= ' ' && c <= 126) 724 logprintf("%c", c); 725 else 726 logprintf("."); 727 } 728 logprintf("\n"); 729 } 730} 731 732/* Verify that two blocks of memory are the same, display the first 733 * block of differences if they're not. */ 734int 735assertion_equal_mem(const char *file, int line, 736 const void *_v1, const char *e1, 737 const void *_v2, const char *e2, 738 size_t l, const char *ld, void *extra) 739{ 740 const char *v1 = (const char *)_v1; 741 const char *v2 = (const char *)_v2; 742 size_t offset; 743 744 assertion_count(file, line); 745 if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0)) 746 return (1); 747 748 failure_start(file, line, "%s != %s", e1, e2); 749 logprintf(" size %s = %d\n", ld, (int)l); 750 /* Dump 48 bytes (3 lines) so that the first difference is 751 * in the second line. */ 752 offset = 0; 753 while (l > 64 && memcmp(v1, v2, 32) == 0) { 754 /* Two lines agree, so step forward one line. */ 755 v1 += 16; 756 v2 += 16; 757 l -= 16; 758 offset += 16; 759 } 760 logprintf(" Dump of %s\n", e1); 761 hexdump(v1, v2, l < 128 ? l : 128, offset); 762 logprintf(" Dump of %s\n", e2); 763 hexdump(v2, v1, l < 128 ? l : 128, offset); 764 logprintf("\n"); 765 failure_finish(extra); 766 return (0); 767} 768 769/* Verify that the named file exists and is empty. */ 770int 771assertion_empty_file(const char *filename, int line, const char *f1) 772{ 773 char buff[1024]; 774 struct stat st; 775 ssize_t s; 776 FILE *f; 777 778 assertion_count(filename, line); 779 780 if (stat(f1, &st) != 0) { 781 failure_start(filename, line, "Stat failed: %s", f1); 782 failure_finish(NULL); 783 return (0); 784 } 785 if (st.st_size == 0) 786 return (1); 787 788 failure_start(filename, line, "File should be empty: %s", f1); 789 logprintf(" File size: %d\n", (int)st.st_size); 790 logprintf(" Contents:\n"); 791 f = fopen(f1, "rb"); 792 if (f == NULL) { 793 logprintf(" Unable to open %s\n", f1); 794 } else { 795 s = ((off_t)sizeof(buff) < st.st_size) ? 796 (ssize_t)sizeof(buff) : (ssize_t)st.st_size; 797 s = fread(buff, 1, s, f); 798 hexdump(buff, NULL, s, 0); 799 fclose(f); 800 } 801 failure_finish(NULL); 802 return (0); 803} 804 805/* Verify that the named file exists and is not empty. */ 806int 807assertion_non_empty_file(const char *filename, int line, const char *f1) 808{ 809 struct stat st; 810 811 assertion_count(filename, line); 812 813 if (stat(f1, &st) != 0) { 814 failure_start(filename, line, "Stat failed: %s", f1); 815 failure_finish(NULL); 816 return (0); 817 } 818 if (st.st_size == 0) { 819 failure_start(filename, line, "File empty: %s", f1); 820 failure_finish(NULL); 821 return (0); 822 } 823 return (1); 824} 825 826/* Verify that two files have the same contents. */ 827/* TODO: hexdump the first bytes that actually differ. */ 828int 829assertion_equal_file(const char *filename, int line, const char *fn1, const char *fn2) 830{ 831 char buff1[1024]; 832 char buff2[1024]; 833 FILE *f1, *f2; 834 int n1, n2; 835 836 assertion_count(filename, line); 837 838 f1 = fopen(fn1, "rb"); 839 f2 = fopen(fn2, "rb"); 840 for (;;) { 841 n1 = fread(buff1, 1, sizeof(buff1), f1); 842 n2 = fread(buff2, 1, sizeof(buff2), f2); 843 if (n1 != n2) 844 break; 845 if (n1 == 0 && n2 == 0) { 846 fclose(f1); 847 fclose(f2); 848 return (1); 849 } 850 if (memcmp(buff1, buff2, n1) != 0) 851 break; 852 } 853 fclose(f1); 854 fclose(f2); 855 failure_start(filename, line, "Files not identical"); 856 logprintf(" file1=\"%s\"\n", fn1); 857 logprintf(" file2=\"%s\"\n", fn2); 858 failure_finish(NULL); 859 return (0); 860} 861 862/* Verify that the named file does exist. */ 863int 864assertion_file_exists(const char *filename, int line, const char *f) 865{ 866 assertion_count(filename, line); 867 868#if defined(_WIN32) && !defined(__CYGWIN__) 869 if (!_access(f, 0)) 870 return (1); 871#else 872 if (!access(f, F_OK)) 873 return (1); 874#endif 875 failure_start(filename, line, "File should exist: %s", f); 876 failure_finish(NULL); 877 return (0); 878} 879 880/* Verify that the named file doesn't exist. */ 881int 882assertion_file_not_exists(const char *filename, int line, const char *f) 883{ 884 assertion_count(filename, line); 885 886#if defined(_WIN32) && !defined(__CYGWIN__) 887 if (_access(f, 0)) 888 return (1); 889#else 890 if (access(f, F_OK)) 891 return (1); 892#endif 893 failure_start(filename, line, "File should not exist: %s", f); 894 failure_finish(NULL); 895 return (0); 896} 897 898/* Compare the contents of a file to a block of memory. */ 899int 900assertion_file_contents(const char *filename, int line, const void *buff, int s, const char *fn) 901{ 902 char *contents; 903 FILE *f; 904 int n; 905 906 assertion_count(filename, line); 907 908 f = fopen(fn, "rb"); 909 if (f == NULL) { 910 failure_start(filename, line, 911 "File should exist: %s", fn); 912 failure_finish(NULL); 913 return (0); 914 } 915 contents = malloc(s * 2); 916 n = fread(contents, 1, s * 2, f); 917 fclose(f); 918 if (n == s && memcmp(buff, contents, s) == 0) { 919 free(contents); 920 return (1); 921 } 922 failure_start(filename, line, "File contents don't match"); 923 logprintf(" file=\"%s\"\n", fn); 924 if (n > 0) 925 hexdump(contents, buff, n > 512 ? 512 : n, 0); 926 else { 927 logprintf(" File empty, contents should be:\n"); 928 hexdump(buff, NULL, s > 512 ? 512 : s, 0); 929 } 930 failure_finish(NULL); 931 free(contents); 932 return (0); 933} 934 935/* Check the contents of a text file, being tolerant of line endings. */ 936int 937assertion_text_file_contents(const char *filename, int line, const char *buff, const char *fn) 938{ 939 char *contents; 940 const char *btxt, *ftxt; 941 FILE *f; 942 int n, s; 943 944 assertion_count(filename, line); 945 f = fopen(fn, "r"); 946 if (f == NULL) { 947 failure_start(filename, line, 948 "File doesn't exist: %s", fn); 949 failure_finish(NULL); 950 return (0); 951 } 952 s = strlen(buff); 953 contents = malloc(s * 2 + 128); 954 n = fread(contents, 1, s * 2 + 128 - 1, f); 955 if (n >= 0) 956 contents[n] = '\0'; 957 fclose(f); 958 /* Compare texts. */ 959 btxt = buff; 960 ftxt = (const char *)contents; 961 while (*btxt != '\0' && *ftxt != '\0') { 962 if (*btxt == *ftxt) { 963 ++btxt; 964 ++ftxt; 965 continue; 966 } 967 if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') { 968 /* Pass over different new line characters. */ 969 ++btxt; 970 ftxt += 2; 971 continue; 972 } 973 break; 974 } 975 if (*btxt == '\0' && *ftxt == '\0') { 976 free(contents); 977 return (1); 978 } 979 failure_start(filename, line, "Contents don't match"); 980 logprintf(" file=\"%s\"\n", fn); 981 if (n > 0) { 982 hexdump(contents, buff, n, 0); 983 logprintf(" expected\n", fn); 984 hexdump(buff, contents, s, 0); 985 } else { 986 logprintf(" File empty, contents should be:\n"); 987 hexdump(buff, NULL, s, 0); 988 } 989 failure_finish(NULL); 990 free(contents); 991 return (0); 992} 993 994/* Verify that a text file contains the specified lines, regardless of order */ 995/* This could be more efficient if we sorted both sets of lines, etc, but 996 * since this is used only for testing and only ever deals with a dozen or so 997 * lines at a time, this relatively crude approach is just fine. */ 998int 999assertion_file_contains_lines_any_order(const char *file, int line, 1000 const char *pathname, const char *lines[]) 1001{ 1002 char *buff; 1003 size_t buff_size; 1004 size_t expected_count, actual_count, i, j; 1005 char **expected; 1006 char *p, **actual; 1007 char c; 1008 int expected_failure = 0, actual_failure = 0; 1009 1010 assertion_count(file, line); 1011 1012 buff = slurpfile(&buff_size, "%s", pathname); 1013 if (buff == NULL) { 1014 failure_start(pathname, line, "Can't read file: %s", pathname); 1015 failure_finish(NULL); 1016 return (0); 1017 } 1018 1019 /* Make a copy of the provided lines and count up the expected file size. */ 1020 expected_count = 0; 1021 for (i = 0; lines[i] != NULL; ++i) { 1022 } 1023 expected_count = i; 1024 expected = malloc(sizeof(char *) * expected_count); 1025 for (i = 0; lines[i] != NULL; ++i) { 1026 expected[i] = strdup(lines[i]); 1027 } 1028 1029 /* Break the file into lines */ 1030 actual_count = 0; 1031 for (c = '\0', p = buff; p < buff + buff_size; ++p) { 1032 if (*p == '\x0d' || *p == '\x0a') 1033 *p = '\0'; 1034 if (c == '\0' && *p != '\0') 1035 ++actual_count; 1036 c = *p; 1037 } 1038 actual = malloc(sizeof(char *) * actual_count); 1039 for (j = 0, p = buff; p < buff + buff_size; p += 1 + strlen(p)) { 1040 if (*p != '\0') { 1041 actual[j] = p; 1042 ++j; 1043 } 1044 } 1045 1046 /* Erase matching lines from both lists */ 1047 for (i = 0; i < expected_count; ++i) { 1048 if (expected[i] == NULL) 1049 continue; 1050 for (j = 0; j < actual_count; ++j) { 1051 if (actual[j] == NULL) 1052 continue; 1053 if (strcmp(expected[i], actual[j]) == 0) { 1054 free(expected[i]); 1055 expected[i] = NULL; 1056 actual[j] = NULL; 1057 break; 1058 } 1059 } 1060 } 1061 1062 /* If there's anything left, it's a failure */ 1063 for (i = 0; i < expected_count; ++i) { 1064 if (expected[i] != NULL) 1065 ++expected_failure; 1066 } 1067 for (j = 0; j < actual_count; ++j) { 1068 if (actual[j] != NULL) 1069 ++actual_failure; 1070 } 1071 if (expected_failure == 0 && actual_failure == 0) { 1072 free(buff); 1073 free(expected); 1074 free(actual); 1075 return (1); 1076 } 1077 failure_start(file, line, "File doesn't match: %s", pathname); 1078 for (i = 0; i < expected_count; ++i) { 1079 if (expected[i] != NULL) { 1080 logprintf(" Expected but not present: %s\n", expected[i]); 1081 free(expected[i]); 1082 } 1083 } 1084 for (j = 0; j < actual_count; ++j) { 1085 if (actual[j] != NULL) 1086 logprintf(" Present but not expected: %s\n", actual[j]); 1087 } 1088 failure_finish(NULL); 1089 free(buff); 1090 free(expected); 1091 free(actual); 1092 return (0); 1093} 1094 1095/* Test that two paths point to the same file. */ 1096/* As a side-effect, asserts that both files exist. */ 1097static int 1098is_hardlink(const char *file, int line, 1099 const char *path1, const char *path2) 1100{ 1101#if defined(_WIN32) && !defined(__CYGWIN__) 1102 BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2; 1103 int r; 1104 1105 assertion_count(file, line); 1106 r = my_GetFileInformationByName(path1, &bhfi1); 1107 if (r == 0) { 1108 failure_start(file, line, "File %s can't be inspected?", path1); 1109 failure_finish(NULL); 1110 return (0); 1111 } 1112 r = my_GetFileInformationByName(path2, &bhfi2); 1113 if (r == 0) { 1114 failure_start(file, line, "File %s can't be inspected?", path2); 1115 failure_finish(NULL); 1116 return (0); 1117 } 1118 return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber 1119 && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh 1120 && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow); 1121#else 1122 struct stat st1, st2; 1123 int r; 1124 1125 assertion_count(file, line); 1126 r = lstat(path1, &st1); 1127 if (r != 0) { 1128 failure_start(file, line, "File should exist: %s", path1); 1129 failure_finish(NULL); 1130 return (0); 1131 } 1132 r = lstat(path2, &st2); 1133 if (r != 0) { 1134 failure_start(file, line, "File should exist: %s", path2); 1135 failure_finish(NULL); 1136 return (0); 1137 } 1138 return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev); 1139#endif 1140} 1141 1142int 1143assertion_is_hardlink(const char *file, int line, 1144 const char *path1, const char *path2) 1145{ 1146 if (is_hardlink(file, line, path1, path2)) 1147 return (1); 1148 failure_start(file, line, 1149 "Files %s and %s are not hardlinked", path1, path2); 1150 failure_finish(NULL); 1151 return (0); 1152} 1153 1154int 1155assertion_is_not_hardlink(const char *file, int line, 1156 const char *path1, const char *path2) 1157{ 1158 if (!is_hardlink(file, line, path1, path2)) 1159 return (1); 1160 failure_start(file, line, 1161 "Files %s and %s should not be hardlinked", path1, path2); 1162 failure_finish(NULL); 1163 return (0); 1164} 1165 1166/* Verify a/b/mtime of 'pathname'. */ 1167/* If 'recent', verify that it's within last 10 seconds. */ 1168static int 1169assertion_file_time(const char *file, int line, 1170 const char *pathname, long t, long nsec, char type, int recent) 1171{ 1172 long long filet, filet_nsec; 1173 int r; 1174 1175#if defined(_WIN32) && !defined(__CYGWIN__) 1176#define EPOC_TIME (116444736000000000ULL) 1177 FILETIME ftime, fbirthtime, fatime, fmtime; 1178 ULARGE_INTEGER wintm; 1179 HANDLE h; 1180 ftime.dwLowDateTime = 0; 1181 ftime.dwHighDateTime = 0; 1182 1183 assertion_count(file, line); 1184 /* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open 1185 * a directory file. If not, CreateFile() will fail when 1186 * the pathname is a directory. */ 1187 h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL, 1188 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 1189 if (h == INVALID_HANDLE_VALUE) { 1190 failure_start(file, line, "Can't access %s\n", pathname); 1191 failure_finish(NULL); 1192 return (0); 1193 } 1194 r = GetFileTime(h, &fbirthtime, &fatime, &fmtime); 1195 switch (type) { 1196 case 'a': ftime = fatime; break; 1197 case 'b': ftime = fbirthtime; break; 1198 case 'm': ftime = fmtime; break; 1199 } 1200 CloseHandle(h); 1201 if (r == 0) { 1202 failure_start(file, line, "Can't GetFileTime %s\n", pathname); 1203 failure_finish(NULL); 1204 return (0); 1205 } 1206 wintm.LowPart = ftime.dwLowDateTime; 1207 wintm.HighPart = ftime.dwHighDateTime; 1208 filet = (wintm.QuadPart - EPOC_TIME) / 10000000; 1209 filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100; 1210 nsec = (nsec / 100) * 100; /* Round the request */ 1211#else 1212 struct stat st; 1213 1214 assertion_count(file, line); 1215 r = lstat(pathname, &st); 1216 if (r != 0) { 1217 failure_start(file, line, "Can't stat %s\n", pathname); 1218 failure_finish(NULL); 1219 return (0); 1220 } 1221 switch (type) { 1222 case 'a': filet = st.st_atime; break; 1223 case 'm': filet = st.st_mtime; break; 1224 case 'b': filet = 0; break; 1225 default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); 1226 exit(1); 1227 } 1228#if defined(__FreeBSD__) 1229 switch (type) { 1230 case 'a': filet_nsec = st.st_atimespec.tv_nsec; break; 1231 case 'b': filet = st.st_birthtime; 1232 filet_nsec = st.st_birthtimespec.tv_nsec; break; 1233 case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break; 1234 default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); 1235 exit(1); 1236 } 1237 /* FreeBSD generally only stores to microsecond res, so round. */ 1238 filet_nsec = (filet_nsec / 1000) * 1000; 1239 nsec = (nsec / 1000) * 1000; 1240#else 1241 filet_nsec = nsec = 0; /* Generic POSIX only has whole seconds. */ 1242 if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */ 1243#if defined(__HAIKU__) 1244 if (type == 'a') return (1); /* Haiku doesn't have atime. */ 1245#endif 1246#endif 1247#endif 1248 if (recent) { 1249 /* Check that requested time is up-to-date. */ 1250 time_t now = time(NULL); 1251 if (filet < now - 10 || filet > now + 1) { 1252 failure_start(file, line, 1253 "File %s has %ctime %lld, %lld seconds ago\n", 1254 pathname, type, filet, now - filet); 1255 failure_finish(NULL); 1256 return (0); 1257 } 1258 } else if (filet != t || filet_nsec != nsec) { 1259 failure_start(file, line, 1260 "File %s has %ctime %lld.%09lld, expected %lld.%09lld", 1261 pathname, type, filet, filet_nsec, t, nsec); 1262 failure_finish(NULL); 1263 return (0); 1264 } 1265 return (1); 1266} 1267 1268/* Verify atime of 'pathname'. */ 1269int 1270assertion_file_atime(const char *file, int line, 1271 const char *pathname, long t, long nsec) 1272{ 1273 return assertion_file_time(file, line, pathname, t, nsec, 'a', 0); 1274} 1275 1276/* Verify atime of 'pathname' is up-to-date. */ 1277int 1278assertion_file_atime_recent(const char *file, int line, const char *pathname) 1279{ 1280 return assertion_file_time(file, line, pathname, 0, 0, 'a', 1); 1281} 1282 1283/* Verify birthtime of 'pathname'. */ 1284int 1285assertion_file_birthtime(const char *file, int line, 1286 const char *pathname, long t, long nsec) 1287{ 1288 return assertion_file_time(file, line, pathname, t, nsec, 'b', 0); 1289} 1290 1291/* Verify birthtime of 'pathname' is up-to-date. */ 1292int 1293assertion_file_birthtime_recent(const char *file, int line, 1294 const char *pathname) 1295{ 1296 return assertion_file_time(file, line, pathname, 0, 0, 'b', 1); 1297} 1298 1299/* Verify mtime of 'pathname'. */ 1300int 1301assertion_file_mtime(const char *file, int line, 1302 const char *pathname, long t, long nsec) 1303{ 1304 return assertion_file_time(file, line, pathname, t, nsec, 'm', 0); 1305} 1306 1307/* Verify mtime of 'pathname' is up-to-date. */ 1308int 1309assertion_file_mtime_recent(const char *file, int line, const char *pathname) 1310{ 1311 return assertion_file_time(file, line, pathname, 0, 0, 'm', 1); 1312} 1313 1314/* Verify number of links to 'pathname'. */ 1315int 1316assertion_file_nlinks(const char *file, int line, 1317 const char *pathname, int nlinks) 1318{ 1319#if defined(_WIN32) && !defined(__CYGWIN__) 1320 BY_HANDLE_FILE_INFORMATION bhfi; 1321 int r; 1322 1323 assertion_count(file, line); 1324 r = my_GetFileInformationByName(pathname, &bhfi); 1325 if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks) 1326 return (1); 1327 failure_start(file, line, "File %s has %d links, expected %d", 1328 pathname, bhfi.nNumberOfLinks, nlinks); 1329 failure_finish(NULL); 1330 return (0); 1331#else 1332 struct stat st; 1333 int r; 1334 1335 assertion_count(file, line); 1336 r = lstat(pathname, &st); 1337 if (r == 0 && (int)st.st_nlink == nlinks) 1338 return (1); 1339 failure_start(file, line, "File %s has %d links, expected %d", 1340 pathname, st.st_nlink, nlinks); 1341 failure_finish(NULL); 1342 return (0); 1343#endif 1344} 1345 1346/* Verify size of 'pathname'. */ 1347int 1348assertion_file_size(const char *file, int line, const char *pathname, long size) 1349{ 1350 int64_t filesize; 1351 int r; 1352 1353 assertion_count(file, line); 1354#if defined(_WIN32) && !defined(__CYGWIN__) 1355 { 1356 BY_HANDLE_FILE_INFORMATION bhfi; 1357 r = !my_GetFileInformationByName(pathname, &bhfi); 1358 filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow; 1359 } 1360#else 1361 { 1362 struct stat st; 1363 r = lstat(pathname, &st); 1364 filesize = st.st_size; 1365 } 1366#endif 1367 if (r == 0 && filesize == size) 1368 return (1); 1369 failure_start(file, line, "File %s has size %ld, expected %ld", 1370 pathname, (long)filesize, (long)size); 1371 failure_finish(NULL); 1372 return (0); 1373} 1374 1375/* Assert that 'pathname' is a dir. If mode >= 0, verify that too. */ 1376int 1377assertion_is_dir(const char *file, int line, const char *pathname, int mode) 1378{ 1379 struct stat st; 1380 int r; 1381 1382#if defined(_WIN32) && !defined(__CYGWIN__) 1383 (void)mode; /* UNUSED */ 1384#endif 1385 assertion_count(file, line); 1386 r = lstat(pathname, &st); 1387 if (r != 0) { 1388 failure_start(file, line, "Dir should exist: %s", pathname); 1389 failure_finish(NULL); 1390 return (0); 1391 } 1392 if (!S_ISDIR(st.st_mode)) { 1393 failure_start(file, line, "%s is not a dir", pathname); 1394 failure_finish(NULL); 1395 return (0); 1396 } 1397#if !defined(_WIN32) || defined(__CYGWIN__) 1398 /* Windows doesn't handle permissions the same way as POSIX, 1399 * so just ignore the mode tests. */ 1400 /* TODO: Can we do better here? */ 1401 if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) { 1402 failure_start(file, line, "Dir %s has wrong mode", pathname); 1403 logprintf(" Expected: 0%3o\n", mode); 1404 logprintf(" Found: 0%3o\n", st.st_mode & 07777); 1405 failure_finish(NULL); 1406 return (0); 1407 } 1408#endif 1409 return (1); 1410} 1411 1412/* Verify that 'pathname' is a regular file. If 'mode' is >= 0, 1413 * verify that too. */ 1414int 1415assertion_is_reg(const char *file, int line, const char *pathname, int mode) 1416{ 1417 struct stat st; 1418 int r; 1419 1420#if defined(_WIN32) && !defined(__CYGWIN__) 1421 (void)mode; /* UNUSED */ 1422#endif 1423 assertion_count(file, line); 1424 r = lstat(pathname, &st); 1425 if (r != 0 || !S_ISREG(st.st_mode)) { 1426 failure_start(file, line, "File should exist: %s", pathname); 1427 failure_finish(NULL); 1428 return (0); 1429 } 1430#if !defined(_WIN32) || defined(__CYGWIN__) 1431 /* Windows doesn't handle permissions the same way as POSIX, 1432 * so just ignore the mode tests. */ 1433 /* TODO: Can we do better here? */ 1434 if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) { 1435 failure_start(file, line, "File %s has wrong mode", pathname); 1436 logprintf(" Expected: 0%3o\n", mode); 1437 logprintf(" Found: 0%3o\n", st.st_mode & 07777); 1438 failure_finish(NULL); 1439 return (0); 1440 } 1441#endif 1442 return (1); 1443} 1444 1445/* Check whether 'pathname' is a symbolic link. If 'contents' is 1446 * non-NULL, verify that the symlink has those contents. */ 1447static int 1448is_symlink(const char *file, int line, 1449 const char *pathname, const char *contents) 1450{ 1451#if defined(_WIN32) && !defined(__CYGWIN__) 1452 (void)pathname; /* UNUSED */ 1453 (void)contents; /* UNUSED */ 1454 assertion_count(file, line); 1455 /* Windows sort-of has real symlinks, but they're only usable 1456 * by privileged users and are crippled even then, so there's 1457 * really not much point in bothering with this. */ 1458 return (0); 1459#else 1460 char buff[300]; 1461 struct stat st; 1462 ssize_t linklen; 1463 int r; 1464 1465 assertion_count(file, line); 1466 r = lstat(pathname, &st); 1467 if (r != 0) { 1468 failure_start(file, line, 1469 "Symlink should exist: %s", pathname); 1470 failure_finish(NULL); 1471 return (0); 1472 } 1473 if (!S_ISLNK(st.st_mode)) 1474 return (0); 1475 if (contents == NULL) 1476 return (1); 1477 linklen = readlink(pathname, buff, sizeof(buff)); 1478 if (linklen < 0) { 1479 failure_start(file, line, "Can't read symlink %s", pathname); 1480 failure_finish(NULL); 1481 return (0); 1482 } 1483 buff[linklen] = '\0'; 1484 if (strcmp(buff, contents) != 0) 1485 return (0); 1486 return (1); 1487#endif 1488} 1489 1490/* Assert that path is a symlink that (optionally) contains contents. */ 1491int 1492assertion_is_symlink(const char *file, int line, 1493 const char *path, const char *contents) 1494{ 1495 if (is_symlink(file, line, path, contents)) 1496 return (1); 1497 if (contents) 1498 failure_start(file, line, "File %s is not a symlink to %s", 1499 path, contents); 1500 else 1501 failure_start(file, line, "File %s is not a symlink", path); 1502 failure_finish(NULL); 1503 return (0); 1504} 1505 1506 1507/* Create a directory and report any errors. */ 1508int 1509assertion_make_dir(const char *file, int line, const char *dirname, int mode) 1510{ 1511 assertion_count(file, line); 1512#if defined(_WIN32) && !defined(__CYGWIN__) 1513 (void)mode; /* UNUSED */ 1514 if (0 == _mkdir(dirname)) 1515 return (1); 1516#else 1517 if (0 == mkdir(dirname, mode)) 1518 return (1); 1519#endif 1520 failure_start(file, line, "Could not create directory %s", dirname); 1521 failure_finish(NULL); 1522 return(0); 1523} 1524 1525/* Create a file with the specified contents and report any failures. */ 1526int 1527assertion_make_file(const char *file, int line, 1528 const char *path, int mode, int csize, const void *contents) 1529{ 1530#if defined(_WIN32) && !defined(__CYGWIN__) 1531 /* TODO: Rework this to set file mode as well. */ 1532 FILE *f; 1533 (void)mode; /* UNUSED */ 1534 assertion_count(file, line); 1535 f = fopen(path, "wb"); 1536 if (f == NULL) { 1537 failure_start(file, line, "Could not create file %s", path); 1538 failure_finish(NULL); 1539 return (0); 1540 } 1541 if (contents != NULL) { 1542 size_t wsize; 1543 1544 if (csize < 0) 1545 wsize = strlen(contents); 1546 else 1547 wsize = (size_t)csize; 1548 if (wsize != fwrite(contents, 1, wsize, f)) { 1549 fclose(f); 1550 failure_start(file, line, 1551 "Could not write file %s", path); 1552 failure_finish(NULL); 1553 return (0); 1554 } 1555 } 1556 fclose(f); 1557 return (1); 1558#else 1559 int fd; 1560 assertion_count(file, line); 1561 fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644); 1562 if (fd < 0) { 1563 failure_start(file, line, "Could not create %s", path); 1564 failure_finish(NULL); 1565 return (0); 1566 } 1567 if (contents != NULL) { 1568 ssize_t wsize; 1569 1570 if (csize < 0) 1571 wsize = (ssize_t)strlen(contents); 1572 else 1573 wsize = (ssize_t)csize; 1574 if (wsize != write(fd, contents, wsize)) { 1575 close(fd); 1576 failure_start(file, line, 1577 "Could not write to %s", path); 1578 failure_finish(NULL); 1579 return (0); 1580 } 1581 } 1582 close(fd); 1583 return (1); 1584#endif 1585} 1586 1587/* Create a hardlink and report any failures. */ 1588int 1589assertion_make_hardlink(const char *file, int line, 1590 const char *newpath, const char *linkto) 1591{ 1592 int succeeded; 1593 1594 assertion_count(file, line); 1595#if defined(_WIN32) && !defined(__CYGWIN__) 1596 succeeded = my_CreateHardLinkA(newpath, linkto); 1597#elif HAVE_LINK 1598 succeeded = !link(linkto, newpath); 1599#else 1600 succeeded = 0; 1601#endif 1602 if (succeeded) 1603 return (1); 1604 failure_start(file, line, "Could not create hardlink"); 1605 logprintf(" New link: %s\n", newpath); 1606 logprintf(" Old name: %s\n", linkto); 1607 failure_finish(NULL); 1608 return(0); 1609} 1610 1611/* Create a symlink and report any failures. */ 1612int 1613assertion_make_symlink(const char *file, int line, 1614 const char *newpath, const char *linkto) 1615{ 1616#if defined(_WIN32) && !defined(__CYGWIN__) 1617 int targetIsDir = 0; /* TODO: Fix this */ 1618 assertion_count(file, line); 1619 if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir)) 1620 return (1); 1621#elif HAVE_SYMLINK 1622 assertion_count(file, line); 1623 if (0 == symlink(linkto, newpath)) 1624 return (1); 1625#endif 1626 failure_start(file, line, "Could not create symlink"); 1627 logprintf(" New link: %s\n", newpath); 1628 logprintf(" Old name: %s\n", linkto); 1629 failure_finish(NULL); 1630 return(0); 1631} 1632 1633/* Set umask, report failures. */ 1634int 1635assertion_umask(const char *file, int line, int mask) 1636{ 1637 assertion_count(file, line); 1638 (void)file; /* UNUSED */ 1639 (void)line; /* UNUSED */ 1640 umask(mask); 1641 return (1); 1642} 1643 1644/* Set times, report failures. */ 1645int 1646assertion_utimes(const char *file, int line, 1647 const char *pathname, long at, long at_nsec, long mt, long mt_nsec) 1648{ 1649 int r; 1650 1651#if defined(_WIN32) && !defined(__CYGWIN__) 1652#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\ 1653 + (((nsec)/1000)*10)) 1654 HANDLE h; 1655 ULARGE_INTEGER wintm; 1656 FILETIME fatime, fmtime; 1657 FILETIME *pat, *pmt; 1658 1659 assertion_count(file, line); 1660 h = CreateFileA(pathname,GENERIC_READ | GENERIC_WRITE, 1661 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 1662 FILE_FLAG_BACKUP_SEMANTICS, NULL); 1663 if (h == INVALID_HANDLE_VALUE) { 1664 failure_start(file, line, "Can't access %s\n", pathname); 1665 failure_finish(NULL); 1666 return (0); 1667 } 1668 1669 if (at > 0 || at_nsec > 0) { 1670 wintm.QuadPart = WINTIME(at, at_nsec); 1671 fatime.dwLowDateTime = wintm.LowPart; 1672 fatime.dwHighDateTime = wintm.HighPart; 1673 pat = &fatime; 1674 } else 1675 pat = NULL; 1676 if (mt > 0 || mt_nsec > 0) { 1677 wintm.QuadPart = WINTIME(mt, mt_nsec); 1678 fmtime.dwLowDateTime = wintm.LowPart; 1679 fmtime.dwHighDateTime = wintm.HighPart; 1680 pmt = &fmtime; 1681 } else 1682 pmt = NULL; 1683 if (pat != NULL || pmt != NULL) 1684 r = SetFileTime(h, NULL, pat, pmt); 1685 else 1686 r = 1; 1687 CloseHandle(h); 1688 if (r == 0) { 1689 failure_start(file, line, "Can't SetFileTime %s\n", pathname); 1690 failure_finish(NULL); 1691 return (0); 1692 } 1693 return (1); 1694#else /* defined(_WIN32) && !defined(__CYGWIN__) */ 1695 struct stat st; 1696 struct timeval times[2]; 1697 1698#if !defined(__FreeBSD__) 1699 mt_nsec = at_nsec = 0; /* Generic POSIX only has whole seconds. */ 1700#endif 1701 if (mt == 0 && mt_nsec == 0 && at == 0 && at_nsec == 0) 1702 return (1); 1703 1704 r = lstat(pathname, &st); 1705 if (r < 0) { 1706 failure_start(file, line, "Can't stat %s\n", pathname); 1707 failure_finish(NULL); 1708 return (0); 1709 } 1710 1711 if (mt == 0 && mt_nsec == 0) { 1712 mt = st.st_mtime; 1713#if defined(__FreeBSD__) 1714 mt_nsec = st.st_mtimespec.tv_nsec; 1715 /* FreeBSD generally only stores to microsecond res, so round. */ 1716 mt_nsec = (mt_nsec / 1000) * 1000; 1717#endif 1718 } 1719 if (at == 0 && at_nsec == 0) { 1720 at = st.st_atime; 1721#if defined(__FreeBSD__) 1722 at_nsec = st.st_atimespec.tv_nsec; 1723 /* FreeBSD generally only stores to microsecond res, so round. */ 1724 at_nsec = (at_nsec / 1000) * 1000; 1725#endif 1726 } 1727 1728 times[1].tv_sec = mt; 1729 times[1].tv_usec = mt_nsec / 1000; 1730 1731 times[0].tv_sec = at; 1732 times[0].tv_usec = at_nsec / 1000; 1733 1734#ifdef HAVE_LUTIMES 1735 r = lutimes(pathname, times); 1736#else 1737 r = utimes(pathname, times); 1738#endif 1739 if (r < 0) { 1740 failure_start(file, line, "Can't utimes %s\n", pathname); 1741 failure_finish(NULL); 1742 return (0); 1743 } 1744 return (1); 1745#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ 1746} 1747 1748/* Set nodump, report failures. */ 1749int 1750assertion_nodump(const char *file, int line, const char *pathname) 1751{ 1752#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) 1753 int r; 1754 1755 assertion_count(file, line); 1756 r = chflags(pathname, UF_NODUMP); 1757 if (r < 0) { 1758 failure_start(file, line, "Can't set nodump %s\n", pathname); 1759 failure_finish(NULL); 1760 return (0); 1761 } 1762#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ 1763 && defined(EXT2_NODUMP_FL) 1764 int fd, r, flags; 1765 1766 assertion_count(file, line); 1767 fd = open(pathname, O_RDONLY | O_NONBLOCK); 1768 if (fd < 0) { 1769 failure_start(file, line, "Can't open %s\n", pathname); 1770 failure_finish(NULL); 1771 return (0); 1772 } 1773 r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); 1774 if (r < 0) { 1775 failure_start(file, line, "Can't get flags %s\n", pathname); 1776 failure_finish(NULL); 1777 return (0); 1778 } 1779 flags |= EXT2_NODUMP_FL; 1780 r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); 1781 if (r < 0) { 1782 failure_start(file, line, "Can't set nodump %s\n", pathname); 1783 failure_finish(NULL); 1784 return (0); 1785 } 1786 close(fd); 1787#else 1788 (void)pathname; /* UNUSED */ 1789 assertion_count(file, line); 1790#endif 1791 return (1); 1792} 1793 1794/* 1795 * 1796 * UTILITIES for use by tests. 1797 * 1798 */ 1799 1800/* 1801 * Check whether platform supports symlinks. This is intended 1802 * for tests to use in deciding whether to bother testing symlink 1803 * support; if the platform doesn't support symlinks, there's no point 1804 * in checking whether the program being tested can create them. 1805 * 1806 * Note that the first time this test is called, we actually go out to 1807 * disk to create and verify a symlink. This is necessary because 1808 * symlink support is actually a property of a particular filesystem 1809 * and can thus vary between directories on a single system. After 1810 * the first call, this returns the cached result from memory, so it's 1811 * safe to call it as often as you wish. 1812 */ 1813int 1814canSymlink(void) 1815{ 1816 /* Remember the test result */ 1817 static int value = 0, tested = 0; 1818 if (tested) 1819 return (value); 1820 1821 ++tested; 1822 assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a"); 1823 /* Note: Cygwin has its own symlink() emulation that does not 1824 * use the Win32 CreateSymbolicLink() function. */ 1825#if defined(_WIN32) && !defined(__CYGWIN__) 1826 value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0) 1827 && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0"); 1828#elif HAVE_SYMLINK 1829 value = (0 == symlink("canSymlink.0", "canSymlink.1")) 1830 && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0"); 1831#endif 1832 return (value); 1833} 1834 1835/* 1836 * Can this platform run the gzip program? 1837 */ 1838/* Platform-dependent options for hiding the output of a subcommand. */ 1839#if defined(_WIN32) && !defined(__CYGWIN__) 1840static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */ 1841#else 1842static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */ 1843#endif 1844int 1845canGzip(void) 1846{ 1847 static int tested = 0, value = 0; 1848 if (!tested) { 1849 tested = 1; 1850 if (systemf("gzip -V %s", redirectArgs) == 0) 1851 value = 1; 1852 } 1853 return (value); 1854} 1855 1856/* 1857 * Can this platform run the gunzip program? 1858 */ 1859int 1860canGunzip(void) 1861{ 1862 static int tested = 0, value = 0; 1863 if (!tested) { 1864 tested = 1; 1865 if (systemf("gunzip -V %s", redirectArgs) == 0) 1866 value = 1; 1867 } 1868 return (value); 1869} 1870 1871/* 1872 * Can this filesystem handle nodump flags. 1873 */ 1874#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) 1875 1876int 1877canNodump(void) 1878{ 1879 const char *path = "cannodumptest"; 1880 struct stat sb; 1881 1882 assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); 1883 if (chflags(path, UF_NODUMP) < 0) 1884 return (0); 1885 if (stat(path, &sb) < 0) 1886 return (0); 1887 if (sb.st_flags & UF_NODUMP) 1888 return (1); 1889 return (0); 1890} 1891 1892#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ 1893 && defined(EXT2_NODUMP_FL) 1894 1895int 1896canNodump(void) 1897{ 1898 const char *path = "cannodumptest"; 1899 int fd, r, flags; 1900 1901 assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); 1902 fd = open(path, O_RDONLY | O_NONBLOCK); 1903 if (fd < 0) 1904 return (0); 1905 r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); 1906 if (r < 0) 1907 return (0); 1908 flags |= EXT2_NODUMP_FL; 1909 r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); 1910 if (r < 0) 1911 return (0); 1912 close(fd); 1913 fd = open(path, O_RDONLY | O_NONBLOCK); 1914 if (fd < 0) 1915 return (0); 1916 r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); 1917 if (r < 0) 1918 return (0); 1919 close(fd); 1920 if (flags & EXT2_NODUMP_FL) 1921 return (1); 1922 return (0); 1923} 1924 1925#else 1926 1927int 1928canNodump() 1929{ 1930 return (0); 1931} 1932 1933#endif 1934 1935/* 1936 * Sleep as needed; useful for verifying disk timestamp changes by 1937 * ensuring that the wall-clock time has actually changed before we 1938 * go back to re-read something from disk. 1939 */ 1940void 1941sleepUntilAfter(time_t t) 1942{ 1943 while (t >= time(NULL)) 1944#if defined(_WIN32) && !defined(__CYGWIN__) 1945 Sleep(500); 1946#else 1947 sleep(1); 1948#endif 1949} 1950 1951/* 1952 * Call standard system() call, but build up the command line using 1953 * sprintf() conventions. 1954 */ 1955int 1956systemf(const char *fmt, ...) 1957{ 1958 char buff[8192]; 1959 va_list ap; 1960 int r; 1961 1962 va_start(ap, fmt); 1963 vsprintf(buff, fmt, ap); 1964 if (verbosity > VERBOSITY_FULL) 1965 logprintf("Cmd: %s\n", buff); 1966 r = system(buff); 1967 va_end(ap); 1968 return (r); 1969} 1970 1971/* 1972 * Slurp a file into memory for ease of comparison and testing. 1973 * Returns size of file in 'sizep' if non-NULL, null-terminates 1974 * data in memory for ease of use. 1975 */ 1976char * 1977slurpfile(size_t * sizep, const char *fmt, ...) 1978{ 1979 char filename[8192]; 1980 struct stat st; 1981 va_list ap; 1982 char *p; 1983 ssize_t bytes_read; 1984 FILE *f; 1985 int r; 1986 1987 va_start(ap, fmt); 1988 vsprintf(filename, fmt, ap); 1989 va_end(ap); 1990 1991 f = fopen(filename, "rb"); 1992 if (f == NULL) { 1993 /* Note: No error; non-existent file is okay here. */ 1994 return (NULL); 1995 } 1996 r = fstat(fileno(f), &st); 1997 if (r != 0) { 1998 logprintf("Can't stat file %s\n", filename); 1999 fclose(f); 2000 return (NULL); 2001 } 2002 p = malloc((size_t)st.st_size + 1); 2003 if (p == NULL) { 2004 logprintf("Can't allocate %ld bytes of memory to read file %s\n", 2005 (long int)st.st_size, filename); 2006 fclose(f); 2007 return (NULL); 2008 } 2009 bytes_read = fread(p, 1, (size_t)st.st_size, f); 2010 if (bytes_read < st.st_size) { 2011 logprintf("Can't read file %s\n", filename); 2012 fclose(f); 2013 free(p); 2014 return (NULL); 2015 } 2016 p[st.st_size] = '\0'; 2017 if (sizep != NULL) 2018 *sizep = (size_t)st.st_size; 2019 fclose(f); 2020 return (p); 2021} 2022 2023/* Read a uuencoded file from the reference directory, decode, and 2024 * write the result into the current directory. */ 2025#define UUDECODE(c) (((c) - 0x20) & 0x3f) 2026void 2027extract_reference_file(const char *name) 2028{ 2029 char buff[1024]; 2030 FILE *in, *out; 2031 2032 sprintf(buff, "%s/%s.uu", refdir, name); 2033 in = fopen(buff, "r"); 2034 failure("Couldn't open reference file %s", buff); 2035 assert(in != NULL); 2036 if (in == NULL) 2037 return; 2038 /* Read up to and including the 'begin' line. */ 2039 for (;;) { 2040 if (fgets(buff, sizeof(buff), in) == NULL) { 2041 /* TODO: This is a failure. */ 2042 return; 2043 } 2044 if (memcmp(buff, "begin ", 6) == 0) 2045 break; 2046 } 2047 /* Now, decode the rest and write it. */ 2048 /* Not a lot of error checking here; the input better be right. */ 2049 out = fopen(name, "wb"); 2050 while (fgets(buff, sizeof(buff), in) != NULL) { 2051 char *p = buff; 2052 int bytes; 2053 2054 if (memcmp(buff, "end", 3) == 0) 2055 break; 2056 2057 bytes = UUDECODE(*p++); 2058 while (bytes > 0) { 2059 int n = 0; 2060 /* Write out 1-3 bytes from that. */ 2061 if (bytes > 0) { 2062 n = UUDECODE(*p++) << 18; 2063 n |= UUDECODE(*p++) << 12; 2064 fputc(n >> 16, out); 2065 --bytes; 2066 } 2067 if (bytes > 0) { 2068 n |= UUDECODE(*p++) << 6; 2069 fputc((n >> 8) & 0xFF, out); 2070 --bytes; 2071 } 2072 if (bytes > 0) { 2073 n |= UUDECODE(*p++); 2074 fputc(n & 0xFF, out); 2075 --bytes; 2076 } 2077 } 2078 } 2079 fclose(out); 2080 fclose(in); 2081} 2082 2083int 2084is_LargeInode(const char *file) 2085{ 2086#if defined(_WIN32) && !defined(__CYGWIN__) 2087 BY_HANDLE_FILE_INFORMATION bhfi; 2088 int r; 2089 2090 r = my_GetFileInformationByName(file, &bhfi); 2091 if (r != 0) 2092 return (0); 2093 return (bhfi.nFileIndexHigh & 0x0000FFFFUL); 2094#else 2095 struct stat st; 2096 int64_t ino; 2097 2098 if (stat(file, &st) < 0) 2099 return (0); 2100 ino = (int64_t)st.st_ino; 2101 return (ino > 0xffffffff); 2102#endif 2103} 2104/* 2105 * 2106 * TEST management 2107 * 2108 */ 2109 2110/* 2111 * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has 2112 * a line like 2113 * DEFINE_TEST(test_function) 2114 * for each test. 2115 */ 2116 2117/* Use "list.h" to declare all of the test functions. */ 2118#undef DEFINE_TEST 2119#define DEFINE_TEST(name) void name(void); 2120#include "list.h" 2121 2122/* Use "list.h" to create a list of all tests (functions and names). */ 2123#undef DEFINE_TEST 2124#define DEFINE_TEST(n) { n, #n, 0 }, 2125struct { void (*func)(void); const char *name; int failures; } tests[] = { 2126 #include "list.h" 2127}; 2128 2129/* 2130 * Summarize repeated failures in the just-completed test. 2131 */ 2132static void 2133test_summarize(int failed) 2134{ 2135 unsigned int i; 2136 2137 switch (verbosity) { 2138 case VERBOSITY_SUMMARY_ONLY: 2139 printf(failed ? "E" : "."); 2140 fflush(stdout); 2141 break; 2142 case VERBOSITY_PASSFAIL: 2143 printf(failed ? "FAIL\n" : "ok\n"); 2144 break; 2145 } 2146 2147 log_console = (verbosity == VERBOSITY_LIGHT_REPORT); 2148 2149 for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { 2150 if (failed_lines[i].count > 1 && !failed_lines[i].skip) 2151 logprintf("%s:%d: Summary: Failed %d times\n", 2152 failed_filename, i, failed_lines[i].count); 2153 } 2154 /* Clear the failure history for the next file. */ 2155 failed_filename = NULL; 2156 memset(failed_lines, 0, sizeof(failed_lines)); 2157} 2158 2159/* 2160 * Actually run a single test, with appropriate setup and cleanup. 2161 */ 2162static int 2163test_run(int i, const char *tmpdir) 2164{ 2165 char workdir[1024]; 2166 char logfilename[64]; 2167 int failures_before = failures; 2168 int oldumask; 2169 2170 switch (verbosity) { 2171 case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */ 2172 break; 2173 case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */ 2174 printf("%3d: %-50s", i, tests[i].name); 2175 fflush(stdout); 2176 break; 2177 default: /* Title of test, details will follow */ 2178 printf("%3d: %s\n", i, tests[i].name); 2179 } 2180 2181 /* Chdir to the top-level work directory. */ 2182 if (!assertChdir(tmpdir)) { 2183 fprintf(stderr, 2184 "ERROR: Can't chdir to top work dir %s\n", tmpdir); 2185 exit(1); 2186 } 2187 /* Create a log file for this test. */ 2188 sprintf(logfilename, "%s.log", tests[i].name); 2189 logfile = fopen(logfilename, "w"); 2190 fprintf(logfile, "%s\n\n", tests[i].name); 2191 /* Chdir() to a work dir for this specific test. */ 2192 snprintf(workdir, sizeof(workdir), "%s/%s", tmpdir, tests[i].name); 2193 testworkdir = workdir; 2194 if (!assertMakeDir(testworkdir, 0755) 2195 || !assertChdir(testworkdir)) { 2196 fprintf(stderr, 2197 "ERROR: Can't chdir to work dir %s\n", testworkdir); 2198 exit(1); 2199 } 2200 /* Explicitly reset the locale before each test. */ 2201 setlocale(LC_ALL, "C"); 2202 /* Record the umask before we run the test. */ 2203 umask(oldumask = umask(0)); 2204 /* 2205 * Run the actual test. 2206 */ 2207 (*tests[i].func)(); 2208 /* 2209 * Clean up and report afterwards. 2210 */ 2211 testworkdir = NULL; 2212 /* Restore umask */ 2213 umask(oldumask); 2214 /* Reset locale. */ 2215 setlocale(LC_ALL, "C"); 2216 /* Reset directory. */ 2217 if (!assertChdir(tmpdir)) { 2218 fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n", 2219 tmpdir); 2220 exit(1); 2221 } 2222 /* Report per-test summaries. */ 2223 tests[i].failures = failures - failures_before; 2224 test_summarize(tests[i].failures); 2225 /* Close the per-test log file. */ 2226 fclose(logfile); 2227 logfile = NULL; 2228 /* If there were no failures, we can remove the work dir and logfile. */ 2229 if (tests[i].failures == 0) { 2230 if (!keep_temp_files && assertChdir(tmpdir)) { 2231#if defined(_WIN32) && !defined(__CYGWIN__) 2232 /* Make sure not to leave empty directories. 2233 * Sometimes a processing of closing files used by tests 2234 * is not done, then rmdir will be failed and it will 2235 * leave a empty test directory. So we should wait a few 2236 * seconds and retry rmdir. */ 2237 int r, t; 2238 for (t = 0; t < 10; t++) { 2239 if (t > 0) 2240 Sleep(1000); 2241 r = systemf("rmdir /S /Q %s", tests[i].name); 2242 if (r == 0) 2243 break; 2244 } 2245 systemf("del %s", logfilename); 2246#else 2247 systemf("rm -rf %s", tests[i].name); 2248 systemf("rm %s", logfilename); 2249#endif 2250 } 2251 } 2252 /* Return appropriate status. */ 2253 return (tests[i].failures); 2254} 2255 2256/* 2257 * 2258 * 2259 * MAIN and support routines. 2260 * 2261 * 2262 */ 2263 2264static void 2265usage(const char *program) 2266{ 2267 static const int limit = sizeof(tests) / sizeof(tests[0]); 2268 int i; 2269 2270 printf("Usage: %s [options] <test> <test> ...\n", program); 2271 printf("Default is to run all tests.\n"); 2272 printf("Otherwise, specify the numbers of the tests you wish to run.\n"); 2273 printf("Options:\n"); 2274 printf(" -d Dump core after any failure, for debugging.\n"); 2275 printf(" -k Keep all temp files.\n"); 2276 printf(" Default: temp files for successful tests deleted.\n"); 2277#ifdef PROGRAM 2278 printf(" -p <path> Path to executable to be tested.\n"); 2279 printf(" Default: path taken from " ENVBASE " environment variable.\n"); 2280#endif 2281 printf(" -q Quiet.\n"); 2282 printf(" -r <dir> Path to dir containing reference files.\n"); 2283 printf(" Default: Current directory.\n"); 2284 printf(" -u Keep running specifies tests until one fails.\n"); 2285 printf(" -v Verbose.\n"); 2286 printf("Available tests:\n"); 2287 for (i = 0; i < limit; i++) 2288 printf(" %d: %s\n", i, tests[i].name); 2289 exit(1); 2290} 2291 2292static char * 2293get_refdir(const char *d) 2294{ 2295 char tried[512] = { '\0' }; 2296 char buff[128]; 2297 char *pwd, *p; 2298 2299 /* If a dir was specified, try that */ 2300 if (d != NULL) { 2301 pwd = NULL; 2302 snprintf(buff, sizeof(buff), "%s", d); 2303 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 2304 if (p != NULL) goto success; 2305 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); 2306 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); 2307 goto failure; 2308 } 2309 2310 /* Get the current dir. */ 2311#ifdef PATH_MAX 2312 pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ 2313#else 2314 pwd = getcwd(NULL, 0); 2315#endif 2316 while (pwd[strlen(pwd) - 1] == '\n') 2317 pwd[strlen(pwd) - 1] = '\0'; 2318 2319 /* Look for a known file. */ 2320 snprintf(buff, sizeof(buff), "%s", pwd); 2321 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 2322 if (p != NULL) goto success; 2323 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); 2324 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); 2325 2326 snprintf(buff, sizeof(buff), "%s/test", pwd); 2327 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 2328 if (p != NULL) goto success; 2329 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); 2330 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); 2331 2332#if defined(LIBRARY) 2333 snprintf(buff, sizeof(buff), "%s/%s/test", pwd, LIBRARY); 2334#else 2335 snprintf(buff, sizeof(buff), "%s/%s/test", pwd, PROGRAM); 2336#endif 2337 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 2338 if (p != NULL) goto success; 2339 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); 2340 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); 2341 2342#if defined(PROGRAM_ALIAS) 2343 snprintf(buff, sizeof(buff), "%s/%s/test", pwd, PROGRAM_ALIAS); 2344 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 2345 if (p != NULL) goto success; 2346 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); 2347 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); 2348#endif 2349 2350 if (memcmp(pwd, "/usr/obj", 8) == 0) { 2351 snprintf(buff, sizeof(buff), "%s", pwd + 8); 2352 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 2353 if (p != NULL) goto success; 2354 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); 2355 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); 2356 2357 snprintf(buff, sizeof(buff), "%s/test", pwd + 8); 2358 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 2359 if (p != NULL) goto success; 2360 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); 2361 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); 2362 } 2363 2364failure: 2365 printf("Unable to locate known reference file %s\n", KNOWNREF); 2366 printf(" Checked following directories:\n%s\n", tried); 2367#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) 2368 DebugBreak(); 2369#endif 2370 exit(1); 2371 2372success: 2373 free(p); 2374 free(pwd); 2375 return strdup(buff); 2376} 2377 2378static int 2379get_test_set(int *test_set, int limit, const char *test) 2380{ 2381 int start, end; 2382 int idx = 0; 2383 2384 if (test == NULL) { 2385 /* Default: Run all tests. */ 2386 for (;idx < limit; idx++) 2387 test_set[idx] = idx; 2388 return (limit); 2389 } 2390 if (*test >= '0' && *test <= '9') { 2391 const char *vp = test; 2392 start = 0; 2393 while (*vp >= '0' && *vp <= '9') { 2394 start *= 10; 2395 start += *vp - '0'; 2396 ++vp; 2397 } 2398 if (*vp == '\0') { 2399 end = start; 2400 } else if (*vp == '-') { 2401 ++vp; 2402 if (*vp == '\0') { 2403 end = limit - 1; 2404 } else { 2405 end = 0; 2406 while (*vp >= '0' && *vp <= '9') { 2407 end *= 10; 2408 end += *vp - '0'; 2409 ++vp; 2410 } 2411 } 2412 } else 2413 return (-1); 2414 if (start < 0 || end >= limit || start > end) 2415 return (-1); 2416 while (start <= end) 2417 test_set[idx++] = start++; 2418 } else { 2419 size_t len = strlen(test); 2420 for (start = 0; start < limit; ++start) { 2421 const char *name = tests[start].name; 2422 const char *p; 2423 2424 while ((p = strchr(name, test[0])) != NULL) { 2425 if (strncmp(p, test, len) == 0) { 2426 test_set[idx++] = start; 2427 break; 2428 } else 2429 name = p + 1; 2430 } 2431 2432 } 2433 } 2434 return ((idx == 0)?-1:idx); 2435} 2436 2437int 2438main(int argc, char **argv) 2439{ 2440 static const int limit = sizeof(tests) / sizeof(tests[0]); 2441 int test_set[sizeof(tests) / sizeof(tests[0])]; 2442 int i = 0, j = 0, tests_run = 0, tests_failed = 0, option; 2443 time_t now; 2444 char *refdir_alloc = NULL; 2445 const char *progname; 2446 char **saved_argv; 2447 const char *tmp, *option_arg, *p; 2448 char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL; 2449 char tmpdir_timestamp[256]; 2450 2451 (void)argc; /* UNUSED */ 2452 2453 /* Get the current dir. */ 2454#ifdef PATH_MAX 2455 pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ 2456#else 2457 pwd = getcwd(NULL, 0); 2458#endif 2459 while (pwd[strlen(pwd) - 1] == '\n') 2460 pwd[strlen(pwd) - 1] = '\0'; 2461 2462#if defined(HAVE__CrtSetReportMode) 2463 /* To stop to run the default invalid parameter handler. */ 2464 _set_invalid_parameter_handler(invalid_parameter_handler); 2465 /* Disable annoying assertion message box. */ 2466 _CrtSetReportMode(_CRT_ASSERT, 0); 2467#endif 2468 2469 /* 2470 * Name of this program, used to build root of our temp directory 2471 * tree. 2472 */ 2473 progname = p = argv[0]; 2474 if ((testprogdir = (char *)malloc(strlen(progname) + 1)) == NULL) 2475 { 2476 fprintf(stderr, "ERROR: Out of memory."); 2477 exit(1); 2478 } 2479 strcpy(testprogdir, progname); 2480 while (*p != '\0') { 2481 /* Support \ or / dir separators for Windows compat. */ 2482 if (*p == '/' || *p == '\\') 2483 { 2484 progname = p + 1; 2485 i = j; 2486 } 2487 ++p; 2488 j++; 2489 } 2490 testprogdir[i] = '\0'; 2491#if defined(_WIN32) && !defined(__CYGWIN__) 2492 if (testprogdir[0] != '/' && testprogdir[0] != '\\' && 2493 !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') || 2494 (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) && 2495 testprogdir[1] == ':' && 2496 (testprogdir[2] == '/' || testprogdir[2] == '\\'))) 2497#else 2498 if (testprogdir[0] != '/') 2499#endif 2500 { 2501 /* Fixup path for relative directories. */ 2502 if ((testprogdir = (char *)realloc(testprogdir, 2503 strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL) 2504 { 2505 fprintf(stderr, "ERROR: Out of memory."); 2506 exit(1); 2507 } 2508 memmove(testprogdir + strlen(pwd) + 1, testprogdir, 2509 strlen(testprogdir)); 2510 memcpy(testprogdir, pwd, strlen(pwd)); 2511 testprogdir[strlen(pwd)] = '/'; 2512 } 2513 2514#ifdef PROGRAM 2515 /* Get the target program from environment, if available. */ 2516 testprogfile = getenv(ENVBASE); 2517#endif 2518 2519 if (getenv("TMPDIR") != NULL) 2520 tmp = getenv("TMPDIR"); 2521 else if (getenv("TMP") != NULL) 2522 tmp = getenv("TMP"); 2523 else if (getenv("TEMP") != NULL) 2524 tmp = getenv("TEMP"); 2525 else if (getenv("TEMPDIR") != NULL) 2526 tmp = getenv("TEMPDIR"); 2527 else 2528 tmp = "/tmp"; 2529 2530 /* Allow -d to be controlled through the environment. */ 2531 if (getenv(ENVBASE "_DEBUG") != NULL) 2532 dump_on_failure = 1; 2533 2534 /* Allow -v to be controlled through the environment. */ 2535 if (getenv("_VERBOSITY_LEVEL") != NULL) 2536 { 2537 vlevel = getenv("_VERBOSITY_LEVEL"); 2538 verbosity = atoi(vlevel); 2539 if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL) 2540 { 2541 /* Unsupported verbosity levels are silently ignored */ 2542 vlevel = NULL; 2543 verbosity = VERBOSITY_PASSFAIL; 2544 } 2545 } 2546 2547 /* Get the directory holding test files from environment. */ 2548 refdir = getenv(ENVBASE "_TEST_FILES"); 2549 2550 /* 2551 * Parse options, without using getopt(), which isn't available 2552 * on all platforms. 2553 */ 2554 ++argv; /* Skip program name */ 2555 while (*argv != NULL) { 2556 if (**argv != '-') 2557 break; 2558 p = *argv++; 2559 ++p; /* Skip '-' */ 2560 while (*p != '\0') { 2561 option = *p++; 2562 option_arg = NULL; 2563 /* If 'opt' takes an argument, parse that. */ 2564 if (option == 'p' || option == 'r') { 2565 if (*p != '\0') 2566 option_arg = p; 2567 else if (*argv == NULL) { 2568 fprintf(stderr, 2569 "Option -%c requires argument.\n", 2570 option); 2571 usage(progname); 2572 } else 2573 option_arg = *argv++; 2574 p = ""; /* End of this option word. */ 2575 } 2576 2577 /* Now, handle the option. */ 2578 switch (option) { 2579 case 'd': 2580 dump_on_failure = 1; 2581 break; 2582 case 'k': 2583 keep_temp_files = 1; 2584 break; 2585 case 'p': 2586#ifdef PROGRAM 2587 testprogfile = option_arg; 2588#else 2589 fprintf(stderr, "-p option not permitted\n"); 2590 usage(progname); 2591#endif 2592 break; 2593 case 'q': 2594 if (!vlevel) 2595 verbosity--; 2596 break; 2597 case 'r': 2598 refdir = option_arg; 2599 break; 2600 case 'u': 2601 until_failure++; 2602 break; 2603 case 'v': 2604 if (!vlevel) 2605 verbosity++; 2606 break; 2607 default: 2608 fprintf(stderr, "Unrecognized option '%c'\n", 2609 option); 2610 usage(progname); 2611 } 2612 } 2613 } 2614 2615 /* 2616 * Sanity-check that our options make sense. 2617 */ 2618#ifdef PROGRAM 2619 if (testprogfile == NULL) 2620 { 2621 if ((tmp2 = (char *)malloc(strlen(testprogdir) + 1 + 2622 strlen(PROGRAM) + 1)) == NULL) 2623 { 2624 fprintf(stderr, "ERROR: Out of memory."); 2625 exit(1); 2626 } 2627 strcpy(tmp2, testprogdir); 2628 strcat(tmp2, "/"); 2629 strcat(tmp2, PROGRAM); 2630 testprogfile = tmp2; 2631 } 2632 2633 { 2634 char *testprg; 2635#if defined(_WIN32) && !defined(__CYGWIN__) 2636 /* Command.com sometimes rejects '/' separators. */ 2637 testprg = strdup(testprogfile); 2638 for (i = 0; testprg[i] != '\0'; i++) { 2639 if (testprg[i] == '/') 2640 testprg[i] = '\\'; 2641 } 2642 testprogfile = testprg; 2643#endif 2644 /* Quote the name that gets put into shell command lines. */ 2645 testprg = malloc(strlen(testprogfile) + 3); 2646 strcpy(testprg, "\""); 2647 strcat(testprg, testprogfile); 2648 strcat(testprg, "\""); 2649 testprog = testprg; 2650 } 2651#endif 2652 2653#if !defined(_WIN32) && defined(SIGPIPE) 2654 { /* Ignore SIGPIPE signals */ 2655 struct sigaction sa; 2656 sa.sa_handler = SIG_IGN; 2657 sigemptyset(&sa.sa_mask); 2658 sa.sa_flags = 0; 2659 sigaction(SIGPIPE, &sa, NULL); 2660 } 2661#endif 2662 2663 /* 2664 * Create a temp directory for the following tests. 2665 * Include the time the tests started as part of the name, 2666 * to make it easier to track the results of multiple tests. 2667 */ 2668 now = time(NULL); 2669 for (i = 0; ; i++) { 2670 strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp), 2671 "%Y-%m-%dT%H.%M.%S", 2672 localtime(&now)); 2673 sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname, 2674 tmpdir_timestamp, i); 2675 if (assertMakeDir(tmpdir,0755)) 2676 break; 2677 if (i >= 999) { 2678 fprintf(stderr, 2679 "ERROR: Unable to create temp directory %s\n", 2680 tmpdir); 2681 exit(1); 2682 } 2683 } 2684 2685 /* 2686 * If the user didn't specify a directory for locating 2687 * reference files, try to find the reference files in 2688 * the "usual places." 2689 */ 2690 refdir = refdir_alloc = get_refdir(refdir); 2691 2692 /* 2693 * Banner with basic information. 2694 */ 2695 printf("\n"); 2696 printf("If tests fail or crash, details will be in:\n"); 2697 printf(" %s\n", tmpdir); 2698 printf("\n"); 2699 if (verbosity > VERBOSITY_SUMMARY_ONLY) { 2700 printf("Reference files will be read from: %s\n", refdir); 2701#ifdef PROGRAM 2702 printf("Running tests on: %s\n", testprog); 2703#endif 2704 printf("Exercising: "); 2705 fflush(stdout); 2706 printf("%s\n", EXTRA_VERSION); 2707 } else { 2708 printf("Running "); 2709 fflush(stdout); 2710 } 2711 2712 /* 2713 * Run some or all of the individual tests. 2714 */ 2715 saved_argv = argv; 2716 do { 2717 argv = saved_argv; 2718 do { 2719 int test_num; 2720 2721 test_num = get_test_set(test_set, limit, *argv); 2722 if (test_num < 0) { 2723 printf("*** INVALID Test %s\n", *argv); 2724 free(refdir_alloc); 2725 usage(progname); 2726 return (1); 2727 } 2728 for (i = 0; i < test_num; i++) { 2729 tests_run++; 2730 if (test_run(test_set[i], tmpdir)) { 2731 tests_failed++; 2732 if (until_failure) 2733 goto finish; 2734 } 2735 } 2736 if (*argv != NULL) 2737 argv++; 2738 } while (*argv != NULL); 2739 } while (until_failure); 2740 2741finish: 2742 /* Must be freed after all tests run */ 2743 free(tmp2); 2744 free(testprogdir); 2745 free(pwd); 2746 2747 /* 2748 * Report summary statistics. 2749 */ 2750 if (verbosity > VERBOSITY_SUMMARY_ONLY) { 2751 printf("\n"); 2752 printf("Totals:\n"); 2753 printf(" Tests run: %8d\n", tests_run); 2754 printf(" Tests failed: %8d\n", tests_failed); 2755 printf(" Assertions checked:%8d\n", assertions); 2756 printf(" Assertions failed: %8d\n", failures); 2757 printf(" Skips reported: %8d\n", skips); 2758 } 2759 if (failures) { 2760 printf("\n"); 2761 printf("Failing tests:\n"); 2762 for (i = 0; i < limit; ++i) { 2763 if (tests[i].failures) 2764 printf(" %d: %s (%d failures)\n", i, 2765 tests[i].name, tests[i].failures); 2766 } 2767 printf("\n"); 2768 printf("Details for failing tests: %s\n", tmpdir); 2769 printf("\n"); 2770 } else { 2771 if (verbosity == VERBOSITY_SUMMARY_ONLY) 2772 printf("\n"); 2773 printf("%d tests passed, no failures\n", tests_run); 2774 } 2775 2776 free(refdir_alloc); 2777 2778 /* If the final tmpdir is empty, we can remove it. */ 2779 /* This should be the usual case when all tests succeed. */ 2780 assertChdir(".."); 2781 rmdir(tmpdir); 2782 2783 return (tests_failed ? 1 : 0); 2784} 2785