1538aa54dSGarrett D'Amore /*
2538aa54dSGarrett D'Amore  * This file and its contents are supplied under the terms of the
3538aa54dSGarrett D'Amore  * Common Development and Distribution License ("CDDL"), version 1.0.
4538aa54dSGarrett D'Amore  * You may only use this file in accordance with the terms of version
5538aa54dSGarrett D'Amore  * 1.0 of the CDDL.
6538aa54dSGarrett D'Amore  *
7538aa54dSGarrett D'Amore  * A full copy of the text of the CDDL should have accompanied this
8538aa54dSGarrett D'Amore  * source.  A copy of the CDDL is also available via the Internet at
9538aa54dSGarrett D'Amore  * http://www.illumos.org/license/CDDL.
10538aa54dSGarrett D'Amore  */
11538aa54dSGarrett D'Amore 
12538aa54dSGarrett D'Amore /*
13*de572d98SGarrett D'Amore  * Copyright 2015 Garrett D'Amore <garrett@damore.org>
14538aa54dSGarrett D'Amore  */
15538aa54dSGarrett D'Amore 
16538aa54dSGarrett D'Amore /*
17538aa54dSGarrett D'Amore  * Common handling for test programs.
18538aa54dSGarrett D'Amore  */
19538aa54dSGarrett D'Amore 
20538aa54dSGarrett D'Amore #include <stdio.h>
21538aa54dSGarrett D'Amore #include <stdlib.h>
22538aa54dSGarrett D'Amore #include <stdarg.h>
23*de572d98SGarrett D'Amore #include <string.h>
24*de572d98SGarrett D'Amore #include <errno.h>
25538aa54dSGarrett D'Amore #include <pthread.h>
26*de572d98SGarrett D'Amore #include <ctype.h>
27*de572d98SGarrett D'Amore #include <unistd.h>
28*de572d98SGarrett D'Amore #include <sys/param.h>
29538aa54dSGarrett D'Amore #include "test_common.h"
30538aa54dSGarrett D'Amore 
31538aa54dSGarrett D'Amore static int debug = 0;
32538aa54dSGarrett D'Amore static int force = 0;
33538aa54dSGarrett D'Amore static pthread_mutex_t lk;
34538aa54dSGarrett D'Amore 
35*de572d98SGarrett D'Amore static int passes;
36*de572d98SGarrett D'Amore static int tests;
37*de572d98SGarrett D'Amore 
38538aa54dSGarrett D'Amore struct test {
39538aa54dSGarrett D'Amore 	char		*name;
40538aa54dSGarrett D'Amore 	int		ntids;
41538aa54dSGarrett D'Amore 	pthread_t	*tids;
42538aa54dSGarrett D'Amore 	int		fails;
43538aa54dSGarrett D'Amore 	void		*arg;
44538aa54dSGarrett D'Amore 	void		(*func)(test_t t, void *);
45538aa54dSGarrett D'Amore };
46538aa54dSGarrett D'Amore 
47538aa54dSGarrett D'Amore void
48538aa54dSGarrett D'Amore test_set_debug(void)
49538aa54dSGarrett D'Amore {
50538aa54dSGarrett D'Amore 	debug++;
51538aa54dSGarrett D'Amore }
52538aa54dSGarrett D'Amore 
53538aa54dSGarrett D'Amore void
54538aa54dSGarrett D'Amore test_set_force(void)
55538aa54dSGarrett D'Amore {
56538aa54dSGarrett D'Amore 	force++;
57538aa54dSGarrett D'Amore }
58538aa54dSGarrett D'Amore 
59538aa54dSGarrett D'Amore test_t
60538aa54dSGarrett D'Amore test_start(const char *format, ...)
61538aa54dSGarrett D'Amore {
62538aa54dSGarrett D'Amore 	va_list args;
63538aa54dSGarrett D'Amore 	test_t t;
64538aa54dSGarrett D'Amore 	char *s;
65538aa54dSGarrett D'Amore 
66538aa54dSGarrett D'Amore 	t = calloc(1, sizeof (*t));
67538aa54dSGarrett D'Amore 	va_start(args, format);
68538aa54dSGarrett D'Amore 	(void) vasprintf(&s, format, args);
69538aa54dSGarrett D'Amore 	va_end(args);
70538aa54dSGarrett D'Amore 
71538aa54dSGarrett D'Amore 	(void) asprintf(&t->name, "%s (%s)", s, ARCH);
72538aa54dSGarrett D'Amore 	free(s);
73538aa54dSGarrett D'Amore 
74538aa54dSGarrett D'Amore 	(void) pthread_mutex_lock(&lk);
75538aa54dSGarrett D'Amore 	(void) printf("TEST STARTING %s:\n", t->name);
76538aa54dSGarrett D'Amore 	(void) fflush(stdout);
77538aa54dSGarrett D'Amore 	(void) pthread_mutex_unlock(&lk);
78538aa54dSGarrett D'Amore 
79538aa54dSGarrett D'Amore #ifdef	LINT
80538aa54dSGarrett D'Amore 	/* We inject references to make avoid name unused warnings */
81538aa54dSGarrett D'Amore 	test_run(0, NULL, NULL, NULL);
82538aa54dSGarrett D'Amore 	test_debugf(t, NULL);
83538aa54dSGarrett D'Amore 	test_failed(t, NULL);
84538aa54dSGarrett D'Amore 	test_passed(t);
85538aa54dSGarrett D'Amore 	test_set_debug();
86538aa54dSGarrett D'Amore 	test_set_force();
87*de572d98SGarrett D'Amore 	test_summary();
88*de572d98SGarrett D'Amore 	(void) test_load_config(t, NULL, NULL);
89538aa54dSGarrett D'Amore #endif
90538aa54dSGarrett D'Amore 
91*de572d98SGarrett D'Amore 	tests++;
92538aa54dSGarrett D'Amore 	return (t);
93538aa54dSGarrett D'Amore }
94538aa54dSGarrett D'Amore 
95538aa54dSGarrett D'Amore void
96538aa54dSGarrett D'Amore test_failed(test_t t, const char *format, ...)
97538aa54dSGarrett D'Amore {
98538aa54dSGarrett D'Amore 	va_list args;
99538aa54dSGarrett D'Amore 
100538aa54dSGarrett D'Amore 	(void) pthread_mutex_lock(&lk);
101*de572d98SGarrett D'Amore 	if (t == NULL) {
102*de572d98SGarrett D'Amore 		(void) printf("FAILURE: ");
103*de572d98SGarrett D'Amore 		va_start(args, format);
104*de572d98SGarrett D'Amore 		(void) vprintf(format, args);
105*de572d98SGarrett D'Amore 		va_end(args);
106*de572d98SGarrett D'Amore 		(void) printf("\n");
107*de572d98SGarrett D'Amore 		(void) fflush(stdout);
108*de572d98SGarrett D'Amore 		(void) pthread_mutex_unlock(&lk);
109*de572d98SGarrett D'Amore 		return;
110*de572d98SGarrett D'Amore 	}
111538aa54dSGarrett D'Amore 	if (force || (t->ntids > 0)) {
112538aa54dSGarrett D'Amore 		(void) printf("TEST FAILING %s: ", t->name);
113538aa54dSGarrett D'Amore 	} else {
114538aa54dSGarrett D'Amore 		(void) printf("TEST FAILED %s: ", t->name);
115538aa54dSGarrett D'Amore 	}
116538aa54dSGarrett D'Amore 
117538aa54dSGarrett D'Amore 	va_start(args, format);
118538aa54dSGarrett D'Amore 	(void) vprintf(format, args);
119538aa54dSGarrett D'Amore 	va_end(args);
120538aa54dSGarrett D'Amore 	(void) printf("\n");
121538aa54dSGarrett D'Amore 	(void) fflush(stdout);
122538aa54dSGarrett D'Amore 	(void) pthread_mutex_unlock(&lk);
123538aa54dSGarrett D'Amore 
124538aa54dSGarrett D'Amore 	t->fails++;
125538aa54dSGarrett D'Amore 	if (!force) {
126538aa54dSGarrett D'Amore 		if (t->ntids > 0) {
127538aa54dSGarrett D'Amore 			pthread_exit(NULL);
128538aa54dSGarrett D'Amore 		} else {
129538aa54dSGarrett D'Amore 			(void) exit(EXIT_FAILURE);
130538aa54dSGarrett D'Amore 		}
131538aa54dSGarrett D'Amore 	}
132538aa54dSGarrett D'Amore }
133538aa54dSGarrett D'Amore 
134538aa54dSGarrett D'Amore void
135538aa54dSGarrett D'Amore test_passed(test_t t)
136538aa54dSGarrett D'Amore {
137*de572d98SGarrett D'Amore 	if (t == NULL) {
138*de572d98SGarrett D'Amore 		return;
139*de572d98SGarrett D'Amore 	}
140538aa54dSGarrett D'Amore 	if (t->ntids > 0) {
141538aa54dSGarrett D'Amore 		if (debug) {
142538aa54dSGarrett D'Amore 			(void) pthread_mutex_lock(&lk);
143538aa54dSGarrett D'Amore 			(void) printf("TEST PASSING: %s\n", t->name);
144538aa54dSGarrett D'Amore 			(void) pthread_mutex_unlock(&lk);
145538aa54dSGarrett D'Amore 		}
146538aa54dSGarrett D'Amore 		return;
147538aa54dSGarrett D'Amore 	}
148538aa54dSGarrett D'Amore 	(void) pthread_mutex_lock(&lk);
149538aa54dSGarrett D'Amore 	if (t->fails == 0) {
150*de572d98SGarrett D'Amore 		passes++;
151538aa54dSGarrett D'Amore 		(void) printf("TEST PASS: %s\n", t->name);
152538aa54dSGarrett D'Amore 	} else {
153538aa54dSGarrett D'Amore 		(void) printf("TEST FAILED: %d failures\n", t->fails);
154538aa54dSGarrett D'Amore 	}
155538aa54dSGarrett D'Amore 	(void) fflush(stdout);
156538aa54dSGarrett D'Amore 	(void) pthread_mutex_unlock(&lk);
157538aa54dSGarrett D'Amore 	free(t->name);
158538aa54dSGarrett D'Amore 	if (t->tids) {
159538aa54dSGarrett D'Amore 		free(t->tids);
160538aa54dSGarrett D'Amore 	}
161538aa54dSGarrett D'Amore 	free(t);
162538aa54dSGarrett D'Amore }
163538aa54dSGarrett D'Amore 
164*de572d98SGarrett D'Amore void
165*de572d98SGarrett D'Amore test_summary(void)
166*de572d98SGarrett D'Amore {
167*de572d98SGarrett D'Amore 	if (passes == tests) {
168*de572d98SGarrett D'Amore 		(void) printf("TEST SUMMARY: %d / %d (ok)\n", passes, tests);
169*de572d98SGarrett D'Amore 	} else {
170*de572d98SGarrett D'Amore 		(void) printf("TEST SUMMARY: %d / %d (%d failing)\n",
171*de572d98SGarrett D'Amore 		    passes, tests, tests - passes);
172*de572d98SGarrett D'Amore 	}
173*de572d98SGarrett D'Amore }
174*de572d98SGarrett D'Amore 
175538aa54dSGarrett D'Amore void
176538aa54dSGarrett D'Amore test_debugf(test_t t, const char *format, ...)
177538aa54dSGarrett D'Amore {
178538aa54dSGarrett D'Amore 	va_list args;
179538aa54dSGarrett D'Amore 
180538aa54dSGarrett D'Amore 	if (!debug)
181538aa54dSGarrett D'Amore 		return;
182538aa54dSGarrett D'Amore 
183538aa54dSGarrett D'Amore 	(void) pthread_mutex_lock(&lk);
184*de572d98SGarrett D'Amore 	if (t) {
185*de572d98SGarrett D'Amore 		(void) printf("TEST DEBUG %s: ", t->name);
186*de572d98SGarrett D'Amore 	} else {
187*de572d98SGarrett D'Amore 		(void) printf("TEST DEBUG: ");
188*de572d98SGarrett D'Amore 	}
189538aa54dSGarrett D'Amore 	va_start(args, format);
190538aa54dSGarrett D'Amore 	(void) vprintf(format, args);
191538aa54dSGarrett D'Amore 	va_end(args);
192538aa54dSGarrett D'Amore 	(void) printf("\n");
193538aa54dSGarrett D'Amore 	(void) fflush(stdout);
194538aa54dSGarrett D'Amore 	(void) pthread_mutex_unlock(&lk);
195538aa54dSGarrett D'Amore }
196538aa54dSGarrett D'Amore 
197538aa54dSGarrett D'Amore static void *
198538aa54dSGarrett D'Amore test_thr_one(void *arg)
199538aa54dSGarrett D'Amore {
200538aa54dSGarrett D'Amore 	test_t t = arg;
201538aa54dSGarrett D'Amore 	t->func(t, t->arg);
202538aa54dSGarrett D'Amore 	return (NULL);
203538aa54dSGarrett D'Amore }
204538aa54dSGarrett D'Amore 
205538aa54dSGarrett D'Amore void
206538aa54dSGarrett D'Amore test_run(int nthr, void (*func)(test_t, void *), void *arg,
207538aa54dSGarrett D'Amore     const char *tname, ...)
208538aa54dSGarrett D'Amore {
209538aa54dSGarrett D'Amore 	test_t		t;
210538aa54dSGarrett D'Amore 	char		*s;
211538aa54dSGarrett D'Amore 	va_list		args;
212538aa54dSGarrett D'Amore 
213538aa54dSGarrett D'Amore 	t = calloc(1, sizeof (*t));
214538aa54dSGarrett D'Amore 	t->ntids = nthr;
215538aa54dSGarrett D'Amore 	t->tids = calloc(nthr, sizeof (pthread_t));
216538aa54dSGarrett D'Amore 	t->func = func;
217538aa54dSGarrett D'Amore 	t->arg = arg;
218538aa54dSGarrett D'Amore 
219538aa54dSGarrett D'Amore 	va_start(args, tname);
220538aa54dSGarrett D'Amore 	(void) vasprintf(&s, tname, args);
221538aa54dSGarrett D'Amore 	va_end(args);
222538aa54dSGarrett D'Amore 
223538aa54dSGarrett D'Amore 	(void) asprintf(&t->name, "%s (%s)", s, ARCH);
224538aa54dSGarrett D'Amore 	free(s);
225538aa54dSGarrett D'Amore 
226538aa54dSGarrett D'Amore 	(void) pthread_mutex_lock(&lk);
227538aa54dSGarrett D'Amore 	(void) printf("TEST STARTING %s:\n", t->name);
228538aa54dSGarrett D'Amore 	(void) fflush(stdout);
229538aa54dSGarrett D'Amore 	(void) pthread_mutex_unlock(&lk);
230538aa54dSGarrett D'Amore 
231538aa54dSGarrett D'Amore 	test_debugf(t, "running %d threads", nthr);
232538aa54dSGarrett D'Amore 
233538aa54dSGarrett D'Amore 	for (int i = 0; i < nthr; i++) {
234538aa54dSGarrett D'Amore 		test_debugf(t, "started thread %d", i);
235538aa54dSGarrett D'Amore 		(void) pthread_create(&t->tids[i], NULL, test_thr_one, t);
236538aa54dSGarrett D'Amore 	}
237538aa54dSGarrett D'Amore 
238538aa54dSGarrett D'Amore 	for (int i = 0; i < nthr; i++) {
239538aa54dSGarrett D'Amore 		(void) pthread_join(t->tids[i], NULL);
240538aa54dSGarrett D'Amore 		test_debugf(t, "thread %d joined", i);
241538aa54dSGarrett D'Amore 		t->ntids--;
242538aa54dSGarrett D'Amore 	}
243538aa54dSGarrett D'Amore 	test_passed(t);
244538aa54dSGarrett D'Amore }
245*de572d98SGarrett D'Amore 
246*de572d98SGarrett D'Amore void
247*de572d98SGarrett D'Amore test_trim(char **ptr)
248*de572d98SGarrett D'Amore {
249*de572d98SGarrett D'Amore 	char *p = *ptr;
250*de572d98SGarrett D'Amore 	while (isspace(*p)) {
251*de572d98SGarrett D'Amore 		p++;
252*de572d98SGarrett D'Amore 	}
253*de572d98SGarrett D'Amore 	*ptr = p;
254*de572d98SGarrett D'Amore 	p += strlen(p);
255*de572d98SGarrett D'Amore 	while ((--p >= *ptr) && (isspace(*p))) {
256*de572d98SGarrett D'Amore 		*p = 0;
257*de572d98SGarrett D'Amore 	}
258*de572d98SGarrett D'Amore }
259*de572d98SGarrett D'Amore 
260*de572d98SGarrett D'Amore #define	MAXCB		20
261*de572d98SGarrett D'Amore #define	MAXFIELD	20
262*de572d98SGarrett D'Amore 
263*de572d98SGarrett D'Amore int
264*de572d98SGarrett D'Amore test_load_config(test_t t, const char *fname, ...)
265*de572d98SGarrett D'Amore {
266*de572d98SGarrett D'Amore 	va_list		va;
267*de572d98SGarrett D'Amore 	const char	*keyws[MAXCB];
268*de572d98SGarrett D'Amore 	test_cfg_func_t	callbs[MAXCB];
269*de572d98SGarrett D'Amore 	char		*fields[MAXFIELD];
270*de572d98SGarrett D'Amore 	int		nfields;
271*de572d98SGarrett D'Amore 
272*de572d98SGarrett D'Amore 	FILE    	*cfg;
273*de572d98SGarrett D'Amore 	char    	line[1024];
274*de572d98SGarrett D'Amore 	char    	buf[1024];
275*de572d98SGarrett D'Amore 	int		done;
276*de572d98SGarrett D'Amore 	char		*ptr;
277*de572d98SGarrett D'Amore 	char		*tok;
278*de572d98SGarrett D'Amore 	char		*err;
279*de572d98SGarrett D'Amore 	int		lineno;
280*de572d98SGarrett D'Amore 	int		rv;
281*de572d98SGarrett D'Amore 	int		found;
282*de572d98SGarrett D'Amore 	char		path[MAXPATHLEN];
283*de572d98SGarrett D'Amore 	int		i;
284*de572d98SGarrett D'Amore 
285*de572d98SGarrett D'Amore 	va_start(va, fname);
286*de572d98SGarrett D'Amore 	for (i = 0; i < MAXCB; i++) {
287*de572d98SGarrett D'Amore 		keyws[i] = (const char *)va_arg(va, const char *);
288*de572d98SGarrett D'Amore 		if (keyws[i] == NULL)
289*de572d98SGarrett D'Amore 			break;
290*de572d98SGarrett D'Amore 		callbs[i] = (test_cfg_func_t)va_arg(va, test_cfg_func_t);
291*de572d98SGarrett D'Amore 	}
292*de572d98SGarrett D'Amore 	va_end(va);
293*de572d98SGarrett D'Amore 	if (i == MAXCB) {
294*de572d98SGarrett D'Amore 		test_debugf(t, "too many arguments to function >= %d", MAXCB);
295*de572d98SGarrett D'Amore 	}
296*de572d98SGarrett D'Amore 
297*de572d98SGarrett D'Amore 	found = 0;
298*de572d98SGarrett D'Amore 
299*de572d98SGarrett D'Amore 	if (access(fname, F_OK) == 0) {
300*de572d98SGarrett D'Amore 		found++;
301*de572d98SGarrett D'Amore 	}
302*de572d98SGarrett D'Amore 	if (!found && fname[0] != '/') {
303*de572d98SGarrett D'Amore 		char *stf = getenv("STF_SUITE");
304*de572d98SGarrett D'Amore 		if (stf == NULL) {
305*de572d98SGarrett D'Amore 			stf = "../..";
306*de572d98SGarrett D'Amore 		}
307*de572d98SGarrett D'Amore 		(void) snprintf(path, sizeof (path), "%s/cfg/%s", stf, fname);
308*de572d98SGarrett D'Amore 		if (access(path, F_OK) == 0) {
309*de572d98SGarrett D'Amore 			fname = path;
310*de572d98SGarrett D'Amore 			found++;
311*de572d98SGarrett D'Amore 		} else {
312*de572d98SGarrett D'Amore 			(void) snprintf(path, sizeof (path), "cfg/%s", fname);
313*de572d98SGarrett D'Amore 			if (access(path, F_OK) == 0) {
314*de572d98SGarrett D'Amore 				fname = path;
315*de572d98SGarrett D'Amore 				found++;
316*de572d98SGarrett D'Amore 			}
317*de572d98SGarrett D'Amore 		}
318*de572d98SGarrett D'Amore 	}
319*de572d98SGarrett D'Amore 
320*de572d98SGarrett D'Amore 	if ((cfg = fopen(fname, "r")) ==  NULL) {
321*de572d98SGarrett D'Amore 		test_failed(t, "open(%s): %s", fname, strerror(errno));
322*de572d98SGarrett D'Amore 		return (-1);
323*de572d98SGarrett D'Amore 	}
324*de572d98SGarrett D'Amore 
325*de572d98SGarrett D'Amore 	line[0] = 0;
326*de572d98SGarrett D'Amore 	done = 0;
327*de572d98SGarrett D'Amore 	lineno = 0;
328*de572d98SGarrett D'Amore 
329*de572d98SGarrett D'Amore 	while (!done) {
330*de572d98SGarrett D'Amore 
331*de572d98SGarrett D'Amore 		lineno++;
332*de572d98SGarrett D'Amore 
333*de572d98SGarrett D'Amore 		if (fgets(buf, sizeof (buf), cfg) == NULL) {
334*de572d98SGarrett D'Amore 			done++;
335*de572d98SGarrett D'Amore 		} else {
336*de572d98SGarrett D'Amore 			(void) strtok(buf, "\n");
337*de572d98SGarrett D'Amore 			if ((*buf != 0) && (buf[strlen(buf)-1] == '\\')) {
338*de572d98SGarrett D'Amore 				/*
339*de572d98SGarrett D'Amore 				 * Continuation.  This isn't quite right,
340*de572d98SGarrett D'Amore 				 * as it doesn't allow for a "\" at the
341*de572d98SGarrett D'Amore 				 * end of line (no escaping).
342*de572d98SGarrett D'Amore 				 */
343*de572d98SGarrett D'Amore 				buf[strlen(buf)-1] = 0;
344*de572d98SGarrett D'Amore 				(void) strlcat(line, buf, sizeof (line));
345*de572d98SGarrett D'Amore 				continue;
346*de572d98SGarrett D'Amore 			}
347*de572d98SGarrett D'Amore 			(void) strlcat(line, buf, sizeof (line));
348*de572d98SGarrett D'Amore 		}
349*de572d98SGarrett D'Amore 
350*de572d98SGarrett D'Amore 		/* got a line */
351*de572d98SGarrett D'Amore 		ptr = line;
352*de572d98SGarrett D'Amore 		test_trim(&ptr);
353*de572d98SGarrett D'Amore 
354*de572d98SGarrett D'Amore 		/* skip comments and empty lines */
355*de572d98SGarrett D'Amore 		if (ptr[0] == 0 || ptr[0] == '#') {
356*de572d98SGarrett D'Amore 			line[0] = 0;
357*de572d98SGarrett D'Amore 			continue;
358*de572d98SGarrett D'Amore 		}
359*de572d98SGarrett D'Amore 
360*de572d98SGarrett D'Amore 		tok = strsep(&ptr, "|");
361*de572d98SGarrett D'Amore 		if (tok == NULL) {
362*de572d98SGarrett D'Amore 			break;
363*de572d98SGarrett D'Amore 		}
364*de572d98SGarrett D'Amore 		test_trim(&tok);
365*de572d98SGarrett D'Amore 
366*de572d98SGarrett D'Amore 		for (nfields = 0; nfields < MAXFIELD; nfields++) {
367*de572d98SGarrett D'Amore 			fields[nfields] = strsep(&ptr, "|");
368*de572d98SGarrett D'Amore 			if (fields[nfields] == NULL) {
369*de572d98SGarrett D'Amore 				break;
370*de572d98SGarrett D'Amore 			}
371*de572d98SGarrett D'Amore 			test_trim(&fields[nfields]);
372*de572d98SGarrett D'Amore 		}
373*de572d98SGarrett D'Amore 
374*de572d98SGarrett D'Amore 		found = 0;
375*de572d98SGarrett D'Amore 		rv = 0;
376*de572d98SGarrett D'Amore 
377*de572d98SGarrett D'Amore 		for (int i = 0; keyws[i] != NULL; i++) {
378*de572d98SGarrett D'Amore 			if (strcmp(tok, keyws[i]) == 0) {
379*de572d98SGarrett D'Amore 				found++;
380*de572d98SGarrett D'Amore 				err = NULL;
381*de572d98SGarrett D'Amore 				rv = callbs[i](fields, nfields, &err);
382*de572d98SGarrett D'Amore 			}
383*de572d98SGarrett D'Amore 		}
384*de572d98SGarrett D'Amore 		if (!found) {
385*de572d98SGarrett D'Amore 			rv = -1;
386*de572d98SGarrett D'Amore 			err = NULL;
387*de572d98SGarrett D'Amore 			(void) asprintf(&err, "unknown keyword %s", tok);
388*de572d98SGarrett D'Amore 		}
389*de572d98SGarrett D'Amore 		if (rv != 0) {
390*de572d98SGarrett D'Amore 			if (err) {
391*de572d98SGarrett D'Amore 				test_failed(t, "%s:%d: %s", fname,
392*de572d98SGarrett D'Amore 				    lineno, err);
393*de572d98SGarrett D'Amore 				free(err);
394*de572d98SGarrett D'Amore 			} else {
395*de572d98SGarrett D'Amore 				test_failed(t, "%s:%d: unknown error",
396*de572d98SGarrett D'Amore 				    fname, lineno);
397*de572d98SGarrett D'Amore 			}
398*de572d98SGarrett D'Amore 			(void) fclose(cfg);
399*de572d98SGarrett D'Amore 			return (rv);
400*de572d98SGarrett D'Amore 		}
401*de572d98SGarrett D'Amore 
402*de572d98SGarrett D'Amore 		line[0] = 0;
403*de572d98SGarrett D'Amore 	}
404*de572d98SGarrett D'Amore 	(void) fclose(cfg);
405*de572d98SGarrett D'Amore 	return (0);
406*de572d98SGarrett D'Amore }
407