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