1#!/usr/bin/perl -w 2# 3# Copyright 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. 4# Licensed under the terms of the GNU GPL License version 2 5# 6 7use strict; 8use IPC::Open2; 9use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); 10use File::Path qw(mkpath); 11use File::Copy qw(cp); 12use FileHandle; 13 14my $VERSION = "0.2"; 15 16$| = 1; 17 18my %opt; 19my %repeat_tests; 20my %repeats; 21my %default; 22 23#default opts 24$default{"NUM_TESTS"} = 1; 25$default{"REBOOT_TYPE"} = "grub"; 26$default{"TEST_TYPE"} = "test"; 27$default{"BUILD_TYPE"} = "randconfig"; 28$default{"MAKE_CMD"} = "make"; 29$default{"TIMEOUT"} = 120; 30$default{"TMP_DIR"} = "/tmp/ktest"; 31$default{"SLEEP_TIME"} = 60; # sleep time between tests 32$default{"BUILD_NOCLEAN"} = 0; 33$default{"REBOOT_ON_ERROR"} = 0; 34$default{"POWEROFF_ON_ERROR"} = 0; 35$default{"REBOOT_ON_SUCCESS"} = 1; 36$default{"POWEROFF_ON_SUCCESS"} = 0; 37$default{"BUILD_OPTIONS"} = ""; 38$default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects 39$default{"PATCHCHECK_SLEEP_TIME"} = 60; # sleep time between patch checks 40$default{"CLEAR_LOG"} = 0; 41$default{"BISECT_MANUAL"} = 0; 42$default{"BISECT_SKIP"} = 1; 43$default{"SUCCESS_LINE"} = "login:"; 44$default{"BOOTED_TIMEOUT"} = 1; 45$default{"DIE_ON_FAILURE"} = 1; 46$default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND"; 47$default{"SCP_TO_TARGET"} = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE"; 48$default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot"; 49$default{"STOP_AFTER_SUCCESS"} = 10; 50$default{"STOP_AFTER_FAILURE"} = 60; 51$default{"STOP_TEST_AFTER"} = 600; 52$default{"LOCALVERSION"} = "-test"; 53 54my $ktest_config; 55my $version; 56my $machine; 57my $ssh_user; 58my $tmpdir; 59my $builddir; 60my $outputdir; 61my $output_config; 62my $test_type; 63my $build_type; 64my $build_options; 65my $reboot_type; 66my $reboot_script; 67my $power_cycle; 68my $reboot; 69my $reboot_on_error; 70my $poweroff_on_error; 71my $die_on_failure; 72my $powercycle_after_reboot; 73my $poweroff_after_halt; 74my $ssh_exec; 75my $scp_to_target; 76my $power_off; 77my $grub_menu; 78my $grub_number; 79my $target; 80my $make; 81my $post_install; 82my $noclean; 83my $minconfig; 84my $addconfig; 85my $in_bisect = 0; 86my $bisect_bad = ""; 87my $reverse_bisect; 88my $bisect_manual; 89my $bisect_skip; 90my $in_patchcheck = 0; 91my $run_test; 92my $redirect; 93my $buildlog; 94my $dmesg; 95my $monitor_fp; 96my $monitor_pid; 97my $monitor_cnt = 0; 98my $sleep_time; 99my $bisect_sleep_time; 100my $patchcheck_sleep_time; 101my $store_failures; 102my $timeout; 103my $booted_timeout; 104my $console; 105my $success_line; 106my $stop_after_success; 107my $stop_after_failure; 108my $stop_test_after; 109my $build_target; 110my $target_image; 111my $localversion; 112my $iteration = 0; 113my $successes = 0; 114 115my %entered_configs; 116my %config_help; 117my %variable; 118 119$config_help{"MACHINE"} = << "EOF" 120 The machine hostname that you will test. 121EOF 122 ; 123$config_help{"SSH_USER"} = << "EOF" 124 The box is expected to have ssh on normal bootup, provide the user 125 (most likely root, since you need privileged operations) 126EOF 127 ; 128$config_help{"BUILD_DIR"} = << "EOF" 129 The directory that contains the Linux source code (full path). 130EOF 131 ; 132$config_help{"OUTPUT_DIR"} = << "EOF" 133 The directory that the objects will be built (full path). 134 (can not be same as BUILD_DIR) 135EOF 136 ; 137$config_help{"BUILD_TARGET"} = << "EOF" 138 The location of the compiled file to copy to the target. 139 (relative to OUTPUT_DIR) 140EOF 141 ; 142$config_help{"TARGET_IMAGE"} = << "EOF" 143 The place to put your image on the test machine. 144EOF 145 ; 146$config_help{"POWER_CYCLE"} = << "EOF" 147 A script or command to reboot the box. 148 149 Here is a digital loggers power switch example 150 POWER_CYCLE = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin\@power/outlet?5=CCL' 151 152 Here is an example to reboot a virtual box on the current host 153 with the name "Guest". 154 POWER_CYCLE = virsh destroy Guest; sleep 5; virsh start Guest 155EOF 156 ; 157$config_help{"CONSOLE"} = << "EOF" 158 The script or command that reads the console 159 160 If you use ttywatch server, something like the following would work. 161CONSOLE = nc -d localhost 3001 162 163 For a virtual machine with guest name "Guest". 164CONSOLE = virsh console Guest 165EOF 166 ; 167$config_help{"LOCALVERSION"} = << "EOF" 168 Required version ending to differentiate the test 169 from other linux builds on the system. 170EOF 171 ; 172$config_help{"REBOOT_TYPE"} = << "EOF" 173 Way to reboot the box to the test kernel. 174 Only valid options so far are "grub" and "script". 175 176 If you specify grub, it will assume grub version 1 177 and will search in /boot/grub/menu.lst for the title \$GRUB_MENU 178 and select that target to reboot to the kernel. If this is not 179 your setup, then specify "script" and have a command or script 180 specified in REBOOT_SCRIPT to boot to the target. 181 182 The entry in /boot/grub/menu.lst must be entered in manually. 183 The test will not modify that file. 184EOF 185 ; 186$config_help{"GRUB_MENU"} = << "EOF" 187 The grub title name for the test kernel to boot 188 (Only mandatory if REBOOT_TYPE = grub) 189 190 Note, ktest.pl will not update the grub menu.lst, you need to 191 manually add an option for the test. ktest.pl will search 192 the grub menu.lst for this option to find what kernel to 193 reboot into. 194 195 For example, if in the /boot/grub/menu.lst the test kernel title has: 196 title Test Kernel 197 kernel vmlinuz-test 198 GRUB_MENU = Test Kernel 199EOF 200 ; 201$config_help{"REBOOT_SCRIPT"} = << "EOF" 202 A script to reboot the target into the test kernel 203 (Only mandatory if REBOOT_TYPE = script) 204EOF 205 ; 206 207 208sub get_ktest_config { 209 my ($config) = @_; 210 211 return if (defined($opt{$config})); 212 213 if (defined($config_help{$config})) { 214 print "\n"; 215 print $config_help{$config}; 216 } 217 218 for (;;) { 219 print "$config = "; 220 if (defined($default{$config})) { 221 print "\[$default{$config}\] "; 222 } 223 $entered_configs{$config} = <STDIN>; 224 $entered_configs{$config} =~ s/^\s*(.*\S)\s*$/$1/; 225 if ($entered_configs{$config} =~ /^\s*$/) { 226 if ($default{$config}) { 227 $entered_configs{$config} = $default{$config}; 228 } else { 229 print "Your answer can not be blank\n"; 230 next; 231 } 232 } 233 last; 234 } 235} 236 237sub get_ktest_configs { 238 get_ktest_config("MACHINE"); 239 get_ktest_config("SSH_USER"); 240 get_ktest_config("BUILD_DIR"); 241 get_ktest_config("OUTPUT_DIR"); 242 get_ktest_config("BUILD_TARGET"); 243 get_ktest_config("TARGET_IMAGE"); 244 get_ktest_config("POWER_CYCLE"); 245 get_ktest_config("CONSOLE"); 246 get_ktest_config("LOCALVERSION"); 247 248 my $rtype = $opt{"REBOOT_TYPE"}; 249 250 if (!defined($rtype)) { 251 if (!defined($opt{"GRUB_MENU"})) { 252 get_ktest_config("REBOOT_TYPE"); 253 $rtype = $entered_configs{"REBOOT_TYPE"}; 254 } else { 255 $rtype = "grub"; 256 } 257 } 258 259 if ($rtype eq "grub") { 260 get_ktest_config("GRUB_MENU"); 261 } else { 262 get_ktest_config("REBOOT_SCRIPT"); 263 } 264} 265 266sub process_variables { 267 my ($value) = @_; 268 my $retval = ""; 269 270 # We want to check for '\', and it is just easier 271 # to check the previous characet of '$' and not need 272 # to worry if '$' is the first character. By adding 273 # a space to $value, we can just check [^\\]\$ and 274 # it will still work. 275 $value = " $value"; 276 277 while ($value =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { 278 my $begin = $1; 279 my $var = $2; 280 my $end = $3; 281 # append beginning of value to retval 282 $retval = "$retval$begin"; 283 if (defined($variable{$var})) { 284 $retval = "$retval$variable{$var}"; 285 } else { 286 # put back the origin piece. 287 $retval = "$retval\$\{$var\}"; 288 } 289 $value = $end; 290 } 291 $retval = "$retval$value"; 292 293 # remove the space added in the beginning 294 $retval =~ s/ //; 295 296 return "$retval" 297} 298 299sub set_value { 300 my ($lvalue, $rvalue) = @_; 301 302 if (defined($opt{$lvalue})) { 303 die "Error: Option $lvalue defined more than once!\n"; 304 } 305 if ($rvalue =~ /^\s*$/) { 306 delete $opt{$lvalue}; 307 } else { 308 $rvalue = process_variables($rvalue); 309 $opt{$lvalue} = $rvalue; 310 } 311} 312 313sub set_variable { 314 my ($lvalue, $rvalue) = @_; 315 316 if ($rvalue =~ /^\s*$/) { 317 delete $variable{$lvalue}; 318 } else { 319 $rvalue = process_variables($rvalue); 320 $variable{$lvalue} = $rvalue; 321 } 322} 323 324sub read_config { 325 my ($config) = @_; 326 327 open(IN, $config) || die "can't read file $config"; 328 329 my $name = $config; 330 $name =~ s,.*/(.*),$1,; 331 332 my $test_num = 0; 333 my $default = 1; 334 my $repeat = 1; 335 my $num_tests_set = 0; 336 my $skip = 0; 337 my $rest; 338 339 while (<IN>) { 340 341 # ignore blank lines and comments 342 next if (/^\s*$/ || /\s*\#/); 343 344 if (/^\s*TEST_START(.*)/) { 345 346 $rest = $1; 347 348 if ($num_tests_set) { 349 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n"; 350 } 351 352 my $old_test_num = $test_num; 353 my $old_repeat = $repeat; 354 355 $test_num += $repeat; 356 $default = 0; 357 $repeat = 1; 358 359 if ($rest =~ /\s+SKIP(.*)/) { 360 $rest = $1; 361 $skip = 1; 362 } else { 363 $skip = 0; 364 } 365 366 if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) { 367 $repeat = $1; 368 $rest = $2; 369 $repeat_tests{"$test_num"} = $repeat; 370 } 371 372 if ($rest =~ /\s+SKIP(.*)/) { 373 $rest = $1; 374 $skip = 1; 375 } 376 377 if ($rest !~ /^\s*$/) { 378 die "$name: $.: Gargbage found after TEST_START\n$_"; 379 } 380 381 if ($skip) { 382 $test_num = $old_test_num; 383 $repeat = $old_repeat; 384 } 385 386 } elsif (/^\s*DEFAULTS(.*)$/) { 387 $default = 1; 388 389 $rest = $1; 390 391 if ($rest =~ /\s+SKIP(.*)/) { 392 $rest = $1; 393 $skip = 1; 394 } else { 395 $skip = 0; 396 } 397 398 if ($rest !~ /^\s*$/) { 399 die "$name: $.: Gargbage found after DEFAULTS\n$_"; 400 } 401 402 } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) { 403 404 next if ($skip); 405 406 my $lvalue = $1; 407 my $rvalue = $2; 408 409 if (!$default && 410 ($lvalue eq "NUM_TESTS" || 411 $lvalue eq "LOG_FILE" || 412 $lvalue eq "CLEAR_LOG")) { 413 die "$name: $.: $lvalue must be set in DEFAULTS section\n"; 414 } 415 416 if ($lvalue eq "NUM_TESTS") { 417 if ($test_num) { 418 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n"; 419 } 420 if (!$default) { 421 die "$name: $.: NUM_TESTS must be set in default section\n"; 422 } 423 $num_tests_set = 1; 424 } 425 426 if ($default || $lvalue =~ /\[\d+\]$/) { 427 set_value($lvalue, $rvalue); 428 } else { 429 my $val = "$lvalue\[$test_num\]"; 430 set_value($val, $rvalue); 431 432 if ($repeat > 1) { 433 $repeats{$val} = $repeat; 434 } 435 } 436 } elsif (/^\s*([A-Z_\[\]\d]+)\s*:=\s*(.*?)\s*$/) { 437 next if ($skip); 438 439 my $lvalue = $1; 440 my $rvalue = $2; 441 442 # process config variables. 443 # Config variables are only active while reading the 444 # config and can be defined anywhere. They also ignore 445 # TEST_START and DEFAULTS, but are skipped if they are in 446 # on of these sections that have SKIP defined. 447 # The save variable can be 448 # defined multiple times and the new one simply overrides 449 # the prevous one. 450 set_variable($lvalue, $rvalue); 451 452 } else { 453 die "$name: $.: Garbage found in config\n$_"; 454 } 455 } 456 457 close(IN); 458 459 if ($test_num) { 460 $test_num += $repeat - 1; 461 $opt{"NUM_TESTS"} = $test_num; 462 } 463 464 # make sure we have all mandatory configs 465 get_ktest_configs; 466 467 # set any defaults 468 469 foreach my $default (keys %default) { 470 if (!defined($opt{$default})) { 471 $opt{$default} = $default{$default}; 472 } 473 } 474} 475 476sub _logit { 477 if (defined($opt{"LOG_FILE"})) { 478 open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}"; 479 print OUT @_; 480 close(OUT); 481 } 482} 483 484sub logit { 485 if (defined($opt{"LOG_FILE"})) { 486 _logit @_; 487 } else { 488 print @_; 489 } 490} 491 492sub doprint { 493 print @_; 494 _logit @_; 495} 496 497sub run_command; 498 499sub reboot { 500 # try to reboot normally 501 if (run_command $reboot) { 502 if (defined($powercycle_after_reboot)) { 503 sleep $powercycle_after_reboot; 504 run_command "$power_cycle"; 505 } 506 } else { 507 # nope? power cycle it. 508 run_command "$power_cycle"; 509 } 510} 511 512sub do_not_reboot { 513 my $i = $iteration; 514 515 return $test_type eq "build" || 516 ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || 517 ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build"); 518} 519 520sub dodie { 521 doprint "CRITICAL FAILURE... ", @_, "\n"; 522 523 my $i = $iteration; 524 525 if ($reboot_on_error && !do_not_reboot) { 526 527 doprint "REBOOTING\n"; 528 reboot; 529 530 } elsif ($poweroff_on_error && defined($power_off)) { 531 doprint "POWERING OFF\n"; 532 `$power_off`; 533 } 534 535 if (defined($opt{"LOG_FILE"})) { 536 print " See $opt{LOG_FILE} for more info.\n"; 537 } 538 539 die @_, "\n"; 540} 541 542sub open_console { 543 my ($fp) = @_; 544 545 my $flags; 546 547 my $pid = open($fp, "$console|") or 548 dodie "Can't open console $console"; 549 550 $flags = fcntl($fp, F_GETFL, 0) or 551 dodie "Can't get flags for the socket: $!"; 552 $flags = fcntl($fp, F_SETFL, $flags | O_NONBLOCK) or 553 dodie "Can't set flags for the socket: $!"; 554 555 return $pid; 556} 557 558sub close_console { 559 my ($fp, $pid) = @_; 560 561 doprint "kill child process $pid\n"; 562 kill 2, $pid; 563 564 print "closing!\n"; 565 close($fp); 566} 567 568sub start_monitor { 569 if ($monitor_cnt++) { 570 return; 571 } 572 $monitor_fp = \*MONFD; 573 $monitor_pid = open_console $monitor_fp; 574 575 return; 576 577 open(MONFD, "Stop perl from warning about single use of MONFD"); 578} 579 580sub end_monitor { 581 if (--$monitor_cnt) { 582 return; 583 } 584 close_console($monitor_fp, $monitor_pid); 585} 586 587sub wait_for_monitor { 588 my ($time) = @_; 589 my $line; 590 591 doprint "** Wait for monitor to settle down **\n"; 592 593 # read the monitor and wait for the system to calm down 594 do { 595 $line = wait_for_input($monitor_fp, $time); 596 print "$line" if (defined($line)); 597 } while (defined($line)); 598 print "** Monitor flushed **\n"; 599} 600 601sub fail { 602 603 if ($die_on_failure) { 604 dodie @_; 605 } 606 607 doprint "FAILED\n"; 608 609 my $i = $iteration; 610 611 # no need to reboot for just building. 612 if (!do_not_reboot) { 613 doprint "REBOOTING\n"; 614 reboot; 615 start_monitor; 616 wait_for_monitor $sleep_time; 617 end_monitor; 618 } 619 620 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; 621 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; 622 doprint "KTEST RESULT: TEST $i Failed: ", @_, "\n"; 623 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; 624 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; 625 626 return 1 if (!defined($store_failures)); 627 628 my @t = localtime; 629 my $date = sprintf "%04d%02d%02d%02d%02d%02d", 630 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0]; 631 632 my $type = $build_type; 633 if ($type =~ /useconfig/) { 634 $type = "useconfig"; 635 } 636 637 my $dir = "$machine-$test_type-$type-fail-$date"; 638 my $faildir = "$store_failures/$dir"; 639 640 if (!-d $faildir) { 641 mkpath($faildir) or 642 die "can't create $faildir"; 643 } 644 if (-f "$output_config") { 645 cp "$output_config", "$faildir/config" or 646 die "failed to copy .config"; 647 } 648 if (-f $buildlog) { 649 cp $buildlog, "$faildir/buildlog" or 650 die "failed to move $buildlog"; 651 } 652 if (-f $dmesg) { 653 cp $dmesg, "$faildir/dmesg" or 654 die "failed to move $dmesg"; 655 } 656 657 doprint "*** Saved info to $faildir ***\n"; 658 659 return 1; 660} 661 662sub run_command { 663 my ($command) = @_; 664 my $dolog = 0; 665 my $dord = 0; 666 my $pid; 667 668 $command =~ s/\$SSH_USER/$ssh_user/g; 669 $command =~ s/\$MACHINE/$machine/g; 670 671 doprint("$command ... "); 672 673 $pid = open(CMD, "$command 2>&1 |") or 674 (fail "unable to exec $command" and return 0); 675 676 if (defined($opt{"LOG_FILE"})) { 677 open(LOG, ">>$opt{LOG_FILE}") or 678 dodie "failed to write to log"; 679 $dolog = 1; 680 } 681 682 if (defined($redirect)) { 683 open (RD, ">$redirect") or 684 dodie "failed to write to redirect $redirect"; 685 $dord = 1; 686 } 687 688 while (<CMD>) { 689 print LOG if ($dolog); 690 print RD if ($dord); 691 } 692 693 waitpid($pid, 0); 694 my $failed = $?; 695 696 close(CMD); 697 close(LOG) if ($dolog); 698 close(RD) if ($dord); 699 700 if ($failed) { 701 doprint "FAILED!\n"; 702 } else { 703 doprint "SUCCESS\n"; 704 } 705 706 return !$failed; 707} 708 709sub run_ssh { 710 my ($cmd) = @_; 711 my $cp_exec = $ssh_exec; 712 713 $cp_exec =~ s/\$SSH_COMMAND/$cmd/g; 714 return run_command "$cp_exec"; 715} 716 717sub run_scp { 718 my ($src, $dst) = @_; 719 my $cp_scp = $scp_to_target; 720 721 $cp_scp =~ s/\$SRC_FILE/$src/g; 722 $cp_scp =~ s/\$DST_FILE/$dst/g; 723 724 return run_command "$cp_scp"; 725} 726 727sub get_grub_index { 728 729 if ($reboot_type ne "grub") { 730 return; 731 } 732 return if (defined($grub_number)); 733 734 doprint "Find grub menu ... "; 735 $grub_number = -1; 736 737 my $ssh_grub = $ssh_exec; 738 $ssh_grub =~ s,\$SSH_COMMAND,cat /boot/grub/menu.lst,g; 739 740 open(IN, "$ssh_grub |") 741 or die "unable to get menu.lst"; 742 743 while (<IN>) { 744 if (/^\s*title\s+$grub_menu\s*$/) { 745 $grub_number++; 746 last; 747 } elsif (/^\s*title\s/) { 748 $grub_number++; 749 } 750 } 751 close(IN); 752 753 die "Could not find '$grub_menu' in /boot/grub/menu on $machine" 754 if ($grub_number < 0); 755 doprint "$grub_number\n"; 756} 757 758sub wait_for_input 759{ 760 my ($fp, $time) = @_; 761 my $rin; 762 my $ready; 763 my $line; 764 my $ch; 765 766 if (!defined($time)) { 767 $time = $timeout; 768 } 769 770 $rin = ''; 771 vec($rin, fileno($fp), 1) = 1; 772 $ready = select($rin, undef, undef, $time); 773 774 $line = ""; 775 776 # try to read one char at a time 777 while (sysread $fp, $ch, 1) { 778 $line .= $ch; 779 last if ($ch eq "\n"); 780 } 781 782 if (!length($line)) { 783 return undef; 784 } 785 786 return $line; 787} 788 789sub reboot_to { 790 if ($reboot_type eq "grub") { 791 run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'"; 792 return; 793 } 794 795 run_command "$reboot_script"; 796} 797 798sub get_sha1 { 799 my ($commit) = @_; 800 801 doprint "git rev-list --max-count=1 $commit ... "; 802 my $sha1 = `git rev-list --max-count=1 $commit`; 803 my $ret = $?; 804 805 logit $sha1; 806 807 if ($ret) { 808 doprint "FAILED\n"; 809 dodie "Failed to get git $commit"; 810 } 811 812 print "SUCCESS\n"; 813 814 chomp $sha1; 815 816 return $sha1; 817} 818 819sub monitor { 820 my $booted = 0; 821 my $bug = 0; 822 my $skip_call_trace = 0; 823 my $loops; 824 825 wait_for_monitor 5; 826 827 my $line; 828 my $full_line = ""; 829 830 open(DMESG, "> $dmesg") or 831 die "unable to write to $dmesg"; 832 833 reboot_to; 834 835 my $success_start; 836 my $failure_start; 837 my $monitor_start = time; 838 my $done = 0; 839 840 while (!$done) { 841 842 if ($booted) { 843 $line = wait_for_input($monitor_fp, $booted_timeout); 844 } else { 845 $line = wait_for_input($monitor_fp); 846 } 847 848 last if (!defined($line)); 849 850 doprint $line; 851 print DMESG $line; 852 853 # we are not guaranteed to get a full line 854 $full_line .= $line; 855 856 if ($full_line =~ /$success_line/) { 857 $booted = 1; 858 $success_start = time; 859 } 860 861 if ($booted && defined($stop_after_success) && 862 $stop_after_success >= 0) { 863 my $now = time; 864 if ($now - $success_start >= $stop_after_success) { 865 doprint "Test forced to stop after $stop_after_success seconds after success\n"; 866 last; 867 } 868 } 869 870 if ($full_line =~ /\[ backtrace testing \]/) { 871 $skip_call_trace = 1; 872 } 873 874 if ($full_line =~ /call trace:/i) { 875 if (!$bug && !$skip_call_trace) { 876 $bug = 1; 877 $failure_start = time; 878 } 879 } 880 881 if ($bug && defined($stop_after_failure) && 882 $stop_after_failure >= 0) { 883 my $now = time; 884 if ($now - $failure_start >= $stop_after_failure) { 885 doprint "Test forced to stop after $stop_after_failure seconds after failure\n"; 886 last; 887 } 888 } 889 890 if ($full_line =~ /\[ end of backtrace testing \]/) { 891 $skip_call_trace = 0; 892 } 893 894 if ($full_line =~ /Kernel panic -/) { 895 $failure_start = time; 896 $bug = 1; 897 } 898 899 if ($line =~ /\n/) { 900 $full_line = ""; 901 } 902 903 if ($stop_test_after > 0 && !$booted && !$bug) { 904 if (time - $monitor_start > $stop_test_after) { 905 doprint "STOP_TEST_AFTER ($stop_test_after seconds) timed out\n"; 906 $done = 1; 907 } 908 } 909 } 910 911 close(DMESG); 912 913 if ($bug) { 914 return 0 if ($in_bisect); 915 fail "failed - got a bug report" and return 0; 916 } 917 918 if (!$booted) { 919 return 0 if ($in_bisect); 920 fail "failed - never got a boot prompt." and return 0; 921 } 922 923 return 1; 924} 925 926sub install { 927 928 run_scp "$outputdir/$build_target", "$target_image" or 929 dodie "failed to copy image"; 930 931 my $install_mods = 0; 932 933 # should we process modules? 934 $install_mods = 0; 935 open(IN, "$output_config") or dodie("Can't read config file"); 936 while (<IN>) { 937 if (/CONFIG_MODULES(=y)?/) { 938 $install_mods = 1 if (defined($1)); 939 last; 940 } 941 } 942 close(IN); 943 944 if (!$install_mods) { 945 doprint "No modules needed\n"; 946 return; 947 } 948 949 run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or 950 dodie "Failed to install modules"; 951 952 my $modlib = "/lib/modules/$version"; 953 my $modtar = "ktest-mods.tar.bz2"; 954 955 run_ssh "rm -rf $modlib" or 956 dodie "failed to remove old mods: $modlib"; 957 958 # would be nice if scp -r did not follow symbolic links 959 run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or 960 dodie "making tarball"; 961 962 run_scp "$tmpdir/$modtar", "/tmp" or 963 dodie "failed to copy modules"; 964 965 unlink "$tmpdir/$modtar"; 966 967 run_ssh "'(cd / && tar xf /tmp/$modtar)'" or 968 dodie "failed to tar modules"; 969 970 run_ssh "rm -f /tmp/$modtar"; 971 972 return if (!defined($post_install)); 973 974 my $cp_post_install = $post_install; 975 $cp_post_install =~ s/\$KERNEL_VERSION/$version/g; 976 run_command "$cp_post_install" or 977 dodie "Failed to run post install"; 978} 979 980sub check_buildlog { 981 my ($patch) = @_; 982 983 my @files = `git show $patch | diffstat -l`; 984 985 open(IN, "git show $patch |") or 986 dodie "failed to show $patch"; 987 while (<IN>) { 988 if (m,^--- a/(.*),) { 989 chomp $1; 990 $files[$#files] = $1; 991 } 992 } 993 close(IN); 994 995 open(IN, $buildlog) or dodie "Can't open $buildlog"; 996 while (<IN>) { 997 if (/^\s*(.*?):.*(warning|error)/) { 998 my $err = $1; 999 foreach my $file (@files) { 1000 my $fullpath = "$builddir/$file"; 1001 if ($file eq $err || $fullpath eq $err) { 1002 fail "$file built with warnings" and return 0; 1003 } 1004 } 1005 } 1006 } 1007 close(IN); 1008 1009 return 1; 1010} 1011 1012sub make_oldconfig { 1013 my ($defconfig) = @_; 1014 1015 if (!run_command "$defconfig $make oldnoconfig") { 1016 # Perhaps oldnoconfig doesn't exist in this version of the kernel 1017 # try a yes '' | oldconfig 1018 doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; 1019 run_command "yes '' | $defconfig $make oldconfig" or 1020 dodie "failed make config oldconfig"; 1021 } 1022} 1023 1024sub build { 1025 my ($type) = @_; 1026 my $defconfig = ""; 1027 1028 unlink $buildlog; 1029 1030 if ($type =~ /^useconfig:(.*)/) { 1031 run_command "cp $1 $output_config" or 1032 dodie "could not copy $1 to .config"; 1033 1034 $type = "oldconfig"; 1035 } 1036 1037 # old config can ask questions 1038 if ($type eq "oldconfig") { 1039 $type = "oldnoconfig"; 1040 1041 # allow for empty configs 1042 run_command "touch $output_config"; 1043 1044 run_command "mv $output_config $outputdir/config_temp" or 1045 dodie "moving .config"; 1046 1047 if (!$noclean && !run_command "$make mrproper") { 1048 dodie "make mrproper"; 1049 } 1050 1051 run_command "mv $outputdir/config_temp $output_config" or 1052 dodie "moving config_temp"; 1053 1054 } elsif (!$noclean) { 1055 unlink "$output_config"; 1056 run_command "$make mrproper" or 1057 dodie "make mrproper"; 1058 } 1059 1060 # add something to distinguish this build 1061 open(OUT, "> $outputdir/localversion") or dodie("Can't make localversion file"); 1062 print OUT "$localversion\n"; 1063 close(OUT); 1064 1065 if (defined($minconfig)) { 1066 $defconfig = "KCONFIG_ALLCONFIG=$minconfig"; 1067 } 1068 1069 if ($type eq "oldnoconfig") { 1070 make_oldconfig $defconfig; 1071 } else { 1072 run_command "$defconfig $make $type" or 1073 dodie "failed make config"; 1074 } 1075 1076 $redirect = "$buildlog"; 1077 if (!run_command "$make $build_options") { 1078 undef $redirect; 1079 # bisect may need this to pass 1080 return 0 if ($in_bisect); 1081 fail "failed build" and return 0; 1082 } 1083 undef $redirect; 1084 1085 return 1; 1086} 1087 1088sub halt { 1089 if (!run_ssh "halt" or defined($power_off)) { 1090 if (defined($poweroff_after_halt)) { 1091 sleep $poweroff_after_halt; 1092 run_command "$power_off"; 1093 } 1094 } else { 1095 # nope? the zap it! 1096 run_command "$power_off"; 1097 } 1098} 1099 1100sub success { 1101 my ($i) = @_; 1102 1103 $successes++; 1104 1105 doprint "\n\n*******************************************\n"; 1106 doprint "*******************************************\n"; 1107 doprint "KTEST RESULT: TEST $i SUCCESS!!!! **\n"; 1108 doprint "*******************************************\n"; 1109 doprint "*******************************************\n"; 1110 1111 if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { 1112 doprint "Reboot and wait $sleep_time seconds\n"; 1113 reboot; 1114 start_monitor; 1115 wait_for_monitor $sleep_time; 1116 end_monitor; 1117 } 1118} 1119 1120sub get_version { 1121 # get the release name 1122 doprint "$make kernelrelease ... "; 1123 $version = `$make kernelrelease | tail -1`; 1124 chomp($version); 1125 doprint "$version\n"; 1126} 1127 1128sub answer_bisect { 1129 for (;;) { 1130 doprint "Pass or fail? [p/f]"; 1131 my $ans = <STDIN>; 1132 chomp $ans; 1133 if ($ans eq "p" || $ans eq "P") { 1134 return 1; 1135 } elsif ($ans eq "f" || $ans eq "F") { 1136 return 0; 1137 } else { 1138 print "Please answer 'P' or 'F'\n"; 1139 } 1140 } 1141} 1142 1143sub child_run_test { 1144 my $failed = 0; 1145 1146 # child should have no power 1147 $reboot_on_error = 0; 1148 $poweroff_on_error = 0; 1149 $die_on_failure = 1; 1150 1151 run_command $run_test or $failed = 1; 1152 exit $failed; 1153} 1154 1155my $child_done; 1156 1157sub child_finished { 1158 $child_done = 1; 1159} 1160 1161sub do_run_test { 1162 my $child_pid; 1163 my $child_exit; 1164 my $line; 1165 my $full_line; 1166 my $bug = 0; 1167 1168 wait_for_monitor 1; 1169 1170 doprint "run test $run_test\n"; 1171 1172 $child_done = 0; 1173 1174 $SIG{CHLD} = qw(child_finished); 1175 1176 $child_pid = fork; 1177 1178 child_run_test if (!$child_pid); 1179 1180 $full_line = ""; 1181 1182 do { 1183 $line = wait_for_input($monitor_fp, 1); 1184 if (defined($line)) { 1185 1186 # we are not guaranteed to get a full line 1187 $full_line .= $line; 1188 doprint $line; 1189 1190 if ($full_line =~ /call trace:/i) { 1191 $bug = 1; 1192 } 1193 1194 if ($full_line =~ /Kernel panic -/) { 1195 $bug = 1; 1196 } 1197 1198 if ($line =~ /\n/) { 1199 $full_line = ""; 1200 } 1201 } 1202 } while (!$child_done && !$bug); 1203 1204 if ($bug) { 1205 my $failure_start = time; 1206 my $now; 1207 do { 1208 $line = wait_for_input($monitor_fp, 1); 1209 if (defined($line)) { 1210 doprint $line; 1211 } 1212 $now = time; 1213 if ($now - $failure_start >= $stop_after_failure) { 1214 last; 1215 } 1216 } while (defined($line)); 1217 1218 doprint "Detected kernel crash!\n"; 1219 # kill the child with extreme prejudice 1220 kill 9, $child_pid; 1221 } 1222 1223 waitpid $child_pid, 0; 1224 $child_exit = $?; 1225 1226 if ($bug || $child_exit) { 1227 return 0 if $in_bisect; 1228 fail "test failed" and return 0; 1229 } 1230 return 1; 1231} 1232 1233sub run_git_bisect { 1234 my ($command) = @_; 1235 1236 doprint "$command ... "; 1237 1238 my $output = `$command 2>&1`; 1239 my $ret = $?; 1240 1241 logit $output; 1242 1243 if ($ret) { 1244 doprint "FAILED\n"; 1245 dodie "Failed to git bisect"; 1246 } 1247 1248 doprint "SUCCESS\n"; 1249 if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) { 1250 doprint "$1 [$2]\n"; 1251 } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) { 1252 $bisect_bad = $1; 1253 doprint "Found bad commit... $1\n"; 1254 return 0; 1255 } else { 1256 # we already logged it, just print it now. 1257 print $output; 1258 } 1259 1260 return 1; 1261} 1262 1263sub bisect_reboot { 1264 doprint "Reboot and sleep $bisect_sleep_time seconds\n"; 1265 reboot; 1266 start_monitor; 1267 wait_for_monitor $bisect_sleep_time; 1268 end_monitor; 1269} 1270 1271# returns 1 on success, 0 on failure, -1 on skip 1272sub run_bisect_test { 1273 my ($type, $buildtype) = @_; 1274 1275 my $failed = 0; 1276 my $result; 1277 my $output; 1278 my $ret; 1279 1280 $in_bisect = 1; 1281 1282 build $buildtype or $failed = 1; 1283 1284 if ($type ne "build") { 1285 if ($failed && $bisect_skip) { 1286 $in_bisect = 0; 1287 return -1; 1288 } 1289 dodie "Failed on build" if $failed; 1290 1291 # Now boot the box 1292 get_grub_index; 1293 get_version; 1294 install; 1295 1296 start_monitor; 1297 monitor or $failed = 1; 1298 1299 if ($type ne "boot") { 1300 if ($failed && $bisect_skip) { 1301 end_monitor; 1302 bisect_reboot; 1303 $in_bisect = 0; 1304 return -1; 1305 } 1306 dodie "Failed on boot" if $failed; 1307 1308 do_run_test or $failed = 1; 1309 } 1310 end_monitor; 1311 } 1312 1313 if ($failed) { 1314 $result = 0; 1315 } else { 1316 $result = 1; 1317 } 1318 1319 # reboot the box to a kernel we can ssh to 1320 if ($type ne "build") { 1321 bisect_reboot; 1322 } 1323 $in_bisect = 0; 1324 1325 return $result; 1326} 1327 1328sub run_bisect { 1329 my ($type) = @_; 1330 my $buildtype = "oldconfig"; 1331 1332 # We should have a minconfig to use? 1333 if (defined($minconfig)) { 1334 $buildtype = "useconfig:$minconfig"; 1335 } 1336 1337 my $ret = run_bisect_test $type, $buildtype; 1338 1339 if ($bisect_manual) { 1340 $ret = answer_bisect; 1341 } 1342 1343 # Are we looking for where it worked, not failed? 1344 if ($reverse_bisect) { 1345 $ret = !$ret; 1346 } 1347 1348 if ($ret > 0) { 1349 return "good"; 1350 } elsif ($ret == 0) { 1351 return "bad"; 1352 } elsif ($bisect_skip) { 1353 doprint "HIT A BAD COMMIT ... SKIPPING\n"; 1354 return "skip"; 1355 } 1356} 1357 1358sub bisect { 1359 my ($i) = @_; 1360 1361 my $result; 1362 1363 die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"})); 1364 die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"})); 1365 die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"})); 1366 1367 my $good = $opt{"BISECT_GOOD[$i]"}; 1368 my $bad = $opt{"BISECT_BAD[$i]"}; 1369 my $type = $opt{"BISECT_TYPE[$i]"}; 1370 my $start = $opt{"BISECT_START[$i]"}; 1371 my $replay = $opt{"BISECT_REPLAY[$i]"}; 1372 my $start_files = $opt{"BISECT_FILES[$i]"}; 1373 1374 if (defined($start_files)) { 1375 $start_files = " -- " . $start_files; 1376 } else { 1377 $start_files = ""; 1378 } 1379 1380 # convert to true sha1's 1381 $good = get_sha1($good); 1382 $bad = get_sha1($bad); 1383 1384 if (defined($opt{"BISECT_REVERSE[$i]"}) && 1385 $opt{"BISECT_REVERSE[$i]"} == 1) { 1386 doprint "Performing a reverse bisect (bad is good, good is bad!)\n"; 1387 $reverse_bisect = 1; 1388 } else { 1389 $reverse_bisect = 0; 1390 } 1391 1392 # Can't have a test without having a test to run 1393 if ($type eq "test" && !defined($run_test)) { 1394 $type = "boot"; 1395 } 1396 1397 my $check = $opt{"BISECT_CHECK[$i]"}; 1398 if (defined($check) && $check ne "0") { 1399 1400 # get current HEAD 1401 my $head = get_sha1("HEAD"); 1402 1403 if ($check ne "good") { 1404 doprint "TESTING BISECT BAD [$bad]\n"; 1405 run_command "git checkout $bad" or 1406 die "Failed to checkout $bad"; 1407 1408 $result = run_bisect $type; 1409 1410 if ($result ne "bad") { 1411 fail "Tested BISECT_BAD [$bad] and it succeeded" and return 0; 1412 } 1413 } 1414 1415 if ($check ne "bad") { 1416 doprint "TESTING BISECT GOOD [$good]\n"; 1417 run_command "git checkout $good" or 1418 die "Failed to checkout $good"; 1419 1420 $result = run_bisect $type; 1421 1422 if ($result ne "good") { 1423 fail "Tested BISECT_GOOD [$good] and it failed" and return 0; 1424 } 1425 } 1426 1427 # checkout where we started 1428 run_command "git checkout $head" or 1429 die "Failed to checkout $head"; 1430 } 1431 1432 run_command "git bisect start$start_files" or 1433 dodie "could not start bisect"; 1434 1435 run_command "git bisect good $good" or 1436 dodie "could not set bisect good to $good"; 1437 1438 run_git_bisect "git bisect bad $bad" or 1439 dodie "could not set bisect bad to $bad"; 1440 1441 if (defined($replay)) { 1442 run_command "git bisect replay $replay" or 1443 dodie "failed to run replay"; 1444 } 1445 1446 if (defined($start)) { 1447 run_command "git checkout $start" or 1448 dodie "failed to checkout $start"; 1449 } 1450 1451 my $test; 1452 do { 1453 $result = run_bisect $type; 1454 $test = run_git_bisect "git bisect $result"; 1455 } while ($test); 1456 1457 run_command "git bisect log" or 1458 dodie "could not capture git bisect log"; 1459 1460 run_command "git bisect reset" or 1461 dodie "could not reset git bisect"; 1462 1463 doprint "Bad commit was [$bisect_bad]\n"; 1464 1465 success $i; 1466} 1467 1468my %config_ignore; 1469my %config_set; 1470 1471my %config_list; 1472my %null_config; 1473 1474my %dependency; 1475 1476sub process_config_ignore { 1477 my ($config) = @_; 1478 1479 open (IN, $config) 1480 or dodie "Failed to read $config"; 1481 1482 while (<IN>) { 1483 if (/^(.*?(CONFIG\S*)(=.*| is not set))/) { 1484 $config_ignore{$2} = $1; 1485 } 1486 } 1487 1488 close(IN); 1489} 1490 1491sub read_current_config { 1492 my ($config_ref) = @_; 1493 1494 %{$config_ref} = (); 1495 undef %{$config_ref}; 1496 1497 my @key = keys %{$config_ref}; 1498 if ($#key >= 0) { 1499 print "did not delete!\n"; 1500 exit; 1501 } 1502 open (IN, "$output_config"); 1503 1504 while (<IN>) { 1505 if (/^(CONFIG\S+)=(.*)/) { 1506 ${$config_ref}{$1} = $2; 1507 } 1508 } 1509 close(IN); 1510} 1511 1512sub get_dependencies { 1513 my ($config) = @_; 1514 1515 my $arr = $dependency{$config}; 1516 if (!defined($arr)) { 1517 return (); 1518 } 1519 1520 my @deps = @{$arr}; 1521 1522 foreach my $dep (@{$arr}) { 1523 print "ADD DEP $dep\n"; 1524 @deps = (@deps, get_dependencies $dep); 1525 } 1526 1527 return @deps; 1528} 1529 1530sub create_config { 1531 my @configs = @_; 1532 1533 open(OUT, ">$output_config") or dodie "Can not write to $output_config"; 1534 1535 foreach my $config (@configs) { 1536 print OUT "$config_set{$config}\n"; 1537 my @deps = get_dependencies $config; 1538 foreach my $dep (@deps) { 1539 print OUT "$config_set{$dep}\n"; 1540 } 1541 } 1542 1543 foreach my $config (keys %config_ignore) { 1544 print OUT "$config_ignore{$config}\n"; 1545 } 1546 close(OUT); 1547 1548# exit; 1549 make_oldconfig ""; 1550} 1551 1552sub compare_configs { 1553 my (%a, %b) = @_; 1554 1555 foreach my $item (keys %a) { 1556 if (!defined($b{$item})) { 1557 print "diff $item\n"; 1558 return 1; 1559 } 1560 delete $b{$item}; 1561 } 1562 1563 my @keys = keys %b; 1564 if ($#keys) { 1565 print "diff2 $keys[0]\n"; 1566 } 1567 return -1 if ($#keys >= 0); 1568 1569 return 0; 1570} 1571 1572sub run_config_bisect_test { 1573 my ($type) = @_; 1574 1575 return run_bisect_test $type, "oldconfig"; 1576} 1577 1578sub process_passed { 1579 my (%configs) = @_; 1580 1581 doprint "These configs had no failure: (Enabling them for further compiles)\n"; 1582 # Passed! All these configs are part of a good compile. 1583 # Add them to the min options. 1584 foreach my $config (keys %configs) { 1585 if (defined($config_list{$config})) { 1586 doprint " removing $config\n"; 1587 $config_ignore{$config} = $config_list{$config}; 1588 delete $config_list{$config}; 1589 } 1590 } 1591 doprint "config copied to $outputdir/config_good\n"; 1592 run_command "cp -f $output_config $outputdir/config_good"; 1593} 1594 1595sub process_failed { 1596 my ($config) = @_; 1597 1598 doprint "\n\n***************************************\n"; 1599 doprint "Found bad config: $config\n"; 1600 doprint "***************************************\n\n"; 1601} 1602 1603sub run_config_bisect { 1604 1605 my @start_list = keys %config_list; 1606 1607 if ($#start_list < 0) { 1608 doprint "No more configs to test!!!\n"; 1609 return -1; 1610 } 1611 1612 doprint "***** RUN TEST ***\n"; 1613 my $type = $opt{"CONFIG_BISECT_TYPE[$iteration]"}; 1614 my $ret; 1615 my %current_config; 1616 1617 my $count = $#start_list + 1; 1618 doprint " $count configs to test\n"; 1619 1620 my $half = int($#start_list / 2); 1621 1622 do { 1623 my @tophalf = @start_list[0 .. $half]; 1624 1625 create_config @tophalf; 1626 read_current_config \%current_config; 1627 1628 $count = $#tophalf + 1; 1629 doprint "Testing $count configs\n"; 1630 my $found = 0; 1631 # make sure we test something 1632 foreach my $config (@tophalf) { 1633 if (defined($current_config{$config})) { 1634 logit " $config\n"; 1635 $found = 1; 1636 } 1637 } 1638 if (!$found) { 1639 # try the other half 1640 doprint "Top half produced no set configs, trying bottom half\n"; 1641 @tophalf = @start_list[$half .. $#start_list]; 1642 create_config @tophalf; 1643 read_current_config \%current_config; 1644 foreach my $config (@tophalf) { 1645 if (defined($current_config{$config})) { 1646 logit " $config\n"; 1647 $found = 1; 1648 } 1649 } 1650 if (!$found) { 1651 doprint "Failed: Can't make new config with current configs\n"; 1652 foreach my $config (@start_list) { 1653 doprint " CONFIG: $config\n"; 1654 } 1655 return -1; 1656 } 1657 $count = $#tophalf + 1; 1658 doprint "Testing $count configs\n"; 1659 } 1660 1661 $ret = run_config_bisect_test $type; 1662 if ($bisect_manual) { 1663 $ret = answer_bisect; 1664 } 1665 if ($ret) { 1666 process_passed %current_config; 1667 return 0; 1668 } 1669 1670 doprint "This config had a failure.\n"; 1671 doprint "Removing these configs that were not set in this config:\n"; 1672 doprint "config copied to $outputdir/config_bad\n"; 1673 run_command "cp -f $output_config $outputdir/config_bad"; 1674 1675 # A config exists in this group that was bad. 1676 foreach my $config (keys %config_list) { 1677 if (!defined($current_config{$config})) { 1678 doprint " removing $config\n"; 1679 delete $config_list{$config}; 1680 } 1681 } 1682 1683 @start_list = @tophalf; 1684 1685 if ($#start_list == 0) { 1686 process_failed $start_list[0]; 1687 return 1; 1688 } 1689 1690 # remove half the configs we are looking at and see if 1691 # they are good. 1692 $half = int($#start_list / 2); 1693 } while ($half > 0); 1694 1695 # we found a single config, try it again unless we are running manually 1696 1697 if ($bisect_manual) { 1698 process_failed $start_list[0]; 1699 return 1; 1700 } 1701 1702 my @tophalf = @start_list[0 .. 0]; 1703 1704 $ret = run_config_bisect_test $type; 1705 if ($ret) { 1706 process_passed %current_config; 1707 return 0; 1708 } 1709 1710 process_failed $start_list[0]; 1711 return 1; 1712} 1713 1714sub config_bisect { 1715 my ($i) = @_; 1716 1717 my $start_config = $opt{"CONFIG_BISECT[$i]"}; 1718 1719 my $tmpconfig = "$tmpdir/use_config"; 1720 1721 # Make the file with the bad config and the min config 1722 if (defined($minconfig)) { 1723 # read the min config for things to ignore 1724 run_command "cp $minconfig $tmpconfig" or 1725 dodie "failed to copy $minconfig to $tmpconfig"; 1726 } else { 1727 unlink $tmpconfig; 1728 } 1729 1730 # Add other configs 1731 if (defined($addconfig)) { 1732 run_command "cat $addconfig >> $tmpconfig" or 1733 dodie "failed to append $addconfig"; 1734 } 1735 1736 my $defconfig = ""; 1737 if (-f $tmpconfig) { 1738 $defconfig = "KCONFIG_ALLCONFIG=$tmpconfig"; 1739 process_config_ignore $tmpconfig; 1740 } 1741 1742 # now process the start config 1743 run_command "cp $start_config $output_config" or 1744 dodie "failed to copy $start_config to $output_config"; 1745 1746 # read directly what we want to check 1747 my %config_check; 1748 open (IN, $output_config) 1749 or dodie "faied to open $output_config"; 1750 1751 while (<IN>) { 1752 if (/^((CONFIG\S*)=.*)/) { 1753 $config_check{$2} = $1; 1754 } 1755 } 1756 close(IN); 1757 1758 # Now run oldconfig with the minconfig (and addconfigs) 1759 make_oldconfig $defconfig; 1760 1761 # check to see what we lost (or gained) 1762 open (IN, $output_config) 1763 or dodie "Failed to read $start_config"; 1764 1765 my %removed_configs; 1766 my %added_configs; 1767 1768 while (<IN>) { 1769 if (/^((CONFIG\S*)=.*)/) { 1770 # save off all options 1771 $config_set{$2} = $1; 1772 if (defined($config_check{$2})) { 1773 if (defined($config_ignore{$2})) { 1774 $removed_configs{$2} = $1; 1775 } else { 1776 $config_list{$2} = $1; 1777 } 1778 } elsif (!defined($config_ignore{$2})) { 1779 $added_configs{$2} = $1; 1780 $config_list{$2} = $1; 1781 } 1782 } 1783 } 1784 close(IN); 1785 1786 my @confs = keys %removed_configs; 1787 if ($#confs >= 0) { 1788 doprint "Configs overridden by default configs and removed from check:\n"; 1789 foreach my $config (@confs) { 1790 doprint " $config\n"; 1791 } 1792 } 1793 @confs = keys %added_configs; 1794 if ($#confs >= 0) { 1795 doprint "Configs appearing in make oldconfig and added:\n"; 1796 foreach my $config (@confs) { 1797 doprint " $config\n"; 1798 } 1799 } 1800 1801 my %config_test; 1802 my $once = 0; 1803 1804 # Sometimes kconfig does weird things. We must make sure 1805 # that the config we autocreate has everything we need 1806 # to test, otherwise we may miss testing configs, or 1807 # may not be able to create a new config. 1808 # Here we create a config with everything set. 1809 create_config (keys %config_list); 1810 read_current_config \%config_test; 1811 foreach my $config (keys %config_list) { 1812 if (!defined($config_test{$config})) { 1813 if (!$once) { 1814 $once = 1; 1815 doprint "Configs not produced by kconfig (will not be checked):\n"; 1816 } 1817 doprint " $config\n"; 1818 delete $config_list{$config}; 1819 } 1820 } 1821 my $ret; 1822 do { 1823 $ret = run_config_bisect; 1824 } while (!$ret); 1825 1826 return $ret if ($ret < 0); 1827 1828 success $i; 1829} 1830 1831sub patchcheck_reboot { 1832 doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; 1833 reboot; 1834 start_monitor; 1835 wait_for_monitor $patchcheck_sleep_time; 1836 end_monitor; 1837} 1838 1839sub patchcheck { 1840 my ($i) = @_; 1841 1842 die "PATCHCHECK_START[$i] not defined\n" 1843 if (!defined($opt{"PATCHCHECK_START[$i]"})); 1844 die "PATCHCHECK_TYPE[$i] not defined\n" 1845 if (!defined($opt{"PATCHCHECK_TYPE[$i]"})); 1846 1847 my $start = $opt{"PATCHCHECK_START[$i]"}; 1848 1849 my $end = "HEAD"; 1850 if (defined($opt{"PATCHCHECK_END[$i]"})) { 1851 $end = $opt{"PATCHCHECK_END[$i]"}; 1852 } 1853 1854 # Get the true sha1's since we can use things like HEAD~3 1855 $start = get_sha1($start); 1856 $end = get_sha1($end); 1857 1858 my $type = $opt{"PATCHCHECK_TYPE[$i]"}; 1859 1860 # Can't have a test without having a test to run 1861 if ($type eq "test" && !defined($run_test)) { 1862 $type = "boot"; 1863 } 1864 1865 open (IN, "git log --pretty=oneline $end|") or 1866 dodie "could not get git list"; 1867 1868 my @list; 1869 1870 while (<IN>) { 1871 chomp; 1872 $list[$#list+1] = $_; 1873 last if (/^$start/); 1874 } 1875 close(IN); 1876 1877 if ($list[$#list] !~ /^$start/) { 1878 fail "SHA1 $start not found"; 1879 } 1880 1881 # go backwards in the list 1882 @list = reverse @list; 1883 1884 my $save_clean = $noclean; 1885 1886 $in_patchcheck = 1; 1887 foreach my $item (@list) { 1888 my $sha1 = $item; 1889 $sha1 =~ s/^([[:xdigit:]]+).*/$1/; 1890 1891 doprint "\nProcessing commit $item\n\n"; 1892 1893 run_command "git checkout $sha1" or 1894 die "Failed to checkout $sha1"; 1895 1896 # only clean on the first and last patch 1897 if ($item eq $list[0] || 1898 $item eq $list[$#list]) { 1899 $noclean = $save_clean; 1900 } else { 1901 $noclean = 1; 1902 } 1903 1904 if (defined($minconfig)) { 1905 build "useconfig:$minconfig" or return 0; 1906 } else { 1907 # ?? no config to use? 1908 build "oldconfig" or return 0; 1909 } 1910 1911 check_buildlog $sha1 or return 0; 1912 1913 next if ($type eq "build"); 1914 1915 get_grub_index; 1916 get_version; 1917 install; 1918 1919 my $failed = 0; 1920 1921 start_monitor; 1922 monitor or $failed = 1; 1923 1924 if (!$failed && $type ne "boot"){ 1925 do_run_test or $failed = 1; 1926 } 1927 end_monitor; 1928 return 0 if ($failed); 1929 1930 patchcheck_reboot; 1931 1932 } 1933 $in_patchcheck = 0; 1934 success $i; 1935 1936 return 1; 1937} 1938 1939$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n"; 1940 1941if ($#ARGV == 0) { 1942 $ktest_config = $ARGV[0]; 1943 if (! -f $ktest_config) { 1944 print "$ktest_config does not exist.\n"; 1945 my $ans; 1946 for (;;) { 1947 print "Create it? [Y/n] "; 1948 $ans = <STDIN>; 1949 chomp $ans; 1950 if ($ans =~ /^\s*$/) { 1951 $ans = "y"; 1952 } 1953 last if ($ans =~ /^y$/i || $ans =~ /^n$/i); 1954 print "Please answer either 'y' or 'n'.\n"; 1955 } 1956 if ($ans !~ /^y$/i) { 1957 exit 0; 1958 } 1959 } 1960} else { 1961 $ktest_config = "ktest.conf"; 1962} 1963 1964if (! -f $ktest_config) { 1965 open(OUT, ">$ktest_config") or die "Can not create $ktest_config"; 1966 print OUT << "EOF" 1967# Generated by ktest.pl 1968# 1969# Define each test with TEST_START 1970# The config options below it will override the defaults 1971TEST_START 1972 1973DEFAULTS 1974EOF 1975; 1976 close(OUT); 1977} 1978read_config $ktest_config; 1979 1980# Append any configs entered in manually to the config file. 1981my @new_configs = keys %entered_configs; 1982if ($#new_configs >= 0) { 1983 print "\nAppending entered in configs to $ktest_config\n"; 1984 open(OUT, ">>$ktest_config") or die "Can not append to $ktest_config"; 1985 foreach my $config (@new_configs) { 1986 print OUT "$config = $entered_configs{$config}\n"; 1987 $opt{$config} = $entered_configs{$config}; 1988 } 1989} 1990 1991if ($opt{"CLEAR_LOG"} && defined($opt{"LOG_FILE"})) { 1992 unlink $opt{"LOG_FILE"}; 1993} 1994 1995doprint "\n\nSTARTING AUTOMATED TESTS\n\n"; 1996 1997for (my $i = 0, my $repeat = 1; $i <= $opt{"NUM_TESTS"}; $i += $repeat) { 1998 1999 if (!$i) { 2000 doprint "DEFAULT OPTIONS:\n"; 2001 } else { 2002 doprint "\nTEST $i OPTIONS"; 2003 if (defined($repeat_tests{$i})) { 2004 $repeat = $repeat_tests{$i}; 2005 doprint " ITERATE $repeat"; 2006 } 2007 doprint "\n"; 2008 } 2009 2010 foreach my $option (sort keys %opt) { 2011 2012 if ($option =~ /\[(\d+)\]$/) { 2013 next if ($i != $1); 2014 } else { 2015 next if ($i); 2016 } 2017 2018 doprint "$option = $opt{$option}\n"; 2019 } 2020} 2021 2022sub __set_test_option { 2023 my ($name, $i) = @_; 2024 2025 my $option = "$name\[$i\]"; 2026 2027 if (defined($opt{$option})) { 2028 return $opt{$option}; 2029 } 2030 2031 foreach my $test (keys %repeat_tests) { 2032 if ($i >= $test && 2033 $i < $test + $repeat_tests{$test}) { 2034 $option = "$name\[$test\]"; 2035 if (defined($opt{$option})) { 2036 return $opt{$option}; 2037 } 2038 } 2039 } 2040 2041 if (defined($opt{$name})) { 2042 return $opt{$name}; 2043 } 2044 2045 return undef; 2046} 2047 2048sub eval_option { 2049 my ($option, $i) = @_; 2050 2051 # Add space to evaluate the character before $ 2052 $option = " $option"; 2053 my $retval = ""; 2054 2055 while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { 2056 my $start = $1; 2057 my $var = $2; 2058 my $end = $3; 2059 2060 # Append beginning of line 2061 $retval = "$retval$start"; 2062 2063 # If the iteration option OPT[$i] exists, then use that. 2064 # otherwise see if the default OPT (without [$i]) exists. 2065 2066 my $o = "$var\[$i\]"; 2067 2068 if (defined($opt{$o})) { 2069 $o = $opt{$o}; 2070 $retval = "$retval$o"; 2071 } elsif (defined($opt{$var})) { 2072 $o = $opt{$var}; 2073 $retval = "$retval$o"; 2074 } else { 2075 $retval = "$retval\$\{$var\}"; 2076 } 2077 2078 $option = $end; 2079 } 2080 2081 $retval = "$retval$option"; 2082 2083 $retval =~ s/^ //; 2084 2085 return $retval; 2086} 2087 2088sub set_test_option { 2089 my ($name, $i) = @_; 2090 2091 my $option = __set_test_option($name, $i); 2092 return $option if (!defined($option)); 2093 2094 my $prev = ""; 2095 2096 # Since an option can evaluate to another option, 2097 # keep iterating until we do not evaluate any more 2098 # options. 2099 my $r = 0; 2100 while ($prev ne $option) { 2101 # Check for recursive evaluations. 2102 # 100 deep should be more than enough. 2103 if ($r++ > 100) { 2104 die "Over 100 evaluations accurred with $name\n" . 2105 "Check for recursive variables\n"; 2106 } 2107 $prev = $option; 2108 $option = eval_option($option, $i); 2109 } 2110 2111 return $option; 2112} 2113 2114# First we need to do is the builds 2115for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { 2116 2117 $iteration = $i; 2118 2119 my $makecmd = set_test_option("MAKE_CMD", $i); 2120 2121 $machine = set_test_option("MACHINE", $i); 2122 $ssh_user = set_test_option("SSH_USER", $i); 2123 $tmpdir = set_test_option("TMP_DIR", $i); 2124 $outputdir = set_test_option("OUTPUT_DIR", $i); 2125 $builddir = set_test_option("BUILD_DIR", $i); 2126 $test_type = set_test_option("TEST_TYPE", $i); 2127 $build_type = set_test_option("BUILD_TYPE", $i); 2128 $build_options = set_test_option("BUILD_OPTIONS", $i); 2129 $power_cycle = set_test_option("POWER_CYCLE", $i); 2130 $reboot = set_test_option("REBOOT", $i); 2131 $noclean = set_test_option("BUILD_NOCLEAN", $i); 2132 $minconfig = set_test_option("MIN_CONFIG", $i); 2133 $run_test = set_test_option("TEST", $i); 2134 $addconfig = set_test_option("ADD_CONFIG", $i); 2135 $reboot_type = set_test_option("REBOOT_TYPE", $i); 2136 $grub_menu = set_test_option("GRUB_MENU", $i); 2137 $post_install = set_test_option("POST_INSTALL", $i); 2138 $reboot_script = set_test_option("REBOOT_SCRIPT", $i); 2139 $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i); 2140 $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i); 2141 $die_on_failure = set_test_option("DIE_ON_FAILURE", $i); 2142 $power_off = set_test_option("POWER_OFF", $i); 2143 $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i); 2144 $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i); 2145 $sleep_time = set_test_option("SLEEP_TIME", $i); 2146 $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i); 2147 $patchcheck_sleep_time = set_test_option("PATCHCHECK_SLEEP_TIME", $i); 2148 $bisect_manual = set_test_option("BISECT_MANUAL", $i); 2149 $bisect_skip = set_test_option("BISECT_SKIP", $i); 2150 $store_failures = set_test_option("STORE_FAILURES", $i); 2151 $timeout = set_test_option("TIMEOUT", $i); 2152 $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i); 2153 $console = set_test_option("CONSOLE", $i); 2154 $success_line = set_test_option("SUCCESS_LINE", $i); 2155 $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i); 2156 $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i); 2157 $stop_test_after = set_test_option("STOP_TEST_AFTER", $i); 2158 $build_target = set_test_option("BUILD_TARGET", $i); 2159 $ssh_exec = set_test_option("SSH_EXEC", $i); 2160 $scp_to_target = set_test_option("SCP_TO_TARGET", $i); 2161 $target_image = set_test_option("TARGET_IMAGE", $i); 2162 $localversion = set_test_option("LOCALVERSION", $i); 2163 2164 chdir $builddir || die "can't change directory to $builddir"; 2165 2166 if (!-d $tmpdir) { 2167 mkpath($tmpdir) or 2168 die "can't create $tmpdir"; 2169 } 2170 2171 $ENV{"SSH_USER"} = $ssh_user; 2172 $ENV{"MACHINE"} = $machine; 2173 2174 $target = "$ssh_user\@$machine"; 2175 2176 $buildlog = "$tmpdir/buildlog-$machine"; 2177 $dmesg = "$tmpdir/dmesg-$machine"; 2178 $make = "$makecmd O=$outputdir"; 2179 $output_config = "$outputdir/.config"; 2180 2181 if ($reboot_type eq "grub") { 2182 dodie "GRUB_MENU not defined" if (!defined($grub_menu)); 2183 } elsif (!defined($reboot_script)) { 2184 dodie "REBOOT_SCRIPT not defined" 2185 } 2186 2187 my $run_type = $build_type; 2188 if ($test_type eq "patchcheck") { 2189 $run_type = $opt{"PATCHCHECK_TYPE[$i]"}; 2190 } elsif ($test_type eq "bisect") { 2191 $run_type = $opt{"BISECT_TYPE[$i]"}; 2192 } elsif ($test_type eq "config_bisect") { 2193 $run_type = $opt{"CONFIG_BISECT_TYPE[$i]"}; 2194 } 2195 2196 # mistake in config file? 2197 if (!defined($run_type)) { 2198 $run_type = "ERROR"; 2199 } 2200 2201 doprint "\n\n"; 2202 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n"; 2203 2204 unlink $dmesg; 2205 unlink $buildlog; 2206 2207 if (!defined($minconfig)) { 2208 $minconfig = $addconfig; 2209 2210 } elsif (defined($addconfig)) { 2211 run_command "cat $addconfig $minconfig > $tmpdir/add_config" or 2212 dodie "Failed to create temp config"; 2213 $minconfig = "$tmpdir/add_config"; 2214 } 2215 2216 my $checkout = $opt{"CHECKOUT[$i]"}; 2217 if (defined($checkout)) { 2218 run_command "git checkout $checkout" or 2219 die "failed to checkout $checkout"; 2220 } 2221 2222 if ($test_type eq "bisect") { 2223 bisect $i; 2224 next; 2225 } elsif ($test_type eq "config_bisect") { 2226 config_bisect $i; 2227 next; 2228 } elsif ($test_type eq "patchcheck") { 2229 patchcheck $i; 2230 next; 2231 } 2232 2233 if ($build_type ne "nobuild") { 2234 build $build_type or next; 2235 } 2236 2237 if ($test_type ne "build") { 2238 get_grub_index; 2239 get_version; 2240 install; 2241 2242 my $failed = 0; 2243 start_monitor; 2244 monitor or $failed = 1;; 2245 2246 if (!$failed && $test_type ne "boot" && defined($run_test)) { 2247 do_run_test or $failed = 1; 2248 } 2249 end_monitor; 2250 next if ($failed); 2251 } 2252 2253 success $i; 2254} 2255 2256if ($opt{"POWEROFF_ON_SUCCESS"}) { 2257 halt; 2258} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) { 2259 reboot; 2260} 2261 2262doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n"; 2263 2264exit 0; 2265