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