1 /* 2 * Copyright (c) 2015-2016 Cyril Hrubis <chrubis (at) suse.cz> 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (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 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include <stdio.h> 19 #include <stdarg.h> 20 #include <unistd.h> 21 #include <string.h> 22 #include <stdlib.h> 23 #include <errno.h> 24 #include <sys/mount.h> 25 #include <sys/types.h> 26 #include <sys/wait.h> 27 #include <sys/time.h> 28 29 #define TST_NO_DEFAULT_MAIN 30 #include "tst_test.h" 31 #include "tst_device.h" 32 #include "lapi/futex.h" 33 #include "lapi/syscalls.h" 34 #include "tst_ansi_color.h" 35 #include "tst_safe_stdio.h" 36 #include "tst_timer_test.h" 37 38 #include "old_resource.h" 39 #include "old_device.h" 40 #include "old_tmpdir.h" 41 42 struct tst_test *tst_test; 43 44 static const char *tid; 45 static int iterations = 1; 46 static float duration = -1; 47 static pid_t main_pid, lib_pid; 48 static int mntpoint_mounted; 49 50 struct results { 51 int passed; 52 int skipped; 53 int failed; 54 int warnings; 55 unsigned int timeout; 56 }; 57 58 static struct results *results; 59 60 static int ipc_fd; 61 62 extern void *tst_futexes; 63 extern unsigned int tst_max_futexes; 64 65 #define IPC_ENV_VAR "LTP_IPC_PATH" 66 67 static char ipc_path[1024]; 68 const char *tst_ipc_path = ipc_path; 69 70 static char shm_path[1024]; 71 72 static void do_cleanup(void); 73 static void do_exit(int ret) __attribute__ ((noreturn)); 74 75 static void setup_ipc(void) 76 { 77 size_t size = getpagesize(); 78 79 if (access("/dev/shm", F_OK) == 0) { 80 snprintf(shm_path, sizeof(shm_path), "/dev/shm/ltp_%s_%d", 81 tid, getpid()); 82 } else { 83 char *tmpdir; 84 85 if (!tst_tmpdir_created()) 86 tst_tmpdir(); 87 88 tmpdir = tst_get_tmpdir(); 89 snprintf(shm_path, sizeof(shm_path), "%s/ltp_%s_%d", 90 tmpdir, tid, getpid()); 91 free(tmpdir); 92 } 93 94 ipc_fd = open(shm_path, O_CREAT | O_EXCL | O_RDWR, 0600); 95 if (ipc_fd < 0) 96 tst_brk(TBROK | TERRNO, "open(%s)", shm_path); 97 SAFE_CHMOD(shm_path, 0666); 98 99 SAFE_FTRUNCATE(ipc_fd, size); 100 101 results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0); 102 103 /* Checkpoints needs to be accessible from processes started by exec() */ 104 if (tst_test->needs_checkpoints) { 105 sprintf(ipc_path, IPC_ENV_VAR "=%s", shm_path); 106 putenv(ipc_path); 107 } else { 108 SAFE_UNLINK(shm_path); 109 } 110 111 SAFE_CLOSE(ipc_fd); 112 113 if (tst_test->needs_checkpoints) { 114 tst_futexes = (char*)results + sizeof(struct results); 115 tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t); 116 } 117 } 118 119 static void cleanup_ipc(void) 120 { 121 size_t size = getpagesize(); 122 123 if (ipc_fd > 0 && close(ipc_fd)) 124 tst_res(TWARN | TERRNO, "close(ipc_fd) failed"); 125 126 if (shm_path[0] && !access(shm_path, F_OK) && unlink(shm_path)) 127 tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path); 128 129 if (results) { 130 msync((void*)results, size, MS_SYNC); 131 munmap((void*)results, size); 132 } 133 } 134 135 void tst_reinit(void) 136 { 137 const char *path = getenv(IPC_ENV_VAR); 138 size_t size = getpagesize(); 139 int fd; 140 void *ptr; 141 142 if (!path) 143 tst_brk(TBROK, IPC_ENV_VAR" is not defined"); 144 145 if (access(path, F_OK)) 146 tst_brk(TBROK, "File %s does not exist!", path); 147 148 fd = SAFE_OPEN(path, O_RDWR); 149 150 ptr = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 151 tst_futexes = (char*)ptr + sizeof(struct results); 152 tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t); 153 154 SAFE_CLOSE(fd); 155 } 156 157 static void update_results(int ttype) 158 { 159 if (!results) 160 return; 161 162 switch (ttype) { 163 case TCONF: 164 tst_atomic_inc(&results->skipped); 165 break; 166 case TPASS: 167 tst_atomic_inc(&results->passed); 168 break; 169 case TWARN: 170 tst_atomic_inc(&results->warnings); 171 break; 172 case TFAIL: 173 tst_atomic_inc(&results->failed); 174 break; 175 } 176 } 177 178 static void print_result(const char *file, const int lineno, int ttype, 179 const char *fmt, va_list va) 180 { 181 char buf[1024]; 182 char *str = buf; 183 int ret, size = sizeof(buf), ssize; 184 const char *str_errno = NULL; 185 const char *res; 186 187 switch (TTYPE_RESULT(ttype)) { 188 case TPASS: 189 res = "PASS"; 190 break; 191 case TFAIL: 192 res = "FAIL"; 193 break; 194 case TBROK: 195 res = "BROK"; 196 break; 197 case TCONF: 198 res = "CONF"; 199 break; 200 case TWARN: 201 res = "WARN"; 202 break; 203 case TINFO: 204 res = "INFO"; 205 break; 206 default: 207 tst_brk(TBROK, "Invalid ttype value %i", ttype); 208 abort(); 209 } 210 211 if (ttype & TERRNO) 212 str_errno = tst_strerrno(errno); 213 214 if (ttype & TTERRNO) 215 str_errno = tst_strerrno(TEST_ERRNO); 216 217 ret = snprintf(str, size, "%s:%i: ", file, lineno); 218 str += ret; 219 size -= ret; 220 221 if (tst_color_enabled(STDERR_FILENO)) 222 ret = snprintf(str, size, "%s%s: %s", tst_ttype2color(ttype), 223 res, ANSI_COLOR_RESET); 224 else 225 ret = snprintf(str, size, "%s: ", res); 226 str += ret; 227 size -= ret; 228 229 ssize = size - 2; 230 ret = vsnprintf(str, size, fmt, va); 231 str += MIN(ret, ssize); 232 size -= MIN(ret, ssize); 233 if (ret >= ssize) { 234 tst_res_(file, lineno, TWARN, 235 "Next message is too long and truncated:"); 236 } else if (str_errno) { 237 ssize = size - 2; 238 ret = snprintf(str, size, ": %s", str_errno); 239 str += MIN(ret, ssize); 240 size -= MIN(ret, ssize); 241 if (ret >= ssize) 242 tst_res_(file, lineno, TWARN, 243 "Next message is too long and truncated:"); 244 } 245 246 snprintf(str, size, "\n"); 247 248 fputs(buf, stderr); 249 } 250 251 void tst_vres_(const char *file, const int lineno, int ttype, 252 const char *fmt, va_list va) 253 { 254 print_result(file, lineno, ttype, fmt, va); 255 256 update_results(TTYPE_RESULT(ttype)); 257 } 258 259 void tst_vbrk_(const char *file, const int lineno, int ttype, 260 const char *fmt, va_list va); 261 262 static void (*tst_brk_handler)(const char *file, const int lineno, int ttype, 263 const char *fmt, va_list va) = tst_vbrk_; 264 265 static void tst_cvres(const char *file, const int lineno, int ttype, 266 const char *fmt, va_list va) 267 { 268 if (TTYPE_RESULT(ttype) == TBROK) { 269 ttype &= ~TTYPE_MASK; 270 ttype |= TWARN; 271 } 272 273 print_result(file, lineno, ttype, fmt, va); 274 update_results(TTYPE_RESULT(ttype)); 275 } 276 277 static void do_test_cleanup(void) 278 { 279 tst_brk_handler = tst_cvres; 280 281 if (tst_test->cleanup) 282 tst_test->cleanup(); 283 284 tst_brk_handler = tst_vbrk_; 285 } 286 287 void tst_vbrk_(const char *file, const int lineno, int ttype, 288 const char *fmt, va_list va) 289 { 290 print_result(file, lineno, ttype, fmt, va); 291 292 /* 293 * The getpid implementation in some C library versions may cause cloned 294 * test threads to show the same pid as their parent when CLONE_VM is 295 * specified but CLONE_THREAD is not. Use direct syscall to avoid 296 * cleanup running in the child. 297 */ 298 if (syscall(SYS_getpid) == main_pid) 299 do_test_cleanup(); 300 301 if (getpid() == lib_pid) 302 do_exit(TTYPE_RESULT(ttype)); 303 304 exit(TTYPE_RESULT(ttype)); 305 } 306 307 void tst_res_(const char *file, const int lineno, int ttype, 308 const char *fmt, ...) 309 { 310 va_list va; 311 312 va_start(va, fmt); 313 tst_vres_(file, lineno, ttype, fmt, va); 314 va_end(va); 315 } 316 317 void tst_brk_(const char *file, const int lineno, int ttype, 318 const char *fmt, ...) 319 { 320 va_list va; 321 322 va_start(va, fmt); 323 tst_brk_handler(file, lineno, ttype, fmt, va); 324 va_end(va); 325 } 326 327 static void check_child_status(pid_t pid, int status) 328 { 329 int ret; 330 331 if (WIFSIGNALED(status)) { 332 tst_brk(TBROK, "Child (%i) killed by signal %s", 333 pid, tst_strsig(WTERMSIG(status))); 334 } 335 336 if (!(WIFEXITED(status))) 337 tst_brk(TBROK, "Child (%i) exited abnormaly", pid); 338 339 ret = WEXITSTATUS(status); 340 switch (ret) { 341 case TPASS: 342 break; 343 case TBROK: 344 case TCONF: 345 tst_brk(ret, "Reported by child (%i)", pid); 346 default: 347 tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, ret); 348 } 349 } 350 351 void tst_reap_children(void) 352 { 353 int status; 354 pid_t pid; 355 356 for (;;) { 357 pid = wait(&status); 358 359 if (pid > 0) { 360 check_child_status(pid, status); 361 continue; 362 } 363 364 if (errno == ECHILD) 365 break; 366 367 if (errno == EINTR) 368 continue; 369 370 tst_brk(TBROK | TERRNO, "wait() failed"); 371 } 372 } 373 374 375 pid_t safe_fork(const char *filename, unsigned int lineno) 376 { 377 pid_t pid; 378 379 if (!tst_test->forks_child) 380 tst_brk(TBROK, "test.forks_child must be set!"); 381 382 fflush(stdout); 383 384 pid = fork(); 385 if (pid < 0) 386 tst_brk_(filename, lineno, TBROK | TERRNO, "fork() failed"); 387 388 return pid; 389 } 390 391 static struct option { 392 char *optstr; 393 char *help; 394 } options[] = { 395 {"h", "-h Prints this help"}, 396 {"i:", "-i n Execute test n times"}, 397 {"I:", "-I x Execute test for n seconds"}, 398 {"C:", "-C ARG Run child process with ARG arguments (used internally)"}, 399 }; 400 401 static void print_help(void) 402 { 403 unsigned int i; 404 405 for (i = 0; i < ARRAY_SIZE(options); i++) 406 fprintf(stderr, "%s\n", options[i].help); 407 408 if (!tst_test->options) 409 return; 410 411 for (i = 0; tst_test->options[i].optstr; i++) 412 fprintf(stderr, "%s\n", tst_test->options[i].help); 413 } 414 415 static void check_option_collision(void) 416 { 417 unsigned int i, j; 418 struct tst_option *toptions = tst_test->options; 419 420 if (!toptions) 421 return; 422 423 for (i = 0; toptions[i].optstr; i++) { 424 for (j = 0; j < ARRAY_SIZE(options); j++) { 425 if (toptions[i].optstr[0] == options[j].optstr[0]) { 426 tst_brk(TBROK, "Option collision '%s'", 427 options[j].help); 428 } 429 } 430 } 431 } 432 433 static unsigned int count_options(void) 434 { 435 unsigned int i; 436 437 if (!tst_test->options) 438 return 0; 439 440 for (i = 0; tst_test->options[i].optstr; i++); 441 442 return i; 443 } 444 445 static void parse_topt(unsigned int topts_len, int opt, char *optarg) 446 { 447 unsigned int i; 448 struct tst_option *toptions = tst_test->options; 449 450 for (i = 0; i < topts_len; i++) { 451 if (toptions[i].optstr[0] == opt) 452 break; 453 } 454 455 if (i >= topts_len) 456 tst_brk(TBROK, "Invalid option '%c' (should not happen)", opt); 457 458 *(toptions[i].arg) = optarg ? optarg : ""; 459 } 460 461 /* see self_exec.c */ 462 #ifdef UCLINUX 463 extern char *child_args; 464 #endif 465 466 static void parse_opts(int argc, char *argv[]) 467 { 468 unsigned int i, topts_len = count_options(); 469 char optstr[2 * ARRAY_SIZE(options) + 2 * topts_len]; 470 int opt; 471 472 check_option_collision(); 473 474 optstr[0] = 0; 475 476 for (i = 0; i < ARRAY_SIZE(options); i++) 477 strcat(optstr, options[i].optstr); 478 479 for (i = 0; i < topts_len; i++) 480 strcat(optstr, tst_test->options[i].optstr); 481 482 while ((opt = getopt(argc, argv, optstr)) > 0) { 483 switch (opt) { 484 case '?': 485 print_help(); 486 tst_brk(TBROK, "Invalid option"); 487 case 'h': 488 print_help(); 489 exit(0); 490 case 'i': 491 iterations = atoi(optarg); 492 break; 493 case 'I': 494 duration = atof(optarg); 495 break; 496 case 'C': 497 #ifdef UCLINUX 498 child_args = optarg; 499 #endif 500 break; 501 default: 502 parse_topt(topts_len, opt, optarg); 503 } 504 } 505 506 if (optind < argc) 507 tst_brk(TBROK, "Unexpected argument(s) '%s'...", argv[optind]); 508 } 509 510 int tst_parse_int(const char *str, int *val, int min, int max) 511 { 512 long rval; 513 514 if (!str) 515 return 0; 516 517 int ret = tst_parse_long(str, &rval, min, max); 518 519 if (ret) 520 return ret; 521 522 *val = (int)rval; 523 return 0; 524 } 525 526 int tst_parse_long(const char *str, long *val, long min, long max) 527 { 528 long rval; 529 char *end; 530 531 if (!str) 532 return 0; 533 534 errno = 0; 535 rval = strtol(str, &end, 10); 536 537 if (str == end || *end != '\0') 538 return EINVAL; 539 540 if (errno) 541 return errno; 542 543 if (rval > max || rval < min) 544 return ERANGE; 545 546 *val = rval; 547 return 0; 548 } 549 550 int tst_parse_float(const char *str, float *val, float min, float max) 551 { 552 double rval; 553 char *end; 554 555 if (!str) 556 return 0; 557 558 errno = 0; 559 rval = strtod(str, &end); 560 561 if (str == end || *end != '\0') 562 return EINVAL; 563 564 if (errno) 565 return errno; 566 567 if (rval > (double)max || rval < (double)min) 568 return ERANGE; 569 570 *val = (float)rval; 571 return 0; 572 } 573 574 static void do_exit(int ret) 575 { 576 if (results) { 577 printf("\nSummary:\n"); 578 printf("passed %d\n", results->passed); 579 printf("failed %d\n", results->failed); 580 printf("skipped %d\n", results->skipped); 581 printf("warnings %d\n", results->warnings); 582 583 if (results->passed && ret == TCONF) 584 ret = 0; 585 586 if (results->failed) 587 ret |= TFAIL; 588 589 if (results->skipped && !results->passed) 590 ret |= TCONF; 591 592 if (results->warnings) 593 ret |= TWARN; 594 } 595 596 do_cleanup(); 597 598 exit(ret); 599 } 600 601 void check_kver(void) 602 { 603 int v1, v2, v3; 604 605 if (tst_parse_kver(tst_test->min_kver, &v1, &v2, &v3)) { 606 tst_res(TWARN, 607 "Invalid kernel version %s, expected %%d.%%d.%%d", 608 tst_test->min_kver); 609 } 610 611 if (tst_kvercmp(v1, v2, v3) < 0) { 612 tst_brk(TCONF, "The test requires kernel %s or newer", 613 tst_test->min_kver); 614 } 615 } 616 617 static int results_equal(struct results *a, struct results *b) 618 { 619 if (a->passed != b->passed) 620 return 0; 621 622 if (a->failed != b->failed) 623 return 0; 624 625 if (a->skipped != b->skipped) 626 return 0; 627 628 return 1; 629 } 630 631 static int needs_tmpdir(void) 632 { 633 return tst_test->needs_tmpdir || 634 tst_test->needs_device || 635 tst_test->resource_files || 636 tst_test->needs_checkpoints; 637 } 638 639 static void copy_resources(void) 640 { 641 unsigned int i; 642 643 for (i = 0; tst_test->resource_files[i]; i++) 644 TST_RESOURCE_COPY(NULL, tst_test->resource_files[i], NULL); 645 } 646 647 static const char *get_tid(char *argv[]) 648 { 649 char *p; 650 651 if (!argv[0] || !argv[0][0]) { 652 tst_res(TINFO, "argv[0] is empty!"); 653 return "ltp_empty_argv"; 654 } 655 656 p = strrchr(argv[0], '/'); 657 if (p) 658 return p+1; 659 660 return argv[0]; 661 } 662 663 static struct tst_device tdev; 664 struct tst_device *tst_device; 665 666 static void assert_test_fn(void) 667 { 668 int cnt = 0; 669 670 if (tst_test->test) 671 cnt++; 672 673 if (tst_test->test_all) 674 cnt++; 675 676 if (tst_test->sample) 677 cnt++; 678 679 if (!cnt) 680 tst_brk(TBROK, "No test function speficied"); 681 682 if (cnt != 1) 683 tst_brk(TBROK, "You can define only one test function"); 684 685 if (tst_test->test && !tst_test->tcnt) 686 tst_brk(TBROK, "Number of tests (tcnt) must not be > 0"); 687 688 if (!tst_test->test && tst_test->tcnt) 689 tst_brk(TBROK, "You can define tcnt only for test()"); 690 } 691 692 static void prepare_device(void) 693 { 694 if (tst_test->format_device) { 695 SAFE_MKFS(tdev.dev, tdev.fs_type, tst_test->dev_fs_opts, 696 tst_test->dev_extra_opt); 697 } 698 699 if (tst_test->mount_device) { 700 SAFE_MOUNT(tdev.dev, tst_test->mntpoint, tdev.fs_type, 701 tst_test->mnt_flags, tst_test->mnt_data); 702 mntpoint_mounted = 1; 703 } 704 } 705 706 static void do_setup(int argc, char *argv[]) 707 { 708 if (!tst_test) 709 tst_brk(TBROK, "No tests to run"); 710 711 if (tst_test->tconf_msg) 712 tst_brk(TCONF, "%s", tst_test->tconf_msg); 713 714 assert_test_fn(); 715 716 tid = get_tid(argv); 717 718 if (tst_test->sample) 719 tst_test = tst_timer_test_setup(tst_test); 720 721 parse_opts(argc, argv); 722 723 if (tst_test->needs_root && geteuid() != 0) 724 tst_brk(TCONF, "Test needs to be run as root"); 725 726 if (tst_test->min_kver) 727 check_kver(); 728 729 if (tst_test->format_device) 730 tst_test->needs_device = 1; 731 732 if (tst_test->mount_device) { 733 tst_test->needs_device = 1; 734 tst_test->format_device = 1; 735 } 736 737 if (tst_test->all_filesystems) 738 tst_test->needs_device = 1; 739 740 setup_ipc(); 741 742 if (needs_tmpdir() && !tst_tmpdir_created()) 743 tst_tmpdir(); 744 745 if (tst_test->mntpoint) 746 SAFE_MKDIR(tst_test->mntpoint, 0777); 747 748 if ((tst_test->needs_rofs || tst_test->mount_device || 749 tst_test->all_filesystems) && !tst_test->mntpoint) { 750 tst_brk(TBROK, "tst_test->mntpoint must be set!"); 751 } 752 753 if (tst_test->needs_rofs) { 754 /* If we failed to mount read-only tmpfs. Fallback to 755 * using a device with empty read-only filesystem. 756 */ 757 if (mount(NULL, tst_test->mntpoint, "tmpfs", MS_RDONLY, NULL)) { 758 tst_res(TINFO | TERRNO, "Can't mount tmpfs read-only" 759 " at %s, setting up a device instead\n", 760 tst_test->mntpoint); 761 tst_test->mount_device = 1; 762 tst_test->needs_device = 1; 763 tst_test->format_device = 1; 764 tst_test->mnt_flags = MS_RDONLY; 765 } else { 766 mntpoint_mounted = 1; 767 } 768 } 769 770 if (tst_test->needs_device && !mntpoint_mounted) { 771 tdev.dev = tst_acquire_device_(NULL, tst_test->dev_min_size); 772 773 if (!tdev.dev) 774 tst_brk(TCONF, "Failed to acquire device"); 775 776 tst_device = &tdev; 777 778 if (tst_test->dev_fs_type) 779 tdev.fs_type = tst_test->dev_fs_type; 780 else 781 tdev.fs_type = tst_dev_fs_type(); 782 783 if (!tst_test->all_filesystems) 784 prepare_device(); 785 } 786 787 if (tst_test->resource_files) 788 copy_resources(); 789 } 790 791 static void do_test_setup(void) 792 { 793 main_pid = getpid(); 794 795 if (tst_test->setup) 796 tst_test->setup(); 797 798 if (main_pid != getpid()) 799 tst_brk(TBROK, "Runaway child in setup()!"); 800 } 801 802 static void do_cleanup(void) 803 { 804 if (mntpoint_mounted) 805 tst_umount(tst_test->mntpoint); 806 807 if (tst_test->needs_device && tdev.dev) 808 tst_release_device(tdev.dev); 809 810 if (tst_tmpdir_created()) { 811 /* avoid munmap() on wrong pointer in tst_rmdir() */ 812 tst_futexes = NULL; 813 tst_rmdir(); 814 } 815 816 cleanup_ipc(); 817 } 818 819 static void run_tests(void) 820 { 821 unsigned int i; 822 struct results saved_results; 823 824 if (!tst_test->test) { 825 saved_results = *results; 826 tst_test->test_all(); 827 828 if (getpid() != main_pid) { 829 exit(0); 830 } 831 832 tst_reap_children(); 833 834 if (results_equal(&saved_results, results)) 835 tst_brk(TBROK, "Test haven't reported results!"); 836 return; 837 } 838 839 for (i = 0; i < tst_test->tcnt; i++) { 840 saved_results = *results; 841 tst_test->test(i); 842 843 if (getpid() != main_pid) { 844 exit(0); 845 } 846 847 tst_reap_children(); 848 849 if (results_equal(&saved_results, results)) 850 tst_brk(TBROK, "Test %i haven't reported results!", i); 851 } 852 } 853 854 static unsigned long long get_time_ms(void) 855 { 856 struct timeval tv; 857 858 gettimeofday(&tv, NULL); 859 860 return tv.tv_sec * 1000 + tv.tv_usec / 1000; 861 } 862 863 static void add_paths(void) 864 { 865 char *old_path = getenv("PATH"); 866 const char *start_dir; 867 char *new_path; 868 869 start_dir = tst_get_startwd(); 870 871 if (old_path) 872 SAFE_ASPRINTF(&new_path, "%s::%s", old_path, start_dir); 873 else 874 SAFE_ASPRINTF(&new_path, "::%s", start_dir); 875 876 SAFE_SETENV("PATH", new_path, 1); 877 free(new_path); 878 } 879 880 static void heartbeat(void) 881 { 882 kill(getppid(), SIGUSR1); 883 } 884 885 static void testrun(void) 886 { 887 unsigned int i = 0; 888 unsigned long long stop_time = 0; 889 int cont = 1; 890 891 add_paths(); 892 do_test_setup(); 893 894 if (duration > 0) 895 stop_time = get_time_ms() + (unsigned long long)(duration * 1000); 896 897 for (;;) { 898 cont = 0; 899 900 if (i < (unsigned int)iterations) { 901 i++; 902 cont = 1; 903 } 904 905 if (stop_time && get_time_ms() < stop_time) 906 cont = 1; 907 908 if (!cont) 909 break; 910 911 run_tests(); 912 heartbeat(); 913 } 914 915 do_test_cleanup(); 916 exit(0); 917 } 918 919 static pid_t test_pid; 920 921 922 static volatile sig_atomic_t sigkill_retries; 923 924 #define WRITE_MSG(msg) do { \ 925 if (write(2, msg, sizeof(msg) - 1)) { \ 926 /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */ \ 927 } \ 928 } while (0) 929 930 static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED) 931 { 932 WRITE_MSG("Test timeouted, sending SIGKILL!\n"); 933 kill(-test_pid, SIGKILL); 934 alarm(5); 935 936 if (++sigkill_retries > 10) { 937 WRITE_MSG("Cannot kill test processes!\n"); 938 WRITE_MSG("Congratulation, likely test hit a kernel bug.\n"); 939 WRITE_MSG("Exitting uncleanly...\n"); 940 _exit(TFAIL); 941 } 942 } 943 944 static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED) 945 { 946 alarm(results->timeout); 947 sigkill_retries = 0; 948 } 949 950 static void sigint_handler(int sig LTP_ATTRIBUTE_UNUSED) 951 { 952 if (test_pid > 0) { 953 WRITE_MSG("Sending SIGKILL to test process...\n"); 954 kill(-test_pid, SIGKILL); 955 } 956 } 957 958 void tst_set_timeout(int timeout) 959 { 960 char *mul = getenv("LTP_TIMEOUT_MUL"); 961 962 if (timeout == -1) { 963 tst_res(TINFO, "Timeout per run is disabled"); 964 return; 965 } 966 967 results->timeout = timeout; 968 969 if (mul) { 970 float m = atof(mul); 971 972 if (m < 1) 973 tst_brk(TBROK, "Invalid timeout multiplier '%s'", mul); 974 975 results->timeout = results->timeout * m + 0.5; 976 } 977 978 tst_res(TINFO, "Timeout per run is %uh %02um %02us", 979 results->timeout/3600, (results->timeout%3600)/60, 980 results->timeout % 60); 981 982 if (getpid() == lib_pid) 983 alarm(results->timeout); 984 else 985 heartbeat(); 986 } 987 988 static int fork_testrun(void) 989 { 990 int status; 991 992 if (tst_test->timeout) 993 tst_set_timeout(tst_test->timeout); 994 else 995 tst_set_timeout(300); 996 997 SAFE_SIGNAL(SIGINT, sigint_handler); 998 999 test_pid = fork(); 1000 if (test_pid < 0) 1001 tst_brk(TBROK | TERRNO, "fork()"); 1002 1003 if (!test_pid) { 1004 SAFE_SIGNAL(SIGALRM, SIG_DFL); 1005 SAFE_SIGNAL(SIGUSR1, SIG_DFL); 1006 SAFE_SIGNAL(SIGINT, SIG_DFL); 1007 SAFE_SETPGID(0, 0); 1008 testrun(); 1009 } 1010 1011 SAFE_WAITPID(test_pid, &status, 0); 1012 alarm(0); 1013 SAFE_SIGNAL(SIGINT, SIG_DFL); 1014 1015 if (WIFEXITED(status) && WEXITSTATUS(status)) 1016 return WEXITSTATUS(status); 1017 1018 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) { 1019 tst_res(TINFO, "If you are running on slow machine, " 1020 "try exporting LTP_TIMEOUT_MUL > 1"); 1021 tst_brk(TBROK, "Test killed! (timeout?)"); 1022 } 1023 1024 if (WIFSIGNALED(status)) 1025 tst_brk(TBROK, "Test killed by %s!", tst_strsig(WTERMSIG(status))); 1026 1027 return 0; 1028 } 1029 1030 static int run_tcases_per_fs(void) 1031 { 1032 int ret = 0; 1033 unsigned int i; 1034 const char *const *filesystems = tst_get_supported_fs_types(); 1035 1036 if (!filesystems[0]) 1037 tst_brk(TCONF, "There are no supported filesystems"); 1038 1039 for (i = 0; filesystems[i]; i++) { 1040 tdev.fs_type = filesystems[i]; 1041 1042 prepare_device(); 1043 1044 ret = fork_testrun(); 1045 1046 if (mntpoint_mounted) { 1047 tst_umount(tst_test->mntpoint); 1048 mntpoint_mounted = 0; 1049 } 1050 1051 if (ret == TCONF) { 1052 update_results(ret); 1053 continue; 1054 } 1055 1056 if (ret == 0) 1057 continue; 1058 1059 do_exit(ret); 1060 } 1061 1062 return ret; 1063 } 1064 1065 void tst_run_tcases(int argc, char *argv[], struct tst_test *self) 1066 { 1067 int ret; 1068 1069 lib_pid = getpid(); 1070 tst_test = self; 1071 1072 do_setup(argc, argv); 1073 1074 TCID = tid; 1075 1076 SAFE_SIGNAL(SIGALRM, alarm_handler); 1077 SAFE_SIGNAL(SIGUSR1, heartbeat_handler); 1078 1079 if (tst_test->all_filesystems) 1080 ret = run_tcases_per_fs(); 1081 else 1082 ret = fork_testrun(); 1083 1084 do_exit(ret); 1085 } 1086