1/*
2 * Copyright (C) 2012-2013  ProFUSION embedded systems
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <dirent.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <getopt.h>
22#include <limits.h>
23#include <stdarg.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <time.h>
28#include <unistd.h>
29#include <sys/epoll.h>
30#include <sys/prctl.h>
31#include <sys/stat.h>
32#include <sys/wait.h>
33
34#include <shared/util.h>
35
36#include "testsuite.h"
37
38static const char *ANSI_HIGHLIGHT_GREEN_ON = "\x1B[1;32m";
39static const char *ANSI_HIGHLIGHT_RED_ON =  "\x1B[1;31m";
40static const char *ANSI_HIGHLIGHT_OFF = "\x1B[0m";
41
42static const char *progname;
43static int oneshot = 0;
44static const char options_short[] = "lhn";
45static const struct option options[] = {
46	{ "list", no_argument, 0, 'l' },
47	{ "help", no_argument, 0, 'h' },
48	{ NULL, 0, 0, 0 }
49};
50
51#define OVERRIDE_LIBDIR ABS_TOP_BUILDDIR "/testsuite/.libs/"
52
53struct _env_config {
54	const char *key;
55	const char *ldpreload;
56} env_config[_TC_LAST] = {
57	[TC_UNAME_R] = { S_TC_UNAME_R, OVERRIDE_LIBDIR  "uname.so" },
58	[TC_ROOTFS] = { S_TC_ROOTFS, OVERRIDE_LIBDIR "path.so" },
59	[TC_INIT_MODULE_RETCODES] = { S_TC_INIT_MODULE_RETCODES, OVERRIDE_LIBDIR "init_module.so" },
60	[TC_DELETE_MODULE_RETCODES] = { S_TC_DELETE_MODULE_RETCODES, OVERRIDE_LIBDIR "delete_module.so" },
61};
62
63#define USEC_PER_SEC  1000000ULL
64#define USEC_PER_MSEC  1000ULL
65#define TEST_TIMEOUT_USEC 2 * USEC_PER_SEC
66static unsigned long long now_usec(void)
67{
68	struct timespec ts;
69
70	if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
71		return 0;
72
73	return ts_usec(&ts);
74}
75
76static void help(void)
77{
78	const struct option *itr;
79	const char *itr_short;
80
81	printf("Usage:\n"
82	       "\t%s [options] <test>\n"
83	       "Options:\n", basename(progname));
84
85	for (itr = options, itr_short = options_short;
86				itr->name != NULL; itr++, itr_short++)
87		printf("\t-%c, --%s\n", *itr_short, itr->name);
88}
89
90static void test_list(const struct test *start, const struct test *stop)
91{
92	const struct test *t;
93
94	printf("Available tests:\n");
95	for (t = start; t < stop; t++)
96		printf("\t%s, %s\n", t->name, t->description);
97}
98
99int test_init(const struct test *start, const struct test *stop,
100	      int argc, char *const argv[])
101{
102	progname = argv[0];
103
104	for (;;) {
105		int c, idx = 0;
106		c = getopt_long(argc, argv, options_short, options, &idx);
107		if (c == -1)
108			break;
109		switch (c) {
110		case 'l':
111			test_list(start, stop);
112			return 0;
113		case 'h':
114			help();
115			return 0;
116		case 'n':
117			oneshot = 1;
118			break;
119		case '?':
120			return -1;
121		default:
122			ERR("unexpected getopt_long() value %c\n", c);
123			return -1;
124		}
125	}
126
127	if (isatty(STDOUT_FILENO) == 0) {
128		ANSI_HIGHLIGHT_OFF = "";
129		ANSI_HIGHLIGHT_RED_ON = "";
130		ANSI_HIGHLIGHT_GREEN_ON = "";
131	}
132
133	return optind;
134}
135
136const struct test *test_find(const struct test *start,
137			     const struct test *stop, const char *name)
138{
139	const struct test *t;
140
141	for (t = start; t < stop; t++) {
142		if (streq(t->name, name))
143			return t;
144	}
145
146	return NULL;
147}
148
149static int test_spawn_test(const struct test *t)
150{
151	const char *const args[] = { progname, "-n", t->name, NULL };
152
153	execv(progname, (char *const *) args);
154
155	ERR("failed to spawn %s for %s: %m\n", progname, t->name);
156	return EXIT_FAILURE;
157}
158
159static int test_run_spawned(const struct test *t)
160{
161	int err = t->func(t);
162	exit(err);
163
164	return EXIT_FAILURE;
165}
166
167int test_spawn_prog(const char *prog, const char *const args[])
168{
169	execv(prog, (char *const *) args);
170
171	ERR("failed to spawn %s\n", prog);
172	ERR("did you forget to build tools?\n");
173	return EXIT_FAILURE;
174}
175
176static void test_export_environ(const struct test *t)
177{
178	char *preload = NULL;
179	size_t preloadlen = 0;
180	size_t i;
181	const struct keyval *env;
182
183	unsetenv("LD_PRELOAD");
184
185	for (i = 0; i < _TC_LAST; i++) {
186		const char *ldpreload;
187		size_t ldpreloadlen;
188		char *tmp;
189
190		if (t->config[i] == NULL)
191			continue;
192
193		setenv(env_config[i].key, t->config[i], 1);
194
195		ldpreload = env_config[i].ldpreload;
196		ldpreloadlen = strlen(ldpreload);
197		tmp = realloc(preload, preloadlen + 2 + ldpreloadlen);
198		if (tmp == NULL) {
199			ERR("oom: test_export_environ()\n");
200			return;
201		}
202		preload = tmp;
203
204		if (preloadlen > 0)
205			preload[preloadlen++] = ' ';
206		memcpy(preload + preloadlen, ldpreload, ldpreloadlen);
207		preloadlen += ldpreloadlen;
208		preload[preloadlen] = '\0';
209	}
210
211	if (preload != NULL)
212		setenv("LD_PRELOAD", preload, 1);
213
214	free(preload);
215
216	for (env = t->env_vars; env && env->key; env++)
217		setenv(env->key, env->val, 1);
218}
219
220static inline int test_run_child(const struct test *t, int fdout[2],
221						int fderr[2], int fdmonitor[2])
222{
223	/* kill child if parent dies */
224	prctl(PR_SET_PDEATHSIG, SIGTERM);
225
226	test_export_environ(t);
227
228	/* Close read-fds and redirect std{out,err} to the write-fds */
229	if (t->output.out != NULL) {
230		close(fdout[0]);
231		if (dup2(fdout[1], STDOUT_FILENO) < 0) {
232			ERR("could not redirect stdout to pipe: %m\n");
233			exit(EXIT_FAILURE);
234		}
235	}
236
237	if (t->output.err != NULL) {
238		close(fderr[0]);
239		if (dup2(fderr[1], STDERR_FILENO) < 0) {
240			ERR("could not redirect stderr to pipe: %m\n");
241			exit(EXIT_FAILURE);
242		}
243	}
244
245	close(fdmonitor[0]);
246
247	if (t->config[TC_ROOTFS] != NULL) {
248		const char *stamp = TESTSUITE_ROOTFS "../stamp-rootfs";
249		const char *rootfs = t->config[TC_ROOTFS];
250		struct stat rootfsst, stampst;
251
252		if (stat(stamp, &stampst) != 0) {
253			ERR("could not stat %s\n - %m", stamp);
254			exit(EXIT_FAILURE);
255		}
256
257		if (stat(rootfs, &rootfsst) != 0) {
258			ERR("could not stat %s\n - %m", rootfs);
259			exit(EXIT_FAILURE);
260		}
261
262		if (stat_mstamp(&rootfsst) > stat_mstamp(&stampst)) {
263			ERR("rootfs %s is dirty, please run 'make rootfs' before runnning this test\n",
264								rootfs);
265			exit(EXIT_FAILURE);
266		}
267	}
268
269	if (t->need_spawn)
270		return test_spawn_test(t);
271	else
272		return test_run_spawned(t);
273}
274
275static int check_activity(int fd, bool activity,  const char *path,
276			  const char *stream)
277{
278	struct stat st;
279
280	/* not monitoring or monitoring and it has activity */
281	if (fd < 0 || activity)
282		return 0;
283
284	/* monitoring, there was no activity and size matches */
285	if (stat(path, &st) == 0 && st.st_size == 0)
286		return 0;
287
288	ERR("Expecting output on %s, but test didn't produce any\n", stream);
289
290	return -1;
291}
292
293static inline bool test_run_parent_check_outputs(const struct test *t,
294			int fdout, int fderr, int fdmonitor, pid_t child)
295{
296	struct epoll_event ep_outpipe, ep_errpipe, ep_monitor;
297	int err, fd_ep, fd_matchout = -1, fd_matcherr = -1;
298	bool fd_activityout = false, fd_activityerr = false;
299	unsigned long long end_usec, start_usec;
300
301	fd_ep = epoll_create1(EPOLL_CLOEXEC);
302	if (fd_ep < 0) {
303		ERR("could not create epoll fd: %m\n");
304		return false;
305	}
306
307	if (t->output.out != NULL) {
308		fd_matchout = open(t->output.out, O_RDONLY);
309		if (fd_matchout < 0) {
310			err = -errno;
311			ERR("could not open %s for read: %m\n",
312							t->output.out);
313			goto out;
314		}
315		memset(&ep_outpipe, 0, sizeof(struct epoll_event));
316		ep_outpipe.events = EPOLLIN;
317		ep_outpipe.data.ptr = &fdout;
318		if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fdout, &ep_outpipe) < 0) {
319			err = -errno;
320			ERR("could not add fd to epoll: %m\n");
321			goto out;
322		}
323	} else
324		fdout = -1;
325
326	if (t->output.err != NULL) {
327		fd_matcherr = open(t->output.err, O_RDONLY);
328		if (fd_matcherr < 0) {
329			err = -errno;
330			ERR("could not open %s for read: %m\n",
331					t->output.err);
332			goto out;
333
334		}
335		memset(&ep_errpipe, 0, sizeof(struct epoll_event));
336		ep_errpipe.events = EPOLLIN;
337		ep_errpipe.data.ptr = &fderr;
338		if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fderr, &ep_errpipe) < 0) {
339			err = -errno;
340			ERR("could not add fd to epoll: %m\n");
341			goto out;
342		}
343	} else
344		fderr = -1;
345
346	memset(&ep_monitor, 0, sizeof(struct epoll_event));
347	ep_monitor.events = EPOLLHUP;
348	ep_monitor.data.ptr = &fdmonitor;
349	if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fdmonitor, &ep_monitor) < 0) {
350		err = -errno;
351		ERR("could not add monitor fd to epoll: %m\n");
352		goto out;
353	}
354
355	start_usec = now_usec();
356	end_usec = start_usec + TEST_TIMEOUT_USEC;
357
358	for (err = 0; fdmonitor >= 0 || fdout >= 0 || fderr >= 0;) {
359		int fdcount, i, timeout;
360		struct epoll_event ev[4];
361		unsigned long long curr_usec = now_usec();
362
363		if (curr_usec > end_usec)
364			break;
365
366		timeout = (end_usec - curr_usec) / USEC_PER_MSEC;
367		fdcount = epoll_wait(fd_ep, ev, 4, timeout);
368		if (fdcount < 0) {
369			if (errno == EINTR)
370				continue;
371			err = -errno;
372			ERR("could not poll: %m\n");
373			goto out;
374		}
375
376		for (i = 0;  i < fdcount; i++) {
377			int *fd = ev[i].data.ptr;
378
379			if (ev[i].events & EPOLLIN) {
380				ssize_t r, done = 0;
381				char buf[4096];
382				char bufmatch[4096];
383				int fd_match;
384
385				/*
386				 * compare the output from child with the one
387				 * saved as correct
388				 */
389
390				r = read(*fd, buf, sizeof(buf) - 1);
391				if (r <= 0)
392					continue;
393
394				if (*fd == fdout) {
395					fd_match = fd_matchout;
396					fd_activityout = true;
397				} else if (*fd == fderr) {
398					fd_match = fd_matcherr;
399					fd_activityerr = true;
400				} else {
401					ERR("Unexpected activity on monitor pipe\n");
402					err = -EINVAL;
403					goto out;
404				}
405
406				for (;;) {
407					int rmatch = read(fd_match,
408						bufmatch + done, r - done);
409					if (rmatch == 0)
410						break;
411
412					if (rmatch < 0) {
413						if (errno == EINTR)
414							continue;
415						err = -errno;
416						ERR("could not read match fd %d\n",
417								fd_match);
418						goto out;
419					}
420
421					done += rmatch;
422				}
423
424				buf[r] = '\0';
425				bufmatch[r] = '\0';
426
427				if (t->print_outputs)
428					printf("%s: %s\n",
429					       fd_match == fd_matchout ? "STDOUT:" : "STDERR:",
430					       buf);
431
432				if (!streq(buf, bufmatch)) {
433					ERR("Outputs do not match on %s:\n",
434						fd_match == fd_matchout ? "STDOUT" : "STDERR");
435					ERR("correct:\n%s\n", bufmatch);
436					ERR("wrong:\n%s\n", buf);
437					err = -1;
438					goto out;
439				}
440			} else if (ev[i].events & EPOLLHUP) {
441				if (epoll_ctl(fd_ep, EPOLL_CTL_DEL,
442							*fd, NULL) < 0) {
443					ERR("could not remove fd %d from epoll: %m\n",
444									*fd);
445				}
446				*fd = -1;
447			}
448		}
449	}
450
451	err = check_activity(fd_matchout, fd_activityout, t->output.out, "stdout");
452	err |= check_activity(fd_matcherr, fd_activityerr, t->output.err, "stderr");
453
454	if (err == 0 && fdmonitor >= 0) {
455		err = -EINVAL;
456		ERR("Test '%s' timed out, killing %d\n", t->name, child);
457		kill(child, SIGKILL);
458	}
459
460out:
461	if (fd_matchout >= 0)
462		close(fd_matchout);
463	if (fd_matcherr >= 0)
464		close(fd_matcherr);
465	if (fd_ep >= 0)
466		close(fd_ep);
467	return err == 0;
468}
469
470static inline int safe_read(int fd, void *buf, size_t count)
471{
472	int r;
473
474	while (1) {
475		r = read(fd, buf, count);
476		if (r == -1 && errno == EINTR)
477			continue;
478		break;
479	}
480
481	return r;
482}
483
484static bool check_generated_files(const struct test *t)
485{
486	const struct keyval *k;
487
488	/* This is not meant to be a diff replacement, just stupidly check if
489	 * the files match. Bear in mind they can be binary files */
490	for (k = t->output.files; k && k->key; k++) {
491		struct stat sta, stb;
492		int fda = -1, fdb = -1;
493		char bufa[4096];
494		char bufb[4096];
495
496		fda = open(k->key, O_RDONLY);
497		if (fda < 0) {
498			ERR("could not open %s\n - %m\n", k->key);
499			goto fail;
500		}
501
502		fdb = open(k->val, O_RDONLY);
503		if (fdb < 0) {
504			ERR("could not open %s\n - %m\n", k->val);
505			goto fail;
506		}
507
508		if (fstat(fda, &sta) != 0) {
509			ERR("could not fstat %d %s\n - %m\n", fda, k->key);
510			goto fail;
511		}
512
513		if (fstat(fdb, &stb) != 0) {
514			ERR("could not fstat %d %s\n - %m\n", fdb, k->key);
515			goto fail;
516		}
517
518		if (sta.st_size != stb.st_size) {
519			ERR("sizes do not match %s %s\n", k->key, k->val);
520			goto fail;
521		}
522
523		for (;;) {
524			int r, done;
525
526			r = safe_read(fda, bufa, sizeof(bufa));
527			if (r < 0)
528				goto fail;
529
530			if (r == 0)
531				/* size is already checked, go to next file */
532				goto next;
533
534			for (done = 0; done < r;) {
535				int r2 = safe_read(fdb, bufb + done, r - done);
536
537				if (r2 <= 0)
538					goto fail;
539
540				done += r2;
541			}
542
543			if (memcmp(bufa, bufb, r) != 0)
544				goto fail;
545		}
546
547next:
548		close(fda);
549		close(fdb);
550		continue;
551
552fail:
553		if (fda >= 0)
554			close(fda);
555		if (fdb >= 0)
556			close(fdb);
557
558		return false;
559	}
560
561	return true;
562}
563
564static int cmp_modnames(const void *m1, const void *m2)
565{
566	const char *s1 = *(char *const *)m1;
567	const char *s2 = *(char *const *)m2;
568	int i;
569
570	for (i = 0; s1[i] || s2[i]; i++) {
571		char c1 = s1[i], c2 = s2[i];
572		if (c1 == '-')
573			c1 = '_';
574		if (c2 == '-')
575			c2 = '_';
576		if (c1 != c2)
577			return c1 - c2;
578	}
579	return 0;
580}
581
582/*
583 * Store the expected module names in buf and return a list of pointers to
584 * them.
585 */
586static const char **read_expected_modules(const struct test *t,
587		char **buf, int *count)
588{
589	const char **res;
590	int len;
591	int i;
592	char *p;
593
594	if (t->modules_loaded[0] == '\0') {
595		*count = 0;
596		*buf = NULL;
597		return NULL;
598	}
599	*buf = strdup(t->modules_loaded);
600	if (!*buf) {
601		*count = -1;
602		return NULL;
603	}
604	len = 1;
605	for (p = *buf; *p; p++)
606		if (*p == ',')
607			len++;
608	res = malloc(sizeof(char *) * len);
609	if (!res) {
610		perror("malloc");
611		*count = -1;
612		free(*buf);
613		*buf = NULL;
614		return NULL;
615	}
616	i = 0;
617	res[i++] = *buf;
618	for (p = *buf; i < len; p++)
619		if (*p == ',') {
620			*p = '\0';
621			res[i++] = p + 1;
622		}
623	*count = len;
624	return res;
625}
626
627static char **read_loaded_modules(const struct test *t, char **buf, int *count)
628{
629	char dirname[PATH_MAX];
630	DIR *dir;
631	struct dirent *dirent;
632	int i;
633	int len = 0, bufsz;
634	char **res = NULL;
635	char *p;
636	const char *rootfs = t->config[TC_ROOTFS] ? t->config[TC_ROOTFS] : "";
637
638	/* Store the entries in /sys/module to res */
639	if (snprintf(dirname, sizeof(dirname), "%s/sys/module", rootfs)
640			>= (int)sizeof(dirname)) {
641		ERR("rootfs path too long: %s\n", rootfs);
642		*buf = NULL;
643		len = -1;
644		goto out;
645	}
646	dir = opendir(dirname);
647	/* not an error, simply return empty list */
648	if (!dir) {
649		*buf = NULL;
650		goto out;
651	}
652	bufsz = 0;
653	while ((dirent = readdir(dir))) {
654		if (dirent->d_name[0] == '.')
655			continue;
656		len++;
657		bufsz += strlen(dirent->d_name) + 1;
658	}
659	res = malloc(sizeof(char *) * len);
660	if (!res) {
661		perror("malloc");
662		len = -1;
663		goto out_dir;
664	}
665	*buf = malloc(bufsz);
666	if (!*buf) {
667		perror("malloc");
668		free(res);
669		res = NULL;
670		len = -1;
671		goto out_dir;
672	}
673	rewinddir(dir);
674	i = 0;
675	p = *buf;
676	while ((dirent = readdir(dir))) {
677		int size;
678
679		if (dirent->d_name[0] == '.')
680			continue;
681		size = strlen(dirent->d_name) + 1;
682		memcpy(p, dirent->d_name, size);
683		res[i++] = p;
684		p += size;
685	}
686out_dir:
687	closedir(dir);
688out:
689	*count = len;
690	return res;
691}
692
693static int check_loaded_modules(const struct test *t)
694{
695	int l1, l2, i1, i2;
696	const char **a1;
697	char **a2;
698	char *buf1, *buf2;
699	int err = false;
700
701	a1 = read_expected_modules(t, &buf1, &l1);
702	if (l1 < 0)
703		return err;
704	a2 = read_loaded_modules(t, &buf2, &l2);
705	if (l2 < 0)
706		goto out_a1;
707	qsort(a1, l1, sizeof(char *), cmp_modnames);
708	qsort(a2, l2, sizeof(char *), cmp_modnames);
709	i1 = i2 = 0;
710	err = true;
711	while (i1 < l1 || i2 < l2) {
712		int cmp;
713
714		if (i1 >= l1)
715			cmp = 1;
716		else if (i2 >= l2)
717			cmp = -1;
718		else
719			cmp = cmp_modnames(&a1[i1], &a2[i2]);
720		if (cmp == 0) {
721			i1++;
722			i2++;
723		} else if (cmp < 0) {
724			err = false;
725			ERR("module %s not loaded\n", a1[i1]);
726			i1++;
727		} else  {
728			err = false;
729			ERR("module %s is loaded but should not be \n", a2[i2]);
730			i2++;
731		}
732	}
733	free(a2);
734	free(buf2);
735out_a1:
736	free(a1);
737	free(buf1);
738	return err;
739}
740
741static inline int test_run_parent(const struct test *t, int fdout[2],
742				int fderr[2], int fdmonitor[2], pid_t child)
743{
744	pid_t pid;
745	int err;
746	bool matchout, match_modules;
747
748	/* Close write-fds */
749	if (t->output.out != NULL)
750		close(fdout[1]);
751	if (t->output.err != NULL)
752		close(fderr[1]);
753	close(fdmonitor[1]);
754
755	matchout = test_run_parent_check_outputs(t, fdout[0], fderr[0],
756							fdmonitor[0], child);
757
758	/*
759	 * break pipe on the other end: either child already closed or we want
760	 * to stop it
761	 */
762	if (t->output.out != NULL)
763		close(fdout[0]);
764	if (t->output.err != NULL)
765		close(fderr[0]);
766	close(fdmonitor[0]);
767
768	do {
769		pid = wait(&err);
770		if (pid == -1) {
771			ERR("error waitpid(): %m\n");
772			err = EXIT_FAILURE;
773			goto exit;
774		}
775	} while (!WIFEXITED(err) && !WIFSIGNALED(err));
776
777	if (WIFEXITED(err)) {
778		if (WEXITSTATUS(err) != 0)
779			ERR("'%s' [%u] exited with return code %d\n",
780					t->name, pid, WEXITSTATUS(err));
781		else
782			LOG("'%s' [%u] exited with return code %d\n",
783					t->name, pid, WEXITSTATUS(err));
784	} else if (WIFSIGNALED(err)) {
785		ERR("'%s' [%u] terminated by signal %d (%s)\n", t->name, pid,
786				WTERMSIG(err), strsignal(WTERMSIG(err)));
787		err = t->expected_fail ? EXIT_SUCCESS : EXIT_FAILURE;
788		goto exit;
789	}
790
791	if (matchout)
792		matchout = check_generated_files(t);
793	if (t->modules_loaded)
794		match_modules = check_loaded_modules(t);
795	else
796		match_modules = true;
797
798	if (t->expected_fail == false) {
799		if (err == 0) {
800			if (matchout && match_modules)
801				LOG("%sPASSED%s: %s\n",
802					ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
803					t->name);
804			else {
805				ERR("%sFAILED%s: exit ok but %s do not match: %s\n",
806					ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
807					matchout ? "loaded modules" : "outputs",
808					t->name);
809				err = EXIT_FAILURE;
810			}
811		} else {
812			ERR("%sFAILED%s: %s\n",
813					ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
814					t->name);
815		}
816	} else {
817		if (err == 0) {
818			if (matchout) {
819				ERR("%sUNEXPECTED PASS%s: exit with 0: %s\n",
820					ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
821					t->name);
822				err = EXIT_FAILURE;
823			} else {
824				ERR("%sUNEXPECTED PASS%s: exit with 0 and outputs do not match: %s\n",
825					ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
826					t->name);
827				err = EXIT_FAILURE;
828			}
829		} else {
830			if (matchout) {
831				LOG("%sEXPECTED FAIL%s: %s\n",
832					ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
833					t->name);
834				err = EXIT_SUCCESS;
835			} else {
836				LOG("%sEXPECTED FAIL%s: exit with %d but outputs do not match: %s\n",
837					ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
838					WEXITSTATUS(err), t->name);
839				err = EXIT_FAILURE;
840			}
841		}
842	}
843
844exit:
845	LOG("------\n");
846	return err;
847}
848
849static int prepend_path(const char *extra)
850{
851	char *oldpath, *newpath;
852	int r;
853
854	if (extra == NULL)
855		return 0;
856
857	oldpath = getenv("PATH");
858	if (oldpath == NULL)
859		return setenv("PATH", extra, 1);
860
861	if (asprintf(&newpath, "%s:%s", extra, oldpath) < 0) {
862		ERR("failed to allocate memory to new PATH\n");
863		return -1;
864	}
865
866	r = setenv("PATH", newpath, 1);
867	free(newpath);
868
869	return r;
870}
871
872int test_run(const struct test *t)
873{
874	pid_t pid;
875	int fdout[2];
876	int fderr[2];
877	int fdmonitor[2];
878
879	if (t->need_spawn && oneshot)
880		test_run_spawned(t);
881
882	if (t->output.out != NULL) {
883		if (pipe(fdout) != 0) {
884			ERR("could not create out pipe for %s\n", t->name);
885			return EXIT_FAILURE;
886		}
887	}
888
889	if (t->output.err != NULL) {
890		if (pipe(fderr) != 0) {
891			ERR("could not create err pipe for %s\n", t->name);
892			return EXIT_FAILURE;
893		}
894	}
895
896	if (pipe(fdmonitor) != 0) {
897		ERR("could not create monitor pipe for %s\n", t->name);
898		return EXIT_FAILURE;
899	}
900
901	if (prepend_path(t->path) < 0) {
902		ERR("failed to prepend '%s' to PATH\n", t->path);
903		return EXIT_FAILURE;
904	}
905
906	LOG("running %s, in forked context\n", t->name);
907
908	pid = fork();
909	if (pid < 0) {
910		ERR("could not fork(): %m\n");
911		LOG("FAILED: %s\n", t->name);
912		return EXIT_FAILURE;
913	}
914
915	if (pid > 0)
916		return test_run_parent(t, fdout, fderr, fdmonitor, pid);
917
918	return test_run_child(t, fdout, fderr, fdmonitor);
919}
920