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