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