]> git.ipfire.org Git - thirdparty/kmod.git/blame - testsuite/testsuite.c
testsuite: depmod: check netsted loops reporting
[thirdparty/kmod.git] / testsuite / testsuite.c
CommitLineData
e701e381 1/*
e6b0e49b 2 * Copyright (C) 2012-2013 ProFUSION embedded systems
e701e381 3 *
e1b1ab24
LDM
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.
e701e381
LDM
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
e1b1ab24
LDM
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
e701e381 13 *
e1b1ab24 14 * You should have received a copy of the GNU Lesser General Public
dea2dfee 15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
e701e381
LDM
16 */
17
c2e4286b 18#include <dirent.h>
80f9e023
LDM
19#include <errno.h>
20#include <fcntl.h>
21#include <getopt.h>
22#include <limits.h>
80f9e023 23#include <stdarg.h>
c2e4286b 24#include <stdio.h>
80f9e023
LDM
25#include <stdlib.h>
26#include <string.h>
b8e344a6 27#include <time.h>
80f9e023 28#include <unistd.h>
3dbb8dea 29#include <sys/epoll.h>
80f9e023 30#include <sys/prctl.h>
0de690c9 31#include <sys/stat.h>
80f9e023
LDM
32#include <sys/wait.h>
33
96573a02
LDM
34#include <shared/util.h>
35
80f9e023
LDM
36#include "testsuite.h"
37
51b1d1ab
LDM
38static const char *ANSI_HIGHLIGHT_GREEN_ON = "\x1B[1;32m";
39static const char *ANSI_HIGHLIGHT_RED_ON = "\x1B[1;31m";
40static const char *ANSI_HIGHLIGHT_OFF = "\x1B[0m";
41
80f9e023 42static const char *progname;
ed2df4e9 43static int oneshot = 0;
80f9e023
LDM
44static const char options_short[] = "lhn";
45static const struct option options[] = {
46 { "list", no_argument, 0, 'l' },
47 { "help", no_argument, 0, 'h' },
48 { NULL, 0, 0, 0 }
49};
50
d2c2b8b5
LDM
51#define OVERRIDE_LIBDIR ABS_TOP_BUILDDIR "/testsuite/.libs/"
52
395478cb
LDM
53struct _env_config {
54 const char *key;
55 const char *ldpreload;
56} env_config[_TC_LAST] = {
d2c2b8b5
LDM
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" },
f6ef5d6b 60 [TC_DELETE_MODULE_RETCODES] = { S_TC_DELETE_MODULE_RETCODES, OVERRIDE_LIBDIR "delete_module.so" },
395478cb
LDM
61};
62
b8e344a6
LDM
63#define USEC_PER_SEC 1000000ULL
64#define USEC_PER_MSEC 1000ULL
65#define TEST_TIMEOUT_USEC 2 * USEC_PER_SEC
66static 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
80f9e023
LDM
76static 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
c5798fea 90static void test_list(const struct test *start, const struct test *stop)
80f9e023 91{
c5798fea 92 const struct test *t;
80f9e023
LDM
93
94 printf("Available tests:\n");
c5798fea
LDM
95 for (t = start; t < stop; t++)
96 printf("\t%s, %s\n", t->name, t->description);
80f9e023
LDM
97}
98
c5798fea
LDM
99int test_init(const struct test *start, const struct test *stop,
100 int argc, char *const argv[])
80f9e023
LDM
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':
c5798fea 111 test_list(start, stop);
80f9e023
LDM
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
51b1d1ab
LDM
127 if (isatty(STDOUT_FILENO) == 0) {
128 ANSI_HIGHLIGHT_OFF = "";
129 ANSI_HIGHLIGHT_RED_ON = "";
130 ANSI_HIGHLIGHT_GREEN_ON = "";
131 }
132
80f9e023
LDM
133 return optind;
134}
135
c5798fea
LDM
136const struct test *test_find(const struct test *start,
137 const struct test *stop, const char *name)
80f9e023 138{
c5798fea 139 const struct test *t;
80f9e023 140
c5798fea 141 for (t = start; t < stop; t++) {
5c42c5fc 142 if (streq(t->name, name))
c5798fea 143 return t;
80f9e023
LDM
144 }
145
146 return NULL;
147}
148
ed2df4e9 149static int test_spawn_test(const struct test *t)
80f9e023
LDM
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
ed2df4e9
LDM
159static 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
9e3b9d2e 167int test_spawn_prog(const char *prog, const char *const args[])
80f9e023
LDM
168{
169 execv(prog, (char *const *) args);
170
9e3b9d2e
LDM
171 ERR("failed to spawn %s\n", prog);
172 ERR("did you forget to build tools?\n");
80f9e023
LDM
173 return EXIT_FAILURE;
174}
175
395478cb 176static void test_export_environ(const struct test *t)
80f9e023 177{
395478cb
LDM
178 char *preload = NULL;
179 size_t preloadlen = 0;
180 size_t i;
34db3f2d 181 const struct keyval *env;
395478cb
LDM
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);
34db3f2d
LDM
215
216 for (env = t->env_vars; env && env->key; env++)
217 setenv(env->key, env->val, 1);
80f9e023
LDM
218}
219
3dbb8dea 220static inline int test_run_child(const struct test *t, int fdout[2],
ed8e93fd 221 int fderr[2], int fdmonitor[2])
80f9e023 222{
45481ee2
LDM
223 /* kill child if parent dies */
224 prctl(PR_SET_PDEATHSIG, SIGTERM);
225
226 test_export_environ(t);
227
3dbb8dea 228 /* Close read-fds and redirect std{out,err} to the write-fds */
bd4e7340 229 if (t->output.out != NULL) {
3dbb8dea
LDM
230 close(fdout[0]);
231 if (dup2(fdout[1], STDOUT_FILENO) < 0) {
050db08c 232 ERR("could not redirect stdout to pipe: %m\n");
3dbb8dea
LDM
233 exit(EXIT_FAILURE);
234 }
235 }
236
bd4e7340 237 if (t->output.err != NULL) {
3dbb8dea
LDM
238 close(fderr[0]);
239 if (dup2(fderr[1], STDERR_FILENO) < 0) {
bd4e7340 240 ERR("could not redirect stderr to pipe: %m\n");
3dbb8dea
LDM
241 exit(EXIT_FAILURE);
242 }
243 }
244
ed8e93fd
LDM
245 close(fdmonitor[0]);
246
0de690c9
LDM
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
45481ee2
LDM
269 if (t->need_spawn)
270 return test_spawn_test(t);
271 else
272 return test_run_spawned(t);
273}
274
03a5079f
LDM
275static 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
3dbb8dea 293static inline bool test_run_parent_check_outputs(const struct test *t,
b8e344a6 294 int fdout, int fderr, int fdmonitor, pid_t child)
3dbb8dea 295{
ed8e93fd 296 struct epoll_event ep_outpipe, ep_errpipe, ep_monitor;
3dbb8dea 297 int err, fd_ep, fd_matchout = -1, fd_matcherr = -1;
03a5079f 298 bool fd_activityout = false, fd_activityerr = false;
b8e344a6 299 unsigned long long end_usec, start_usec;
3dbb8dea 300
3dbb8dea
LDM
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
bd4e7340
JS
307 if (t->output.out != NULL) {
308 fd_matchout = open(t->output.out, O_RDONLY);
3dbb8dea
LDM
309 if (fd_matchout < 0) {
310 err = -errno;
311 ERR("could not open %s for read: %m\n",
bd4e7340 312 t->output.out);
3dbb8dea
LDM
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
bd4e7340
JS
326 if (t->output.err != NULL) {
327 fd_matcherr = open(t->output.err, O_RDONLY);
3dbb8dea
LDM
328 if (fd_matcherr < 0) {
329 err = -errno;
330 ERR("could not open %s for read: %m\n",
bd4e7340 331 t->output.err);
3dbb8dea
LDM
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
ed8e93fd
LDM
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
b8e344a6
LDM
355 start_usec = now_usec();
356 end_usec = start_usec + TEST_TIMEOUT_USEC;
357
ed8e93fd 358 for (err = 0; fdmonitor >= 0 || fdout >= 0 || fderr >= 0;) {
b8e344a6 359 int fdcount, i, timeout;
3dbb8dea 360 struct epoll_event ev[4];
b8e344a6 361 unsigned long long curr_usec = now_usec();
3dbb8dea 362
b8e344a6
LDM
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);
3dbb8dea
LDM
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
03a5079f 394 if (*fd == fdout) {
3dbb8dea 395 fd_match = fd_matchout;
03a5079f
LDM
396 fd_activityout = true;
397 } else if (*fd == fderr) {
3dbb8dea 398 fd_match = fd_matcherr;
03a5079f
LDM
399 fd_activityerr = true;
400 } else {
ed8e93fd
LDM
401 ERR("Unexpected activity on monitor pipe\n");
402 err = -EINVAL;
403 goto out;
404 }
3dbb8dea
LDM
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';
f6dc239e
LDM
426
427 if (t->print_outputs)
428 printf("%s: %s\n",
429 fd_match == fd_matchout ? "STDOUT:" : "STDERR:",
430 buf);
431
5c42c5fc 432 if (!streq(buf, bufmatch)) {
3dbb8dea 433 ERR("Outputs do not match on %s:\n",
03a5079f 434 fd_match == fd_matchout ? "STDOUT" : "STDERR");
3dbb8dea
LDM
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 }
b8e344a6 449 }
3dbb8dea 450
03a5079f
LDM
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
b8e344a6
LDM
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);
3dbb8dea 458 }
b8e344a6 459
3dbb8dea
LDM
460out:
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
3e451bfe
LDM
470static 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);
2ad09ccf 476 if (r == -1 && errno == EINTR)
3e451bfe
LDM
477 continue;
478 break;
479 }
480
481 return r;
482}
483
484static 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
547next:
548 close(fda);
549 close(fdb);
550 continue;
551
552fail:
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
88ac4084
MM
564static 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 */
586static 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
627static 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 }
686out_dir:
687 closedir(dir);
688out:
689 *count = len;
690 return res;
691}
692
693static 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);
735out_a1:
736 free(a1);
737 free(buf1);
738 return err;
739}
740
3dbb8dea 741static inline int test_run_parent(const struct test *t, int fdout[2],
b8e344a6 742 int fderr[2], int fdmonitor[2], pid_t child)
45481ee2
LDM
743{
744 pid_t pid;
80f9e023 745 int err;
88ac4084 746 bool matchout, match_modules;
3dbb8dea
LDM
747
748 /* Close write-fds */
bd4e7340 749 if (t->output.out != NULL)
3dbb8dea 750 close(fdout[1]);
bd4e7340 751 if (t->output.err != NULL)
3dbb8dea 752 close(fderr[1]);
ed8e93fd 753 close(fdmonitor[1]);
3dbb8dea 754
ed8e93fd 755 matchout = test_run_parent_check_outputs(t, fdout[0], fderr[0],
b8e344a6 756 fdmonitor[0], child);
3dbb8dea
LDM
757
758 /*
759 * break pipe on the other end: either child already closed or we want
760 * to stop it
761 */
bd4e7340 762 if (t->output.out != NULL)
3dbb8dea 763 close(fdout[0]);
bd4e7340 764 if (t->output.err != NULL)
3dbb8dea 765 close(fderr[0]);
ed8e93fd 766 close(fdmonitor[0]);
45481ee2
LDM
767
768 do {
769 pid = wait(&err);
770 if (pid == -1) {
771 ERR("error waitpid(): %m\n");
f988e25c
LDM
772 err = EXIT_FAILURE;
773 goto exit;
45481ee2
LDM
774 }
775 } while (!WIFEXITED(err) && !WIFSIGNALED(err));
776
3dbb8dea
LDM
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)));
f988e25c
LDM
787 err = t->expected_fail ? EXIT_SUCCESS : EXIT_FAILURE;
788 goto exit;
3dbb8dea
LDM
789 }
790
3e451bfe
LDM
791 if (matchout)
792 matchout = check_generated_files(t);
88ac4084
MM
793 if (t->modules_loaded)
794 match_modules = check_loaded_modules(t);
795 else
796 match_modules = true;
3e451bfe 797
fa0046ba
DR
798 if (t->expected_fail == false) {
799 if (err == 0) {
88ac4084 800 if (matchout && match_modules)
fa0046ba
DR
801 LOG("%sPASSED%s: %s\n",
802 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
803 t->name);
804 else {
88ac4084 805 ERR("%sFAILED%s: exit ok but %s do not match: %s\n",
fa0046ba 806 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
88ac4084 807 matchout ? "loaded modules" : "outputs",
fa0046ba
DR
808 t->name);
809 err = EXIT_FAILURE;
810 }
f429113a 811 } else {
fa0046ba
DR
812 ERR("%sFAILED%s: %s\n",
813 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
814 t->name);
f429113a 815 }
fa0046ba
DR
816 } else {
817 if (err == 0) {
818 if (matchout) {
d7293a16 819 ERR("%sUNEXPECTED PASS%s: exit with 0: %s\n",
658e0471 820 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
fa0046ba
DR
821 t->name);
822 err = EXIT_FAILURE;
d7293a16
LDM
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,
fa0046ba 826 t->name);
d7293a16
LDM
827 err = EXIT_FAILURE;
828 }
fa0046ba 829 } else {
d7293a16
LDM
830 if (matchout) {
831 LOG("%sEXPECTED FAIL%s: %s\n",
fa0046ba
DR
832 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
833 t->name);
d7293a16
LDM
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 }
3dbb8dea 841 }
fa0046ba 842 }
45481ee2 843
f988e25c
LDM
844exit:
845 LOG("------\n");
45481ee2
LDM
846 return err;
847}
848
f31d49c8
DR
849static 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) {
050db08c 862 ERR("failed to allocate memory to new PATH\n");
f31d49c8
DR
863 return -1;
864 }
865
866 r = setenv("PATH", newpath, 1);
867 free(newpath);
868
869 return r;
870}
871
45481ee2
LDM
872int test_run(const struct test *t)
873{
80f9e023 874 pid_t pid;
3dbb8dea
LDM
875 int fdout[2];
876 int fderr[2];
ed8e93fd 877 int fdmonitor[2];
80f9e023 878
ed2df4e9
LDM
879 if (t->need_spawn && oneshot)
880 test_run_spawned(t);
881
bd4e7340 882 if (t->output.out != NULL) {
3dbb8dea
LDM
883 if (pipe(fdout) != 0) {
884 ERR("could not create out pipe for %s\n", t->name);
885 return EXIT_FAILURE;
886 }
887 }
888
bd4e7340 889 if (t->output.err != NULL) {
3dbb8dea
LDM
890 if (pipe(fderr) != 0) {
891 ERR("could not create err pipe for %s\n", t->name);
892 return EXIT_FAILURE;
893 }
894 }
895
ed8e93fd
LDM
896 if (pipe(fdmonitor) != 0) {
897 ERR("could not create monitor pipe for %s\n", t->name);
898 return EXIT_FAILURE;
899 }
900
f31d49c8
DR
901 if (prepend_path(t->path) < 0) {
902 ERR("failed to prepend '%s' to PATH\n", t->path);
903 return EXIT_FAILURE;
904 }
905
80f9e023
LDM
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
45481ee2 915 if (pid > 0)
b8e344a6 916 return test_run_parent(t, fdout, fderr, fdmonitor, pid);
80f9e023 917
ed8e93fd 918 return test_run_child(t, fdout, fderr, fdmonitor);
80f9e023 919}