]> git.ipfire.org Git - thirdparty/kmod.git/blob - testsuite/testsuite.c
Move remaining functions from libkmod-util to shared
[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 "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
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
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
91 static void test_list(const struct test *tests[])
92 {
93 size_t i;
94
95 printf("Available tests:\n");
96 for (i = 0; tests[i] != NULL; i++)
97 printf("\t%s, %s\n", tests[i]->name, tests[i]->description);
98 }
99
100 int test_init(int argc, char *const argv[], const struct test *tests[])
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(tests);
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
136 const struct test *test_find(const struct test *tests[], const char *name)
137 {
138 size_t i;
139
140 for (i = 0; tests[i] != NULL; i++) {
141 if (strcmp(tests[i]->name, name) == 0)
142 return tests[i];
143 }
144
145 return NULL;
146 }
147
148 static int test_spawn_test(const struct test *t)
149 {
150 const char *const args[] = { progname, "-n", t->name, NULL };
151
152 execv(progname, (char *const *) args);
153
154 ERR("failed to spawn %s for %s: %m\n", progname, t->name);
155 return EXIT_FAILURE;
156 }
157
158 static int test_run_spawned(const struct test *t)
159 {
160 int err = t->func(t);
161 exit(err);
162
163 return EXIT_FAILURE;
164 }
165
166 int test_spawn_prog(const char *prog, const char *const args[])
167 {
168 execv(prog, (char *const *) args);
169
170 ERR("failed to spawn %s\n", prog);
171 ERR("did you forget to build tools?\n");
172 return EXIT_FAILURE;
173 }
174
175 static void test_export_environ(const struct test *t)
176 {
177 char *preload = NULL;
178 size_t preloadlen = 0;
179 size_t i;
180 const struct keyval *env;
181
182 unsetenv("LD_PRELOAD");
183
184 for (i = 0; i < _TC_LAST; i++) {
185 const char *ldpreload;
186 size_t ldpreloadlen;
187 char *tmp;
188
189 if (t->config[i] == NULL)
190 continue;
191
192 setenv(env_config[i].key, t->config[i], 1);
193
194 ldpreload = env_config[i].ldpreload;
195 ldpreloadlen = strlen(ldpreload);
196 tmp = realloc(preload, preloadlen + 2 + ldpreloadlen);
197 if (tmp == NULL) {
198 ERR("oom: test_export_environ()\n");
199 return;
200 }
201 preload = tmp;
202
203 if (preloadlen > 0)
204 preload[preloadlen++] = ' ';
205 memcpy(preload + preloadlen, ldpreload, ldpreloadlen);
206 preloadlen += ldpreloadlen;
207 preload[preloadlen] = '\0';
208 }
209
210 if (preload != NULL)
211 setenv("LD_PRELOAD", preload, 1);
212
213 free(preload);
214
215 for (env = t->env_vars; env && env->key; env++)
216 setenv(env->key, env->val, 1);
217 }
218
219 static inline int test_run_child(const struct test *t, int fdout[2],
220 int fderr[2], int fdmonitor[2])
221 {
222 /* kill child if parent dies */
223 prctl(PR_SET_PDEATHSIG, SIGTERM);
224
225 test_export_environ(t);
226
227 /* Close read-fds and redirect std{out,err} to the write-fds */
228 if (t->output.out != NULL) {
229 close(fdout[0]);
230 if (dup2(fdout[1], STDOUT_FILENO) < 0) {
231 ERR("could not redirect stdout to pipe: %m\n");
232 exit(EXIT_FAILURE);
233 }
234 }
235
236 if (t->output.err != NULL) {
237 close(fderr[0]);
238 if (dup2(fderr[1], STDERR_FILENO) < 0) {
239 ERR("could not redirect stderr to pipe: %m\n");
240 exit(EXIT_FAILURE);
241 }
242 }
243
244 close(fdmonitor[0]);
245
246 if (t->config[TC_ROOTFS] != NULL) {
247 const char *stamp = TESTSUITE_ROOTFS "../stamp-rootfs";
248 const char *rootfs = t->config[TC_ROOTFS];
249 struct stat rootfsst, stampst;
250
251 if (stat(stamp, &stampst) != 0) {
252 ERR("could not stat %s\n - %m", stamp);
253 exit(EXIT_FAILURE);
254 }
255
256 if (stat(rootfs, &rootfsst) != 0) {
257 ERR("could not stat %s\n - %m", rootfs);
258 exit(EXIT_FAILURE);
259 }
260
261 if (stat_mstamp(&rootfsst) > stat_mstamp(&stampst)) {
262 ERR("rootfs %s is dirty, please run 'make rootfs' before runnning this test\n",
263 rootfs);
264 exit(EXIT_FAILURE);
265 }
266 }
267
268 if (t->need_spawn)
269 return test_spawn_test(t);
270 else
271 return test_run_spawned(t);
272 }
273
274 static inline bool test_run_parent_check_outputs(const struct test *t,
275 int fdout, int fderr, int fdmonitor, pid_t child)
276 {
277 struct epoll_event ep_outpipe, ep_errpipe, ep_monitor;
278 int err, fd_ep, fd_matchout = -1, fd_matcherr = -1;
279 unsigned long long end_usec, start_usec;
280
281 fd_ep = epoll_create1(EPOLL_CLOEXEC);
282 if (fd_ep < 0) {
283 ERR("could not create epoll fd: %m\n");
284 return false;
285 }
286
287 if (t->output.out != NULL) {
288 fd_matchout = open(t->output.out, O_RDONLY);
289 if (fd_matchout < 0) {
290 err = -errno;
291 ERR("could not open %s for read: %m\n",
292 t->output.out);
293 goto out;
294 }
295 memset(&ep_outpipe, 0, sizeof(struct epoll_event));
296 ep_outpipe.events = EPOLLIN;
297 ep_outpipe.data.ptr = &fdout;
298 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fdout, &ep_outpipe) < 0) {
299 err = -errno;
300 ERR("could not add fd to epoll: %m\n");
301 goto out;
302 }
303 } else
304 fdout = -1;
305
306 if (t->output.err != NULL) {
307 fd_matcherr = open(t->output.err, O_RDONLY);
308 if (fd_matcherr < 0) {
309 err = -errno;
310 ERR("could not open %s for read: %m\n",
311 t->output.err);
312 goto out;
313
314 }
315 memset(&ep_errpipe, 0, sizeof(struct epoll_event));
316 ep_errpipe.events = EPOLLIN;
317 ep_errpipe.data.ptr = &fderr;
318 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fderr, &ep_errpipe) < 0) {
319 err = -errno;
320 ERR("could not add fd to epoll: %m\n");
321 goto out;
322 }
323 } else
324 fderr = -1;
325
326 memset(&ep_monitor, 0, sizeof(struct epoll_event));
327 ep_monitor.events = EPOLLHUP;
328 ep_monitor.data.ptr = &fdmonitor;
329 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fdmonitor, &ep_monitor) < 0) {
330 err = -errno;
331 ERR("could not add monitor fd to epoll: %m\n");
332 goto out;
333 }
334
335 start_usec = now_usec();
336 end_usec = start_usec + TEST_TIMEOUT_USEC;
337
338 for (err = 0; fdmonitor >= 0 || fdout >= 0 || fderr >= 0;) {
339 int fdcount, i, timeout;
340 struct epoll_event ev[4];
341 unsigned long long curr_usec = now_usec();
342
343 if (curr_usec > end_usec)
344 break;
345
346 timeout = (end_usec - curr_usec) / USEC_PER_MSEC;
347 fdcount = epoll_wait(fd_ep, ev, 4, timeout);
348 if (fdcount < 0) {
349 if (errno == EINTR)
350 continue;
351 err = -errno;
352 ERR("could not poll: %m\n");
353 goto out;
354 }
355
356 for (i = 0; i < fdcount; i++) {
357 int *fd = ev[i].data.ptr;
358
359 if (ev[i].events & EPOLLIN) {
360 ssize_t r, done = 0;
361 char buf[4096];
362 char bufmatch[4096];
363 int fd_match;
364
365 /*
366 * compare the output from child with the one
367 * saved as correct
368 */
369
370 r = read(*fd, buf, sizeof(buf) - 1);
371 if (r <= 0)
372 continue;
373
374 if (*fd == fdout)
375 fd_match = fd_matchout;
376 else if (*fd == fderr)
377 fd_match = fd_matcherr;
378 else {
379 ERR("Unexpected activity on monitor pipe\n");
380 err = -EINVAL;
381 goto out;
382 }
383
384 for (;;) {
385 int rmatch = read(fd_match,
386 bufmatch + done, r - done);
387 if (rmatch == 0)
388 break;
389
390 if (rmatch < 0) {
391 if (errno == EINTR)
392 continue;
393 err = -errno;
394 ERR("could not read match fd %d\n",
395 fd_match);
396 goto out;
397 }
398
399 done += rmatch;
400 }
401
402 buf[r] = '\0';
403 bufmatch[r] = '\0';
404 if (strcmp(buf, bufmatch) != 0) {
405 ERR("Outputs do not match on %s:\n",
406 fd_match == fd_matchout ? "stdout" : "stderr");
407 ERR("correct:\n%s\n", bufmatch);
408 ERR("wrong:\n%s\n", buf);
409 err = -1;
410 goto out;
411 }
412 } else if (ev[i].events & EPOLLHUP) {
413 if (epoll_ctl(fd_ep, EPOLL_CTL_DEL,
414 *fd, NULL) < 0) {
415 ERR("could not remove fd %d from epoll: %m\n",
416 *fd);
417 }
418 *fd = -1;
419 }
420 }
421 }
422
423 if (err == 0 && fdmonitor >= 0) {
424 err = -EINVAL;
425 ERR("Test '%s' timed out, killing %d\n", t->name, child);
426 kill(child, SIGKILL);
427 }
428
429 out:
430 if (fd_matchout >= 0)
431 close(fd_matchout);
432 if (fd_matcherr >= 0)
433 close(fd_matcherr);
434 if (fd_ep >= 0)
435 close(fd_ep);
436 return err == 0;
437 }
438
439 static inline int safe_read(int fd, void *buf, size_t count)
440 {
441 int r;
442
443 while (1) {
444 r = read(fd, buf, count);
445 if (r == -1 && errno == EINTR)
446 continue;
447 break;
448 }
449
450 return r;
451 }
452
453 static bool check_generated_files(const struct test *t)
454 {
455 const struct keyval *k;
456
457 /* This is not meant to be a diff replacement, just stupidly check if
458 * the files match. Bear in mind they can be binary files */
459 for (k = t->output.files; k && k->key; k++) {
460 struct stat sta, stb;
461 int fda = -1, fdb = -1;
462 char bufa[4096];
463 char bufb[4096];
464
465 fda = open(k->key, O_RDONLY);
466 if (fda < 0) {
467 ERR("could not open %s\n - %m\n", k->key);
468 goto fail;
469 }
470
471 fdb = open(k->val, O_RDONLY);
472 if (fdb < 0) {
473 ERR("could not open %s\n - %m\n", k->val);
474 goto fail;
475 }
476
477 if (fstat(fda, &sta) != 0) {
478 ERR("could not fstat %d %s\n - %m\n", fda, k->key);
479 goto fail;
480 }
481
482 if (fstat(fdb, &stb) != 0) {
483 ERR("could not fstat %d %s\n - %m\n", fdb, k->key);
484 goto fail;
485 }
486
487 if (sta.st_size != stb.st_size) {
488 ERR("sizes do not match %s %s\n", k->key, k->val);
489 goto fail;
490 }
491
492 for (;;) {
493 int r, done;
494
495 r = safe_read(fda, bufa, sizeof(bufa));
496 if (r < 0)
497 goto fail;
498
499 if (r == 0)
500 /* size is already checked, go to next file */
501 goto next;
502
503 for (done = 0; done < r;) {
504 int r2 = safe_read(fdb, bufb + done, r - done);
505
506 if (r2 <= 0)
507 goto fail;
508
509 done += r2;
510 }
511
512 if (memcmp(bufa, bufb, r) != 0)
513 goto fail;
514 }
515
516 next:
517 close(fda);
518 close(fdb);
519 continue;
520
521 fail:
522 if (fda >= 0)
523 close(fda);
524 if (fdb >= 0)
525 close(fdb);
526
527 return false;
528 }
529
530 return true;
531 }
532
533 static int cmp_modnames(const void *m1, const void *m2)
534 {
535 const char *s1 = *(char *const *)m1;
536 const char *s2 = *(char *const *)m2;
537 int i;
538
539 for (i = 0; s1[i] || s2[i]; i++) {
540 char c1 = s1[i], c2 = s2[i];
541 if (c1 == '-')
542 c1 = '_';
543 if (c2 == '-')
544 c2 = '_';
545 if (c1 != c2)
546 return c1 - c2;
547 }
548 return 0;
549 }
550
551 /*
552 * Store the expected module names in buf and return a list of pointers to
553 * them.
554 */
555 static const char **read_expected_modules(const struct test *t,
556 char **buf, int *count)
557 {
558 const char **res;
559 int len;
560 int i;
561 char *p;
562
563 if (t->modules_loaded[0] == '\0') {
564 *count = 0;
565 *buf = NULL;
566 return NULL;
567 }
568 *buf = strdup(t->modules_loaded);
569 if (!*buf) {
570 *count = -1;
571 return NULL;
572 }
573 len = 1;
574 for (p = *buf; *p; p++)
575 if (*p == ',')
576 len++;
577 res = malloc(sizeof(char *) * len);
578 if (!res) {
579 perror("malloc");
580 *count = -1;
581 free(*buf);
582 *buf = NULL;
583 return NULL;
584 }
585 i = 0;
586 res[i++] = *buf;
587 for (p = *buf; i < len; p++)
588 if (*p == ',') {
589 *p = '\0';
590 res[i++] = p + 1;
591 }
592 *count = len;
593 return res;
594 }
595
596 static char **read_loaded_modules(const struct test *t, char **buf, int *count)
597 {
598 char dirname[PATH_MAX];
599 DIR *dir;
600 struct dirent *dirent;
601 int i;
602 int len = 0, bufsz;
603 char **res = NULL;
604 char *p;
605 const char *rootfs = t->config[TC_ROOTFS] ? t->config[TC_ROOTFS] : "";
606
607 /* Store the entries in /sys/module to res */
608 if (snprintf(dirname, sizeof(dirname), "%s/sys/module", rootfs)
609 >= (int)sizeof(dirname)) {
610 ERR("rootfs path too long: %s\n", rootfs);
611 *buf = NULL;
612 len = -1;
613 goto out;
614 }
615 dir = opendir(dirname);
616 /* not an error, simply return empty list */
617 if (!dir) {
618 *buf = NULL;
619 goto out;
620 }
621 bufsz = 0;
622 while ((dirent = readdir(dir))) {
623 if (dirent->d_name[0] == '.')
624 continue;
625 len++;
626 bufsz += strlen(dirent->d_name) + 1;
627 }
628 res = malloc(sizeof(char *) * len);
629 if (!res) {
630 perror("malloc");
631 len = -1;
632 goto out_dir;
633 }
634 *buf = malloc(bufsz);
635 if (!*buf) {
636 perror("malloc");
637 free(res);
638 res = NULL;
639 len = -1;
640 goto out_dir;
641 }
642 rewinddir(dir);
643 i = 0;
644 p = *buf;
645 while ((dirent = readdir(dir))) {
646 int size;
647
648 if (dirent->d_name[0] == '.')
649 continue;
650 size = strlen(dirent->d_name) + 1;
651 memcpy(p, dirent->d_name, size);
652 res[i++] = p;
653 p += size;
654 }
655 out_dir:
656 closedir(dir);
657 out:
658 *count = len;
659 return res;
660 }
661
662 static int check_loaded_modules(const struct test *t)
663 {
664 int l1, l2, i1, i2;
665 const char **a1;
666 char **a2;
667 char *buf1, *buf2;
668 int err = false;
669
670 a1 = read_expected_modules(t, &buf1, &l1);
671 if (l1 < 0)
672 return err;
673 a2 = read_loaded_modules(t, &buf2, &l2);
674 if (l2 < 0)
675 goto out_a1;
676 qsort(a1, l1, sizeof(char *), cmp_modnames);
677 qsort(a2, l2, sizeof(char *), cmp_modnames);
678 i1 = i2 = 0;
679 err = true;
680 while (i1 < l1 || i2 < l2) {
681 int cmp;
682
683 if (i1 >= l1)
684 cmp = 1;
685 else if (i2 >= l2)
686 cmp = -1;
687 else
688 cmp = cmp_modnames(&a1[i1], &a2[i2]);
689 if (cmp == 0) {
690 i1++;
691 i2++;
692 } else if (cmp < 0) {
693 err = false;
694 ERR("module %s not loaded\n", a1[i1]);
695 i1++;
696 } else {
697 err = false;
698 ERR("module %s is loaded but should not be \n", a2[i2]);
699 i2++;
700 }
701 }
702 free(a2);
703 free(buf2);
704 out_a1:
705 free(a1);
706 free(buf1);
707 return err;
708 }
709
710 static inline int test_run_parent(const struct test *t, int fdout[2],
711 int fderr[2], int fdmonitor[2], pid_t child)
712 {
713 pid_t pid;
714 int err;
715 bool matchout, match_modules;
716
717 /* Close write-fds */
718 if (t->output.out != NULL)
719 close(fdout[1]);
720 if (t->output.err != NULL)
721 close(fderr[1]);
722 close(fdmonitor[1]);
723
724 matchout = test_run_parent_check_outputs(t, fdout[0], fderr[0],
725 fdmonitor[0], child);
726
727 /*
728 * break pipe on the other end: either child already closed or we want
729 * to stop it
730 */
731 if (t->output.out != NULL)
732 close(fdout[0]);
733 if (t->output.err != NULL)
734 close(fderr[0]);
735 close(fdmonitor[0]);
736
737 do {
738 pid = wait(&err);
739 if (pid == -1) {
740 ERR("error waitpid(): %m\n");
741 err = EXIT_FAILURE;
742 goto exit;
743 }
744 } while (!WIFEXITED(err) && !WIFSIGNALED(err));
745
746 if (WIFEXITED(err)) {
747 if (WEXITSTATUS(err) != 0)
748 ERR("'%s' [%u] exited with return code %d\n",
749 t->name, pid, WEXITSTATUS(err));
750 else
751 LOG("'%s' [%u] exited with return code %d\n",
752 t->name, pid, WEXITSTATUS(err));
753 } else if (WIFSIGNALED(err)) {
754 ERR("'%s' [%u] terminated by signal %d (%s)\n", t->name, pid,
755 WTERMSIG(err), strsignal(WTERMSIG(err)));
756 err = t->expected_fail ? EXIT_SUCCESS : EXIT_FAILURE;
757 goto exit;
758 }
759
760 if (matchout)
761 matchout = check_generated_files(t);
762 if (t->modules_loaded)
763 match_modules = check_loaded_modules(t);
764 else
765 match_modules = true;
766
767 if (t->expected_fail == false) {
768 if (err == 0) {
769 if (matchout && match_modules)
770 LOG("%sPASSED%s: %s\n",
771 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
772 t->name);
773 else {
774 ERR("%sFAILED%s: exit ok but %s do not match: %s\n",
775 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
776 matchout ? "loaded modules" : "outputs",
777 t->name);
778 err = EXIT_FAILURE;
779 }
780 } else {
781 ERR("%sFAILED%s: %s\n",
782 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
783 t->name);
784 }
785 } else {
786 if (err == 0) {
787 if (matchout) {
788 ERR("%sUNEXPECTED PASS%s: exit with 0: %s\n",
789 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
790 t->name);
791 err = EXIT_FAILURE;
792 } else {
793 ERR("%sUNEXPECTED PASS%s: exit with 0 and outputs do not match: %s\n",
794 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
795 t->name);
796 err = EXIT_FAILURE;
797 }
798 } else {
799 if (matchout) {
800 LOG("%sEXPECTED FAIL%s: %s\n",
801 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
802 t->name);
803 err = EXIT_SUCCESS;
804 } else {
805 LOG("%sEXPECTED FAIL%s: exit with %d but outputs do not match: %s\n",
806 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
807 WEXITSTATUS(err), t->name);
808 err = EXIT_FAILURE;
809 }
810 }
811 }
812
813 exit:
814 LOG("------\n");
815 return err;
816 }
817
818 static int prepend_path(const char *extra)
819 {
820 char *oldpath, *newpath;
821 int r;
822
823 if (extra == NULL)
824 return 0;
825
826 oldpath = getenv("PATH");
827 if (oldpath == NULL)
828 return setenv("PATH", extra, 1);
829
830 if (asprintf(&newpath, "%s:%s", extra, oldpath) < 0) {
831 ERR("failed to allocate memory to new PATH\n");
832 return -1;
833 }
834
835 r = setenv("PATH", newpath, 1);
836 free(newpath);
837
838 return r;
839 }
840
841 int test_run(const struct test *t)
842 {
843 pid_t pid;
844 int fdout[2];
845 int fderr[2];
846 int fdmonitor[2];
847
848 if (t->need_spawn && oneshot)
849 test_run_spawned(t);
850
851 if (t->output.out != NULL) {
852 if (pipe(fdout) != 0) {
853 ERR("could not create out pipe for %s\n", t->name);
854 return EXIT_FAILURE;
855 }
856 }
857
858 if (t->output.err != NULL) {
859 if (pipe(fderr) != 0) {
860 ERR("could not create err pipe for %s\n", t->name);
861 return EXIT_FAILURE;
862 }
863 }
864
865 if (pipe(fdmonitor) != 0) {
866 ERR("could not create monitor pipe for %s\n", t->name);
867 return EXIT_FAILURE;
868 }
869
870 if (prepend_path(t->path) < 0) {
871 ERR("failed to prepend '%s' to PATH\n", t->path);
872 return EXIT_FAILURE;
873 }
874
875 LOG("running %s, in forked context\n", t->name);
876
877 pid = fork();
878 if (pid < 0) {
879 ERR("could not fork(): %m\n");
880 LOG("FAILED: %s\n", t->name);
881 return EXIT_FAILURE;
882 }
883
884 if (pid > 0)
885 return test_run_parent(t, fdout, fderr, fdmonitor, pid);
886
887 return test_run_child(t, fdout, fderr, fdmonitor);
888 }