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/types.h> 25 #include <sys/wait.h> 26 #include <sys/time.h> 27 28 #define TST_NO_DEFAULT_MAIN 29 #include "tst_test.h" 30 #include "tst_device.h" 31 #include "lapi/futex.h" 32 33 #include "old_resource.h" 34 #include "old_device.h" 35 #include "old_tmpdir.h" 36 37 struct tst_test *tst_test; 38 39 static char tmpdir_created; 40 static int iterations = 1; 41 static float duration = -1; 42 static pid_t main_pid, lib_pid; 43 44 struct results { 45 int passed; 46 int skipped; 47 int failed; 48 int warnings; 49 }; 50 51 static struct results *results; 52 53 static int ipc_fd; 54 55 extern void *tst_futexes; 56 extern unsigned int tst_max_futexes; 57 58 #define IPC_ENV_VAR "LTP_IPC_PATH" 59 60 static char ipc_path[1024]; 61 const char *tst_ipc_path = ipc_path; 62 char *const tst_ipc_envp[] = {ipc_path, NULL}; 63 64 static char shm_path[1024]; 65 66 static void do_cleanup(void); 67 static void do_exit(int ret) __attribute__ ((noreturn)); 68 69 static void setup_ipc(void) 70 { 71 size_t size = getpagesize(); 72 73 #ifndef ANDROID 74 //TODO: Fallback to tst_tmpdir() if /dev/shm does not exits? 75 snprintf(shm_path, sizeof(shm_path), "/dev/shm/ltp_%s_%d", 76 tst_test->tid, getpid()); 77 #else 78 snprintf(shm_path, sizeof(shm_path), "%s/ltp_%s_%d", 79 getenv("TMPDIR"), tst_test->tid, getpid()); 80 #endif 81 82 ipc_fd = open(shm_path, O_CREAT | O_EXCL | O_RDWR, 0600); 83 if (ipc_fd < 0) 84 tst_brk(TBROK | TERRNO, "open(%s)", shm_path); 85 86 SAFE_FTRUNCATE(ipc_fd, size); 87 88 results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0); 89 90 /* Checkpoints needs to be accessible from processes started by exec() */ 91 if (tst_test->needs_checkpoints) 92 sprintf(ipc_path, IPC_ENV_VAR "=%s", shm_path); 93 else 94 SAFE_UNLINK(shm_path); 95 96 SAFE_CLOSE(ipc_fd); 97 98 if (tst_test->needs_checkpoints) { 99 tst_futexes = (char*)results + sizeof(struct results); 100 tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t); 101 } 102 } 103 104 static void cleanup_ipc(void) 105 { 106 size_t size = getpagesize(); 107 108 if (ipc_fd > 0 && close(ipc_fd)) 109 tst_res(TWARN | TERRNO, "close(ipc_fd) failed"); 110 111 if (!access(shm_path, F_OK) && unlink(shm_path)) 112 tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path); 113 114 msync((void*)results, size, MS_SYNC); 115 munmap((void*)results, size); 116 } 117 118 void tst_reinit(void) 119 { 120 const char *path = getenv("LTP_IPC_PATH"); 121 size_t size = getpagesize(); 122 int fd; 123 void *ptr; 124 125 if (!path) 126 tst_brk(TBROK, "LTP_IPC_PATH is not defined"); 127 128 if (access(path, F_OK)) 129 tst_brk(TBROK, "File %s does not exist!", path); 130 131 fd = SAFE_OPEN(path, O_RDWR); 132 133 ptr = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 134 tst_futexes = (char*)ptr + sizeof(struct results); 135 tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t); 136 137 SAFE_CLOSE(fd); 138 } 139 140 static void update_results(const char *file, unsigned int lineno, int ttype) 141 { 142 if (!results) { 143 tst_brk(TBROK, 144 "%s: %d: Results IPC not initialized!", file, lineno); 145 } 146 147 switch (ttype) { 148 case TCONF: 149 tst_atomic_inc(&results->skipped); 150 break; 151 case TPASS: 152 tst_atomic_inc(&results->passed); 153 break; 154 case TWARN: 155 tst_atomic_inc(&results->warnings); 156 break; 157 case TFAIL: 158 tst_atomic_inc(&results->failed); 159 break; 160 } 161 } 162 163 static void print_result(const char *file, const int lineno, int ttype, 164 const char *fmt, va_list va) 165 { 166 char buf[1024]; 167 char *str = buf; 168 int ret, size = sizeof(buf); 169 const char *str_errno = NULL; 170 const char *res; 171 172 switch (TTYPE_RESULT(ttype)) { 173 case TPASS: 174 res = "PASS"; 175 break; 176 case TFAIL: 177 res = "FAIL"; 178 break; 179 case TBROK: 180 res = "BROK"; 181 break; 182 case TCONF: 183 res = "CONF"; 184 break; 185 case TWARN: 186 res = "WARN"; 187 break; 188 case TINFO: 189 res = "INFO"; 190 break; 191 default: 192 tst_brk(TBROK, "Invalid ttype value %i", ttype); 193 } 194 195 if (ttype & TERRNO) 196 str_errno = tst_strerrno(errno); 197 198 if (ttype & TTERRNO) 199 str_errno = tst_strerrno(TEST_ERRNO); 200 201 ret = snprintf(str, size, "%s:%i: %s: ", file, lineno, res); 202 203 str += ret; 204 size -= ret; 205 206 ret = vsnprintf(str, size, fmt, va); 207 208 str += ret; 209 size -= ret; 210 211 if (str_errno) 212 snprintf(str, size, ": %s\n", str_errno); 213 else 214 snprintf(str, size, "\n"); 215 216 fputs(buf, stderr); 217 } 218 219 void tst_vres_(const char *file, const int lineno, int ttype, 220 const char *fmt, va_list va) 221 { 222 print_result(file, lineno, ttype, fmt, va); 223 224 update_results(file, lineno, TTYPE_RESULT(ttype)); 225 } 226 227 void tst_vbrk_(const char *file, const int lineno, int ttype, 228 const char *fmt, va_list va) __attribute__((noreturn)); 229 230 static void do_test_cleanup(void) 231 { 232 if (tst_test->cleanup) 233 tst_test->cleanup(); 234 } 235 236 void tst_vbrk_(const char *file, const int lineno, int ttype, 237 const char *fmt, va_list va) 238 { 239 print_result(file, lineno, ttype, fmt, va); 240 241 if (getpid() == main_pid) 242 do_test_cleanup(); 243 244 if (getpid() == lib_pid) 245 do_exit(TTYPE_RESULT(ttype)); 246 247 exit(TTYPE_RESULT(ttype)); 248 } 249 250 void tst_res_(const char *file, const int lineno, int ttype, 251 const char *fmt, ...) 252 { 253 va_list va; 254 255 va_start(va, fmt); 256 tst_vres_(file, lineno, ttype, fmt, va); 257 va_end(va); 258 } 259 260 void tst_brk_(const char *file, const int lineno, int ttype, 261 const char *fmt, ...) 262 { 263 va_list va; 264 265 va_start(va, fmt); 266 tst_vbrk_(file, lineno, ttype, fmt, va); 267 va_end(va); 268 } 269 270 static void check_child_status(pid_t pid, int status) 271 { 272 int ret; 273 274 if (WIFSIGNALED(status)) { 275 tst_brk(TBROK, "Child (%i) killed by signal %s", 276 pid, tst_strsig(WTERMSIG(status))); 277 } 278 279 if (!(WIFEXITED(status))) 280 tst_brk(TBROK, "Child (%i) exitted abnormaly", pid); 281 282 ret = WEXITSTATUS(status); 283 switch (ret) { 284 case TPASS: 285 break; 286 case TBROK: 287 case TCONF: 288 tst_brk(ret, "Reported by child (%i)", pid); 289 default: 290 tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, ret); 291 } 292 } 293 294 static void reap_children(void) 295 { 296 int status; 297 pid_t pid; 298 299 for (;;) { 300 pid = wait(&status); 301 302 if (pid > 0) { 303 check_child_status(pid, status); 304 continue; 305 } 306 307 if (errno == ECHILD) 308 break; 309 310 if (errno == EINTR) 311 continue; 312 313 tst_brk(TBROK | TERRNO, "wait() failed"); 314 } 315 } 316 317 318 pid_t safe_fork(const char *filename, unsigned int lineno) 319 { 320 pid_t pid; 321 322 if (!tst_test->forks_child) 323 tst_brk(TBROK, "test.forks_child must be set!"); 324 325 fflush(stdout); 326 327 pid = fork(); 328 if (pid < 0) 329 tst_brk_(filename, lineno, TBROK | TERRNO, "fork() failed"); 330 331 return pid; 332 } 333 334 static struct option { 335 char *optstr; 336 char *help; 337 } options[] = { 338 {"h", "-h Prints this help"}, 339 {"i:", "-i n Execute test n times"}, 340 {"I:", "-I x Execute test for n seconds"}, 341 {"C:", "-C ARG Run child process with ARG arguments (used internally)"}, 342 }; 343 344 static void print_help(void) 345 { 346 unsigned int i; 347 348 for (i = 0; i < ARRAY_SIZE(options); i++) 349 fprintf(stderr, "%s\n", options[i].help); 350 351 if (!tst_test->options) 352 return; 353 354 for (i = 0; tst_test->options[i].optstr; i++) 355 fprintf(stderr, "%s", tst_test->options[i].help); 356 } 357 358 static void check_option_collision(void) 359 { 360 unsigned int i, j; 361 struct tst_option *toptions = tst_test->options; 362 363 if (!toptions) 364 return; 365 366 for (i = 0; toptions[i].optstr; i++) { 367 for (j = 0; j < ARRAY_SIZE(options); j++) { 368 if (toptions[i].optstr[0] == options[j].optstr[0]) { 369 tst_brk(TBROK, "Option collision '%s'", 370 options[j].help); 371 } 372 } 373 } 374 } 375 376 static unsigned int count_options(void) 377 { 378 unsigned int i; 379 380 if (!tst_test->options) 381 return 0; 382 383 for (i = 0; tst_test->options[i].optstr; i++); 384 385 return i; 386 } 387 388 static void parse_topt(unsigned int topts_len, int opt, char *optarg) 389 { 390 unsigned int i; 391 struct tst_option *toptions = tst_test->options; 392 393 for (i = 0; i < topts_len; i++) { 394 if (toptions[i].optstr[0] == opt) 395 break; 396 } 397 398 if (i >= topts_len) 399 tst_brk(TBROK, "Invalid option '%c' (should not happen)", opt); 400 401 *(toptions[i].arg) = optarg; 402 } 403 404 /* see self_exec.c */ 405 #ifdef UCLINUX 406 extern char *child_args; 407 #endif 408 409 static void parse_opts(int argc, char *argv[]) 410 { 411 unsigned int i, topts_len = count_options(); 412 char optstr[2 * ARRAY_SIZE(options) + 2 * topts_len]; 413 int opt; 414 415 check_option_collision(); 416 417 optstr[0] = 0; 418 419 for (i = 0; i < ARRAY_SIZE(options); i++) 420 strcat(optstr, options[i].optstr); 421 422 for (i = 0; i < topts_len; i++) 423 strcat(optstr, tst_test->options[i].optstr); 424 425 while ((opt = getopt(argc, argv, optstr)) > 0) { 426 switch (opt) { 427 case '?': 428 print_help(); 429 tst_brk(TBROK, "Invalid option"); 430 case 'h': 431 print_help(); 432 exit(0); 433 case 'i': 434 iterations = atoi(optarg); 435 break; 436 case 'I': 437 duration = atof(optarg); 438 break; 439 case 'C': 440 #ifdef UCLINUX 441 child_args = optarg; 442 #endif 443 break; 444 default: 445 parse_topt(topts_len, opt, optarg); 446 } 447 } 448 } 449 450 451 static void do_exit(int ret) 452 { 453 if (results) { 454 printf("\nSummary:\n"); 455 printf("passed %d\n", results->passed); 456 printf("failed %d\n", results->failed); 457 printf("skipped %d\n", results->skipped); 458 printf("warnings %d\n", results->warnings); 459 460 if (results->failed) 461 ret |= TFAIL; 462 463 if (results->skipped) 464 ret |= TCONF; 465 466 if (results->warnings) 467 ret |= TWARN; 468 } 469 470 do_cleanup(); 471 472 exit(ret); 473 } 474 475 void check_kver(void) 476 { 477 int v1, v2, v3; 478 479 tst_parse_kver(tst_test->min_kver, &v1, &v2, &v3); 480 481 if (tst_kvercmp(v1, v2, v3) < 0) { 482 tst_brk(TCONF, "The test requires kernel %s or newer", 483 tst_test->min_kver); 484 } 485 } 486 487 static int results_equal(struct results *a, struct results *b) 488 { 489 if (a->passed != b->passed) 490 return 0; 491 492 if (a->failed != b->failed) 493 return 0; 494 495 if (a->skipped != b->skipped) 496 return 0; 497 498 return 1; 499 } 500 501 static int needs_tmpdir(void) 502 { 503 return tst_test->needs_tmpdir || 504 tst_test->needs_device || 505 tst_test->resource_files || 506 tst_test->needs_checkpoints; 507 } 508 509 static void copy_resources(void) 510 { 511 unsigned int i; 512 513 for (i = 0; tst_test->resource_files[i]; i++) 514 TST_RESOURCE_COPY(NULL, tst_test->resource_files[i], NULL); 515 } 516 517 static struct tst_device tdev; 518 struct tst_device *tst_device; 519 520 static void do_setup(int argc, char *argv[]) 521 { 522 if (!tst_test) 523 tst_brk(TBROK, "No tests to run"); 524 525 if (!tst_test->test && !tst_test->test_all) 526 tst_brk(TBROK, "No test function speficied"); 527 528 if (tst_test->test && tst_test->test_all) 529 tst_brk(TBROK, "You can define either test() or test_all()"); 530 531 if (tst_test->test && !tst_test->tcnt) 532 tst_brk(TBROK, "Number of tests (tcnt) must not be > 0"); 533 534 if (tst_test->test_all && tst_test->tcnt) 535 tst_brk(TBROK, "You can't define tcnt for test_all()"); 536 537 if (tst_test->needs_root && geteuid() != 0) 538 tst_brk(TCONF, "Test needs to be run as root"); 539 540 if (tst_test->min_kver) 541 check_kver(); 542 543 parse_opts(argc, argv); 544 545 setup_ipc(); 546 547 if (needs_tmpdir()) { 548 tst_tmpdir(); 549 tmpdir_created = 1; 550 } 551 552 if (tst_test->needs_device) { 553 tdev.dev = tst_acquire_device(NULL); 554 tdev.fs_type = tst_dev_fs_type(); 555 556 if (!tdev.dev) 557 tst_brk(TCONF, "Failed to acquire device"); 558 559 tst_device = &tdev; 560 } 561 562 if (tst_test->resource_files) 563 copy_resources(); 564 } 565 566 static void do_test_setup(void) 567 { 568 main_pid = getpid(); 569 570 if (tst_test->setup) 571 tst_test->setup(); 572 573 if (main_pid != getpid()) 574 tst_brk(TBROK, "Runaway child in setup()!"); 575 } 576 577 static void do_cleanup(void) 578 { 579 if (tst_test->needs_device && tdev.dev) 580 tst_release_device(tdev.dev); 581 582 if (needs_tmpdir() && tmpdir_created) { 583 /* avoid munmap() on wrong pointer in tst_rmdir() */ 584 tst_futexes = NULL; 585 tst_rmdir(); 586 } 587 588 cleanup_ipc(); 589 } 590 591 static void run_tests(void) 592 { 593 unsigned int i; 594 struct results saved_results; 595 596 if (!tst_test->test) { 597 saved_results = *results; 598 tst_test->test_all(); 599 600 if (getpid() != main_pid) { 601 exit(0); 602 } 603 604 reap_children(); 605 606 if (results_equal(&saved_results, results)) 607 tst_brk(TBROK, "Test haven't reported results!"); 608 return; 609 } 610 611 for (i = 0; i < tst_test->tcnt; i++) { 612 saved_results = *results; 613 tst_test->test(i); 614 615 if (getpid() != main_pid) { 616 exit(0); 617 } 618 619 reap_children(); 620 621 if (results_equal(&saved_results, results)) 622 tst_brk(TBROK, "Test %i haven't reported results!", i); 623 } 624 } 625 626 static unsigned long long get_time_ms(void) 627 { 628 struct timeval tv; 629 630 gettimeofday(&tv, NULL); 631 632 return tv.tv_sec * 1000 + tv.tv_usec / 1000; 633 } 634 635 static void testrun(void) 636 { 637 unsigned int i = 0; 638 unsigned long long stop_time = 0; 639 int cont = 1; 640 641 do_test_setup(); 642 643 if (duration > 0) 644 stop_time = get_time_ms() + (unsigned long long)(duration * 1000); 645 646 for (;;) { 647 cont = 0; 648 649 if (i < (unsigned int)iterations) { 650 i++; 651 cont = 1; 652 } 653 654 if (stop_time && get_time_ms() < stop_time) 655 cont = 1; 656 657 if (!cont) 658 break; 659 660 run_tests(); 661 662 kill(getppid(), SIGUSR1); 663 } 664 665 do_test_cleanup(); 666 exit(0); 667 } 668 669 static pid_t test_pid; 670 static unsigned int timeout = 300; 671 672 static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED) 673 { 674 kill(-test_pid, SIGKILL); 675 } 676 677 static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED) 678 { 679 alarm(timeout); 680 } 681 682 void tst_run_tcases(int argc, char *argv[], struct tst_test *self) 683 { 684 int status; 685 char *mul; 686 687 lib_pid = getpid(); 688 tst_test = self; 689 TCID = tst_test->tid; 690 691 do_setup(argc, argv); 692 693 if (tst_test->timeout) 694 timeout = tst_test->timeout; 695 696 mul = getenv("LTP_TIMEOUT_MUL"); 697 if (mul) { 698 float m = atof(mul); 699 700 if (m < 1) 701 tst_brk(TBROK, "Invalid timeout multiplier '%s'", mul); 702 703 timeout = timeout * m + 0.5; 704 } 705 706 tst_res(TINFO, "Timeout per run is %us", timeout); 707 708 SAFE_SIGNAL(SIGALRM, alarm_handler); 709 SAFE_SIGNAL(SIGUSR1, heartbeat_handler); 710 711 alarm(timeout); 712 713 test_pid = fork(); 714 if (test_pid < 0) 715 tst_brk(TBROK | TERRNO, "fork()"); 716 717 if (!test_pid) { 718 SAFE_SETPGID(0, 0); 719 testrun(); 720 } 721 722 SAFE_WAITPID(test_pid, &status, 0); 723 724 alarm(0); 725 726 if (WIFEXITED(status) && WEXITSTATUS(status)) 727 do_exit(WEXITSTATUS(status)); 728 729 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) { 730 tst_res(TINFO, "If you are running on slow machine, " 731 "try exporting LTP_TIMEOUT_MUL > 1"); 732 tst_brk(TBROK, "Test killed! (timeout?)"); 733 } 734 735 if (WIFSIGNALED(status)) 736 tst_brk(TBROK, "Test killed by %s!", tst_strsig(WTERMSIG(status))); 737 738 do_exit(0); 739 } 740