xref: /OK3568_Linux_fs/kernel/tools/testing/ktest/ktest.pl (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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