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