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