• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
38 static const char *ANSI_HIGHLIGHT_GREEN_ON = "\x1B[1;32m";
39 static const char *ANSI_HIGHLIGHT_RED_ON =  "\x1B[1;31m";
40 static const char *ANSI_HIGHLIGHT_OFF = "\x1B[0m";
41 
42 static const char *progname;
43 static int oneshot = 0;
44 static const char options_short[] = "lhn";
45 static 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 
53 struct _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
now_usec(void)66 static 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 
help(void)76 static 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 
test_list(const struct test * start,const struct test * stop)90 static 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 
test_init(const struct test * start,const struct test * stop,int argc,char * const argv[])99 int 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 
test_find(const struct test * start,const struct test * stop,const char * name)136 const 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 
test_spawn_test(const struct test * t)149 static 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 
test_run_spawned(const struct test * t)159 static 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 
test_spawn_prog(const char * prog,const char * const args[])167 int 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 
test_export_environ(const struct test * t)176 static 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 
test_run_child(const struct test * t,int fdout[2],int fderr[2],int fdmonitor[2])220 static 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 
check_activity(int fd,bool activity,const char * path,const char * stream)275 static 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 
test_run_parent_check_outputs(const struct test * t,int fdout,int fderr,int fdmonitor,pid_t child)293 static 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 
460 out:
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 
safe_read(int fd,void * buf,size_t count)470 static 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 
check_generated_files(const struct test * t)484 static 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 
547 next:
548 		close(fda);
549 		close(fdb);
550 		continue;
551 
552 fail:
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 
cmp_modnames(const void * m1,const void * m2)564 static 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  */
read_expected_modules(const struct test * t,char ** buf,int * count)586 static 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 
read_loaded_modules(const struct test * t,char ** buf,int * count)627 static 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 	}
686 out_dir:
687 	closedir(dir);
688 out:
689 	*count = len;
690 	return res;
691 }
692 
check_loaded_modules(const struct test * t)693 static 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);
735 out_a1:
736 	free(a1);
737 	free(buf1);
738 	return err;
739 }
740 
test_run_parent(const struct test * t,int fdout[2],int fderr[2],int fdmonitor[2],pid_t child)741 static 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 
844 exit:
845 	LOG("------\n");
846 	return err;
847 }
848 
prepend_path(const char * extra)849 static 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 
test_run(const struct test * t)872 int 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