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{"REBOOT_ON_SUCCESS"} = 1;
25 $opt{"POWEROFF_ON_SUCCESS"} = 0;
26 $opt{"BUILD_OPTIONS"} = "";
27 $opt{"BISECT_SLEEP_TIME"} = 10; # sleep time between bisects
42 open(IN, $config) || die "can't read file $config";
46 # ignore blank lines and comments
47 next if (/^\s*$/ || /\s*\#/);
49 if (/^\s*(\S+)\s*=\s*(.*?)\s*$/) {
53 $opt{$lvalue} = $rvalue;
61 if (defined($opt{"LOG_FILE"})) {
62 open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
74 doprint "CRITICAL FAILURE... ", @_, "\n";
76 if ($opt{"REBOOT_ON_ERROR"}) {
77 doprint "REBOOTING\n";
78 `$opt{"POWER_CYCLE"}`;
80 } elsif ($opt{"POWEROFF_ON_ERROR"} && defined($opt{"POWER_OFF"})) {
81 doprint "POWERING OFF\n";
90 my $redirect_log = "";
92 if (defined($opt{"LOG_FILE"})) {
93 $redirect_log = " >> $opt{LOG_FILE} 2>&1";
96 doprint "$command ... ";
97 `$command $redirect_log`;
112 return if (defined($grub_number));
114 doprint "Find grub menu ... ";
116 open(IN, "ssh $target cat /boot/grub/menu.lst |")
117 or die "unable to get menu.lst";
119 if (/^\s*title\s+$opt{GRUB_MENU}\s*$/) {
122 } elsif (/^\s*title\s/) {
128 die "Could not find '$opt{GRUB_MENU}' in /boot/grub/menu on $opt{MACHINE}"
129 if ($grub_number < 0);
130 doprint "$grub_number\n";
133 my $timeout = $opt{"TIMEOUT"};
137 my ($fp, $time) = @_;
143 if (!defined($time)) {
148 vec($rin, fileno($fp), 1) = 1;
149 $ready = select($rin, undef, undef, $time);
153 # try to read one char at a time
154 while (sysread $fp, $ch, 1) {
156 last if ($ch eq "\n");
159 if (!length($line)) {
167 run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
175 my $pid = open($fp, "$opt{CONSOLE}|") or
176 dodie "Can't open console $opt{CONSOLE}";
178 $flags = fcntl($fp, F_GETFL, 0) or
179 dodie "Can't get flags for the socket: $!\n";
180 $flags = fcntl($fp, F_SETFL, $flags | O_NONBLOCK) or
181 dodie "Can't set flags for the socket: $!\n";
189 doprint "kill child process $pid\n";
200 my $skip_call_trace = 0;
203 $pid = open_console($fp);
208 doprint "Wait for monitor to settle down.\n";
209 # read the monitor and wait for the system to calm down
211 $line = wait_for_input($fp, 5);
212 } while (defined($line));
218 $line = wait_for_input($fp);
220 last if (!defined($line));
224 # we are not guaranteed to get a full line
227 if ($full_line =~ /login:/) {
231 if ($full_line =~ /\[ backtrace testing \]/) {
232 $skip_call_trace = 1;
235 if ($full_line =~ /call trace:/i) {
236 $bug = 1 if (!$skip_call_trace);
239 if ($full_line =~ /\[ end of backtrace testing \]/) {
240 $skip_call_trace = 0;
243 if ($full_line =~ /Kernel panic -/) {
252 close_console($fp, $pid);
255 return 1 if ($in_bisect);
256 dodie "failed - never got a boot prompt.\n";
260 return 1 if ($in_bisect);
261 dodie "failed - got a bug report\n";
269 run_command "scp $opt{OUTPUT_DIR}/$opt{BUILD_TARGET} $target:$opt{TARGET_IMAGE}" or
270 dodie "failed to copy image";
272 my $install_mods = 0;
274 # should we process modules?
276 open(IN, "$opt{OUTPUT_DIR}/.config") or dodie("Can't read config file");
278 if (/CONFIG_MODULES(=y)?/) {
279 $install_mods = 1 if (defined($1));
285 if (!$install_mods) {
286 doprint "No modules needed\n";
290 run_command "$make INSTALL_MOD_PATH=$opt{TMP_DIR} modules_install" or
291 dodie "Failed to install modules";
293 my $modlib = "/lib/modules/$version";
294 my $modtar = "autotest-mods.tar.bz2";
296 run_command "ssh $target rm -rf $modlib" or
297 dodie "failed to remove old mods: $modlib";
299 # would be nice if scp -r did not follow symbolic links
300 run_command "cd $opt{TMP_DIR} && tar -cjf $modtar lib/modules/$version" or
301 dodie "making tarball";
303 run_command "scp $opt{TMP_DIR}/$modtar $target:/tmp" or
304 dodie "failed to copy modules";
306 unlink "$opt{TMP_DIR}/$modtar";
308 run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'" or
309 dodie "failed to tar modules";
311 run_command "ssh $target rm -f /tmp/$modtar";
319 if ($type =~ /^useconfig:(.*)/) {
320 run_command "cp $1 $opt{OUTPUT_DIR}/.config" or
321 dodie "could not copy $1 to .config";
326 # old config can ask questions
327 if ($type eq "oldconfig") {
330 # allow for empty configs
331 run_command "touch $opt{OUTPUT_DIR}/.config";
333 run_command "mv $opt{OUTPUT_DIR}/.config $opt{OUTPUT_DIR}/config_temp" or
334 dodie "moving .config";
336 if (!$noclean && !run_command "$make mrproper") {
337 dodie "make mrproper";
340 run_command "mv $opt{OUTPUT_DIR}/config_temp $opt{OUTPUT_DIR}/.config" or
341 dodie "moving config_temp";
343 } elsif (!$noclean) {
344 unlink "$opt{OUTPUT_DIR}/.config";
345 run_command "$make mrproper" or
346 dodie "make mrproper";
349 # add something to distinguish this build
350 open(OUT, "> $opt{OUTPUT_DIR}/localversion") or dodie("Can't make localversion file");
351 print OUT "$opt{LOCALVERSION}\n";
354 if (defined($minconfig)) {
355 $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
358 run_command "$defconfig $append $make $type" or
359 dodie "failed make config";
361 if (!run_command "$make $opt{BUILD_OPTIONS}") {
362 # bisect may need this to pass
363 return 1 if ($in_bisect);
364 dodie "failed build";
371 # try to reboot normally
372 if (!run_command "ssh $target reboot") {
373 # nope? power cycle it.
374 run_command "$opt{POWER_CYCLE}";
379 if (!run_command "ssh $target halt" or defined($opt{"POWER_OFF"})) {
381 run_command "$opt{POWER_OFF}";
388 doprint "\n\n*******************************************\n";
389 doprint "*******************************************\n";
390 doprint "** SUCCESS!!!! **\n";
391 doprint "*******************************************\n";
392 doprint "*******************************************\n";
394 if ($i != $opt{"NUM_BUILDS"}) {
396 doprint "Sleeping $opt{SLEEP_TIME} seconds\n";
397 sleep "$opt{SLEEP_TIME}";
402 # get the release name
403 doprint "$make kernelrelease ... ";
404 $version = `$make kernelrelease | tail -1`;
406 doprint "$version\n";
412 $failed = !run_command $run_test;
431 $pid = open_console($fp);
433 # read the monitor and wait for the system to calm down
435 $line = wait_for_input($fp, 1);
436 } while (defined($line));
440 $SIG{CHLD} = qw(child_finished);
444 child_run_test if (!$child_pid);
449 $line = wait_for_input($fp, 1);
450 if (defined($line)) {
452 # we are not guaranteed to get a full line
455 if ($full_line =~ /call trace:/i) {
459 if ($full_line =~ /Kernel panic -/) {
467 } while (!$child_done && !$bug);
470 doprint "Detected kernel crash!\n";
471 # kill the child with extreme prejudice
475 waitpid $child_pid, 0;
478 close_console($fp, $pid);
480 if ($bug || $child_exit) {
481 return 1 if $in_bisect;
496 if (defined($minconfig)) {
497 $failed = build "useconfig:$minconfig";
499 # ?? no config to use?
500 $failed = build "oldconfig";
503 if ($type ne "build") {
504 dodie "Failed on build" if $failed;
512 if ($type ne "boot") {
513 dodie "Failed on boot" if $failed;
515 $failed = do_run_test;
522 # reboot the box to a good kernel
523 if ($type eq "boot") {
525 doprint "sleep a little for reboot\n";
526 sleep $opt{"BISECT_SLEEP_TIME"};
532 doprint "git bisect $result ... ";
533 $output = `git bisect $result 2>&1`;
540 dodie "Failed to git bisect";
544 if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
546 } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
548 doprint "Found bad commit... $1\n";
551 # we already logged it, just print it now.
564 die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"}));
565 die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"}));
566 die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"}));
568 my $good = $opt{"BISECT_GOOD[$i]"};
569 my $bad = $opt{"BISECT_BAD[$i]"};
570 my $type = $opt{"BISECT_TYPE[$i]"};
574 run_command "git bisect start" or
575 dodie "could not start bisect";
577 run_command "git bisect good $good" or
578 dodie "could not set bisect good to $good";
580 run_command "git bisect bad $bad" or
581 dodie "could not set bisect good to $bad";
583 # Can't have a test without having a test to run
584 if ($type eq "test" && !defined($run_test)) {
589 $result = run_bisect $type;
592 run_command "git bisect log" or
593 dodie "could not capture git bisect log";
595 run_command "git bisect reset" or
596 dodie "could not reset git bisect";
598 doprint "Bad commit was [$bisect_bad]\n";
605 read_config $ARGV[0];
608 die "MACHINE not defined\n" if (!defined($opt{"MACHINE"}));
609 die "SSH_USER not defined\n" if (!defined($opt{"SSH_USER"}));
610 die "BUILD_DIR not defined\n" if (!defined($opt{"BUILD_DIR"}));
611 die "OUTPUT_DIR not defined\n" if (!defined($opt{"OUTPUT_DIR"}));
612 die "BUILD_TARGET not defined\n" if (!defined($opt{"BUILD_TARGET"}));
613 die "TARGET_IMAGE not defined\n" if (!defined($opt{"TARGET_IMAGE"}));
614 die "POWER_CYCLE not defined\n" if (!defined($opt{"POWER_CYCLE"}));
615 die "CONSOLE not defined\n" if (!defined($opt{"CONSOLE"}));
616 die "LOCALVERSION not defined\n" if (!defined($opt{"LOCALVERSION"}));
617 die "GRUB_MENU not defined\n" if (!defined($opt{"GRUB_MENU"}));
619 chdir $opt{"BUILD_DIR"} || die "can't change directory to $opt{BUILD_DIR}";
621 $target = "$opt{SSH_USER}\@$opt{MACHINE}";
623 doprint "\n\nSTARTING AUTOMATED TESTS\n";
626 $make = "$opt{MAKE_CMD} O=$opt{OUTPUT_DIR}";
628 sub set_build_option {
631 my $option = "$name\[$i\]";
633 if (defined($opt{$option})) {
634 return $opt{$option};
637 if (defined($opt{$name})) {
644 # First we need to do is the builds
645 for (my $i = 1; $i <= $opt{"NUM_BUILDS"}; $i++) {
646 my $type = "BUILD_TYPE[$i]";
648 if (!defined($opt{$type})) {
649 $opt{$type} = $opt{"DEFAULT_BUILD_TYPE"};
652 $noclean = set_build_option("BUILD_NOCLEAN", $i);
653 $minconfig = set_build_option("MIN_CONFIG", $i);
654 $run_test = set_build_option("TEST", $i);
657 doprint "RUNNING TEST $i of $opt{NUM_BUILDS} with option $opt{$type}\n\n";
659 if ($opt{$type} eq "bisect") {
664 if ($opt{$type} ne "nobuild") {
673 if (defined($run_test)) {
680 if ($opt{"POWEROFF_ON_SUCCESS"}) {
682 } elsif ($opt{"REBOOT_ON_SUCCESS"}) {