xref: /openbmc/linux/tools/testing/ktest/ktest.pl (revision 5a391fbff8755592eb080784ef32ff818d2daa44)
12545eb61SSteven Rostedt#!/usr/bin/perl -w
22545eb61SSteven Rostedt
32545eb61SSteven Rostedtuse strict;
42545eb61SSteven Rostedtuse IPC::Open2;
52545eb61SSteven Rostedtuse Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
62545eb61SSteven Rostedtuse FileHandle;
72545eb61SSteven Rostedt
82545eb61SSteven Rostedt$#ARGV >= 0 || die "usage: autotest.pl config-file\n";
92545eb61SSteven Rostedt
102545eb61SSteven Rostedt$| = 1;
112545eb61SSteven Rostedt
122545eb61SSteven Rostedtmy %opt;
132545eb61SSteven Rostedt
142545eb61SSteven Rostedt#default opts
152545eb61SSteven Rostedt$opt{"NUM_BUILDS"}		= 5;
162545eb61SSteven Rostedt$opt{"DEFAULT_BUILD_TYPE"}	= "randconfig";
172545eb61SSteven Rostedt$opt{"MAKE_CMD"}		= "make";
182545eb61SSteven Rostedt$opt{"TIMEOUT"}			= 50;
192545eb61SSteven Rostedt$opt{"TMP_DIR"}			= "/tmp/autotest";
202545eb61SSteven Rostedt$opt{"SLEEP_TIME"}		= 60;	# sleep time between tests
215c42fc5bSSteven Rostedt$opt{"BUILD_NOCLEAN"}		= 0;
2275c3fda7SSteven Rostedt$opt{"REBOOT_ON_ERROR"}		= 0;
235c42fc5bSSteven Rostedt$opt{"POWEROFF_ON_ERROR"}	= 0;
245c42fc5bSSteven Rostedt$opt{"POWEROFF_ON_SUCCESS"}	= 0;
2575c3fda7SSteven Rostedt$opt{"BUILD_OPTIONS"}		= "";
26*5a391fbfSSteven Rostedt$opt{"BISECT_SLEEP_TIME"}	= 10;   # sleep time between bisects
272545eb61SSteven Rostedt
282545eb61SSteven Rostedtmy $version;
292545eb61SSteven Rostedtmy $grub_number;
302545eb61SSteven Rostedtmy $target;
312545eb61SSteven Rostedtmy $make;
325c42fc5bSSteven Rostedtmy $noclean;
335f9b6cedSSteven Rostedtmy $minconfig;
345f9b6cedSSteven Rostedtmy $in_bisect = 0;
355f9b6cedSSteven Rostedtmy $bisect_bad = "";
36*5a391fbfSSteven Rostedtmy $run_test;
372545eb61SSteven Rostedt
382545eb61SSteven Rostedtsub read_config {
392545eb61SSteven Rostedt    my ($config) = @_;
402545eb61SSteven Rostedt
412545eb61SSteven Rostedt    open(IN, $config) || die "can't read file $config";
422545eb61SSteven Rostedt
432545eb61SSteven Rostedt    while (<IN>) {
442545eb61SSteven Rostedt
452545eb61SSteven Rostedt	# ignore blank lines and comments
462545eb61SSteven Rostedt	next if (/^\s*$/ || /\s*\#/);
472545eb61SSteven Rostedt
482545eb61SSteven Rostedt	if (/^\s*(\S+)\s*=\s*(.*?)\s*$/) {
492545eb61SSteven Rostedt	    my $lvalue = $1;
502545eb61SSteven Rostedt	    my $rvalue = $2;
512545eb61SSteven Rostedt
522545eb61SSteven Rostedt	    $opt{$lvalue} = $rvalue;
532545eb61SSteven Rostedt	}
542545eb61SSteven Rostedt    }
552545eb61SSteven Rostedt
562545eb61SSteven Rostedt    close(IN);
572545eb61SSteven Rostedt}
582545eb61SSteven Rostedt
595f9b6cedSSteven Rostedtsub logit {
602545eb61SSteven Rostedt    if (defined($opt{"LOG_FILE"})) {
612545eb61SSteven Rostedt	open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
622545eb61SSteven Rostedt	print OUT @_;
632545eb61SSteven Rostedt	close(OUT);
642545eb61SSteven Rostedt    }
652545eb61SSteven Rostedt}
662545eb61SSteven Rostedt
675f9b6cedSSteven Rostedtsub doprint {
685f9b6cedSSteven Rostedt    print @_;
695f9b6cedSSteven Rostedt    logit @_;
705f9b6cedSSteven Rostedt}
715f9b6cedSSteven Rostedt
725c42fc5bSSteven Rostedtsub dodie {
73*5a391fbfSSteven Rostedt    doprint "CRITICAL FAILURE... ", @_, "\n";
745c42fc5bSSteven Rostedt
7575c3fda7SSteven Rostedt    if ($opt{"REBOOT_ON_ERROR"}) {
7675c3fda7SSteven Rostedt	doprint "REBOOTING\n";
7775c3fda7SSteven Rostedt	`$opt{"POWER_CYCLE"}`;
7875c3fda7SSteven Rostedt
7975c3fda7SSteven Rostedt    } elsif ($opt{"POWEROFF_ON_ERROR"} && defined($opt{"POWER_OFF"})) {
805c42fc5bSSteven Rostedt	doprint "POWERING OFF\n";
815c42fc5bSSteven Rostedt	`$opt{"POWER_OFF"}`;
825c42fc5bSSteven Rostedt    }
8375c3fda7SSteven Rostedt
845c42fc5bSSteven Rostedt    die @_;
855c42fc5bSSteven Rostedt}
865c42fc5bSSteven Rostedt
872545eb61SSteven Rostedtsub run_command {
882545eb61SSteven Rostedt    my ($command) = @_;
89*5a391fbfSSteven Rostedt    my $redirect_log = "";
902545eb61SSteven Rostedt
912545eb61SSteven Rostedt    if (defined($opt{"LOG_FILE"})) {
92*5a391fbfSSteven Rostedt	$redirect_log = " >> $opt{LOG_FILE} 2>&1";
932545eb61SSteven Rostedt    }
942545eb61SSteven Rostedt
952545eb61SSteven Rostedt    doprint "$command ... ";
96*5a391fbfSSteven Rostedt    `$command $redirect_log`;
972545eb61SSteven Rostedt
982545eb61SSteven Rostedt    my $failed = $?;
992545eb61SSteven Rostedt
1002545eb61SSteven Rostedt    if ($failed) {
1012545eb61SSteven Rostedt	doprint "FAILED!\n";
1022545eb61SSteven Rostedt    } else {
1032545eb61SSteven Rostedt	doprint "SUCCESS\n";
1042545eb61SSteven Rostedt    }
1052545eb61SSteven Rostedt
1065f9b6cedSSteven Rostedt    return !$failed;
1075f9b6cedSSteven Rostedt}
1085f9b6cedSSteven Rostedt
1095f9b6cedSSteven Rostedtsub get_grub_index {
1105f9b6cedSSteven Rostedt
111*5a391fbfSSteven Rostedt    return if (defined($grub_number));
1125f9b6cedSSteven Rostedt
1135f9b6cedSSteven Rostedt    doprint "Find grub menu ... ";
1145f9b6cedSSteven Rostedt    $grub_number = -1;
1155f9b6cedSSteven Rostedt    open(IN, "ssh $target cat /boot/grub/menu.lst |")
1165f9b6cedSSteven Rostedt	or die "unable to get menu.lst";
1175f9b6cedSSteven Rostedt    while (<IN>) {
1185f9b6cedSSteven Rostedt	if (/^\s*title\s+$opt{GRUB_MENU}\s*$/) {
1195f9b6cedSSteven Rostedt	    $grub_number++;
1205f9b6cedSSteven Rostedt	    last;
1215f9b6cedSSteven Rostedt	} elsif (/^\s*title\s/) {
1225f9b6cedSSteven Rostedt	    $grub_number++;
1235f9b6cedSSteven Rostedt	}
1245f9b6cedSSteven Rostedt    }
1255f9b6cedSSteven Rostedt    close(IN);
1265f9b6cedSSteven Rostedt
1275f9b6cedSSteven Rostedt    die "Could not find '$opt{GRUB_MENU}' in /boot/grub/menu on $opt{MACHINE}"
1285f9b6cedSSteven Rostedt	if ($grub_number < 0);
1295f9b6cedSSteven Rostedt    doprint "$grub_number\n";
1302545eb61SSteven Rostedt}
1312545eb61SSteven Rostedt
1322545eb61SSteven Rostedtmy $timeout = $opt{"TIMEOUT"};
1332545eb61SSteven Rostedt
1342545eb61SSteven Rostedtsub wait_for_input
1352545eb61SSteven Rostedt{
1362545eb61SSteven Rostedt    my ($fp, $time) = @_;
1372545eb61SSteven Rostedt    my $rin;
1382545eb61SSteven Rostedt    my $ready;
1392545eb61SSteven Rostedt    my $line;
1402545eb61SSteven Rostedt    my $ch;
1412545eb61SSteven Rostedt
1422545eb61SSteven Rostedt    if (!defined($time)) {
1432545eb61SSteven Rostedt	$time = $timeout;
1442545eb61SSteven Rostedt    }
1452545eb61SSteven Rostedt
1462545eb61SSteven Rostedt    $rin = '';
1472545eb61SSteven Rostedt    vec($rin, fileno($fp), 1) = 1;
1482545eb61SSteven Rostedt    $ready = select($rin, undef, undef, $time);
1492545eb61SSteven Rostedt
1502545eb61SSteven Rostedt    $line = "";
1512545eb61SSteven Rostedt
1522545eb61SSteven Rostedt    # try to read one char at a time
1532545eb61SSteven Rostedt    while (sysread $fp, $ch, 1) {
1542545eb61SSteven Rostedt	$line .= $ch;
1552545eb61SSteven Rostedt	last if ($ch eq "\n");
1562545eb61SSteven Rostedt    }
1572545eb61SSteven Rostedt
1582545eb61SSteven Rostedt    if (!length($line)) {
1592545eb61SSteven Rostedt	return undef;
1602545eb61SSteven Rostedt    }
1612545eb61SSteven Rostedt
1622545eb61SSteven Rostedt    return $line;
1632545eb61SSteven Rostedt}
1642545eb61SSteven Rostedt
16575c3fda7SSteven Rostedtsub reboot_to {
1662545eb61SSteven Rostedt    run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
1672545eb61SSteven Rostedt}
1682545eb61SSteven Rostedt
169*5a391fbfSSteven Rostedtsub open_console {
170*5a391fbfSSteven Rostedt    my ($fp) = @_;
171*5a391fbfSSteven Rostedt
1722545eb61SSteven Rostedt    my $flags;
173*5a391fbfSSteven Rostedt
174*5a391fbfSSteven Rostedt    my $pid = open($fp, "$opt{CONSOLE}|") or
175*5a391fbfSSteven Rostedt	dodie "Can't open console $opt{CONSOLE}";
176*5a391fbfSSteven Rostedt
177*5a391fbfSSteven Rostedt    $flags = fcntl($fp, F_GETFL, 0) or
178*5a391fbfSSteven Rostedt	dodie "Can't get flags for the socket: $!\n";
179*5a391fbfSSteven Rostedt    $flags = fcntl($fp, F_SETFL, $flags | O_NONBLOCK) or
180*5a391fbfSSteven Rostedt	dodie "Can't set flags for the socket: $!\n";
181*5a391fbfSSteven Rostedt
182*5a391fbfSSteven Rostedt    return $pid;
183*5a391fbfSSteven Rostedt}
184*5a391fbfSSteven Rostedt
185*5a391fbfSSteven Rostedtsub close_console {
186*5a391fbfSSteven Rostedt    my ($fp, $pid) = @_;
187*5a391fbfSSteven Rostedt
188*5a391fbfSSteven Rostedt    doprint "kill child process $pid\n";
189*5a391fbfSSteven Rostedt    kill 2, $pid;
190*5a391fbfSSteven Rostedt
191*5a391fbfSSteven Rostedt    print "closing!\n";
192*5a391fbfSSteven Rostedt    close($fp);
193*5a391fbfSSteven Rostedt}
194*5a391fbfSSteven Rostedt
195*5a391fbfSSteven Rostedtsub monitor {
1962545eb61SSteven Rostedt    my $booted = 0;
1972545eb61SSteven Rostedt    my $bug = 0;
1982545eb61SSteven Rostedt    my $pid;
1995c42fc5bSSteven Rostedt    my $skip_call_trace = 0;
200*5a391fbfSSteven Rostedt    my $fp = \*IN;
2012545eb61SSteven Rostedt
202*5a391fbfSSteven Rostedt    $pid = open_console($fp);
2032545eb61SSteven Rostedt
2042545eb61SSteven Rostedt    my $line;
2052545eb61SSteven Rostedt    my $full_line = "";
2062545eb61SSteven Rostedt
2072545eb61SSteven Rostedt    doprint "Wait for monitor to settle down.\n";
2082545eb61SSteven Rostedt    # read the monitor and wait for the system to calm down
2092545eb61SSteven Rostedt    do {
210*5a391fbfSSteven Rostedt	$line = wait_for_input($fp, 5);
2112545eb61SSteven Rostedt    } while (defined($line));
2122545eb61SSteven Rostedt
21375c3fda7SSteven Rostedt    reboot_to;
2142545eb61SSteven Rostedt
2152545eb61SSteven Rostedt    for (;;) {
2162545eb61SSteven Rostedt
217*5a391fbfSSteven Rostedt	$line = wait_for_input($fp);
2182545eb61SSteven Rostedt
2192545eb61SSteven Rostedt	last if (!defined($line));
2202545eb61SSteven Rostedt
2212545eb61SSteven Rostedt	doprint $line;
2222545eb61SSteven Rostedt
2232545eb61SSteven Rostedt	# we are not guaranteed to get a full line
2242545eb61SSteven Rostedt	$full_line .= $line;
2252545eb61SSteven Rostedt
2262545eb61SSteven Rostedt	if ($full_line =~ /login:/) {
2272545eb61SSteven Rostedt	    $booted = 1;
2282545eb61SSteven Rostedt	}
2292545eb61SSteven Rostedt
2305c42fc5bSSteven Rostedt	if ($full_line =~ /\[ backtrace testing \]/) {
2315c42fc5bSSteven Rostedt	    $skip_call_trace = 1;
2325c42fc5bSSteven Rostedt	}
2335c42fc5bSSteven Rostedt
2342545eb61SSteven Rostedt	if ($full_line =~ /call trace:/i) {
2355c42fc5bSSteven Rostedt	    $bug = 1 if (!$skip_call_trace);
2365c42fc5bSSteven Rostedt	}
2375c42fc5bSSteven Rostedt
2385c42fc5bSSteven Rostedt	if ($full_line =~ /\[ end of backtrace testing \]/) {
2395c42fc5bSSteven Rostedt	    $skip_call_trace = 0;
2405c42fc5bSSteven Rostedt	}
2415c42fc5bSSteven Rostedt
2425c42fc5bSSteven Rostedt	if ($full_line =~ /Kernel panic -/) {
2432545eb61SSteven Rostedt	    $bug = 1;
2442545eb61SSteven Rostedt	}
2452545eb61SSteven Rostedt
2462545eb61SSteven Rostedt	if ($line =~ /\n/) {
2472545eb61SSteven Rostedt	    $full_line = "";
2482545eb61SSteven Rostedt	}
2492545eb61SSteven Rostedt    }
2502545eb61SSteven Rostedt
251*5a391fbfSSteven Rostedt    close_console($fp, $pid);
2522545eb61SSteven Rostedt
2532545eb61SSteven Rostedt    if (!$booted) {
254*5a391fbfSSteven Rostedt	return 1 if ($in_bisect);
2555c42fc5bSSteven Rostedt	dodie "failed - never got a boot prompt.\n";
2562545eb61SSteven Rostedt    }
2572545eb61SSteven Rostedt
2582545eb61SSteven Rostedt    if ($bug) {
259*5a391fbfSSteven Rostedt	return 1 if ($in_bisect);
2605c42fc5bSSteven Rostedt	dodie "failed - got a bug report\n";
2612545eb61SSteven Rostedt    }
2625f9b6cedSSteven Rostedt
2635f9b6cedSSteven Rostedt    return 0;
2642545eb61SSteven Rostedt}
2652545eb61SSteven Rostedt
2662545eb61SSteven Rostedtsub install {
2672545eb61SSteven Rostedt
2685f9b6cedSSteven Rostedt    run_command "scp $opt{OUTPUT_DIR}/$opt{BUILD_TARGET} $target:$opt{TARGET_IMAGE}" or
2695c42fc5bSSteven Rostedt	dodie "failed to copy image";
2705f9b6cedSSteven Rostedt
2715f9b6cedSSteven Rostedt    my $install_mods = 0;
2725f9b6cedSSteven Rostedt
2735f9b6cedSSteven Rostedt    # should we process modules?
2745f9b6cedSSteven Rostedt    $install_mods = 0;
2755f9b6cedSSteven Rostedt    open(IN, "$opt{OUTPUT_DIR}/.config") or dodie("Can't read config file");
2765f9b6cedSSteven Rostedt    while (<IN>) {
2775f9b6cedSSteven Rostedt	if (/CONFIG_MODULES(=y)?/) {
2785f9b6cedSSteven Rostedt	    $install_mods = 1 if (defined($1));
2795f9b6cedSSteven Rostedt	    last;
2805f9b6cedSSteven Rostedt	}
2815f9b6cedSSteven Rostedt    }
2825f9b6cedSSteven Rostedt    close(IN);
2835f9b6cedSSteven Rostedt
2845f9b6cedSSteven Rostedt    if (!$install_mods) {
2855f9b6cedSSteven Rostedt	doprint "No modules needed\n";
2865f9b6cedSSteven Rostedt	return;
2872545eb61SSteven Rostedt    }
2882545eb61SSteven Rostedt
2895f9b6cedSSteven Rostedt    run_command "$make INSTALL_MOD_PATH=$opt{TMP_DIR} modules_install" or
2905f9b6cedSSteven Rostedt	dodie "Failed to install modules";
2915f9b6cedSSteven Rostedt
2922545eb61SSteven Rostedt    my $modlib = "/lib/modules/$version";
2935c42fc5bSSteven Rostedt    my $modtar = "autotest-mods.tar.bz2";
2942545eb61SSteven Rostedt
2955f9b6cedSSteven Rostedt    run_command "ssh $target rm -rf $modlib" or
2965c42fc5bSSteven Rostedt	dodie "failed to remove old mods: $modlib";
2972545eb61SSteven Rostedt
2985c42fc5bSSteven Rostedt    # would be nice if scp -r did not follow symbolic links
2995f9b6cedSSteven Rostedt    run_command "cd $opt{TMP_DIR} && tar -cjf $modtar lib/modules/$version" or
3005c42fc5bSSteven Rostedt	dodie "making tarball";
3015c42fc5bSSteven Rostedt
3025f9b6cedSSteven Rostedt    run_command "scp $opt{TMP_DIR}/$modtar $target:/tmp" or
3035c42fc5bSSteven Rostedt	dodie "failed to copy modules";
3045c42fc5bSSteven Rostedt
3055c42fc5bSSteven Rostedt    unlink "$opt{TMP_DIR}/$modtar";
3065c42fc5bSSteven Rostedt
3075f9b6cedSSteven Rostedt    run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'" or
3085c42fc5bSSteven Rostedt	dodie "failed to tar modules";
3095c42fc5bSSteven Rostedt
3105c42fc5bSSteven Rostedt    run_command "ssh $target rm -f /tmp/$modtar";
3112545eb61SSteven Rostedt}
3122545eb61SSteven Rostedt
3132545eb61SSteven Rostedtsub build {
3142545eb61SSteven Rostedt    my ($type) = @_;
3155c42fc5bSSteven Rostedt    my $defconfig = "";
3165c42fc5bSSteven Rostedt    my $append = "";
3172545eb61SSteven Rostedt
31875c3fda7SSteven Rostedt    if ($type =~ /^useconfig:(.*)/) {
3195f9b6cedSSteven Rostedt	run_command "cp $1 $opt{OUTPUT_DIR}/.config" or
32075c3fda7SSteven Rostedt	    dodie "could not copy $1 to .config";
3215f9b6cedSSteven Rostedt
32275c3fda7SSteven Rostedt	$type = "oldconfig";
32375c3fda7SSteven Rostedt    }
32475c3fda7SSteven Rostedt
3255c42fc5bSSteven Rostedt    # old config can ask questions
3265c42fc5bSSteven Rostedt    if ($type eq "oldconfig") {
3275c42fc5bSSteven Rostedt	$append = "yes ''|";
32875c3fda7SSteven Rostedt
32975c3fda7SSteven Rostedt	# allow for empty configs
33075c3fda7SSteven Rostedt	run_command "touch $opt{OUTPUT_DIR}/.config";
33175c3fda7SSteven Rostedt
3325f9b6cedSSteven Rostedt	run_command "mv $opt{OUTPUT_DIR}/.config $opt{OUTPUT_DIR}/config_temp" or
3335c42fc5bSSteven Rostedt	    dodie "moving .config";
3345c42fc5bSSteven Rostedt
3355f9b6cedSSteven Rostedt	if (!$noclean && !run_command "$make mrproper") {
3365c42fc5bSSteven Rostedt	    dodie "make mrproper";
3375c42fc5bSSteven Rostedt	}
3385c42fc5bSSteven Rostedt
3395f9b6cedSSteven Rostedt	run_command "mv $opt{OUTPUT_DIR}/config_temp $opt{OUTPUT_DIR}/.config" or
3405c42fc5bSSteven Rostedt	    dodie "moving config_temp";
3415c42fc5bSSteven Rostedt
3425c42fc5bSSteven Rostedt    } elsif (!$noclean) {
3432545eb61SSteven Rostedt	unlink "$opt{OUTPUT_DIR}/.config";
3445f9b6cedSSteven Rostedt	run_command "$make mrproper" or
3455c42fc5bSSteven Rostedt	    dodie "make mrproper";
3465c42fc5bSSteven Rostedt    }
3472545eb61SSteven Rostedt
3482545eb61SSteven Rostedt    # add something to distinguish this build
3495c42fc5bSSteven Rostedt    open(OUT, "> $opt{OUTPUT_DIR}/localversion") or dodie("Can't make localversion file");
3502545eb61SSteven Rostedt    print OUT "$opt{LOCALVERSION}\n";
3512545eb61SSteven Rostedt    close(OUT);
3522545eb61SSteven Rostedt
3535f9b6cedSSteven Rostedt    if (defined($minconfig)) {
3545f9b6cedSSteven Rostedt	$defconfig = "KCONFIG_ALLCONFIG=$minconfig";
3552545eb61SSteven Rostedt    }
3562545eb61SSteven Rostedt
3575f9b6cedSSteven Rostedt    run_command "$defconfig $append $make $type" or
3585c42fc5bSSteven Rostedt	dodie "failed make config";
3592545eb61SSteven Rostedt
3605f9b6cedSSteven Rostedt    if (!run_command "$make $opt{BUILD_OPTIONS}") {
3615f9b6cedSSteven Rostedt	# bisect may need this to pass
3625f9b6cedSSteven Rostedt	return 1 if ($in_bisect);
3635c42fc5bSSteven Rostedt	dodie "failed build";
3642545eb61SSteven Rostedt    }
3655f9b6cedSSteven Rostedt
3665f9b6cedSSteven Rostedt    return 0;
3672545eb61SSteven Rostedt}
3682545eb61SSteven Rostedt
36975c3fda7SSteven Rostedtsub reboot {
37075c3fda7SSteven Rostedt    # try to reboot normally
3715f9b6cedSSteven Rostedt    if (!run_command "ssh $target reboot") {
37275c3fda7SSteven Rostedt	# nope? power cycle it.
37375c3fda7SSteven Rostedt	run_command "$opt{POWER_CYCLE}";
37475c3fda7SSteven Rostedt    }
37575c3fda7SSteven Rostedt}
37675c3fda7SSteven Rostedt
37775c3fda7SSteven Rostedtsub halt {
3785f9b6cedSSteven Rostedt    if (!run_command "ssh $target halt" or defined($opt{"POWER_OFF"})) {
37975c3fda7SSteven Rostedt	# nope? the zap it!
38075c3fda7SSteven Rostedt	run_command "$opt{POWER_OFF}";
38175c3fda7SSteven Rostedt    }
38275c3fda7SSteven Rostedt}
38375c3fda7SSteven Rostedt
3845f9b6cedSSteven Rostedtsub success {
3855f9b6cedSSteven Rostedt    my ($i) = @_;
3865f9b6cedSSteven Rostedt
3875f9b6cedSSteven Rostedt    doprint "\n\n*******************************************\n";
3885f9b6cedSSteven Rostedt    doprint     "*******************************************\n";
3895f9b6cedSSteven Rostedt    doprint     "**            SUCCESS!!!!                **\n";
3905f9b6cedSSteven Rostedt    doprint     "*******************************************\n";
3915f9b6cedSSteven Rostedt    doprint     "*******************************************\n";
3925f9b6cedSSteven Rostedt
3935f9b6cedSSteven Rostedt    if ($i != $opt{"NUM_BUILDS"}) {
3945f9b6cedSSteven Rostedt	reboot;
3955f9b6cedSSteven Rostedt	doprint "Sleeping $opt{SLEEP_TIME} seconds\n";
3965f9b6cedSSteven Rostedt	sleep "$opt{SLEEP_TIME}";
3975f9b6cedSSteven Rostedt    }
3985f9b6cedSSteven Rostedt}
3995f9b6cedSSteven Rostedt
4005f9b6cedSSteven Rostedtsub get_version {
4015f9b6cedSSteven Rostedt    # get the release name
4025f9b6cedSSteven Rostedt    doprint "$make kernelrelease ... ";
4035f9b6cedSSteven Rostedt    $version = `$make kernelrelease | tail -1`;
4045f9b6cedSSteven Rostedt    chomp($version);
4055f9b6cedSSteven Rostedt    doprint "$version\n";
4065f9b6cedSSteven Rostedt}
4075f9b6cedSSteven Rostedt
408*5a391fbfSSteven Rostedtsub child_run_test {
409*5a391fbfSSteven Rostedt    my $failed;
410*5a391fbfSSteven Rostedt
411*5a391fbfSSteven Rostedt    $failed = !run_command $run_test;
412*5a391fbfSSteven Rostedt    exit $failed;
413*5a391fbfSSteven Rostedt}
414*5a391fbfSSteven Rostedt
415*5a391fbfSSteven Rostedtmy $child_done;
416*5a391fbfSSteven Rostedt
417*5a391fbfSSteven Rostedtsub child_finished {
418*5a391fbfSSteven Rostedt    $child_done = 1;
419*5a391fbfSSteven Rostedt}
420*5a391fbfSSteven Rostedt
421*5a391fbfSSteven Rostedtsub do_run_test {
422*5a391fbfSSteven Rostedt    my $child_pid;
423*5a391fbfSSteven Rostedt    my $child_exit;
424*5a391fbfSSteven Rostedt    my $pid;
425*5a391fbfSSteven Rostedt    my $line;
426*5a391fbfSSteven Rostedt    my $full_line;
427*5a391fbfSSteven Rostedt    my $bug = 0;
428*5a391fbfSSteven Rostedt    my $fp = \*IN;
429*5a391fbfSSteven Rostedt
430*5a391fbfSSteven Rostedt    $pid = open_console($fp);
431*5a391fbfSSteven Rostedt
432*5a391fbfSSteven Rostedt    # read the monitor and wait for the system to calm down
433*5a391fbfSSteven Rostedt    do {
434*5a391fbfSSteven Rostedt	$line = wait_for_input($fp, 1);
435*5a391fbfSSteven Rostedt    } while (defined($line));
436*5a391fbfSSteven Rostedt
437*5a391fbfSSteven Rostedt    $child_done = 0;
438*5a391fbfSSteven Rostedt
439*5a391fbfSSteven Rostedt    $SIG{CHLD} = qw(child_finished);
440*5a391fbfSSteven Rostedt
441*5a391fbfSSteven Rostedt    $child_pid = fork;
442*5a391fbfSSteven Rostedt
443*5a391fbfSSteven Rostedt    child_run_test if (!$child_pid);
444*5a391fbfSSteven Rostedt
445*5a391fbfSSteven Rostedt    $full_line = "";
446*5a391fbfSSteven Rostedt
447*5a391fbfSSteven Rostedt    do {
448*5a391fbfSSteven Rostedt	$line = wait_for_input($fp, 1);
449*5a391fbfSSteven Rostedt	if (defined($line)) {
450*5a391fbfSSteven Rostedt
451*5a391fbfSSteven Rostedt	    # we are not guaranteed to get a full line
452*5a391fbfSSteven Rostedt	    $full_line .= $line;
453*5a391fbfSSteven Rostedt
454*5a391fbfSSteven Rostedt	    if ($full_line =~ /call trace:/i) {
455*5a391fbfSSteven Rostedt		$bug = 1;
456*5a391fbfSSteven Rostedt	    }
457*5a391fbfSSteven Rostedt
458*5a391fbfSSteven Rostedt	    if ($full_line =~ /Kernel panic -/) {
459*5a391fbfSSteven Rostedt		$bug = 1;
460*5a391fbfSSteven Rostedt	    }
461*5a391fbfSSteven Rostedt
462*5a391fbfSSteven Rostedt	    if ($line =~ /\n/) {
463*5a391fbfSSteven Rostedt		$full_line = "";
464*5a391fbfSSteven Rostedt	    }
465*5a391fbfSSteven Rostedt	}
466*5a391fbfSSteven Rostedt    } while (!$child_done && !$bug);
467*5a391fbfSSteven Rostedt
468*5a391fbfSSteven Rostedt    if ($bug) {
469*5a391fbfSSteven Rostedt	doprint "Detected kernel crash!\n";
470*5a391fbfSSteven Rostedt	# kill the child with extreme prejudice
471*5a391fbfSSteven Rostedt	kill 9, $child_pid;
472*5a391fbfSSteven Rostedt    }
473*5a391fbfSSteven Rostedt
474*5a391fbfSSteven Rostedt    waitpid $child_pid, 0;
475*5a391fbfSSteven Rostedt    $child_exit = $?;
476*5a391fbfSSteven Rostedt
477*5a391fbfSSteven Rostedt    close_console($fp, $pid);
478*5a391fbfSSteven Rostedt
479*5a391fbfSSteven Rostedt    if ($bug || $child_exit) {
480*5a391fbfSSteven Rostedt	return 1 if $in_bisect;
481*5a391fbfSSteven Rostedt	dodie "test failed";
482*5a391fbfSSteven Rostedt    }
483*5a391fbfSSteven Rostedt    return 0;
484*5a391fbfSSteven Rostedt}
485*5a391fbfSSteven Rostedt
4865f9b6cedSSteven Rostedtsub run_bisect {
4875f9b6cedSSteven Rostedt    my ($type) = @_;
4885f9b6cedSSteven Rostedt
4895f9b6cedSSteven Rostedt    my $failed;
4905f9b6cedSSteven Rostedt    my $result;
4915f9b6cedSSteven Rostedt    my $output;
4925f9b6cedSSteven Rostedt    my $ret;
4935f9b6cedSSteven Rostedt
4945f9b6cedSSteven Rostedt
4955f9b6cedSSteven Rostedt    if (defined($minconfig)) {
4965f9b6cedSSteven Rostedt	$failed = build "useconfig:$minconfig";
4975f9b6cedSSteven Rostedt    } else {
4985f9b6cedSSteven Rostedt	# ?? no config to use?
4995f9b6cedSSteven Rostedt	$failed = build "oldconfig";
5005f9b6cedSSteven Rostedt    }
5015f9b6cedSSteven Rostedt
5025f9b6cedSSteven Rostedt    if ($type ne "build") {
5035f9b6cedSSteven Rostedt	dodie "Failed on build" if $failed;
5045f9b6cedSSteven Rostedt
5055f9b6cedSSteven Rostedt	# Now boot the box
5065f9b6cedSSteven Rostedt	get_grub_index;
5075f9b6cedSSteven Rostedt	get_version;
5085f9b6cedSSteven Rostedt	install;
5095f9b6cedSSteven Rostedt	$failed = monitor;
5105f9b6cedSSteven Rostedt
5115f9b6cedSSteven Rostedt	if ($type ne "boot") {
5125f9b6cedSSteven Rostedt	    dodie "Failed on boot" if $failed;
513*5a391fbfSSteven Rostedt
514*5a391fbfSSteven Rostedt	    $failed = do_run_test;
5155f9b6cedSSteven Rostedt	}
5165f9b6cedSSteven Rostedt    }
5175f9b6cedSSteven Rostedt
5185f9b6cedSSteven Rostedt    if ($failed) {
5195f9b6cedSSteven Rostedt	$result = "bad";
520*5a391fbfSSteven Rostedt
521*5a391fbfSSteven Rostedt	# reboot the box to a good kernel
522*5a391fbfSSteven Rostedt	if ($type eq "boot") {
523*5a391fbfSSteven Rostedt	    reboot;
524*5a391fbfSSteven Rostedt	    doprint "sleep a little for reboot\n";
525*5a391fbfSSteven Rostedt	    sleep $opt{"BISECT_SLEEP_TIME"};
526*5a391fbfSSteven Rostedt	}
5275f9b6cedSSteven Rostedt    } else {
5285f9b6cedSSteven Rostedt	$result = "good";
5295f9b6cedSSteven Rostedt    }
5305f9b6cedSSteven Rostedt
5315f9b6cedSSteven Rostedt    doprint "git bisect $result ... ";
5325f9b6cedSSteven Rostedt    $output = `git bisect $result 2>&1`;
5335f9b6cedSSteven Rostedt    $ret = $?;
5345f9b6cedSSteven Rostedt
5355f9b6cedSSteven Rostedt    logit $output;
5365f9b6cedSSteven Rostedt
5375f9b6cedSSteven Rostedt    if ($ret) {
5385f9b6cedSSteven Rostedt	doprint "FAILED\n";
5395f9b6cedSSteven Rostedt	dodie "Failed to git bisect";
5405f9b6cedSSteven Rostedt    }
5415f9b6cedSSteven Rostedt
5425f9b6cedSSteven Rostedt    doprint "SUCCESS\n";
543*5a391fbfSSteven Rostedt    if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
5445f9b6cedSSteven Rostedt	doprint "$1 [$2]\n";
5455f9b6cedSSteven Rostedt    } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
5465f9b6cedSSteven Rostedt	$bisect_bad = $1;
5475f9b6cedSSteven Rostedt	doprint "Found bad commit... $1\n";
5485f9b6cedSSteven Rostedt	return 0;
549*5a391fbfSSteven Rostedt    } else {
550*5a391fbfSSteven Rostedt	# we already logged it, just print it now.
551*5a391fbfSSteven Rostedt	print $output;
5525f9b6cedSSteven Rostedt    }
5535f9b6cedSSteven Rostedt
5545f9b6cedSSteven Rostedt
5555f9b6cedSSteven Rostedt    return 1;
5565f9b6cedSSteven Rostedt}
5575f9b6cedSSteven Rostedt
5585f9b6cedSSteven Rostedtsub bisect {
5595f9b6cedSSteven Rostedt    my ($i) = @_;
5605f9b6cedSSteven Rostedt
5615f9b6cedSSteven Rostedt    my $result;
5625f9b6cedSSteven Rostedt
5635f9b6cedSSteven Rostedt    die "BISECT_GOOD[$i] not defined\n"	if (!defined($opt{"BISECT_GOOD[$i]"}));
5645f9b6cedSSteven Rostedt    die "BISECT_BAD[$i] not defined\n"	if (!defined($opt{"BISECT_BAD[$i]"}));
5655f9b6cedSSteven Rostedt    die "BISECT_TYPE[$i] not defined\n"	if (!defined($opt{"BISECT_TYPE[$i]"}));
5665f9b6cedSSteven Rostedt
5675f9b6cedSSteven Rostedt    my $good = $opt{"BISECT_GOOD[$i]"};
5685f9b6cedSSteven Rostedt    my $bad = $opt{"BISECT_BAD[$i]"};
5695f9b6cedSSteven Rostedt    my $type = $opt{"BISECT_TYPE[$i]"};
5705f9b6cedSSteven Rostedt
5715f9b6cedSSteven Rostedt    $in_bisect = 1;
5725f9b6cedSSteven Rostedt
5735f9b6cedSSteven Rostedt    run_command "git bisect start" or
5745f9b6cedSSteven Rostedt	dodie "could not start bisect";
5755f9b6cedSSteven Rostedt
5765f9b6cedSSteven Rostedt    run_command "git bisect good $good" or
5775f9b6cedSSteven Rostedt	dodie "could not set bisect good to $good";
5785f9b6cedSSteven Rostedt
5795f9b6cedSSteven Rostedt    run_command "git bisect bad $bad" or
5805f9b6cedSSteven Rostedt	dodie "could not set bisect good to $bad";
5815f9b6cedSSteven Rostedt
582*5a391fbfSSteven Rostedt    # Can't have a test without having a test to run
583*5a391fbfSSteven Rostedt    if ($type eq "test" && !defined($run_test)) {
584*5a391fbfSSteven Rostedt	$type = "boot";
585*5a391fbfSSteven Rostedt    }
586*5a391fbfSSteven Rostedt
5875f9b6cedSSteven Rostedt    do {
5885f9b6cedSSteven Rostedt	$result = run_bisect $type;
5895f9b6cedSSteven Rostedt    } while ($result);
5905f9b6cedSSteven Rostedt
5915f9b6cedSSteven Rostedt    run_command "git bisect log" or
5925f9b6cedSSteven Rostedt	dodie "could not capture git bisect log";
5935f9b6cedSSteven Rostedt
5945f9b6cedSSteven Rostedt    run_command "git bisect reset" or
5955f9b6cedSSteven Rostedt	dodie "could not reset git bisect";
5965f9b6cedSSteven Rostedt
5975f9b6cedSSteven Rostedt    doprint "Bad commit was [$bisect_bad]\n";
5985f9b6cedSSteven Rostedt
5995f9b6cedSSteven Rostedt    $in_bisect = 0;
6005f9b6cedSSteven Rostedt
6015f9b6cedSSteven Rostedt    success $i;
6025f9b6cedSSteven Rostedt}
6035f9b6cedSSteven Rostedt
6042545eb61SSteven Rostedtread_config $ARGV[0];
6052545eb61SSteven Rostedt
6062545eb61SSteven Rostedt# mandatory configs
6072545eb61SSteven Rostedtdie "MACHINE not defined\n"		if (!defined($opt{"MACHINE"}));
6082545eb61SSteven Rostedtdie "SSH_USER not defined\n"		if (!defined($opt{"SSH_USER"}));
6092545eb61SSteven Rostedtdie "BUILD_DIR not defined\n"		if (!defined($opt{"BUILD_DIR"}));
6102545eb61SSteven Rostedtdie "OUTPUT_DIR not defined\n"		if (!defined($opt{"OUTPUT_DIR"}));
6112545eb61SSteven Rostedtdie "BUILD_TARGET not defined\n"	if (!defined($opt{"BUILD_TARGET"}));
61275c3fda7SSteven Rostedtdie "TARGET_IMAGE not defined\n"	if (!defined($opt{"TARGET_IMAGE"}));
6132545eb61SSteven Rostedtdie "POWER_CYCLE not defined\n"		if (!defined($opt{"POWER_CYCLE"}));
6142545eb61SSteven Rostedtdie "CONSOLE not defined\n"		if (!defined($opt{"CONSOLE"}));
6152545eb61SSteven Rostedtdie "LOCALVERSION not defined\n"	if (!defined($opt{"LOCALVERSION"}));
6162545eb61SSteven Rostedtdie "GRUB_MENU not defined\n"		if (!defined($opt{"GRUB_MENU"}));
6172545eb61SSteven Rostedt
6182545eb61SSteven Rostedtchdir $opt{"BUILD_DIR"} || die "can't change directory to $opt{BUILD_DIR}";
6192545eb61SSteven Rostedt
6202545eb61SSteven Rostedt$target = "$opt{SSH_USER}\@$opt{MACHINE}";
6212545eb61SSteven Rostedt
6222545eb61SSteven Rostedtdoprint "\n\nSTARTING AUTOMATED TESTS\n";
6232545eb61SSteven Rostedt
6242545eb61SSteven Rostedt
6252545eb61SSteven Rostedt$make = "$opt{MAKE_CMD} O=$opt{OUTPUT_DIR}";
6262545eb61SSteven Rostedt
627*5a391fbfSSteven Rostedtsub set_build_option {
628*5a391fbfSSteven Rostedt    my ($name, $i) = @_;
629*5a391fbfSSteven Rostedt
630*5a391fbfSSteven Rostedt    my $option = "$name\[$i\]";
631*5a391fbfSSteven Rostedt
632*5a391fbfSSteven Rostedt    if (defined($opt{$option})) {
633*5a391fbfSSteven Rostedt	return $opt{$option};
634*5a391fbfSSteven Rostedt    }
635*5a391fbfSSteven Rostedt
636*5a391fbfSSteven Rostedt    if (defined($opt{$name})) {
637*5a391fbfSSteven Rostedt	return $opt{$name};
638*5a391fbfSSteven Rostedt    }
639*5a391fbfSSteven Rostedt
640*5a391fbfSSteven Rostedt    return undef;
641*5a391fbfSSteven Rostedt}
642*5a391fbfSSteven Rostedt
6432545eb61SSteven Rostedt# First we need to do is the builds
6442545eb61SSteven Rostedtfor (my $i = 1; $i <= $opt{"NUM_BUILDS"}; $i++) {
6452545eb61SSteven Rostedt    my $type = "BUILD_TYPE[$i]";
6462545eb61SSteven Rostedt
647*5a391fbfSSteven Rostedt    $noclean = set_build_option("BUILD_NOCLEAN", $i);
648*5a391fbfSSteven Rostedt    $minconfig = set_build_option("MIN_CONFIG", $i);
649*5a391fbfSSteven Rostedt    $run_test = set_build_option("TEST", $i);
6502545eb61SSteven Rostedt
6512545eb61SSteven Rostedt    doprint "\n\n";
6522545eb61SSteven Rostedt    doprint "RUNNING TEST $i of $opt{NUM_BUILDS} with option $opt{$type}\n\n";
6532545eb61SSteven Rostedt
6545f9b6cedSSteven Rostedt    if ($opt{$type} eq "bisect") {
6555f9b6cedSSteven Rostedt	bisect $i;
6565f9b6cedSSteven Rostedt	next;
6575f9b6cedSSteven Rostedt    }
6585f9b6cedSSteven Rostedt
6592545eb61SSteven Rostedt    if ($opt{$type} ne "nobuild") {
6605c42fc5bSSteven Rostedt	build $opt{$type};
6612545eb61SSteven Rostedt    }
6622545eb61SSteven Rostedt
6635f9b6cedSSteven Rostedt    get_grub_index;
6645f9b6cedSSteven Rostedt    get_version;
6652545eb61SSteven Rostedt    install;
6662545eb61SSteven Rostedt    monitor;
667*5a391fbfSSteven Rostedt
668*5a391fbfSSteven Rostedt    if (defined($run_test)) {
669*5a391fbfSSteven Rostedt	do_run_test;
670*5a391fbfSSteven Rostedt    }
671*5a391fbfSSteven Rostedt
6725f9b6cedSSteven Rostedt    success $i;
67375c3fda7SSteven Rostedt}
6742545eb61SSteven Rostedt
6755c42fc5bSSteven Rostedtif ($opt{"POWEROFF_ON_SUCCESS"}) {
67675c3fda7SSteven Rostedt    halt;
67775c3fda7SSteven Rostedt} else {
67875c3fda7SSteven Rostedt    reboot;
6795c42fc5bSSteven Rostedt}
68075c3fda7SSteven Rostedt
6812545eb61SSteven Rostedtexit 0;
682