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 /*
13de572d98SGarrett 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>
23de572d98SGarrett D'Amore #include <string.h>
24de572d98SGarrett D'Amore #include <errno.h>
25538aa54dSGarrett D'Amore #include <pthread.h>
26de572d98SGarrett D'Amore #include <ctype.h>
27de572d98SGarrett D'Amore #include <unistd.h>
28de572d98SGarrett 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 
35de572d98SGarrett D'Amore static int passes;
36de572d98SGarrett D'Amore static int tests;
37de572d98SGarrett 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
test_set_debug(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
test_set_force(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
test_start(const char * format,...)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();
87de572d98SGarrett D'Amore 	test_summary();
88de572d98SGarrett D'Amore 	(void) test_load_config(t, NULL, NULL);
89538aa54dSGarrett D'Amore #endif
90538aa54dSGarrett D'Amore 
91de572d98SGarrett D'Amore 	tests++;
92538aa54dSGarrett D'Amore 	return (t);
93538aa54dSGarrett D'Amore }
94538aa54dSGarrett D'Amore 
95538aa54dSGarrett D'Amore void
test_failed(test_t t,const char * format,...)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);
101de572d98SGarrett D'Amore 	if (t == NULL) {
102de572d98SGarrett D'Amore 		(void) printf("FAILURE: ");
103de572d98SGarrett D'Amore 		va_start(args, format);
104de572d98SGarrett D'Amore 		(void) vprintf(format, args);
105de572d98SGarrett D'Amore 		va_end(args);
106de572d98SGarrett D'Amore 		(void) printf("\n");
107de572d98SGarrett D'Amore 		(void) fflush(stdout);
108de572d98SGarrett D'Amore 		(void) pthread_mutex_unlock(&lk);
109de572d98SGarrett D'Amore 		return;
110de572d98SGarrett 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
test_passed(test_t t)135538aa54dSGarrett D'Amore test_passed(test_t t)
136538aa54dSGarrett D'Amore {
137de572d98SGarrett D'Amore 	if (t == NULL) {
138de572d98SGarrett D'Amore 		return;
139de572d98SGarrett 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) {
150de572d98SGarrett 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 
164de572d98SGarrett D'Amore void
test_summary(void)165de572d98SGarrett D'Amore test_summary(void)
166de572d98SGarrett D'Amore {
167de572d98SGarrett D'Amore 	if (passes == tests) {
168de572d98SGarrett D'Amore 		(void) printf("TEST SUMMARY: %d / %d (ok)\n", passes, tests);
169de572d98SGarrett D'Amore 	} else {
170de572d98SGarrett D'Amore 		(void) printf("TEST SUMMARY: %d / %d (%d failing)\n",
171de572d98SGarrett D'Amore 		    passes, tests, tests - passes);
172de572d98SGarrett D'Amore 	}
173de572d98SGarrett D'Amore }
174de572d98SGarrett D'Amore 
175538aa54dSGarrett D'Amore void
test_debugf(test_t t,const char * format,...)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);
184de572d98SGarrett D'Amore 	if (t) {
185de572d98SGarrett D'Amore 		(void) printf("TEST DEBUG %s: ", t->name);
186de572d98SGarrett D'Amore 	} else {
187de572d98SGarrett D'Amore 		(void) printf("TEST DEBUG: ");
188de572d98SGarrett 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 *
test_thr_one(void * arg)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
test_run(int nthr,void (* func)(test_t,void *),void * arg,const char * tname,...)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 }
245de572d98SGarrett D'Amore 
246de572d98SGarrett D'Amore void
test_trim(char ** ptr)247de572d98SGarrett D'Amore test_trim(char **ptr)
248de572d98SGarrett D'Amore {
249de572d98SGarrett D'Amore 	char *p = *ptr;
250de572d98SGarrett D'Amore 	while (isspace(*p)) {
251de572d98SGarrett D'Amore 		p++;
252de572d98SGarrett D'Amore 	}
253de572d98SGarrett D'Amore 	*ptr = p;
254de572d98SGarrett D'Amore 	p += strlen(p);
255de572d98SGarrett D'Amore 	while ((--p >= *ptr) && (isspace(*p))) {
256*fc2512cfSRobert Mustacchi 		*p = '\0';
257de572d98SGarrett D'Amore 	}
258de572d98SGarrett D'Amore }
259de572d98SGarrett D'Amore 
260de572d98SGarrett D'Amore #define	MAXCB		20
261de572d98SGarrett D'Amore #define	MAXFIELD	20
262de572d98SGarrett D'Amore 
263de572d98SGarrett D'Amore int
test_load_config(test_t t,const char * fname,...)264de572d98SGarrett D'Amore test_load_config(test_t t, const char *fname, ...)
265de572d98SGarrett D'Amore {
266de572d98SGarrett D'Amore 	va_list		va;
267de572d98SGarrett D'Amore 	const char	*keyws[MAXCB];
268de572d98SGarrett D'Amore 	test_cfg_func_t	callbs[MAXCB];
269de572d98SGarrett D'Amore 	char		*fields[MAXFIELD];
270de572d98SGarrett D'Amore 	int		nfields;
271de572d98SGarrett D'Amore 
272de572d98SGarrett D'Amore 	FILE    	*cfg;
273de572d98SGarrett D'Amore 	char    	line[1024];
274de572d98SGarrett D'Amore 	char    	buf[1024];
275de572d98SGarrett D'Amore 	int		done;
276de572d98SGarrett D'Amore 	char		*ptr;
277de572d98SGarrett D'Amore 	char		*tok;
278de572d98SGarrett D'Amore 	char		*err;
279de572d98SGarrett D'Amore 	int		lineno;
280de572d98SGarrett D'Amore 	int		rv;
281de572d98SGarrett D'Amore 	int		found;
282de572d98SGarrett D'Amore 	char		path[MAXPATHLEN];
283de572d98SGarrett D'Amore 	int		i;
284de572d98SGarrett D'Amore 
285de572d98SGarrett D'Amore 	va_start(va, fname);
286de572d98SGarrett D'Amore 	for (i = 0; i < MAXCB; i++) {
287de572d98SGarrett D'Amore 		keyws[i] = (const char *)va_arg(va, const char *);
288de572d98SGarrett D'Amore 		if (keyws[i] == NULL)
289de572d98SGarrett D'Amore 			break;
290de572d98SGarrett D'Amore 		callbs[i] = (test_cfg_func_t)va_arg(va, test_cfg_func_t);
291de572d98SGarrett D'Amore 	}
292de572d98SGarrett D'Amore 	va_end(va);
293de572d98SGarrett D'Amore 	if (i == MAXCB) {
294de572d98SGarrett D'Amore 		test_debugf(t, "too many arguments to function >= %d", MAXCB);
295de572d98SGarrett D'Amore 	}
296de572d98SGarrett D'Amore 
297de572d98SGarrett D'Amore 	found = 0;
298de572d98SGarrett D'Amore 
299de572d98SGarrett D'Amore 	if (access(fname, F_OK) == 0) {
300de572d98SGarrett D'Amore 		found++;
301de572d98SGarrett D'Amore 	}
302de572d98SGarrett D'Amore 	if (!found && fname[0] != '/') {
303de572d98SGarrett D'Amore 		char *stf = getenv("STF_SUITE");
304de572d98SGarrett D'Amore 		if (stf == NULL) {
305de572d98SGarrett D'Amore 			stf = "../..";
306de572d98SGarrett D'Amore 		}
307de572d98SGarrett D'Amore 		(void) snprintf(path, sizeof (path), "%s/cfg/%s", stf, fname);
308de572d98SGarrett D'Amore 		if (access(path, F_OK) == 0) {
309de572d98SGarrett D'Amore 			fname = path;
310de572d98SGarrett D'Amore 			found++;
311de572d98SGarrett D'Amore 		} else {
312de572d98SGarrett D'Amore 			(void) snprintf(path, sizeof (path), "cfg/%s", fname);
313de572d98SGarrett D'Amore 			if (access(path, F_OK) == 0) {
314de572d98SGarrett D'Amore 				fname = path;
315de572d98SGarrett D'Amore 				found++;
316de572d98SGarrett D'Amore 			}
317de572d98SGarrett D'Amore 		}
318de572d98SGarrett D'Amore 	}
319de572d98SGarrett D'Amore 
320de572d98SGarrett D'Amore 	if ((cfg = fopen(fname, "r")) ==  NULL) {
321de572d98SGarrett D'Amore 		test_failed(t, "open(%s): %s", fname, strerror(errno));
322de572d98SGarrett D'Amore 		return (-1);
323de572d98SGarrett D'Amore 	}
324de572d98SGarrett D'Amore 
325de572d98SGarrett D'Amore 	line[0] = 0;
326de572d98SGarrett D'Amore 	done = 0;
327de572d98SGarrett D'Amore 	lineno = 0;
328de572d98SGarrett D'Amore 
329de572d98SGarrett D'Amore 	while (!done) {
330de572d98SGarrett D'Amore 
331de572d98SGarrett D'Amore 		lineno++;
332de572d98SGarrett D'Amore 
333de572d98SGarrett D'Amore 		if (fgets(buf, sizeof (buf), cfg) == NULL) {
334de572d98SGarrett D'Amore 			done++;
335de572d98SGarrett D'Amore 		} else {
336de572d98SGarrett D'Amore 			(void) strtok(buf, "\n");
337de572d98SGarrett D'Amore 			if ((*buf != 0) && (buf[strlen(buf)-1] == '\\')) {
338de572d98SGarrett D'Amore 				/*
339de572d98SGarrett D'Amore 				 * Continuation.  This isn't quite right,
340de572d98SGarrett D'Amore 				 * as it doesn't allow for a "\" at the
341de572d98SGarrett D'Amore 				 * end of line (no escaping).
342de572d98SGarrett D'Amore 				 */
343de572d98SGarrett D'Amore 				buf[strlen(buf)-1] = 0;
344de572d98SGarrett D'Amore 				(void) strlcat(line, buf, sizeof (line));
345de572d98SGarrett D'Amore 				continue;
346de572d98SGarrett D'Amore 			}
347de572d98SGarrett D'Amore 			(void) strlcat(line, buf, sizeof (line));
348de572d98SGarrett D'Amore 		}
349de572d98SGarrett D'Amore 
350de572d98SGarrett D'Amore 		/* got a line */
351de572d98SGarrett D'Amore 		ptr = line;
352de572d98SGarrett D'Amore 		test_trim(&ptr);
353de572d98SGarrett D'Amore 
354de572d98SGarrett D'Amore 		/* skip comments and empty lines */
355de572d98SGarrett D'Amore 		if (ptr[0] == 0 || ptr[0] == '#') {
356de572d98SGarrett D'Amore 			line[0] = 0;
357de572d98SGarrett D'Amore 			continue;
358de572d98SGarrett D'Amore 		}
359de572d98SGarrett D'Amore 
360de572d98SGarrett D'Amore 		tok = strsep(&ptr, "|");
361de572d98SGarrett D'Amore 		if (tok == NULL) {
362de572d98SGarrett D'Amore 			break;
363de572d98SGarrett D'Amore 		}
364de572d98SGarrett D'Amore 		test_trim(&tok);
365de572d98SGarrett D'Amore 
366de572d98SGarrett D'Amore 		for (nfields = 0; nfields < MAXFIELD; nfields++) {
367de572d98SGarrett D'Amore 			fields[nfields] = strsep(&ptr, "|");
368de572d98SGarrett D'Amore 			if (fields[nfields] == NULL) {
369de572d98SGarrett D'Amore 				break;
370de572d98SGarrett D'Amore 			}
371de572d98SGarrett D'Amore 			test_trim(&fields[nfields]);
372de572d98SGarrett D'Amore 		}
373de572d98SGarrett D'Amore 
374de572d98SGarrett D'Amore 		found = 0;
375de572d98SGarrett D'Amore 		rv = 0;
376de572d98SGarrett D'Amore 
377de572d98SGarrett D'Amore 		for (int i = 0; keyws[i] != NULL; i++) {
378de572d98SGarrett D'Amore 			if (strcmp(tok, keyws[i]) == 0) {
379de572d98SGarrett D'Amore 				found++;
380de572d98SGarrett D'Amore 				err = NULL;
381de572d98SGarrett D'Amore 				rv = callbs[i](fields, nfields, &err);
382de572d98SGarrett D'Amore 			}
383de572d98SGarrett D'Amore 		}
384de572d98SGarrett D'Amore 		if (!found) {
385de572d98SGarrett D'Amore 			rv = -1;
386de572d98SGarrett D'Amore 			err = NULL;
387de572d98SGarrett D'Amore 			(void) asprintf(&err, "unknown keyword %s", tok);
388de572d98SGarrett D'Amore 		}
389de572d98SGarrett D'Amore 		if (rv != 0) {
390de572d98SGarrett D'Amore 			if (err) {
391de572d98SGarrett D'Amore 				test_failed(t, "%s:%d: %s", fname,
392de572d98SGarrett D'Amore 				    lineno, err);
393de572d98SGarrett D'Amore 				free(err);
394de572d98SGarrett D'Amore 			} else {
395de572d98SGarrett D'Amore 				test_failed(t, "%s:%d: unknown error",
396de572d98SGarrett D'Amore 				    fname, lineno);
397de572d98SGarrett D'Amore 			}
398de572d98SGarrett D'Amore 			(void) fclose(cfg);
399de572d98SGarrett D'Amore 			return (rv);
400de572d98SGarrett D'Amore 		}
401de572d98SGarrett D'Amore 
402de572d98SGarrett D'Amore 		line[0] = 0;
403de572d98SGarrett D'Amore 	}
404de572d98SGarrett D'Amore 	(void) fclose(cfg);
405de572d98SGarrett D'Amore 	return (0);
406de572d98SGarrett D'Amore }