]> git.ipfire.org Git - thirdparty/kmod.git/blame - testsuite/testsuite.c
testsuite: move --show-exports test to use regex
[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>
c0937526 23#include <regex.h>
80f9e023 24#include <stdarg.h>
c2e4286b 25#include <stdio.h>
80f9e023
LDM
26#include <stdlib.h>
27#include <string.h>
b8e344a6 28#include <time.h>
80f9e023 29#include <unistd.h>
3dbb8dea 30#include <sys/epoll.h>
80f9e023 31#include <sys/prctl.h>
0de690c9 32#include <sys/stat.h>
80f9e023
LDM
33#include <sys/wait.h>
34
96573a02
LDM
35#include <shared/util.h>
36
80f9e023
LDM
37#include "testsuite.h"
38
51b1d1ab
LDM
39static const char *ANSI_HIGHLIGHT_GREEN_ON = "\x1B[1;32m";
40static const char *ANSI_HIGHLIGHT_RED_ON = "\x1B[1;31m";
41static const char *ANSI_HIGHLIGHT_OFF = "\x1B[0m";
42
80f9e023 43static const char *progname;
ed2df4e9 44static int oneshot = 0;
80f9e023
LDM
45static const char options_short[] = "lhn";
46static const struct option options[] = {
47 { "list", no_argument, 0, 'l' },
48 { "help", no_argument, 0, 'h' },
49 { NULL, 0, 0, 0 }
50};
51
d2c2b8b5
LDM
52#define OVERRIDE_LIBDIR ABS_TOP_BUILDDIR "/testsuite/.libs/"
53
395478cb
LDM
54struct _env_config {
55 const char *key;
56 const char *ldpreload;
57} env_config[_TC_LAST] = {
d2c2b8b5
LDM
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" },
f6ef5d6b 61 [TC_DELETE_MODULE_RETCODES] = { S_TC_DELETE_MODULE_RETCODES, OVERRIDE_LIBDIR "delete_module.so" },
395478cb
LDM
62};
63
b8e344a6
LDM
64#define USEC_PER_SEC 1000000ULL
65#define USEC_PER_MSEC 1000ULL
66#define TEST_TIMEOUT_USEC 2 * USEC_PER_SEC
67static 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
80f9e023
LDM
77static 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
c5798fea 91static void test_list(const struct test *start, const struct test *stop)
80f9e023 92{
c5798fea 93 const struct test *t;
80f9e023
LDM
94
95 printf("Available tests:\n");
c5798fea
LDM
96 for (t = start; t < stop; t++)
97 printf("\t%s, %s\n", t->name, t->description);
80f9e023
LDM
98}
99
c5798fea
LDM
100int test_init(const struct test *start, const struct test *stop,
101 int argc, char *const argv[])
80f9e023
LDM
102{
103 progname = argv[0];
104
105 for (;;) {
106 int c, idx = 0;
107 c = getopt_long(argc, argv, options_short, options, &idx);
108 if (c == -1)
109 break;
110 switch (c) {
111 case 'l':
c5798fea 112 test_list(start, stop);
80f9e023
LDM
113 return 0;
114 case 'h':
115 help();
116 return 0;
117 case 'n':
118 oneshot = 1;
119 break;
120 case '?':
121 return -1;
122 default:
123 ERR("unexpected getopt_long() value %c\n", c);
124 return -1;
125 }
126 }
127
51b1d1ab
LDM
128 if (isatty(STDOUT_FILENO) == 0) {
129 ANSI_HIGHLIGHT_OFF = "";
130 ANSI_HIGHLIGHT_RED_ON = "";
131 ANSI_HIGHLIGHT_GREEN_ON = "";
132 }
133
80f9e023
LDM
134 return optind;
135}
136
c5798fea
LDM
137const struct test *test_find(const struct test *start,
138 const struct test *stop, const char *name)
80f9e023 139{
c5798fea 140 const struct test *t;
80f9e023 141
c5798fea 142 for (t = start; t < stop; t++) {
5c42c5fc 143 if (streq(t->name, name))
c5798fea 144 return t;
80f9e023
LDM
145 }
146
147 return NULL;
148}
149
ed2df4e9 150static int test_spawn_test(const struct test *t)
80f9e023
LDM
151{
152 const char *const args[] = { progname, "-n", t->name, NULL };
153
154 execv(progname, (char *const *) args);
155
156 ERR("failed to spawn %s for %s: %m\n", progname, t->name);
157 return EXIT_FAILURE;
158}
159
ed2df4e9
LDM
160static int test_run_spawned(const struct test *t)
161{
162 int err = t->func(t);
163 exit(err);
164
165 return EXIT_FAILURE;
166}
167
9e3b9d2e 168int test_spawn_prog(const char *prog, const char *const args[])
80f9e023
LDM
169{
170 execv(prog, (char *const *) args);
171
9e3b9d2e
LDM
172 ERR("failed to spawn %s\n", prog);
173 ERR("did you forget to build tools?\n");
80f9e023
LDM
174 return EXIT_FAILURE;
175}
176
395478cb 177static void test_export_environ(const struct test *t)
80f9e023 178{
395478cb
LDM
179 char *preload = NULL;
180 size_t preloadlen = 0;
181 size_t i;
34db3f2d 182 const struct keyval *env;
395478cb
LDM
183
184 unsetenv("LD_PRELOAD");
185
186 for (i = 0; i < _TC_LAST; i++) {
187 const char *ldpreload;
188 size_t ldpreloadlen;
189 char *tmp;
190
191 if (t->config[i] == NULL)
192 continue;
193
194 setenv(env_config[i].key, t->config[i], 1);
195
196 ldpreload = env_config[i].ldpreload;
197 ldpreloadlen = strlen(ldpreload);
198 tmp = realloc(preload, preloadlen + 2 + ldpreloadlen);
199 if (tmp == NULL) {
200 ERR("oom: test_export_environ()\n");
201 return;
202 }
203 preload = tmp;
204
205 if (preloadlen > 0)
206 preload[preloadlen++] = ' ';
207 memcpy(preload + preloadlen, ldpreload, ldpreloadlen);
208 preloadlen += ldpreloadlen;
209 preload[preloadlen] = '\0';
210 }
211
212 if (preload != NULL)
213 setenv("LD_PRELOAD", preload, 1);
214
215 free(preload);
34db3f2d
LDM
216
217 for (env = t->env_vars; env && env->key; env++)
218 setenv(env->key, env->val, 1);
80f9e023
LDM
219}
220
3dbb8dea 221static inline int test_run_child(const struct test *t, int fdout[2],
ed8e93fd 222 int fderr[2], int fdmonitor[2])
80f9e023 223{
45481ee2
LDM
224 /* kill child if parent dies */
225 prctl(PR_SET_PDEATHSIG, SIGTERM);
226
227 test_export_environ(t);
228
3dbb8dea 229 /* Close read-fds and redirect std{out,err} to the write-fds */
bd4e7340 230 if (t->output.out != NULL) {
3dbb8dea
LDM
231 close(fdout[0]);
232 if (dup2(fdout[1], STDOUT_FILENO) < 0) {
050db08c 233 ERR("could not redirect stdout to pipe: %m\n");
3dbb8dea
LDM
234 exit(EXIT_FAILURE);
235 }
236 }
237
bd4e7340 238 if (t->output.err != NULL) {
3dbb8dea
LDM
239 close(fderr[0]);
240 if (dup2(fderr[1], STDERR_FILENO) < 0) {
bd4e7340 241 ERR("could not redirect stderr to pipe: %m\n");
3dbb8dea
LDM
242 exit(EXIT_FAILURE);
243 }
244 }
245
ed8e93fd
LDM
246 close(fdmonitor[0]);
247
0de690c9
LDM
248 if (t->config[TC_ROOTFS] != NULL) {
249 const char *stamp = TESTSUITE_ROOTFS "../stamp-rootfs";
250 const char *rootfs = t->config[TC_ROOTFS];
251 struct stat rootfsst, stampst;
252
253 if (stat(stamp, &stampst) != 0) {
254 ERR("could not stat %s\n - %m", stamp);
255 exit(EXIT_FAILURE);
256 }
257
258 if (stat(rootfs, &rootfsst) != 0) {
259 ERR("could not stat %s\n - %m", rootfs);
260 exit(EXIT_FAILURE);
261 }
262
263 if (stat_mstamp(&rootfsst) > stat_mstamp(&stampst)) {
264 ERR("rootfs %s is dirty, please run 'make rootfs' before runnning this test\n",
265 rootfs);
266 exit(EXIT_FAILURE);
267 }
268 }
269
45481ee2
LDM
270 if (t->need_spawn)
271 return test_spawn_test(t);
272 else
273 return test_run_spawned(t);
274}
275
03a5079f
LDM
276static int check_activity(int fd, bool activity, const char *path,
277 const char *stream)
278{
279 struct stat st;
280
281 /* not monitoring or monitoring and it has activity */
282 if (fd < 0 || activity)
283 return 0;
284
285 /* monitoring, there was no activity and size matches */
286 if (stat(path, &st) == 0 && st.st_size == 0)
287 return 0;
288
289 ERR("Expecting output on %s, but test didn't produce any\n", stream);
290
291 return -1;
292}
293
a5cc3521
LDM
294#define BUFSZ 4096
295struct buffer {
296 char buf[BUFSZ];
c0937526 297 unsigned int head;
a5cc3521
LDM
298};
299
c0937526
LDM
300
301static bool cmpbuf_regex_one(const char *pattern, const char *s)
302{
303 _cleanup_(regfree) regex_t re = { };
304
305 return !regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) &&
306 !regexec(&re, s, 0, NULL, 0);
307}
308
309/*
310 * read fd and fd_match, checking the first matches the regex of the second,
311 * line by line
312 */
313static bool cmpbuf_regex(const struct test *t, const char *prefix,
314 int fd, int fd_match, struct buffer *buf,
315 struct buffer *buf_match)
316{
317 char *p, *p_match;
318 int done = 0, done_match = 0, r;
319
320 if (buf->head >= sizeof(buf->buf)) {
321 ERR("Read %zu bytes without a newline\n", sizeof(buf->buf));
322 ERR("output: %.*s", (int)sizeof(buf->buf), buf->buf);
323 return false;
324 }
325
326 r = read(fd, buf->buf + buf->head, sizeof(buf->buf) - buf->head);
327 if (r <= 0)
328 return true;
329
330 buf->head += r;
331
332 /*
333 * Process as many lines as read from fd and that fits in the buffer -
334 * it's assumed that if we get N lines from fd, we should be able to
335 * get the same amount from fd_match
336 */
337 for (;;) {
338 p = memchr(buf->buf + done, '\n', buf->head - done);
339 if (!p)
340 break;
341 *p = '\0';
342
343 p_match = memchr(buf_match->buf + done_match, '\n',
344 buf_match->head - done_match);
345 if (!p_match) {
346 if (buf_match->head >= sizeof(buf_match->buf)) {
347 ERR("Read %zu bytes without a match\n", sizeof(buf_match->buf));
348 ERR("output: %.*s", (int)sizeof(buf_match->buf), buf_match->buf);
349 return false;
350 }
351
352 /* pump more data from file */
353 r = read(fd_match, buf_match->buf + buf_match->head,
354 sizeof(buf_match->buf) - buf_match->head);
355 if (r <= 0) {
356 ERR("could not read match fd %d\n", fd_match);
357 return false;
358 }
359 buf_match->head += r;
360 p_match = memchr(buf_match->buf + done_match, '\n',
361 buf_match->head - done_match);
362 if (!p_match) {
363 ERR("could not find match line from fd %d\n", fd_match);
364 return false;
365 }
366 }
367 *p_match = '\0';
368
369 if (!cmpbuf_regex_one(buf_match->buf + done_match, buf->buf + done)) {
370 ERR("Output does not match pattern on %s:\n", prefix);
371 ERR("pattern: %s\n", buf_match->buf + done_match);
372 ERR("output : %s\n", buf->buf + done);
373 return false;
374 }
375
376 done = p - buf->buf + 1;
377 done_match = p_match - buf_match->buf + 1;
378 }
379
380 /*
381 * Prepare for the next call: anything we processed we remove from the
382 * buffer by memmoving the remaining bytes up to the beginning
383 */
384 if (done) {
385 if (buf->head - done)
386 memmove(buf->buf, buf->buf + done, buf->head - done);
387 buf->head -= done;
388 }
389
390 if (done_match) {
391 if (buf_match->head - done_match)
392 memmove(buf_match->buf, buf_match->buf + done_match,
393 buf_match->head - done_match);
394 buf_match->head -= done_match;
395 }
396
397 return true;
398}
399
a5cc3521
LDM
400/* read fd and fd_match, checking they match exactly */
401static bool cmpbuf_exact(const struct test *t, const char *prefix,
402 int fd, int fd_match, struct buffer *buf,
403 struct buffer *buf_match)
404{
405 int r, rmatch, done = 0;
406
407 r = read(fd, buf->buf, sizeof(buf->buf) - 1);
408 if (r <= 0)
409 /* try again later */
410 return true;
411
412 /* read as much data from fd_match as we read from fd */
413 for (;;) {
414 rmatch = read(fd_match, buf_match->buf + done, r - done);
415 if (rmatch == 0)
416 break;
417
418 if (rmatch < 0) {
419 if (errno == EINTR)
420 continue;
421 ERR("could not read match fd %d\n", fd_match);
422 return false;
423 }
424
425 done += rmatch;
426 }
427
428 buf->buf[r] = '\0';
429 buf_match->buf[r] = '\0';
430
431 if (t->print_outputs)
432 printf("%s: %s\n", prefix, buf->buf);
433
434 if (!streq(buf->buf, buf_match->buf)) {
435 ERR("Outputs do not match on %s:\n", prefix);
436 ERR("correct:\n%s\n", buf_match->buf);
437 ERR("wrong:\n%s\n", buf->buf);
438 return false;
439 }
440
441 return true;
442}
443
444static bool test_run_parent_check_outputs(const struct test *t,
445 int fdout, int fderr, int fdmonitor,
446 pid_t child)
3dbb8dea 447{
ed8e93fd 448 struct epoll_event ep_outpipe, ep_errpipe, ep_monitor;
3dbb8dea 449 int err, fd_ep, fd_matchout = -1, fd_matcherr = -1;
03a5079f 450 bool fd_activityout = false, fd_activityerr = false;
b8e344a6 451 unsigned long long end_usec, start_usec;
a5cc3521 452 _cleanup_free_ struct buffer *buf_out = NULL, *buf_err = NULL;
3dbb8dea 453
3dbb8dea
LDM
454 fd_ep = epoll_create1(EPOLL_CLOEXEC);
455 if (fd_ep < 0) {
456 ERR("could not create epoll fd: %m\n");
457 return false;
458 }
459
bd4e7340
JS
460 if (t->output.out != NULL) {
461 fd_matchout = open(t->output.out, O_RDONLY);
3dbb8dea
LDM
462 if (fd_matchout < 0) {
463 err = -errno;
464 ERR("could not open %s for read: %m\n",
bd4e7340 465 t->output.out);
3dbb8dea
LDM
466 goto out;
467 }
468 memset(&ep_outpipe, 0, sizeof(struct epoll_event));
469 ep_outpipe.events = EPOLLIN;
470 ep_outpipe.data.ptr = &fdout;
471 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fdout, &ep_outpipe) < 0) {
472 err = -errno;
473 ERR("could not add fd to epoll: %m\n");
474 goto out;
475 }
a5cc3521 476 buf_out = calloc(2, sizeof(*buf_out));
3dbb8dea
LDM
477 } else
478 fdout = -1;
479
bd4e7340
JS
480 if (t->output.err != NULL) {
481 fd_matcherr = open(t->output.err, O_RDONLY);
3dbb8dea
LDM
482 if (fd_matcherr < 0) {
483 err = -errno;
484 ERR("could not open %s for read: %m\n",
bd4e7340 485 t->output.err);
3dbb8dea
LDM
486 goto out;
487
488 }
489 memset(&ep_errpipe, 0, sizeof(struct epoll_event));
490 ep_errpipe.events = EPOLLIN;
491 ep_errpipe.data.ptr = &fderr;
492 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fderr, &ep_errpipe) < 0) {
493 err = -errno;
494 ERR("could not add fd to epoll: %m\n");
495 goto out;
496 }
a5cc3521 497 buf_err = calloc(2, sizeof(*buf_err));
3dbb8dea
LDM
498 } else
499 fderr = -1;
500
ed8e93fd
LDM
501 memset(&ep_monitor, 0, sizeof(struct epoll_event));
502 ep_monitor.events = EPOLLHUP;
503 ep_monitor.data.ptr = &fdmonitor;
504 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fdmonitor, &ep_monitor) < 0) {
505 err = -errno;
506 ERR("could not add monitor fd to epoll: %m\n");
507 goto out;
508 }
509
b8e344a6
LDM
510 start_usec = now_usec();
511 end_usec = start_usec + TEST_TIMEOUT_USEC;
512
ed8e93fd 513 for (err = 0; fdmonitor >= 0 || fdout >= 0 || fderr >= 0;) {
b8e344a6 514 int fdcount, i, timeout;
3dbb8dea 515 struct epoll_event ev[4];
b8e344a6 516 unsigned long long curr_usec = now_usec();
3dbb8dea 517
b8e344a6
LDM
518 if (curr_usec > end_usec)
519 break;
520
521 timeout = (end_usec - curr_usec) / USEC_PER_MSEC;
522 fdcount = epoll_wait(fd_ep, ev, 4, timeout);
3dbb8dea
LDM
523 if (fdcount < 0) {
524 if (errno == EINTR)
525 continue;
526 err = -errno;
527 ERR("could not poll: %m\n");
528 goto out;
529 }
530
531 for (i = 0; i < fdcount; i++) {
a5cc3521 532 int fd = *(int *)ev[i].data.ptr;
c0937526 533 bool ret;
3dbb8dea
LDM
534
535 if (ev[i].events & EPOLLIN) {
3dbb8dea 536 int fd_match;
a5cc3521
LDM
537 struct buffer *buf, *buf_match;
538 const char *prefix;
3dbb8dea 539
a5cc3521 540 if (fd == fdout) {
3dbb8dea 541 fd_match = fd_matchout;
a5cc3521 542 buf = buf_out;
03a5079f 543 fd_activityout = true;
a5cc3521
LDM
544 prefix = "STDOUT";
545 } else if (fd == fderr) {
3dbb8dea 546 fd_match = fd_matcherr;
a5cc3521 547 buf = buf_err;
03a5079f 548 fd_activityerr = true;
a5cc3521 549 prefix = "STDERR";
03a5079f 550 } else {
ed8e93fd
LDM
551 ERR("Unexpected activity on monitor pipe\n");
552 err = -EINVAL;
553 goto out;
554 }
3dbb8dea 555
a5cc3521 556 buf_match = buf + 1;
f6dc239e 557
c0937526
LDM
558 if (t->output.regex)
559 ret = cmpbuf_regex(t, prefix, fd, fd_match,
560 buf, buf_match);
561 else
562 ret = cmpbuf_exact(t, prefix, fd, fd_match,
563 buf, buf_match);
564
565 if (!ret) {
566 err = -1;
3dbb8dea 567 goto out;
c0937526 568 }
3dbb8dea 569 } else if (ev[i].events & EPOLLHUP) {
a5cc3521
LDM
570 if (epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd, NULL) < 0) {
571 ERR("could not remove fd %d from epoll: %m\n", fd);
3dbb8dea 572 }
a5cc3521 573 *(int *)ev[i].data.ptr = -1;
3dbb8dea
LDM
574 }
575 }
b8e344a6 576 }
3dbb8dea 577
03a5079f
LDM
578 err = check_activity(fd_matchout, fd_activityout, t->output.out, "stdout");
579 err |= check_activity(fd_matcherr, fd_activityerr, t->output.err, "stderr");
580
b8e344a6
LDM
581 if (err == 0 && fdmonitor >= 0) {
582 err = -EINVAL;
583 ERR("Test '%s' timed out, killing %d\n", t->name, child);
584 kill(child, SIGKILL);
3dbb8dea 585 }
b8e344a6 586
3dbb8dea
LDM
587out:
588 if (fd_matchout >= 0)
589 close(fd_matchout);
590 if (fd_matcherr >= 0)
591 close(fd_matcherr);
592 if (fd_ep >= 0)
593 close(fd_ep);
594 return err == 0;
595}
596
3e451bfe
LDM
597static inline int safe_read(int fd, void *buf, size_t count)
598{
599 int r;
600
601 while (1) {
602 r = read(fd, buf, count);
2ad09ccf 603 if (r == -1 && errno == EINTR)
3e451bfe
LDM
604 continue;
605 break;
606 }
607
608 return r;
609}
610
611static bool check_generated_files(const struct test *t)
612{
613 const struct keyval *k;
614
615 /* This is not meant to be a diff replacement, just stupidly check if
616 * the files match. Bear in mind they can be binary files */
617 for (k = t->output.files; k && k->key; k++) {
618 struct stat sta, stb;
619 int fda = -1, fdb = -1;
620 char bufa[4096];
621 char bufb[4096];
622
623 fda = open(k->key, O_RDONLY);
624 if (fda < 0) {
625 ERR("could not open %s\n - %m\n", k->key);
626 goto fail;
627 }
628
629 fdb = open(k->val, O_RDONLY);
630 if (fdb < 0) {
631 ERR("could not open %s\n - %m\n", k->val);
632 goto fail;
633 }
634
635 if (fstat(fda, &sta) != 0) {
636 ERR("could not fstat %d %s\n - %m\n", fda, k->key);
637 goto fail;
638 }
639
640 if (fstat(fdb, &stb) != 0) {
641 ERR("could not fstat %d %s\n - %m\n", fdb, k->key);
642 goto fail;
643 }
644
645 if (sta.st_size != stb.st_size) {
646 ERR("sizes do not match %s %s\n", k->key, k->val);
647 goto fail;
648 }
649
650 for (;;) {
651 int r, done;
652
653 r = safe_read(fda, bufa, sizeof(bufa));
654 if (r < 0)
655 goto fail;
656
657 if (r == 0)
658 /* size is already checked, go to next file */
659 goto next;
660
661 for (done = 0; done < r;) {
662 int r2 = safe_read(fdb, bufb + done, r - done);
663
664 if (r2 <= 0)
665 goto fail;
666
667 done += r2;
668 }
669
670 if (memcmp(bufa, bufb, r) != 0)
671 goto fail;
672 }
673
674next:
675 close(fda);
676 close(fdb);
677 continue;
678
679fail:
680 if (fda >= 0)
681 close(fda);
682 if (fdb >= 0)
683 close(fdb);
684
685 return false;
686 }
687
688 return true;
689}
690
88ac4084
MM
691static int cmp_modnames(const void *m1, const void *m2)
692{
693 const char *s1 = *(char *const *)m1;
694 const char *s2 = *(char *const *)m2;
695 int i;
696
697 for (i = 0; s1[i] || s2[i]; i++) {
698 char c1 = s1[i], c2 = s2[i];
699 if (c1 == '-')
700 c1 = '_';
701 if (c2 == '-')
702 c2 = '_';
703 if (c1 != c2)
704 return c1 - c2;
705 }
706 return 0;
707}
708
709/*
710 * Store the expected module names in buf and return a list of pointers to
711 * them.
712 */
713static const char **read_expected_modules(const struct test *t,
714 char **buf, int *count)
715{
716 const char **res;
717 int len;
718 int i;
719 char *p;
720
721 if (t->modules_loaded[0] == '\0') {
722 *count = 0;
723 *buf = NULL;
724 return NULL;
725 }
726 *buf = strdup(t->modules_loaded);
727 if (!*buf) {
728 *count = -1;
729 return NULL;
730 }
731 len = 1;
732 for (p = *buf; *p; p++)
733 if (*p == ',')
734 len++;
735 res = malloc(sizeof(char *) * len);
736 if (!res) {
737 perror("malloc");
738 *count = -1;
739 free(*buf);
740 *buf = NULL;
741 return NULL;
742 }
743 i = 0;
744 res[i++] = *buf;
745 for (p = *buf; i < len; p++)
746 if (*p == ',') {
747 *p = '\0';
748 res[i++] = p + 1;
749 }
750 *count = len;
751 return res;
752}
753
754static char **read_loaded_modules(const struct test *t, char **buf, int *count)
755{
756 char dirname[PATH_MAX];
757 DIR *dir;
758 struct dirent *dirent;
759 int i;
760 int len = 0, bufsz;
761 char **res = NULL;
762 char *p;
763 const char *rootfs = t->config[TC_ROOTFS] ? t->config[TC_ROOTFS] : "";
764
765 /* Store the entries in /sys/module to res */
766 if (snprintf(dirname, sizeof(dirname), "%s/sys/module", rootfs)
767 >= (int)sizeof(dirname)) {
768 ERR("rootfs path too long: %s\n", rootfs);
769 *buf = NULL;
770 len = -1;
771 goto out;
772 }
773 dir = opendir(dirname);
774 /* not an error, simply return empty list */
775 if (!dir) {
776 *buf = NULL;
777 goto out;
778 }
779 bufsz = 0;
780 while ((dirent = readdir(dir))) {
781 if (dirent->d_name[0] == '.')
782 continue;
783 len++;
784 bufsz += strlen(dirent->d_name) + 1;
785 }
786 res = malloc(sizeof(char *) * len);
787 if (!res) {
788 perror("malloc");
789 len = -1;
790 goto out_dir;
791 }
792 *buf = malloc(bufsz);
793 if (!*buf) {
794 perror("malloc");
795 free(res);
796 res = NULL;
797 len = -1;
798 goto out_dir;
799 }
800 rewinddir(dir);
801 i = 0;
802 p = *buf;
803 while ((dirent = readdir(dir))) {
804 int size;
805
806 if (dirent->d_name[0] == '.')
807 continue;
808 size = strlen(dirent->d_name) + 1;
809 memcpy(p, dirent->d_name, size);
810 res[i++] = p;
811 p += size;
812 }
813out_dir:
814 closedir(dir);
815out:
816 *count = len;
817 return res;
818}
819
820static int check_loaded_modules(const struct test *t)
821{
822 int l1, l2, i1, i2;
823 const char **a1;
824 char **a2;
825 char *buf1, *buf2;
826 int err = false;
827
828 a1 = read_expected_modules(t, &buf1, &l1);
829 if (l1 < 0)
830 return err;
831 a2 = read_loaded_modules(t, &buf2, &l2);
832 if (l2 < 0)
833 goto out_a1;
834 qsort(a1, l1, sizeof(char *), cmp_modnames);
835 qsort(a2, l2, sizeof(char *), cmp_modnames);
836 i1 = i2 = 0;
837 err = true;
838 while (i1 < l1 || i2 < l2) {
839 int cmp;
840
841 if (i1 >= l1)
842 cmp = 1;
843 else if (i2 >= l2)
844 cmp = -1;
845 else
846 cmp = cmp_modnames(&a1[i1], &a2[i2]);
847 if (cmp == 0) {
848 i1++;
849 i2++;
850 } else if (cmp < 0) {
851 err = false;
852 ERR("module %s not loaded\n", a1[i1]);
853 i1++;
854 } else {
855 err = false;
856 ERR("module %s is loaded but should not be \n", a2[i2]);
857 i2++;
858 }
859 }
860 free(a2);
861 free(buf2);
862out_a1:
863 free(a1);
864 free(buf1);
865 return err;
866}
867
3dbb8dea 868static inline int test_run_parent(const struct test *t, int fdout[2],
b8e344a6 869 int fderr[2], int fdmonitor[2], pid_t child)
45481ee2
LDM
870{
871 pid_t pid;
80f9e023 872 int err;
88ac4084 873 bool matchout, match_modules;
3dbb8dea
LDM
874
875 /* Close write-fds */
bd4e7340 876 if (t->output.out != NULL)
3dbb8dea 877 close(fdout[1]);
bd4e7340 878 if (t->output.err != NULL)
3dbb8dea 879 close(fderr[1]);
ed8e93fd 880 close(fdmonitor[1]);
3dbb8dea 881
ed8e93fd 882 matchout = test_run_parent_check_outputs(t, fdout[0], fderr[0],
b8e344a6 883 fdmonitor[0], child);
3dbb8dea
LDM
884
885 /*
886 * break pipe on the other end: either child already closed or we want
887 * to stop it
888 */
bd4e7340 889 if (t->output.out != NULL)
3dbb8dea 890 close(fdout[0]);
bd4e7340 891 if (t->output.err != NULL)
3dbb8dea 892 close(fderr[0]);
ed8e93fd 893 close(fdmonitor[0]);
45481ee2
LDM
894
895 do {
896 pid = wait(&err);
897 if (pid == -1) {
898 ERR("error waitpid(): %m\n");
f988e25c
LDM
899 err = EXIT_FAILURE;
900 goto exit;
45481ee2
LDM
901 }
902 } while (!WIFEXITED(err) && !WIFSIGNALED(err));
903
3dbb8dea
LDM
904 if (WIFEXITED(err)) {
905 if (WEXITSTATUS(err) != 0)
906 ERR("'%s' [%u] exited with return code %d\n",
907 t->name, pid, WEXITSTATUS(err));
908 else
909 LOG("'%s' [%u] exited with return code %d\n",
910 t->name, pid, WEXITSTATUS(err));
911 } else if (WIFSIGNALED(err)) {
912 ERR("'%s' [%u] terminated by signal %d (%s)\n", t->name, pid,
913 WTERMSIG(err), strsignal(WTERMSIG(err)));
f988e25c
LDM
914 err = t->expected_fail ? EXIT_SUCCESS : EXIT_FAILURE;
915 goto exit;
3dbb8dea
LDM
916 }
917
3e451bfe
LDM
918 if (matchout)
919 matchout = check_generated_files(t);
88ac4084
MM
920 if (t->modules_loaded)
921 match_modules = check_loaded_modules(t);
922 else
923 match_modules = true;
3e451bfe 924
fa0046ba
DR
925 if (t->expected_fail == false) {
926 if (err == 0) {
88ac4084 927 if (matchout && match_modules)
fa0046ba
DR
928 LOG("%sPASSED%s: %s\n",
929 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
930 t->name);
931 else {
88ac4084 932 ERR("%sFAILED%s: exit ok but %s do not match: %s\n",
fa0046ba 933 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
88ac4084 934 matchout ? "loaded modules" : "outputs",
fa0046ba
DR
935 t->name);
936 err = EXIT_FAILURE;
937 }
f429113a 938 } else {
fa0046ba
DR
939 ERR("%sFAILED%s: %s\n",
940 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
941 t->name);
f429113a 942 }
fa0046ba
DR
943 } else {
944 if (err == 0) {
945 if (matchout) {
d7293a16 946 ERR("%sUNEXPECTED PASS%s: exit with 0: %s\n",
658e0471 947 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
fa0046ba
DR
948 t->name);
949 err = EXIT_FAILURE;
d7293a16
LDM
950 } else {
951 ERR("%sUNEXPECTED PASS%s: exit with 0 and outputs do not match: %s\n",
952 ANSI_HIGHLIGHT_RED_ON, ANSI_HIGHLIGHT_OFF,
fa0046ba 953 t->name);
d7293a16
LDM
954 err = EXIT_FAILURE;
955 }
fa0046ba 956 } else {
d7293a16
LDM
957 if (matchout) {
958 LOG("%sEXPECTED FAIL%s: %s\n",
fa0046ba
DR
959 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
960 t->name);
d7293a16
LDM
961 err = EXIT_SUCCESS;
962 } else {
963 LOG("%sEXPECTED FAIL%s: exit with %d but outputs do not match: %s\n",
964 ANSI_HIGHLIGHT_GREEN_ON, ANSI_HIGHLIGHT_OFF,
965 WEXITSTATUS(err), t->name);
966 err = EXIT_FAILURE;
967 }
3dbb8dea 968 }
fa0046ba 969 }
45481ee2 970
f988e25c
LDM
971exit:
972 LOG("------\n");
45481ee2
LDM
973 return err;
974}
975
f31d49c8
DR
976static int prepend_path(const char *extra)
977{
978 char *oldpath, *newpath;
979 int r;
980
981 if (extra == NULL)
982 return 0;
983
984 oldpath = getenv("PATH");
985 if (oldpath == NULL)
986 return setenv("PATH", extra, 1);
987
988 if (asprintf(&newpath, "%s:%s", extra, oldpath) < 0) {
050db08c 989 ERR("failed to allocate memory to new PATH\n");
f31d49c8
DR
990 return -1;
991 }
992
993 r = setenv("PATH", newpath, 1);
994 free(newpath);
995
996 return r;
997}
998
45481ee2
LDM
999int test_run(const struct test *t)
1000{
80f9e023 1001 pid_t pid;
3dbb8dea
LDM
1002 int fdout[2];
1003 int fderr[2];
ed8e93fd 1004 int fdmonitor[2];
80f9e023 1005
ed2df4e9
LDM
1006 if (t->need_spawn && oneshot)
1007 test_run_spawned(t);
1008
bd4e7340 1009 if (t->output.out != NULL) {
3dbb8dea
LDM
1010 if (pipe(fdout) != 0) {
1011 ERR("could not create out pipe for %s\n", t->name);
1012 return EXIT_FAILURE;
1013 }
1014 }
1015
bd4e7340 1016 if (t->output.err != NULL) {
3dbb8dea
LDM
1017 if (pipe(fderr) != 0) {
1018 ERR("could not create err pipe for %s\n", t->name);
1019 return EXIT_FAILURE;
1020 }
1021 }
1022
ed8e93fd
LDM
1023 if (pipe(fdmonitor) != 0) {
1024 ERR("could not create monitor pipe for %s\n", t->name);
1025 return EXIT_FAILURE;
1026 }
1027
f31d49c8
DR
1028 if (prepend_path(t->path) < 0) {
1029 ERR("failed to prepend '%s' to PATH\n", t->path);
1030 return EXIT_FAILURE;
1031 }
1032
80f9e023
LDM
1033 LOG("running %s, in forked context\n", t->name);
1034
1035 pid = fork();
1036 if (pid < 0) {
1037 ERR("could not fork(): %m\n");
1038 LOG("FAILED: %s\n", t->name);
1039 return EXIT_FAILURE;
1040 }
1041
45481ee2 1042 if (pid > 0)
b8e344a6 1043 return test_run_parent(t, fdout, fderr, fdmonitor, pid);
80f9e023 1044
ed8e93fd 1045 return test_run_child(t, fdout, fderr, fdmonitor);
80f9e023 1046}