5 use Fcntl
qw(F_GETFL F_SETFL O_NONBLOCK);
8 $#ARGV >= 0 || die "usage: autotest.pl config-file\n";
15 $opt{"NUM_BUILDS"} = 5;
16 $opt{"DEFAULT_BUILD_TYPE"} = "randconfig";
17 $opt{"MAKE_CMD"} = "make";
19 $opt{"TMP_DIR"} = "/tmp/autotest";
20 $opt{"SLEEP_TIME"} = 60; # sleep time between tests
21 $opt{"BUILD_NOCLEAN"} = 0;
22 $opt{"REBOOT_ON_ERROR"} = 0;
23 $opt{"POWEROFF_ON_ERROR"} = 0;
24 $opt{"POWEROFF_ON_SUCCESS"} = 0;
25 $opt{"BUILD_OPTIONS"} = "";
26 $opt{"BISECT_SLEEP_TIME"} = 10; # sleep time between bisects
41 open(IN
, $config) || die "can't read file $config";
45 # ignore blank lines and comments
46 next if (/^\s*$/ || /\s*\#/);
48 if (/^\s*(\S+)\s*=\s*(.*?)\s*$/) {
52 $opt{$lvalue} = $rvalue;
60 if (defined($opt{"LOG_FILE"})) {
61 open(OUT
, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
73 doprint
"CRITICAL FAILURE... ", @_, "\n";
75 if ($opt{"REBOOT_ON_ERROR"}) {
76 doprint
"REBOOTING\n";
77 `$opt{"POWER_CYCLE"}`;
79 } elsif ($opt{"POWEROFF_ON_ERROR"} && defined($opt{"POWER_OFF"})) {
80 doprint
"POWERING OFF\n";
89 my $redirect_log = "";
91 if (defined($opt{"LOG_FILE"})) {
92 $redirect_log = " >> $opt{LOG_FILE} 2>&1";
95 doprint
"$command ... ";
96 `$command $redirect_log`;
111 return if (defined($grub_number));
113 doprint
"Find grub menu ... ";
115 open(IN
, "ssh $target cat /boot/grub/menu.lst |")
116 or die "unable to get menu.lst";
118 if (/^\s*title\s+$opt{GRUB_MENU}\s*$/) {
121 } elsif (/^\s*title\s/) {
127 die "Could not find '$opt{GRUB_MENU}' in /boot/grub/menu on $opt{MACHINE}"
128 if ($grub_number < 0);
129 doprint
"$grub_number\n";
132 my $timeout = $opt{"TIMEOUT"};
136 my ($fp, $time) = @_;
142 if (!defined($time)) {
147 vec($rin, fileno($fp), 1) = 1;
148 $ready = select($rin, undef, undef, $time);
152 # try to read one char at a time
153 while (sysread $fp, $ch, 1) {
155 last if ($ch eq "\n");
158 if (!length($line)) {
166 run_command
"ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
174 my $pid = open($fp, "$opt{CONSOLE}|") or
175 dodie
"Can't open console $opt{CONSOLE}";
177 $flags = fcntl($fp, F_GETFL
, 0) or
178 dodie
"Can't get flags for the socket: $!\n";
179 $flags = fcntl($fp, F_SETFL
, $flags | O_NONBLOCK
) or
180 dodie
"Can't set flags for the socket: $!\n";
188 doprint
"kill child process $pid\n";
199 my $skip_call_trace = 0;
202 $pid = open_console
($fp);
207 doprint
"Wait for monitor to settle down.\n";
208 # read the monitor and wait for the system to calm down
210 $line = wait_for_input
($fp, 5);
211 } while (defined($line));
217 $line = wait_for_input
($fp);
219 last if (!defined($line));
223 # we are not guaranteed to get a full line
226 if ($full_line =~ /login:/) {
230 if ($full_line =~ /\[ backtrace testing \]/) {
231 $skip_call_trace = 1;
234 if ($full_line =~ /call trace:/i) {
235 $bug = 1 if (!$skip_call_trace);
238 if ($full_line =~ /\[ end of backtrace testing \]/) {
239 $skip_call_trace = 0;
242 if ($full_line =~ /Kernel panic -/) {
251 close_console
($fp, $pid);
254 return 1 if ($in_bisect);
255 dodie
"failed - never got a boot prompt.\n";
259 return 1 if ($in_bisect);
260 dodie
"failed - got a bug report\n";
268 run_command
"scp $opt{OUTPUT_DIR}/$opt{BUILD_TARGET} $target:$opt{TARGET_IMAGE}" or
269 dodie
"failed to copy image";
271 my $install_mods = 0;
273 # should we process modules?
275 open(IN
, "$opt{OUTPUT_DIR}/.config") or dodie
("Can't read config file");
277 if (/CONFIG_MODULES(=y)?/) {
278 $install_mods = 1 if (defined($1));
284 if (!$install_mods) {
285 doprint
"No modules needed\n";
289 run_command
"$make INSTALL_MOD_PATH=$opt{TMP_DIR} modules_install" or
290 dodie
"Failed to install modules";
292 my $modlib = "/lib/modules/$version";
293 my $modtar = "autotest-mods.tar.bz2";
295 run_command
"ssh $target rm -rf $modlib" or
296 dodie
"failed to remove old mods: $modlib";
298 # would be nice if scp -r did not follow symbolic links
299 run_command
"cd $opt{TMP_DIR} && tar -cjf $modtar lib/modules/$version" or
300 dodie
"making tarball";
302 run_command
"scp $opt{TMP_DIR}/$modtar $target:/tmp" or
303 dodie
"failed to copy modules";
305 unlink "$opt{TMP_DIR}/$modtar";
307 run_command
"ssh $target '(cd / && tar xf /tmp/$modtar)'" or
308 dodie
"failed to tar modules";
310 run_command
"ssh $target rm -f /tmp/$modtar";
318 if ($type =~ /^useconfig:(.*)/) {
319 run_command
"cp $1 $opt{OUTPUT_DIR}/.config" or
320 dodie
"could not copy $1 to .config";
325 # old config can ask questions
326 if ($type eq "oldconfig") {
329 # allow for empty configs
330 run_command
"touch $opt{OUTPUT_DIR}/.config";
332 run_command
"mv $opt{OUTPUT_DIR}/.config $opt{OUTPUT_DIR}/config_temp" or
333 dodie
"moving .config";
335 if (!$noclean && !run_command
"$make mrproper") {
336 dodie
"make mrproper";
339 run_command
"mv $opt{OUTPUT_DIR}/config_temp $opt{OUTPUT_DIR}/.config" or
340 dodie
"moving config_temp";
342 } elsif (!$noclean) {
343 unlink "$opt{OUTPUT_DIR}/.config";
344 run_command
"$make mrproper" or
345 dodie
"make mrproper";
348 # add something to distinguish this build
349 open(OUT
, "> $opt{OUTPUT_DIR}/localversion") or dodie
("Can't make localversion file");
350 print OUT
"$opt{LOCALVERSION}\n";
353 if (defined($minconfig)) {
354 $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
357 run_command
"$defconfig $append $make $type" or
358 dodie
"failed make config";
360 if (!run_command
"$make $opt{BUILD_OPTIONS}") {
361 # bisect may need this to pass
362 return 1 if ($in_bisect);
363 dodie
"failed build";
370 # try to reboot normally
371 if (!run_command
"ssh $target reboot") {
372 # nope? power cycle it.
373 run_command
"$opt{POWER_CYCLE}";
378 if (!run_command
"ssh $target halt" or defined($opt{"POWER_OFF"})) {
380 run_command
"$opt{POWER_OFF}";
387 doprint
"\n\n*******************************************\n";
388 doprint
"*******************************************\n";
389 doprint
"** SUCCESS!!!! **\n";
390 doprint
"*******************************************\n";
391 doprint
"*******************************************\n";
393 if ($i != $opt{"NUM_BUILDS"}) {
395 doprint
"Sleeping $opt{SLEEP_TIME} seconds\n";
396 sleep "$opt{SLEEP_TIME}";
401 # get the release name
402 doprint
"$make kernelrelease ... ";
403 $version = `$make kernelrelease | tail -1`;
405 doprint
"$version\n";
411 $failed = !run_command
$run_test;
430 $pid = open_console
($fp);
432 # read the monitor and wait for the system to calm down
434 $line = wait_for_input
($fp, 1);
435 } while (defined($line));
439 $SIG{CHLD
} = qw(child_finished);
443 child_run_test
if (!$child_pid);
448 $line = wait_for_input
($fp, 1);
449 if (defined($line)) {
451 # we are not guaranteed to get a full line
454 if ($full_line =~ /call trace:/i) {
458 if ($full_line =~ /Kernel panic -/) {
466 } while (!$child_done && !$bug);
469 doprint
"Detected kernel crash!\n";
470 # kill the child with extreme prejudice
474 waitpid $child_pid, 0;
477 close_console
($fp, $pid);
479 if ($bug || $child_exit) {
480 return 1 if $in_bisect;
495 if (defined($minconfig)) {
496 $failed = build
"useconfig:$minconfig";
498 # ?? no config to use?
499 $failed = build
"oldconfig";
502 if ($type ne "build") {
503 dodie
"Failed on build" if $failed;
511 if ($type ne "boot") {
512 dodie
"Failed on boot" if $failed;
514 $failed = do_run_test
;
521 # reboot the box to a good kernel
522 if ($type eq "boot") {
524 doprint
"sleep a little for reboot\n";
525 sleep $opt{"BISECT_SLEEP_TIME"};
531 doprint
"git bisect $result ... ";
532 $output = `git bisect $result 2>&1`;
539 dodie
"Failed to git bisect";
543 if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
545 } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
547 doprint
"Found bad commit... $1\n";
550 # we already logged it, just print it now.
563 die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"}));
564 die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"}));
565 die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"}));
567 my $good = $opt{"BISECT_GOOD[$i]"};
568 my $bad = $opt{"BISECT_BAD[$i]"};
569 my $type = $opt{"BISECT_TYPE[$i]"};
573 run_command
"git bisect start" or
574 dodie
"could not start bisect";
576 run_command
"git bisect good $good" or
577 dodie
"could not set bisect good to $good";
579 run_command
"git bisect bad $bad" or
580 dodie
"could not set bisect good to $bad";
582 # Can't have a test without having a test to run
583 if ($type eq "test" && !defined($run_test)) {
588 $result = run_bisect
$type;
591 run_command
"git bisect log" or
592 dodie
"could not capture git bisect log";
594 run_command
"git bisect reset" or
595 dodie
"could not reset git bisect";
597 doprint
"Bad commit was [$bisect_bad]\n";
604 read_config
$ARGV[0];
607 die "MACHINE not defined\n" if (!defined($opt{"MACHINE"}));
608 die "SSH_USER not defined\n" if (!defined($opt{"SSH_USER"}));
609 die "BUILD_DIR not defined\n" if (!defined($opt{"BUILD_DIR"}));
610 die "OUTPUT_DIR not defined\n" if (!defined($opt{"OUTPUT_DIR"}));
611 die "BUILD_TARGET not defined\n" if (!defined($opt{"BUILD_TARGET"}));
612 die "TARGET_IMAGE not defined\n" if (!defined($opt{"TARGET_IMAGE"}));
613 die "POWER_CYCLE not defined\n" if (!defined($opt{"POWER_CYCLE"}));
614 die "CONSOLE not defined\n" if (!defined($opt{"CONSOLE"}));
615 die "LOCALVERSION not defined\n" if (!defined($opt{"LOCALVERSION"}));
616 die "GRUB_MENU not defined\n" if (!defined($opt{"GRUB_MENU"}));
618 chdir $opt{"BUILD_DIR"} || die "can't change directory to $opt{BUILD_DIR}";
620 $target = "$opt{SSH_USER}\@$opt{MACHINE}";
622 doprint
"\n\nSTARTING AUTOMATED TESTS\n";
625 $make = "$opt{MAKE_CMD} O=$opt{OUTPUT_DIR}";
627 sub set_build_option
{
630 my $option = "$name\[$i\]";
632 if (defined($opt{$option})) {
633 return $opt{$option};
636 if (defined($opt{$name})) {
643 # First we need to do is the builds
644 for (my $i = 1; $i <= $opt{"NUM_BUILDS"}; $i++) {
645 my $type = "BUILD_TYPE[$i]";
647 $noclean = set_build_option
("BUILD_NOCLEAN", $i);
648 $minconfig = set_build_option
("MIN_CONFIG", $i);
649 $run_test = set_build_option
("TEST", $i);
652 doprint
"RUNNING TEST $i of $opt{NUM_BUILDS} with option $opt{$type}\n\n";
654 if ($opt{$type} eq "bisect") {
659 if ($opt{$type} ne "nobuild") {
668 if (defined($run_test)) {
675 if ($opt{"POWEROFF_ON_SUCCESS"}) {