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