]> git.ipfire.org Git - thirdparty/kmod.git/blame - testsuite/testsuite.c
testsuite: split out function to compare outputs exactly
[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
a5cc3521
LDM
293#define BUFSZ 4096
294struct buffer {
295 char buf[BUFSZ];
296};
297
298/* read fd and fd_match, checking they match exactly */
299static bool cmpbuf_exact(const struct test *t, const char *prefix,
300 int fd, int fd_match, struct buffer *buf,
301 struct buffer *buf_match)
302{
303 int r, rmatch, done = 0;
304
305 r = read(fd, buf->buf, sizeof(buf->buf) - 1);
306 if (r <= 0)
307 /* try again later */
308 return true;
309
310 /* read as much data from fd_match as we read from fd */
311 for (;;) {
312 rmatch = read(fd_match, buf_match->buf + done, r - done);
313 if (rmatch == 0)
314 break;
315
316 if (rmatch < 0) {
317 if (errno == EINTR)
318 continue;
319 ERR("could not read match fd %d\n", fd_match);
320 return false;
321 }
322
323 done += rmatch;
324 }
325
326 buf->buf[r] = '\0';
327 buf_match->buf[r] = '\0';
328
329 if (t->print_outputs)
330 printf("%s: %s\n", prefix, buf->buf);
331
332 if (!streq(buf->buf, buf_match->buf)) {
333 ERR("Outputs do not match on %s:\n", prefix);
334 ERR("correct:\n%s\n", buf_match->buf);
335 ERR("wrong:\n%s\n", buf->buf);
336 return false;
337 }
338
339 return true;
340}
341
342static bool test_run_parent_check_outputs(const struct test *t,
343 int fdout, int fderr, int fdmonitor,
344 pid_t child)
3dbb8dea 345{
ed8e93fd 346 struct epoll_event ep_outpipe, ep_errpipe, ep_monitor;
3dbb8dea 347 int err, fd_ep, fd_matchout = -1, fd_matcherr = -1;
03a5079f 348 bool fd_activityout = false, fd_activityerr = false;
b8e344a6 349 unsigned long long end_usec, start_usec;
a5cc3521 350 _cleanup_free_ struct buffer *buf_out = NULL, *buf_err = NULL;
3dbb8dea 351
3dbb8dea
LDM
352 fd_ep = epoll_create1(EPOLL_CLOEXEC);
353 if (fd_ep < 0) {
354 ERR("could not create epoll fd: %m\n");
355 return false;
356 }
357
bd4e7340
JS
358 if (t->output.out != NULL) {
359 fd_matchout = open(t->output.out, O_RDONLY);
3dbb8dea
LDM
360 if (fd_matchout < 0) {
361 err = -errno;
362 ERR("could not open %s for read: %m\n",
bd4e7340 363 t->output.out);
3dbb8dea
LDM
364 goto out;
365 }
366 memset(&ep_outpipe, 0, sizeof(struct epoll_event));
367 ep_outpipe.events = EPOLLIN;
368 ep_outpipe.data.ptr = &fdout;
369 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fdout, &ep_outpipe) < 0) {
370 err = -errno;
371 ERR("could not add fd to epoll: %m\n");
372 goto out;
373 }
a5cc3521 374 buf_out = calloc(2, sizeof(*buf_out));
3dbb8dea
LDM
375 } else
376 fdout = -1;
377
bd4e7340
JS
378 if (t->output.err != NULL) {
379 fd_matcherr = open(t->output.err, O_RDONLY);
3dbb8dea
LDM
380 if (fd_matcherr < 0) {
381 err = -errno;
382 ERR("could not open %s for read: %m\n",
bd4e7340 383 t->output.err);
3dbb8dea
LDM
384 goto out;
385
386 }
387 memset(&ep_errpipe, 0, sizeof(struct epoll_event));
388 ep_errpipe.events = EPOLLIN;
389 ep_errpipe.data.ptr = &fderr;
390 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fderr, &ep_errpipe) < 0) {
391 err = -errno;
392 ERR("could not add fd to epoll: %m\n");
393 goto out;
394 }
a5cc3521 395 buf_err = calloc(2, sizeof(*buf_err));
3dbb8dea
LDM
396 } else
397 fderr = -1;
398
ed8e93fd
LDM
399 memset(&ep_monitor, 0, sizeof(struct epoll_event));
400 ep_monitor.events = EPOLLHUP;
401 ep_monitor.data.ptr = &fdmonitor;
402 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fdmonitor, &ep_monitor) < 0) {
403 err = -errno;
404 ERR("could not add monitor fd to epoll: %m\n");
405 goto out;
406 }
407
b8e344a6
LDM
408 start_usec = now_usec();
409 end_usec = start_usec + TEST_TIMEOUT_USEC;
410
ed8e93fd 411 for (err = 0; fdmonitor >= 0 || fdout >= 0 || fderr >= 0;) {
b8e344a6 412 int fdcount, i, timeout;
3dbb8dea 413 struct epoll_event ev[4];
b8e344a6 414 unsigned long long curr_usec = now_usec();
3dbb8dea 415
b8e344a6
LDM
416 if (curr_usec > end_usec)
417 break;
418
419 timeout = (end_usec - curr_usec) / USEC_PER_MSEC;
420 fdcount = epoll_wait(fd_ep, ev, 4, timeout);
3dbb8dea
LDM
421 if (fdcount < 0) {
422 if (errno == EINTR)
423 continue;
424 err = -errno;
425 ERR("could not poll: %m\n");
426 goto out;
427 }
428
429 for (i = 0; i < fdcount; i++) {
a5cc3521 430 int fd = *(int *)ev[i].data.ptr;
3dbb8dea
LDM
431
432 if (ev[i].events & EPOLLIN) {
3dbb8dea 433 int fd_match;
a5cc3521
LDM
434 struct buffer *buf, *buf_match;
435 const char *prefix;
3dbb8dea 436
a5cc3521 437 if (fd == fdout) {
3dbb8dea 438 fd_match = fd_matchout;
a5cc3521 439 buf = buf_out;
03a5079f 440 fd_activityout = true;
a5cc3521
LDM
441 prefix = "STDOUT";
442 } else if (fd == fderr) {
3dbb8dea 443 fd_match = fd_matcherr;
a5cc3521 444 buf = buf_err;
03a5079f 445 fd_activityerr = true;
a5cc3521 446 prefix = "STDERR";
03a5079f 447 } else {
ed8e93fd
LDM
448 ERR("Unexpected activity on monitor pipe\n");
449 err = -EINVAL;
450 goto out;
451 }
3dbb8dea 452
a5cc3521 453 buf_match = buf + 1;
f6dc239e 454
a5cc3521
LDM
455 if (!cmpbuf_exact(t, prefix, fd, fd_match,
456 buf, buf_match))
3dbb8dea 457 goto out;
3dbb8dea 458 } else if (ev[i].events & EPOLLHUP) {
a5cc3521
LDM
459 if (epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd, NULL) < 0) {
460 ERR("could not remove fd %d from epoll: %m\n", fd);
3dbb8dea 461 }
a5cc3521 462 *(int *)ev[i].data.ptr = -1;
3dbb8dea
LDM
463 }
464 }
b8e344a6 465 }
3dbb8dea 466
03a5079f
LDM
467 err = check_activity(fd_matchout, fd_activityout, t->output.out, "stdout");
468 err |= check_activity(fd_matcherr, fd_activityerr, t->output.err, "stderr");
469
b8e344a6
LDM
470 if (err == 0 && fdmonitor >= 0) {
471 err = -EINVAL;
472 ERR("Test '%s' timed out, killing %d\n", t->name, child);
473 kill(child, SIGKILL);
3dbb8dea 474 }
b8e344a6 475
3dbb8dea
LDM
476out:
477 if (fd_matchout >= 0)
478 close(fd_matchout);
479 if (fd_matcherr >= 0)
480 close(fd_matcherr);
481 if (fd_ep >= 0)
482 close(fd_ep);
483 return err == 0;
484}
485
3e451bfe
LDM
486static inline int safe_read(int fd, void *buf, size_t count)
487{
488 int r;
489
490 while (1) {
491 r = read(fd, buf, count);
2ad09ccf 492 if (r == -1 && errno == EINTR)
3e451bfe
LDM
493 continue;
494 break;
495 }
496
497 return r;
498}
499
500static bool check_generated_files(const struct test *t)
501{
502 const struct keyval *k;
503
504 /* This is not meant to be a diff replacement, just stupidly check if
505 * the files match. Bear in mind they can be binary files */
506 for (k = t->output.files; k && k->key; k++) {
507 struct stat sta, stb;
508 int fda = -1, fdb = -1;
509 char bufa[4096];
510 char bufb[4096];
511
512 fda = open(k->key, O_RDONLY);
513 if (fda < 0) {
514 ERR("could not open %s\n - %m\n", k->key);
515 goto fail;
516 }
517
518 fdb = open(k->val, O_RDONLY);
519 if (fdb < 0) {
520 ERR("could not open %s\n - %m\n", k->val);
521 goto fail;
522 }
523
524 if (fstat(fda, &sta) != 0) {
525 ERR("could not fstat %d %s\n - %m\n", fda, k->key);
526 goto fail;
527 }
528
529 if (fstat(fdb, &stb) != 0) {
530 ERR("could not fstat %d %s\n - %m\n", fdb, k->key);
531 goto fail;
532 }
533
534 if (sta.st_size != stb.st_size) {
535 ERR("sizes do not match %s %s\n", k->key, k->val);
536 goto fail;
537 }
538
539 for (;;) {
540 int r, done;
541
542 r = safe_read(fda, bufa, sizeof(bufa));
543 if (r < 0)
544 goto fail;
545
546 if (r == 0)
547 /* size is already checked, go to next file */
548 goto next;
549
550 for (done = 0; done < r;) {
551 int r2 = safe_read(fdb, bufb + done, r - done);
552
553 if (r2 <= 0)
554 goto fail;
555
556 done += r2;
557 }
558
559 if (memcmp(bufa, bufb, r) != 0)
560 goto fail;
561 }
562
563next:
564 close(fda);
565 close(fdb);
566 continue;
567
568fail:
569 if (fda >= 0)
570 close(fda);
571 if (fdb >= 0)
572 close(fdb);
573
574 return false;
575 }
576
577 return true;
578}
579
88ac4084
MM
580static int cmp_modnames(const void *m1, const void *m2)
581{
582 const char *s1 = *(char *const *)m1;
583 const char *s2 = *(char *const *)m2;
584 int i;
585
586 for (i = 0; s1[i] || s2[i]; i++) {
587 char c1 = s1[i], c2 = s2[i];
588 if (c1 == '-')
589 c1 = '_';
590 if (c2 == '-')
591 c2 = '_';
592 if (c1 != c2)
593 return c1 - c2;
594 }
595 return 0;
596}
597
598/*
599 * Store the expected module names in buf and return a list of pointers to
600 * them.
601 */
602static const char **read_expected_modules(const struct test *t,
603 char **buf, int *count)
604{
605 const char **res;
606 int len;
607 int i;
608 char *p;
609
610 if (t->modules_loaded[0] == '\0') {
611 *count = 0;
612 *buf = NULL;
613 return NULL;
614 }
615 *buf = strdup(t->modules_loaded);
616 if (!*buf) {
617 *count = -1;
618 return NULL;
619 }
620 len = 1;
621 for (p = *buf; *p; p++)
622 if (*p == ',')
623 len++;
624 res = malloc(sizeof(char *) * len);
625 if (!res) {
626 perror("malloc");
627 *count = -1;
628 free(*buf);
629 *buf = NULL;
630 return NULL;
631 }
632 i = 0;
633 res[i++] = *buf;
634 for (p = *buf; i < len; p++)
635 if (*p == ',') {
636 *p = '\0';
637 res[i++] = p + 1;
638 }
639 *count = len;
640 return res;
641}
642
643static char **read_loaded_modules(const struct test *t, char **buf, int *count)
644{
645 char dirname[PATH_MAX];
646 DIR *dir;
647 struct dirent *dirent;
648 int i;
649 int len = 0, bufsz;
650 char **res = NULL;
651 char *p;
652 const char *rootfs = t->config[TC_ROOTFS] ? t->config[TC_ROOTFS] : "";
653
654 /* Store the entries in /sys/module to res */
655 if (snprintf(dirname, sizeof(dirname), "%s/sys/module", rootfs)
656 >= (int)sizeof(dirname)) {
657 ERR("rootfs path too long: %s\n", rootfs);
658 *buf = NULL;
659 len = -1;
660 goto out;
661 }
662 dir = opendir(dirname);
663 /* not an error, simply return empty list */
664 if (!dir) {
665 *buf = NULL;
666 goto out;
667 }
668 bufsz = 0;
669 while ((dirent = readdir(dir))) {
670 if (dirent->d_name[0] == '.')
671 continue;
672 len++;
673 bufsz += strlen(dirent->d_name) + 1;
674 }
675 res = malloc(sizeof(char *) * len);
676 if (!res) {
677 perror("malloc");
678 len = -1;
679 goto out_dir;
680 }
681 *buf = malloc(bufsz);
682 if (!*buf) {
683 perror("malloc");
684 free(res);
685 res = NULL;
686 len = -1;
687 goto out_dir;
688 }
689 rewinddir(dir);
690 i = 0;
691 p = *buf;
692 while ((dirent = readdir(dir))) {
693 int size;
694
695 if (dirent->d_name[0] == '.')
696 continue;
697 size = strlen(dirent->d_name) + 1;
698 memcpy(p, dirent->d_name, size);
699 res[i++] = p;
700 p += size;
701 }
702out_dir:
703 closedir(dir);
704out:
705 *count = len;
706 return res;
707}
708
709static int check_loaded_modules(const struct test *t)
710{
711 int l1, l2, i1, i2;
712 const char **a1;
713 char **a2;
714 char *buf1, *buf2;
715 int err = false;
716
717 a1 = read_expected_modules(t, &buf1, &l1);
718 if (l1 < 0)
719 return err;
720 a2 = read_loaded_modules(t, &buf2, &l2);
721 if (l2 < 0)
722 goto out_a1;
723 qsort(a1, l1, sizeof(char *), cmp_modnames);
724 qsort(a2, l2, sizeof(char *), cmp_modnames);
725 i1 = i2 = 0;
726 err = true;
727 while (i1 < l1 || i2 < l2) {
728 int cmp;
729
730 if (i1 >= l1)
731 cmp = 1;
732 else if (i2 >= l2)
733 cmp = -1;
734 else
735 cmp = cmp_modnames(&a1[i1], &a2[i2]);
736 if (cmp == 0) {
737 i1++;
738 i2++;
739 } else if (cmp < 0) {
740 err = false;
741 ERR("module %s not loaded\n", a1[i1]);
742 i1++;
743 } else {
744 err = false;
745 ERR("module %s is loaded but should not be \n", a2[i2]);
746 i2++;
747 }
748 }
749 free(a2);
750 free(buf2);
751out_a1:
752 free(a1);
753 free(buf1);
754 return err;
755}
756
3dbb8dea 757static inline int test_run_parent(const struct test *t, int fdout[2],
b8e344a6 758 int fderr[2], int fdmonitor[2], pid_t child)
45481ee2
LDM
759{
760 pid_t pid;
80f9e023 761 int err;
88ac4084 762 bool matchout, match_modules;
3dbb8dea
LDM
763
764 /* Close write-fds */
bd4e7340 765 if (t->output.out != NULL)
3dbb8dea 766 close(fdout[1]);
bd4e7340 767 if (t->output.err != NULL)
3dbb8dea 768 close(fderr[1]);
ed8e93fd 769 close(fdmonitor[1]);
3dbb8dea 770
ed8e93fd 771 matchout = test_run_parent_check_outputs(t, fdout[0], fderr[0],
b8e344a6 772 fdmonitor[0], child);
3dbb8dea
LDM
773
774 /*
775 * break pipe on the other end: either child already closed or we want
776 * to stop it
777 */
bd4e7340 778 if (t->output.out != NULL)
3dbb8dea 779 close(fdout[0]);
bd4e7340 780 if (t->output.err != NULL)
3dbb8dea 781 close(fderr[0]);
ed8e93fd 782 close(fdmonitor[0]);
45481ee2
LDM
783
784 do {
785 pid = wait(&err);
786 if (pid == -1) {
787 ERR("error waitpid(): %m\n");
f988e25c
LDM
788 err = EXIT_FAILURE;
789 goto exit;
45481ee2
LDM
790 }
791 } while (!WIFEXITED(err) && !WIFSIGNALED(err));
792
3dbb8dea
LDM
793 if (WIFEXITED(err)) {
794 if (WEXITSTATUS(err) != 0)
795 ERR("'%s' [%u] exited with return code %d\n",
796 t->name, pid, WEXITSTATUS(err));
797 else
798 LOG("'%s' [%u] exited with return code %d\n",
799 t->name, pid, WEXITSTATUS(err));
800 } else if (WIFSIGNALED(err)) {
801 ERR("'%s' [%u] terminated by signal %d (%s)\n", t->name, pid,
802 WTERMSIG(err), strsignal(WTERMSIG(err)));
f988e25c
LDM
803 err = t->expected_fail ? EXIT_SUCCESS : EXIT_FAILURE;
804 goto exit;
3dbb8dea
LDM
805 }
806
3e451bfe
LDM
807 if (matchout)
808 matchout = check_generated_files(t);
88ac4084
MM
809 if (t->modules_loaded)
810 match_modules = check_loaded_modules(t);
811 else
812 match_modules = true;
3e451bfe 813
fa0046ba
DR
814 if (t->expected_fail == false) {
815 if (err == 0) {
88ac4084 816 if (matchout && match_modules)
fa0046ba
DR
817 LOG("%sPASSED%s: %s\n",
818 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
819 t->name);
820 else {
88ac4084 821 ERR("%sFAILED%s: exit ok but %s do not match: %s\n",
fa0046ba 822 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
88ac4084 823 matchout ? "loaded modules" : "outputs",
fa0046ba
DR
824 t->name);
825 err = EXIT_FAILURE;
826 }
f429113a 827 } else {
fa0046ba
DR
828 ERR("%sFAILED%s: %s\n",
829 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
830 t->name);
f429113a 831 }
fa0046ba
DR
832 } else {
833 if (err == 0) {
834 if (matchout) {
d7293a16 835 ERR("%sUNEXPECTED PASS%s: exit with 0: %s\n",
658e0471 836 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
fa0046ba
DR
837 t->name);
838 err = EXIT_FAILURE;
d7293a16
LDM
839 } else {
840 ERR("%sUNEXPECTED PASS%s: exit with 0 and outputs do not match: %s\n",
841 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
fa0046ba 842 t->name);
d7293a16
LDM
843 err = EXIT_FAILURE;
844 }
fa0046ba 845 } else {
d7293a16
LDM
846 if (matchout) {
847 LOG("%sEXPECTED FAIL%s: %s\n",
fa0046ba
DR
848 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
849 t->name);
d7293a16
LDM
850 err = EXIT_SUCCESS;
851 } else {
852 LOG("%sEXPECTED FAIL%s: exit with %d but outputs do not match: %s\n",
853 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
854 WEXITSTATUS(err), t->name);
855 err = EXIT_FAILURE;
856 }
3dbb8dea 857 }
fa0046ba 858 }
45481ee2 859
f988e25c
LDM
860exit:
861 LOG("------\n");
45481ee2
LDM
862 return err;
863}
864
f31d49c8
DR
865static int prepend_path(const char *extra)
866{
867 char *oldpath, *newpath;
868 int r;
869
870 if (extra == NULL)
871 return 0;
872
873 oldpath = getenv("PATH");
874 if (oldpath == NULL)
875 return setenv("PATH", extra, 1);
876
877 if (asprintf(&newpath, "%s:%s", extra, oldpath) < 0) {
050db08c 878 ERR("failed to allocate memory to new PATH\n");
f31d49c8
DR
879 return -1;
880 }
881
882 r = setenv("PATH", newpath, 1);
883 free(newpath);
884
885 return r;
886}
887
45481ee2
LDM
888int test_run(const struct test *t)
889{
80f9e023 890 pid_t pid;
3dbb8dea
LDM
891 int fdout[2];
892 int fderr[2];
ed8e93fd 893 int fdmonitor[2];
80f9e023 894
ed2df4e9
LDM
895 if (t->need_spawn && oneshot)
896 test_run_spawned(t);
897
bd4e7340 898 if (t->output.out != NULL) {
3dbb8dea
LDM
899 if (pipe(fdout) != 0) {
900 ERR("could not create out pipe for %s\n", t->name);
901 return EXIT_FAILURE;
902 }
903 }
904
bd4e7340 905 if (t->output.err != NULL) {
3dbb8dea
LDM
906 if (pipe(fderr) != 0) {
907 ERR("could not create err pipe for %s\n", t->name);
908 return EXIT_FAILURE;
909 }
910 }
911
ed8e93fd
LDM
912 if (pipe(fdmonitor) != 0) {
913 ERR("could not create monitor pipe for %s\n", t->name);
914 return EXIT_FAILURE;
915 }
916
f31d49c8
DR
917 if (prepend_path(t->path) < 0) {
918 ERR("failed to prepend '%s' to PATH\n", t->path);
919 return EXIT_FAILURE;
920 }
921
80f9e023
LDM
922 LOG("running %s, in forked context\n", t->name);
923
924 pid = fork();
925 if (pid < 0) {
926 ERR("could not fork(): %m\n");
927 LOG("FAILED: %s\n", t->name);
928 return EXIT_FAILURE;
929 }
930
45481ee2 931 if (pid > 0)
b8e344a6 932 return test_run_parent(t, fdout, fderr, fdmonitor, pid);
80f9e023 933
ed8e93fd 934 return test_run_child(t, fdout, fderr, fdmonitor);
80f9e023 935}