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