• 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 <regex.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include <sys/epoll.h>
31 #include <sys/prctl.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
34 
35 #include <shared/util.h>
36 
37 #include "testsuite.h"
38 
39 static const char *ANSI_HIGHLIGHT_GREEN_ON = "\x1B[1;32m";
40 static const char *ANSI_HIGHLIGHT_RED_ON =  "\x1B[1;31m";
41 static const char *ANSI_HIGHLIGHT_OFF = "\x1B[0m";
42 
43 static const char *progname;
44 static int oneshot = 0;
45 static const char options_short[] = "lhn";
46 static const struct option options[] = {
47 	{ "list", no_argument, 0, 'l' },
48 	{ "help", no_argument, 0, 'h' },
49 	{ NULL, 0, 0, 0 }
50 };
51 
52 #define OVERRIDE_LIBDIR ABS_TOP_BUILDDIR "/testsuite/.libs/"
53 
54 struct _env_config {
55 	const char *key;
56 	const char *ldpreload;
57 } env_config[_TC_LAST] = {
58 	[TC_UNAME_R] = { S_TC_UNAME_R, OVERRIDE_LIBDIR  "uname.so" },
59 	[TC_ROOTFS] = { S_TC_ROOTFS, OVERRIDE_LIBDIR "path.so" },
60 	[TC_INIT_MODULE_RETCODES] = { S_TC_INIT_MODULE_RETCODES, OVERRIDE_LIBDIR "init_module.so" },
61 	[TC_DELETE_MODULE_RETCODES] = { S_TC_DELETE_MODULE_RETCODES, OVERRIDE_LIBDIR "delete_module.so" },
62 };
63 
64 #define USEC_PER_SEC  1000000ULL
65 #define USEC_PER_MSEC  1000ULL
66 #define TEST_TIMEOUT_USEC 2 * USEC_PER_SEC
now_usec(void)67 static unsigned long long now_usec(void)
68 {
69 	struct timespec ts;
70 
71 	if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
72 		return 0;
73 
74 	return ts_usec(&ts);
75 }
76 
help(void)77 static void help(void)
78 {
79 	const struct option *itr;
80 	const char *itr_short;
81 
82 	printf("Usage:\n"
83 	       "\t%s [options] <test>\n"
84 	       "Options:\n", basename(progname));
85 
86 	for (itr = options, itr_short = options_short;
87 				itr->name != NULL; itr++, itr_short++)
88 		printf("\t-%c, --%s\n", *itr_short, itr->name);
89 }
90 
test_list(const struct test * start,const struct test * stop)91 static void test_list(const struct test *start, const struct test *stop)
92 {
93 	const struct test *t;
94 
95 	printf("Available tests:\n");
96 	for (t = start; t < stop; t++)
97 		printf("\t%s, %s\n", t->name, t->description);
98 }
99 
test_init(const struct test * start,const struct test * stop,int argc,char * const argv[])100 int test_init(const struct test *start, const struct test *stop,
101 	      int argc, char *const argv[])
102 {
103 	progname = argv[0];
104 
105 	for (;;) {
106 		int c, idx = 0;
107 		c = getopt_long(argc, argv, options_short, options, &idx);
108 		if (c == -1)
109 			break;
110 		switch (c) {
111 		case 'l':
112 			test_list(start, stop);
113 			return 0;
114 		case 'h':
115 			help();
116 			return 0;
117 		case 'n':
118 			oneshot = 1;
119 			break;
120 		case '?':
121 			return -1;
122 		default:
123 			ERR("unexpected getopt_long() value %c\n", c);
124 			return -1;
125 		}
126 	}
127 
128 	if (isatty(STDOUT_FILENO) == 0) {
129 		ANSI_HIGHLIGHT_OFF = "";
130 		ANSI_HIGHLIGHT_RED_ON = "";
131 		ANSI_HIGHLIGHT_GREEN_ON = "";
132 	}
133 
134 	return optind;
135 }
136 
test_find(const struct test * start,const struct test * stop,const char * name)137 const struct test *test_find(const struct test *start,
138 			     const struct test *stop, const char *name)
139 {
140 	const struct test *t;
141 
142 	for (t = start; t < stop; t++) {
143 		if (streq(t->name, name))
144 			return t;
145 	}
146 
147 	return NULL;
148 }
149 
test_spawn_test(const struct test * t)150 static int test_spawn_test(const struct test *t)
151 {
152 	const char *const args[] = { progname, "-n", t->name, NULL };
153 
154 	execv(progname, (char *const *) args);
155 
156 	ERR("failed to spawn %s for %s: %m\n", progname, t->name);
157 	return EXIT_FAILURE;
158 }
159 
test_run_spawned(const struct test * t)160 static int test_run_spawned(const struct test *t)
161 {
162 	int err = t->func(t);
163 	exit(err);
164 
165 	return EXIT_FAILURE;
166 }
167 
test_spawn_prog(const char * prog,const char * const args[])168 int test_spawn_prog(const char *prog, const char *const args[])
169 {
170 	execv(prog, (char *const *) args);
171 
172 	ERR("failed to spawn %s\n", prog);
173 	ERR("did you forget to build tools?\n");
174 	return EXIT_FAILURE;
175 }
176 
test_export_environ(const struct test * t)177 static void test_export_environ(const struct test *t)
178 {
179 	char *preload = NULL;
180 	size_t preloadlen = 0;
181 	size_t i;
182 	const struct keyval *env;
183 
184 	unsetenv("LD_PRELOAD");
185 
186 	for (i = 0; i < _TC_LAST; i++) {
187 		const char *ldpreload;
188 		size_t ldpreloadlen;
189 		char *tmp;
190 
191 		if (t->config[i] == NULL)
192 			continue;
193 
194 		setenv(env_config[i].key, t->config[i], 1);
195 
196 		ldpreload = env_config[i].ldpreload;
197 		ldpreloadlen = strlen(ldpreload);
198 		tmp = realloc(preload, preloadlen + 2 + ldpreloadlen);
199 		if (tmp == NULL) {
200 			ERR("oom: test_export_environ()\n");
201 			return;
202 		}
203 		preload = tmp;
204 
205 		if (preloadlen > 0)
206 			preload[preloadlen++] = ' ';
207 		memcpy(preload + preloadlen, ldpreload, ldpreloadlen);
208 		preloadlen += ldpreloadlen;
209 		preload[preloadlen] = '\0';
210 	}
211 
212 	if (preload != NULL)
213 		setenv("LD_PRELOAD", preload, 1);
214 
215 	free(preload);
216 
217 	for (env = t->env_vars; env && env->key; env++)
218 		setenv(env->key, env->val, 1);
219 }
220 
test_run_child(const struct test * t,int fdout[2],int fderr[2],int fdmonitor[2])221 static inline int test_run_child(const struct test *t, int fdout[2],
222 						int fderr[2], int fdmonitor[2])
223 {
224 	/* kill child if parent dies */
225 	prctl(PR_SET_PDEATHSIG, SIGTERM);
226 
227 	test_export_environ(t);
228 
229 	/* Close read-fds and redirect std{out,err} to the write-fds */
230 	if (t->output.out != NULL) {
231 		close(fdout[0]);
232 		if (dup2(fdout[1], STDOUT_FILENO) < 0) {
233 			ERR("could not redirect stdout to pipe: %m\n");
234 			exit(EXIT_FAILURE);
235 		}
236 	}
237 
238 	if (t->output.err != NULL) {
239 		close(fderr[0]);
240 		if (dup2(fderr[1], STDERR_FILENO) < 0) {
241 			ERR("could not redirect stderr to pipe: %m\n");
242 			exit(EXIT_FAILURE);
243 		}
244 	}
245 
246 	close(fdmonitor[0]);
247 
248 	if (t->config[TC_ROOTFS] != NULL) {
249 		const char *stamp = TESTSUITE_ROOTFS "../stamp-rootfs";
250 		const char *rootfs = t->config[TC_ROOTFS];
251 		struct stat rootfsst, stampst;
252 
253 		if (stat(stamp, &stampst) != 0) {
254 			ERR("could not stat %s\n - %m", stamp);
255 			exit(EXIT_FAILURE);
256 		}
257 
258 		if (stat(rootfs, &rootfsst) != 0) {
259 			ERR("could not stat %s\n - %m", rootfs);
260 			exit(EXIT_FAILURE);
261 		}
262 
263 		if (stat_mstamp(&rootfsst) > stat_mstamp(&stampst)) {
264 			ERR("rootfs %s is dirty, please run 'make rootfs' before runnning this test\n",
265 								rootfs);
266 			exit(EXIT_FAILURE);
267 		}
268 	}
269 
270 	if (t->need_spawn)
271 		return test_spawn_test(t);
272 	else
273 		return test_run_spawned(t);
274 }
275 
276 #define BUFSZ 4096
277 
278 enum fd_cmp_type {
279 	FD_CMP_MONITOR,
280 	FD_CMP_OUT,
281 	FD_CMP_ERR,
282 	FD_CMP_MAX = FD_CMP_ERR,
283 };
284 
285 struct fd_cmp {
286 	enum fd_cmp_type type;
287 	int fd;
288 	int fd_match;
289 	bool activity;
290 	const char *path;
291 	const char *name;
292 	char buf[BUFSZ];
293 	char buf_match[BUFSZ];
294 	unsigned int head;
295 	unsigned int head_match;
296 };
297 
fd_cmp_check_activity(struct fd_cmp * fd_cmp)298 static int fd_cmp_check_activity(struct fd_cmp *fd_cmp)
299 {
300 	struct stat st;
301 
302 	/* not monitoring or monitoring and it has activity */
303 	if (fd_cmp == NULL || fd_cmp->fd < 0 || fd_cmp->activity)
304 		return 0;
305 
306 	/* monitoring, there was no activity and size matches */
307 	if (stat(fd_cmp->path, &st) == 0 && st.st_size == 0)
308 		return 0;
309 
310 	ERR("Expecting output on %s, but test didn't produce any\n",
311 	    fd_cmp->name);
312 
313 	return -1;
314 }
315 
fd_cmp_is_active(struct fd_cmp * fd_cmp)316 static bool fd_cmp_is_active(struct fd_cmp *fd_cmp)
317 {
318 	return fd_cmp->fd != -1;
319 }
320 
fd_cmp_open_monitor(struct fd_cmp * fd_cmp,int fd,int fd_ep)321 static int fd_cmp_open_monitor(struct fd_cmp *fd_cmp, int fd, int fd_ep)
322 {
323 	struct epoll_event ep = {};
324 
325 	ep.events = EPOLLHUP;
326 	ep.data.ptr = fd_cmp;
327 	if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd, &ep) < 0) {
328 		ERR("could not add monitor fd to epoll: %m\n");
329 		return -errno;
330 	}
331 
332 	return 0;
333 }
334 
fd_cmp_open_std(struct fd_cmp * fd_cmp,const char * fn,int fd,int fd_ep)335 static int fd_cmp_open_std(struct fd_cmp *fd_cmp,
336 			   const char *fn, int fd, int fd_ep)
337 {
338 	struct epoll_event ep = {};
339 	int fd_match;
340 
341 	fd_match = open(fn, O_RDONLY);
342 	if (fd_match < 0) {
343 		ERR("could not open %s for read: %m\n", fn);
344 		return -errno;
345 	}
346 	ep.events = EPOLLIN;
347 	ep.data.ptr = fd_cmp;
348 	if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd, &ep) < 0) {
349 		ERR("could not add fd to epoll: %m\n");
350 		close(fd_match);
351 		return -errno;
352 	}
353 
354 	return fd_match;
355 }
356 
357 /* opens output file AND adds descriptor to epoll */
fd_cmp_open(struct fd_cmp ** fd_cmp_out,enum fd_cmp_type type,const char * fn,int fd,int fd_ep)358 static int fd_cmp_open(struct fd_cmp **fd_cmp_out,
359 		       enum fd_cmp_type type, const char *fn, int fd,
360 		       int fd_ep)
361 {
362 	int err = 0;
363 	struct fd_cmp *fd_cmp;
364 
365 	fd_cmp = calloc(1, sizeof(*fd_cmp));
366 	if (fd_cmp == NULL) {
367 		ERR("could not allocate fd_cmp\n");
368 		return -ENOMEM;
369 	}
370 
371 	switch (type) {
372 	case FD_CMP_MONITOR:
373 		err = fd_cmp_open_monitor(fd_cmp, fd, fd_ep);
374 		break;
375 	case FD_CMP_OUT:
376 		fd_cmp->name = "STDOUT";
377 		err = fd_cmp_open_std(fd_cmp, fn, fd, fd_ep);
378 		break;
379 	case FD_CMP_ERR:
380 		fd_cmp->name = "STDERR";
381 		err = fd_cmp_open_std(fd_cmp, fn, fd, fd_ep);
382 		break;
383 	default:
384 		ERR("unknown fd type %d\n", type);
385 		err = -1;
386 	}
387 
388 	if (err < 0) {
389 		free(fd_cmp);
390 		return err;
391 	}
392 
393 	fd_cmp->fd_match = err;
394 	fd_cmp->fd = fd;
395 	fd_cmp->type = type;
396 	fd_cmp->path = fn;
397 
398 	*fd_cmp_out = fd_cmp;
399 	return 0;
400 }
401 
fd_cmp_check_ev_in(struct fd_cmp * fd_cmp)402 static int fd_cmp_check_ev_in(struct fd_cmp *fd_cmp)
403 {
404 	if (fd_cmp->type == FD_CMP_MONITOR) {
405 		ERR("Unexpected activity on monitor pipe\n");
406 		return -EINVAL;
407 	}
408 	fd_cmp->activity = true;
409 
410 	return 0;
411 }
412 
fd_cmp_delete_ep(struct fd_cmp * fd_cmp,int fd_ep)413 static void fd_cmp_delete_ep(struct fd_cmp *fd_cmp, int fd_ep)
414 {
415 	if (epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_cmp->fd, NULL) < 0) {
416 		ERR("could not remove fd %d from epoll: %m\n", fd_cmp->fd);
417 	}
418 	fd_cmp->fd = -1;
419 }
420 
fd_cmp_close(struct fd_cmp * fd_cmp)421 static void fd_cmp_close(struct fd_cmp *fd_cmp)
422 {
423 	if (fd_cmp == NULL)
424 		return;
425 
426 	if (fd_cmp->fd >= 0)
427 		close(fd_cmp->fd);
428 	free(fd_cmp);
429 }
430 
fd_cmp_regex_one(const char * pattern,const char * s)431 static bool fd_cmp_regex_one(const char *pattern, const char *s)
432 {
433 	_cleanup_(regfree) regex_t re = { };
434 
435 	return !regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) &&
436 	       !regexec(&re, s, 0, NULL, 0);
437 }
438 
439 /*
440  * read fd and fd_match, checking the first matches the regex of the second,
441  * line by line
442  */
fd_cmp_regex(struct fd_cmp * fd_cmp,const struct test * t)443 static bool fd_cmp_regex(struct fd_cmp *fd_cmp, const struct test *t)
444 {
445 	char *p, *p_match;
446 	int done = 0, done_match = 0, r;
447 
448 	if (fd_cmp->head >= sizeof(fd_cmp->buf)) {
449 		ERR("Read %zu bytes without a newline\n", sizeof(fd_cmp->buf));
450 		ERR("output: %.*s", (int)sizeof(fd_cmp->buf), fd_cmp->buf);
451 		return false;
452 	}
453 
454 	r = read(fd_cmp->fd, fd_cmp->buf + fd_cmp->head,
455 		 sizeof(fd_cmp->buf) - fd_cmp->head);
456 	if (r <= 0)
457 		return true;
458 
459 	fd_cmp->head += r;
460 
461 	/*
462 	 * Process as many lines as read from fd and that fits in the buffer -
463 	 * it's assumed that if we get N lines from fd, we should be able to
464 	 * get the same amount from fd_match
465 	 */
466 	for (;;) {
467 		p = memchr(fd_cmp->buf + done, '\n', fd_cmp->head - done);
468 		if (!p)
469 			break;
470 		*p = '\0';
471 
472 		p_match = memchr(fd_cmp->buf_match + done_match, '\n',
473 				 fd_cmp->head_match - done_match);
474 		if (!p_match) {
475 			if (fd_cmp->head_match >= sizeof(fd_cmp->buf_match)) {
476 				ERR("Read %zu bytes without a match\n", sizeof(fd_cmp->buf_match));
477 				ERR("output: %.*s", (int)sizeof(fd_cmp->buf_match), fd_cmp->buf_match);
478 				return false;
479 			}
480 
481 			/* pump more data from file */
482 			r = read(fd_cmp->fd_match, fd_cmp->buf_match + fd_cmp->head_match,
483 				 sizeof(fd_cmp->buf_match) - fd_cmp->head_match);
484 			if (r <= 0) {
485 				ERR("could not read match fd %d\n", fd_cmp->fd_match);
486 				return false;
487 			}
488 			fd_cmp->head_match += r;
489 			p_match = memchr(fd_cmp->buf_match + done_match, '\n',
490 					 fd_cmp->head_match - done_match);
491 			if (!p_match) {
492 				ERR("could not find match line from fd %d\n", fd_cmp->fd_match);
493 				return false;
494 			}
495 		}
496 		*p_match = '\0';
497 
498 		if (!fd_cmp_regex_one(fd_cmp->buf_match + done_match, fd_cmp->buf + done)) {
499 			ERR("Output does not match pattern on %s:\n", fd_cmp->name);
500 			ERR("pattern: %s\n", fd_cmp->buf_match + done_match);
501 			ERR("output : %s\n", fd_cmp->buf + done);
502 			return false;
503 		}
504 
505 		done = p - fd_cmp->buf + 1;
506 		done_match = p_match - fd_cmp->buf_match + 1;
507 	}
508 
509 	/*
510 	 * Prepare for the next call: anything we processed we remove from the
511 	 * buffer by memmoving the remaining bytes up to the beginning
512 	 */
513 	if (done) {
514 		if (fd_cmp->head - done)
515 			memmove(fd_cmp->buf, fd_cmp->buf + done, fd_cmp->head - done);
516 		fd_cmp->head -= done;
517 	}
518 
519 	if (done_match) {
520 		if (fd_cmp->head_match - done_match)
521 			memmove(fd_cmp->buf_match, fd_cmp->buf_match + done_match,
522 				fd_cmp->head_match - done_match);
523 		fd_cmp->head_match -= done_match;
524 	}
525 
526 	return true;
527 }
528 
529 /* read fd and fd_match, checking they match exactly */
fd_cmp_exact(struct fd_cmp * fd_cmp,const struct test * t)530 static bool fd_cmp_exact(struct fd_cmp *fd_cmp, const struct test *t)
531 {
532 	int r, rmatch, done = 0;
533 
534 	r = read(fd_cmp->fd, fd_cmp->buf, sizeof(fd_cmp->buf) - 1);
535 	if (r <= 0)
536 		/* try again later */
537 		return true;
538 
539 	/* read as much data from fd_match as we read from fd */
540 	for (;;) {
541 		rmatch = read(fd_cmp->fd_match, fd_cmp->buf_match + done, r - done);
542 		if (rmatch == 0)
543 			break;
544 
545 		if (rmatch < 0) {
546 			if (errno == EINTR)
547 				continue;
548 			ERR("could not read match fd %d\n", fd_cmp->fd_match);
549 			return false;
550 		}
551 
552 		done += rmatch;
553 	}
554 
555 	fd_cmp->buf[r] = '\0';
556 	fd_cmp->buf_match[r] = '\0';
557 
558 	if (t->print_outputs)
559 		printf("%s: %s\n", fd_cmp->name, fd_cmp->buf);
560 
561 	if (!streq(fd_cmp->buf, fd_cmp->buf_match)) {
562 		ERR("Outputs do not match on %s:\n", fd_cmp->name);
563 		ERR("correct:\n%s\n", fd_cmp->buf_match);
564 		ERR("wrong:\n%s\n", fd_cmp->buf);
565 		return false;
566 	}
567 
568 	return true;
569 }
570 
test_run_parent_check_outputs(const struct test * t,int fdout,int fderr,int fdmonitor,pid_t child)571 static bool test_run_parent_check_outputs(const struct test *t,
572 					  int fdout, int fderr, int fdmonitor,
573 					  pid_t child)
574 {
575 	int err, fd_ep;
576 	unsigned long long end_usec, start_usec;
577 	struct fd_cmp *fd_cmp_out = NULL;
578 	struct fd_cmp *fd_cmp_err = NULL;
579 	struct fd_cmp *fd_cmp_monitor = NULL;
580 	int n_fd = 0;
581 
582 	fd_ep = epoll_create1(EPOLL_CLOEXEC);
583 	if (fd_ep < 0) {
584 		ERR("could not create epoll fd: %m\n");
585 		return false;
586 	}
587 
588 	if (t->output.out != NULL) {
589 		err = fd_cmp_open(&fd_cmp_out,
590 				  FD_CMP_OUT, t->output.out, fdout, fd_ep);
591 		if (err < 0)
592 			goto out;
593 		n_fd++;
594 	}
595 
596 	if (t->output.err != NULL) {
597 		err = fd_cmp_open(&fd_cmp_err,
598 				  FD_CMP_ERR, t->output.err, fderr, fd_ep);
599 		if (err < 0)
600 			goto out;
601 		n_fd++;
602 	}
603 
604 	err = fd_cmp_open(&fd_cmp_monitor, FD_CMP_MONITOR, NULL, fdmonitor, fd_ep);
605 	if (err < 0)
606 		goto out;
607 	n_fd++;
608 
609 	start_usec = now_usec();
610 	end_usec = start_usec + TEST_TIMEOUT_USEC;
611 
612 	for (err = 0; n_fd > 0;) {
613 		int fdcount, i, timeout;
614 		struct epoll_event ev[4];
615 		unsigned long long curr_usec = now_usec();
616 
617 		if (curr_usec > end_usec)
618 			break;
619 
620 		timeout = (end_usec - curr_usec) / USEC_PER_MSEC;
621 		fdcount = epoll_wait(fd_ep, ev, 4, timeout);
622 		if (fdcount < 0) {
623 			if (errno == EINTR)
624 				continue;
625 			err = -errno;
626 			ERR("could not poll: %m\n");
627 			goto out;
628 		}
629 
630 		for (i = 0;  i < fdcount; i++) {
631 			struct fd_cmp *fd_cmp = ev[i].data.ptr;
632 			bool ret;
633 
634 			if (ev[i].events & EPOLLIN) {
635 				err = fd_cmp_check_ev_in(fd_cmp);
636 				if (err < 0)
637 					goto out;
638 
639 				if (t->output.regex)
640 					ret = fd_cmp_regex(fd_cmp, t);
641 				else
642 					ret = fd_cmp_exact(fd_cmp, t);
643 
644 				if (!ret) {
645 					err = -1;
646 					goto out;
647 				}
648 			} else if (ev[i].events & EPOLLHUP) {
649 				fd_cmp_delete_ep(fd_cmp, fd_ep);
650 				n_fd--;
651 			}
652 		}
653 	}
654 
655 	err = fd_cmp_check_activity(fd_cmp_out);
656 	err |= fd_cmp_check_activity(fd_cmp_err);
657 
658 	if (err == 0 && fd_cmp_is_active(fd_cmp_monitor)) {
659 		err = -EINVAL;
660 		ERR("Test '%s' timed out, killing %d\n", t->name, child);
661 		kill(child, SIGKILL);
662 	}
663 
664 out:
665 	fd_cmp_close(fd_cmp_out);
666 	fd_cmp_close(fd_cmp_err);
667 	fd_cmp_close(fd_cmp_monitor);
668 	close(fd_ep);
669 
670 	return err == 0;
671 }
672 
safe_read(int fd,void * buf,size_t count)673 static inline int safe_read(int fd, void *buf, size_t count)
674 {
675 	int r;
676 
677 	while (1) {
678 		r = read(fd, buf, count);
679 		if (r == -1 && errno == EINTR)
680 			continue;
681 		break;
682 	}
683 
684 	return r;
685 }
686 
check_generated_files(const struct test * t)687 static bool check_generated_files(const struct test *t)
688 {
689 	const struct keyval *k;
690 
691 	/* This is not meant to be a diff replacement, just stupidly check if
692 	 * the files match. Bear in mind they can be binary files */
693 	for (k = t->output.files; k && k->key; k++) {
694 		struct stat sta, stb;
695 		int fda = -1, fdb = -1;
696 		char bufa[4096];
697 		char bufb[4096];
698 
699 		fda = open(k->key, O_RDONLY);
700 		if (fda < 0) {
701 			ERR("could not open %s\n - %m\n", k->key);
702 			goto fail;
703 		}
704 
705 		fdb = open(k->val, O_RDONLY);
706 		if (fdb < 0) {
707 			ERR("could not open %s\n - %m\n", k->val);
708 			goto fail;
709 		}
710 
711 		if (fstat(fda, &sta) != 0) {
712 			ERR("could not fstat %d %s\n - %m\n", fda, k->key);
713 			goto fail;
714 		}
715 
716 		if (fstat(fdb, &stb) != 0) {
717 			ERR("could not fstat %d %s\n - %m\n", fdb, k->key);
718 			goto fail;
719 		}
720 
721 		if (sta.st_size != stb.st_size) {
722 			ERR("sizes do not match %s %s\n", k->key, k->val);
723 			goto fail;
724 		}
725 
726 		for (;;) {
727 			int r, done;
728 
729 			r = safe_read(fda, bufa, sizeof(bufa));
730 			if (r < 0)
731 				goto fail;
732 
733 			if (r == 0)
734 				/* size is already checked, go to next file */
735 				goto next;
736 
737 			for (done = 0; done < r;) {
738 				int r2 = safe_read(fdb, bufb + done, r - done);
739 
740 				if (r2 <= 0)
741 					goto fail;
742 
743 				done += r2;
744 			}
745 
746 			if (memcmp(bufa, bufb, r) != 0)
747 				goto fail;
748 		}
749 
750 next:
751 		close(fda);
752 		close(fdb);
753 		continue;
754 
755 fail:
756 		if (fda >= 0)
757 			close(fda);
758 		if (fdb >= 0)
759 			close(fdb);
760 
761 		return false;
762 	}
763 
764 	return true;
765 }
766 
cmp_modnames(const void * m1,const void * m2)767 static int cmp_modnames(const void *m1, const void *m2)
768 {
769 	const char *s1 = *(char *const *)m1;
770 	const char *s2 = *(char *const *)m2;
771 	int i;
772 
773 	for (i = 0; s1[i] || s2[i]; i++) {
774 		char c1 = s1[i], c2 = s2[i];
775 		if (c1 == '-')
776 			c1 = '_';
777 		if (c2 == '-')
778 			c2 = '_';
779 		if (c1 != c2)
780 			return c1 - c2;
781 	}
782 	return 0;
783 }
784 
785 /*
786  * Store the expected module names in buf and return a list of pointers to
787  * them.
788  */
read_expected_modules(const struct test * t,char ** buf,int * count)789 static const char **read_expected_modules(const struct test *t,
790 		char **buf, int *count)
791 {
792 	const char **res;
793 	int len;
794 	int i;
795 	char *p;
796 
797 	if (t->modules_loaded[0] == '\0') {
798 		*count = 0;
799 		*buf = NULL;
800 		return NULL;
801 	}
802 	*buf = strdup(t->modules_loaded);
803 	if (!*buf) {
804 		*count = -1;
805 		return NULL;
806 	}
807 	len = 1;
808 	for (p = *buf; *p; p++)
809 		if (*p == ',')
810 			len++;
811 	res = malloc(sizeof(char *) * len);
812 	if (!res) {
813 		perror("malloc");
814 		*count = -1;
815 		free(*buf);
816 		*buf = NULL;
817 		return NULL;
818 	}
819 	i = 0;
820 	res[i++] = *buf;
821 	for (p = *buf; i < len; p++)
822 		if (*p == ',') {
823 			*p = '\0';
824 			res[i++] = p + 1;
825 		}
826 	*count = len;
827 	return res;
828 }
829 
read_loaded_modules(const struct test * t,char ** buf,int * count)830 static char **read_loaded_modules(const struct test *t, char **buf, int *count)
831 {
832 	char dirname[PATH_MAX];
833 	DIR *dir;
834 	struct dirent *dirent;
835 	int i;
836 	int len = 0, bufsz;
837 	char **res = NULL;
838 	char *p;
839 	const char *rootfs = t->config[TC_ROOTFS] ? t->config[TC_ROOTFS] : "";
840 
841 	/* Store the entries in /sys/module to res */
842 	if (snprintf(dirname, sizeof(dirname), "%s/sys/module", rootfs)
843 			>= (int)sizeof(dirname)) {
844 		ERR("rootfs path too long: %s\n", rootfs);
845 		*buf = NULL;
846 		len = -1;
847 		goto out;
848 	}
849 	dir = opendir(dirname);
850 	/* not an error, simply return empty list */
851 	if (!dir) {
852 		*buf = NULL;
853 		goto out;
854 	}
855 	bufsz = 0;
856 	while ((dirent = readdir(dir))) {
857 		if (dirent->d_name[0] == '.')
858 			continue;
859 		len++;
860 		bufsz += strlen(dirent->d_name) + 1;
861 	}
862 	res = malloc(sizeof(char *) * len);
863 	if (!res) {
864 		perror("malloc");
865 		len = -1;
866 		goto out_dir;
867 	}
868 	*buf = malloc(bufsz);
869 	if (!*buf) {
870 		perror("malloc");
871 		free(res);
872 		res = NULL;
873 		len = -1;
874 		goto out_dir;
875 	}
876 	rewinddir(dir);
877 	i = 0;
878 	p = *buf;
879 	while ((dirent = readdir(dir))) {
880 		int size;
881 
882 		if (dirent->d_name[0] == '.')
883 			continue;
884 		size = strlen(dirent->d_name) + 1;
885 		memcpy(p, dirent->d_name, size);
886 		res[i++] = p;
887 		p += size;
888 	}
889 out_dir:
890 	closedir(dir);
891 out:
892 	*count = len;
893 	return res;
894 }
895 
check_loaded_modules(const struct test * t)896 static int check_loaded_modules(const struct test *t)
897 {
898 	int l1, l2, i1, i2;
899 	const char **a1;
900 	char **a2;
901 	char *buf1, *buf2;
902 	int err = false;
903 
904 	a1 = read_expected_modules(t, &buf1, &l1);
905 	if (l1 < 0)
906 		return err;
907 	a2 = read_loaded_modules(t, &buf2, &l2);
908 	if (l2 < 0)
909 		goto out_a1;
910 	qsort(a1, l1, sizeof(char *), cmp_modnames);
911 	qsort(a2, l2, sizeof(char *), cmp_modnames);
912 	i1 = i2 = 0;
913 	err = true;
914 	while (i1 < l1 || i2 < l2) {
915 		int cmp;
916 
917 		if (i1 >= l1)
918 			cmp = 1;
919 		else if (i2 >= l2)
920 			cmp = -1;
921 		else
922 			cmp = cmp_modnames(&a1[i1], &a2[i2]);
923 		if (cmp == 0) {
924 			i1++;
925 			i2++;
926 		} else if (cmp < 0) {
927 			err = false;
928 			ERR("module %s not loaded\n", a1[i1]);
929 			i1++;
930 		} else  {
931 			err = false;
932 			ERR("module %s is loaded but should not be \n", a2[i2]);
933 			i2++;
934 		}
935 	}
936 	free(a2);
937 	free(buf2);
938 out_a1:
939 	free(a1);
940 	free(buf1);
941 	return err;
942 }
943 
test_run_parent(const struct test * t,int fdout[2],int fderr[2],int fdmonitor[2],pid_t child)944 static inline int test_run_parent(const struct test *t, int fdout[2],
945 				int fderr[2], int fdmonitor[2], pid_t child)
946 {
947 	pid_t pid;
948 	int err;
949 	bool matchout, match_modules;
950 
951 	/* Close write-fds */
952 	if (t->output.out != NULL)
953 		close(fdout[1]);
954 	if (t->output.err != NULL)
955 		close(fderr[1]);
956 	close(fdmonitor[1]);
957 
958 	matchout = test_run_parent_check_outputs(t, fdout[0], fderr[0],
959 							fdmonitor[0], child);
960 
961 	/*
962 	 * break pipe on the other end: either child already closed or we want
963 	 * to stop it
964 	 */
965 	if (t->output.out != NULL)
966 		close(fdout[0]);
967 	if (t->output.err != NULL)
968 		close(fderr[0]);
969 	close(fdmonitor[0]);
970 
971 	do {
972 		pid = wait(&err);
973 		if (pid == -1) {
974 			ERR("error waitpid(): %m\n");
975 			err = EXIT_FAILURE;
976 			goto exit;
977 		}
978 	} while (!WIFEXITED(err) && !WIFSIGNALED(err));
979 
980 	if (WIFEXITED(err)) {
981 		if (WEXITSTATUS(err) != 0)
982 			ERR("'%s' [%u] exited with return code %d\n",
983 					t->name, pid, WEXITSTATUS(err));
984 		else
985 			LOG("'%s' [%u] exited with return code %d\n",
986 					t->name, pid, WEXITSTATUS(err));
987 	} else if (WIFSIGNALED(err)) {
988 		ERR("'%s' [%u] terminated by signal %d (%s)\n", t->name, pid,
989 				WTERMSIG(err), strsignal(WTERMSIG(err)));
990 		err = t->expected_fail ? EXIT_SUCCESS : EXIT_FAILURE;
991 		goto exit;
992 	}
993 
994 	if (matchout)
995 		matchout = check_generated_files(t);
996 	if (t->modules_loaded)
997 		match_modules = check_loaded_modules(t);
998 	else
999 		match_modules = true;
1000 
1001 	if (t->expected_fail == false) {
1002 		if (err == 0) {
1003 			if (matchout && match_modules)
1004 				LOG("%sPASSED%s: %s\n",
1005 					ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
1006 					t->name);
1007 			else {
1008 				ERR("%sFAILED%s: exit ok but %s do not match: %s\n",
1009 					ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
1010 					matchout ? "loaded modules" : "outputs",
1011 					t->name);
1012 				err = EXIT_FAILURE;
1013 			}
1014 		} else {
1015 			ERR("%sFAILED%s: %s\n",
1016 					ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
1017 					t->name);
1018 		}
1019 	} else {
1020 		if (err == 0) {
1021 			if (matchout) {
1022 				ERR("%sUNEXPECTED PASS%s: exit with 0: %s\n",
1023 					ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
1024 					t->name);
1025 				err = EXIT_FAILURE;
1026 			} else {
1027 				ERR("%sUNEXPECTED PASS%s: exit with 0 and outputs do not match: %s\n",
1028 					ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
1029 					t->name);
1030 				err = EXIT_FAILURE;
1031 			}
1032 		} else {
1033 			if (matchout) {
1034 				LOG("%sEXPECTED FAIL%s: %s\n",
1035 					ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
1036 					t->name);
1037 				err = EXIT_SUCCESS;
1038 			} else {
1039 				LOG("%sEXPECTED FAIL%s: exit with %d but outputs do not match: %s\n",
1040 					ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
1041 					WEXITSTATUS(err), t->name);
1042 				err = EXIT_FAILURE;
1043 			}
1044 		}
1045 	}
1046 
1047 exit:
1048 	LOG("------\n");
1049 	return err;
1050 }
1051 
prepend_path(const char * extra)1052 static int prepend_path(const char *extra)
1053 {
1054 	char *oldpath, *newpath;
1055 	int r;
1056 
1057 	if (extra == NULL)
1058 		return 0;
1059 
1060 	oldpath = getenv("PATH");
1061 	if (oldpath == NULL)
1062 		return setenv("PATH", extra, 1);
1063 
1064 	if (asprintf(&newpath, "%s:%s", extra, oldpath) < 0) {
1065 		ERR("failed to allocate memory to new PATH\n");
1066 		return -1;
1067 	}
1068 
1069 	r = setenv("PATH", newpath, 1);
1070 	free(newpath);
1071 
1072 	return r;
1073 }
1074 
test_run(const struct test * t)1075 int test_run(const struct test *t)
1076 {
1077 	pid_t pid;
1078 	int fdout[2];
1079 	int fderr[2];
1080 	int fdmonitor[2];
1081 
1082 	if (t->need_spawn && oneshot)
1083 		test_run_spawned(t);
1084 
1085 	if (t->output.out != NULL) {
1086 		if (pipe(fdout) != 0) {
1087 			ERR("could not create out pipe for %s\n", t->name);
1088 			return EXIT_FAILURE;
1089 		}
1090 	}
1091 
1092 	if (t->output.err != NULL) {
1093 		if (pipe(fderr) != 0) {
1094 			ERR("could not create err pipe for %s\n", t->name);
1095 			return EXIT_FAILURE;
1096 		}
1097 	}
1098 
1099 	if (pipe(fdmonitor) != 0) {
1100 		ERR("could not create monitor pipe for %s\n", t->name);
1101 		return EXIT_FAILURE;
1102 	}
1103 
1104 	if (prepend_path(t->path) < 0) {
1105 		ERR("failed to prepend '%s' to PATH\n", t->path);
1106 		return EXIT_FAILURE;
1107 	}
1108 
1109 	LOG("running %s, in forked context\n", t->name);
1110 
1111 	pid = fork();
1112 	if (pid < 0) {
1113 		ERR("could not fork(): %m\n");
1114 		LOG("FAILED: %s\n", t->name);
1115 		return EXIT_FAILURE;
1116 	}
1117 
1118 	if (pid > 0)
1119 		return test_run_parent(t, fdout, fderr, fdmonitor, pid);
1120 
1121 	return test_run_child(t, fdout, fderr, fdmonitor);
1122 }
1123