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