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