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 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 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 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 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 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 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 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 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 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 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 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 316 static bool fd_cmp_is_active(struct fd_cmp *fd_cmp) 317 { 318 return fd_cmp->fd != -1; 319 } 320 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 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 */ 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 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 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 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 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 */ 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 */ 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 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 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 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 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 */ 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 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 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 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 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 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