ktest: Use $output_config instead of typing $outputdir/.config
[linux-2.6.git] / tools / testing / ktest / ktest.pl
1 #!/usr/bin/perl -w
2 #
3 # Copywrite 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
4 # Licensed under the terms of the GNU GPL License version 2
5 #
6
7 use strict;
8 use IPC::Open2;
9 use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
10 use File::Path qw(mkpath);
11 use File::Copy qw(cp);
12 use FileHandle;
13
14 $#ARGV >= 0 || die "usage: ktest.pl config-file\n";
15
16 $| = 1;
17
18 my %opt;
19 my %repeat_tests;
20 my %repeats;
21 my %default;
22
23 #default opts
24 $default{"NUM_TESTS"}           = 1;
25 $default{"REBOOT_TYPE"}         = "grub";
26 $default{"TEST_TYPE"}           = "test";
27 $default{"BUILD_TYPE"}          = "randconfig";
28 $default{"MAKE_CMD"}            = "make";
29 $default{"TIMEOUT"}             = 120;
30 $default{"TMP_DIR"}             = "/tmp/ktest";
31 $default{"SLEEP_TIME"}          = 60;   # sleep time between tests
32 $default{"BUILD_NOCLEAN"}       = 0;
33 $default{"REBOOT_ON_ERROR"}     = 0;
34 $default{"POWEROFF_ON_ERROR"}   = 0;
35 $default{"REBOOT_ON_SUCCESS"}   = 1;
36 $default{"POWEROFF_ON_SUCCESS"} = 0;
37 $default{"BUILD_OPTIONS"}       = "";
38 $default{"BISECT_SLEEP_TIME"}   = 60;   # sleep time between bisects
39 $default{"CLEAR_LOG"}           = 0;
40 $default{"SUCCESS_LINE"}        = "login:";
41 $default{"BOOTED_TIMEOUT"}      = 1;
42 $default{"DIE_ON_FAILURE"}      = 1;
43
44 my $version;
45 my $machine;
46 my $tmpdir;
47 my $builddir;
48 my $outputdir;
49 my $output_config;
50 my $test_type;
51 my $build_type;
52 my $build_options;
53 my $reboot_type;
54 my $reboot_script;
55 my $power_cycle;
56 my $reboot_on_error;
57 my $poweroff_on_error;
58 my $die_on_failure;
59 my $powercycle_after_reboot;
60 my $poweroff_after_halt;
61 my $power_off;
62 my $grub_menu;
63 my $grub_number;
64 my $target;
65 my $make;
66 my $post_install;
67 my $noclean;
68 my $minconfig;
69 my $addconfig;
70 my $in_bisect = 0;
71 my $bisect_bad = "";
72 my $reverse_bisect;
73 my $in_patchcheck = 0;
74 my $run_test;
75 my $redirect;
76 my $buildlog;
77 my $dmesg;
78 my $monitor_fp;
79 my $monitor_pid;
80 my $monitor_cnt = 0;
81 my $sleep_time;
82 my $bisect_sleep_time;
83 my $store_failures;
84 my $timeout;
85 my $booted_timeout;
86 my $console;
87 my $success_line;
88 my $build_target;
89 my $target_image;
90 my $localversion;
91 my $iteration = 0;
92
93 sub set_value {
94     my ($lvalue, $rvalue) = @_;
95
96     if (defined($opt{$lvalue})) {
97         die "Error: Option $lvalue defined more than once!\n";
98     }
99     $opt{$lvalue} = $rvalue;
100 }
101
102 sub read_config {
103     my ($config) = @_;
104
105     open(IN, $config) || die "can't read file $config";
106
107     my $name = $config;
108     $name =~ s,.*/(.*),$1,;
109
110     my $test_num = 0;
111     my $default = 1;
112     my $repeat = 1;
113     my $num_tests_set = 0;
114     my $skip = 0;
115     my $rest;
116
117     while (<IN>) {
118
119         # ignore blank lines and comments
120         next if (/^\s*$/ || /\s*\#/);
121
122         if (/^\s*TEST_START(.*)/) {
123
124             $rest = $1;
125
126             if ($num_tests_set) {
127                 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
128             }
129
130             my $old_test_num = $test_num;
131
132             $test_num += $repeat;
133             $default = 0;
134             $repeat = 1;
135
136             if ($rest =~ /\s+SKIP(.*)/) {
137                 $rest = $1;
138                 $skip = 1;
139             } else {
140                 $skip = 0;
141             }
142
143             if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) {
144                 $repeat = $1;
145                 $rest = $2;
146                 $repeat_tests{"$test_num"} = $repeat;
147             }
148
149             if ($rest =~ /\s+SKIP(.*)/) {
150                 $rest = $1;
151                 $skip = 1;
152             }
153
154             if ($rest !~ /^\s*$/) {
155                 die "$name: $.: Gargbage found after TEST_START\n$_";
156             }
157
158             if ($skip) {
159                 $test_num = $old_test_num;
160                 $repeat = 1;
161             }
162
163         } elsif (/^\s*DEFAULTS(.*)$/) {
164             $default = 1;
165
166             $rest = $1;
167
168             if ($rest =~ /\s+SKIP(.*)/) {
169                 $rest = $1;
170                 $skip = 1;
171             } else {
172                 $skip = 0;
173             }
174
175             if ($rest !~ /^\s*$/) {
176                 die "$name: $.: Gargbage found after DEFAULTS\n$_";
177             }
178
179         } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) {
180
181             next if ($skip);
182
183             my $lvalue = $1;
184             my $rvalue = $2;
185
186             if (!$default &&
187                 ($lvalue eq "NUM_TESTS" ||
188                  $lvalue eq "LOG_FILE" ||
189                  $lvalue eq "CLEAR_LOG")) {
190                 die "$name: $.: $lvalue must be set in DEFAULTS section\n";
191             }
192
193             if ($lvalue eq "NUM_TESTS") {
194                 if ($test_num) {
195                     die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
196                 }
197                 if (!$default) {
198                     die "$name: $.: NUM_TESTS must be set in default section\n";
199                 }
200                 $num_tests_set = 1;
201             }
202
203             if ($default || $lvalue =~ /\[\d+\]$/) {
204                 set_value($lvalue, $rvalue);
205             } else {
206                 my $val = "$lvalue\[$test_num\]";
207                 set_value($val, $rvalue);
208
209                 if ($repeat > 1) {
210                     $repeats{$val} = $repeat;
211                 }
212             }
213         } else {
214             die "$name: $.: Garbage found in config\n$_";
215         }
216     }
217
218     close(IN);
219
220     if ($test_num) {
221         $test_num += $repeat - 1;
222         $opt{"NUM_TESTS"} = $test_num;
223     }
224
225     # set any defaults
226
227     foreach my $default (keys %default) {
228         if (!defined($opt{$default})) {
229             $opt{$default} = $default{$default};
230         }
231     }
232 }
233
234 sub _logit {
235     if (defined($opt{"LOG_FILE"})) {
236         open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
237         print OUT @_;
238         close(OUT);
239     }
240 }
241
242 sub logit {
243     if (defined($opt{"LOG_FILE"})) {
244         _logit @_;
245     } else {
246         print @_;
247     }
248 }
249
250 sub doprint {
251     print @_;
252     _logit @_;
253 }
254
255 sub run_command;
256
257 sub reboot {
258     # try to reboot normally
259     if (run_command "ssh $target reboot") {
260         if (defined($powercycle_after_reboot)) {
261             sleep $powercycle_after_reboot;
262             run_command "$power_cycle";
263         }
264     } else {
265         # nope? power cycle it.
266         run_command "$power_cycle";
267     }
268 }
269
270 sub do_not_reboot {
271     my $i = $iteration;
272
273     return $test_type eq "build" ||
274         ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") ||
275         ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build");
276 }
277
278 sub dodie {
279     doprint "CRITICAL FAILURE... ", @_, "\n";
280
281     my $i = $iteration;
282
283     if ($reboot_on_error && !do_not_reboot) {
284
285         doprint "REBOOTING\n";
286         reboot;
287
288     } elsif ($poweroff_on_error && defined($power_off)) {
289         doprint "POWERING OFF\n";
290         `$power_off`;
291     }
292
293     die @_, "\n";
294 }
295
296 sub open_console {
297     my ($fp) = @_;
298
299     my $flags;
300
301     my $pid = open($fp, "$console|") or
302         dodie "Can't open console $console";
303
304     $flags = fcntl($fp, F_GETFL, 0) or
305         dodie "Can't get flags for the socket: $!";
306     $flags = fcntl($fp, F_SETFL, $flags | O_NONBLOCK) or
307         dodie "Can't set flags for the socket: $!";
308
309     return $pid;
310 }
311
312 sub close_console {
313     my ($fp, $pid) = @_;
314
315     doprint "kill child process $pid\n";
316     kill 2, $pid;
317
318     print "closing!\n";
319     close($fp);
320 }
321
322 sub start_monitor {
323     if ($monitor_cnt++) {
324         return;
325     }
326     $monitor_fp = \*MONFD;
327     $monitor_pid = open_console $monitor_fp;
328
329     return;
330
331     open(MONFD, "Stop perl from warning about single use of MONFD");
332 }
333
334 sub end_monitor {
335     if (--$monitor_cnt) {
336         return;
337     }
338     close_console($monitor_fp, $monitor_pid);
339 }
340
341 sub wait_for_monitor {
342     my ($time) = @_;
343     my $line;
344
345     doprint "** Wait for monitor to settle down **\n";
346
347     # read the monitor and wait for the system to calm down
348     do {
349         $line = wait_for_input($monitor_fp, $time);
350         print "$line" if (defined($line));
351     } while (defined($line));
352     print "** Monitor flushed **\n";
353 }
354
355 sub fail {
356
357         if ($die_on_failure) {
358                 dodie @_;
359         }
360
361         doprint "FAILED\n";
362
363         my $i = $iteration;
364
365         # no need to reboot for just building.
366         if (!do_not_reboot) {
367             doprint "REBOOTING\n";
368             reboot;
369             start_monitor;
370             wait_for_monitor $sleep_time;
371             end_monitor;
372         }
373
374         doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
375         doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
376         doprint "**** Failed: ", @_, " ****\n";
377         doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
378         doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
379
380         return 1 if (!defined($store_failures));
381
382         my @t = localtime;
383         my $date = sprintf "%04d%02d%02d%02d%02d%02d",
384                 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
385
386         my $dir = "$machine-$test_type-$build_type-fail-$date";
387         my $faildir = "$store_failures/$dir";
388
389         if (!-d $faildir) {
390             mkpath($faildir) or
391                 die "can't create $faildir";
392         }
393         if (-f "$output_config") {
394             cp "$output_config", "$faildir/config" or
395                 die "failed to copy .config";
396         }
397         if (-f $buildlog) {
398             cp $buildlog, "$faildir/buildlog" or
399                 die "failed to move $buildlog";
400         }
401         if (-f $dmesg) {
402             cp $dmesg, "$faildir/dmesg" or
403                 die "failed to move $dmesg";
404         }
405
406         doprint "*** Saved info to $faildir ***\n";
407
408         return 1;
409 }
410
411 sub run_command {
412     my ($command) = @_;
413     my $dolog = 0;
414     my $dord = 0;
415     my $pid;
416
417     doprint("$command ... ");
418
419     $pid = open(CMD, "$command 2>&1 |") or
420         (fail "unable to exec $command" and return 0);
421
422     if (defined($opt{"LOG_FILE"})) {
423         open(LOG, ">>$opt{LOG_FILE}") or
424             dodie "failed to write to log";
425         $dolog = 1;
426     }
427
428     if (defined($redirect)) {
429         open (RD, ">$redirect") or
430             dodie "failed to write to redirect $redirect";
431         $dord = 1;
432     }
433
434     while (<CMD>) {
435         print LOG if ($dolog);
436         print RD  if ($dord);
437     }
438
439     waitpid($pid, 0);
440     my $failed = $?;
441
442     close(CMD);
443     close(LOG) if ($dolog);
444     close(RD)  if ($dord);
445
446     if ($failed) {
447         doprint "FAILED!\n";
448     } else {
449         doprint "SUCCESS\n";
450     }
451
452     return !$failed;
453 }
454
455 sub get_grub_index {
456
457     if ($reboot_type ne "grub") {
458         return;
459     }
460     return if (defined($grub_number));
461
462     doprint "Find grub menu ... ";
463     $grub_number = -1;
464     open(IN, "ssh $target cat /boot/grub/menu.lst |")
465         or die "unable to get menu.lst";
466     while (<IN>) {
467         if (/^\s*title\s+$grub_menu\s*$/) {
468             $grub_number++;
469             last;
470         } elsif (/^\s*title\s/) {
471             $grub_number++;
472         }
473     }
474     close(IN);
475
476     die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
477         if ($grub_number < 0);
478     doprint "$grub_number\n";
479 }
480
481 sub wait_for_input
482 {
483     my ($fp, $time) = @_;
484     my $rin;
485     my $ready;
486     my $line;
487     my $ch;
488
489     if (!defined($time)) {
490         $time = $timeout;
491     }
492
493     $rin = '';
494     vec($rin, fileno($fp), 1) = 1;
495     $ready = select($rin, undef, undef, $time);
496
497     $line = "";
498
499     # try to read one char at a time
500     while (sysread $fp, $ch, 1) {
501         $line .= $ch;
502         last if ($ch eq "\n");
503     }
504
505     if (!length($line)) {
506         return undef;
507     }
508
509     return $line;
510 }
511
512 sub reboot_to {
513     if ($reboot_type eq "grub") {
514         run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
515         return;
516     }
517
518     run_command "$reboot_script";
519 }
520
521 sub get_sha1 {
522     my ($commit) = @_;
523
524     doprint "git rev-list --max-count=1 $commit ... ";
525     my $sha1 = `git rev-list --max-count=1 $commit`;
526     my $ret = $?;
527
528     logit $sha1;
529
530     if ($ret) {
531         doprint "FAILED\n";
532         dodie "Failed to get git $commit";
533     }
534
535     print "SUCCESS\n";
536
537     chomp $sha1;
538
539     return $sha1;
540 }
541
542 sub monitor {
543     my $booted = 0;
544     my $bug = 0;
545     my $skip_call_trace = 0;
546     my $loops;
547
548     wait_for_monitor 5;
549
550     my $line;
551     my $full_line = "";
552
553     open(DMESG, "> $dmesg") or
554         die "unable to write to $dmesg";
555
556     reboot_to;
557
558     for (;;) {
559
560         if ($booted) {
561             $line = wait_for_input($monitor_fp, $booted_timeout);
562         } else {
563             $line = wait_for_input($monitor_fp);
564         }
565
566         last if (!defined($line));
567
568         doprint $line;
569         print DMESG $line;
570
571         # we are not guaranteed to get a full line
572         $full_line .= $line;
573
574         if ($full_line =~ /$success_line/) {
575             $booted = 1;
576         }
577
578         if ($full_line =~ /\[ backtrace testing \]/) {
579             $skip_call_trace = 1;
580         }
581
582         if ($full_line =~ /call trace:/i) {
583             $bug = 1 if (!$skip_call_trace);
584         }
585
586         if ($full_line =~ /\[ end of backtrace testing \]/) {
587             $skip_call_trace = 0;
588         }
589
590         if ($full_line =~ /Kernel panic -/) {
591             $bug = 1;
592         }
593
594         if ($line =~ /\n/) {
595             $full_line = "";
596         }
597     }
598
599     close(DMESG);
600
601     if ($bug) {
602         return 0 if ($in_bisect);
603         fail "failed - got a bug report" and return 0;
604     }
605
606     if (!$booted) {
607         return 0 if ($in_bisect);
608         fail "failed - never got a boot prompt." and return 0;
609     }
610
611     return 1;
612 }
613
614 sub install {
615
616     run_command "scp $outputdir/$build_target $target:$target_image" or
617         dodie "failed to copy image";
618
619     my $install_mods = 0;
620
621     # should we process modules?
622     $install_mods = 0;
623     open(IN, "$output_config") or dodie("Can't read config file");
624     while (<IN>) {
625         if (/CONFIG_MODULES(=y)?/) {
626             $install_mods = 1 if (defined($1));
627             last;
628         }
629     }
630     close(IN);
631
632     if (!$install_mods) {
633         doprint "No modules needed\n";
634         return;
635     }
636
637     run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or
638         dodie "Failed to install modules";
639
640     my $modlib = "/lib/modules/$version";
641     my $modtar = "ktest-mods.tar.bz2";
642
643     run_command "ssh $target rm -rf $modlib" or
644         dodie "failed to remove old mods: $modlib";
645
646     # would be nice if scp -r did not follow symbolic links
647     run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or
648         dodie "making tarball";
649
650     run_command "scp $tmpdir/$modtar $target:/tmp" or
651         dodie "failed to copy modules";
652
653     unlink "$tmpdir/$modtar";
654
655     run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'" or
656         dodie "failed to tar modules";
657
658     run_command "ssh $target rm -f /tmp/$modtar";
659
660     return if (!defined($post_install));
661
662     my $save_env = $ENV{KERNEL_VERSION};
663
664     $ENV{KERNEL_VERSION} = $version;
665     run_command "$post_install" or
666         dodie "Failed to run post install";
667
668     $ENV{KERNEL_VERSION} = $save_env;
669 }
670
671 sub check_buildlog {
672     my ($patch) = @_;
673
674     my @files = `git show $patch | diffstat -l`;
675
676     open(IN, "git show $patch |") or
677         dodie "failed to show $patch";
678     while (<IN>) {
679         if (m,^--- a/(.*),) {
680             chomp $1;
681             $files[$#files] = $1;
682         }
683     }
684     close(IN);
685
686     open(IN, $buildlog) or dodie "Can't open $buildlog";
687     while (<IN>) {
688         if (/^\s*(.*?):.*(warning|error)/) {
689             my $err = $1;
690             foreach my $file (@files) {
691                 my $fullpath = "$builddir/$file";
692                 if ($file eq $err || $fullpath eq $err) {
693                     fail "$file built with warnings" and return 0;
694                 }
695             }
696         }
697     }
698     close(IN);
699
700     return 1;
701 }
702
703 sub build {
704     my ($type) = @_;
705     my $defconfig = "";
706
707     unlink $buildlog;
708
709     if ($type =~ /^useconfig:(.*)/) {
710         run_command "cp $1 $output_config" or
711             dodie "could not copy $1 to .config";
712
713         $type = "oldconfig";
714     }
715
716     # old config can ask questions
717     if ($type eq "oldconfig") {
718         $type = "oldnoconfig";
719
720         # allow for empty configs
721         run_command "touch $output_config";
722
723         run_command "mv $output_config $outputdir/config_temp" or
724             dodie "moving .config";
725
726         if (!$noclean && !run_command "$make mrproper") {
727             dodie "make mrproper";
728         }
729
730         run_command "mv $outputdir/config_temp $output_config" or
731             dodie "moving config_temp";
732
733     } elsif (!$noclean) {
734         unlink "$output_config";
735         run_command "$make mrproper" or
736             dodie "make mrproper";
737     }
738
739     # add something to distinguish this build
740     open(OUT, "> $outputdir/localversion") or dodie("Can't make localversion file");
741     print OUT "$localversion\n";
742     close(OUT);
743
744     if (defined($minconfig)) {
745         $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
746     }
747
748     run_command "$defconfig $make $type" or
749         dodie "failed make config";
750
751     $redirect = "$buildlog";
752     if (!run_command "$make $build_options") {
753         undef $redirect;
754         # bisect may need this to pass
755         return 0 if ($in_bisect);
756         fail "failed build" and return 0;
757     }
758     undef $redirect;
759
760     return 1;
761 }
762
763 sub halt {
764     if (!run_command "ssh $target halt" or defined($power_off)) {
765         if (defined($poweroff_after_halt)) {
766             sleep $poweroff_after_halt;
767             run_command "$power_off";
768         }
769     } else {
770         # nope? the zap it!
771         run_command "$power_off";
772     }
773 }
774
775 sub success {
776     my ($i) = @_;
777
778     doprint "\n\n*******************************************\n";
779     doprint     "*******************************************\n";
780     doprint     "**           TEST $i SUCCESS!!!!         **\n";
781     doprint     "*******************************************\n";
782     doprint     "*******************************************\n";
783
784     if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
785         doprint "Reboot and wait $sleep_time seconds\n";
786         reboot;
787         start_monitor;
788         wait_for_monitor $sleep_time;
789         end_monitor;
790     }
791 }
792
793 sub get_version {
794     # get the release name
795     doprint "$make kernelrelease ... ";
796     $version = `$make kernelrelease | tail -1`;
797     chomp($version);
798     doprint "$version\n";
799 }
800
801 sub child_run_test {
802     my $failed = 0;
803
804     # child should have no power
805     $reboot_on_error = 0;
806     $poweroff_on_error = 0;
807     $die_on_failure = 1;
808
809     run_command $run_test or $failed = 1;
810     exit $failed;
811 }
812
813 my $child_done;
814
815 sub child_finished {
816     $child_done = 1;
817 }
818
819 sub do_run_test {
820     my $child_pid;
821     my $child_exit;
822     my $line;
823     my $full_line;
824     my $bug = 0;
825
826     wait_for_monitor 1;
827
828     doprint "run test $run_test\n";
829
830     $child_done = 0;
831
832     $SIG{CHLD} = qw(child_finished);
833
834     $child_pid = fork;
835
836     child_run_test if (!$child_pid);
837
838     $full_line = "";
839
840     do {
841         $line = wait_for_input($monitor_fp, 1);
842         if (defined($line)) {
843
844             # we are not guaranteed to get a full line
845             $full_line .= $line;
846
847             if ($full_line =~ /call trace:/i) {
848                 $bug = 1;
849             }
850
851             if ($full_line =~ /Kernel panic -/) {
852                 $bug = 1;
853             }
854
855             if ($line =~ /\n/) {
856                 $full_line = "";
857             }
858         }
859     } while (!$child_done && !$bug);
860
861     if ($bug) {
862         doprint "Detected kernel crash!\n";
863         # kill the child with extreme prejudice
864         kill 9, $child_pid;
865     }
866
867     waitpid $child_pid, 0;
868     $child_exit = $?;
869
870     if ($bug || $child_exit) {
871         return 0 if $in_bisect;
872         fail "test failed" and return 0;
873     }
874     return 1;
875 }
876
877 sub run_git_bisect {
878     my ($command) = @_;
879
880     doprint "$command ... ";
881
882     my $output = `$command 2>&1`;
883     my $ret = $?;
884
885     logit $output;
886
887     if ($ret) {
888         doprint "FAILED\n";
889         dodie "Failed to git bisect";
890     }
891
892     doprint "SUCCESS\n";
893     if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
894         doprint "$1 [$2]\n";
895     } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
896         $bisect_bad = $1;
897         doprint "Found bad commit... $1\n";
898         return 0;
899     } else {
900         # we already logged it, just print it now.
901         print $output;
902     }
903
904     return 1;
905 }
906
907 sub run_bisect {
908     my ($type) = @_;
909
910     my $failed = 0;
911     my $result;
912     my $output;
913     my $ret;
914
915     if (defined($minconfig)) {
916         build "useconfig:$minconfig" or $failed = 1;
917     } else {
918         # ?? no config to use?
919         build "oldconfig" or $failed = 1;
920     }
921
922     if ($type ne "build") {
923         dodie "Failed on build" if $failed;
924
925         # Now boot the box
926         get_grub_index;
927         get_version;
928         install;
929
930         start_monitor;
931         monitor or $failed = 1;
932
933         if ($type ne "boot") {
934             dodie "Failed on boot" if $failed;
935
936             do_run_test or $failed = 1;
937         }
938         end_monitor;
939     }
940
941     if ($failed) {
942         $result = "bad";
943
944         # reboot the box to a good kernel
945         if ($type ne "build") {
946             doprint "Reboot and sleep $bisect_sleep_time seconds\n";
947             reboot;
948             start_monitor;
949             wait_for_monitor $bisect_sleep_time;
950             end_monitor;
951         }
952     } else {
953         $result = "good";
954     }
955
956     # Are we looking for where it worked, not failed?
957     if ($reverse_bisect) {
958         if ($failed) {
959             $result = "good";
960         } else {
961             $result = "bad";
962         }
963     }
964
965     return $result;
966 }
967
968 sub bisect {
969     my ($i) = @_;
970
971     my $result;
972
973     die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"}));
974     die "BISECT_BAD[$i] not defined\n"  if (!defined($opt{"BISECT_BAD[$i]"}));
975     die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"}));
976
977     my $good = $opt{"BISECT_GOOD[$i]"};
978     my $bad = $opt{"BISECT_BAD[$i]"};
979     my $type = $opt{"BISECT_TYPE[$i]"};
980     my $start = $opt{"BISECT_START[$i]"};
981     my $replay = $opt{"BISECT_REPLAY[$i]"};
982
983     # convert to true sha1's
984     $good = get_sha1($good);
985     $bad = get_sha1($bad);
986
987     if (defined($opt{"BISECT_REVERSE[$i]"}) &&
988         $opt{"BISECT_REVERSE[$i]"} == 1) {
989         doprint "Performing a reverse bisect (bad is good, good is bad!)\n";
990         $reverse_bisect = 1;
991     } else {
992         $reverse_bisect = 0;
993     }
994
995     $in_bisect = 1;
996
997     # Can't have a test without having a test to run
998     if ($type eq "test" && !defined($run_test)) {
999         $type = "boot";
1000     }
1001
1002     my $check = $opt{"BISECT_CHECK[$i]"};
1003     if (defined($check) && $check ne "0") {
1004
1005         # get current HEAD
1006         my $head = get_sha1("HEAD");
1007
1008         if ($check ne "good") {
1009             doprint "TESTING BISECT BAD [$bad]\n";
1010             run_command "git checkout $bad" or
1011                 die "Failed to checkout $bad";
1012
1013             $result = run_bisect $type;
1014
1015             if ($result ne "bad") {
1016                 fail "Tested BISECT_BAD [$bad] and it succeeded" and return 0;
1017             }
1018         }
1019
1020         if ($check ne "bad") {
1021             doprint "TESTING BISECT GOOD [$good]\n";
1022             run_command "git checkout $good" or
1023                 die "Failed to checkout $good";
1024
1025             $result = run_bisect $type;
1026
1027             if ($result ne "good") {
1028                 fail "Tested BISECT_GOOD [$good] and it failed" and return 0;
1029             }
1030         }
1031
1032         # checkout where we started
1033         run_command "git checkout $head" or
1034             die "Failed to checkout $head";
1035     }
1036
1037     run_command "git bisect start" or
1038         dodie "could not start bisect";
1039
1040     run_command "git bisect good $good" or
1041         dodie "could not set bisect good to $good";
1042
1043     run_git_bisect "git bisect bad $bad" or
1044         dodie "could not set bisect bad to $bad";
1045
1046     if (defined($replay)) {
1047         run_command "git bisect replay $replay" or
1048             dodie "failed to run replay";
1049     }
1050
1051     if (defined($start)) {
1052         run_command "git checkout $start" or
1053             dodie "failed to checkout $start";
1054     }
1055
1056     my $test;
1057     do {
1058         $result = run_bisect $type;
1059         $test = run_git_bisect "git bisect $result";
1060     } while ($test);
1061
1062     run_command "git bisect log" or
1063         dodie "could not capture git bisect log";
1064
1065     run_command "git bisect reset" or
1066         dodie "could not reset git bisect";
1067
1068     doprint "Bad commit was [$bisect_bad]\n";
1069
1070     $in_bisect = 0;
1071
1072     success $i;
1073 }
1074
1075 sub patchcheck {
1076     my ($i) = @_;
1077
1078     die "PATCHCHECK_START[$i] not defined\n"
1079         if (!defined($opt{"PATCHCHECK_START[$i]"}));
1080     die "PATCHCHECK_TYPE[$i] not defined\n"
1081         if (!defined($opt{"PATCHCHECK_TYPE[$i]"}));
1082
1083     my $start = $opt{"PATCHCHECK_START[$i]"};
1084
1085     my $end = "HEAD";
1086     if (defined($opt{"PATCHCHECK_END[$i]"})) {
1087         $end = $opt{"PATCHCHECK_END[$i]"};
1088     }
1089
1090     # Get the true sha1's since we can use things like HEAD~3
1091     $start = get_sha1($start);
1092     $end = get_sha1($end);
1093
1094     my $type = $opt{"PATCHCHECK_TYPE[$i]"};
1095
1096     # Can't have a test without having a test to run
1097     if ($type eq "test" && !defined($run_test)) {
1098         $type = "boot";
1099     }
1100
1101     open (IN, "git log --pretty=oneline $end|") or
1102         dodie "could not get git list";
1103
1104     my @list;
1105
1106     while (<IN>) {
1107         chomp;
1108         $list[$#list+1] = $_;
1109         last if (/^$start/);
1110     }
1111     close(IN);
1112
1113     if ($list[$#list] !~ /^$start/) {
1114         fail "SHA1 $start not found";
1115     }
1116
1117     # go backwards in the list
1118     @list = reverse @list;
1119
1120     my $save_clean = $noclean;
1121
1122     $in_patchcheck = 1;
1123     foreach my $item (@list) {
1124         my $sha1 = $item;
1125         $sha1 =~ s/^([[:xdigit:]]+).*/$1/;
1126
1127         doprint "\nProcessing commit $item\n\n";
1128
1129         run_command "git checkout $sha1" or
1130             die "Failed to checkout $sha1";
1131
1132         # only clean on the first and last patch
1133         if ($item eq $list[0] ||
1134             $item eq $list[$#list]) {
1135             $noclean = $save_clean;
1136         } else {
1137             $noclean = 1;
1138         }
1139
1140         if (defined($minconfig)) {
1141             build "useconfig:$minconfig" or return 0;
1142         } else {
1143             # ?? no config to use?
1144             build "oldconfig" or return 0;
1145         }
1146
1147         check_buildlog $sha1 or return 0;
1148
1149         next if ($type eq "build");
1150
1151         get_grub_index;
1152         get_version;
1153         install;
1154
1155         my $failed = 0;
1156
1157         start_monitor;
1158         monitor or $failed = 1;
1159
1160         if (!$failed && $type ne "boot"){
1161             do_run_test or $failed = 1;
1162         }
1163         end_monitor;
1164         return 0 if ($failed);
1165
1166     }
1167     $in_patchcheck = 0;
1168     success $i;
1169
1170     return 1;
1171 }
1172
1173 read_config $ARGV[0];
1174
1175 # mandatory configs
1176 die "MACHINE not defined\n"             if (!defined($opt{"MACHINE"}));
1177 die "SSH_USER not defined\n"            if (!defined($opt{"SSH_USER"}));
1178 die "BUILD_DIR not defined\n"           if (!defined($opt{"BUILD_DIR"}));
1179 die "OUTPUT_DIR not defined\n"          if (!defined($opt{"OUTPUT_DIR"}));
1180 die "BUILD_TARGET not defined\n"        if (!defined($opt{"BUILD_TARGET"}));
1181 die "TARGET_IMAGE not defined\n"        if (!defined($opt{"TARGET_IMAGE"}));
1182 die "POWER_CYCLE not defined\n"         if (!defined($opt{"POWER_CYCLE"}));
1183 die "CONSOLE not defined\n"             if (!defined($opt{"CONSOLE"}));
1184 die "LOCALVERSION not defined\n"        if (!defined($opt{"LOCALVERSION"}));
1185
1186 if ($opt{"CLEAR_LOG"} && defined($opt{"LOG_FILE"})) {
1187     unlink $opt{"LOG_FILE"};
1188 }
1189
1190 doprint "\n\nSTARTING AUTOMATED TESTS\n\n";
1191
1192 for (my $i = 0, my $repeat = 1; $i <= $opt{"NUM_TESTS"}; $i += $repeat) {
1193
1194     if (!$i) {
1195         doprint "DEFAULT OPTIONS:\n";
1196     } else {
1197         doprint "\nTEST $i OPTIONS";
1198         if (defined($repeat_tests{$i})) {
1199             $repeat = $repeat_tests{$i};
1200             doprint " ITERATE $repeat";
1201         }
1202         doprint "\n";
1203     }
1204
1205     foreach my $option (sort keys %opt) {
1206
1207         if ($option =~ /\[(\d+)\]$/) {
1208             next if ($i != $1);
1209         } else {
1210             next if ($i);
1211         }
1212
1213         doprint "$option = $opt{$option}\n";
1214     }
1215 }
1216
1217 sub set_test_option {
1218     my ($name, $i) = @_;
1219
1220     my $option = "$name\[$i\]";
1221
1222     if (defined($opt{$option})) {
1223         return $opt{$option};
1224     }
1225
1226     foreach my $test (keys %repeat_tests) {
1227         if ($i >= $test &&
1228             $i < $test + $repeat_tests{$test}) {
1229             $option = "$name\[$test\]";
1230             if (defined($opt{$option})) {
1231                 return $opt{$option};
1232             }
1233         }
1234     }
1235
1236     if (defined($opt{$name})) {
1237         return $opt{$name};
1238     }
1239
1240     return undef;
1241 }
1242
1243 # First we need to do is the builds
1244 for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
1245
1246     $iteration = $i;
1247
1248     my $ssh_user = set_test_option("SSH_USER", $i);
1249     my $makecmd = set_test_option("MAKE_CMD", $i);
1250
1251     $machine = set_test_option("MACHINE", $i);
1252     $tmpdir = set_test_option("TMP_DIR", $i);
1253     $outputdir = set_test_option("OUTPUT_DIR", $i);
1254     $builddir = set_test_option("BUILD_DIR", $i);
1255     $test_type = set_test_option("TEST_TYPE", $i);
1256     $build_type = set_test_option("BUILD_TYPE", $i);
1257     $build_options = set_test_option("BUILD_OPTIONS", $i);
1258     $power_cycle = set_test_option("POWER_CYCLE", $i);
1259     $noclean = set_test_option("BUILD_NOCLEAN", $i);
1260     $minconfig = set_test_option("MIN_CONFIG", $i);
1261     $run_test = set_test_option("TEST", $i);
1262     $addconfig = set_test_option("ADD_CONFIG", $i);
1263     $reboot_type = set_test_option("REBOOT_TYPE", $i);
1264     $grub_menu = set_test_option("GRUB_MENU", $i);
1265     $post_install = set_test_option("POST_INSTALL", $i);
1266     $reboot_script = set_test_option("REBOOT_SCRIPT", $i);
1267     $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i);
1268     $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i);
1269     $die_on_failure = set_test_option("DIE_ON_FAILURE", $i);
1270     $power_off = set_test_option("POWER_OFF", $i);
1271     $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i);
1272     $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i);
1273     $sleep_time = set_test_option("SLEEP_TIME", $i);
1274     $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i);
1275     $store_failures = set_test_option("STORE_FAILURES", $i);
1276     $timeout = set_test_option("TIMEOUT", $i);
1277     $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
1278     $console = set_test_option("CONSOLE", $i);
1279     $success_line = set_test_option("SUCCESS_LINE", $i);
1280     $build_target = set_test_option("BUILD_TARGET", $i);
1281     $target_image = set_test_option("TARGET_IMAGE", $i);
1282     $localversion = set_test_option("LOCALVERSION", $i);
1283
1284     chdir $builddir || die "can't change directory to $builddir";
1285
1286     if (!-d $tmpdir) {
1287         mkpath($tmpdir) or
1288             die "can't create $tmpdir";
1289     }
1290
1291     $target = "$ssh_user\@$machine";
1292
1293     $buildlog = "$tmpdir/buildlog-$machine";
1294     $dmesg = "$tmpdir/dmesg-$machine";
1295     $make = "$makecmd O=$outputdir";
1296     $output_config = "$outputdir/.config";
1297
1298     if ($reboot_type eq "grub") {
1299         dodie "GRUB_MENU not defined" if (!defined($grub_menu));
1300     } elsif (!defined($reboot_script)) {
1301         dodie "REBOOT_SCRIPT not defined"
1302     }
1303
1304     my $run_type = $build_type;
1305     if ($test_type eq "patchcheck") {
1306         $run_type = $opt{"PATCHCHECK_TYPE[$i]"};
1307     } elsif ($test_type eq "bisect") {
1308         $run_type = $opt{"BISECT_TYPE[$i]"};
1309     }
1310
1311     # mistake in config file?
1312     if (!defined($run_type)) {
1313         $run_type = "ERROR";
1314     }
1315
1316     doprint "\n\n";
1317     doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n";
1318
1319     unlink $dmesg;
1320     unlink $buildlog;
1321
1322     if (!defined($minconfig)) {
1323         $minconfig = $addconfig;
1324
1325     } elsif (defined($addconfig)) {
1326         run_command "cat $addconfig $minconfig > $tmpdir/use_config" or
1327             dodie "Failed to create temp config";
1328         $minconfig = "$tmpdir/use_config";
1329     }
1330
1331     my $checkout = $opt{"CHECKOUT[$i]"};
1332     if (defined($checkout)) {
1333         run_command "git checkout $checkout" or
1334             die "failed to checkout $checkout";
1335     }
1336
1337     if ($test_type eq "bisect") {
1338         bisect $i;
1339         next;
1340     } elsif ($test_type eq "patchcheck") {
1341         patchcheck $i;
1342         next;
1343     }
1344
1345     if ($build_type ne "nobuild") {
1346         build $build_type or next;
1347     }
1348
1349     if ($test_type ne "build") {
1350         get_grub_index;
1351         get_version;
1352         install;
1353
1354         my $failed = 0;
1355         start_monitor;
1356         monitor or $failed = 1;;
1357
1358         if (!$failed && $test_type ne "boot" && defined($run_test)) {
1359             do_run_test or $failed = 1;
1360         }
1361         end_monitor;
1362         next if ($failed);
1363     }
1364
1365     success $i;
1366 }
1367
1368 if ($opt{"POWEROFF_ON_SUCCESS"}) {
1369     halt;
1370 } elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) {
1371     reboot;
1372 }
1373
1374 exit 0;