]> git.ipfire.org Git - thirdparty/kmod.git/blob - testsuite/testsuite.c
Reorder and reorganize header files
[thirdparty/kmod.git] / testsuite / testsuite.c
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, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <getopt.h>
23 #include <limits.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 <libkmod-util.h>
38
39 #include "testsuite.h"
40
41 static const char *ANSI_HIGHLIGHT_GREEN_ON = "\x1B[1;32m";
42 static const char *ANSI_HIGHLIGHT_RED_ON = "\x1B[1;31m";
43 static const char *ANSI_HIGHLIGHT_OFF = "\x1B[0m";
44
45 static const char *progname;
46 static int oneshot = 0;
47 static const char options_short[] = "lhn";
48 static const struct option options[] = {
49 { "list", no_argument, 0, 'l' },
50 { "help", no_argument, 0, 'h' },
51 { NULL, 0, 0, 0 }
52 };
53
54 #define OVERRIDE_LIBDIR ABS_TOP_BUILDDIR "/testsuite/.libs/"
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
66 #define USEC_PER_SEC 1000000ULL
67 #define USEC_PER_MSEC 1000ULL
68 #define TEST_TIMEOUT_USEC 2 * USEC_PER_SEC
69 static unsigned long long now_usec(void)
70 {
71 struct timespec ts;
72
73 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
74 return 0;
75
76 return ts_usec(&ts);
77 }
78
79 static void help(void)
80 {
81 const struct option *itr;
82 const char *itr_short;
83
84 printf("Usage:\n"
85 "\t%s [options] <test>\n"
86 "Options:\n", basename(progname));
87
88 for (itr = options, itr_short = options_short;
89 itr->name != NULL; itr++, itr_short++)
90 printf("\t-%c, --%s\n", *itr_short, itr->name);
91 }
92
93 static void test_list(const struct test *tests[])
94 {
95 size_t i;
96
97 printf("Available tests:\n");
98 for (i = 0; tests[i] != NULL; i++)
99 printf("\t%s, %s\n", tests[i]->name, tests[i]->description);
100 }
101
102 int test_init(int argc, char *const argv[], const struct test *tests[])
103 {
104 progname = argv[0];
105
106 for (;;) {
107 int c, idx = 0;
108 c = getopt_long(argc, argv, options_short, options, &idx);
109 if (c == -1)
110 break;
111 switch (c) {
112 case 'l':
113 test_list(tests);
114 return 0;
115 case 'h':
116 help();
117 return 0;
118 case 'n':
119 oneshot = 1;
120 break;
121 case '?':
122 return -1;
123 default:
124 ERR("unexpected getopt_long() value %c\n", c);
125 return -1;
126 }
127 }
128
129 if (isatty(STDOUT_FILENO) == 0) {
130 ANSI_HIGHLIGHT_OFF = "";
131 ANSI_HIGHLIGHT_RED_ON = "";
132 ANSI_HIGHLIGHT_GREEN_ON = "";
133 }
134
135 return optind;
136 }
137
138 const struct test *test_find(const struct test *tests[], const char *name)
139 {
140 size_t i;
141
142 for (i = 0; tests[i] != NULL; i++) {
143 if (strcmp(tests[i]->name, name) == 0)
144 return tests[i];
145 }
146
147 return NULL;
148 }
149
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
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
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
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
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 static inline bool test_run_parent_check_outputs(const struct test *t,
277 int fdout, int fderr, int fdmonitor, pid_t child)
278 {
279 struct epoll_event ep_outpipe, ep_errpipe, ep_monitor;
280 int err, fd_ep, fd_matchout = -1, fd_matcherr = -1;
281 unsigned long long end_usec, start_usec;
282
283 fd_ep = epoll_create1(EPOLL_CLOEXEC);
284 if (fd_ep < 0) {
285 ERR("could not create epoll fd: %m\n");
286 return false;
287 }
288
289 if (t->output.out != NULL) {
290 fd_matchout = open(t->output.out, O_RDONLY);
291 if (fd_matchout < 0) {
292 err = -errno;
293 ERR("could not open %s for read: %m\n",
294 t->output.out);
295 goto out;
296 }
297 memset(&ep_outpipe, 0, sizeof(struct epoll_event));
298 ep_outpipe.events = EPOLLIN;
299 ep_outpipe.data.ptr = &fdout;
300 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fdout, &ep_outpipe) < 0) {
301 err = -errno;
302 ERR("could not add fd to epoll: %m\n");
303 goto out;
304 }
305 } else
306 fdout = -1;
307
308 if (t->output.err != NULL) {
309 fd_matcherr = open(t->output.err, O_RDONLY);
310 if (fd_matcherr < 0) {
311 err = -errno;
312 ERR("could not open %s for read: %m\n",
313 t->output.err);
314 goto out;
315
316 }
317 memset(&ep_errpipe, 0, sizeof(struct epoll_event));
318 ep_errpipe.events = EPOLLIN;
319 ep_errpipe.data.ptr = &fderr;
320 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fderr, &ep_errpipe) < 0) {
321 err = -errno;
322 ERR("could not add fd to epoll: %m\n");
323 goto out;
324 }
325 } else
326 fderr = -1;
327
328 memset(&ep_monitor, 0, sizeof(struct epoll_event));
329 ep_monitor.events = EPOLLHUP;
330 ep_monitor.data.ptr = &fdmonitor;
331 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fdmonitor, &ep_monitor) < 0) {
332 err = -errno;
333 ERR("could not add monitor fd to epoll: %m\n");
334 goto out;
335 }
336
337 start_usec = now_usec();
338 end_usec = start_usec + TEST_TIMEOUT_USEC;
339
340 for (err = 0; fdmonitor >= 0 || fdout >= 0 || fderr >= 0;) {
341 int fdcount, i, timeout;
342 struct epoll_event ev[4];
343 unsigned long long curr_usec = now_usec();
344
345 if (curr_usec > end_usec)
346 break;
347
348 timeout = (end_usec - curr_usec) / USEC_PER_MSEC;
349 fdcount = epoll_wait(fd_ep, ev, 4, timeout);
350 if (fdcount < 0) {
351 if (errno == EINTR)
352 continue;
353 err = -errno;
354 ERR("could not poll: %m\n");
355 goto out;
356 }
357
358 for (i = 0; i < fdcount; i++) {
359 int *fd = ev[i].data.ptr;
360
361 if (ev[i].events & EPOLLIN) {
362 ssize_t r, done = 0;
363 char buf[4096];
364 char bufmatch[4096];
365 int fd_match;
366
367 /*
368 * compare the output from child with the one
369 * saved as correct
370 */
371
372 r = read(*fd, buf, sizeof(buf) - 1);
373 if (r <= 0)
374 continue;
375
376 if (*fd == fdout)
377 fd_match = fd_matchout;
378 else if (*fd == fderr)
379 fd_match = fd_matcherr;
380 else {
381 ERR("Unexpected activity on monitor pipe\n");
382 err = -EINVAL;
383 goto out;
384 }
385
386 for (;;) {
387 int rmatch = read(fd_match,
388 bufmatch + done, r - done);
389 if (rmatch == 0)
390 break;
391
392 if (rmatch < 0) {
393 if (errno == EINTR)
394 continue;
395 err = -errno;
396 ERR("could not read match fd %d\n",
397 fd_match);
398 goto out;
399 }
400
401 done += rmatch;
402 }
403
404 buf[r] = '\0';
405 bufmatch[r] = '\0';
406 if (strcmp(buf, bufmatch) != 0) {
407 ERR("Outputs do not match on %s:\n",
408 fd_match == fd_matchout ? "stdout" : "stderr");
409 ERR("correct:\n%s\n", bufmatch);
410 ERR("wrong:\n%s\n", buf);
411 err = -1;
412 goto out;
413 }
414 } else if (ev[i].events & EPOLLHUP) {
415 if (epoll_ctl(fd_ep, EPOLL_CTL_DEL,
416 *fd, NULL) < 0) {
417 ERR("could not remove fd %d from epoll: %m\n",
418 *fd);
419 }
420 *fd = -1;
421 }
422 }
423 }
424
425 if (err == 0 && fdmonitor >= 0) {
426 err = -EINVAL;
427 ERR("Test '%s' timed out, killing %d\n", t->name, child);
428 kill(child, SIGKILL);
429 }
430
431 out:
432 if (fd_matchout >= 0)
433 close(fd_matchout);
434 if (fd_matcherr >= 0)
435 close(fd_matcherr);
436 if (fd_ep >= 0)
437 close(fd_ep);
438 return err == 0;
439 }
440
441 static inline int safe_read(int fd, void *buf, size_t count)
442 {
443 int r;
444
445 while (1) {
446 r = read(fd, buf, count);
447 if (r == -1 && errno == EINTR)
448 continue;
449 break;
450 }
451
452 return r;
453 }
454
455 static bool check_generated_files(const struct test *t)
456 {
457 const struct keyval *k;
458
459 /* This is not meant to be a diff replacement, just stupidly check if
460 * the files match. Bear in mind they can be binary files */
461 for (k = t->output.files; k && k->key; k++) {
462 struct stat sta, stb;
463 int fda = -1, fdb = -1;
464 char bufa[4096];
465 char bufb[4096];
466
467 fda = open(k->key, O_RDONLY);
468 if (fda < 0) {
469 ERR("could not open %s\n - %m\n", k->key);
470 goto fail;
471 }
472
473 fdb = open(k->val, O_RDONLY);
474 if (fdb < 0) {
475 ERR("could not open %s\n - %m\n", k->val);
476 goto fail;
477 }
478
479 if (fstat(fda, &sta) != 0) {
480 ERR("could not fstat %d %s\n - %m\n", fda, k->key);
481 goto fail;
482 }
483
484 if (fstat(fdb, &stb) != 0) {
485 ERR("could not fstat %d %s\n - %m\n", fdb, k->key);
486 goto fail;
487 }
488
489 if (sta.st_size != stb.st_size) {
490 ERR("sizes do not match %s %s\n", k->key, k->val);
491 goto fail;
492 }
493
494 for (;;) {
495 int r, done;
496
497 r = safe_read(fda, bufa, sizeof(bufa));
498 if (r < 0)
499 goto fail;
500
501 if (r == 0)
502 /* size is already checked, go to next file */
503 goto next;
504
505 for (done = 0; done < r;) {
506 int r2 = safe_read(fdb, bufb + done, r - done);
507
508 if (r2 <= 0)
509 goto fail;
510
511 done += r2;
512 }
513
514 if (memcmp(bufa, bufb, r) != 0)
515 goto fail;
516 }
517
518 next:
519 close(fda);
520 close(fdb);
521 continue;
522
523 fail:
524 if (fda >= 0)
525 close(fda);
526 if (fdb >= 0)
527 close(fdb);
528
529 return false;
530 }
531
532 return true;
533 }
534
535 static int cmp_modnames(const void *m1, const void *m2)
536 {
537 const char *s1 = *(char *const *)m1;
538 const char *s2 = *(char *const *)m2;
539 int i;
540
541 for (i = 0; s1[i] || s2[i]; i++) {
542 char c1 = s1[i], c2 = s2[i];
543 if (c1 == '-')
544 c1 = '_';
545 if (c2 == '-')
546 c2 = '_';
547 if (c1 != c2)
548 return c1 - c2;
549 }
550 return 0;
551 }
552
553 /*
554 * Store the expected module names in buf and return a list of pointers to
555 * them.
556 */
557 static const char **read_expected_modules(const struct test *t,
558 char **buf, int *count)
559 {
560 const char **res;
561 int len;
562 int i;
563 char *p;
564
565 if (t->modules_loaded[0] == '\0') {
566 *count = 0;
567 *buf = NULL;
568 return NULL;
569 }
570 *buf = strdup(t->modules_loaded);
571 if (!*buf) {
572 *count = -1;
573 return NULL;
574 }
575 len = 1;
576 for (p = *buf; *p; p++)
577 if (*p == ',')
578 len++;
579 res = malloc(sizeof(char *) * len);
580 if (!res) {
581 perror("malloc");
582 *count = -1;
583 free(*buf);
584 *buf = NULL;
585 return NULL;
586 }
587 i = 0;
588 res[i++] = *buf;
589 for (p = *buf; i < len; p++)
590 if (*p == ',') {
591 *p = '\0';
592 res[i++] = p + 1;
593 }
594 *count = len;
595 return res;
596 }
597
598 static char **read_loaded_modules(const struct test *t, char **buf, int *count)
599 {
600 char dirname[PATH_MAX];
601 DIR *dir;
602 struct dirent *dirent;
603 int i;
604 int len = 0, bufsz;
605 char **res = NULL;
606 char *p;
607 const char *rootfs = t->config[TC_ROOTFS] ? t->config[TC_ROOTFS] : "";
608
609 /* Store the entries in /sys/module to res */
610 if (snprintf(dirname, sizeof(dirname), "%s/sys/module", rootfs)
611 >= (int)sizeof(dirname)) {
612 ERR("rootfs path too long: %s\n", rootfs);
613 *buf = NULL;
614 len = -1;
615 goto out;
616 }
617 dir = opendir(dirname);
618 /* not an error, simply return empty list */
619 if (!dir) {
620 *buf = NULL;
621 goto out;
622 }
623 bufsz = 0;
624 while ((dirent = readdir(dir))) {
625 if (dirent->d_name[0] == '.')
626 continue;
627 len++;
628 bufsz += strlen(dirent->d_name) + 1;
629 }
630 res = malloc(sizeof(char *) * len);
631 if (!res) {
632 perror("malloc");
633 len = -1;
634 goto out_dir;
635 }
636 *buf = malloc(bufsz);
637 if (!*buf) {
638 perror("malloc");
639 free(res);
640 res = NULL;
641 len = -1;
642 goto out_dir;
643 }
644 rewinddir(dir);
645 i = 0;
646 p = *buf;
647 while ((dirent = readdir(dir))) {
648 int size;
649
650 if (dirent->d_name[0] == '.')
651 continue;
652 size = strlen(dirent->d_name) + 1;
653 memcpy(p, dirent->d_name, size);
654 res[i++] = p;
655 p += size;
656 }
657 out_dir:
658 closedir(dir);
659 out:
660 *count = len;
661 return res;
662 }
663
664 static int check_loaded_modules(const struct test *t)
665 {
666 int l1, l2, i1, i2;
667 const char **a1;
668 char **a2;
669 char *buf1, *buf2;
670 int err = false;
671
672 a1 = read_expected_modules(t, &buf1, &l1);
673 if (l1 < 0)
674 return err;
675 a2 = read_loaded_modules(t, &buf2, &l2);
676 if (l2 < 0)
677 goto out_a1;
678 qsort(a1, l1, sizeof(char *), cmp_modnames);
679 qsort(a2, l2, sizeof(char *), cmp_modnames);
680 i1 = i2 = 0;
681 err = true;
682 while (i1 < l1 || i2 < l2) {
683 int cmp;
684
685 if (i1 >= l1)
686 cmp = 1;
687 else if (i2 >= l2)
688 cmp = -1;
689 else
690 cmp = cmp_modnames(&a1[i1], &a2[i2]);
691 if (cmp == 0) {
692 i1++;
693 i2++;
694 } else if (cmp < 0) {
695 err = false;
696 ERR("module %s not loaded\n", a1[i1]);
697 i1++;
698 } else {
699 err = false;
700 ERR("module %s is loaded but should not be \n", a2[i2]);
701 i2++;
702 }
703 }
704 free(a2);
705 free(buf2);
706 out_a1:
707 free(a1);
708 free(buf1);
709 return err;
710 }
711
712 static inline int test_run_parent(const struct test *t, int fdout[2],
713 int fderr[2], int fdmonitor[2], pid_t child)
714 {
715 pid_t pid;
716 int err;
717 bool matchout, match_modules;
718
719 /* Close write-fds */
720 if (t->output.out != NULL)
721 close(fdout[1]);
722 if (t->output.err != NULL)
723 close(fderr[1]);
724 close(fdmonitor[1]);
725
726 matchout = test_run_parent_check_outputs(t, fdout[0], fderr[0],
727 fdmonitor[0], child);
728
729 /*
730 * break pipe on the other end: either child already closed or we want
731 * to stop it
732 */
733 if (t->output.out != NULL)
734 close(fdout[0]);
735 if (t->output.err != NULL)
736 close(fderr[0]);
737 close(fdmonitor[0]);
738
739 do {
740 pid = wait(&err);
741 if (pid == -1) {
742 ERR("error waitpid(): %m\n");
743 err = EXIT_FAILURE;
744 goto exit;
745 }
746 } while (!WIFEXITED(err) && !WIFSIGNALED(err));
747
748 if (WIFEXITED(err)) {
749 if (WEXITSTATUS(err) != 0)
750 ERR("'%s' [%u] exited with return code %d\n",
751 t->name, pid, WEXITSTATUS(err));
752 else
753 LOG("'%s' [%u] exited with return code %d\n",
754 t->name, pid, WEXITSTATUS(err));
755 } else if (WIFSIGNALED(err)) {
756 ERR("'%s' [%u] terminated by signal %d (%s)\n", t->name, pid,
757 WTERMSIG(err), strsignal(WTERMSIG(err)));
758 err = t->expected_fail ? EXIT_SUCCESS : EXIT_FAILURE;
759 goto exit;
760 }
761
762 if (matchout)
763 matchout = check_generated_files(t);
764 if (t->modules_loaded)
765 match_modules = check_loaded_modules(t);
766 else
767 match_modules = true;
768
769 if (t->expected_fail == false) {
770 if (err == 0) {
771 if (matchout && match_modules)
772 LOG("%sPASSED%s: %s\n",
773 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
774 t->name);
775 else {
776 ERR("%sFAILED%s: exit ok but %s do not match: %s\n",
777 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
778 matchout ? "loaded modules" : "outputs",
779 t->name);
780 err = EXIT_FAILURE;
781 }
782 } else {
783 ERR("%sFAILED%s: %s\n",
784 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
785 t->name);
786 }
787 } else {
788 if (err == 0) {
789 if (matchout) {
790 ERR("%sUNEXPECTED PASS%s: exit with 0: %s\n",
791 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
792 t->name);
793 err = EXIT_FAILURE;
794 } else {
795 ERR("%sUNEXPECTED PASS%s: exit with 0 and outputs do not match: %s\n",
796 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
797 t->name);
798 err = EXIT_FAILURE;
799 }
800 } else {
801 if (matchout) {
802 LOG("%sEXPECTED FAIL%s: %s\n",
803 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
804 t->name);
805 err = EXIT_SUCCESS;
806 } else {
807 LOG("%sEXPECTED FAIL%s: exit with %d but outputs do not match: %s\n",
808 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
809 WEXITSTATUS(err), t->name);
810 err = EXIT_FAILURE;
811 }
812 }
813 }
814
815 exit:
816 LOG("------\n");
817 return err;
818 }
819
820 static int prepend_path(const char *extra)
821 {
822 char *oldpath, *newpath;
823 int r;
824
825 if (extra == NULL)
826 return 0;
827
828 oldpath = getenv("PATH");
829 if (oldpath == NULL)
830 return setenv("PATH", extra, 1);
831
832 if (asprintf(&newpath, "%s:%s", extra, oldpath) < 0) {
833 ERR("failed to allocate memory to new PATH\n");
834 return -1;
835 }
836
837 r = setenv("PATH", newpath, 1);
838 free(newpath);
839
840 return r;
841 }
842
843 int test_run(const struct test *t)
844 {
845 pid_t pid;
846 int fdout[2];
847 int fderr[2];
848 int fdmonitor[2];
849
850 if (t->need_spawn && oneshot)
851 test_run_spawned(t);
852
853 if (t->output.out != NULL) {
854 if (pipe(fdout) != 0) {
855 ERR("could not create out pipe for %s\n", t->name);
856 return EXIT_FAILURE;
857 }
858 }
859
860 if (t->output.err != NULL) {
861 if (pipe(fderr) != 0) {
862 ERR("could not create err pipe for %s\n", t->name);
863 return EXIT_FAILURE;
864 }
865 }
866
867 if (pipe(fdmonitor) != 0) {
868 ERR("could not create monitor pipe for %s\n", t->name);
869 return EXIT_FAILURE;
870 }
871
872 if (prepend_path(t->path) < 0) {
873 ERR("failed to prepend '%s' to PATH\n", t->path);
874 return EXIT_FAILURE;
875 }
876
877 LOG("running %s, in forked context\n", t->name);
878
879 pid = fork();
880 if (pid < 0) {
881 ERR("could not fork(): %m\n");
882 LOG("FAILED: %s\n", t->name);
883 return EXIT_FAILURE;
884 }
885
886 if (pid > 0)
887 return test_run_parent(t, fdout, fderr, fdmonitor, pid);
888
889 return test_run_child(t, fdout, fderr, fdmonitor);
890 }