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