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