1*4882a593Smuzhiyun#!/usr/bin/perl -w 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# Copyright 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun 7*4882a593Smuzhiyunuse strict; 8*4882a593Smuzhiyunuse IPC::Open2; 9*4882a593Smuzhiyunuse Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); 10*4882a593Smuzhiyunuse File::Path qw(mkpath); 11*4882a593Smuzhiyunuse File::Copy qw(cp); 12*4882a593Smuzhiyunuse FileHandle; 13*4882a593Smuzhiyunuse FindBin; 14*4882a593Smuzhiyunuse IO::Handle; 15*4882a593Smuzhiyun 16*4882a593Smuzhiyunmy $VERSION = "0.2"; 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun$| = 1; 19*4882a593Smuzhiyun 20*4882a593Smuzhiyunmy %opt; 21*4882a593Smuzhiyunmy %repeat_tests; 22*4882a593Smuzhiyunmy %repeats; 23*4882a593Smuzhiyunmy %evals; 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun#default opts 26*4882a593Smuzhiyunmy %default = ( 27*4882a593Smuzhiyun "MAILER" => "sendmail", # default mailer 28*4882a593Smuzhiyun "EMAIL_ON_ERROR" => 1, 29*4882a593Smuzhiyun "EMAIL_WHEN_FINISHED" => 1, 30*4882a593Smuzhiyun "EMAIL_WHEN_CANCELED" => 0, 31*4882a593Smuzhiyun "EMAIL_WHEN_STARTED" => 0, 32*4882a593Smuzhiyun "NUM_TESTS" => 1, 33*4882a593Smuzhiyun "TEST_TYPE" => "build", 34*4882a593Smuzhiyun "BUILD_TYPE" => "oldconfig", 35*4882a593Smuzhiyun "MAKE_CMD" => "make", 36*4882a593Smuzhiyun "CLOSE_CONSOLE_SIGNAL" => "INT", 37*4882a593Smuzhiyun "TIMEOUT" => 120, 38*4882a593Smuzhiyun "TMP_DIR" => "/tmp/ktest/\${MACHINE}", 39*4882a593Smuzhiyun "SLEEP_TIME" => 60, # sleep time between tests 40*4882a593Smuzhiyun "BUILD_NOCLEAN" => 0, 41*4882a593Smuzhiyun "REBOOT_ON_ERROR" => 0, 42*4882a593Smuzhiyun "POWEROFF_ON_ERROR" => 0, 43*4882a593Smuzhiyun "REBOOT_ON_SUCCESS" => 1, 44*4882a593Smuzhiyun "POWEROFF_ON_SUCCESS" => 0, 45*4882a593Smuzhiyun "BUILD_OPTIONS" => "", 46*4882a593Smuzhiyun "BISECT_SLEEP_TIME" => 60, # sleep time between bisects 47*4882a593Smuzhiyun "PATCHCHECK_SLEEP_TIME" => 60, # sleep time between patch checks 48*4882a593Smuzhiyun "CLEAR_LOG" => 0, 49*4882a593Smuzhiyun "BISECT_MANUAL" => 0, 50*4882a593Smuzhiyun "BISECT_SKIP" => 1, 51*4882a593Smuzhiyun "BISECT_TRIES" => 1, 52*4882a593Smuzhiyun "MIN_CONFIG_TYPE" => "boot", 53*4882a593Smuzhiyun "SUCCESS_LINE" => "login:", 54*4882a593Smuzhiyun "DETECT_TRIPLE_FAULT" => 1, 55*4882a593Smuzhiyun "NO_INSTALL" => 0, 56*4882a593Smuzhiyun "BOOTED_TIMEOUT" => 1, 57*4882a593Smuzhiyun "DIE_ON_FAILURE" => 1, 58*4882a593Smuzhiyun "SSH_EXEC" => "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND", 59*4882a593Smuzhiyun "SCP_TO_TARGET" => "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE", 60*4882a593Smuzhiyun "SCP_TO_TARGET_INSTALL" => "\${SCP_TO_TARGET}", 61*4882a593Smuzhiyun "REBOOT" => "ssh \$SSH_USER\@\$MACHINE reboot", 62*4882a593Smuzhiyun "REBOOT_RETURN_CODE" => 255, 63*4882a593Smuzhiyun "STOP_AFTER_SUCCESS" => 10, 64*4882a593Smuzhiyun "STOP_AFTER_FAILURE" => 60, 65*4882a593Smuzhiyun "STOP_TEST_AFTER" => 600, 66*4882a593Smuzhiyun "MAX_MONITOR_WAIT" => 1800, 67*4882a593Smuzhiyun "GRUB_REBOOT" => "grub2-reboot", 68*4882a593Smuzhiyun "GRUB_BLS_GET" => "grubby --info=ALL", 69*4882a593Smuzhiyun "SYSLINUX" => "extlinux", 70*4882a593Smuzhiyun "SYSLINUX_PATH" => "/boot/extlinux", 71*4882a593Smuzhiyun "CONNECT_TIMEOUT" => 25, 72*4882a593Smuzhiyun 73*4882a593Smuzhiyun# required, and we will ask users if they don't have them but we keep the default 74*4882a593Smuzhiyun# value something that is common. 75*4882a593Smuzhiyun "REBOOT_TYPE" => "grub", 76*4882a593Smuzhiyun "LOCALVERSION" => "-test", 77*4882a593Smuzhiyun "SSH_USER" => "root", 78*4882a593Smuzhiyun "BUILD_TARGET" => "arch/x86/boot/bzImage", 79*4882a593Smuzhiyun "TARGET_IMAGE" => "/boot/vmlinuz-test", 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun "LOG_FILE" => undef, 82*4882a593Smuzhiyun "IGNORE_UNUSED" => 0, 83*4882a593Smuzhiyun); 84*4882a593Smuzhiyun 85*4882a593Smuzhiyunmy $test_log_start = 0; 86*4882a593Smuzhiyun 87*4882a593Smuzhiyunmy $ktest_config = "ktest.conf"; 88*4882a593Smuzhiyunmy $version; 89*4882a593Smuzhiyunmy $have_version = 0; 90*4882a593Smuzhiyunmy $machine; 91*4882a593Smuzhiyunmy $last_machine; 92*4882a593Smuzhiyunmy $ssh_user; 93*4882a593Smuzhiyunmy $tmpdir; 94*4882a593Smuzhiyunmy $builddir; 95*4882a593Smuzhiyunmy $outputdir; 96*4882a593Smuzhiyunmy $output_config; 97*4882a593Smuzhiyunmy $test_type; 98*4882a593Smuzhiyunmy $build_type; 99*4882a593Smuzhiyunmy $build_options; 100*4882a593Smuzhiyunmy $final_post_ktest; 101*4882a593Smuzhiyunmy $pre_ktest; 102*4882a593Smuzhiyunmy $post_ktest; 103*4882a593Smuzhiyunmy $pre_test; 104*4882a593Smuzhiyunmy $pre_test_die; 105*4882a593Smuzhiyunmy $post_test; 106*4882a593Smuzhiyunmy $pre_build; 107*4882a593Smuzhiyunmy $post_build; 108*4882a593Smuzhiyunmy $pre_build_die; 109*4882a593Smuzhiyunmy $post_build_die; 110*4882a593Smuzhiyunmy $reboot_type; 111*4882a593Smuzhiyunmy $reboot_script; 112*4882a593Smuzhiyunmy $power_cycle; 113*4882a593Smuzhiyunmy $reboot; 114*4882a593Smuzhiyunmy $reboot_return_code; 115*4882a593Smuzhiyunmy $reboot_on_error; 116*4882a593Smuzhiyunmy $switch_to_good; 117*4882a593Smuzhiyunmy $switch_to_test; 118*4882a593Smuzhiyunmy $poweroff_on_error; 119*4882a593Smuzhiyunmy $reboot_on_success; 120*4882a593Smuzhiyunmy $die_on_failure; 121*4882a593Smuzhiyunmy $powercycle_after_reboot; 122*4882a593Smuzhiyunmy $poweroff_after_halt; 123*4882a593Smuzhiyunmy $max_monitor_wait; 124*4882a593Smuzhiyunmy $ssh_exec; 125*4882a593Smuzhiyunmy $scp_to_target; 126*4882a593Smuzhiyunmy $scp_to_target_install; 127*4882a593Smuzhiyunmy $power_off; 128*4882a593Smuzhiyunmy $grub_menu; 129*4882a593Smuzhiyunmy $last_grub_menu; 130*4882a593Smuzhiyunmy $grub_file; 131*4882a593Smuzhiyunmy $grub_number; 132*4882a593Smuzhiyunmy $grub_reboot; 133*4882a593Smuzhiyunmy $grub_bls_get; 134*4882a593Smuzhiyunmy $syslinux; 135*4882a593Smuzhiyunmy $syslinux_path; 136*4882a593Smuzhiyunmy $syslinux_label; 137*4882a593Smuzhiyunmy $target; 138*4882a593Smuzhiyunmy $make; 139*4882a593Smuzhiyunmy $pre_install; 140*4882a593Smuzhiyunmy $post_install; 141*4882a593Smuzhiyunmy $no_install; 142*4882a593Smuzhiyunmy $noclean; 143*4882a593Smuzhiyunmy $minconfig; 144*4882a593Smuzhiyunmy $start_minconfig; 145*4882a593Smuzhiyunmy $start_minconfig_defined; 146*4882a593Smuzhiyunmy $output_minconfig; 147*4882a593Smuzhiyunmy $minconfig_type; 148*4882a593Smuzhiyunmy $use_output_minconfig; 149*4882a593Smuzhiyunmy $warnings_file; 150*4882a593Smuzhiyunmy $ignore_config; 151*4882a593Smuzhiyunmy $ignore_errors; 152*4882a593Smuzhiyunmy $addconfig; 153*4882a593Smuzhiyunmy $in_bisect = 0; 154*4882a593Smuzhiyunmy $bisect_bad_commit = ""; 155*4882a593Smuzhiyunmy $reverse_bisect; 156*4882a593Smuzhiyunmy $bisect_manual; 157*4882a593Smuzhiyunmy $bisect_skip; 158*4882a593Smuzhiyunmy $bisect_tries; 159*4882a593Smuzhiyunmy $config_bisect_good; 160*4882a593Smuzhiyunmy $bisect_ret_good; 161*4882a593Smuzhiyunmy $bisect_ret_bad; 162*4882a593Smuzhiyunmy $bisect_ret_skip; 163*4882a593Smuzhiyunmy $bisect_ret_abort; 164*4882a593Smuzhiyunmy $bisect_ret_default; 165*4882a593Smuzhiyunmy $in_patchcheck = 0; 166*4882a593Smuzhiyunmy $run_test; 167*4882a593Smuzhiyunmy $buildlog; 168*4882a593Smuzhiyunmy $testlog; 169*4882a593Smuzhiyunmy $dmesg; 170*4882a593Smuzhiyunmy $monitor_fp; 171*4882a593Smuzhiyunmy $monitor_pid; 172*4882a593Smuzhiyunmy $monitor_cnt = 0; 173*4882a593Smuzhiyunmy $sleep_time; 174*4882a593Smuzhiyunmy $bisect_sleep_time; 175*4882a593Smuzhiyunmy $patchcheck_sleep_time; 176*4882a593Smuzhiyunmy $ignore_warnings; 177*4882a593Smuzhiyunmy $store_failures; 178*4882a593Smuzhiyunmy $store_successes; 179*4882a593Smuzhiyunmy $test_name; 180*4882a593Smuzhiyunmy $timeout; 181*4882a593Smuzhiyunmy $connect_timeout; 182*4882a593Smuzhiyunmy $config_bisect_exec; 183*4882a593Smuzhiyunmy $booted_timeout; 184*4882a593Smuzhiyunmy $detect_triplefault; 185*4882a593Smuzhiyunmy $console; 186*4882a593Smuzhiyunmy $close_console_signal; 187*4882a593Smuzhiyunmy $reboot_success_line; 188*4882a593Smuzhiyunmy $success_line; 189*4882a593Smuzhiyunmy $stop_after_success; 190*4882a593Smuzhiyunmy $stop_after_failure; 191*4882a593Smuzhiyunmy $stop_test_after; 192*4882a593Smuzhiyunmy $build_target; 193*4882a593Smuzhiyunmy $target_image; 194*4882a593Smuzhiyunmy $checkout; 195*4882a593Smuzhiyunmy $localversion; 196*4882a593Smuzhiyunmy $iteration = 0; 197*4882a593Smuzhiyunmy $successes = 0; 198*4882a593Smuzhiyunmy $stty_orig; 199*4882a593Smuzhiyunmy $run_command_status = 0; 200*4882a593Smuzhiyun 201*4882a593Smuzhiyunmy $bisect_good; 202*4882a593Smuzhiyunmy $bisect_bad; 203*4882a593Smuzhiyunmy $bisect_type; 204*4882a593Smuzhiyunmy $bisect_start; 205*4882a593Smuzhiyunmy $bisect_replay; 206*4882a593Smuzhiyunmy $bisect_files; 207*4882a593Smuzhiyunmy $bisect_reverse; 208*4882a593Smuzhiyunmy $bisect_check; 209*4882a593Smuzhiyun 210*4882a593Smuzhiyunmy $config_bisect; 211*4882a593Smuzhiyunmy $config_bisect_type; 212*4882a593Smuzhiyunmy $config_bisect_check; 213*4882a593Smuzhiyun 214*4882a593Smuzhiyunmy $patchcheck_type; 215*4882a593Smuzhiyunmy $patchcheck_start; 216*4882a593Smuzhiyunmy $patchcheck_cherry; 217*4882a593Smuzhiyunmy $patchcheck_end; 218*4882a593Smuzhiyun 219*4882a593Smuzhiyunmy $build_time; 220*4882a593Smuzhiyunmy $install_time; 221*4882a593Smuzhiyunmy $reboot_time; 222*4882a593Smuzhiyunmy $test_time; 223*4882a593Smuzhiyun 224*4882a593Smuzhiyunmy $pwd; 225*4882a593Smuzhiyunmy $dirname = $FindBin::Bin; 226*4882a593Smuzhiyun 227*4882a593Smuzhiyunmy $mailto; 228*4882a593Smuzhiyunmy $mailer; 229*4882a593Smuzhiyunmy $mail_path; 230*4882a593Smuzhiyunmy $mail_max_size; 231*4882a593Smuzhiyunmy $mail_command; 232*4882a593Smuzhiyunmy $email_on_error; 233*4882a593Smuzhiyunmy $email_when_finished; 234*4882a593Smuzhiyunmy $email_when_started; 235*4882a593Smuzhiyunmy $email_when_canceled; 236*4882a593Smuzhiyun 237*4882a593Smuzhiyunmy $script_start_time = localtime(); 238*4882a593Smuzhiyun 239*4882a593Smuzhiyun# set when a test is something other that just building or install 240*4882a593Smuzhiyun# which would require more options. 241*4882a593Smuzhiyunmy $buildonly = 1; 242*4882a593Smuzhiyun 243*4882a593Smuzhiyun# tell build not to worry about warnings, even when WARNINGS_FILE is set 244*4882a593Smuzhiyunmy $warnings_ok = 0; 245*4882a593Smuzhiyun 246*4882a593Smuzhiyun# set when creating a new config 247*4882a593Smuzhiyunmy $newconfig = 0; 248*4882a593Smuzhiyun 249*4882a593Smuzhiyunmy %entered_configs; 250*4882a593Smuzhiyunmy %config_help; 251*4882a593Smuzhiyunmy %variable; 252*4882a593Smuzhiyun 253*4882a593Smuzhiyun# force_config is the list of configs that we force enabled (or disabled) 254*4882a593Smuzhiyun# in a .config file. The MIN_CONFIG and ADD_CONFIG configs. 255*4882a593Smuzhiyunmy %force_config; 256*4882a593Smuzhiyun 257*4882a593Smuzhiyun# do not force reboots on config problems 258*4882a593Smuzhiyunmy $no_reboot = 1; 259*4882a593Smuzhiyun 260*4882a593Smuzhiyun# reboot on success 261*4882a593Smuzhiyunmy $reboot_success = 0; 262*4882a593Smuzhiyun 263*4882a593Smuzhiyunmy %option_map = ( 264*4882a593Smuzhiyun "MAILTO" => \$mailto, 265*4882a593Smuzhiyun "MAILER" => \$mailer, 266*4882a593Smuzhiyun "MAIL_PATH" => \$mail_path, 267*4882a593Smuzhiyun "MAIL_MAX_SIZE" => \$mail_max_size, 268*4882a593Smuzhiyun "MAIL_COMMAND" => \$mail_command, 269*4882a593Smuzhiyun "EMAIL_ON_ERROR" => \$email_on_error, 270*4882a593Smuzhiyun "EMAIL_WHEN_FINISHED" => \$email_when_finished, 271*4882a593Smuzhiyun "EMAIL_WHEN_STARTED" => \$email_when_started, 272*4882a593Smuzhiyun "EMAIL_WHEN_CANCELED" => \$email_when_canceled, 273*4882a593Smuzhiyun "MACHINE" => \$machine, 274*4882a593Smuzhiyun "SSH_USER" => \$ssh_user, 275*4882a593Smuzhiyun "TMP_DIR" => \$tmpdir, 276*4882a593Smuzhiyun "OUTPUT_DIR" => \$outputdir, 277*4882a593Smuzhiyun "BUILD_DIR" => \$builddir, 278*4882a593Smuzhiyun "TEST_TYPE" => \$test_type, 279*4882a593Smuzhiyun "PRE_KTEST" => \$pre_ktest, 280*4882a593Smuzhiyun "POST_KTEST" => \$post_ktest, 281*4882a593Smuzhiyun "PRE_TEST" => \$pre_test, 282*4882a593Smuzhiyun "PRE_TEST_DIE" => \$pre_test_die, 283*4882a593Smuzhiyun "POST_TEST" => \$post_test, 284*4882a593Smuzhiyun "BUILD_TYPE" => \$build_type, 285*4882a593Smuzhiyun "BUILD_OPTIONS" => \$build_options, 286*4882a593Smuzhiyun "PRE_BUILD" => \$pre_build, 287*4882a593Smuzhiyun "POST_BUILD" => \$post_build, 288*4882a593Smuzhiyun "PRE_BUILD_DIE" => \$pre_build_die, 289*4882a593Smuzhiyun "POST_BUILD_DIE" => \$post_build_die, 290*4882a593Smuzhiyun "POWER_CYCLE" => \$power_cycle, 291*4882a593Smuzhiyun "REBOOT" => \$reboot, 292*4882a593Smuzhiyun "REBOOT_RETURN_CODE" => \$reboot_return_code, 293*4882a593Smuzhiyun "BUILD_NOCLEAN" => \$noclean, 294*4882a593Smuzhiyun "MIN_CONFIG" => \$minconfig, 295*4882a593Smuzhiyun "OUTPUT_MIN_CONFIG" => \$output_minconfig, 296*4882a593Smuzhiyun "START_MIN_CONFIG" => \$start_minconfig, 297*4882a593Smuzhiyun "MIN_CONFIG_TYPE" => \$minconfig_type, 298*4882a593Smuzhiyun "USE_OUTPUT_MIN_CONFIG" => \$use_output_minconfig, 299*4882a593Smuzhiyun "WARNINGS_FILE" => \$warnings_file, 300*4882a593Smuzhiyun "IGNORE_CONFIG" => \$ignore_config, 301*4882a593Smuzhiyun "TEST" => \$run_test, 302*4882a593Smuzhiyun "ADD_CONFIG" => \$addconfig, 303*4882a593Smuzhiyun "REBOOT_TYPE" => \$reboot_type, 304*4882a593Smuzhiyun "GRUB_MENU" => \$grub_menu, 305*4882a593Smuzhiyun "GRUB_FILE" => \$grub_file, 306*4882a593Smuzhiyun "GRUB_REBOOT" => \$grub_reboot, 307*4882a593Smuzhiyun "GRUB_BLS_GET" => \$grub_bls_get, 308*4882a593Smuzhiyun "SYSLINUX" => \$syslinux, 309*4882a593Smuzhiyun "SYSLINUX_PATH" => \$syslinux_path, 310*4882a593Smuzhiyun "SYSLINUX_LABEL" => \$syslinux_label, 311*4882a593Smuzhiyun "PRE_INSTALL" => \$pre_install, 312*4882a593Smuzhiyun "POST_INSTALL" => \$post_install, 313*4882a593Smuzhiyun "NO_INSTALL" => \$no_install, 314*4882a593Smuzhiyun "REBOOT_SCRIPT" => \$reboot_script, 315*4882a593Smuzhiyun "REBOOT_ON_ERROR" => \$reboot_on_error, 316*4882a593Smuzhiyun "SWITCH_TO_GOOD" => \$switch_to_good, 317*4882a593Smuzhiyun "SWITCH_TO_TEST" => \$switch_to_test, 318*4882a593Smuzhiyun "POWEROFF_ON_ERROR" => \$poweroff_on_error, 319*4882a593Smuzhiyun "REBOOT_ON_SUCCESS" => \$reboot_on_success, 320*4882a593Smuzhiyun "DIE_ON_FAILURE" => \$die_on_failure, 321*4882a593Smuzhiyun "POWER_OFF" => \$power_off, 322*4882a593Smuzhiyun "POWERCYCLE_AFTER_REBOOT" => \$powercycle_after_reboot, 323*4882a593Smuzhiyun "POWEROFF_AFTER_HALT" => \$poweroff_after_halt, 324*4882a593Smuzhiyun "MAX_MONITOR_WAIT" => \$max_monitor_wait, 325*4882a593Smuzhiyun "SLEEP_TIME" => \$sleep_time, 326*4882a593Smuzhiyun "BISECT_SLEEP_TIME" => \$bisect_sleep_time, 327*4882a593Smuzhiyun "PATCHCHECK_SLEEP_TIME" => \$patchcheck_sleep_time, 328*4882a593Smuzhiyun "IGNORE_WARNINGS" => \$ignore_warnings, 329*4882a593Smuzhiyun "IGNORE_ERRORS" => \$ignore_errors, 330*4882a593Smuzhiyun "BISECT_MANUAL" => \$bisect_manual, 331*4882a593Smuzhiyun "BISECT_SKIP" => \$bisect_skip, 332*4882a593Smuzhiyun "BISECT_TRIES" => \$bisect_tries, 333*4882a593Smuzhiyun "CONFIG_BISECT_GOOD" => \$config_bisect_good, 334*4882a593Smuzhiyun "BISECT_RET_GOOD" => \$bisect_ret_good, 335*4882a593Smuzhiyun "BISECT_RET_BAD" => \$bisect_ret_bad, 336*4882a593Smuzhiyun "BISECT_RET_SKIP" => \$bisect_ret_skip, 337*4882a593Smuzhiyun "BISECT_RET_ABORT" => \$bisect_ret_abort, 338*4882a593Smuzhiyun "BISECT_RET_DEFAULT" => \$bisect_ret_default, 339*4882a593Smuzhiyun "STORE_FAILURES" => \$store_failures, 340*4882a593Smuzhiyun "STORE_SUCCESSES" => \$store_successes, 341*4882a593Smuzhiyun "TEST_NAME" => \$test_name, 342*4882a593Smuzhiyun "TIMEOUT" => \$timeout, 343*4882a593Smuzhiyun "CONNECT_TIMEOUT" => \$connect_timeout, 344*4882a593Smuzhiyun "CONFIG_BISECT_EXEC" => \$config_bisect_exec, 345*4882a593Smuzhiyun "BOOTED_TIMEOUT" => \$booted_timeout, 346*4882a593Smuzhiyun "CONSOLE" => \$console, 347*4882a593Smuzhiyun "CLOSE_CONSOLE_SIGNAL" => \$close_console_signal, 348*4882a593Smuzhiyun "DETECT_TRIPLE_FAULT" => \$detect_triplefault, 349*4882a593Smuzhiyun "SUCCESS_LINE" => \$success_line, 350*4882a593Smuzhiyun "REBOOT_SUCCESS_LINE" => \$reboot_success_line, 351*4882a593Smuzhiyun "STOP_AFTER_SUCCESS" => \$stop_after_success, 352*4882a593Smuzhiyun "STOP_AFTER_FAILURE" => \$stop_after_failure, 353*4882a593Smuzhiyun "STOP_TEST_AFTER" => \$stop_test_after, 354*4882a593Smuzhiyun "BUILD_TARGET" => \$build_target, 355*4882a593Smuzhiyun "SSH_EXEC" => \$ssh_exec, 356*4882a593Smuzhiyun "SCP_TO_TARGET" => \$scp_to_target, 357*4882a593Smuzhiyun "SCP_TO_TARGET_INSTALL" => \$scp_to_target_install, 358*4882a593Smuzhiyun "CHECKOUT" => \$checkout, 359*4882a593Smuzhiyun "TARGET_IMAGE" => \$target_image, 360*4882a593Smuzhiyun "LOCALVERSION" => \$localversion, 361*4882a593Smuzhiyun 362*4882a593Smuzhiyun "BISECT_GOOD" => \$bisect_good, 363*4882a593Smuzhiyun "BISECT_BAD" => \$bisect_bad, 364*4882a593Smuzhiyun "BISECT_TYPE" => \$bisect_type, 365*4882a593Smuzhiyun "BISECT_START" => \$bisect_start, 366*4882a593Smuzhiyun "BISECT_REPLAY" => \$bisect_replay, 367*4882a593Smuzhiyun "BISECT_FILES" => \$bisect_files, 368*4882a593Smuzhiyun "BISECT_REVERSE" => \$bisect_reverse, 369*4882a593Smuzhiyun "BISECT_CHECK" => \$bisect_check, 370*4882a593Smuzhiyun 371*4882a593Smuzhiyun "CONFIG_BISECT" => \$config_bisect, 372*4882a593Smuzhiyun "CONFIG_BISECT_TYPE" => \$config_bisect_type, 373*4882a593Smuzhiyun "CONFIG_BISECT_CHECK" => \$config_bisect_check, 374*4882a593Smuzhiyun 375*4882a593Smuzhiyun "PATCHCHECK_TYPE" => \$patchcheck_type, 376*4882a593Smuzhiyun "PATCHCHECK_START" => \$patchcheck_start, 377*4882a593Smuzhiyun "PATCHCHECK_CHERRY" => \$patchcheck_cherry, 378*4882a593Smuzhiyun "PATCHCHECK_END" => \$patchcheck_end, 379*4882a593Smuzhiyun); 380*4882a593Smuzhiyun 381*4882a593Smuzhiyun# Options may be used by other options, record them. 382*4882a593Smuzhiyunmy %used_options; 383*4882a593Smuzhiyun 384*4882a593Smuzhiyun# default variables that can be used 385*4882a593Smuzhiyunchomp ($variable{"PWD"} = `pwd`); 386*4882a593Smuzhiyun$pwd = $variable{"PWD"}; 387*4882a593Smuzhiyun 388*4882a593Smuzhiyun$config_help{"MACHINE"} = << "EOF" 389*4882a593Smuzhiyun The machine hostname that you will test. 390*4882a593Smuzhiyun For build only tests, it is still needed to differentiate log files. 391*4882a593SmuzhiyunEOF 392*4882a593Smuzhiyun ; 393*4882a593Smuzhiyun$config_help{"SSH_USER"} = << "EOF" 394*4882a593Smuzhiyun The box is expected to have ssh on normal bootup, provide the user 395*4882a593Smuzhiyun (most likely root, since you need privileged operations) 396*4882a593SmuzhiyunEOF 397*4882a593Smuzhiyun ; 398*4882a593Smuzhiyun$config_help{"BUILD_DIR"} = << "EOF" 399*4882a593Smuzhiyun The directory that contains the Linux source code (full path). 400*4882a593Smuzhiyun You can use \${PWD} that will be the path where ktest.pl is run, or use 401*4882a593Smuzhiyun \${THIS_DIR} which is assigned \${PWD} but may be changed later. 402*4882a593SmuzhiyunEOF 403*4882a593Smuzhiyun ; 404*4882a593Smuzhiyun$config_help{"OUTPUT_DIR"} = << "EOF" 405*4882a593Smuzhiyun The directory that the objects will be built (full path). 406*4882a593Smuzhiyun (can not be same as BUILD_DIR) 407*4882a593Smuzhiyun You can use \${PWD} that will be the path where ktest.pl is run, or use 408*4882a593Smuzhiyun \${THIS_DIR} which is assigned \${PWD} but may be changed later. 409*4882a593SmuzhiyunEOF 410*4882a593Smuzhiyun ; 411*4882a593Smuzhiyun$config_help{"BUILD_TARGET"} = << "EOF" 412*4882a593Smuzhiyun The location of the compiled file to copy to the target. 413*4882a593Smuzhiyun (relative to OUTPUT_DIR) 414*4882a593SmuzhiyunEOF 415*4882a593Smuzhiyun ; 416*4882a593Smuzhiyun$config_help{"BUILD_OPTIONS"} = << "EOF" 417*4882a593Smuzhiyun Options to add to \"make\" when building. 418*4882a593Smuzhiyun i.e. -j20 419*4882a593SmuzhiyunEOF 420*4882a593Smuzhiyun ; 421*4882a593Smuzhiyun$config_help{"TARGET_IMAGE"} = << "EOF" 422*4882a593Smuzhiyun The place to put your image on the test machine. 423*4882a593SmuzhiyunEOF 424*4882a593Smuzhiyun ; 425*4882a593Smuzhiyun$config_help{"POWER_CYCLE"} = << "EOF" 426*4882a593Smuzhiyun A script or command to reboot the box. 427*4882a593Smuzhiyun 428*4882a593Smuzhiyun Here is a digital loggers power switch example 429*4882a593Smuzhiyun POWER_CYCLE = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin\@power/outlet?5=CCL' 430*4882a593Smuzhiyun 431*4882a593Smuzhiyun Here is an example to reboot a virtual box on the current host 432*4882a593Smuzhiyun with the name "Guest". 433*4882a593Smuzhiyun POWER_CYCLE = virsh destroy Guest; sleep 5; virsh start Guest 434*4882a593SmuzhiyunEOF 435*4882a593Smuzhiyun ; 436*4882a593Smuzhiyun$config_help{"CONSOLE"} = << "EOF" 437*4882a593Smuzhiyun The script or command that reads the console 438*4882a593Smuzhiyun 439*4882a593Smuzhiyun If you use ttywatch server, something like the following would work. 440*4882a593SmuzhiyunCONSOLE = nc -d localhost 3001 441*4882a593Smuzhiyun 442*4882a593Smuzhiyun For a virtual machine with guest name "Guest". 443*4882a593SmuzhiyunCONSOLE = virsh console Guest 444*4882a593SmuzhiyunEOF 445*4882a593Smuzhiyun ; 446*4882a593Smuzhiyun$config_help{"LOCALVERSION"} = << "EOF" 447*4882a593Smuzhiyun Required version ending to differentiate the test 448*4882a593Smuzhiyun from other linux builds on the system. 449*4882a593SmuzhiyunEOF 450*4882a593Smuzhiyun ; 451*4882a593Smuzhiyun$config_help{"REBOOT_TYPE"} = << "EOF" 452*4882a593Smuzhiyun Way to reboot the box to the test kernel. 453*4882a593Smuzhiyun Only valid options so far are "grub", "grub2", "grub2bls", "syslinux", and "script". 454*4882a593Smuzhiyun 455*4882a593Smuzhiyun If you specify grub, it will assume grub version 1 456*4882a593Smuzhiyun and will search in /boot/grub/menu.lst for the title \$GRUB_MENU 457*4882a593Smuzhiyun and select that target to reboot to the kernel. If this is not 458*4882a593Smuzhiyun your setup, then specify "script" and have a command or script 459*4882a593Smuzhiyun specified in REBOOT_SCRIPT to boot to the target. 460*4882a593Smuzhiyun 461*4882a593Smuzhiyun The entry in /boot/grub/menu.lst must be entered in manually. 462*4882a593Smuzhiyun The test will not modify that file. 463*4882a593Smuzhiyun 464*4882a593Smuzhiyun If you specify grub2, then you also need to specify both \$GRUB_MENU 465*4882a593Smuzhiyun and \$GRUB_FILE. 466*4882a593Smuzhiyun 467*4882a593Smuzhiyun If you specify grub2bls, then you also need to specify \$GRUB_MENU. 468*4882a593Smuzhiyun 469*4882a593Smuzhiyun If you specify syslinux, then you may use SYSLINUX to define the syslinux 470*4882a593Smuzhiyun command (defaults to extlinux), and SYSLINUX_PATH to specify the path to 471*4882a593Smuzhiyun the syslinux install (defaults to /boot/extlinux). But you have to specify 472*4882a593Smuzhiyun SYSLINUX_LABEL to define the label to boot to for the test kernel. 473*4882a593SmuzhiyunEOF 474*4882a593Smuzhiyun ; 475*4882a593Smuzhiyun$config_help{"GRUB_MENU"} = << "EOF" 476*4882a593Smuzhiyun The grub title name for the test kernel to boot 477*4882a593Smuzhiyun (Only mandatory if REBOOT_TYPE = grub or grub2) 478*4882a593Smuzhiyun 479*4882a593Smuzhiyun Note, ktest.pl will not update the grub menu.lst, you need to 480*4882a593Smuzhiyun manually add an option for the test. ktest.pl will search 481*4882a593Smuzhiyun the grub menu.lst for this option to find what kernel to 482*4882a593Smuzhiyun reboot into. 483*4882a593Smuzhiyun 484*4882a593Smuzhiyun For example, if in the /boot/grub/menu.lst the test kernel title has: 485*4882a593Smuzhiyun title Test Kernel 486*4882a593Smuzhiyun kernel vmlinuz-test 487*4882a593Smuzhiyun GRUB_MENU = Test Kernel 488*4882a593Smuzhiyun 489*4882a593Smuzhiyun For grub2, a search of \$GRUB_FILE is performed for the lines 490*4882a593Smuzhiyun that begin with "menuentry". It will not detect submenus. The 491*4882a593Smuzhiyun menu must be a non-nested menu. Add the quotes used in the menu 492*4882a593Smuzhiyun to guarantee your selection, as the first menuentry with the content 493*4882a593Smuzhiyun of \$GRUB_MENU that is found will be used. 494*4882a593Smuzhiyun 495*4882a593Smuzhiyun For grub2bls, \$GRUB_MENU is searched on the result of \$GRUB_BLS_GET 496*4882a593Smuzhiyun command for the lines that begin with "title". 497*4882a593SmuzhiyunEOF 498*4882a593Smuzhiyun ; 499*4882a593Smuzhiyun$config_help{"GRUB_FILE"} = << "EOF" 500*4882a593Smuzhiyun If grub2 is used, the full path for the grub.cfg file is placed 501*4882a593Smuzhiyun here. Use something like /boot/grub2/grub.cfg to search. 502*4882a593SmuzhiyunEOF 503*4882a593Smuzhiyun ; 504*4882a593Smuzhiyun$config_help{"SYSLINUX_LABEL"} = << "EOF" 505*4882a593Smuzhiyun If syslinux is used, the label that boots the target kernel must 506*4882a593Smuzhiyun be specified with SYSLINUX_LABEL. 507*4882a593SmuzhiyunEOF 508*4882a593Smuzhiyun ; 509*4882a593Smuzhiyun$config_help{"REBOOT_SCRIPT"} = << "EOF" 510*4882a593Smuzhiyun A script to reboot the target into the test kernel 511*4882a593Smuzhiyun (Only mandatory if REBOOT_TYPE = script) 512*4882a593SmuzhiyunEOF 513*4882a593Smuzhiyun ; 514*4882a593Smuzhiyun 515*4882a593Smuzhiyunsub _logit { 516*4882a593Smuzhiyun if (defined($opt{"LOG_FILE"})) { 517*4882a593Smuzhiyun print LOG @_; 518*4882a593Smuzhiyun } 519*4882a593Smuzhiyun} 520*4882a593Smuzhiyun 521*4882a593Smuzhiyunsub logit { 522*4882a593Smuzhiyun if (defined($opt{"LOG_FILE"})) { 523*4882a593Smuzhiyun _logit @_; 524*4882a593Smuzhiyun } else { 525*4882a593Smuzhiyun print @_; 526*4882a593Smuzhiyun } 527*4882a593Smuzhiyun} 528*4882a593Smuzhiyun 529*4882a593Smuzhiyunsub doprint { 530*4882a593Smuzhiyun print @_; 531*4882a593Smuzhiyun _logit @_; 532*4882a593Smuzhiyun} 533*4882a593Smuzhiyun 534*4882a593Smuzhiyunsub read_prompt { 535*4882a593Smuzhiyun my ($cancel, $prompt) = @_; 536*4882a593Smuzhiyun 537*4882a593Smuzhiyun my $ans; 538*4882a593Smuzhiyun 539*4882a593Smuzhiyun for (;;) { 540*4882a593Smuzhiyun if ($cancel) { 541*4882a593Smuzhiyun print "$prompt [y/n/C] "; 542*4882a593Smuzhiyun } else { 543*4882a593Smuzhiyun print "$prompt [Y/n] "; 544*4882a593Smuzhiyun } 545*4882a593Smuzhiyun $ans = <STDIN>; 546*4882a593Smuzhiyun chomp $ans; 547*4882a593Smuzhiyun if ($ans =~ /^\s*$/) { 548*4882a593Smuzhiyun if ($cancel) { 549*4882a593Smuzhiyun $ans = "c"; 550*4882a593Smuzhiyun } else { 551*4882a593Smuzhiyun $ans = "y"; 552*4882a593Smuzhiyun } 553*4882a593Smuzhiyun } 554*4882a593Smuzhiyun last if ($ans =~ /^y$/i || $ans =~ /^n$/i); 555*4882a593Smuzhiyun if ($cancel) { 556*4882a593Smuzhiyun last if ($ans =~ /^c$/i); 557*4882a593Smuzhiyun print "Please answer either 'y', 'n' or 'c'.\n"; 558*4882a593Smuzhiyun } else { 559*4882a593Smuzhiyun print "Please answer either 'y' or 'n'.\n"; 560*4882a593Smuzhiyun } 561*4882a593Smuzhiyun } 562*4882a593Smuzhiyun if ($ans =~ /^c/i) { 563*4882a593Smuzhiyun exit; 564*4882a593Smuzhiyun } 565*4882a593Smuzhiyun if ($ans !~ /^y$/i) { 566*4882a593Smuzhiyun return 0; 567*4882a593Smuzhiyun } 568*4882a593Smuzhiyun return 1; 569*4882a593Smuzhiyun} 570*4882a593Smuzhiyun 571*4882a593Smuzhiyunsub read_yn { 572*4882a593Smuzhiyun my ($prompt) = @_; 573*4882a593Smuzhiyun 574*4882a593Smuzhiyun return read_prompt 0, $prompt; 575*4882a593Smuzhiyun} 576*4882a593Smuzhiyun 577*4882a593Smuzhiyunsub read_ync { 578*4882a593Smuzhiyun my ($prompt) = @_; 579*4882a593Smuzhiyun 580*4882a593Smuzhiyun return read_prompt 1, $prompt; 581*4882a593Smuzhiyun} 582*4882a593Smuzhiyun 583*4882a593Smuzhiyunsub get_mandatory_config { 584*4882a593Smuzhiyun my ($config) = @_; 585*4882a593Smuzhiyun my $ans; 586*4882a593Smuzhiyun 587*4882a593Smuzhiyun return if (defined($opt{$config})); 588*4882a593Smuzhiyun 589*4882a593Smuzhiyun if (defined($config_help{$config})) { 590*4882a593Smuzhiyun print "\n"; 591*4882a593Smuzhiyun print $config_help{$config}; 592*4882a593Smuzhiyun } 593*4882a593Smuzhiyun 594*4882a593Smuzhiyun for (;;) { 595*4882a593Smuzhiyun print "$config = "; 596*4882a593Smuzhiyun if (defined($default{$config}) && length($default{$config})) { 597*4882a593Smuzhiyun print "\[$default{$config}\] "; 598*4882a593Smuzhiyun } 599*4882a593Smuzhiyun $ans = <STDIN>; 600*4882a593Smuzhiyun $ans =~ s/^\s*(.*\S)\s*$/$1/; 601*4882a593Smuzhiyun if ($ans =~ /^\s*$/) { 602*4882a593Smuzhiyun if ($default{$config}) { 603*4882a593Smuzhiyun $ans = $default{$config}; 604*4882a593Smuzhiyun } else { 605*4882a593Smuzhiyun print "Your answer can not be blank\n"; 606*4882a593Smuzhiyun next; 607*4882a593Smuzhiyun } 608*4882a593Smuzhiyun } 609*4882a593Smuzhiyun $entered_configs{$config} = ${ans}; 610*4882a593Smuzhiyun last; 611*4882a593Smuzhiyun } 612*4882a593Smuzhiyun} 613*4882a593Smuzhiyun 614*4882a593Smuzhiyunsub show_time { 615*4882a593Smuzhiyun my ($time) = @_; 616*4882a593Smuzhiyun 617*4882a593Smuzhiyun my $hours = 0; 618*4882a593Smuzhiyun my $minutes = 0; 619*4882a593Smuzhiyun 620*4882a593Smuzhiyun if ($time > 3600) { 621*4882a593Smuzhiyun $hours = int($time / 3600); 622*4882a593Smuzhiyun $time -= $hours * 3600; 623*4882a593Smuzhiyun } 624*4882a593Smuzhiyun if ($time > 60) { 625*4882a593Smuzhiyun $minutes = int($time / 60); 626*4882a593Smuzhiyun $time -= $minutes * 60; 627*4882a593Smuzhiyun } 628*4882a593Smuzhiyun 629*4882a593Smuzhiyun if ($hours > 0) { 630*4882a593Smuzhiyun doprint "$hours hour"; 631*4882a593Smuzhiyun doprint "s" if ($hours > 1); 632*4882a593Smuzhiyun doprint " "; 633*4882a593Smuzhiyun } 634*4882a593Smuzhiyun 635*4882a593Smuzhiyun if ($minutes > 0) { 636*4882a593Smuzhiyun doprint "$minutes minute"; 637*4882a593Smuzhiyun doprint "s" if ($minutes > 1); 638*4882a593Smuzhiyun doprint " "; 639*4882a593Smuzhiyun } 640*4882a593Smuzhiyun 641*4882a593Smuzhiyun doprint "$time second"; 642*4882a593Smuzhiyun doprint "s" if ($time != 1); 643*4882a593Smuzhiyun} 644*4882a593Smuzhiyun 645*4882a593Smuzhiyunsub print_times { 646*4882a593Smuzhiyun doprint "\n"; 647*4882a593Smuzhiyun if ($build_time) { 648*4882a593Smuzhiyun doprint "Build time: "; 649*4882a593Smuzhiyun show_time($build_time); 650*4882a593Smuzhiyun doprint "\n"; 651*4882a593Smuzhiyun } 652*4882a593Smuzhiyun if ($install_time) { 653*4882a593Smuzhiyun doprint "Install time: "; 654*4882a593Smuzhiyun show_time($install_time); 655*4882a593Smuzhiyun doprint "\n"; 656*4882a593Smuzhiyun } 657*4882a593Smuzhiyun if ($reboot_time) { 658*4882a593Smuzhiyun doprint "Reboot time: "; 659*4882a593Smuzhiyun show_time($reboot_time); 660*4882a593Smuzhiyun doprint "\n"; 661*4882a593Smuzhiyun } 662*4882a593Smuzhiyun if ($test_time) { 663*4882a593Smuzhiyun doprint "Test time: "; 664*4882a593Smuzhiyun show_time($test_time); 665*4882a593Smuzhiyun doprint "\n"; 666*4882a593Smuzhiyun } 667*4882a593Smuzhiyun # reset for iterations like bisect 668*4882a593Smuzhiyun $build_time = 0; 669*4882a593Smuzhiyun $install_time = 0; 670*4882a593Smuzhiyun $reboot_time = 0; 671*4882a593Smuzhiyun $test_time = 0; 672*4882a593Smuzhiyun} 673*4882a593Smuzhiyun 674*4882a593Smuzhiyunsub get_mandatory_configs { 675*4882a593Smuzhiyun get_mandatory_config("MACHINE"); 676*4882a593Smuzhiyun get_mandatory_config("BUILD_DIR"); 677*4882a593Smuzhiyun get_mandatory_config("OUTPUT_DIR"); 678*4882a593Smuzhiyun 679*4882a593Smuzhiyun if ($newconfig) { 680*4882a593Smuzhiyun get_mandatory_config("BUILD_OPTIONS"); 681*4882a593Smuzhiyun } 682*4882a593Smuzhiyun 683*4882a593Smuzhiyun # options required for other than just building a kernel 684*4882a593Smuzhiyun if (!$buildonly) { 685*4882a593Smuzhiyun get_mandatory_config("POWER_CYCLE"); 686*4882a593Smuzhiyun get_mandatory_config("CONSOLE"); 687*4882a593Smuzhiyun } 688*4882a593Smuzhiyun 689*4882a593Smuzhiyun # options required for install and more 690*4882a593Smuzhiyun if ($buildonly != 1) { 691*4882a593Smuzhiyun get_mandatory_config("SSH_USER"); 692*4882a593Smuzhiyun get_mandatory_config("BUILD_TARGET"); 693*4882a593Smuzhiyun get_mandatory_config("TARGET_IMAGE"); 694*4882a593Smuzhiyun } 695*4882a593Smuzhiyun 696*4882a593Smuzhiyun get_mandatory_config("LOCALVERSION"); 697*4882a593Smuzhiyun 698*4882a593Smuzhiyun return if ($buildonly); 699*4882a593Smuzhiyun 700*4882a593Smuzhiyun my $rtype = $opt{"REBOOT_TYPE"}; 701*4882a593Smuzhiyun 702*4882a593Smuzhiyun if (!defined($rtype)) { 703*4882a593Smuzhiyun if (!defined($opt{"GRUB_MENU"})) { 704*4882a593Smuzhiyun get_mandatory_config("REBOOT_TYPE"); 705*4882a593Smuzhiyun $rtype = $entered_configs{"REBOOT_TYPE"}; 706*4882a593Smuzhiyun } else { 707*4882a593Smuzhiyun $rtype = "grub"; 708*4882a593Smuzhiyun } 709*4882a593Smuzhiyun } 710*4882a593Smuzhiyun 711*4882a593Smuzhiyun if (($rtype eq "grub") or ($rtype eq "grub2bls")) { 712*4882a593Smuzhiyun get_mandatory_config("GRUB_MENU"); 713*4882a593Smuzhiyun } 714*4882a593Smuzhiyun 715*4882a593Smuzhiyun if ($rtype eq "grub2") { 716*4882a593Smuzhiyun get_mandatory_config("GRUB_MENU"); 717*4882a593Smuzhiyun get_mandatory_config("GRUB_FILE"); 718*4882a593Smuzhiyun } 719*4882a593Smuzhiyun 720*4882a593Smuzhiyun if ($rtype eq "syslinux") { 721*4882a593Smuzhiyun get_mandatory_config("SYSLINUX_LABEL"); 722*4882a593Smuzhiyun } 723*4882a593Smuzhiyun} 724*4882a593Smuzhiyun 725*4882a593Smuzhiyunsub process_variables { 726*4882a593Smuzhiyun my ($value, $remove_undef) = @_; 727*4882a593Smuzhiyun my $retval = ""; 728*4882a593Smuzhiyun 729*4882a593Smuzhiyun # We want to check for '\', and it is just easier 730*4882a593Smuzhiyun # to check the previous characet of '$' and not need 731*4882a593Smuzhiyun # to worry if '$' is the first character. By adding 732*4882a593Smuzhiyun # a space to $value, we can just check [^\\]\$ and 733*4882a593Smuzhiyun # it will still work. 734*4882a593Smuzhiyun $value = " $value"; 735*4882a593Smuzhiyun 736*4882a593Smuzhiyun while ($value =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { 737*4882a593Smuzhiyun my $begin = $1; 738*4882a593Smuzhiyun my $var = $2; 739*4882a593Smuzhiyun my $end = $3; 740*4882a593Smuzhiyun # append beginning of value to retval 741*4882a593Smuzhiyun $retval = "$retval$begin"; 742*4882a593Smuzhiyun if (defined($variable{$var})) { 743*4882a593Smuzhiyun $retval = "$retval$variable{$var}"; 744*4882a593Smuzhiyun } elsif (defined($remove_undef) && $remove_undef) { 745*4882a593Smuzhiyun # for if statements, any variable that is not defined, 746*4882a593Smuzhiyun # we simple convert to 0 747*4882a593Smuzhiyun $retval = "${retval}0"; 748*4882a593Smuzhiyun } else { 749*4882a593Smuzhiyun # put back the origin piece. 750*4882a593Smuzhiyun $retval = "$retval\$\{$var\}"; 751*4882a593Smuzhiyun # This could be an option that is used later, save 752*4882a593Smuzhiyun # it so we don't warn if this option is not one of 753*4882a593Smuzhiyun # ktests options. 754*4882a593Smuzhiyun $used_options{$var} = 1; 755*4882a593Smuzhiyun } 756*4882a593Smuzhiyun $value = $end; 757*4882a593Smuzhiyun } 758*4882a593Smuzhiyun $retval = "$retval$value"; 759*4882a593Smuzhiyun 760*4882a593Smuzhiyun # remove the space added in the beginning 761*4882a593Smuzhiyun $retval =~ s/ //; 762*4882a593Smuzhiyun 763*4882a593Smuzhiyun return "$retval" 764*4882a593Smuzhiyun} 765*4882a593Smuzhiyun 766*4882a593Smuzhiyunsub set_value { 767*4882a593Smuzhiyun my ($lvalue, $rvalue, $override, $overrides, $name) = @_; 768*4882a593Smuzhiyun 769*4882a593Smuzhiyun my $prvalue = process_variables($rvalue); 770*4882a593Smuzhiyun 771*4882a593Smuzhiyun if ($lvalue =~ /^(TEST|BISECT|CONFIG_BISECT)_TYPE(\[.*\])?$/ && 772*4882a593Smuzhiyun $prvalue !~ /^(config_|)bisect$/ && 773*4882a593Smuzhiyun $prvalue !~ /^build$/ && 774*4882a593Smuzhiyun $buildonly) { 775*4882a593Smuzhiyun 776*4882a593Smuzhiyun # Note if a test is something other than build, then we 777*4882a593Smuzhiyun # will need other mandatory options. 778*4882a593Smuzhiyun if ($prvalue ne "install") { 779*4882a593Smuzhiyun $buildonly = 0; 780*4882a593Smuzhiyun } else { 781*4882a593Smuzhiyun # install still limits some mandatory options. 782*4882a593Smuzhiyun $buildonly = 2; 783*4882a593Smuzhiyun } 784*4882a593Smuzhiyun } 785*4882a593Smuzhiyun 786*4882a593Smuzhiyun if (defined($opt{$lvalue})) { 787*4882a593Smuzhiyun if (!$override || defined(${$overrides}{$lvalue})) { 788*4882a593Smuzhiyun my $extra = ""; 789*4882a593Smuzhiyun if ($override) { 790*4882a593Smuzhiyun $extra = "In the same override section!\n"; 791*4882a593Smuzhiyun } 792*4882a593Smuzhiyun die "$name: $.: Option $lvalue defined more than once!\n$extra"; 793*4882a593Smuzhiyun } 794*4882a593Smuzhiyun ${$overrides}{$lvalue} = $prvalue; 795*4882a593Smuzhiyun } 796*4882a593Smuzhiyun 797*4882a593Smuzhiyun $opt{$lvalue} = $prvalue; 798*4882a593Smuzhiyun} 799*4882a593Smuzhiyun 800*4882a593Smuzhiyunsub set_eval { 801*4882a593Smuzhiyun my ($lvalue, $rvalue, $name) = @_; 802*4882a593Smuzhiyun 803*4882a593Smuzhiyun my $prvalue = process_variables($rvalue); 804*4882a593Smuzhiyun my $arr; 805*4882a593Smuzhiyun 806*4882a593Smuzhiyun if (defined($evals{$lvalue})) { 807*4882a593Smuzhiyun $arr = $evals{$lvalue}; 808*4882a593Smuzhiyun } else { 809*4882a593Smuzhiyun $arr = []; 810*4882a593Smuzhiyun $evals{$lvalue} = $arr; 811*4882a593Smuzhiyun } 812*4882a593Smuzhiyun 813*4882a593Smuzhiyun push @{$arr}, $rvalue; 814*4882a593Smuzhiyun} 815*4882a593Smuzhiyun 816*4882a593Smuzhiyunsub set_variable { 817*4882a593Smuzhiyun my ($lvalue, $rvalue) = @_; 818*4882a593Smuzhiyun 819*4882a593Smuzhiyun if ($rvalue =~ /^\s*$/) { 820*4882a593Smuzhiyun delete $variable{$lvalue}; 821*4882a593Smuzhiyun } else { 822*4882a593Smuzhiyun $rvalue = process_variables($rvalue); 823*4882a593Smuzhiyun $variable{$lvalue} = $rvalue; 824*4882a593Smuzhiyun } 825*4882a593Smuzhiyun} 826*4882a593Smuzhiyun 827*4882a593Smuzhiyunsub process_compare { 828*4882a593Smuzhiyun my ($lval, $cmp, $rval) = @_; 829*4882a593Smuzhiyun 830*4882a593Smuzhiyun # remove whitespace 831*4882a593Smuzhiyun 832*4882a593Smuzhiyun $lval =~ s/^\s*//; 833*4882a593Smuzhiyun $lval =~ s/\s*$//; 834*4882a593Smuzhiyun 835*4882a593Smuzhiyun $rval =~ s/^\s*//; 836*4882a593Smuzhiyun $rval =~ s/\s*$//; 837*4882a593Smuzhiyun 838*4882a593Smuzhiyun if ($cmp eq "==") { 839*4882a593Smuzhiyun return $lval eq $rval; 840*4882a593Smuzhiyun } elsif ($cmp eq "!=") { 841*4882a593Smuzhiyun return $lval ne $rval; 842*4882a593Smuzhiyun } elsif ($cmp eq "=~") { 843*4882a593Smuzhiyun return $lval =~ m/$rval/; 844*4882a593Smuzhiyun } elsif ($cmp eq "!~") { 845*4882a593Smuzhiyun return $lval !~ m/$rval/; 846*4882a593Smuzhiyun } 847*4882a593Smuzhiyun 848*4882a593Smuzhiyun my $statement = "$lval $cmp $rval"; 849*4882a593Smuzhiyun my $ret = eval $statement; 850*4882a593Smuzhiyun 851*4882a593Smuzhiyun # $@ stores error of eval 852*4882a593Smuzhiyun if ($@) { 853*4882a593Smuzhiyun return -1; 854*4882a593Smuzhiyun } 855*4882a593Smuzhiyun 856*4882a593Smuzhiyun return $ret; 857*4882a593Smuzhiyun} 858*4882a593Smuzhiyun 859*4882a593Smuzhiyunsub value_defined { 860*4882a593Smuzhiyun my ($val) = @_; 861*4882a593Smuzhiyun 862*4882a593Smuzhiyun return defined($variable{$2}) || 863*4882a593Smuzhiyun defined($opt{$2}); 864*4882a593Smuzhiyun} 865*4882a593Smuzhiyun 866*4882a593Smuzhiyunmy $d = 0; 867*4882a593Smuzhiyunsub process_expression { 868*4882a593Smuzhiyun my ($name, $val) = @_; 869*4882a593Smuzhiyun 870*4882a593Smuzhiyun my $c = $d++; 871*4882a593Smuzhiyun 872*4882a593Smuzhiyun while ($val =~ s/\(([^\(]*?)\)/\&\&\&\&VAL\&\&\&\&/) { 873*4882a593Smuzhiyun my $express = $1; 874*4882a593Smuzhiyun 875*4882a593Smuzhiyun if (process_expression($name, $express)) { 876*4882a593Smuzhiyun $val =~ s/\&\&\&\&VAL\&\&\&\&/ 1 /; 877*4882a593Smuzhiyun } else { 878*4882a593Smuzhiyun $val =~ s/\&\&\&\&VAL\&\&\&\&/ 0 /; 879*4882a593Smuzhiyun } 880*4882a593Smuzhiyun } 881*4882a593Smuzhiyun 882*4882a593Smuzhiyun $d--; 883*4882a593Smuzhiyun my $OR = "\\|\\|"; 884*4882a593Smuzhiyun my $AND = "\\&\\&"; 885*4882a593Smuzhiyun 886*4882a593Smuzhiyun while ($val =~ s/^(.*?)($OR|$AND)//) { 887*4882a593Smuzhiyun my $express = $1; 888*4882a593Smuzhiyun my $op = $2; 889*4882a593Smuzhiyun 890*4882a593Smuzhiyun if (process_expression($name, $express)) { 891*4882a593Smuzhiyun if ($op eq "||") { 892*4882a593Smuzhiyun return 1; 893*4882a593Smuzhiyun } 894*4882a593Smuzhiyun } else { 895*4882a593Smuzhiyun if ($op eq "&&") { 896*4882a593Smuzhiyun return 0; 897*4882a593Smuzhiyun } 898*4882a593Smuzhiyun } 899*4882a593Smuzhiyun } 900*4882a593Smuzhiyun 901*4882a593Smuzhiyun if ($val =~ /(.*)(==|\!=|>=|<=|>|<|=~|\!~)(.*)/) { 902*4882a593Smuzhiyun my $ret = process_compare($1, $2, $3); 903*4882a593Smuzhiyun if ($ret < 0) { 904*4882a593Smuzhiyun die "$name: $.: Unable to process comparison\n"; 905*4882a593Smuzhiyun } 906*4882a593Smuzhiyun return $ret; 907*4882a593Smuzhiyun } 908*4882a593Smuzhiyun 909*4882a593Smuzhiyun if ($val =~ /^\s*(NOT\s*)?DEFINED\s+(\S+)\s*$/) { 910*4882a593Smuzhiyun if (defined $1) { 911*4882a593Smuzhiyun return !value_defined($2); 912*4882a593Smuzhiyun } else { 913*4882a593Smuzhiyun return value_defined($2); 914*4882a593Smuzhiyun } 915*4882a593Smuzhiyun } 916*4882a593Smuzhiyun 917*4882a593Smuzhiyun if ($val =~ s/^\s*NOT\s+(.*)//) { 918*4882a593Smuzhiyun my $express = $1; 919*4882a593Smuzhiyun my $ret = process_expression($name, $express); 920*4882a593Smuzhiyun return !$ret; 921*4882a593Smuzhiyun } 922*4882a593Smuzhiyun 923*4882a593Smuzhiyun if ($val =~ /^\s*0\s*$/) { 924*4882a593Smuzhiyun return 0; 925*4882a593Smuzhiyun } elsif ($val =~ /^\s*\d+\s*$/) { 926*4882a593Smuzhiyun return 1; 927*4882a593Smuzhiyun } 928*4882a593Smuzhiyun 929*4882a593Smuzhiyun die ("$name: $.: Undefined content $val in if statement\n"); 930*4882a593Smuzhiyun} 931*4882a593Smuzhiyun 932*4882a593Smuzhiyunsub process_if { 933*4882a593Smuzhiyun my ($name, $value) = @_; 934*4882a593Smuzhiyun 935*4882a593Smuzhiyun # Convert variables and replace undefined ones with 0 936*4882a593Smuzhiyun my $val = process_variables($value, 1); 937*4882a593Smuzhiyun my $ret = process_expression $name, $val; 938*4882a593Smuzhiyun 939*4882a593Smuzhiyun return $ret; 940*4882a593Smuzhiyun} 941*4882a593Smuzhiyun 942*4882a593Smuzhiyunsub __read_config { 943*4882a593Smuzhiyun my ($config, $current_test_num) = @_; 944*4882a593Smuzhiyun 945*4882a593Smuzhiyun my $in; 946*4882a593Smuzhiyun open($in, $config) || die "can't read file $config"; 947*4882a593Smuzhiyun 948*4882a593Smuzhiyun my $name = $config; 949*4882a593Smuzhiyun $name =~ s,.*/(.*),$1,; 950*4882a593Smuzhiyun 951*4882a593Smuzhiyun my $test_num = $$current_test_num; 952*4882a593Smuzhiyun my $default = 1; 953*4882a593Smuzhiyun my $repeat = 1; 954*4882a593Smuzhiyun my $num_tests_set = 0; 955*4882a593Smuzhiyun my $skip = 0; 956*4882a593Smuzhiyun my $rest; 957*4882a593Smuzhiyun my $line; 958*4882a593Smuzhiyun my $test_case = 0; 959*4882a593Smuzhiyun my $if = 0; 960*4882a593Smuzhiyun my $if_set = 0; 961*4882a593Smuzhiyun my $override = 0; 962*4882a593Smuzhiyun 963*4882a593Smuzhiyun my %overrides; 964*4882a593Smuzhiyun 965*4882a593Smuzhiyun while (<$in>) { 966*4882a593Smuzhiyun 967*4882a593Smuzhiyun # ignore blank lines and comments 968*4882a593Smuzhiyun next if (/^\s*$/ || /\s*\#/); 969*4882a593Smuzhiyun 970*4882a593Smuzhiyun if (/^\s*(TEST_START|DEFAULTS)\b(.*)/) { 971*4882a593Smuzhiyun 972*4882a593Smuzhiyun my $type = $1; 973*4882a593Smuzhiyun $rest = $2; 974*4882a593Smuzhiyun $line = $2; 975*4882a593Smuzhiyun 976*4882a593Smuzhiyun my $old_test_num; 977*4882a593Smuzhiyun my $old_repeat; 978*4882a593Smuzhiyun $override = 0; 979*4882a593Smuzhiyun 980*4882a593Smuzhiyun if ($type eq "TEST_START") { 981*4882a593Smuzhiyun 982*4882a593Smuzhiyun if ($num_tests_set) { 983*4882a593Smuzhiyun die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n"; 984*4882a593Smuzhiyun } 985*4882a593Smuzhiyun 986*4882a593Smuzhiyun $old_test_num = $test_num; 987*4882a593Smuzhiyun $old_repeat = $repeat; 988*4882a593Smuzhiyun 989*4882a593Smuzhiyun $test_num += $repeat; 990*4882a593Smuzhiyun $default = 0; 991*4882a593Smuzhiyun $repeat = 1; 992*4882a593Smuzhiyun } else { 993*4882a593Smuzhiyun $default = 1; 994*4882a593Smuzhiyun } 995*4882a593Smuzhiyun 996*4882a593Smuzhiyun # If SKIP is anywhere in the line, the command will be skipped 997*4882a593Smuzhiyun if ($rest =~ s/\s+SKIP\b//) { 998*4882a593Smuzhiyun $skip = 1; 999*4882a593Smuzhiyun } else { 1000*4882a593Smuzhiyun $test_case = 1; 1001*4882a593Smuzhiyun $skip = 0; 1002*4882a593Smuzhiyun } 1003*4882a593Smuzhiyun 1004*4882a593Smuzhiyun if ($rest =~ s/\sELSE\b//) { 1005*4882a593Smuzhiyun if (!$if) { 1006*4882a593Smuzhiyun die "$name: $.: ELSE found with out matching IF section\n$_"; 1007*4882a593Smuzhiyun } 1008*4882a593Smuzhiyun $if = 0; 1009*4882a593Smuzhiyun 1010*4882a593Smuzhiyun if ($if_set) { 1011*4882a593Smuzhiyun $skip = 1; 1012*4882a593Smuzhiyun } else { 1013*4882a593Smuzhiyun $skip = 0; 1014*4882a593Smuzhiyun } 1015*4882a593Smuzhiyun } 1016*4882a593Smuzhiyun 1017*4882a593Smuzhiyun if ($rest =~ s/\sIF\s+(.*)//) { 1018*4882a593Smuzhiyun if (process_if($name, $1)) { 1019*4882a593Smuzhiyun $if_set = 1; 1020*4882a593Smuzhiyun } else { 1021*4882a593Smuzhiyun $skip = 1; 1022*4882a593Smuzhiyun } 1023*4882a593Smuzhiyun $if = 1; 1024*4882a593Smuzhiyun } else { 1025*4882a593Smuzhiyun $if = 0; 1026*4882a593Smuzhiyun $if_set = 0; 1027*4882a593Smuzhiyun } 1028*4882a593Smuzhiyun 1029*4882a593Smuzhiyun if (!$skip) { 1030*4882a593Smuzhiyun if ($type eq "TEST_START") { 1031*4882a593Smuzhiyun if ($rest =~ s/\s+ITERATE\s+(\d+)//) { 1032*4882a593Smuzhiyun $repeat = $1; 1033*4882a593Smuzhiyun $repeat_tests{"$test_num"} = $repeat; 1034*4882a593Smuzhiyun } 1035*4882a593Smuzhiyun } elsif ($rest =~ s/\sOVERRIDE\b//) { 1036*4882a593Smuzhiyun # DEFAULT only 1037*4882a593Smuzhiyun $override = 1; 1038*4882a593Smuzhiyun # Clear previous overrides 1039*4882a593Smuzhiyun %overrides = (); 1040*4882a593Smuzhiyun } 1041*4882a593Smuzhiyun } 1042*4882a593Smuzhiyun 1043*4882a593Smuzhiyun if (!$skip && $rest !~ /^\s*$/) { 1044*4882a593Smuzhiyun die "$name: $.: Garbage found after $type\n$_"; 1045*4882a593Smuzhiyun } 1046*4882a593Smuzhiyun 1047*4882a593Smuzhiyun if ($skip && $type eq "TEST_START") { 1048*4882a593Smuzhiyun $test_num = $old_test_num; 1049*4882a593Smuzhiyun $repeat = $old_repeat; 1050*4882a593Smuzhiyun } 1051*4882a593Smuzhiyun 1052*4882a593Smuzhiyun } elsif (/^\s*ELSE\b(.*)$/) { 1053*4882a593Smuzhiyun if (!$if) { 1054*4882a593Smuzhiyun die "$name: $.: ELSE found with out matching IF section\n$_"; 1055*4882a593Smuzhiyun } 1056*4882a593Smuzhiyun $rest = $1; 1057*4882a593Smuzhiyun if ($if_set) { 1058*4882a593Smuzhiyun $skip = 1; 1059*4882a593Smuzhiyun $rest = ""; 1060*4882a593Smuzhiyun } else { 1061*4882a593Smuzhiyun $skip = 0; 1062*4882a593Smuzhiyun 1063*4882a593Smuzhiyun if ($rest =~ /\sIF\s+(.*)/) { 1064*4882a593Smuzhiyun # May be a ELSE IF section. 1065*4882a593Smuzhiyun if (process_if($name, $1)) { 1066*4882a593Smuzhiyun $if_set = 1; 1067*4882a593Smuzhiyun } else { 1068*4882a593Smuzhiyun $skip = 1; 1069*4882a593Smuzhiyun } 1070*4882a593Smuzhiyun $rest = ""; 1071*4882a593Smuzhiyun } else { 1072*4882a593Smuzhiyun $if = 0; 1073*4882a593Smuzhiyun } 1074*4882a593Smuzhiyun } 1075*4882a593Smuzhiyun 1076*4882a593Smuzhiyun if ($rest !~ /^\s*$/) { 1077*4882a593Smuzhiyun die "$name: $.: Garbage found after DEFAULTS\n$_"; 1078*4882a593Smuzhiyun } 1079*4882a593Smuzhiyun 1080*4882a593Smuzhiyun } elsif (/^\s*INCLUDE\s+(\S+)/) { 1081*4882a593Smuzhiyun 1082*4882a593Smuzhiyun next if ($skip); 1083*4882a593Smuzhiyun 1084*4882a593Smuzhiyun if (!$default) { 1085*4882a593Smuzhiyun die "$name: $.: INCLUDE can only be done in default sections\n$_"; 1086*4882a593Smuzhiyun } 1087*4882a593Smuzhiyun 1088*4882a593Smuzhiyun my $file = process_variables($1); 1089*4882a593Smuzhiyun 1090*4882a593Smuzhiyun if ($file !~ m,^/,) { 1091*4882a593Smuzhiyun # check the path of the config file first 1092*4882a593Smuzhiyun if ($config =~ m,(.*)/,) { 1093*4882a593Smuzhiyun if (-f "$1/$file") { 1094*4882a593Smuzhiyun $file = "$1/$file"; 1095*4882a593Smuzhiyun } 1096*4882a593Smuzhiyun } 1097*4882a593Smuzhiyun } 1098*4882a593Smuzhiyun 1099*4882a593Smuzhiyun if ( ! -r $file ) { 1100*4882a593Smuzhiyun die "$name: $.: Can't read file $file\n$_"; 1101*4882a593Smuzhiyun } 1102*4882a593Smuzhiyun 1103*4882a593Smuzhiyun if (__read_config($file, \$test_num)) { 1104*4882a593Smuzhiyun $test_case = 1; 1105*4882a593Smuzhiyun } 1106*4882a593Smuzhiyun 1107*4882a593Smuzhiyun } elsif (/^\s*([A-Z_\[\]\d]+)\s*=~\s*(.*?)\s*$/) { 1108*4882a593Smuzhiyun 1109*4882a593Smuzhiyun next if ($skip); 1110*4882a593Smuzhiyun 1111*4882a593Smuzhiyun my $lvalue = $1; 1112*4882a593Smuzhiyun my $rvalue = $2; 1113*4882a593Smuzhiyun 1114*4882a593Smuzhiyun if ($default || $lvalue =~ /\[\d+\]$/) { 1115*4882a593Smuzhiyun set_eval($lvalue, $rvalue, $name); 1116*4882a593Smuzhiyun } else { 1117*4882a593Smuzhiyun my $val = "$lvalue\[$test_num\]"; 1118*4882a593Smuzhiyun set_eval($val, $rvalue, $name); 1119*4882a593Smuzhiyun } 1120*4882a593Smuzhiyun 1121*4882a593Smuzhiyun } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) { 1122*4882a593Smuzhiyun 1123*4882a593Smuzhiyun next if ($skip); 1124*4882a593Smuzhiyun 1125*4882a593Smuzhiyun my $lvalue = $1; 1126*4882a593Smuzhiyun my $rvalue = $2; 1127*4882a593Smuzhiyun 1128*4882a593Smuzhiyun if (!$default && 1129*4882a593Smuzhiyun ($lvalue eq "NUM_TESTS" || 1130*4882a593Smuzhiyun $lvalue eq "LOG_FILE" || 1131*4882a593Smuzhiyun $lvalue eq "CLEAR_LOG")) { 1132*4882a593Smuzhiyun die "$name: $.: $lvalue must be set in DEFAULTS section\n"; 1133*4882a593Smuzhiyun } 1134*4882a593Smuzhiyun 1135*4882a593Smuzhiyun if ($lvalue eq "NUM_TESTS") { 1136*4882a593Smuzhiyun if ($test_num) { 1137*4882a593Smuzhiyun die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n"; 1138*4882a593Smuzhiyun } 1139*4882a593Smuzhiyun if (!$default) { 1140*4882a593Smuzhiyun die "$name: $.: NUM_TESTS must be set in default section\n"; 1141*4882a593Smuzhiyun } 1142*4882a593Smuzhiyun $num_tests_set = 1; 1143*4882a593Smuzhiyun } 1144*4882a593Smuzhiyun 1145*4882a593Smuzhiyun if ($default || $lvalue =~ /\[\d+\]$/) { 1146*4882a593Smuzhiyun set_value($lvalue, $rvalue, $override, \%overrides, $name); 1147*4882a593Smuzhiyun } else { 1148*4882a593Smuzhiyun my $val = "$lvalue\[$test_num\]"; 1149*4882a593Smuzhiyun set_value($val, $rvalue, $override, \%overrides, $name); 1150*4882a593Smuzhiyun 1151*4882a593Smuzhiyun if ($repeat > 1) { 1152*4882a593Smuzhiyun $repeats{$val} = $repeat; 1153*4882a593Smuzhiyun } 1154*4882a593Smuzhiyun } 1155*4882a593Smuzhiyun } elsif (/^\s*([A-Z_\[\]\d]+)\s*:=\s*(.*?)\s*$/) { 1156*4882a593Smuzhiyun next if ($skip); 1157*4882a593Smuzhiyun 1158*4882a593Smuzhiyun my $lvalue = $1; 1159*4882a593Smuzhiyun my $rvalue = $2; 1160*4882a593Smuzhiyun 1161*4882a593Smuzhiyun # process config variables. 1162*4882a593Smuzhiyun # Config variables are only active while reading the 1163*4882a593Smuzhiyun # config and can be defined anywhere. They also ignore 1164*4882a593Smuzhiyun # TEST_START and DEFAULTS, but are skipped if they are in 1165*4882a593Smuzhiyun # on of these sections that have SKIP defined. 1166*4882a593Smuzhiyun # The save variable can be 1167*4882a593Smuzhiyun # defined multiple times and the new one simply overrides 1168*4882a593Smuzhiyun # the previous one. 1169*4882a593Smuzhiyun set_variable($lvalue, $rvalue); 1170*4882a593Smuzhiyun 1171*4882a593Smuzhiyun } else { 1172*4882a593Smuzhiyun die "$name: $.: Garbage found in config\n$_"; 1173*4882a593Smuzhiyun } 1174*4882a593Smuzhiyun } 1175*4882a593Smuzhiyun 1176*4882a593Smuzhiyun if ($test_num) { 1177*4882a593Smuzhiyun $test_num += $repeat - 1; 1178*4882a593Smuzhiyun $opt{"NUM_TESTS"} = $test_num; 1179*4882a593Smuzhiyun } 1180*4882a593Smuzhiyun 1181*4882a593Smuzhiyun close($in); 1182*4882a593Smuzhiyun 1183*4882a593Smuzhiyun $$current_test_num = $test_num; 1184*4882a593Smuzhiyun 1185*4882a593Smuzhiyun return $test_case; 1186*4882a593Smuzhiyun} 1187*4882a593Smuzhiyun 1188*4882a593Smuzhiyunsub get_test_case { 1189*4882a593Smuzhiyun print "What test case would you like to run?\n"; 1190*4882a593Smuzhiyun print " (build, install or boot)\n"; 1191*4882a593Smuzhiyun print " Other tests are available but require editing ktest.conf\n"; 1192*4882a593Smuzhiyun print " (see tools/testing/ktest/sample.conf)\n"; 1193*4882a593Smuzhiyun my $ans = <STDIN>; 1194*4882a593Smuzhiyun chomp $ans; 1195*4882a593Smuzhiyun $default{"TEST_TYPE"} = $ans; 1196*4882a593Smuzhiyun} 1197*4882a593Smuzhiyun 1198*4882a593Smuzhiyunsub read_config { 1199*4882a593Smuzhiyun my ($config) = @_; 1200*4882a593Smuzhiyun 1201*4882a593Smuzhiyun my $test_case; 1202*4882a593Smuzhiyun my $test_num = 0; 1203*4882a593Smuzhiyun 1204*4882a593Smuzhiyun $test_case = __read_config $config, \$test_num; 1205*4882a593Smuzhiyun 1206*4882a593Smuzhiyun # make sure we have all mandatory configs 1207*4882a593Smuzhiyun get_mandatory_configs; 1208*4882a593Smuzhiyun 1209*4882a593Smuzhiyun # was a test specified? 1210*4882a593Smuzhiyun if (!$test_case) { 1211*4882a593Smuzhiyun print "No test case specified.\n"; 1212*4882a593Smuzhiyun get_test_case; 1213*4882a593Smuzhiyun } 1214*4882a593Smuzhiyun 1215*4882a593Smuzhiyun # set any defaults 1216*4882a593Smuzhiyun 1217*4882a593Smuzhiyun foreach my $default (keys %default) { 1218*4882a593Smuzhiyun if (!defined($opt{$default})) { 1219*4882a593Smuzhiyun $opt{$default} = $default{$default}; 1220*4882a593Smuzhiyun } 1221*4882a593Smuzhiyun } 1222*4882a593Smuzhiyun 1223*4882a593Smuzhiyun if ($opt{"IGNORE_UNUSED"} == 1) { 1224*4882a593Smuzhiyun return; 1225*4882a593Smuzhiyun } 1226*4882a593Smuzhiyun 1227*4882a593Smuzhiyun my %not_used; 1228*4882a593Smuzhiyun 1229*4882a593Smuzhiyun # check if there are any stragglers (typos?) 1230*4882a593Smuzhiyun foreach my $option (keys %opt) { 1231*4882a593Smuzhiyun my $op = $option; 1232*4882a593Smuzhiyun # remove per test labels. 1233*4882a593Smuzhiyun $op =~ s/\[.*\]//; 1234*4882a593Smuzhiyun if (!exists($option_map{$op}) && 1235*4882a593Smuzhiyun !exists($default{$op}) && 1236*4882a593Smuzhiyun !exists($used_options{$op})) { 1237*4882a593Smuzhiyun $not_used{$op} = 1; 1238*4882a593Smuzhiyun } 1239*4882a593Smuzhiyun } 1240*4882a593Smuzhiyun 1241*4882a593Smuzhiyun if (%not_used) { 1242*4882a593Smuzhiyun my $s = "s are"; 1243*4882a593Smuzhiyun $s = " is" if (keys %not_used == 1); 1244*4882a593Smuzhiyun print "The following option$s not used; could be a typo:\n"; 1245*4882a593Smuzhiyun foreach my $option (keys %not_used) { 1246*4882a593Smuzhiyun print "$option\n"; 1247*4882a593Smuzhiyun } 1248*4882a593Smuzhiyun print "Set IGNORE_UNUSED = 1 to have ktest ignore unused variables\n"; 1249*4882a593Smuzhiyun if (!read_yn "Do you want to continue?") { 1250*4882a593Smuzhiyun exit -1; 1251*4882a593Smuzhiyun } 1252*4882a593Smuzhiyun } 1253*4882a593Smuzhiyun} 1254*4882a593Smuzhiyun 1255*4882a593Smuzhiyunsub __eval_option { 1256*4882a593Smuzhiyun my ($name, $option, $i) = @_; 1257*4882a593Smuzhiyun 1258*4882a593Smuzhiyun # Add space to evaluate the character before $ 1259*4882a593Smuzhiyun $option = " $option"; 1260*4882a593Smuzhiyun my $retval = ""; 1261*4882a593Smuzhiyun my $repeated = 0; 1262*4882a593Smuzhiyun my $parent = 0; 1263*4882a593Smuzhiyun 1264*4882a593Smuzhiyun foreach my $test (keys %repeat_tests) { 1265*4882a593Smuzhiyun if ($i >= $test && 1266*4882a593Smuzhiyun $i < $test + $repeat_tests{$test}) { 1267*4882a593Smuzhiyun 1268*4882a593Smuzhiyun $repeated = 1; 1269*4882a593Smuzhiyun $parent = $test; 1270*4882a593Smuzhiyun last; 1271*4882a593Smuzhiyun } 1272*4882a593Smuzhiyun } 1273*4882a593Smuzhiyun 1274*4882a593Smuzhiyun while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { 1275*4882a593Smuzhiyun my $start = $1; 1276*4882a593Smuzhiyun my $var = $2; 1277*4882a593Smuzhiyun my $end = $3; 1278*4882a593Smuzhiyun 1279*4882a593Smuzhiyun # Append beginning of line 1280*4882a593Smuzhiyun $retval = "$retval$start"; 1281*4882a593Smuzhiyun 1282*4882a593Smuzhiyun # If the iteration option OPT[$i] exists, then use that. 1283*4882a593Smuzhiyun # otherwise see if the default OPT (without [$i]) exists. 1284*4882a593Smuzhiyun 1285*4882a593Smuzhiyun my $o = "$var\[$i\]"; 1286*4882a593Smuzhiyun my $parento = "$var\[$parent\]"; 1287*4882a593Smuzhiyun 1288*4882a593Smuzhiyun # If a variable contains itself, use the default var 1289*4882a593Smuzhiyun if (($var eq $name) && defined($opt{$var})) { 1290*4882a593Smuzhiyun $o = $opt{$var}; 1291*4882a593Smuzhiyun $retval = "$retval$o"; 1292*4882a593Smuzhiyun } elsif (defined($opt{$o})) { 1293*4882a593Smuzhiyun $o = $opt{$o}; 1294*4882a593Smuzhiyun $retval = "$retval$o"; 1295*4882a593Smuzhiyun } elsif ($repeated && defined($opt{$parento})) { 1296*4882a593Smuzhiyun $o = $opt{$parento}; 1297*4882a593Smuzhiyun $retval = "$retval$o"; 1298*4882a593Smuzhiyun } elsif (defined($opt{$var})) { 1299*4882a593Smuzhiyun $o = $opt{$var}; 1300*4882a593Smuzhiyun $retval = "$retval$o"; 1301*4882a593Smuzhiyun } elsif ($var eq "KERNEL_VERSION" && defined($make)) { 1302*4882a593Smuzhiyun # special option KERNEL_VERSION uses kernel version 1303*4882a593Smuzhiyun get_version(); 1304*4882a593Smuzhiyun $retval = "$retval$version"; 1305*4882a593Smuzhiyun } else { 1306*4882a593Smuzhiyun $retval = "$retval\$\{$var\}"; 1307*4882a593Smuzhiyun } 1308*4882a593Smuzhiyun 1309*4882a593Smuzhiyun $option = $end; 1310*4882a593Smuzhiyun } 1311*4882a593Smuzhiyun 1312*4882a593Smuzhiyun $retval = "$retval$option"; 1313*4882a593Smuzhiyun 1314*4882a593Smuzhiyun $retval =~ s/^ //; 1315*4882a593Smuzhiyun 1316*4882a593Smuzhiyun return $retval; 1317*4882a593Smuzhiyun} 1318*4882a593Smuzhiyun 1319*4882a593Smuzhiyunsub process_evals { 1320*4882a593Smuzhiyun my ($name, $option, $i) = @_; 1321*4882a593Smuzhiyun 1322*4882a593Smuzhiyun my $option_name = "$name\[$i\]"; 1323*4882a593Smuzhiyun my $ev; 1324*4882a593Smuzhiyun 1325*4882a593Smuzhiyun my $old_option = $option; 1326*4882a593Smuzhiyun 1327*4882a593Smuzhiyun if (defined($evals{$option_name})) { 1328*4882a593Smuzhiyun $ev = $evals{$option_name}; 1329*4882a593Smuzhiyun } elsif (defined($evals{$name})) { 1330*4882a593Smuzhiyun $ev = $evals{$name}; 1331*4882a593Smuzhiyun } else { 1332*4882a593Smuzhiyun return $option; 1333*4882a593Smuzhiyun } 1334*4882a593Smuzhiyun 1335*4882a593Smuzhiyun for my $e (@{$ev}) { 1336*4882a593Smuzhiyun eval "\$option =~ $e"; 1337*4882a593Smuzhiyun } 1338*4882a593Smuzhiyun 1339*4882a593Smuzhiyun if ($option ne $old_option) { 1340*4882a593Smuzhiyun doprint("$name changed from '$old_option' to '$option'\n"); 1341*4882a593Smuzhiyun } 1342*4882a593Smuzhiyun 1343*4882a593Smuzhiyun return $option; 1344*4882a593Smuzhiyun} 1345*4882a593Smuzhiyun 1346*4882a593Smuzhiyunsub eval_option { 1347*4882a593Smuzhiyun my ($name, $option, $i) = @_; 1348*4882a593Smuzhiyun 1349*4882a593Smuzhiyun my $prev = ""; 1350*4882a593Smuzhiyun 1351*4882a593Smuzhiyun # Since an option can evaluate to another option, 1352*4882a593Smuzhiyun # keep iterating until we do not evaluate any more 1353*4882a593Smuzhiyun # options. 1354*4882a593Smuzhiyun my $r = 0; 1355*4882a593Smuzhiyun while ($prev ne $option) { 1356*4882a593Smuzhiyun # Check for recursive evaluations. 1357*4882a593Smuzhiyun # 100 deep should be more than enough. 1358*4882a593Smuzhiyun if ($r++ > 100) { 1359*4882a593Smuzhiyun die "Over 100 evaluations occurred with $option\n" . 1360*4882a593Smuzhiyun "Check for recursive variables\n"; 1361*4882a593Smuzhiyun } 1362*4882a593Smuzhiyun $prev = $option; 1363*4882a593Smuzhiyun $option = __eval_option($name, $option, $i); 1364*4882a593Smuzhiyun } 1365*4882a593Smuzhiyun 1366*4882a593Smuzhiyun $option = process_evals($name, $option, $i); 1367*4882a593Smuzhiyun 1368*4882a593Smuzhiyun return $option; 1369*4882a593Smuzhiyun} 1370*4882a593Smuzhiyun 1371*4882a593Smuzhiyunsub run_command; 1372*4882a593Smuzhiyunsub start_monitor; 1373*4882a593Smuzhiyunsub end_monitor; 1374*4882a593Smuzhiyunsub wait_for_monitor; 1375*4882a593Smuzhiyun 1376*4882a593Smuzhiyunsub reboot { 1377*4882a593Smuzhiyun my ($time) = @_; 1378*4882a593Smuzhiyun my $powercycle = 0; 1379*4882a593Smuzhiyun 1380*4882a593Smuzhiyun # test if the machine can be connected to within a few seconds 1381*4882a593Smuzhiyun my $stat = run_ssh("echo check machine status", $connect_timeout); 1382*4882a593Smuzhiyun if (!$stat) { 1383*4882a593Smuzhiyun doprint("power cycle\n"); 1384*4882a593Smuzhiyun $powercycle = 1; 1385*4882a593Smuzhiyun } 1386*4882a593Smuzhiyun 1387*4882a593Smuzhiyun if ($powercycle) { 1388*4882a593Smuzhiyun run_command "$power_cycle"; 1389*4882a593Smuzhiyun 1390*4882a593Smuzhiyun start_monitor; 1391*4882a593Smuzhiyun # flush out current monitor 1392*4882a593Smuzhiyun # May contain the reboot success line 1393*4882a593Smuzhiyun wait_for_monitor 1; 1394*4882a593Smuzhiyun 1395*4882a593Smuzhiyun } else { 1396*4882a593Smuzhiyun # Make sure everything has been written to disk 1397*4882a593Smuzhiyun run_ssh("sync", 10); 1398*4882a593Smuzhiyun 1399*4882a593Smuzhiyun if (defined($time)) { 1400*4882a593Smuzhiyun start_monitor; 1401*4882a593Smuzhiyun # flush out current monitor 1402*4882a593Smuzhiyun # May contain the reboot success line 1403*4882a593Smuzhiyun wait_for_monitor 1; 1404*4882a593Smuzhiyun } 1405*4882a593Smuzhiyun 1406*4882a593Smuzhiyun # try to reboot normally 1407*4882a593Smuzhiyun if (run_command $reboot) { 1408*4882a593Smuzhiyun if (defined($powercycle_after_reboot)) { 1409*4882a593Smuzhiyun sleep $powercycle_after_reboot; 1410*4882a593Smuzhiyun run_command "$power_cycle"; 1411*4882a593Smuzhiyun } 1412*4882a593Smuzhiyun } else { 1413*4882a593Smuzhiyun # nope? power cycle it. 1414*4882a593Smuzhiyun run_command "$power_cycle"; 1415*4882a593Smuzhiyun } 1416*4882a593Smuzhiyun } 1417*4882a593Smuzhiyun 1418*4882a593Smuzhiyun if (defined($time)) { 1419*4882a593Smuzhiyun 1420*4882a593Smuzhiyun # We only want to get to the new kernel, don't fail 1421*4882a593Smuzhiyun # if we stumble over a call trace. 1422*4882a593Smuzhiyun my $save_ignore_errors = $ignore_errors; 1423*4882a593Smuzhiyun $ignore_errors = 1; 1424*4882a593Smuzhiyun 1425*4882a593Smuzhiyun # Look for the good kernel to boot 1426*4882a593Smuzhiyun if (wait_for_monitor($time, "Linux version")) { 1427*4882a593Smuzhiyun # reboot got stuck? 1428*4882a593Smuzhiyun doprint "Reboot did not finish. Forcing power cycle\n"; 1429*4882a593Smuzhiyun run_command "$power_cycle"; 1430*4882a593Smuzhiyun } 1431*4882a593Smuzhiyun 1432*4882a593Smuzhiyun $ignore_errors = $save_ignore_errors; 1433*4882a593Smuzhiyun 1434*4882a593Smuzhiyun # Still need to wait for the reboot to finish 1435*4882a593Smuzhiyun wait_for_monitor($time, $reboot_success_line); 1436*4882a593Smuzhiyun 1437*4882a593Smuzhiyun end_monitor; 1438*4882a593Smuzhiyun } 1439*4882a593Smuzhiyun} 1440*4882a593Smuzhiyun 1441*4882a593Smuzhiyunsub reboot_to_good { 1442*4882a593Smuzhiyun my ($time) = @_; 1443*4882a593Smuzhiyun 1444*4882a593Smuzhiyun if (defined($switch_to_good)) { 1445*4882a593Smuzhiyun run_command $switch_to_good; 1446*4882a593Smuzhiyun } 1447*4882a593Smuzhiyun 1448*4882a593Smuzhiyun reboot $time; 1449*4882a593Smuzhiyun} 1450*4882a593Smuzhiyun 1451*4882a593Smuzhiyunsub do_not_reboot { 1452*4882a593Smuzhiyun my $i = $iteration; 1453*4882a593Smuzhiyun 1454*4882a593Smuzhiyun return $test_type eq "build" || $no_reboot || 1455*4882a593Smuzhiyun ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || 1456*4882a593Smuzhiyun ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build") || 1457*4882a593Smuzhiyun ($test_type eq "config_bisect" && $opt{"CONFIG_BISECT_TYPE[$i]"} eq "build"); 1458*4882a593Smuzhiyun} 1459*4882a593Smuzhiyun 1460*4882a593Smuzhiyunmy $in_die = 0; 1461*4882a593Smuzhiyun 1462*4882a593Smuzhiyunsub get_test_name() { 1463*4882a593Smuzhiyun my $name; 1464*4882a593Smuzhiyun 1465*4882a593Smuzhiyun if (defined($test_name)) { 1466*4882a593Smuzhiyun $name = "$test_name:$test_type"; 1467*4882a593Smuzhiyun } else { 1468*4882a593Smuzhiyun $name = $test_type; 1469*4882a593Smuzhiyun } 1470*4882a593Smuzhiyun return $name; 1471*4882a593Smuzhiyun} 1472*4882a593Smuzhiyun 1473*4882a593Smuzhiyunsub dodie { 1474*4882a593Smuzhiyun 1475*4882a593Smuzhiyun # avoid recursion 1476*4882a593Smuzhiyun return if ($in_die); 1477*4882a593Smuzhiyun $in_die = 1; 1478*4882a593Smuzhiyun 1479*4882a593Smuzhiyun my $i = $iteration; 1480*4882a593Smuzhiyun 1481*4882a593Smuzhiyun doprint "CRITICAL FAILURE... [TEST $i] ", @_, "\n"; 1482*4882a593Smuzhiyun 1483*4882a593Smuzhiyun if ($reboot_on_error && !do_not_reboot) { 1484*4882a593Smuzhiyun 1485*4882a593Smuzhiyun doprint "REBOOTING\n"; 1486*4882a593Smuzhiyun reboot_to_good; 1487*4882a593Smuzhiyun 1488*4882a593Smuzhiyun } elsif ($poweroff_on_error && defined($power_off)) { 1489*4882a593Smuzhiyun doprint "POWERING OFF\n"; 1490*4882a593Smuzhiyun `$power_off`; 1491*4882a593Smuzhiyun } 1492*4882a593Smuzhiyun 1493*4882a593Smuzhiyun if (defined($opt{"LOG_FILE"})) { 1494*4882a593Smuzhiyun print " See $opt{LOG_FILE} for more info.\n"; 1495*4882a593Smuzhiyun } 1496*4882a593Smuzhiyun 1497*4882a593Smuzhiyun if ($email_on_error) { 1498*4882a593Smuzhiyun my $name = get_test_name; 1499*4882a593Smuzhiyun my $log_file; 1500*4882a593Smuzhiyun 1501*4882a593Smuzhiyun if (defined($opt{"LOG_FILE"})) { 1502*4882a593Smuzhiyun my $whence = 2; # End of file 1503*4882a593Smuzhiyun my $log_size = tell LOG; 1504*4882a593Smuzhiyun my $size = $log_size - $test_log_start; 1505*4882a593Smuzhiyun 1506*4882a593Smuzhiyun if (defined($mail_max_size)) { 1507*4882a593Smuzhiyun if ($size > $mail_max_size) { 1508*4882a593Smuzhiyun $size = $mail_max_size; 1509*4882a593Smuzhiyun } 1510*4882a593Smuzhiyun } 1511*4882a593Smuzhiyun my $pos = - $size; 1512*4882a593Smuzhiyun $log_file = "$tmpdir/log"; 1513*4882a593Smuzhiyun open (L, "$opt{LOG_FILE}") or die "Can't open $opt{LOG_FILE} to read)"; 1514*4882a593Smuzhiyun open (O, "> $tmpdir/log") or die "Can't open $tmpdir/log\n"; 1515*4882a593Smuzhiyun seek(L, $pos, $whence); 1516*4882a593Smuzhiyun while (<L>) { 1517*4882a593Smuzhiyun print O; 1518*4882a593Smuzhiyun } 1519*4882a593Smuzhiyun close O; 1520*4882a593Smuzhiyun close L; 1521*4882a593Smuzhiyun } 1522*4882a593Smuzhiyun send_email("KTEST: critical failure for test $i [$name]", 1523*4882a593Smuzhiyun "Your test started at $script_start_time has failed with:\n@_\n", $log_file); 1524*4882a593Smuzhiyun } 1525*4882a593Smuzhiyun 1526*4882a593Smuzhiyun if ($monitor_cnt) { 1527*4882a593Smuzhiyun # restore terminal settings 1528*4882a593Smuzhiyun system("stty $stty_orig"); 1529*4882a593Smuzhiyun } 1530*4882a593Smuzhiyun 1531*4882a593Smuzhiyun if (defined($post_test)) { 1532*4882a593Smuzhiyun run_command $post_test; 1533*4882a593Smuzhiyun } 1534*4882a593Smuzhiyun 1535*4882a593Smuzhiyun die @_, "\n"; 1536*4882a593Smuzhiyun} 1537*4882a593Smuzhiyun 1538*4882a593Smuzhiyunsub create_pty { 1539*4882a593Smuzhiyun my ($ptm, $pts) = @_; 1540*4882a593Smuzhiyun my $tmp; 1541*4882a593Smuzhiyun my $TIOCSPTLCK = 0x40045431; 1542*4882a593Smuzhiyun my $TIOCGPTN = 0x80045430; 1543*4882a593Smuzhiyun 1544*4882a593Smuzhiyun sysopen($ptm, "/dev/ptmx", O_RDWR | O_NONBLOCK) or 1545*4882a593Smuzhiyun dodie "Can't open /dev/ptmx"; 1546*4882a593Smuzhiyun 1547*4882a593Smuzhiyun # unlockpt() 1548*4882a593Smuzhiyun $tmp = pack("i", 0); 1549*4882a593Smuzhiyun ioctl($ptm, $TIOCSPTLCK, $tmp) or 1550*4882a593Smuzhiyun dodie "ioctl TIOCSPTLCK for /dev/ptmx failed"; 1551*4882a593Smuzhiyun 1552*4882a593Smuzhiyun # ptsname() 1553*4882a593Smuzhiyun ioctl($ptm, $TIOCGPTN, $tmp) or 1554*4882a593Smuzhiyun dodie "ioctl TIOCGPTN for /dev/ptmx failed"; 1555*4882a593Smuzhiyun $tmp = unpack("i", $tmp); 1556*4882a593Smuzhiyun 1557*4882a593Smuzhiyun sysopen($pts, "/dev/pts/$tmp", O_RDWR | O_NONBLOCK) or 1558*4882a593Smuzhiyun dodie "Can't open /dev/pts/$tmp"; 1559*4882a593Smuzhiyun} 1560*4882a593Smuzhiyun 1561*4882a593Smuzhiyunsub exec_console { 1562*4882a593Smuzhiyun my ($ptm, $pts) = @_; 1563*4882a593Smuzhiyun 1564*4882a593Smuzhiyun close($ptm); 1565*4882a593Smuzhiyun 1566*4882a593Smuzhiyun close(\*STDIN); 1567*4882a593Smuzhiyun close(\*STDOUT); 1568*4882a593Smuzhiyun close(\*STDERR); 1569*4882a593Smuzhiyun 1570*4882a593Smuzhiyun open(\*STDIN, '<&', $pts); 1571*4882a593Smuzhiyun open(\*STDOUT, '>&', $pts); 1572*4882a593Smuzhiyun open(\*STDERR, '>&', $pts); 1573*4882a593Smuzhiyun 1574*4882a593Smuzhiyun close($pts); 1575*4882a593Smuzhiyun 1576*4882a593Smuzhiyun exec $console or 1577*4882a593Smuzhiyun dodie "Can't open console $console"; 1578*4882a593Smuzhiyun} 1579*4882a593Smuzhiyun 1580*4882a593Smuzhiyunsub open_console { 1581*4882a593Smuzhiyun my ($ptm) = @_; 1582*4882a593Smuzhiyun my $pts = \*PTSFD; 1583*4882a593Smuzhiyun my $pid; 1584*4882a593Smuzhiyun 1585*4882a593Smuzhiyun # save terminal settings 1586*4882a593Smuzhiyun $stty_orig = `stty -g`; 1587*4882a593Smuzhiyun 1588*4882a593Smuzhiyun # place terminal in cbreak mode so that stdin can be read one character at 1589*4882a593Smuzhiyun # a time without having to wait for a newline 1590*4882a593Smuzhiyun system("stty -icanon -echo -icrnl"); 1591*4882a593Smuzhiyun 1592*4882a593Smuzhiyun create_pty($ptm, $pts); 1593*4882a593Smuzhiyun 1594*4882a593Smuzhiyun $pid = fork; 1595*4882a593Smuzhiyun 1596*4882a593Smuzhiyun if (!$pid) { 1597*4882a593Smuzhiyun # child 1598*4882a593Smuzhiyun exec_console($ptm, $pts) 1599*4882a593Smuzhiyun } 1600*4882a593Smuzhiyun 1601*4882a593Smuzhiyun # parent 1602*4882a593Smuzhiyun close($pts); 1603*4882a593Smuzhiyun 1604*4882a593Smuzhiyun return $pid; 1605*4882a593Smuzhiyun 1606*4882a593Smuzhiyun open(PTSFD, "Stop perl from warning about single use of PTSFD"); 1607*4882a593Smuzhiyun} 1608*4882a593Smuzhiyun 1609*4882a593Smuzhiyunsub close_console { 1610*4882a593Smuzhiyun my ($fp, $pid) = @_; 1611*4882a593Smuzhiyun 1612*4882a593Smuzhiyun doprint "kill child process $pid\n"; 1613*4882a593Smuzhiyun kill $close_console_signal, $pid; 1614*4882a593Smuzhiyun 1615*4882a593Smuzhiyun doprint "wait for child process $pid to exit\n"; 1616*4882a593Smuzhiyun waitpid($pid, 0); 1617*4882a593Smuzhiyun 1618*4882a593Smuzhiyun print "closing!\n"; 1619*4882a593Smuzhiyun close($fp); 1620*4882a593Smuzhiyun 1621*4882a593Smuzhiyun # restore terminal settings 1622*4882a593Smuzhiyun system("stty $stty_orig"); 1623*4882a593Smuzhiyun} 1624*4882a593Smuzhiyun 1625*4882a593Smuzhiyunsub start_monitor { 1626*4882a593Smuzhiyun if ($monitor_cnt++) { 1627*4882a593Smuzhiyun return; 1628*4882a593Smuzhiyun } 1629*4882a593Smuzhiyun $monitor_fp = \*MONFD; 1630*4882a593Smuzhiyun $monitor_pid = open_console $monitor_fp; 1631*4882a593Smuzhiyun 1632*4882a593Smuzhiyun return; 1633*4882a593Smuzhiyun 1634*4882a593Smuzhiyun open(MONFD, "Stop perl from warning about single use of MONFD"); 1635*4882a593Smuzhiyun} 1636*4882a593Smuzhiyun 1637*4882a593Smuzhiyunsub end_monitor { 1638*4882a593Smuzhiyun return if (!defined $console); 1639*4882a593Smuzhiyun if (--$monitor_cnt) { 1640*4882a593Smuzhiyun return; 1641*4882a593Smuzhiyun } 1642*4882a593Smuzhiyun close_console($monitor_fp, $monitor_pid); 1643*4882a593Smuzhiyun} 1644*4882a593Smuzhiyun 1645*4882a593Smuzhiyunsub wait_for_monitor { 1646*4882a593Smuzhiyun my ($time, $stop) = @_; 1647*4882a593Smuzhiyun my $full_line = ""; 1648*4882a593Smuzhiyun my $line; 1649*4882a593Smuzhiyun my $booted = 0; 1650*4882a593Smuzhiyun my $start_time = time; 1651*4882a593Smuzhiyun my $skip_call_trace = 0; 1652*4882a593Smuzhiyun my $bug = 0; 1653*4882a593Smuzhiyun my $bug_ignored = 0; 1654*4882a593Smuzhiyun my $now; 1655*4882a593Smuzhiyun 1656*4882a593Smuzhiyun doprint "** Wait for monitor to settle down **\n"; 1657*4882a593Smuzhiyun 1658*4882a593Smuzhiyun # read the monitor and wait for the system to calm down 1659*4882a593Smuzhiyun while (!$booted) { 1660*4882a593Smuzhiyun $line = wait_for_input($monitor_fp, $time); 1661*4882a593Smuzhiyun last if (!defined($line)); 1662*4882a593Smuzhiyun print "$line"; 1663*4882a593Smuzhiyun $full_line .= $line; 1664*4882a593Smuzhiyun 1665*4882a593Smuzhiyun if (defined($stop) && $full_line =~ /$stop/) { 1666*4882a593Smuzhiyun doprint "wait for monitor detected $stop\n"; 1667*4882a593Smuzhiyun $booted = 1; 1668*4882a593Smuzhiyun } 1669*4882a593Smuzhiyun 1670*4882a593Smuzhiyun if ($full_line =~ /\[ backtrace testing \]/) { 1671*4882a593Smuzhiyun $skip_call_trace = 1; 1672*4882a593Smuzhiyun } 1673*4882a593Smuzhiyun 1674*4882a593Smuzhiyun if ($full_line =~ /call trace:/i) { 1675*4882a593Smuzhiyun if (!$bug && !$skip_call_trace) { 1676*4882a593Smuzhiyun if ($ignore_errors) { 1677*4882a593Smuzhiyun $bug_ignored = 1; 1678*4882a593Smuzhiyun } else { 1679*4882a593Smuzhiyun $bug = 1; 1680*4882a593Smuzhiyun } 1681*4882a593Smuzhiyun } 1682*4882a593Smuzhiyun } 1683*4882a593Smuzhiyun 1684*4882a593Smuzhiyun if ($full_line =~ /\[ end of backtrace testing \]/) { 1685*4882a593Smuzhiyun $skip_call_trace = 0; 1686*4882a593Smuzhiyun } 1687*4882a593Smuzhiyun 1688*4882a593Smuzhiyun if ($full_line =~ /Kernel panic -/) { 1689*4882a593Smuzhiyun $bug = 1; 1690*4882a593Smuzhiyun } 1691*4882a593Smuzhiyun 1692*4882a593Smuzhiyun if ($line =~ /\n/) { 1693*4882a593Smuzhiyun $full_line = ""; 1694*4882a593Smuzhiyun } 1695*4882a593Smuzhiyun $now = time; 1696*4882a593Smuzhiyun if ($now - $start_time >= $max_monitor_wait) { 1697*4882a593Smuzhiyun doprint "Exiting monitor flush due to hitting MAX_MONITOR_WAIT\n"; 1698*4882a593Smuzhiyun return 1; 1699*4882a593Smuzhiyun } 1700*4882a593Smuzhiyun } 1701*4882a593Smuzhiyun print "** Monitor flushed **\n"; 1702*4882a593Smuzhiyun 1703*4882a593Smuzhiyun # if stop is defined but wasn't hit, return error 1704*4882a593Smuzhiyun # used by reboot (which wants to see a reboot) 1705*4882a593Smuzhiyun if (defined($stop) && !$booted) { 1706*4882a593Smuzhiyun $bug = 1; 1707*4882a593Smuzhiyun } 1708*4882a593Smuzhiyun return $bug; 1709*4882a593Smuzhiyun} 1710*4882a593Smuzhiyun 1711*4882a593Smuzhiyunsub save_logs { 1712*4882a593Smuzhiyun my ($result, $basedir) = @_; 1713*4882a593Smuzhiyun my @t = localtime; 1714*4882a593Smuzhiyun my $date = sprintf "%04d%02d%02d%02d%02d%02d", 1715*4882a593Smuzhiyun 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0]; 1716*4882a593Smuzhiyun 1717*4882a593Smuzhiyun my $type = $build_type; 1718*4882a593Smuzhiyun if ($type =~ /useconfig/) { 1719*4882a593Smuzhiyun $type = "useconfig"; 1720*4882a593Smuzhiyun } 1721*4882a593Smuzhiyun 1722*4882a593Smuzhiyun my $dir = "$machine-$test_type-$type-$result-$date"; 1723*4882a593Smuzhiyun 1724*4882a593Smuzhiyun $dir = "$basedir/$dir"; 1725*4882a593Smuzhiyun 1726*4882a593Smuzhiyun if (!-d $dir) { 1727*4882a593Smuzhiyun mkpath($dir) or 1728*4882a593Smuzhiyun dodie "can't create $dir"; 1729*4882a593Smuzhiyun } 1730*4882a593Smuzhiyun 1731*4882a593Smuzhiyun my %files = ( 1732*4882a593Smuzhiyun "config" => $output_config, 1733*4882a593Smuzhiyun "buildlog" => $buildlog, 1734*4882a593Smuzhiyun "dmesg" => $dmesg, 1735*4882a593Smuzhiyun "testlog" => $testlog, 1736*4882a593Smuzhiyun ); 1737*4882a593Smuzhiyun 1738*4882a593Smuzhiyun while (my ($name, $source) = each(%files)) { 1739*4882a593Smuzhiyun if (-f "$source") { 1740*4882a593Smuzhiyun cp "$source", "$dir/$name" or 1741*4882a593Smuzhiyun dodie "failed to copy $source"; 1742*4882a593Smuzhiyun } 1743*4882a593Smuzhiyun } 1744*4882a593Smuzhiyun 1745*4882a593Smuzhiyun doprint "*** Saved info to $dir ***\n"; 1746*4882a593Smuzhiyun} 1747*4882a593Smuzhiyun 1748*4882a593Smuzhiyunsub fail { 1749*4882a593Smuzhiyun 1750*4882a593Smuzhiyun if ($die_on_failure) { 1751*4882a593Smuzhiyun dodie @_; 1752*4882a593Smuzhiyun } 1753*4882a593Smuzhiyun 1754*4882a593Smuzhiyun doprint "FAILED\n"; 1755*4882a593Smuzhiyun 1756*4882a593Smuzhiyun my $i = $iteration; 1757*4882a593Smuzhiyun 1758*4882a593Smuzhiyun # no need to reboot for just building. 1759*4882a593Smuzhiyun if (!do_not_reboot) { 1760*4882a593Smuzhiyun doprint "REBOOTING\n"; 1761*4882a593Smuzhiyun reboot_to_good $sleep_time; 1762*4882a593Smuzhiyun } 1763*4882a593Smuzhiyun 1764*4882a593Smuzhiyun my $name = ""; 1765*4882a593Smuzhiyun 1766*4882a593Smuzhiyun if (defined($test_name)) { 1767*4882a593Smuzhiyun $name = " ($test_name)"; 1768*4882a593Smuzhiyun } 1769*4882a593Smuzhiyun 1770*4882a593Smuzhiyun print_times; 1771*4882a593Smuzhiyun 1772*4882a593Smuzhiyun doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; 1773*4882a593Smuzhiyun doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; 1774*4882a593Smuzhiyun doprint "KTEST RESULT: TEST $i$name Failed: ", @_, "\n"; 1775*4882a593Smuzhiyun doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; 1776*4882a593Smuzhiyun doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; 1777*4882a593Smuzhiyun 1778*4882a593Smuzhiyun if (defined($store_failures)) { 1779*4882a593Smuzhiyun save_logs "fail", $store_failures; 1780*4882a593Smuzhiyun } 1781*4882a593Smuzhiyun 1782*4882a593Smuzhiyun if (defined($post_test)) { 1783*4882a593Smuzhiyun run_command $post_test; 1784*4882a593Smuzhiyun } 1785*4882a593Smuzhiyun 1786*4882a593Smuzhiyun return 1; 1787*4882a593Smuzhiyun} 1788*4882a593Smuzhiyun 1789*4882a593Smuzhiyunsub run_command { 1790*4882a593Smuzhiyun my ($command, $redirect, $timeout) = @_; 1791*4882a593Smuzhiyun my $start_time; 1792*4882a593Smuzhiyun my $end_time; 1793*4882a593Smuzhiyun my $dolog = 0; 1794*4882a593Smuzhiyun my $dord = 0; 1795*4882a593Smuzhiyun my $dostdout = 0; 1796*4882a593Smuzhiyun my $pid; 1797*4882a593Smuzhiyun my $command_orig = $command; 1798*4882a593Smuzhiyun 1799*4882a593Smuzhiyun $command =~ s/\$SSH_USER/$ssh_user/g; 1800*4882a593Smuzhiyun $command =~ s/\$MACHINE/$machine/g; 1801*4882a593Smuzhiyun 1802*4882a593Smuzhiyun doprint("$command ... "); 1803*4882a593Smuzhiyun $start_time = time; 1804*4882a593Smuzhiyun 1805*4882a593Smuzhiyun $pid = open(CMD, "$command 2>&1 |") or 1806*4882a593Smuzhiyun (fail "unable to exec $command" and return 0); 1807*4882a593Smuzhiyun 1808*4882a593Smuzhiyun if (defined($opt{"LOG_FILE"})) { 1809*4882a593Smuzhiyun $dolog = 1; 1810*4882a593Smuzhiyun } 1811*4882a593Smuzhiyun 1812*4882a593Smuzhiyun if (defined($redirect)) { 1813*4882a593Smuzhiyun if ($redirect eq 1) { 1814*4882a593Smuzhiyun $dostdout = 1; 1815*4882a593Smuzhiyun # Have the output of the command on its own line 1816*4882a593Smuzhiyun doprint "\n"; 1817*4882a593Smuzhiyun } else { 1818*4882a593Smuzhiyun open (RD, ">$redirect") or 1819*4882a593Smuzhiyun dodie "failed to write to redirect $redirect"; 1820*4882a593Smuzhiyun $dord = 1; 1821*4882a593Smuzhiyun } 1822*4882a593Smuzhiyun } 1823*4882a593Smuzhiyun 1824*4882a593Smuzhiyun my $hit_timeout = 0; 1825*4882a593Smuzhiyun 1826*4882a593Smuzhiyun while (1) { 1827*4882a593Smuzhiyun my $fp = \*CMD; 1828*4882a593Smuzhiyun if (defined($timeout)) { 1829*4882a593Smuzhiyun doprint "timeout = $timeout\n"; 1830*4882a593Smuzhiyun } 1831*4882a593Smuzhiyun my $line = wait_for_input($fp, $timeout); 1832*4882a593Smuzhiyun if (!defined($line)) { 1833*4882a593Smuzhiyun my $now = time; 1834*4882a593Smuzhiyun if (defined($timeout) && (($now - $start_time) >= $timeout)) { 1835*4882a593Smuzhiyun doprint "Hit timeout of $timeout, killing process\n"; 1836*4882a593Smuzhiyun $hit_timeout = 1; 1837*4882a593Smuzhiyun kill 9, $pid; 1838*4882a593Smuzhiyun } 1839*4882a593Smuzhiyun last; 1840*4882a593Smuzhiyun } 1841*4882a593Smuzhiyun print LOG $line if ($dolog); 1842*4882a593Smuzhiyun print RD $line if ($dord); 1843*4882a593Smuzhiyun print $line if ($dostdout); 1844*4882a593Smuzhiyun } 1845*4882a593Smuzhiyun 1846*4882a593Smuzhiyun waitpid($pid, 0); 1847*4882a593Smuzhiyun # shift 8 for real exit status 1848*4882a593Smuzhiyun $run_command_status = $? >> 8; 1849*4882a593Smuzhiyun 1850*4882a593Smuzhiyun if ($command_orig eq $default{REBOOT} && 1851*4882a593Smuzhiyun $run_command_status == $reboot_return_code) { 1852*4882a593Smuzhiyun $run_command_status = 0; 1853*4882a593Smuzhiyun } 1854*4882a593Smuzhiyun 1855*4882a593Smuzhiyun close(CMD); 1856*4882a593Smuzhiyun close(RD) if ($dord); 1857*4882a593Smuzhiyun 1858*4882a593Smuzhiyun $end_time = time; 1859*4882a593Smuzhiyun my $delta = $end_time - $start_time; 1860*4882a593Smuzhiyun 1861*4882a593Smuzhiyun if ($delta == 1) { 1862*4882a593Smuzhiyun doprint "[1 second] "; 1863*4882a593Smuzhiyun } else { 1864*4882a593Smuzhiyun doprint "[$delta seconds] "; 1865*4882a593Smuzhiyun } 1866*4882a593Smuzhiyun 1867*4882a593Smuzhiyun if ($hit_timeout) { 1868*4882a593Smuzhiyun $run_command_status = 1; 1869*4882a593Smuzhiyun } 1870*4882a593Smuzhiyun 1871*4882a593Smuzhiyun if ($run_command_status) { 1872*4882a593Smuzhiyun doprint "FAILED!\n"; 1873*4882a593Smuzhiyun } else { 1874*4882a593Smuzhiyun doprint "SUCCESS\n"; 1875*4882a593Smuzhiyun } 1876*4882a593Smuzhiyun 1877*4882a593Smuzhiyun return !$run_command_status; 1878*4882a593Smuzhiyun} 1879*4882a593Smuzhiyun 1880*4882a593Smuzhiyunsub run_ssh { 1881*4882a593Smuzhiyun my ($cmd, $timeout) = @_; 1882*4882a593Smuzhiyun my $cp_exec = $ssh_exec; 1883*4882a593Smuzhiyun 1884*4882a593Smuzhiyun $cp_exec =~ s/\$SSH_COMMAND/$cmd/g; 1885*4882a593Smuzhiyun return run_command "$cp_exec", undef , $timeout; 1886*4882a593Smuzhiyun} 1887*4882a593Smuzhiyun 1888*4882a593Smuzhiyunsub run_scp { 1889*4882a593Smuzhiyun my ($src, $dst, $cp_scp) = @_; 1890*4882a593Smuzhiyun 1891*4882a593Smuzhiyun $cp_scp =~ s/\$SRC_FILE/$src/g; 1892*4882a593Smuzhiyun $cp_scp =~ s/\$DST_FILE/$dst/g; 1893*4882a593Smuzhiyun 1894*4882a593Smuzhiyun return run_command "$cp_scp"; 1895*4882a593Smuzhiyun} 1896*4882a593Smuzhiyun 1897*4882a593Smuzhiyunsub run_scp_install { 1898*4882a593Smuzhiyun my ($src, $dst) = @_; 1899*4882a593Smuzhiyun 1900*4882a593Smuzhiyun my $cp_scp = $scp_to_target_install; 1901*4882a593Smuzhiyun 1902*4882a593Smuzhiyun return run_scp($src, $dst, $cp_scp); 1903*4882a593Smuzhiyun} 1904*4882a593Smuzhiyun 1905*4882a593Smuzhiyunsub run_scp_mod { 1906*4882a593Smuzhiyun my ($src, $dst) = @_; 1907*4882a593Smuzhiyun 1908*4882a593Smuzhiyun my $cp_scp = $scp_to_target; 1909*4882a593Smuzhiyun 1910*4882a593Smuzhiyun return run_scp($src, $dst, $cp_scp); 1911*4882a593Smuzhiyun} 1912*4882a593Smuzhiyun 1913*4882a593Smuzhiyunsub _get_grub_index { 1914*4882a593Smuzhiyun 1915*4882a593Smuzhiyun my ($command, $target, $skip) = @_; 1916*4882a593Smuzhiyun 1917*4882a593Smuzhiyun return if (defined($grub_number) && defined($last_grub_menu) && 1918*4882a593Smuzhiyun $last_grub_menu eq $grub_menu && defined($last_machine) && 1919*4882a593Smuzhiyun $last_machine eq $machine); 1920*4882a593Smuzhiyun 1921*4882a593Smuzhiyun doprint "Find $reboot_type menu ... "; 1922*4882a593Smuzhiyun $grub_number = -1; 1923*4882a593Smuzhiyun 1924*4882a593Smuzhiyun my $ssh_grub = $ssh_exec; 1925*4882a593Smuzhiyun $ssh_grub =~ s,\$SSH_COMMAND,$command,g; 1926*4882a593Smuzhiyun 1927*4882a593Smuzhiyun open(IN, "$ssh_grub |") 1928*4882a593Smuzhiyun or dodie "unable to execute $command"; 1929*4882a593Smuzhiyun 1930*4882a593Smuzhiyun my $found = 0; 1931*4882a593Smuzhiyun 1932*4882a593Smuzhiyun while (<IN>) { 1933*4882a593Smuzhiyun if (/$target/) { 1934*4882a593Smuzhiyun $grub_number++; 1935*4882a593Smuzhiyun $found = 1; 1936*4882a593Smuzhiyun last; 1937*4882a593Smuzhiyun } elsif (/$skip/) { 1938*4882a593Smuzhiyun $grub_number++; 1939*4882a593Smuzhiyun } 1940*4882a593Smuzhiyun } 1941*4882a593Smuzhiyun close(IN); 1942*4882a593Smuzhiyun 1943*4882a593Smuzhiyun dodie "Could not find '$grub_menu' through $command on $machine" 1944*4882a593Smuzhiyun if (!$found); 1945*4882a593Smuzhiyun doprint "$grub_number\n"; 1946*4882a593Smuzhiyun $last_grub_menu = $grub_menu; 1947*4882a593Smuzhiyun $last_machine = $machine; 1948*4882a593Smuzhiyun} 1949*4882a593Smuzhiyun 1950*4882a593Smuzhiyunsub get_grub_index { 1951*4882a593Smuzhiyun 1952*4882a593Smuzhiyun my $command; 1953*4882a593Smuzhiyun my $target; 1954*4882a593Smuzhiyun my $skip; 1955*4882a593Smuzhiyun my $grub_menu_qt; 1956*4882a593Smuzhiyun 1957*4882a593Smuzhiyun if ($reboot_type !~ /^grub/) { 1958*4882a593Smuzhiyun return; 1959*4882a593Smuzhiyun } 1960*4882a593Smuzhiyun 1961*4882a593Smuzhiyun $grub_menu_qt = quotemeta($grub_menu); 1962*4882a593Smuzhiyun 1963*4882a593Smuzhiyun if ($reboot_type eq "grub") { 1964*4882a593Smuzhiyun $command = "cat /boot/grub/menu.lst"; 1965*4882a593Smuzhiyun $target = '^\s*title\s+' . $grub_menu_qt . '\s*$'; 1966*4882a593Smuzhiyun $skip = '^\s*title\s'; 1967*4882a593Smuzhiyun } elsif ($reboot_type eq "grub2") { 1968*4882a593Smuzhiyun $command = "cat $grub_file"; 1969*4882a593Smuzhiyun $target = '^menuentry.*' . $grub_menu_qt; 1970*4882a593Smuzhiyun $skip = '^menuentry\s|^submenu\s'; 1971*4882a593Smuzhiyun } elsif ($reboot_type eq "grub2bls") { 1972*4882a593Smuzhiyun $command = $grub_bls_get; 1973*4882a593Smuzhiyun $target = '^title=.*' . $grub_menu_qt; 1974*4882a593Smuzhiyun $skip = '^title='; 1975*4882a593Smuzhiyun } else { 1976*4882a593Smuzhiyun return; 1977*4882a593Smuzhiyun } 1978*4882a593Smuzhiyun 1979*4882a593Smuzhiyun _get_grub_index($command, $target, $skip); 1980*4882a593Smuzhiyun} 1981*4882a593Smuzhiyun 1982*4882a593Smuzhiyunsub wait_for_input 1983*4882a593Smuzhiyun{ 1984*4882a593Smuzhiyun my ($fp, $time) = @_; 1985*4882a593Smuzhiyun my $start_time; 1986*4882a593Smuzhiyun my $rin; 1987*4882a593Smuzhiyun my $rout; 1988*4882a593Smuzhiyun my $nr; 1989*4882a593Smuzhiyun my $buf; 1990*4882a593Smuzhiyun my $line; 1991*4882a593Smuzhiyun my $ch; 1992*4882a593Smuzhiyun 1993*4882a593Smuzhiyun if (!defined($time)) { 1994*4882a593Smuzhiyun $time = $timeout; 1995*4882a593Smuzhiyun } 1996*4882a593Smuzhiyun 1997*4882a593Smuzhiyun $rin = ''; 1998*4882a593Smuzhiyun vec($rin, fileno($fp), 1) = 1; 1999*4882a593Smuzhiyun vec($rin, fileno(\*STDIN), 1) = 1; 2000*4882a593Smuzhiyun 2001*4882a593Smuzhiyun $start_time = time; 2002*4882a593Smuzhiyun 2003*4882a593Smuzhiyun while (1) { 2004*4882a593Smuzhiyun $nr = select($rout=$rin, undef, undef, $time); 2005*4882a593Smuzhiyun 2006*4882a593Smuzhiyun last if ($nr <= 0); 2007*4882a593Smuzhiyun 2008*4882a593Smuzhiyun # copy data from stdin to the console 2009*4882a593Smuzhiyun if (vec($rout, fileno(\*STDIN), 1) == 1) { 2010*4882a593Smuzhiyun $nr = sysread(\*STDIN, $buf, 1000); 2011*4882a593Smuzhiyun syswrite($fp, $buf, $nr) if ($nr > 0); 2012*4882a593Smuzhiyun } 2013*4882a593Smuzhiyun 2014*4882a593Smuzhiyun # The timeout is based on time waiting for the fp data 2015*4882a593Smuzhiyun if (vec($rout, fileno($fp), 1) != 1) { 2016*4882a593Smuzhiyun last if (defined($time) && (time - $start_time > $time)); 2017*4882a593Smuzhiyun next; 2018*4882a593Smuzhiyun } 2019*4882a593Smuzhiyun 2020*4882a593Smuzhiyun $line = ""; 2021*4882a593Smuzhiyun 2022*4882a593Smuzhiyun # try to read one char at a time 2023*4882a593Smuzhiyun while (sysread $fp, $ch, 1) { 2024*4882a593Smuzhiyun $line .= $ch; 2025*4882a593Smuzhiyun last if ($ch eq "\n"); 2026*4882a593Smuzhiyun } 2027*4882a593Smuzhiyun 2028*4882a593Smuzhiyun last if (!length($line)); 2029*4882a593Smuzhiyun 2030*4882a593Smuzhiyun return $line; 2031*4882a593Smuzhiyun } 2032*4882a593Smuzhiyun return undef; 2033*4882a593Smuzhiyun} 2034*4882a593Smuzhiyun 2035*4882a593Smuzhiyunsub reboot_to { 2036*4882a593Smuzhiyun if (defined($switch_to_test)) { 2037*4882a593Smuzhiyun run_command $switch_to_test; 2038*4882a593Smuzhiyun } 2039*4882a593Smuzhiyun 2040*4882a593Smuzhiyun if ($reboot_type eq "grub") { 2041*4882a593Smuzhiyun run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'"; 2042*4882a593Smuzhiyun } elsif (($reboot_type eq "grub2") or ($reboot_type eq "grub2bls")) { 2043*4882a593Smuzhiyun run_ssh "$grub_reboot $grub_number"; 2044*4882a593Smuzhiyun } elsif ($reboot_type eq "syslinux") { 2045*4882a593Smuzhiyun run_ssh "$syslinux --once \\\"$syslinux_label\\\" $syslinux_path"; 2046*4882a593Smuzhiyun } elsif (defined $reboot_script) { 2047*4882a593Smuzhiyun run_command "$reboot_script"; 2048*4882a593Smuzhiyun } 2049*4882a593Smuzhiyun reboot; 2050*4882a593Smuzhiyun} 2051*4882a593Smuzhiyun 2052*4882a593Smuzhiyunsub get_sha1 { 2053*4882a593Smuzhiyun my ($commit) = @_; 2054*4882a593Smuzhiyun 2055*4882a593Smuzhiyun doprint "git rev-list --max-count=1 $commit ... "; 2056*4882a593Smuzhiyun my $sha1 = `git rev-list --max-count=1 $commit`; 2057*4882a593Smuzhiyun my $ret = $?; 2058*4882a593Smuzhiyun 2059*4882a593Smuzhiyun logit $sha1; 2060*4882a593Smuzhiyun 2061*4882a593Smuzhiyun if ($ret) { 2062*4882a593Smuzhiyun doprint "FAILED\n"; 2063*4882a593Smuzhiyun dodie "Failed to get git $commit"; 2064*4882a593Smuzhiyun } 2065*4882a593Smuzhiyun 2066*4882a593Smuzhiyun print "SUCCESS\n"; 2067*4882a593Smuzhiyun 2068*4882a593Smuzhiyun chomp $sha1; 2069*4882a593Smuzhiyun 2070*4882a593Smuzhiyun return $sha1; 2071*4882a593Smuzhiyun} 2072*4882a593Smuzhiyun 2073*4882a593Smuzhiyunsub monitor { 2074*4882a593Smuzhiyun my $booted = 0; 2075*4882a593Smuzhiyun my $bug = 0; 2076*4882a593Smuzhiyun my $bug_ignored = 0; 2077*4882a593Smuzhiyun my $skip_call_trace = 0; 2078*4882a593Smuzhiyun my $loops; 2079*4882a593Smuzhiyun 2080*4882a593Smuzhiyun my $start_time = time; 2081*4882a593Smuzhiyun 2082*4882a593Smuzhiyun wait_for_monitor 5; 2083*4882a593Smuzhiyun 2084*4882a593Smuzhiyun my $line; 2085*4882a593Smuzhiyun my $full_line = ""; 2086*4882a593Smuzhiyun 2087*4882a593Smuzhiyun open(DMESG, "> $dmesg") or 2088*4882a593Smuzhiyun dodie "unable to write to $dmesg"; 2089*4882a593Smuzhiyun 2090*4882a593Smuzhiyun reboot_to; 2091*4882a593Smuzhiyun 2092*4882a593Smuzhiyun my $success_start; 2093*4882a593Smuzhiyun my $failure_start; 2094*4882a593Smuzhiyun my $monitor_start = time; 2095*4882a593Smuzhiyun my $done = 0; 2096*4882a593Smuzhiyun my $version_found = 0; 2097*4882a593Smuzhiyun 2098*4882a593Smuzhiyun while (!$done) { 2099*4882a593Smuzhiyun 2100*4882a593Smuzhiyun if ($bug && defined($stop_after_failure) && 2101*4882a593Smuzhiyun $stop_after_failure >= 0) { 2102*4882a593Smuzhiyun my $time = $stop_after_failure - (time - $failure_start); 2103*4882a593Smuzhiyun $line = wait_for_input($monitor_fp, $time); 2104*4882a593Smuzhiyun if (!defined($line)) { 2105*4882a593Smuzhiyun doprint "bug timed out after $booted_timeout seconds\n"; 2106*4882a593Smuzhiyun doprint "Test forced to stop after $stop_after_failure seconds after failure\n"; 2107*4882a593Smuzhiyun last; 2108*4882a593Smuzhiyun } 2109*4882a593Smuzhiyun } elsif ($booted) { 2110*4882a593Smuzhiyun $line = wait_for_input($monitor_fp, $booted_timeout); 2111*4882a593Smuzhiyun if (!defined($line)) { 2112*4882a593Smuzhiyun my $s = $booted_timeout == 1 ? "" : "s"; 2113*4882a593Smuzhiyun doprint "Successful boot found: break after $booted_timeout second$s\n"; 2114*4882a593Smuzhiyun last; 2115*4882a593Smuzhiyun } 2116*4882a593Smuzhiyun } else { 2117*4882a593Smuzhiyun $line = wait_for_input($monitor_fp); 2118*4882a593Smuzhiyun if (!defined($line)) { 2119*4882a593Smuzhiyun my $s = $timeout == 1 ? "" : "s"; 2120*4882a593Smuzhiyun doprint "Timed out after $timeout second$s\n"; 2121*4882a593Smuzhiyun last; 2122*4882a593Smuzhiyun } 2123*4882a593Smuzhiyun } 2124*4882a593Smuzhiyun 2125*4882a593Smuzhiyun doprint $line; 2126*4882a593Smuzhiyun print DMESG $line; 2127*4882a593Smuzhiyun 2128*4882a593Smuzhiyun # we are not guaranteed to get a full line 2129*4882a593Smuzhiyun $full_line .= $line; 2130*4882a593Smuzhiyun 2131*4882a593Smuzhiyun if ($full_line =~ /$success_line/) { 2132*4882a593Smuzhiyun $booted = 1; 2133*4882a593Smuzhiyun $success_start = time; 2134*4882a593Smuzhiyun } 2135*4882a593Smuzhiyun 2136*4882a593Smuzhiyun if ($booted && defined($stop_after_success) && 2137*4882a593Smuzhiyun $stop_after_success >= 0) { 2138*4882a593Smuzhiyun my $now = time; 2139*4882a593Smuzhiyun if ($now - $success_start >= $stop_after_success) { 2140*4882a593Smuzhiyun doprint "Test forced to stop after $stop_after_success seconds after success\n"; 2141*4882a593Smuzhiyun last; 2142*4882a593Smuzhiyun } 2143*4882a593Smuzhiyun } 2144*4882a593Smuzhiyun 2145*4882a593Smuzhiyun if ($full_line =~ /\[ backtrace testing \]/) { 2146*4882a593Smuzhiyun $skip_call_trace = 1; 2147*4882a593Smuzhiyun } 2148*4882a593Smuzhiyun 2149*4882a593Smuzhiyun if ($full_line =~ /call trace:/i) { 2150*4882a593Smuzhiyun if (!$bug && !$skip_call_trace) { 2151*4882a593Smuzhiyun if ($ignore_errors) { 2152*4882a593Smuzhiyun $bug_ignored = 1; 2153*4882a593Smuzhiyun } else { 2154*4882a593Smuzhiyun $bug = 1; 2155*4882a593Smuzhiyun $failure_start = time; 2156*4882a593Smuzhiyun } 2157*4882a593Smuzhiyun } 2158*4882a593Smuzhiyun } 2159*4882a593Smuzhiyun 2160*4882a593Smuzhiyun if ($bug && defined($stop_after_failure) && 2161*4882a593Smuzhiyun $stop_after_failure >= 0) { 2162*4882a593Smuzhiyun my $now = time; 2163*4882a593Smuzhiyun if ($now - $failure_start >= $stop_after_failure) { 2164*4882a593Smuzhiyun doprint "Test forced to stop after $stop_after_failure seconds after failure\n"; 2165*4882a593Smuzhiyun last; 2166*4882a593Smuzhiyun } 2167*4882a593Smuzhiyun } 2168*4882a593Smuzhiyun 2169*4882a593Smuzhiyun if ($full_line =~ /\[ end of backtrace testing \]/) { 2170*4882a593Smuzhiyun $skip_call_trace = 0; 2171*4882a593Smuzhiyun } 2172*4882a593Smuzhiyun 2173*4882a593Smuzhiyun if ($full_line =~ /Kernel panic -/) { 2174*4882a593Smuzhiyun $failure_start = time; 2175*4882a593Smuzhiyun $bug = 1; 2176*4882a593Smuzhiyun } 2177*4882a593Smuzhiyun 2178*4882a593Smuzhiyun # Detect triple faults by testing the banner 2179*4882a593Smuzhiyun if ($full_line =~ /\bLinux version (\S+).*\n/) { 2180*4882a593Smuzhiyun if ($1 eq $version) { 2181*4882a593Smuzhiyun $version_found = 1; 2182*4882a593Smuzhiyun } elsif ($version_found && $detect_triplefault) { 2183*4882a593Smuzhiyun # We already booted into the kernel we are testing, 2184*4882a593Smuzhiyun # but now we booted into another kernel? 2185*4882a593Smuzhiyun # Consider this a triple fault. 2186*4882a593Smuzhiyun doprint "Already booted in Linux kernel $version, but now\n"; 2187*4882a593Smuzhiyun doprint "we booted into Linux kernel $1.\n"; 2188*4882a593Smuzhiyun doprint "Assuming that this is a triple fault.\n"; 2189*4882a593Smuzhiyun doprint "To disable this: set DETECT_TRIPLE_FAULT to 0\n"; 2190*4882a593Smuzhiyun last; 2191*4882a593Smuzhiyun } 2192*4882a593Smuzhiyun } 2193*4882a593Smuzhiyun 2194*4882a593Smuzhiyun if ($line =~ /\n/) { 2195*4882a593Smuzhiyun $full_line = ""; 2196*4882a593Smuzhiyun } 2197*4882a593Smuzhiyun 2198*4882a593Smuzhiyun if ($stop_test_after > 0 && !$booted && !$bug) { 2199*4882a593Smuzhiyun if (time - $monitor_start > $stop_test_after) { 2200*4882a593Smuzhiyun doprint "STOP_TEST_AFTER ($stop_test_after seconds) timed out\n"; 2201*4882a593Smuzhiyun $done = 1; 2202*4882a593Smuzhiyun } 2203*4882a593Smuzhiyun } 2204*4882a593Smuzhiyun } 2205*4882a593Smuzhiyun 2206*4882a593Smuzhiyun my $end_time = time; 2207*4882a593Smuzhiyun $reboot_time = $end_time - $start_time; 2208*4882a593Smuzhiyun 2209*4882a593Smuzhiyun close(DMESG); 2210*4882a593Smuzhiyun 2211*4882a593Smuzhiyun if ($bug) { 2212*4882a593Smuzhiyun return 0 if ($in_bisect); 2213*4882a593Smuzhiyun fail "failed - got a bug report" and return 0; 2214*4882a593Smuzhiyun } 2215*4882a593Smuzhiyun 2216*4882a593Smuzhiyun if (!$booted) { 2217*4882a593Smuzhiyun return 0 if ($in_bisect); 2218*4882a593Smuzhiyun fail "failed - never got a boot prompt." and return 0; 2219*4882a593Smuzhiyun } 2220*4882a593Smuzhiyun 2221*4882a593Smuzhiyun if ($bug_ignored) { 2222*4882a593Smuzhiyun doprint "WARNING: Call Trace detected but ignored due to IGNORE_ERRORS=1\n"; 2223*4882a593Smuzhiyun } 2224*4882a593Smuzhiyun 2225*4882a593Smuzhiyun return 1; 2226*4882a593Smuzhiyun} 2227*4882a593Smuzhiyun 2228*4882a593Smuzhiyunsub eval_kernel_version { 2229*4882a593Smuzhiyun my ($option) = @_; 2230*4882a593Smuzhiyun 2231*4882a593Smuzhiyun $option =~ s/\$KERNEL_VERSION/$version/g; 2232*4882a593Smuzhiyun 2233*4882a593Smuzhiyun return $option; 2234*4882a593Smuzhiyun} 2235*4882a593Smuzhiyun 2236*4882a593Smuzhiyunsub do_post_install { 2237*4882a593Smuzhiyun 2238*4882a593Smuzhiyun return if (!defined($post_install)); 2239*4882a593Smuzhiyun 2240*4882a593Smuzhiyun my $cp_post_install = eval_kernel_version $post_install; 2241*4882a593Smuzhiyun run_command "$cp_post_install" or 2242*4882a593Smuzhiyun dodie "Failed to run post install"; 2243*4882a593Smuzhiyun} 2244*4882a593Smuzhiyun 2245*4882a593Smuzhiyun# Sometimes the reboot fails, and will hang. We try to ssh to the box 2246*4882a593Smuzhiyun# and if we fail, we force another reboot, that should powercycle it. 2247*4882a593Smuzhiyunsub test_booted { 2248*4882a593Smuzhiyun if (!run_ssh "echo testing connection") { 2249*4882a593Smuzhiyun reboot $sleep_time; 2250*4882a593Smuzhiyun } 2251*4882a593Smuzhiyun} 2252*4882a593Smuzhiyun 2253*4882a593Smuzhiyunsub install { 2254*4882a593Smuzhiyun 2255*4882a593Smuzhiyun return if ($no_install); 2256*4882a593Smuzhiyun 2257*4882a593Smuzhiyun my $start_time = time; 2258*4882a593Smuzhiyun 2259*4882a593Smuzhiyun if (defined($pre_install)) { 2260*4882a593Smuzhiyun my $cp_pre_install = eval_kernel_version $pre_install; 2261*4882a593Smuzhiyun run_command "$cp_pre_install" or 2262*4882a593Smuzhiyun dodie "Failed to run pre install"; 2263*4882a593Smuzhiyun } 2264*4882a593Smuzhiyun 2265*4882a593Smuzhiyun my $cp_target = eval_kernel_version $target_image; 2266*4882a593Smuzhiyun 2267*4882a593Smuzhiyun test_booted; 2268*4882a593Smuzhiyun 2269*4882a593Smuzhiyun run_scp_install "$outputdir/$build_target", "$cp_target" or 2270*4882a593Smuzhiyun dodie "failed to copy image"; 2271*4882a593Smuzhiyun 2272*4882a593Smuzhiyun my $install_mods = 0; 2273*4882a593Smuzhiyun 2274*4882a593Smuzhiyun # should we process modules? 2275*4882a593Smuzhiyun $install_mods = 0; 2276*4882a593Smuzhiyun open(IN, "$output_config") or dodie("Can't read config file"); 2277*4882a593Smuzhiyun while (<IN>) { 2278*4882a593Smuzhiyun if (/CONFIG_MODULES(=y)?/) { 2279*4882a593Smuzhiyun if (defined($1)) { 2280*4882a593Smuzhiyun $install_mods = 1; 2281*4882a593Smuzhiyun last; 2282*4882a593Smuzhiyun } 2283*4882a593Smuzhiyun } 2284*4882a593Smuzhiyun } 2285*4882a593Smuzhiyun close(IN); 2286*4882a593Smuzhiyun 2287*4882a593Smuzhiyun if (!$install_mods) { 2288*4882a593Smuzhiyun do_post_install; 2289*4882a593Smuzhiyun doprint "No modules needed\n"; 2290*4882a593Smuzhiyun my $end_time = time; 2291*4882a593Smuzhiyun $install_time = $end_time - $start_time; 2292*4882a593Smuzhiyun return; 2293*4882a593Smuzhiyun } 2294*4882a593Smuzhiyun 2295*4882a593Smuzhiyun run_command "$make INSTALL_MOD_STRIP=1 INSTALL_MOD_PATH=$tmpdir modules_install" or 2296*4882a593Smuzhiyun dodie "Failed to install modules"; 2297*4882a593Smuzhiyun 2298*4882a593Smuzhiyun my $modlib = "/lib/modules/$version"; 2299*4882a593Smuzhiyun my $modtar = "ktest-mods.tar.bz2"; 2300*4882a593Smuzhiyun 2301*4882a593Smuzhiyun run_ssh "rm -rf $modlib" or 2302*4882a593Smuzhiyun dodie "failed to remove old mods: $modlib"; 2303*4882a593Smuzhiyun 2304*4882a593Smuzhiyun # would be nice if scp -r did not follow symbolic links 2305*4882a593Smuzhiyun run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or 2306*4882a593Smuzhiyun dodie "making tarball"; 2307*4882a593Smuzhiyun 2308*4882a593Smuzhiyun run_scp_mod "$tmpdir/$modtar", "/tmp" or 2309*4882a593Smuzhiyun dodie "failed to copy modules"; 2310*4882a593Smuzhiyun 2311*4882a593Smuzhiyun unlink "$tmpdir/$modtar"; 2312*4882a593Smuzhiyun 2313*4882a593Smuzhiyun run_ssh "'(cd / && tar xjf /tmp/$modtar)'" or 2314*4882a593Smuzhiyun dodie "failed to tar modules"; 2315*4882a593Smuzhiyun 2316*4882a593Smuzhiyun run_ssh "rm -f /tmp/$modtar"; 2317*4882a593Smuzhiyun 2318*4882a593Smuzhiyun do_post_install; 2319*4882a593Smuzhiyun 2320*4882a593Smuzhiyun my $end_time = time; 2321*4882a593Smuzhiyun $install_time = $end_time - $start_time; 2322*4882a593Smuzhiyun} 2323*4882a593Smuzhiyun 2324*4882a593Smuzhiyunsub get_version { 2325*4882a593Smuzhiyun # get the release name 2326*4882a593Smuzhiyun return if ($have_version); 2327*4882a593Smuzhiyun doprint "$make kernelrelease ... "; 2328*4882a593Smuzhiyun $version = `$make -s kernelrelease | tail -1`; 2329*4882a593Smuzhiyun chomp($version); 2330*4882a593Smuzhiyun doprint "$version\n"; 2331*4882a593Smuzhiyun $have_version = 1; 2332*4882a593Smuzhiyun} 2333*4882a593Smuzhiyun 2334*4882a593Smuzhiyunsub start_monitor_and_install { 2335*4882a593Smuzhiyun # Make sure the stable kernel has finished booting 2336*4882a593Smuzhiyun 2337*4882a593Smuzhiyun # Install bisects, don't need console 2338*4882a593Smuzhiyun if (defined $console) { 2339*4882a593Smuzhiyun start_monitor; 2340*4882a593Smuzhiyun wait_for_monitor 5; 2341*4882a593Smuzhiyun end_monitor; 2342*4882a593Smuzhiyun } 2343*4882a593Smuzhiyun 2344*4882a593Smuzhiyun get_grub_index; 2345*4882a593Smuzhiyun get_version; 2346*4882a593Smuzhiyun install; 2347*4882a593Smuzhiyun 2348*4882a593Smuzhiyun start_monitor if (defined $console); 2349*4882a593Smuzhiyun return monitor; 2350*4882a593Smuzhiyun} 2351*4882a593Smuzhiyun 2352*4882a593Smuzhiyunmy $check_build_re = ".*:.*(warning|error|Error):.*"; 2353*4882a593Smuzhiyunmy $utf8_quote = "\\x{e2}\\x{80}(\\x{98}|\\x{99})"; 2354*4882a593Smuzhiyun 2355*4882a593Smuzhiyunsub process_warning_line { 2356*4882a593Smuzhiyun my ($line) = @_; 2357*4882a593Smuzhiyun 2358*4882a593Smuzhiyun chomp $line; 2359*4882a593Smuzhiyun 2360*4882a593Smuzhiyun # for distcc heterogeneous systems, some compilers 2361*4882a593Smuzhiyun # do things differently causing warning lines 2362*4882a593Smuzhiyun # to be slightly different. This makes an attempt 2363*4882a593Smuzhiyun # to fixe those issues. 2364*4882a593Smuzhiyun 2365*4882a593Smuzhiyun # chop off the index into the line 2366*4882a593Smuzhiyun # using distcc, some compilers give different indexes 2367*4882a593Smuzhiyun # depending on white space 2368*4882a593Smuzhiyun $line =~ s/^(\s*\S+:\d+:)\d+/$1/; 2369*4882a593Smuzhiyun 2370*4882a593Smuzhiyun # Some compilers use UTF-8 extended for quotes and some don't. 2371*4882a593Smuzhiyun $line =~ s/$utf8_quote/'/g; 2372*4882a593Smuzhiyun 2373*4882a593Smuzhiyun return $line; 2374*4882a593Smuzhiyun} 2375*4882a593Smuzhiyun 2376*4882a593Smuzhiyun# Read buildlog and check against warnings file for any 2377*4882a593Smuzhiyun# new warnings. 2378*4882a593Smuzhiyun# 2379*4882a593Smuzhiyun# Returns 1 if OK 2380*4882a593Smuzhiyun# 0 otherwise 2381*4882a593Smuzhiyunsub check_buildlog { 2382*4882a593Smuzhiyun return 1 if (!defined $warnings_file); 2383*4882a593Smuzhiyun 2384*4882a593Smuzhiyun my %warnings_list; 2385*4882a593Smuzhiyun 2386*4882a593Smuzhiyun # Failed builds should not reboot the target 2387*4882a593Smuzhiyun my $save_no_reboot = $no_reboot; 2388*4882a593Smuzhiyun $no_reboot = 1; 2389*4882a593Smuzhiyun 2390*4882a593Smuzhiyun if (-f $warnings_file) { 2391*4882a593Smuzhiyun open(IN, $warnings_file) or 2392*4882a593Smuzhiyun dodie "Error opening $warnings_file"; 2393*4882a593Smuzhiyun 2394*4882a593Smuzhiyun while (<IN>) { 2395*4882a593Smuzhiyun if (/$check_build_re/) { 2396*4882a593Smuzhiyun my $warning = process_warning_line $_; 2397*4882a593Smuzhiyun 2398*4882a593Smuzhiyun $warnings_list{$warning} = 1; 2399*4882a593Smuzhiyun } 2400*4882a593Smuzhiyun } 2401*4882a593Smuzhiyun close(IN); 2402*4882a593Smuzhiyun } 2403*4882a593Smuzhiyun 2404*4882a593Smuzhiyun # If warnings file didn't exist, and WARNINGS_FILE exist, 2405*4882a593Smuzhiyun # then we fail on any warning! 2406*4882a593Smuzhiyun 2407*4882a593Smuzhiyun open(IN, $buildlog) or dodie "Can't open $buildlog"; 2408*4882a593Smuzhiyun while (<IN>) { 2409*4882a593Smuzhiyun if (/$check_build_re/) { 2410*4882a593Smuzhiyun my $warning = process_warning_line $_; 2411*4882a593Smuzhiyun 2412*4882a593Smuzhiyun if (!defined $warnings_list{$warning}) { 2413*4882a593Smuzhiyun fail "New warning found (not in $warnings_file)\n$_\n"; 2414*4882a593Smuzhiyun $no_reboot = $save_no_reboot; 2415*4882a593Smuzhiyun return 0; 2416*4882a593Smuzhiyun } 2417*4882a593Smuzhiyun } 2418*4882a593Smuzhiyun } 2419*4882a593Smuzhiyun $no_reboot = $save_no_reboot; 2420*4882a593Smuzhiyun close(IN); 2421*4882a593Smuzhiyun} 2422*4882a593Smuzhiyun 2423*4882a593Smuzhiyunsub check_patch_buildlog { 2424*4882a593Smuzhiyun my ($patch) = @_; 2425*4882a593Smuzhiyun 2426*4882a593Smuzhiyun my @files = `git show $patch | diffstat -l`; 2427*4882a593Smuzhiyun 2428*4882a593Smuzhiyun foreach my $file (@files) { 2429*4882a593Smuzhiyun chomp $file; 2430*4882a593Smuzhiyun } 2431*4882a593Smuzhiyun 2432*4882a593Smuzhiyun open(IN, "git show $patch |") or 2433*4882a593Smuzhiyun dodie "failed to show $patch"; 2434*4882a593Smuzhiyun while (<IN>) { 2435*4882a593Smuzhiyun if (m,^--- a/(.*),) { 2436*4882a593Smuzhiyun chomp $1; 2437*4882a593Smuzhiyun $files[$#files] = $1; 2438*4882a593Smuzhiyun } 2439*4882a593Smuzhiyun } 2440*4882a593Smuzhiyun close(IN); 2441*4882a593Smuzhiyun 2442*4882a593Smuzhiyun open(IN, $buildlog) or dodie "Can't open $buildlog"; 2443*4882a593Smuzhiyun while (<IN>) { 2444*4882a593Smuzhiyun if (/^\s*(.*?):.*(warning|error)/) { 2445*4882a593Smuzhiyun my $err = $1; 2446*4882a593Smuzhiyun foreach my $file (@files) { 2447*4882a593Smuzhiyun my $fullpath = "$builddir/$file"; 2448*4882a593Smuzhiyun if ($file eq $err || $fullpath eq $err) { 2449*4882a593Smuzhiyun fail "$file built with warnings" and return 0; 2450*4882a593Smuzhiyun } 2451*4882a593Smuzhiyun } 2452*4882a593Smuzhiyun } 2453*4882a593Smuzhiyun } 2454*4882a593Smuzhiyun close(IN); 2455*4882a593Smuzhiyun 2456*4882a593Smuzhiyun return 1; 2457*4882a593Smuzhiyun} 2458*4882a593Smuzhiyun 2459*4882a593Smuzhiyunsub apply_min_config { 2460*4882a593Smuzhiyun my $outconfig = "$output_config.new"; 2461*4882a593Smuzhiyun 2462*4882a593Smuzhiyun # Read the config file and remove anything that 2463*4882a593Smuzhiyun # is in the force_config hash (from minconfig and others) 2464*4882a593Smuzhiyun # then add the force config back. 2465*4882a593Smuzhiyun 2466*4882a593Smuzhiyun doprint "Applying minimum configurations into $output_config.new\n"; 2467*4882a593Smuzhiyun 2468*4882a593Smuzhiyun open (OUT, ">$outconfig") or 2469*4882a593Smuzhiyun dodie "Can't create $outconfig"; 2470*4882a593Smuzhiyun 2471*4882a593Smuzhiyun if (-f $output_config) { 2472*4882a593Smuzhiyun open (IN, $output_config) or 2473*4882a593Smuzhiyun dodie "Failed to open $output_config"; 2474*4882a593Smuzhiyun while (<IN>) { 2475*4882a593Smuzhiyun if (/^(# )?(CONFIG_[^\s=]*)/) { 2476*4882a593Smuzhiyun next if (defined($force_config{$2})); 2477*4882a593Smuzhiyun } 2478*4882a593Smuzhiyun print OUT; 2479*4882a593Smuzhiyun } 2480*4882a593Smuzhiyun close IN; 2481*4882a593Smuzhiyun } 2482*4882a593Smuzhiyun foreach my $config (keys %force_config) { 2483*4882a593Smuzhiyun print OUT "$force_config{$config}\n"; 2484*4882a593Smuzhiyun } 2485*4882a593Smuzhiyun close OUT; 2486*4882a593Smuzhiyun 2487*4882a593Smuzhiyun run_command "mv $outconfig $output_config"; 2488*4882a593Smuzhiyun} 2489*4882a593Smuzhiyun 2490*4882a593Smuzhiyunsub make_oldconfig { 2491*4882a593Smuzhiyun 2492*4882a593Smuzhiyun my @force_list = keys %force_config; 2493*4882a593Smuzhiyun 2494*4882a593Smuzhiyun if ($#force_list >= 0) { 2495*4882a593Smuzhiyun apply_min_config; 2496*4882a593Smuzhiyun } 2497*4882a593Smuzhiyun 2498*4882a593Smuzhiyun if (!run_command "$make olddefconfig") { 2499*4882a593Smuzhiyun # Perhaps olddefconfig doesn't exist in this version of the kernel 2500*4882a593Smuzhiyun # try oldnoconfig 2501*4882a593Smuzhiyun doprint "olddefconfig failed, trying make oldnoconfig\n"; 2502*4882a593Smuzhiyun if (!run_command "$make oldnoconfig") { 2503*4882a593Smuzhiyun doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; 2504*4882a593Smuzhiyun # try a yes '' | oldconfig 2505*4882a593Smuzhiyun run_command "yes '' | $make oldconfig" or 2506*4882a593Smuzhiyun dodie "failed make config oldconfig"; 2507*4882a593Smuzhiyun } 2508*4882a593Smuzhiyun } 2509*4882a593Smuzhiyun} 2510*4882a593Smuzhiyun 2511*4882a593Smuzhiyun# read a config file and use this to force new configs. 2512*4882a593Smuzhiyunsub load_force_config { 2513*4882a593Smuzhiyun my ($config) = @_; 2514*4882a593Smuzhiyun 2515*4882a593Smuzhiyun doprint "Loading force configs from $config\n"; 2516*4882a593Smuzhiyun open(IN, $config) or 2517*4882a593Smuzhiyun dodie "failed to read $config"; 2518*4882a593Smuzhiyun while (<IN>) { 2519*4882a593Smuzhiyun chomp; 2520*4882a593Smuzhiyun if (/^(CONFIG[^\s=]*)(\s*=.*)/) { 2521*4882a593Smuzhiyun $force_config{$1} = $_; 2522*4882a593Smuzhiyun } elsif (/^# (CONFIG_\S*) is not set/) { 2523*4882a593Smuzhiyun $force_config{$1} = $_; 2524*4882a593Smuzhiyun } 2525*4882a593Smuzhiyun } 2526*4882a593Smuzhiyun close IN; 2527*4882a593Smuzhiyun} 2528*4882a593Smuzhiyun 2529*4882a593Smuzhiyunsub build { 2530*4882a593Smuzhiyun my ($type) = @_; 2531*4882a593Smuzhiyun 2532*4882a593Smuzhiyun unlink $buildlog; 2533*4882a593Smuzhiyun 2534*4882a593Smuzhiyun my $start_time = time; 2535*4882a593Smuzhiyun 2536*4882a593Smuzhiyun # Failed builds should not reboot the target 2537*4882a593Smuzhiyun my $save_no_reboot = $no_reboot; 2538*4882a593Smuzhiyun $no_reboot = 1; 2539*4882a593Smuzhiyun 2540*4882a593Smuzhiyun # Calculate a new version from here. 2541*4882a593Smuzhiyun $have_version = 0; 2542*4882a593Smuzhiyun 2543*4882a593Smuzhiyun if (defined($pre_build)) { 2544*4882a593Smuzhiyun my $ret = run_command $pre_build; 2545*4882a593Smuzhiyun if (!$ret && defined($pre_build_die) && 2546*4882a593Smuzhiyun $pre_build_die) { 2547*4882a593Smuzhiyun dodie "failed to pre_build\n"; 2548*4882a593Smuzhiyun } 2549*4882a593Smuzhiyun } 2550*4882a593Smuzhiyun 2551*4882a593Smuzhiyun if ($type =~ /^useconfig:(.*)/) { 2552*4882a593Smuzhiyun run_command "cp $1 $output_config" or 2553*4882a593Smuzhiyun dodie "could not copy $1 to .config"; 2554*4882a593Smuzhiyun 2555*4882a593Smuzhiyun $type = "oldconfig"; 2556*4882a593Smuzhiyun } 2557*4882a593Smuzhiyun 2558*4882a593Smuzhiyun # old config can ask questions 2559*4882a593Smuzhiyun if ($type eq "oldconfig") { 2560*4882a593Smuzhiyun $type = "olddefconfig"; 2561*4882a593Smuzhiyun 2562*4882a593Smuzhiyun # allow for empty configs 2563*4882a593Smuzhiyun run_command "touch $output_config"; 2564*4882a593Smuzhiyun 2565*4882a593Smuzhiyun if (!$noclean) { 2566*4882a593Smuzhiyun run_command "mv $output_config $outputdir/config_temp" or 2567*4882a593Smuzhiyun dodie "moving .config"; 2568*4882a593Smuzhiyun 2569*4882a593Smuzhiyun run_command "$make mrproper" or dodie "make mrproper"; 2570*4882a593Smuzhiyun 2571*4882a593Smuzhiyun run_command "mv $outputdir/config_temp $output_config" or 2572*4882a593Smuzhiyun dodie "moving config_temp"; 2573*4882a593Smuzhiyun } 2574*4882a593Smuzhiyun 2575*4882a593Smuzhiyun } elsif (!$noclean) { 2576*4882a593Smuzhiyun unlink "$output_config"; 2577*4882a593Smuzhiyun run_command "$make mrproper" or 2578*4882a593Smuzhiyun dodie "make mrproper"; 2579*4882a593Smuzhiyun } 2580*4882a593Smuzhiyun 2581*4882a593Smuzhiyun # add something to distinguish this build 2582*4882a593Smuzhiyun open(OUT, "> $outputdir/localversion") or dodie("Can't make localversion file"); 2583*4882a593Smuzhiyun print OUT "$localversion\n"; 2584*4882a593Smuzhiyun close(OUT); 2585*4882a593Smuzhiyun 2586*4882a593Smuzhiyun if (defined($minconfig)) { 2587*4882a593Smuzhiyun load_force_config($minconfig); 2588*4882a593Smuzhiyun } 2589*4882a593Smuzhiyun 2590*4882a593Smuzhiyun if ($type ne "olddefconfig") { 2591*4882a593Smuzhiyun run_command "$make $type" or 2592*4882a593Smuzhiyun dodie "failed make config"; 2593*4882a593Smuzhiyun } 2594*4882a593Smuzhiyun # Run old config regardless, to enforce min configurations 2595*4882a593Smuzhiyun make_oldconfig; 2596*4882a593Smuzhiyun 2597*4882a593Smuzhiyun my $build_ret = run_command "$make $build_options", $buildlog; 2598*4882a593Smuzhiyun 2599*4882a593Smuzhiyun if (defined($post_build)) { 2600*4882a593Smuzhiyun # Because a post build may change the kernel version 2601*4882a593Smuzhiyun # do it now. 2602*4882a593Smuzhiyun get_version; 2603*4882a593Smuzhiyun my $ret = run_command $post_build; 2604*4882a593Smuzhiyun if (!$ret && defined($post_build_die) && 2605*4882a593Smuzhiyun $post_build_die) { 2606*4882a593Smuzhiyun dodie "failed to post_build\n"; 2607*4882a593Smuzhiyun } 2608*4882a593Smuzhiyun } 2609*4882a593Smuzhiyun 2610*4882a593Smuzhiyun if (!$build_ret) { 2611*4882a593Smuzhiyun # bisect may need this to pass 2612*4882a593Smuzhiyun if ($in_bisect) { 2613*4882a593Smuzhiyun $no_reboot = $save_no_reboot; 2614*4882a593Smuzhiyun return 0; 2615*4882a593Smuzhiyun } 2616*4882a593Smuzhiyun fail "failed build" and return 0; 2617*4882a593Smuzhiyun } 2618*4882a593Smuzhiyun 2619*4882a593Smuzhiyun $no_reboot = $save_no_reboot; 2620*4882a593Smuzhiyun 2621*4882a593Smuzhiyun my $end_time = time; 2622*4882a593Smuzhiyun $build_time = $end_time - $start_time; 2623*4882a593Smuzhiyun 2624*4882a593Smuzhiyun return 1; 2625*4882a593Smuzhiyun} 2626*4882a593Smuzhiyun 2627*4882a593Smuzhiyunsub halt { 2628*4882a593Smuzhiyun if (!run_ssh "halt" or defined($power_off)) { 2629*4882a593Smuzhiyun if (defined($poweroff_after_halt)) { 2630*4882a593Smuzhiyun sleep $poweroff_after_halt; 2631*4882a593Smuzhiyun run_command "$power_off"; 2632*4882a593Smuzhiyun } 2633*4882a593Smuzhiyun } else { 2634*4882a593Smuzhiyun # nope? the zap it! 2635*4882a593Smuzhiyun run_command "$power_off"; 2636*4882a593Smuzhiyun } 2637*4882a593Smuzhiyun} 2638*4882a593Smuzhiyun 2639*4882a593Smuzhiyunsub success { 2640*4882a593Smuzhiyun my ($i) = @_; 2641*4882a593Smuzhiyun 2642*4882a593Smuzhiyun $successes++; 2643*4882a593Smuzhiyun 2644*4882a593Smuzhiyun my $name = ""; 2645*4882a593Smuzhiyun 2646*4882a593Smuzhiyun if (defined($test_name)) { 2647*4882a593Smuzhiyun $name = " ($test_name)"; 2648*4882a593Smuzhiyun } 2649*4882a593Smuzhiyun 2650*4882a593Smuzhiyun print_times; 2651*4882a593Smuzhiyun 2652*4882a593Smuzhiyun doprint "\n\n*******************************************\n"; 2653*4882a593Smuzhiyun doprint "*******************************************\n"; 2654*4882a593Smuzhiyun doprint "KTEST RESULT: TEST $i$name SUCCESS!!!! **\n"; 2655*4882a593Smuzhiyun doprint "*******************************************\n"; 2656*4882a593Smuzhiyun doprint "*******************************************\n"; 2657*4882a593Smuzhiyun 2658*4882a593Smuzhiyun if (defined($store_successes)) { 2659*4882a593Smuzhiyun save_logs "success", $store_successes; 2660*4882a593Smuzhiyun } 2661*4882a593Smuzhiyun 2662*4882a593Smuzhiyun if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { 2663*4882a593Smuzhiyun doprint "Reboot and wait $sleep_time seconds\n"; 2664*4882a593Smuzhiyun reboot_to_good $sleep_time; 2665*4882a593Smuzhiyun } 2666*4882a593Smuzhiyun 2667*4882a593Smuzhiyun if (defined($post_test)) { 2668*4882a593Smuzhiyun run_command $post_test; 2669*4882a593Smuzhiyun } 2670*4882a593Smuzhiyun} 2671*4882a593Smuzhiyun 2672*4882a593Smuzhiyunsub answer_bisect { 2673*4882a593Smuzhiyun for (;;) { 2674*4882a593Smuzhiyun doprint "Pass, fail, or skip? [p/f/s]"; 2675*4882a593Smuzhiyun my $ans = <STDIN>; 2676*4882a593Smuzhiyun chomp $ans; 2677*4882a593Smuzhiyun if ($ans eq "p" || $ans eq "P") { 2678*4882a593Smuzhiyun return 1; 2679*4882a593Smuzhiyun } elsif ($ans eq "f" || $ans eq "F") { 2680*4882a593Smuzhiyun return 0; 2681*4882a593Smuzhiyun } elsif ($ans eq "s" || $ans eq "S") { 2682*4882a593Smuzhiyun return -1; 2683*4882a593Smuzhiyun } else { 2684*4882a593Smuzhiyun print "Please answer 'p', 'f', or 's'\n"; 2685*4882a593Smuzhiyun } 2686*4882a593Smuzhiyun } 2687*4882a593Smuzhiyun} 2688*4882a593Smuzhiyun 2689*4882a593Smuzhiyunsub child_run_test { 2690*4882a593Smuzhiyun 2691*4882a593Smuzhiyun # child should have no power 2692*4882a593Smuzhiyun $reboot_on_error = 0; 2693*4882a593Smuzhiyun $poweroff_on_error = 0; 2694*4882a593Smuzhiyun $die_on_failure = 1; 2695*4882a593Smuzhiyun 2696*4882a593Smuzhiyun run_command $run_test, $testlog; 2697*4882a593Smuzhiyun 2698*4882a593Smuzhiyun exit $run_command_status; 2699*4882a593Smuzhiyun} 2700*4882a593Smuzhiyun 2701*4882a593Smuzhiyunmy $child_done; 2702*4882a593Smuzhiyun 2703*4882a593Smuzhiyunsub child_finished { 2704*4882a593Smuzhiyun $child_done = 1; 2705*4882a593Smuzhiyun} 2706*4882a593Smuzhiyun 2707*4882a593Smuzhiyunsub do_run_test { 2708*4882a593Smuzhiyun my $child_pid; 2709*4882a593Smuzhiyun my $child_exit; 2710*4882a593Smuzhiyun my $line; 2711*4882a593Smuzhiyun my $full_line; 2712*4882a593Smuzhiyun my $bug = 0; 2713*4882a593Smuzhiyun my $bug_ignored = 0; 2714*4882a593Smuzhiyun 2715*4882a593Smuzhiyun my $start_time = time; 2716*4882a593Smuzhiyun 2717*4882a593Smuzhiyun wait_for_monitor 1; 2718*4882a593Smuzhiyun 2719*4882a593Smuzhiyun doprint "run test $run_test\n"; 2720*4882a593Smuzhiyun 2721*4882a593Smuzhiyun $child_done = 0; 2722*4882a593Smuzhiyun 2723*4882a593Smuzhiyun $SIG{CHLD} = qw(child_finished); 2724*4882a593Smuzhiyun 2725*4882a593Smuzhiyun $child_pid = fork; 2726*4882a593Smuzhiyun 2727*4882a593Smuzhiyun child_run_test if (!$child_pid); 2728*4882a593Smuzhiyun 2729*4882a593Smuzhiyun $full_line = ""; 2730*4882a593Smuzhiyun 2731*4882a593Smuzhiyun do { 2732*4882a593Smuzhiyun $line = wait_for_input($monitor_fp, 1); 2733*4882a593Smuzhiyun if (defined($line)) { 2734*4882a593Smuzhiyun 2735*4882a593Smuzhiyun # we are not guaranteed to get a full line 2736*4882a593Smuzhiyun $full_line .= $line; 2737*4882a593Smuzhiyun doprint $line; 2738*4882a593Smuzhiyun 2739*4882a593Smuzhiyun if ($full_line =~ /call trace:/i) { 2740*4882a593Smuzhiyun if ($ignore_errors) { 2741*4882a593Smuzhiyun $bug_ignored = 1; 2742*4882a593Smuzhiyun } else { 2743*4882a593Smuzhiyun $bug = 1; 2744*4882a593Smuzhiyun } 2745*4882a593Smuzhiyun } 2746*4882a593Smuzhiyun 2747*4882a593Smuzhiyun if ($full_line =~ /Kernel panic -/) { 2748*4882a593Smuzhiyun $bug = 1; 2749*4882a593Smuzhiyun } 2750*4882a593Smuzhiyun 2751*4882a593Smuzhiyun if ($line =~ /\n/) { 2752*4882a593Smuzhiyun $full_line = ""; 2753*4882a593Smuzhiyun } 2754*4882a593Smuzhiyun } 2755*4882a593Smuzhiyun } while (!$child_done && !$bug); 2756*4882a593Smuzhiyun 2757*4882a593Smuzhiyun if (!$bug && $bug_ignored) { 2758*4882a593Smuzhiyun doprint "WARNING: Call Trace detected but ignored due to IGNORE_ERRORS=1\n"; 2759*4882a593Smuzhiyun } 2760*4882a593Smuzhiyun 2761*4882a593Smuzhiyun if ($bug) { 2762*4882a593Smuzhiyun my $failure_start = time; 2763*4882a593Smuzhiyun my $now; 2764*4882a593Smuzhiyun do { 2765*4882a593Smuzhiyun $line = wait_for_input($monitor_fp, 1); 2766*4882a593Smuzhiyun if (defined($line)) { 2767*4882a593Smuzhiyun doprint $line; 2768*4882a593Smuzhiyun } 2769*4882a593Smuzhiyun $now = time; 2770*4882a593Smuzhiyun if ($now - $failure_start >= $stop_after_failure) { 2771*4882a593Smuzhiyun last; 2772*4882a593Smuzhiyun } 2773*4882a593Smuzhiyun } while (defined($line)); 2774*4882a593Smuzhiyun 2775*4882a593Smuzhiyun doprint "Detected kernel crash!\n"; 2776*4882a593Smuzhiyun # kill the child with extreme prejudice 2777*4882a593Smuzhiyun kill 9, $child_pid; 2778*4882a593Smuzhiyun } 2779*4882a593Smuzhiyun 2780*4882a593Smuzhiyun waitpid $child_pid, 0; 2781*4882a593Smuzhiyun $child_exit = $? >> 8; 2782*4882a593Smuzhiyun 2783*4882a593Smuzhiyun my $end_time = time; 2784*4882a593Smuzhiyun $test_time = $end_time - $start_time; 2785*4882a593Smuzhiyun 2786*4882a593Smuzhiyun if (!$bug && $in_bisect) { 2787*4882a593Smuzhiyun if (defined($bisect_ret_good)) { 2788*4882a593Smuzhiyun if ($child_exit == $bisect_ret_good) { 2789*4882a593Smuzhiyun return 1; 2790*4882a593Smuzhiyun } 2791*4882a593Smuzhiyun } 2792*4882a593Smuzhiyun if (defined($bisect_ret_skip)) { 2793*4882a593Smuzhiyun if ($child_exit == $bisect_ret_skip) { 2794*4882a593Smuzhiyun return -1; 2795*4882a593Smuzhiyun } 2796*4882a593Smuzhiyun } 2797*4882a593Smuzhiyun if (defined($bisect_ret_abort)) { 2798*4882a593Smuzhiyun if ($child_exit == $bisect_ret_abort) { 2799*4882a593Smuzhiyun fail "test abort" and return -2; 2800*4882a593Smuzhiyun } 2801*4882a593Smuzhiyun } 2802*4882a593Smuzhiyun if (defined($bisect_ret_bad)) { 2803*4882a593Smuzhiyun if ($child_exit == $bisect_ret_skip) { 2804*4882a593Smuzhiyun return 0; 2805*4882a593Smuzhiyun } 2806*4882a593Smuzhiyun } 2807*4882a593Smuzhiyun if (defined($bisect_ret_default)) { 2808*4882a593Smuzhiyun if ($bisect_ret_default eq "good") { 2809*4882a593Smuzhiyun return 1; 2810*4882a593Smuzhiyun } elsif ($bisect_ret_default eq "bad") { 2811*4882a593Smuzhiyun return 0; 2812*4882a593Smuzhiyun } elsif ($bisect_ret_default eq "skip") { 2813*4882a593Smuzhiyun return -1; 2814*4882a593Smuzhiyun } elsif ($bisect_ret_default eq "abort") { 2815*4882a593Smuzhiyun return -2; 2816*4882a593Smuzhiyun } else { 2817*4882a593Smuzhiyun fail "unknown default action: $bisect_ret_default" 2818*4882a593Smuzhiyun and return -2; 2819*4882a593Smuzhiyun } 2820*4882a593Smuzhiyun } 2821*4882a593Smuzhiyun } 2822*4882a593Smuzhiyun 2823*4882a593Smuzhiyun if ($bug || $child_exit) { 2824*4882a593Smuzhiyun return 0 if $in_bisect; 2825*4882a593Smuzhiyun fail "test failed" and return 0; 2826*4882a593Smuzhiyun } 2827*4882a593Smuzhiyun return 1; 2828*4882a593Smuzhiyun} 2829*4882a593Smuzhiyun 2830*4882a593Smuzhiyunsub run_git_bisect { 2831*4882a593Smuzhiyun my ($command) = @_; 2832*4882a593Smuzhiyun 2833*4882a593Smuzhiyun doprint "$command ... "; 2834*4882a593Smuzhiyun 2835*4882a593Smuzhiyun my $output = `$command 2>&1`; 2836*4882a593Smuzhiyun my $ret = $?; 2837*4882a593Smuzhiyun 2838*4882a593Smuzhiyun logit $output; 2839*4882a593Smuzhiyun 2840*4882a593Smuzhiyun if ($ret) { 2841*4882a593Smuzhiyun doprint "FAILED\n"; 2842*4882a593Smuzhiyun dodie "Failed to git bisect"; 2843*4882a593Smuzhiyun } 2844*4882a593Smuzhiyun 2845*4882a593Smuzhiyun doprint "SUCCESS\n"; 2846*4882a593Smuzhiyun if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) { 2847*4882a593Smuzhiyun doprint "$1 [$2]\n"; 2848*4882a593Smuzhiyun } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) { 2849*4882a593Smuzhiyun $bisect_bad_commit = $1; 2850*4882a593Smuzhiyun doprint "Found bad commit... $1\n"; 2851*4882a593Smuzhiyun return 0; 2852*4882a593Smuzhiyun } else { 2853*4882a593Smuzhiyun # we already logged it, just print it now. 2854*4882a593Smuzhiyun print $output; 2855*4882a593Smuzhiyun } 2856*4882a593Smuzhiyun 2857*4882a593Smuzhiyun return 1; 2858*4882a593Smuzhiyun} 2859*4882a593Smuzhiyun 2860*4882a593Smuzhiyunsub bisect_reboot { 2861*4882a593Smuzhiyun doprint "Reboot and sleep $bisect_sleep_time seconds\n"; 2862*4882a593Smuzhiyun reboot_to_good $bisect_sleep_time; 2863*4882a593Smuzhiyun} 2864*4882a593Smuzhiyun 2865*4882a593Smuzhiyun# returns 1 on success, 0 on failure, -1 on skip 2866*4882a593Smuzhiyunsub run_bisect_test { 2867*4882a593Smuzhiyun my ($type, $buildtype) = @_; 2868*4882a593Smuzhiyun 2869*4882a593Smuzhiyun my $failed = 0; 2870*4882a593Smuzhiyun my $result; 2871*4882a593Smuzhiyun my $output; 2872*4882a593Smuzhiyun my $ret; 2873*4882a593Smuzhiyun 2874*4882a593Smuzhiyun $in_bisect = 1; 2875*4882a593Smuzhiyun 2876*4882a593Smuzhiyun build $buildtype or $failed = 1; 2877*4882a593Smuzhiyun 2878*4882a593Smuzhiyun if ($type ne "build") { 2879*4882a593Smuzhiyun if ($failed && $bisect_skip) { 2880*4882a593Smuzhiyun $in_bisect = 0; 2881*4882a593Smuzhiyun return -1; 2882*4882a593Smuzhiyun } 2883*4882a593Smuzhiyun dodie "Failed on build" if $failed; 2884*4882a593Smuzhiyun 2885*4882a593Smuzhiyun # Now boot the box 2886*4882a593Smuzhiyun start_monitor_and_install or $failed = 1; 2887*4882a593Smuzhiyun 2888*4882a593Smuzhiyun if ($type ne "boot") { 2889*4882a593Smuzhiyun if ($failed && $bisect_skip) { 2890*4882a593Smuzhiyun end_monitor; 2891*4882a593Smuzhiyun bisect_reboot; 2892*4882a593Smuzhiyun $in_bisect = 0; 2893*4882a593Smuzhiyun return -1; 2894*4882a593Smuzhiyun } 2895*4882a593Smuzhiyun dodie "Failed on boot" if $failed; 2896*4882a593Smuzhiyun 2897*4882a593Smuzhiyun do_run_test or $failed = 1; 2898*4882a593Smuzhiyun } 2899*4882a593Smuzhiyun end_monitor; 2900*4882a593Smuzhiyun } 2901*4882a593Smuzhiyun 2902*4882a593Smuzhiyun if ($failed) { 2903*4882a593Smuzhiyun $result = 0; 2904*4882a593Smuzhiyun } else { 2905*4882a593Smuzhiyun $result = 1; 2906*4882a593Smuzhiyun } 2907*4882a593Smuzhiyun 2908*4882a593Smuzhiyun # reboot the box to a kernel we can ssh to 2909*4882a593Smuzhiyun if ($type ne "build") { 2910*4882a593Smuzhiyun bisect_reboot; 2911*4882a593Smuzhiyun } 2912*4882a593Smuzhiyun $in_bisect = 0; 2913*4882a593Smuzhiyun 2914*4882a593Smuzhiyun return $result; 2915*4882a593Smuzhiyun} 2916*4882a593Smuzhiyun 2917*4882a593Smuzhiyunsub run_bisect { 2918*4882a593Smuzhiyun my ($type) = @_; 2919*4882a593Smuzhiyun my $buildtype = "oldconfig"; 2920*4882a593Smuzhiyun 2921*4882a593Smuzhiyun # We should have a minconfig to use? 2922*4882a593Smuzhiyun if (defined($minconfig)) { 2923*4882a593Smuzhiyun $buildtype = "useconfig:$minconfig"; 2924*4882a593Smuzhiyun } 2925*4882a593Smuzhiyun 2926*4882a593Smuzhiyun # If the user sets bisect_tries to less than 1, then no tries 2927*4882a593Smuzhiyun # is a success. 2928*4882a593Smuzhiyun my $ret = 1; 2929*4882a593Smuzhiyun 2930*4882a593Smuzhiyun # Still let the user manually decide that though. 2931*4882a593Smuzhiyun if ($bisect_tries < 1 && $bisect_manual) { 2932*4882a593Smuzhiyun $ret = answer_bisect; 2933*4882a593Smuzhiyun } 2934*4882a593Smuzhiyun 2935*4882a593Smuzhiyun for (my $i = 0; $i < $bisect_tries; $i++) { 2936*4882a593Smuzhiyun if ($bisect_tries > 1) { 2937*4882a593Smuzhiyun my $t = $i + 1; 2938*4882a593Smuzhiyun doprint("Running bisect trial $t of $bisect_tries:\n"); 2939*4882a593Smuzhiyun } 2940*4882a593Smuzhiyun $ret = run_bisect_test $type, $buildtype; 2941*4882a593Smuzhiyun 2942*4882a593Smuzhiyun if ($bisect_manual) { 2943*4882a593Smuzhiyun $ret = answer_bisect; 2944*4882a593Smuzhiyun } 2945*4882a593Smuzhiyun 2946*4882a593Smuzhiyun last if (!$ret); 2947*4882a593Smuzhiyun } 2948*4882a593Smuzhiyun 2949*4882a593Smuzhiyun # Are we looking for where it worked, not failed? 2950*4882a593Smuzhiyun if ($reverse_bisect && $ret >= 0) { 2951*4882a593Smuzhiyun $ret = !$ret; 2952*4882a593Smuzhiyun } 2953*4882a593Smuzhiyun 2954*4882a593Smuzhiyun if ($ret > 0) { 2955*4882a593Smuzhiyun return "good"; 2956*4882a593Smuzhiyun } elsif ($ret == 0) { 2957*4882a593Smuzhiyun return "bad"; 2958*4882a593Smuzhiyun } elsif ($bisect_skip) { 2959*4882a593Smuzhiyun doprint "HIT A BAD COMMIT ... SKIPPING\n"; 2960*4882a593Smuzhiyun return "skip"; 2961*4882a593Smuzhiyun } 2962*4882a593Smuzhiyun} 2963*4882a593Smuzhiyun 2964*4882a593Smuzhiyunsub update_bisect_replay { 2965*4882a593Smuzhiyun my $tmp_log = "$tmpdir/ktest_bisect_log"; 2966*4882a593Smuzhiyun run_command "git bisect log > $tmp_log" or 2967*4882a593Smuzhiyun dodie "can't create bisect log"; 2968*4882a593Smuzhiyun return $tmp_log; 2969*4882a593Smuzhiyun} 2970*4882a593Smuzhiyun 2971*4882a593Smuzhiyunsub bisect { 2972*4882a593Smuzhiyun my ($i) = @_; 2973*4882a593Smuzhiyun 2974*4882a593Smuzhiyun my $result; 2975*4882a593Smuzhiyun 2976*4882a593Smuzhiyun dodie "BISECT_GOOD[$i] not defined\n" if (!defined($bisect_good)); 2977*4882a593Smuzhiyun dodie "BISECT_BAD[$i] not defined\n" if (!defined($bisect_bad)); 2978*4882a593Smuzhiyun dodie "BISECT_TYPE[$i] not defined\n" if (!defined($bisect_type)); 2979*4882a593Smuzhiyun 2980*4882a593Smuzhiyun my $good = $bisect_good; 2981*4882a593Smuzhiyun my $bad = $bisect_bad; 2982*4882a593Smuzhiyun my $type = $bisect_type; 2983*4882a593Smuzhiyun my $start = $bisect_start; 2984*4882a593Smuzhiyun my $replay = $bisect_replay; 2985*4882a593Smuzhiyun my $start_files = $bisect_files; 2986*4882a593Smuzhiyun 2987*4882a593Smuzhiyun if (defined($start_files)) { 2988*4882a593Smuzhiyun $start_files = " -- " . $start_files; 2989*4882a593Smuzhiyun } else { 2990*4882a593Smuzhiyun $start_files = ""; 2991*4882a593Smuzhiyun } 2992*4882a593Smuzhiyun 2993*4882a593Smuzhiyun # convert to true sha1's 2994*4882a593Smuzhiyun $good = get_sha1($good); 2995*4882a593Smuzhiyun $bad = get_sha1($bad); 2996*4882a593Smuzhiyun 2997*4882a593Smuzhiyun if (defined($bisect_reverse) && $bisect_reverse == 1) { 2998*4882a593Smuzhiyun doprint "Performing a reverse bisect (bad is good, good is bad!)\n"; 2999*4882a593Smuzhiyun $reverse_bisect = 1; 3000*4882a593Smuzhiyun } else { 3001*4882a593Smuzhiyun $reverse_bisect = 0; 3002*4882a593Smuzhiyun } 3003*4882a593Smuzhiyun 3004*4882a593Smuzhiyun # Can't have a test without having a test to run 3005*4882a593Smuzhiyun if ($type eq "test" && !defined($run_test)) { 3006*4882a593Smuzhiyun $type = "boot"; 3007*4882a593Smuzhiyun } 3008*4882a593Smuzhiyun 3009*4882a593Smuzhiyun # Check if a bisect was running 3010*4882a593Smuzhiyun my $bisect_start_file = "$builddir/.git/BISECT_START"; 3011*4882a593Smuzhiyun 3012*4882a593Smuzhiyun my $check = $bisect_check; 3013*4882a593Smuzhiyun my $do_check = defined($check) && $check ne "0"; 3014*4882a593Smuzhiyun 3015*4882a593Smuzhiyun if ( -f $bisect_start_file ) { 3016*4882a593Smuzhiyun print "Bisect in progress found\n"; 3017*4882a593Smuzhiyun if ($do_check) { 3018*4882a593Smuzhiyun print " If you say yes, then no checks of good or bad will be done\n"; 3019*4882a593Smuzhiyun } 3020*4882a593Smuzhiyun if (defined($replay)) { 3021*4882a593Smuzhiyun print "** BISECT_REPLAY is defined in config file **"; 3022*4882a593Smuzhiyun print " Ignore config option and perform new git bisect log?\n"; 3023*4882a593Smuzhiyun if (read_ync " (yes, no, or cancel) ") { 3024*4882a593Smuzhiyun $replay = update_bisect_replay; 3025*4882a593Smuzhiyun $do_check = 0; 3026*4882a593Smuzhiyun } 3027*4882a593Smuzhiyun } elsif (read_yn "read git log and continue?") { 3028*4882a593Smuzhiyun $replay = update_bisect_replay; 3029*4882a593Smuzhiyun $do_check = 0; 3030*4882a593Smuzhiyun } 3031*4882a593Smuzhiyun } 3032*4882a593Smuzhiyun 3033*4882a593Smuzhiyun if ($do_check) { 3034*4882a593Smuzhiyun 3035*4882a593Smuzhiyun # get current HEAD 3036*4882a593Smuzhiyun my $head = get_sha1("HEAD"); 3037*4882a593Smuzhiyun 3038*4882a593Smuzhiyun if ($check ne "good") { 3039*4882a593Smuzhiyun doprint "TESTING BISECT BAD [$bad]\n"; 3040*4882a593Smuzhiyun run_command "git checkout $bad" or 3041*4882a593Smuzhiyun dodie "Failed to checkout $bad"; 3042*4882a593Smuzhiyun 3043*4882a593Smuzhiyun $result = run_bisect $type; 3044*4882a593Smuzhiyun 3045*4882a593Smuzhiyun if ($result ne "bad") { 3046*4882a593Smuzhiyun fail "Tested BISECT_BAD [$bad] and it succeeded" and return 0; 3047*4882a593Smuzhiyun } 3048*4882a593Smuzhiyun } 3049*4882a593Smuzhiyun 3050*4882a593Smuzhiyun if ($check ne "bad") { 3051*4882a593Smuzhiyun doprint "TESTING BISECT GOOD [$good]\n"; 3052*4882a593Smuzhiyun run_command "git checkout $good" or 3053*4882a593Smuzhiyun dodie "Failed to checkout $good"; 3054*4882a593Smuzhiyun 3055*4882a593Smuzhiyun $result = run_bisect $type; 3056*4882a593Smuzhiyun 3057*4882a593Smuzhiyun if ($result ne "good") { 3058*4882a593Smuzhiyun fail "Tested BISECT_GOOD [$good] and it failed" and return 0; 3059*4882a593Smuzhiyun } 3060*4882a593Smuzhiyun } 3061*4882a593Smuzhiyun 3062*4882a593Smuzhiyun # checkout where we started 3063*4882a593Smuzhiyun run_command "git checkout $head" or 3064*4882a593Smuzhiyun dodie "Failed to checkout $head"; 3065*4882a593Smuzhiyun } 3066*4882a593Smuzhiyun 3067*4882a593Smuzhiyun run_command "git bisect start$start_files" or 3068*4882a593Smuzhiyun dodie "could not start bisect"; 3069*4882a593Smuzhiyun 3070*4882a593Smuzhiyun if (defined($replay)) { 3071*4882a593Smuzhiyun run_command "git bisect replay $replay" or 3072*4882a593Smuzhiyun dodie "failed to run replay"; 3073*4882a593Smuzhiyun } else { 3074*4882a593Smuzhiyun 3075*4882a593Smuzhiyun run_command "git bisect good $good" or 3076*4882a593Smuzhiyun dodie "could not set bisect good to $good"; 3077*4882a593Smuzhiyun 3078*4882a593Smuzhiyun run_git_bisect "git bisect bad $bad" or 3079*4882a593Smuzhiyun dodie "could not set bisect bad to $bad"; 3080*4882a593Smuzhiyun 3081*4882a593Smuzhiyun } 3082*4882a593Smuzhiyun 3083*4882a593Smuzhiyun if (defined($start)) { 3084*4882a593Smuzhiyun run_command "git checkout $start" or 3085*4882a593Smuzhiyun dodie "failed to checkout $start"; 3086*4882a593Smuzhiyun } 3087*4882a593Smuzhiyun 3088*4882a593Smuzhiyun my $test; 3089*4882a593Smuzhiyun do { 3090*4882a593Smuzhiyun $result = run_bisect $type; 3091*4882a593Smuzhiyun $test = run_git_bisect "git bisect $result"; 3092*4882a593Smuzhiyun print_times; 3093*4882a593Smuzhiyun } while ($test); 3094*4882a593Smuzhiyun 3095*4882a593Smuzhiyun run_command "git bisect log" or 3096*4882a593Smuzhiyun dodie "could not capture git bisect log"; 3097*4882a593Smuzhiyun 3098*4882a593Smuzhiyun run_command "git bisect reset" or 3099*4882a593Smuzhiyun dodie "could not reset git bisect"; 3100*4882a593Smuzhiyun 3101*4882a593Smuzhiyun doprint "Bad commit was [$bisect_bad_commit]\n"; 3102*4882a593Smuzhiyun 3103*4882a593Smuzhiyun success $i; 3104*4882a593Smuzhiyun} 3105*4882a593Smuzhiyun 3106*4882a593Smuzhiyun# config_ignore holds the configs that were set (or unset) for 3107*4882a593Smuzhiyun# a good config and we will ignore these configs for the rest 3108*4882a593Smuzhiyun# of a config bisect. These configs stay as they were. 3109*4882a593Smuzhiyunmy %config_ignore; 3110*4882a593Smuzhiyun 3111*4882a593Smuzhiyun# config_set holds what all configs were set as. 3112*4882a593Smuzhiyunmy %config_set; 3113*4882a593Smuzhiyun 3114*4882a593Smuzhiyun# config_off holds the set of configs that the bad config had disabled. 3115*4882a593Smuzhiyun# We need to record them and set them in the .config when running 3116*4882a593Smuzhiyun# olddefconfig, because olddefconfig keeps the defaults. 3117*4882a593Smuzhiyunmy %config_off; 3118*4882a593Smuzhiyun 3119*4882a593Smuzhiyun# config_off_tmp holds a set of configs to turn off for now 3120*4882a593Smuzhiyunmy @config_off_tmp; 3121*4882a593Smuzhiyun 3122*4882a593Smuzhiyun# config_list is the set of configs that are being tested 3123*4882a593Smuzhiyunmy %config_list; 3124*4882a593Smuzhiyunmy %null_config; 3125*4882a593Smuzhiyun 3126*4882a593Smuzhiyunmy %dependency; 3127*4882a593Smuzhiyun 3128*4882a593Smuzhiyunsub assign_configs { 3129*4882a593Smuzhiyun my ($hash, $config) = @_; 3130*4882a593Smuzhiyun 3131*4882a593Smuzhiyun doprint "Reading configs from $config\n"; 3132*4882a593Smuzhiyun 3133*4882a593Smuzhiyun open (IN, $config) 3134*4882a593Smuzhiyun or dodie "Failed to read $config"; 3135*4882a593Smuzhiyun 3136*4882a593Smuzhiyun while (<IN>) { 3137*4882a593Smuzhiyun chomp; 3138*4882a593Smuzhiyun if (/^((CONFIG\S*)=.*)/) { 3139*4882a593Smuzhiyun ${$hash}{$2} = $1; 3140*4882a593Smuzhiyun } elsif (/^(# (CONFIG\S*) is not set)/) { 3141*4882a593Smuzhiyun ${$hash}{$2} = $1; 3142*4882a593Smuzhiyun } 3143*4882a593Smuzhiyun } 3144*4882a593Smuzhiyun 3145*4882a593Smuzhiyun close(IN); 3146*4882a593Smuzhiyun} 3147*4882a593Smuzhiyun 3148*4882a593Smuzhiyunsub process_config_ignore { 3149*4882a593Smuzhiyun my ($config) = @_; 3150*4882a593Smuzhiyun 3151*4882a593Smuzhiyun assign_configs \%config_ignore, $config; 3152*4882a593Smuzhiyun} 3153*4882a593Smuzhiyun 3154*4882a593Smuzhiyunsub get_dependencies { 3155*4882a593Smuzhiyun my ($config) = @_; 3156*4882a593Smuzhiyun 3157*4882a593Smuzhiyun my $arr = $dependency{$config}; 3158*4882a593Smuzhiyun if (!defined($arr)) { 3159*4882a593Smuzhiyun return (); 3160*4882a593Smuzhiyun } 3161*4882a593Smuzhiyun 3162*4882a593Smuzhiyun my @deps = @{$arr}; 3163*4882a593Smuzhiyun 3164*4882a593Smuzhiyun foreach my $dep (@{$arr}) { 3165*4882a593Smuzhiyun print "ADD DEP $dep\n"; 3166*4882a593Smuzhiyun @deps = (@deps, get_dependencies $dep); 3167*4882a593Smuzhiyun } 3168*4882a593Smuzhiyun 3169*4882a593Smuzhiyun return @deps; 3170*4882a593Smuzhiyun} 3171*4882a593Smuzhiyun 3172*4882a593Smuzhiyunsub save_config { 3173*4882a593Smuzhiyun my ($pc, $file) = @_; 3174*4882a593Smuzhiyun 3175*4882a593Smuzhiyun my %configs = %{$pc}; 3176*4882a593Smuzhiyun 3177*4882a593Smuzhiyun doprint "Saving configs into $file\n"; 3178*4882a593Smuzhiyun 3179*4882a593Smuzhiyun open(OUT, ">$file") or dodie "Can not write to $file"; 3180*4882a593Smuzhiyun 3181*4882a593Smuzhiyun foreach my $config (keys %configs) { 3182*4882a593Smuzhiyun print OUT "$configs{$config}\n"; 3183*4882a593Smuzhiyun } 3184*4882a593Smuzhiyun close(OUT); 3185*4882a593Smuzhiyun} 3186*4882a593Smuzhiyun 3187*4882a593Smuzhiyunsub create_config { 3188*4882a593Smuzhiyun my ($name, $pc) = @_; 3189*4882a593Smuzhiyun 3190*4882a593Smuzhiyun doprint "Creating old config from $name configs\n"; 3191*4882a593Smuzhiyun 3192*4882a593Smuzhiyun save_config $pc, $output_config; 3193*4882a593Smuzhiyun 3194*4882a593Smuzhiyun make_oldconfig; 3195*4882a593Smuzhiyun} 3196*4882a593Smuzhiyun 3197*4882a593Smuzhiyunsub run_config_bisect_test { 3198*4882a593Smuzhiyun my ($type) = @_; 3199*4882a593Smuzhiyun 3200*4882a593Smuzhiyun my $ret = run_bisect_test $type, "oldconfig"; 3201*4882a593Smuzhiyun 3202*4882a593Smuzhiyun if ($bisect_manual) { 3203*4882a593Smuzhiyun $ret = answer_bisect; 3204*4882a593Smuzhiyun } 3205*4882a593Smuzhiyun 3206*4882a593Smuzhiyun return $ret; 3207*4882a593Smuzhiyun} 3208*4882a593Smuzhiyun 3209*4882a593Smuzhiyunsub config_bisect_end { 3210*4882a593Smuzhiyun my ($good, $bad) = @_; 3211*4882a593Smuzhiyun my $diffexec = "diff -u"; 3212*4882a593Smuzhiyun 3213*4882a593Smuzhiyun if (-f "$builddir/scripts/diffconfig") { 3214*4882a593Smuzhiyun $diffexec = "$builddir/scripts/diffconfig"; 3215*4882a593Smuzhiyun } 3216*4882a593Smuzhiyun doprint "\n\n***************************************\n"; 3217*4882a593Smuzhiyun doprint "No more config bisecting possible.\n"; 3218*4882a593Smuzhiyun run_command "$diffexec $good $bad", 1; 3219*4882a593Smuzhiyun doprint "***************************************\n\n"; 3220*4882a593Smuzhiyun} 3221*4882a593Smuzhiyun 3222*4882a593Smuzhiyunmy $pass = 1; 3223*4882a593Smuzhiyun 3224*4882a593Smuzhiyunsub run_config_bisect { 3225*4882a593Smuzhiyun my ($good, $bad, $last_result) = @_; 3226*4882a593Smuzhiyun my $reset = ""; 3227*4882a593Smuzhiyun my $cmd; 3228*4882a593Smuzhiyun my $ret; 3229*4882a593Smuzhiyun 3230*4882a593Smuzhiyun if (!length($last_result)) { 3231*4882a593Smuzhiyun $reset = "-r"; 3232*4882a593Smuzhiyun } 3233*4882a593Smuzhiyun run_command "$config_bisect_exec $reset -b $outputdir $good $bad $last_result", 1; 3234*4882a593Smuzhiyun 3235*4882a593Smuzhiyun # config-bisect returns: 3236*4882a593Smuzhiyun # 0 if there is more to bisect 3237*4882a593Smuzhiyun # 1 for finding a good config 3238*4882a593Smuzhiyun # 2 if it can not find any more configs 3239*4882a593Smuzhiyun # -1 (255) on error 3240*4882a593Smuzhiyun if ($run_command_status) { 3241*4882a593Smuzhiyun return $run_command_status; 3242*4882a593Smuzhiyun } 3243*4882a593Smuzhiyun 3244*4882a593Smuzhiyun $ret = run_config_bisect_test $config_bisect_type; 3245*4882a593Smuzhiyun if ($ret) { 3246*4882a593Smuzhiyun doprint "NEW GOOD CONFIG ($pass)\n"; 3247*4882a593Smuzhiyun system("cp $output_config $tmpdir/good_config.tmp.$pass"); 3248*4882a593Smuzhiyun $pass++; 3249*4882a593Smuzhiyun # Return 3 for good config 3250*4882a593Smuzhiyun return 3; 3251*4882a593Smuzhiyun } else { 3252*4882a593Smuzhiyun doprint "NEW BAD CONFIG ($pass)\n"; 3253*4882a593Smuzhiyun system("cp $output_config $tmpdir/bad_config.tmp.$pass"); 3254*4882a593Smuzhiyun $pass++; 3255*4882a593Smuzhiyun # Return 4 for bad config 3256*4882a593Smuzhiyun return 4; 3257*4882a593Smuzhiyun } 3258*4882a593Smuzhiyun} 3259*4882a593Smuzhiyun 3260*4882a593Smuzhiyunsub config_bisect { 3261*4882a593Smuzhiyun my ($i) = @_; 3262*4882a593Smuzhiyun 3263*4882a593Smuzhiyun my $good_config; 3264*4882a593Smuzhiyun my $bad_config; 3265*4882a593Smuzhiyun 3266*4882a593Smuzhiyun my $type = $config_bisect_type; 3267*4882a593Smuzhiyun my $ret; 3268*4882a593Smuzhiyun 3269*4882a593Smuzhiyun $bad_config = $config_bisect; 3270*4882a593Smuzhiyun 3271*4882a593Smuzhiyun if (defined($config_bisect_good)) { 3272*4882a593Smuzhiyun $good_config = $config_bisect_good; 3273*4882a593Smuzhiyun } elsif (defined($minconfig)) { 3274*4882a593Smuzhiyun $good_config = $minconfig; 3275*4882a593Smuzhiyun } else { 3276*4882a593Smuzhiyun doprint "No config specified, checking if defconfig works"; 3277*4882a593Smuzhiyun $ret = run_bisect_test $type, "defconfig"; 3278*4882a593Smuzhiyun if (!$ret) { 3279*4882a593Smuzhiyun fail "Have no good config to compare with, please set CONFIG_BISECT_GOOD"; 3280*4882a593Smuzhiyun return 1; 3281*4882a593Smuzhiyun } 3282*4882a593Smuzhiyun $good_config = $output_config; 3283*4882a593Smuzhiyun } 3284*4882a593Smuzhiyun 3285*4882a593Smuzhiyun if (!defined($config_bisect_exec)) { 3286*4882a593Smuzhiyun # First check the location that ktest.pl ran 3287*4882a593Smuzhiyun my @locations = ( "$pwd/config-bisect.pl", 3288*4882a593Smuzhiyun "$dirname/config-bisect.pl", 3289*4882a593Smuzhiyun "$builddir/tools/testing/ktest/config-bisect.pl", 3290*4882a593Smuzhiyun undef ); 3291*4882a593Smuzhiyun foreach my $loc (@locations) { 3292*4882a593Smuzhiyun doprint "loc = $loc\n"; 3293*4882a593Smuzhiyun $config_bisect_exec = $loc; 3294*4882a593Smuzhiyun last if (defined($config_bisect_exec && -x $config_bisect_exec)); 3295*4882a593Smuzhiyun } 3296*4882a593Smuzhiyun if (!defined($config_bisect_exec)) { 3297*4882a593Smuzhiyun fail "Could not find an executable config-bisect.pl\n", 3298*4882a593Smuzhiyun " Set CONFIG_BISECT_EXEC to point to config-bisect.pl"; 3299*4882a593Smuzhiyun return 1; 3300*4882a593Smuzhiyun } 3301*4882a593Smuzhiyun } 3302*4882a593Smuzhiyun 3303*4882a593Smuzhiyun # we don't want min configs to cause issues here. 3304*4882a593Smuzhiyun doprint "Disabling 'MIN_CONFIG' for this test\n"; 3305*4882a593Smuzhiyun undef $minconfig; 3306*4882a593Smuzhiyun 3307*4882a593Smuzhiyun my %good_configs; 3308*4882a593Smuzhiyun my %bad_configs; 3309*4882a593Smuzhiyun my %tmp_configs; 3310*4882a593Smuzhiyun 3311*4882a593Smuzhiyun if (-f "$tmpdir/good_config.tmp" || -f "$tmpdir/bad_config.tmp") { 3312*4882a593Smuzhiyun if (read_yn "Interrupted config-bisect. Continue (n - will start new)?") { 3313*4882a593Smuzhiyun if (-f "$tmpdir/good_config.tmp") { 3314*4882a593Smuzhiyun $good_config = "$tmpdir/good_config.tmp"; 3315*4882a593Smuzhiyun } else { 3316*4882a593Smuzhiyun $good_config = "$tmpdir/good_config"; 3317*4882a593Smuzhiyun } 3318*4882a593Smuzhiyun if (-f "$tmpdir/bad_config.tmp") { 3319*4882a593Smuzhiyun $bad_config = "$tmpdir/bad_config.tmp"; 3320*4882a593Smuzhiyun } else { 3321*4882a593Smuzhiyun $bad_config = "$tmpdir/bad_config"; 3322*4882a593Smuzhiyun } 3323*4882a593Smuzhiyun } 3324*4882a593Smuzhiyun } 3325*4882a593Smuzhiyun doprint "Run good configs through make oldconfig\n"; 3326*4882a593Smuzhiyun assign_configs \%tmp_configs, $good_config; 3327*4882a593Smuzhiyun create_config "$good_config", \%tmp_configs; 3328*4882a593Smuzhiyun $good_config = "$tmpdir/good_config"; 3329*4882a593Smuzhiyun system("cp $output_config $good_config") == 0 or dodie "cp good config"; 3330*4882a593Smuzhiyun 3331*4882a593Smuzhiyun doprint "Run bad configs through make oldconfig\n"; 3332*4882a593Smuzhiyun assign_configs \%tmp_configs, $bad_config; 3333*4882a593Smuzhiyun create_config "$bad_config", \%tmp_configs; 3334*4882a593Smuzhiyun $bad_config = "$tmpdir/bad_config"; 3335*4882a593Smuzhiyun system("cp $output_config $bad_config") == 0 or dodie "cp bad config"; 3336*4882a593Smuzhiyun 3337*4882a593Smuzhiyun if (defined($config_bisect_check) && $config_bisect_check ne "0") { 3338*4882a593Smuzhiyun if ($config_bisect_check ne "good") { 3339*4882a593Smuzhiyun doprint "Testing bad config\n"; 3340*4882a593Smuzhiyun 3341*4882a593Smuzhiyun $ret = run_bisect_test $type, "useconfig:$bad_config"; 3342*4882a593Smuzhiyun if ($ret) { 3343*4882a593Smuzhiyun fail "Bad config succeeded when expected to fail!"; 3344*4882a593Smuzhiyun return 0; 3345*4882a593Smuzhiyun } 3346*4882a593Smuzhiyun } 3347*4882a593Smuzhiyun if ($config_bisect_check ne "bad") { 3348*4882a593Smuzhiyun doprint "Testing good config\n"; 3349*4882a593Smuzhiyun 3350*4882a593Smuzhiyun $ret = run_bisect_test $type, "useconfig:$good_config"; 3351*4882a593Smuzhiyun if (!$ret) { 3352*4882a593Smuzhiyun fail "Good config failed when expected to succeed!"; 3353*4882a593Smuzhiyun return 0; 3354*4882a593Smuzhiyun } 3355*4882a593Smuzhiyun } 3356*4882a593Smuzhiyun } 3357*4882a593Smuzhiyun 3358*4882a593Smuzhiyun my $last_run = ""; 3359*4882a593Smuzhiyun 3360*4882a593Smuzhiyun do { 3361*4882a593Smuzhiyun $ret = run_config_bisect $good_config, $bad_config, $last_run; 3362*4882a593Smuzhiyun if ($ret == 3) { 3363*4882a593Smuzhiyun $last_run = "good"; 3364*4882a593Smuzhiyun } elsif ($ret == 4) { 3365*4882a593Smuzhiyun $last_run = "bad"; 3366*4882a593Smuzhiyun } 3367*4882a593Smuzhiyun print_times; 3368*4882a593Smuzhiyun } while ($ret == 3 || $ret == 4); 3369*4882a593Smuzhiyun 3370*4882a593Smuzhiyun if ($ret == 2) { 3371*4882a593Smuzhiyun config_bisect_end "$good_config.tmp", "$bad_config.tmp"; 3372*4882a593Smuzhiyun } 3373*4882a593Smuzhiyun 3374*4882a593Smuzhiyun return $ret if ($ret < 0); 3375*4882a593Smuzhiyun 3376*4882a593Smuzhiyun success $i; 3377*4882a593Smuzhiyun} 3378*4882a593Smuzhiyun 3379*4882a593Smuzhiyunsub patchcheck_reboot { 3380*4882a593Smuzhiyun doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; 3381*4882a593Smuzhiyun reboot_to_good $patchcheck_sleep_time; 3382*4882a593Smuzhiyun} 3383*4882a593Smuzhiyun 3384*4882a593Smuzhiyunsub patchcheck { 3385*4882a593Smuzhiyun my ($i) = @_; 3386*4882a593Smuzhiyun 3387*4882a593Smuzhiyun dodie "PATCHCHECK_START[$i] not defined\n" 3388*4882a593Smuzhiyun if (!defined($patchcheck_start)); 3389*4882a593Smuzhiyun dodie "PATCHCHECK_TYPE[$i] not defined\n" 3390*4882a593Smuzhiyun if (!defined($patchcheck_type)); 3391*4882a593Smuzhiyun 3392*4882a593Smuzhiyun my $start = $patchcheck_start; 3393*4882a593Smuzhiyun 3394*4882a593Smuzhiyun my $cherry = $patchcheck_cherry; 3395*4882a593Smuzhiyun if (!defined($cherry)) { 3396*4882a593Smuzhiyun $cherry = 0; 3397*4882a593Smuzhiyun } 3398*4882a593Smuzhiyun 3399*4882a593Smuzhiyun my $end = "HEAD"; 3400*4882a593Smuzhiyun if (defined($patchcheck_end)) { 3401*4882a593Smuzhiyun $end = $patchcheck_end; 3402*4882a593Smuzhiyun } elsif ($cherry) { 3403*4882a593Smuzhiyun dodie "PATCHCHECK_END must be defined with PATCHCHECK_CHERRY\n"; 3404*4882a593Smuzhiyun } 3405*4882a593Smuzhiyun 3406*4882a593Smuzhiyun # Get the true sha1's since we can use things like HEAD~3 3407*4882a593Smuzhiyun $start = get_sha1($start); 3408*4882a593Smuzhiyun $end = get_sha1($end); 3409*4882a593Smuzhiyun 3410*4882a593Smuzhiyun my $type = $patchcheck_type; 3411*4882a593Smuzhiyun 3412*4882a593Smuzhiyun # Can't have a test without having a test to run 3413*4882a593Smuzhiyun if ($type eq "test" && !defined($run_test)) { 3414*4882a593Smuzhiyun $type = "boot"; 3415*4882a593Smuzhiyun } 3416*4882a593Smuzhiyun 3417*4882a593Smuzhiyun if ($cherry) { 3418*4882a593Smuzhiyun open (IN, "git cherry -v $start $end|") or 3419*4882a593Smuzhiyun dodie "could not get git list"; 3420*4882a593Smuzhiyun } else { 3421*4882a593Smuzhiyun open (IN, "git log --pretty=oneline $end|") or 3422*4882a593Smuzhiyun dodie "could not get git list"; 3423*4882a593Smuzhiyun } 3424*4882a593Smuzhiyun 3425*4882a593Smuzhiyun my @list; 3426*4882a593Smuzhiyun 3427*4882a593Smuzhiyun while (<IN>) { 3428*4882a593Smuzhiyun chomp; 3429*4882a593Smuzhiyun # git cherry adds a '+' we want to remove 3430*4882a593Smuzhiyun s/^\+ //; 3431*4882a593Smuzhiyun $list[$#list+1] = $_; 3432*4882a593Smuzhiyun last if (/^$start/); 3433*4882a593Smuzhiyun } 3434*4882a593Smuzhiyun close(IN); 3435*4882a593Smuzhiyun 3436*4882a593Smuzhiyun if (!$cherry) { 3437*4882a593Smuzhiyun if ($list[$#list] !~ /^$start/) { 3438*4882a593Smuzhiyun fail "SHA1 $start not found"; 3439*4882a593Smuzhiyun } 3440*4882a593Smuzhiyun 3441*4882a593Smuzhiyun # go backwards in the list 3442*4882a593Smuzhiyun @list = reverse @list; 3443*4882a593Smuzhiyun } 3444*4882a593Smuzhiyun 3445*4882a593Smuzhiyun doprint("Going to test the following commits:\n"); 3446*4882a593Smuzhiyun foreach my $l (@list) { 3447*4882a593Smuzhiyun doprint "$l\n"; 3448*4882a593Smuzhiyun } 3449*4882a593Smuzhiyun 3450*4882a593Smuzhiyun my $save_clean = $noclean; 3451*4882a593Smuzhiyun my %ignored_warnings; 3452*4882a593Smuzhiyun 3453*4882a593Smuzhiyun if (defined($ignore_warnings)) { 3454*4882a593Smuzhiyun foreach my $sha1 (split /\s+/, $ignore_warnings) { 3455*4882a593Smuzhiyun $ignored_warnings{$sha1} = 1; 3456*4882a593Smuzhiyun } 3457*4882a593Smuzhiyun } 3458*4882a593Smuzhiyun 3459*4882a593Smuzhiyun $in_patchcheck = 1; 3460*4882a593Smuzhiyun foreach my $item (@list) { 3461*4882a593Smuzhiyun my $sha1 = $item; 3462*4882a593Smuzhiyun $sha1 =~ s/^([[:xdigit:]]+).*/$1/; 3463*4882a593Smuzhiyun 3464*4882a593Smuzhiyun doprint "\nProcessing commit \"$item\"\n\n"; 3465*4882a593Smuzhiyun 3466*4882a593Smuzhiyun run_command "git checkout $sha1" or 3467*4882a593Smuzhiyun dodie "Failed to checkout $sha1"; 3468*4882a593Smuzhiyun 3469*4882a593Smuzhiyun # only clean on the first and last patch 3470*4882a593Smuzhiyun if ($item eq $list[0] || 3471*4882a593Smuzhiyun $item eq $list[$#list]) { 3472*4882a593Smuzhiyun $noclean = $save_clean; 3473*4882a593Smuzhiyun } else { 3474*4882a593Smuzhiyun $noclean = 1; 3475*4882a593Smuzhiyun } 3476*4882a593Smuzhiyun 3477*4882a593Smuzhiyun if (defined($minconfig)) { 3478*4882a593Smuzhiyun build "useconfig:$minconfig" or return 0; 3479*4882a593Smuzhiyun } else { 3480*4882a593Smuzhiyun # ?? no config to use? 3481*4882a593Smuzhiyun build "oldconfig" or return 0; 3482*4882a593Smuzhiyun } 3483*4882a593Smuzhiyun 3484*4882a593Smuzhiyun # No need to do per patch checking if warnings file exists 3485*4882a593Smuzhiyun if (!defined($warnings_file) && !defined($ignored_warnings{$sha1})) { 3486*4882a593Smuzhiyun check_patch_buildlog $sha1 or return 0; 3487*4882a593Smuzhiyun } 3488*4882a593Smuzhiyun 3489*4882a593Smuzhiyun check_buildlog or return 0; 3490*4882a593Smuzhiyun 3491*4882a593Smuzhiyun next if ($type eq "build"); 3492*4882a593Smuzhiyun 3493*4882a593Smuzhiyun my $failed = 0; 3494*4882a593Smuzhiyun 3495*4882a593Smuzhiyun start_monitor_and_install or $failed = 1; 3496*4882a593Smuzhiyun 3497*4882a593Smuzhiyun if (!$failed && $type ne "boot"){ 3498*4882a593Smuzhiyun do_run_test or $failed = 1; 3499*4882a593Smuzhiyun } 3500*4882a593Smuzhiyun end_monitor; 3501*4882a593Smuzhiyun if ($failed) { 3502*4882a593Smuzhiyun print_times; 3503*4882a593Smuzhiyun return 0; 3504*4882a593Smuzhiyun } 3505*4882a593Smuzhiyun patchcheck_reboot; 3506*4882a593Smuzhiyun print_times; 3507*4882a593Smuzhiyun } 3508*4882a593Smuzhiyun $in_patchcheck = 0; 3509*4882a593Smuzhiyun success $i; 3510*4882a593Smuzhiyun 3511*4882a593Smuzhiyun return 1; 3512*4882a593Smuzhiyun} 3513*4882a593Smuzhiyun 3514*4882a593Smuzhiyunmy %depends; 3515*4882a593Smuzhiyunmy %depcount; 3516*4882a593Smuzhiyunmy $iflevel = 0; 3517*4882a593Smuzhiyunmy @ifdeps; 3518*4882a593Smuzhiyun 3519*4882a593Smuzhiyun# prevent recursion 3520*4882a593Smuzhiyunmy %read_kconfigs; 3521*4882a593Smuzhiyun 3522*4882a593Smuzhiyunsub add_dep { 3523*4882a593Smuzhiyun # $config depends on $dep 3524*4882a593Smuzhiyun my ($config, $dep) = @_; 3525*4882a593Smuzhiyun 3526*4882a593Smuzhiyun if (defined($depends{$config})) { 3527*4882a593Smuzhiyun $depends{$config} .= " " . $dep; 3528*4882a593Smuzhiyun } else { 3529*4882a593Smuzhiyun $depends{$config} = $dep; 3530*4882a593Smuzhiyun } 3531*4882a593Smuzhiyun 3532*4882a593Smuzhiyun # record the number of configs depending on $dep 3533*4882a593Smuzhiyun if (defined $depcount{$dep}) { 3534*4882a593Smuzhiyun $depcount{$dep}++; 3535*4882a593Smuzhiyun } else { 3536*4882a593Smuzhiyun $depcount{$dep} = 1; 3537*4882a593Smuzhiyun } 3538*4882a593Smuzhiyun} 3539*4882a593Smuzhiyun 3540*4882a593Smuzhiyun# taken from streamline_config.pl 3541*4882a593Smuzhiyunsub read_kconfig { 3542*4882a593Smuzhiyun my ($kconfig) = @_; 3543*4882a593Smuzhiyun 3544*4882a593Smuzhiyun my $state = "NONE"; 3545*4882a593Smuzhiyun my $config; 3546*4882a593Smuzhiyun my @kconfigs; 3547*4882a593Smuzhiyun 3548*4882a593Smuzhiyun my $cont = 0; 3549*4882a593Smuzhiyun my $line; 3550*4882a593Smuzhiyun 3551*4882a593Smuzhiyun 3552*4882a593Smuzhiyun if (! -f $kconfig) { 3553*4882a593Smuzhiyun doprint "file $kconfig does not exist, skipping\n"; 3554*4882a593Smuzhiyun return; 3555*4882a593Smuzhiyun } 3556*4882a593Smuzhiyun 3557*4882a593Smuzhiyun open(KIN, "$kconfig") 3558*4882a593Smuzhiyun or dodie "Can't open $kconfig"; 3559*4882a593Smuzhiyun while (<KIN>) { 3560*4882a593Smuzhiyun chomp; 3561*4882a593Smuzhiyun 3562*4882a593Smuzhiyun # Make sure that lines ending with \ continue 3563*4882a593Smuzhiyun if ($cont) { 3564*4882a593Smuzhiyun $_ = $line . " " . $_; 3565*4882a593Smuzhiyun } 3566*4882a593Smuzhiyun 3567*4882a593Smuzhiyun if (s/\\$//) { 3568*4882a593Smuzhiyun $cont = 1; 3569*4882a593Smuzhiyun $line = $_; 3570*4882a593Smuzhiyun next; 3571*4882a593Smuzhiyun } 3572*4882a593Smuzhiyun 3573*4882a593Smuzhiyun $cont = 0; 3574*4882a593Smuzhiyun 3575*4882a593Smuzhiyun # collect any Kconfig sources 3576*4882a593Smuzhiyun if (/^source\s*"(.*)"/) { 3577*4882a593Smuzhiyun $kconfigs[$#kconfigs+1] = $1; 3578*4882a593Smuzhiyun } 3579*4882a593Smuzhiyun 3580*4882a593Smuzhiyun # configs found 3581*4882a593Smuzhiyun if (/^\s*(menu)?config\s+(\S+)\s*$/) { 3582*4882a593Smuzhiyun $state = "NEW"; 3583*4882a593Smuzhiyun $config = $2; 3584*4882a593Smuzhiyun 3585*4882a593Smuzhiyun for (my $i = 0; $i < $iflevel; $i++) { 3586*4882a593Smuzhiyun add_dep $config, $ifdeps[$i]; 3587*4882a593Smuzhiyun } 3588*4882a593Smuzhiyun 3589*4882a593Smuzhiyun # collect the depends for the config 3590*4882a593Smuzhiyun } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) { 3591*4882a593Smuzhiyun 3592*4882a593Smuzhiyun add_dep $config, $1; 3593*4882a593Smuzhiyun 3594*4882a593Smuzhiyun # Get the configs that select this config 3595*4882a593Smuzhiyun } elsif ($state eq "NEW" && /^\s*select\s+(\S+)/) { 3596*4882a593Smuzhiyun 3597*4882a593Smuzhiyun # selected by depends on config 3598*4882a593Smuzhiyun add_dep $1, $config; 3599*4882a593Smuzhiyun 3600*4882a593Smuzhiyun # Check for if statements 3601*4882a593Smuzhiyun } elsif (/^if\s+(.*\S)\s*$/) { 3602*4882a593Smuzhiyun my $deps = $1; 3603*4882a593Smuzhiyun # remove beginning and ending non text 3604*4882a593Smuzhiyun $deps =~ s/^[^a-zA-Z0-9_]*//; 3605*4882a593Smuzhiyun $deps =~ s/[^a-zA-Z0-9_]*$//; 3606*4882a593Smuzhiyun 3607*4882a593Smuzhiyun my @deps = split /[^a-zA-Z0-9_]+/, $deps; 3608*4882a593Smuzhiyun 3609*4882a593Smuzhiyun $ifdeps[$iflevel++] = join ':', @deps; 3610*4882a593Smuzhiyun 3611*4882a593Smuzhiyun } elsif (/^endif/) { 3612*4882a593Smuzhiyun 3613*4882a593Smuzhiyun $iflevel-- if ($iflevel); 3614*4882a593Smuzhiyun 3615*4882a593Smuzhiyun # stop on "help" 3616*4882a593Smuzhiyun } elsif (/^\s*help\s*$/) { 3617*4882a593Smuzhiyun $state = "NONE"; 3618*4882a593Smuzhiyun } 3619*4882a593Smuzhiyun } 3620*4882a593Smuzhiyun close(KIN); 3621*4882a593Smuzhiyun 3622*4882a593Smuzhiyun # read in any configs that were found. 3623*4882a593Smuzhiyun foreach $kconfig (@kconfigs) { 3624*4882a593Smuzhiyun if (!defined($read_kconfigs{$kconfig})) { 3625*4882a593Smuzhiyun $read_kconfigs{$kconfig} = 1; 3626*4882a593Smuzhiyun read_kconfig("$builddir/$kconfig"); 3627*4882a593Smuzhiyun } 3628*4882a593Smuzhiyun } 3629*4882a593Smuzhiyun} 3630*4882a593Smuzhiyun 3631*4882a593Smuzhiyunsub read_depends { 3632*4882a593Smuzhiyun # find out which arch this is by the kconfig file 3633*4882a593Smuzhiyun open (IN, $output_config) 3634*4882a593Smuzhiyun or dodie "Failed to read $output_config"; 3635*4882a593Smuzhiyun my $arch; 3636*4882a593Smuzhiyun while (<IN>) { 3637*4882a593Smuzhiyun if (m,Linux/(\S+)\s+\S+\s+Kernel Configuration,) { 3638*4882a593Smuzhiyun $arch = $1; 3639*4882a593Smuzhiyun last; 3640*4882a593Smuzhiyun } 3641*4882a593Smuzhiyun } 3642*4882a593Smuzhiyun close IN; 3643*4882a593Smuzhiyun 3644*4882a593Smuzhiyun if (!defined($arch)) { 3645*4882a593Smuzhiyun doprint "Could not find arch from config file\n"; 3646*4882a593Smuzhiyun doprint "no dependencies used\n"; 3647*4882a593Smuzhiyun return; 3648*4882a593Smuzhiyun } 3649*4882a593Smuzhiyun 3650*4882a593Smuzhiyun # arch is really the subarch, we need to know 3651*4882a593Smuzhiyun # what directory to look at. 3652*4882a593Smuzhiyun if ($arch eq "i386" || $arch eq "x86_64") { 3653*4882a593Smuzhiyun $arch = "x86"; 3654*4882a593Smuzhiyun } 3655*4882a593Smuzhiyun 3656*4882a593Smuzhiyun my $kconfig = "$builddir/arch/$arch/Kconfig"; 3657*4882a593Smuzhiyun 3658*4882a593Smuzhiyun if (! -f $kconfig && $arch =~ /\d$/) { 3659*4882a593Smuzhiyun my $orig = $arch; 3660*4882a593Smuzhiyun # some subarchs have numbers, truncate them 3661*4882a593Smuzhiyun $arch =~ s/\d*$//; 3662*4882a593Smuzhiyun $kconfig = "$builddir/arch/$arch/Kconfig"; 3663*4882a593Smuzhiyun if (! -f $kconfig) { 3664*4882a593Smuzhiyun doprint "No idea what arch dir $orig is for\n"; 3665*4882a593Smuzhiyun doprint "no dependencies used\n"; 3666*4882a593Smuzhiyun return; 3667*4882a593Smuzhiyun } 3668*4882a593Smuzhiyun } 3669*4882a593Smuzhiyun 3670*4882a593Smuzhiyun read_kconfig($kconfig); 3671*4882a593Smuzhiyun} 3672*4882a593Smuzhiyun 3673*4882a593Smuzhiyunsub make_new_config { 3674*4882a593Smuzhiyun my @configs = @_; 3675*4882a593Smuzhiyun 3676*4882a593Smuzhiyun open (OUT, ">$output_config") 3677*4882a593Smuzhiyun or dodie "Failed to write $output_config"; 3678*4882a593Smuzhiyun 3679*4882a593Smuzhiyun foreach my $config (@configs) { 3680*4882a593Smuzhiyun print OUT "$config\n"; 3681*4882a593Smuzhiyun } 3682*4882a593Smuzhiyun close OUT; 3683*4882a593Smuzhiyun} 3684*4882a593Smuzhiyun 3685*4882a593Smuzhiyunsub chomp_config { 3686*4882a593Smuzhiyun my ($config) = @_; 3687*4882a593Smuzhiyun 3688*4882a593Smuzhiyun $config =~ s/CONFIG_//; 3689*4882a593Smuzhiyun 3690*4882a593Smuzhiyun return $config; 3691*4882a593Smuzhiyun} 3692*4882a593Smuzhiyun 3693*4882a593Smuzhiyunsub get_depends { 3694*4882a593Smuzhiyun my ($dep) = @_; 3695*4882a593Smuzhiyun 3696*4882a593Smuzhiyun my $kconfig = chomp_config $dep; 3697*4882a593Smuzhiyun 3698*4882a593Smuzhiyun $dep = $depends{"$kconfig"}; 3699*4882a593Smuzhiyun 3700*4882a593Smuzhiyun # the dep string we have saves the dependencies as they 3701*4882a593Smuzhiyun # were found, including expressions like ! && ||. We 3702*4882a593Smuzhiyun # want to split this out into just an array of configs. 3703*4882a593Smuzhiyun 3704*4882a593Smuzhiyun my $valid = "A-Za-z_0-9"; 3705*4882a593Smuzhiyun 3706*4882a593Smuzhiyun my @configs; 3707*4882a593Smuzhiyun 3708*4882a593Smuzhiyun while ($dep =~ /[$valid]/) { 3709*4882a593Smuzhiyun 3710*4882a593Smuzhiyun if ($dep =~ /^[^$valid]*([$valid]+)/) { 3711*4882a593Smuzhiyun my $conf = "CONFIG_" . $1; 3712*4882a593Smuzhiyun 3713*4882a593Smuzhiyun $configs[$#configs + 1] = $conf; 3714*4882a593Smuzhiyun 3715*4882a593Smuzhiyun $dep =~ s/^[^$valid]*[$valid]+//; 3716*4882a593Smuzhiyun } else { 3717*4882a593Smuzhiyun dodie "this should never happen"; 3718*4882a593Smuzhiyun } 3719*4882a593Smuzhiyun } 3720*4882a593Smuzhiyun 3721*4882a593Smuzhiyun return @configs; 3722*4882a593Smuzhiyun} 3723*4882a593Smuzhiyun 3724*4882a593Smuzhiyunmy %min_configs; 3725*4882a593Smuzhiyunmy %keep_configs; 3726*4882a593Smuzhiyunmy %save_configs; 3727*4882a593Smuzhiyunmy %processed_configs; 3728*4882a593Smuzhiyunmy %nochange_config; 3729*4882a593Smuzhiyun 3730*4882a593Smuzhiyunsub test_this_config { 3731*4882a593Smuzhiyun my ($config) = @_; 3732*4882a593Smuzhiyun 3733*4882a593Smuzhiyun my $found; 3734*4882a593Smuzhiyun 3735*4882a593Smuzhiyun # if we already processed this config, skip it 3736*4882a593Smuzhiyun if (defined($processed_configs{$config})) { 3737*4882a593Smuzhiyun return undef; 3738*4882a593Smuzhiyun } 3739*4882a593Smuzhiyun $processed_configs{$config} = 1; 3740*4882a593Smuzhiyun 3741*4882a593Smuzhiyun # if this config failed during this round, skip it 3742*4882a593Smuzhiyun if (defined($nochange_config{$config})) { 3743*4882a593Smuzhiyun return undef; 3744*4882a593Smuzhiyun } 3745*4882a593Smuzhiyun 3746*4882a593Smuzhiyun my $kconfig = chomp_config $config; 3747*4882a593Smuzhiyun 3748*4882a593Smuzhiyun # Test dependencies first 3749*4882a593Smuzhiyun if (defined($depends{"$kconfig"})) { 3750*4882a593Smuzhiyun my @parents = get_depends $config; 3751*4882a593Smuzhiyun foreach my $parent (@parents) { 3752*4882a593Smuzhiyun # if the parent is in the min config, check it first 3753*4882a593Smuzhiyun next if (!defined($min_configs{$parent})); 3754*4882a593Smuzhiyun $found = test_this_config($parent); 3755*4882a593Smuzhiyun if (defined($found)) { 3756*4882a593Smuzhiyun return $found; 3757*4882a593Smuzhiyun } 3758*4882a593Smuzhiyun } 3759*4882a593Smuzhiyun } 3760*4882a593Smuzhiyun 3761*4882a593Smuzhiyun # Remove this config from the list of configs 3762*4882a593Smuzhiyun # do a make olddefconfig and then read the resulting 3763*4882a593Smuzhiyun # .config to make sure it is missing the config that 3764*4882a593Smuzhiyun # we had before 3765*4882a593Smuzhiyun my %configs = %min_configs; 3766*4882a593Smuzhiyun delete $configs{$config}; 3767*4882a593Smuzhiyun make_new_config ((values %configs), (values %keep_configs)); 3768*4882a593Smuzhiyun make_oldconfig; 3769*4882a593Smuzhiyun undef %configs; 3770*4882a593Smuzhiyun assign_configs \%configs, $output_config; 3771*4882a593Smuzhiyun 3772*4882a593Smuzhiyun if (!defined($configs{$config}) || $configs{$config} =~ /^#/) { 3773*4882a593Smuzhiyun return $config; 3774*4882a593Smuzhiyun } 3775*4882a593Smuzhiyun 3776*4882a593Smuzhiyun doprint "disabling config $config did not change .config\n"; 3777*4882a593Smuzhiyun 3778*4882a593Smuzhiyun $nochange_config{$config} = 1; 3779*4882a593Smuzhiyun 3780*4882a593Smuzhiyun return undef; 3781*4882a593Smuzhiyun} 3782*4882a593Smuzhiyun 3783*4882a593Smuzhiyunsub make_min_config { 3784*4882a593Smuzhiyun my ($i) = @_; 3785*4882a593Smuzhiyun 3786*4882a593Smuzhiyun my $type = $minconfig_type; 3787*4882a593Smuzhiyun if ($type ne "boot" && $type ne "test") { 3788*4882a593Smuzhiyun fail "Invalid MIN_CONFIG_TYPE '$minconfig_type'\n" . 3789*4882a593Smuzhiyun " make_min_config works only with 'boot' and 'test'\n" and return; 3790*4882a593Smuzhiyun } 3791*4882a593Smuzhiyun 3792*4882a593Smuzhiyun if (!defined($output_minconfig)) { 3793*4882a593Smuzhiyun fail "OUTPUT_MIN_CONFIG not defined" and return; 3794*4882a593Smuzhiyun } 3795*4882a593Smuzhiyun 3796*4882a593Smuzhiyun # If output_minconfig exists, and the start_minconfig 3797*4882a593Smuzhiyun # came from min_config, than ask if we should use 3798*4882a593Smuzhiyun # that instead. 3799*4882a593Smuzhiyun if (-f $output_minconfig && !$start_minconfig_defined) { 3800*4882a593Smuzhiyun print "$output_minconfig exists\n"; 3801*4882a593Smuzhiyun if (!defined($use_output_minconfig)) { 3802*4882a593Smuzhiyun if (read_yn " Use it as minconfig?") { 3803*4882a593Smuzhiyun $start_minconfig = $output_minconfig; 3804*4882a593Smuzhiyun } 3805*4882a593Smuzhiyun } elsif ($use_output_minconfig > 0) { 3806*4882a593Smuzhiyun doprint "Using $output_minconfig as MIN_CONFIG\n"; 3807*4882a593Smuzhiyun $start_minconfig = $output_minconfig; 3808*4882a593Smuzhiyun } else { 3809*4882a593Smuzhiyun doprint "Set to still use MIN_CONFIG as starting point\n"; 3810*4882a593Smuzhiyun } 3811*4882a593Smuzhiyun } 3812*4882a593Smuzhiyun 3813*4882a593Smuzhiyun if (!defined($start_minconfig)) { 3814*4882a593Smuzhiyun fail "START_MIN_CONFIG or MIN_CONFIG not defined" and return; 3815*4882a593Smuzhiyun } 3816*4882a593Smuzhiyun 3817*4882a593Smuzhiyun my $temp_config = "$tmpdir/temp_config"; 3818*4882a593Smuzhiyun 3819*4882a593Smuzhiyun # First things first. We build an allnoconfig to find 3820*4882a593Smuzhiyun # out what the defaults are that we can't touch. 3821*4882a593Smuzhiyun # Some are selections, but we really can't handle selections. 3822*4882a593Smuzhiyun 3823*4882a593Smuzhiyun my $save_minconfig = $minconfig; 3824*4882a593Smuzhiyun undef $minconfig; 3825*4882a593Smuzhiyun 3826*4882a593Smuzhiyun run_command "$make allnoconfig" or return 0; 3827*4882a593Smuzhiyun 3828*4882a593Smuzhiyun read_depends; 3829*4882a593Smuzhiyun 3830*4882a593Smuzhiyun process_config_ignore $output_config; 3831*4882a593Smuzhiyun 3832*4882a593Smuzhiyun undef %save_configs; 3833*4882a593Smuzhiyun undef %min_configs; 3834*4882a593Smuzhiyun 3835*4882a593Smuzhiyun if (defined($ignore_config)) { 3836*4882a593Smuzhiyun # make sure the file exists 3837*4882a593Smuzhiyun `touch $ignore_config`; 3838*4882a593Smuzhiyun assign_configs \%save_configs, $ignore_config; 3839*4882a593Smuzhiyun } 3840*4882a593Smuzhiyun 3841*4882a593Smuzhiyun %keep_configs = %save_configs; 3842*4882a593Smuzhiyun 3843*4882a593Smuzhiyun doprint "Load initial configs from $start_minconfig\n"; 3844*4882a593Smuzhiyun 3845*4882a593Smuzhiyun # Look at the current min configs, and save off all the 3846*4882a593Smuzhiyun # ones that were set via the allnoconfig 3847*4882a593Smuzhiyun assign_configs \%min_configs, $start_minconfig; 3848*4882a593Smuzhiyun 3849*4882a593Smuzhiyun my @config_keys = keys %min_configs; 3850*4882a593Smuzhiyun 3851*4882a593Smuzhiyun # All configs need a depcount 3852*4882a593Smuzhiyun foreach my $config (@config_keys) { 3853*4882a593Smuzhiyun my $kconfig = chomp_config $config; 3854*4882a593Smuzhiyun if (!defined $depcount{$kconfig}) { 3855*4882a593Smuzhiyun $depcount{$kconfig} = 0; 3856*4882a593Smuzhiyun } 3857*4882a593Smuzhiyun } 3858*4882a593Smuzhiyun 3859*4882a593Smuzhiyun # Remove anything that was set by the make allnoconfig 3860*4882a593Smuzhiyun # we shouldn't need them as they get set for us anyway. 3861*4882a593Smuzhiyun foreach my $config (@config_keys) { 3862*4882a593Smuzhiyun # Remove anything in the ignore_config 3863*4882a593Smuzhiyun if (defined($keep_configs{$config})) { 3864*4882a593Smuzhiyun my $file = $ignore_config; 3865*4882a593Smuzhiyun $file =~ s,.*/(.*?)$,$1,; 3866*4882a593Smuzhiyun doprint "$config set by $file ... ignored\n"; 3867*4882a593Smuzhiyun delete $min_configs{$config}; 3868*4882a593Smuzhiyun next; 3869*4882a593Smuzhiyun } 3870*4882a593Smuzhiyun # But make sure the settings are the same. If a min config 3871*4882a593Smuzhiyun # sets a selection, we do not want to get rid of it if 3872*4882a593Smuzhiyun # it is not the same as what we have. Just move it into 3873*4882a593Smuzhiyun # the keep configs. 3874*4882a593Smuzhiyun if (defined($config_ignore{$config})) { 3875*4882a593Smuzhiyun if ($config_ignore{$config} ne $min_configs{$config}) { 3876*4882a593Smuzhiyun doprint "$config is in allnoconfig as '$config_ignore{$config}'"; 3877*4882a593Smuzhiyun doprint " but it is '$min_configs{$config}' in minconfig .. keeping\n"; 3878*4882a593Smuzhiyun $keep_configs{$config} = $min_configs{$config}; 3879*4882a593Smuzhiyun } else { 3880*4882a593Smuzhiyun doprint "$config set by allnoconfig ... ignored\n"; 3881*4882a593Smuzhiyun } 3882*4882a593Smuzhiyun delete $min_configs{$config}; 3883*4882a593Smuzhiyun } 3884*4882a593Smuzhiyun } 3885*4882a593Smuzhiyun 3886*4882a593Smuzhiyun my $done = 0; 3887*4882a593Smuzhiyun my $take_two = 0; 3888*4882a593Smuzhiyun 3889*4882a593Smuzhiyun while (!$done) { 3890*4882a593Smuzhiyun 3891*4882a593Smuzhiyun my $config; 3892*4882a593Smuzhiyun my $found; 3893*4882a593Smuzhiyun 3894*4882a593Smuzhiyun # Now disable each config one by one and do a make oldconfig 3895*4882a593Smuzhiyun # till we find a config that changes our list. 3896*4882a593Smuzhiyun 3897*4882a593Smuzhiyun my @test_configs = keys %min_configs; 3898*4882a593Smuzhiyun 3899*4882a593Smuzhiyun # Sort keys by who is most dependent on 3900*4882a593Smuzhiyun @test_configs = sort { $depcount{chomp_config($b)} <=> $depcount{chomp_config($a)} } 3901*4882a593Smuzhiyun @test_configs ; 3902*4882a593Smuzhiyun 3903*4882a593Smuzhiyun # Put configs that did not modify the config at the end. 3904*4882a593Smuzhiyun my $reset = 1; 3905*4882a593Smuzhiyun for (my $i = 0; $i < $#test_configs; $i++) { 3906*4882a593Smuzhiyun if (!defined($nochange_config{$test_configs[0]})) { 3907*4882a593Smuzhiyun $reset = 0; 3908*4882a593Smuzhiyun last; 3909*4882a593Smuzhiyun } 3910*4882a593Smuzhiyun # This config didn't change the .config last time. 3911*4882a593Smuzhiyun # Place it at the end 3912*4882a593Smuzhiyun my $config = shift @test_configs; 3913*4882a593Smuzhiyun push @test_configs, $config; 3914*4882a593Smuzhiyun } 3915*4882a593Smuzhiyun 3916*4882a593Smuzhiyun # if every test config has failed to modify the .config file 3917*4882a593Smuzhiyun # in the past, then reset and start over. 3918*4882a593Smuzhiyun if ($reset) { 3919*4882a593Smuzhiyun undef %nochange_config; 3920*4882a593Smuzhiyun } 3921*4882a593Smuzhiyun 3922*4882a593Smuzhiyun undef %processed_configs; 3923*4882a593Smuzhiyun 3924*4882a593Smuzhiyun foreach my $config (@test_configs) { 3925*4882a593Smuzhiyun 3926*4882a593Smuzhiyun $found = test_this_config $config; 3927*4882a593Smuzhiyun 3928*4882a593Smuzhiyun last if (defined($found)); 3929*4882a593Smuzhiyun 3930*4882a593Smuzhiyun # oh well, try another config 3931*4882a593Smuzhiyun } 3932*4882a593Smuzhiyun 3933*4882a593Smuzhiyun if (!defined($found)) { 3934*4882a593Smuzhiyun # we could have failed due to the nochange_config hash 3935*4882a593Smuzhiyun # reset and try again 3936*4882a593Smuzhiyun if (!$take_two) { 3937*4882a593Smuzhiyun undef %nochange_config; 3938*4882a593Smuzhiyun $take_two = 1; 3939*4882a593Smuzhiyun next; 3940*4882a593Smuzhiyun } 3941*4882a593Smuzhiyun doprint "No more configs found that we can disable\n"; 3942*4882a593Smuzhiyun $done = 1; 3943*4882a593Smuzhiyun last; 3944*4882a593Smuzhiyun } 3945*4882a593Smuzhiyun $take_two = 0; 3946*4882a593Smuzhiyun 3947*4882a593Smuzhiyun $config = $found; 3948*4882a593Smuzhiyun 3949*4882a593Smuzhiyun doprint "Test with $config disabled\n"; 3950*4882a593Smuzhiyun 3951*4882a593Smuzhiyun # set in_bisect to keep build and monitor from dieing 3952*4882a593Smuzhiyun $in_bisect = 1; 3953*4882a593Smuzhiyun 3954*4882a593Smuzhiyun my $failed = 0; 3955*4882a593Smuzhiyun build "oldconfig" or $failed = 1; 3956*4882a593Smuzhiyun if (!$failed) { 3957*4882a593Smuzhiyun start_monitor_and_install or $failed = 1; 3958*4882a593Smuzhiyun 3959*4882a593Smuzhiyun if ($type eq "test" && !$failed) { 3960*4882a593Smuzhiyun do_run_test or $failed = 1; 3961*4882a593Smuzhiyun } 3962*4882a593Smuzhiyun 3963*4882a593Smuzhiyun end_monitor; 3964*4882a593Smuzhiyun } 3965*4882a593Smuzhiyun 3966*4882a593Smuzhiyun $in_bisect = 0; 3967*4882a593Smuzhiyun 3968*4882a593Smuzhiyun if ($failed) { 3969*4882a593Smuzhiyun doprint "$min_configs{$config} is needed to boot the box... keeping\n"; 3970*4882a593Smuzhiyun # this config is needed, add it to the ignore list. 3971*4882a593Smuzhiyun $keep_configs{$config} = $min_configs{$config}; 3972*4882a593Smuzhiyun $save_configs{$config} = $min_configs{$config}; 3973*4882a593Smuzhiyun delete $min_configs{$config}; 3974*4882a593Smuzhiyun 3975*4882a593Smuzhiyun # update new ignore configs 3976*4882a593Smuzhiyun if (defined($ignore_config)) { 3977*4882a593Smuzhiyun open (OUT, ">$temp_config") 3978*4882a593Smuzhiyun or dodie "Can't write to $temp_config"; 3979*4882a593Smuzhiyun foreach my $config (keys %save_configs) { 3980*4882a593Smuzhiyun print OUT "$save_configs{$config}\n"; 3981*4882a593Smuzhiyun } 3982*4882a593Smuzhiyun close OUT; 3983*4882a593Smuzhiyun run_command "mv $temp_config $ignore_config" or 3984*4882a593Smuzhiyun dodie "failed to copy update to $ignore_config"; 3985*4882a593Smuzhiyun } 3986*4882a593Smuzhiyun 3987*4882a593Smuzhiyun } else { 3988*4882a593Smuzhiyun # We booted without this config, remove it from the minconfigs. 3989*4882a593Smuzhiyun doprint "$config is not needed, disabling\n"; 3990*4882a593Smuzhiyun 3991*4882a593Smuzhiyun delete $min_configs{$config}; 3992*4882a593Smuzhiyun 3993*4882a593Smuzhiyun # Also disable anything that is not enabled in this config 3994*4882a593Smuzhiyun my %configs; 3995*4882a593Smuzhiyun assign_configs \%configs, $output_config; 3996*4882a593Smuzhiyun my @config_keys = keys %min_configs; 3997*4882a593Smuzhiyun foreach my $config (@config_keys) { 3998*4882a593Smuzhiyun if (!defined($configs{$config})) { 3999*4882a593Smuzhiyun doprint "$config is not set, disabling\n"; 4000*4882a593Smuzhiyun delete $min_configs{$config}; 4001*4882a593Smuzhiyun } 4002*4882a593Smuzhiyun } 4003*4882a593Smuzhiyun 4004*4882a593Smuzhiyun # Save off all the current mandatory configs 4005*4882a593Smuzhiyun open (OUT, ">$temp_config") 4006*4882a593Smuzhiyun or dodie "Can't write to $temp_config"; 4007*4882a593Smuzhiyun foreach my $config (keys %keep_configs) { 4008*4882a593Smuzhiyun print OUT "$keep_configs{$config}\n"; 4009*4882a593Smuzhiyun } 4010*4882a593Smuzhiyun foreach my $config (keys %min_configs) { 4011*4882a593Smuzhiyun print OUT "$min_configs{$config}\n"; 4012*4882a593Smuzhiyun } 4013*4882a593Smuzhiyun close OUT; 4014*4882a593Smuzhiyun 4015*4882a593Smuzhiyun run_command "mv $temp_config $output_minconfig" or 4016*4882a593Smuzhiyun dodie "failed to copy update to $output_minconfig"; 4017*4882a593Smuzhiyun } 4018*4882a593Smuzhiyun 4019*4882a593Smuzhiyun doprint "Reboot and wait $sleep_time seconds\n"; 4020*4882a593Smuzhiyun reboot_to_good $sleep_time; 4021*4882a593Smuzhiyun } 4022*4882a593Smuzhiyun 4023*4882a593Smuzhiyun success $i; 4024*4882a593Smuzhiyun return 1; 4025*4882a593Smuzhiyun} 4026*4882a593Smuzhiyun 4027*4882a593Smuzhiyunsub make_warnings_file { 4028*4882a593Smuzhiyun my ($i) = @_; 4029*4882a593Smuzhiyun 4030*4882a593Smuzhiyun if (!defined($warnings_file)) { 4031*4882a593Smuzhiyun dodie "Must define WARNINGS_FILE for make_warnings_file test"; 4032*4882a593Smuzhiyun } 4033*4882a593Smuzhiyun 4034*4882a593Smuzhiyun if ($build_type eq "nobuild") { 4035*4882a593Smuzhiyun dodie "BUILD_TYPE can not be 'nobuild' for make_warnings_file test"; 4036*4882a593Smuzhiyun } 4037*4882a593Smuzhiyun 4038*4882a593Smuzhiyun build $build_type or dodie "Failed to build"; 4039*4882a593Smuzhiyun 4040*4882a593Smuzhiyun open(OUT, ">$warnings_file") or dodie "Can't create $warnings_file"; 4041*4882a593Smuzhiyun 4042*4882a593Smuzhiyun open(IN, $buildlog) or dodie "Can't open $buildlog"; 4043*4882a593Smuzhiyun while (<IN>) { 4044*4882a593Smuzhiyun 4045*4882a593Smuzhiyun # Some compilers use UTF-8 extended for quotes 4046*4882a593Smuzhiyun # for distcc heterogeneous systems, this causes issues 4047*4882a593Smuzhiyun s/$utf8_quote/'/g; 4048*4882a593Smuzhiyun 4049*4882a593Smuzhiyun if (/$check_build_re/) { 4050*4882a593Smuzhiyun print OUT; 4051*4882a593Smuzhiyun } 4052*4882a593Smuzhiyun } 4053*4882a593Smuzhiyun close(IN); 4054*4882a593Smuzhiyun 4055*4882a593Smuzhiyun close(OUT); 4056*4882a593Smuzhiyun 4057*4882a593Smuzhiyun success $i; 4058*4882a593Smuzhiyun} 4059*4882a593Smuzhiyun 4060*4882a593Smuzhiyun$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl [config-file]\n"; 4061*4882a593Smuzhiyun 4062*4882a593Smuzhiyunif ($#ARGV == 0) { 4063*4882a593Smuzhiyun $ktest_config = $ARGV[0]; 4064*4882a593Smuzhiyun if (! -f $ktest_config) { 4065*4882a593Smuzhiyun print "$ktest_config does not exist.\n"; 4066*4882a593Smuzhiyun if (!read_yn "Create it?") { 4067*4882a593Smuzhiyun exit 0; 4068*4882a593Smuzhiyun } 4069*4882a593Smuzhiyun } 4070*4882a593Smuzhiyun} 4071*4882a593Smuzhiyun 4072*4882a593Smuzhiyunif (! -f $ktest_config) { 4073*4882a593Smuzhiyun $newconfig = 1; 4074*4882a593Smuzhiyun get_test_case; 4075*4882a593Smuzhiyun open(OUT, ">$ktest_config") or die "Can not create $ktest_config"; 4076*4882a593Smuzhiyun print OUT << "EOF" 4077*4882a593Smuzhiyun# Generated by ktest.pl 4078*4882a593Smuzhiyun# 4079*4882a593Smuzhiyun 4080*4882a593Smuzhiyun# PWD is a ktest.pl variable that will result in the process working 4081*4882a593Smuzhiyun# directory that ktest.pl is executed in. 4082*4882a593Smuzhiyun 4083*4882a593Smuzhiyun# THIS_DIR is automatically assigned the PWD of the path that generated 4084*4882a593Smuzhiyun# the config file. It is best to use this variable when assigning other 4085*4882a593Smuzhiyun# directory paths within this directory. This allows you to easily 4086*4882a593Smuzhiyun# move the test cases to other locations or to other machines. 4087*4882a593Smuzhiyun# 4088*4882a593SmuzhiyunTHIS_DIR := $variable{"PWD"} 4089*4882a593Smuzhiyun 4090*4882a593Smuzhiyun# Define each test with TEST_START 4091*4882a593Smuzhiyun# The config options below it will override the defaults 4092*4882a593SmuzhiyunTEST_START 4093*4882a593SmuzhiyunTEST_TYPE = $default{"TEST_TYPE"} 4094*4882a593Smuzhiyun 4095*4882a593SmuzhiyunDEFAULTS 4096*4882a593SmuzhiyunEOF 4097*4882a593Smuzhiyun; 4098*4882a593Smuzhiyun close(OUT); 4099*4882a593Smuzhiyun} 4100*4882a593Smuzhiyunread_config $ktest_config; 4101*4882a593Smuzhiyun 4102*4882a593Smuzhiyunif (defined($opt{"LOG_FILE"})) { 4103*4882a593Smuzhiyun $opt{"LOG_FILE"} = eval_option("LOG_FILE", $opt{"LOG_FILE"}, -1); 4104*4882a593Smuzhiyun} 4105*4882a593Smuzhiyun 4106*4882a593Smuzhiyun# Append any configs entered in manually to the config file. 4107*4882a593Smuzhiyunmy @new_configs = keys %entered_configs; 4108*4882a593Smuzhiyunif ($#new_configs >= 0) { 4109*4882a593Smuzhiyun print "\nAppending entered in configs to $ktest_config\n"; 4110*4882a593Smuzhiyun open(OUT, ">>$ktest_config") or die "Can not append to $ktest_config"; 4111*4882a593Smuzhiyun foreach my $config (@new_configs) { 4112*4882a593Smuzhiyun print OUT "$config = $entered_configs{$config}\n"; 4113*4882a593Smuzhiyun $opt{$config} = process_variables($entered_configs{$config}); 4114*4882a593Smuzhiyun } 4115*4882a593Smuzhiyun} 4116*4882a593Smuzhiyun 4117*4882a593Smuzhiyunif (defined($opt{"LOG_FILE"})) { 4118*4882a593Smuzhiyun if ($opt{"CLEAR_LOG"}) { 4119*4882a593Smuzhiyun unlink $opt{"LOG_FILE"}; 4120*4882a593Smuzhiyun } 4121*4882a593Smuzhiyun open(LOG, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}"; 4122*4882a593Smuzhiyun LOG->autoflush(1); 4123*4882a593Smuzhiyun} 4124*4882a593Smuzhiyun 4125*4882a593Smuzhiyundoprint "\n\nSTARTING AUTOMATED TESTS\n\n"; 4126*4882a593Smuzhiyun 4127*4882a593Smuzhiyunfor (my $i = 0, my $repeat = 1; $i <= $opt{"NUM_TESTS"}; $i += $repeat) { 4128*4882a593Smuzhiyun 4129*4882a593Smuzhiyun if (!$i) { 4130*4882a593Smuzhiyun doprint "DEFAULT OPTIONS:\n"; 4131*4882a593Smuzhiyun } else { 4132*4882a593Smuzhiyun doprint "\nTEST $i OPTIONS"; 4133*4882a593Smuzhiyun if (defined($repeat_tests{$i})) { 4134*4882a593Smuzhiyun $repeat = $repeat_tests{$i}; 4135*4882a593Smuzhiyun doprint " ITERATE $repeat"; 4136*4882a593Smuzhiyun } 4137*4882a593Smuzhiyun doprint "\n"; 4138*4882a593Smuzhiyun } 4139*4882a593Smuzhiyun 4140*4882a593Smuzhiyun foreach my $option (sort keys %opt) { 4141*4882a593Smuzhiyun 4142*4882a593Smuzhiyun if ($option =~ /\[(\d+)\]$/) { 4143*4882a593Smuzhiyun next if ($i != $1); 4144*4882a593Smuzhiyun } else { 4145*4882a593Smuzhiyun next if ($i); 4146*4882a593Smuzhiyun } 4147*4882a593Smuzhiyun 4148*4882a593Smuzhiyun doprint "$option = $opt{$option}\n"; 4149*4882a593Smuzhiyun } 4150*4882a593Smuzhiyun} 4151*4882a593Smuzhiyun 4152*4882a593Smuzhiyunsub option_defined { 4153*4882a593Smuzhiyun my ($option) = @_; 4154*4882a593Smuzhiyun 4155*4882a593Smuzhiyun if (defined($opt{$option}) && $opt{$option} !~ /^\s*$/) { 4156*4882a593Smuzhiyun return 1; 4157*4882a593Smuzhiyun } 4158*4882a593Smuzhiyun 4159*4882a593Smuzhiyun return 0; 4160*4882a593Smuzhiyun} 4161*4882a593Smuzhiyun 4162*4882a593Smuzhiyunsub __set_test_option { 4163*4882a593Smuzhiyun my ($name, $i) = @_; 4164*4882a593Smuzhiyun 4165*4882a593Smuzhiyun my $option = "$name\[$i\]"; 4166*4882a593Smuzhiyun 4167*4882a593Smuzhiyun if (option_defined($option)) { 4168*4882a593Smuzhiyun return $opt{$option}; 4169*4882a593Smuzhiyun } 4170*4882a593Smuzhiyun 4171*4882a593Smuzhiyun foreach my $test (keys %repeat_tests) { 4172*4882a593Smuzhiyun if ($i >= $test && 4173*4882a593Smuzhiyun $i < $test + $repeat_tests{$test}) { 4174*4882a593Smuzhiyun $option = "$name\[$test\]"; 4175*4882a593Smuzhiyun if (option_defined($option)) { 4176*4882a593Smuzhiyun return $opt{$option}; 4177*4882a593Smuzhiyun } 4178*4882a593Smuzhiyun } 4179*4882a593Smuzhiyun } 4180*4882a593Smuzhiyun 4181*4882a593Smuzhiyun if (option_defined($name)) { 4182*4882a593Smuzhiyun return $opt{$name}; 4183*4882a593Smuzhiyun } 4184*4882a593Smuzhiyun 4185*4882a593Smuzhiyun return undef; 4186*4882a593Smuzhiyun} 4187*4882a593Smuzhiyun 4188*4882a593Smuzhiyunsub set_test_option { 4189*4882a593Smuzhiyun my ($name, $i) = @_; 4190*4882a593Smuzhiyun 4191*4882a593Smuzhiyun my $option = __set_test_option($name, $i); 4192*4882a593Smuzhiyun return $option if (!defined($option)); 4193*4882a593Smuzhiyun 4194*4882a593Smuzhiyun return eval_option($name, $option, $i); 4195*4882a593Smuzhiyun} 4196*4882a593Smuzhiyun 4197*4882a593Smuzhiyunsub find_mailer { 4198*4882a593Smuzhiyun my ($mailer) = @_; 4199*4882a593Smuzhiyun 4200*4882a593Smuzhiyun my @paths = split /:/, $ENV{PATH}; 4201*4882a593Smuzhiyun 4202*4882a593Smuzhiyun # sendmail is usually in /usr/sbin 4203*4882a593Smuzhiyun $paths[$#paths + 1] = "/usr/sbin"; 4204*4882a593Smuzhiyun 4205*4882a593Smuzhiyun foreach my $path (@paths) { 4206*4882a593Smuzhiyun if (-x "$path/$mailer") { 4207*4882a593Smuzhiyun return $path; 4208*4882a593Smuzhiyun } 4209*4882a593Smuzhiyun } 4210*4882a593Smuzhiyun 4211*4882a593Smuzhiyun return undef; 4212*4882a593Smuzhiyun} 4213*4882a593Smuzhiyun 4214*4882a593Smuzhiyunsub do_send_mail { 4215*4882a593Smuzhiyun my ($subject, $message, $file) = @_; 4216*4882a593Smuzhiyun 4217*4882a593Smuzhiyun if (!defined($mail_path)) { 4218*4882a593Smuzhiyun # find the mailer 4219*4882a593Smuzhiyun $mail_path = find_mailer $mailer; 4220*4882a593Smuzhiyun if (!defined($mail_path)) { 4221*4882a593Smuzhiyun die "\nCan not find $mailer in PATH\n"; 4222*4882a593Smuzhiyun } 4223*4882a593Smuzhiyun } 4224*4882a593Smuzhiyun 4225*4882a593Smuzhiyun my $header_file = "$tmpdir/header"; 4226*4882a593Smuzhiyun open (HEAD, ">$header_file") or die "Can not create $header_file\n"; 4227*4882a593Smuzhiyun print HEAD "To: $mailto\n"; 4228*4882a593Smuzhiyun print HEAD "Subject: $subject\n\n"; 4229*4882a593Smuzhiyun print HEAD "$message\n"; 4230*4882a593Smuzhiyun close HEAD; 4231*4882a593Smuzhiyun 4232*4882a593Smuzhiyun if (!defined($mail_command)) { 4233*4882a593Smuzhiyun if ($mailer eq "mail" || $mailer eq "mailx") { 4234*4882a593Smuzhiyun $mail_command = "cat \$HEADER_FILE \$BODY_FILE | \$MAIL_PATH/\$MAILER -s \'\$SUBJECT\' \$MAILTO"; 4235*4882a593Smuzhiyun } elsif ($mailer eq "sendmail" ) { 4236*4882a593Smuzhiyun $mail_command = "cat \$HEADER_FILE \$BODY_FILE | \$MAIL_PATH/\$MAILER -t \$MAILTO"; 4237*4882a593Smuzhiyun } else { 4238*4882a593Smuzhiyun die "\nYour mailer: $mailer is not supported.\n"; 4239*4882a593Smuzhiyun } 4240*4882a593Smuzhiyun } 4241*4882a593Smuzhiyun 4242*4882a593Smuzhiyun if (defined($file)) { 4243*4882a593Smuzhiyun $mail_command =~ s/\$BODY_FILE/$file/g; 4244*4882a593Smuzhiyun } else { 4245*4882a593Smuzhiyun $mail_command =~ s/\$BODY_FILE//g; 4246*4882a593Smuzhiyun } 4247*4882a593Smuzhiyun 4248*4882a593Smuzhiyun $mail_command =~ s/\$HEADER_FILE/$header_file/g; 4249*4882a593Smuzhiyun $mail_command =~ s/\$MAILER/$mailer/g; 4250*4882a593Smuzhiyun $mail_command =~ s/\$MAIL_PATH/$mail_path/g; 4251*4882a593Smuzhiyun $mail_command =~ s/\$MAILTO/$mailto/g; 4252*4882a593Smuzhiyun $mail_command =~ s/\$SUBJECT/$subject/g; 4253*4882a593Smuzhiyun $mail_command =~ s/\$MESSAGE/$message/g; 4254*4882a593Smuzhiyun 4255*4882a593Smuzhiyun my $ret = run_command $mail_command; 4256*4882a593Smuzhiyun if (!$ret && defined($file)) { 4257*4882a593Smuzhiyun # try again without the file 4258*4882a593Smuzhiyun $message .= "\n\n*** FAILED TO SEND LOG ***\n\n"; 4259*4882a593Smuzhiyun do_send_email($subject, $message); 4260*4882a593Smuzhiyun } 4261*4882a593Smuzhiyun} 4262*4882a593Smuzhiyun 4263*4882a593Smuzhiyunsub send_email { 4264*4882a593Smuzhiyun 4265*4882a593Smuzhiyun if (defined($mailto)) { 4266*4882a593Smuzhiyun if (!defined($mailer)) { 4267*4882a593Smuzhiyun doprint "No email sent: email or mailer not specified in config.\n"; 4268*4882a593Smuzhiyun return; 4269*4882a593Smuzhiyun } 4270*4882a593Smuzhiyun do_send_mail @_; 4271*4882a593Smuzhiyun } 4272*4882a593Smuzhiyun} 4273*4882a593Smuzhiyun 4274*4882a593Smuzhiyunsub cancel_test { 4275*4882a593Smuzhiyun if ($email_when_canceled) { 4276*4882a593Smuzhiyun my $name = get_test_name; 4277*4882a593Smuzhiyun send_email("KTEST: Your [$name] test was cancelled", 4278*4882a593Smuzhiyun "Your test started at $script_start_time was cancelled: sig int"); 4279*4882a593Smuzhiyun } 4280*4882a593Smuzhiyun die "\nCaught Sig Int, test interrupted: $!\n" 4281*4882a593Smuzhiyun} 4282*4882a593Smuzhiyun 4283*4882a593Smuzhiyun$SIG{INT} = qw(cancel_test); 4284*4882a593Smuzhiyun 4285*4882a593Smuzhiyun# First we need to do is the builds 4286*4882a593Smuzhiyunfor (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { 4287*4882a593Smuzhiyun 4288*4882a593Smuzhiyun # Do not reboot on failing test options 4289*4882a593Smuzhiyun $no_reboot = 1; 4290*4882a593Smuzhiyun $reboot_success = 0; 4291*4882a593Smuzhiyun 4292*4882a593Smuzhiyun $have_version = 0; 4293*4882a593Smuzhiyun 4294*4882a593Smuzhiyun $iteration = $i; 4295*4882a593Smuzhiyun 4296*4882a593Smuzhiyun $build_time = 0; 4297*4882a593Smuzhiyun $install_time = 0; 4298*4882a593Smuzhiyun $reboot_time = 0; 4299*4882a593Smuzhiyun $test_time = 0; 4300*4882a593Smuzhiyun 4301*4882a593Smuzhiyun undef %force_config; 4302*4882a593Smuzhiyun 4303*4882a593Smuzhiyun my $makecmd = set_test_option("MAKE_CMD", $i); 4304*4882a593Smuzhiyun 4305*4882a593Smuzhiyun $outputdir = set_test_option("OUTPUT_DIR", $i); 4306*4882a593Smuzhiyun $builddir = set_test_option("BUILD_DIR", $i); 4307*4882a593Smuzhiyun 4308*4882a593Smuzhiyun chdir $builddir || dodie "can't change directory to $builddir"; 4309*4882a593Smuzhiyun 4310*4882a593Smuzhiyun if (!-d $outputdir) { 4311*4882a593Smuzhiyun mkpath($outputdir) or 4312*4882a593Smuzhiyun dodie "can't create $outputdir"; 4313*4882a593Smuzhiyun } 4314*4882a593Smuzhiyun 4315*4882a593Smuzhiyun $make = "$makecmd O=$outputdir"; 4316*4882a593Smuzhiyun 4317*4882a593Smuzhiyun # Load all the options into their mapped variable names 4318*4882a593Smuzhiyun foreach my $opt (keys %option_map) { 4319*4882a593Smuzhiyun ${$option_map{$opt}} = set_test_option($opt, $i); 4320*4882a593Smuzhiyun } 4321*4882a593Smuzhiyun 4322*4882a593Smuzhiyun $start_minconfig_defined = 1; 4323*4882a593Smuzhiyun 4324*4882a593Smuzhiyun # The first test may override the PRE_KTEST option 4325*4882a593Smuzhiyun if ($i == 1) { 4326*4882a593Smuzhiyun if (defined($pre_ktest)) { 4327*4882a593Smuzhiyun doprint "\n"; 4328*4882a593Smuzhiyun run_command $pre_ktest; 4329*4882a593Smuzhiyun } 4330*4882a593Smuzhiyun if ($email_when_started) { 4331*4882a593Smuzhiyun my $name = get_test_name; 4332*4882a593Smuzhiyun send_email("KTEST: Your [$name] test was started", 4333*4882a593Smuzhiyun "Your test was started on $script_start_time"); 4334*4882a593Smuzhiyun } 4335*4882a593Smuzhiyun } 4336*4882a593Smuzhiyun 4337*4882a593Smuzhiyun # Any test can override the POST_KTEST option 4338*4882a593Smuzhiyun # The last test takes precedence. 4339*4882a593Smuzhiyun if (defined($post_ktest)) { 4340*4882a593Smuzhiyun $final_post_ktest = $post_ktest; 4341*4882a593Smuzhiyun } 4342*4882a593Smuzhiyun 4343*4882a593Smuzhiyun if (!defined($start_minconfig)) { 4344*4882a593Smuzhiyun $start_minconfig_defined = 0; 4345*4882a593Smuzhiyun $start_minconfig = $minconfig; 4346*4882a593Smuzhiyun } 4347*4882a593Smuzhiyun 4348*4882a593Smuzhiyun if (!-d $tmpdir) { 4349*4882a593Smuzhiyun mkpath($tmpdir) or 4350*4882a593Smuzhiyun dodie "can't create $tmpdir"; 4351*4882a593Smuzhiyun } 4352*4882a593Smuzhiyun 4353*4882a593Smuzhiyun $ENV{"SSH_USER"} = $ssh_user; 4354*4882a593Smuzhiyun $ENV{"MACHINE"} = $machine; 4355*4882a593Smuzhiyun 4356*4882a593Smuzhiyun $buildlog = "$tmpdir/buildlog-$machine"; 4357*4882a593Smuzhiyun $testlog = "$tmpdir/testlog-$machine"; 4358*4882a593Smuzhiyun $dmesg = "$tmpdir/dmesg-$machine"; 4359*4882a593Smuzhiyun $output_config = "$outputdir/.config"; 4360*4882a593Smuzhiyun 4361*4882a593Smuzhiyun if (!$buildonly) { 4362*4882a593Smuzhiyun $target = "$ssh_user\@$machine"; 4363*4882a593Smuzhiyun if (($reboot_type eq "grub") or ($reboot_type eq "grub2bls")) { 4364*4882a593Smuzhiyun dodie "GRUB_MENU not defined" if (!defined($grub_menu)); 4365*4882a593Smuzhiyun } elsif ($reboot_type eq "grub2") { 4366*4882a593Smuzhiyun dodie "GRUB_MENU not defined" if (!defined($grub_menu)); 4367*4882a593Smuzhiyun dodie "GRUB_FILE not defined" if (!defined($grub_file)); 4368*4882a593Smuzhiyun } elsif ($reboot_type eq "syslinux") { 4369*4882a593Smuzhiyun dodie "SYSLINUX_LABEL not defined" if (!defined($syslinux_label)); 4370*4882a593Smuzhiyun } 4371*4882a593Smuzhiyun } 4372*4882a593Smuzhiyun 4373*4882a593Smuzhiyun my $run_type = $build_type; 4374*4882a593Smuzhiyun if ($test_type eq "patchcheck") { 4375*4882a593Smuzhiyun $run_type = $patchcheck_type; 4376*4882a593Smuzhiyun } elsif ($test_type eq "bisect") { 4377*4882a593Smuzhiyun $run_type = $bisect_type; 4378*4882a593Smuzhiyun } elsif ($test_type eq "config_bisect") { 4379*4882a593Smuzhiyun $run_type = $config_bisect_type; 4380*4882a593Smuzhiyun } elsif ($test_type eq "make_min_config") { 4381*4882a593Smuzhiyun $run_type = ""; 4382*4882a593Smuzhiyun } elsif ($test_type eq "make_warnings_file") { 4383*4882a593Smuzhiyun $run_type = ""; 4384*4882a593Smuzhiyun } 4385*4882a593Smuzhiyun 4386*4882a593Smuzhiyun # mistake in config file? 4387*4882a593Smuzhiyun if (!defined($run_type)) { 4388*4882a593Smuzhiyun $run_type = "ERROR"; 4389*4882a593Smuzhiyun } 4390*4882a593Smuzhiyun 4391*4882a593Smuzhiyun my $installme = ""; 4392*4882a593Smuzhiyun $installme = " no_install" if ($no_install); 4393*4882a593Smuzhiyun 4394*4882a593Smuzhiyun my $name = ""; 4395*4882a593Smuzhiyun 4396*4882a593Smuzhiyun if (defined($test_name)) { 4397*4882a593Smuzhiyun $name = " ($test_name)"; 4398*4882a593Smuzhiyun } 4399*4882a593Smuzhiyun 4400*4882a593Smuzhiyun doprint "\n\n"; 4401*4882a593Smuzhiyun 4402*4882a593Smuzhiyun if (defined($opt{"LOG_FILE"})) { 4403*4882a593Smuzhiyun $test_log_start = tell(LOG); 4404*4882a593Smuzhiyun } 4405*4882a593Smuzhiyun 4406*4882a593Smuzhiyun doprint "RUNNING TEST $i of $opt{NUM_TESTS}$name with option $test_type $run_type$installme\n\n"; 4407*4882a593Smuzhiyun 4408*4882a593Smuzhiyun if (defined($pre_test)) { 4409*4882a593Smuzhiyun my $ret = run_command $pre_test; 4410*4882a593Smuzhiyun if (!$ret && defined($pre_test_die) && 4411*4882a593Smuzhiyun $pre_test_die) { 4412*4882a593Smuzhiyun dodie "failed to pre_test\n"; 4413*4882a593Smuzhiyun } 4414*4882a593Smuzhiyun } 4415*4882a593Smuzhiyun 4416*4882a593Smuzhiyun unlink $dmesg; 4417*4882a593Smuzhiyun unlink $buildlog; 4418*4882a593Smuzhiyun unlink $testlog; 4419*4882a593Smuzhiyun 4420*4882a593Smuzhiyun if (defined($addconfig)) { 4421*4882a593Smuzhiyun my $min = $minconfig; 4422*4882a593Smuzhiyun if (!defined($minconfig)) { 4423*4882a593Smuzhiyun $min = ""; 4424*4882a593Smuzhiyun } 4425*4882a593Smuzhiyun run_command "cat $addconfig $min > $tmpdir/add_config" or 4426*4882a593Smuzhiyun dodie "Failed to create temp config"; 4427*4882a593Smuzhiyun $minconfig = "$tmpdir/add_config"; 4428*4882a593Smuzhiyun } 4429*4882a593Smuzhiyun 4430*4882a593Smuzhiyun if (defined($checkout)) { 4431*4882a593Smuzhiyun run_command "git checkout $checkout" or 4432*4882a593Smuzhiyun dodie "failed to checkout $checkout"; 4433*4882a593Smuzhiyun } 4434*4882a593Smuzhiyun 4435*4882a593Smuzhiyun $no_reboot = 0; 4436*4882a593Smuzhiyun 4437*4882a593Smuzhiyun # A test may opt to not reboot the box 4438*4882a593Smuzhiyun if ($reboot_on_success) { 4439*4882a593Smuzhiyun $reboot_success = 1; 4440*4882a593Smuzhiyun } 4441*4882a593Smuzhiyun 4442*4882a593Smuzhiyun if ($test_type eq "bisect") { 4443*4882a593Smuzhiyun bisect $i; 4444*4882a593Smuzhiyun next; 4445*4882a593Smuzhiyun } elsif ($test_type eq "config_bisect") { 4446*4882a593Smuzhiyun config_bisect $i; 4447*4882a593Smuzhiyun next; 4448*4882a593Smuzhiyun } elsif ($test_type eq "patchcheck") { 4449*4882a593Smuzhiyun patchcheck $i; 4450*4882a593Smuzhiyun next; 4451*4882a593Smuzhiyun } elsif ($test_type eq "make_min_config") { 4452*4882a593Smuzhiyun make_min_config $i; 4453*4882a593Smuzhiyun next; 4454*4882a593Smuzhiyun } elsif ($test_type eq "make_warnings_file") { 4455*4882a593Smuzhiyun $no_reboot = 1; 4456*4882a593Smuzhiyun make_warnings_file $i; 4457*4882a593Smuzhiyun next; 4458*4882a593Smuzhiyun } 4459*4882a593Smuzhiyun 4460*4882a593Smuzhiyun if ($build_type ne "nobuild") { 4461*4882a593Smuzhiyun build $build_type or next; 4462*4882a593Smuzhiyun check_buildlog or next; 4463*4882a593Smuzhiyun } 4464*4882a593Smuzhiyun 4465*4882a593Smuzhiyun if ($test_type eq "install") { 4466*4882a593Smuzhiyun get_version; 4467*4882a593Smuzhiyun install; 4468*4882a593Smuzhiyun success $i; 4469*4882a593Smuzhiyun next; 4470*4882a593Smuzhiyun } 4471*4882a593Smuzhiyun 4472*4882a593Smuzhiyun if ($test_type ne "build") { 4473*4882a593Smuzhiyun my $failed = 0; 4474*4882a593Smuzhiyun start_monitor_and_install or $failed = 1; 4475*4882a593Smuzhiyun 4476*4882a593Smuzhiyun if (!$failed && $test_type ne "boot" && defined($run_test)) { 4477*4882a593Smuzhiyun do_run_test or $failed = 1; 4478*4882a593Smuzhiyun } 4479*4882a593Smuzhiyun end_monitor; 4480*4882a593Smuzhiyun if ($failed) { 4481*4882a593Smuzhiyun print_times; 4482*4882a593Smuzhiyun next; 4483*4882a593Smuzhiyun } 4484*4882a593Smuzhiyun } 4485*4882a593Smuzhiyun 4486*4882a593Smuzhiyun print_times; 4487*4882a593Smuzhiyun 4488*4882a593Smuzhiyun success $i; 4489*4882a593Smuzhiyun} 4490*4882a593Smuzhiyun 4491*4882a593Smuzhiyunif (defined($final_post_ktest)) { 4492*4882a593Smuzhiyun 4493*4882a593Smuzhiyun my $cp_final_post_ktest = eval_kernel_version $final_post_ktest; 4494*4882a593Smuzhiyun run_command $cp_final_post_ktest; 4495*4882a593Smuzhiyun} 4496*4882a593Smuzhiyun 4497*4882a593Smuzhiyunif ($opt{"POWEROFF_ON_SUCCESS"}) { 4498*4882a593Smuzhiyun halt; 4499*4882a593Smuzhiyun} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot && $reboot_success) { 4500*4882a593Smuzhiyun reboot_to_good; 4501*4882a593Smuzhiyun} elsif (defined($switch_to_good)) { 4502*4882a593Smuzhiyun # still need to get to the good kernel 4503*4882a593Smuzhiyun run_command $switch_to_good; 4504*4882a593Smuzhiyun} 4505*4882a593Smuzhiyun 4506*4882a593Smuzhiyun 4507*4882a593Smuzhiyundoprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n"; 4508*4882a593Smuzhiyun 4509*4882a593Smuzhiyunif ($email_when_finished) { 4510*4882a593Smuzhiyun send_email("KTEST: Your test has finished!", 4511*4882a593Smuzhiyun "$successes of $opt{NUM_TESTS} tests started at $script_start_time were successful!"); 4512*4882a593Smuzhiyun} 4513*4882a593Smuzhiyun 4514*4882a593Smuzhiyunif (defined($opt{"LOG_FILE"})) { 4515*4882a593Smuzhiyun print "\n See $opt{LOG_FILE} for the record of results.\n\n"; 4516*4882a593Smuzhiyun close LOG; 4517*4882a593Smuzhiyun} 4518*4882a593Smuzhiyun 4519*4882a593Smuzhiyunexit 0; 4520