f344fd0d4f28e4c0a538839c2189a9d24181885a
[platform/adaptation/renesas_rcar/renesas_kernel.git] / tools / testing / ktest / ktest.pl
1 #!/usr/bin/perl -w
2
3 use strict;
4 use IPC::Open2;
5 use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
6 use FileHandle;
7
8 $#ARGV >= 0 || die "usage: autotest.pl config-file\n";
9
10 $| = 1;
11
12 my %opt;
13
14 #default opts
15 $opt{"NUM_BUILDS"}              = 5;
16 $opt{"DEFAULT_BUILD_TYPE"}      = "randconfig";
17 $opt{"MAKE_CMD"}                = "make";
18 $opt{"TIMEOUT"}                 = 50;
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
28
29 my $version;
30 my $grub_number;
31 my $target;
32 my $make;
33 my $noclean;
34 my $minconfig;
35 my $in_bisect = 0;
36 my $bisect_bad = "";
37 my $run_test;
38
39 sub read_config {
40     my ($config) = @_;
41
42     open(IN, $config) || die "can't read file $config";
43
44     while (<IN>) {
45
46         # ignore blank lines and comments
47         next if (/^\s*$/ || /\s*\#/);
48
49         if (/^\s*(\S+)\s*=\s*(.*?)\s*$/) {
50             my $lvalue = $1;
51             my $rvalue = $2;
52
53             $opt{$lvalue} = $rvalue;
54         }
55     }
56
57     close(IN);
58 }
59
60 sub logit {
61     if (defined($opt{"LOG_FILE"})) {
62         open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
63         print OUT @_;
64         close(OUT);
65     }
66 }
67
68 sub doprint {
69     print @_;
70     logit @_;
71 }
72
73 sub dodie {
74     doprint "CRITICAL FAILURE... ", @_, "\n";
75
76     if ($opt{"REBOOT_ON_ERROR"}) {
77         doprint "REBOOTING\n";
78         `$opt{"POWER_CYCLE"}`;
79
80     } elsif ($opt{"POWEROFF_ON_ERROR"} && defined($opt{"POWER_OFF"})) {
81         doprint "POWERING OFF\n";
82         `$opt{"POWER_OFF"}`;
83     }
84
85     die @_;
86 }
87
88 sub run_command {
89     my ($command) = @_;
90     my $redirect_log = "";
91
92     if (defined($opt{"LOG_FILE"})) {
93         $redirect_log = " >> $opt{LOG_FILE} 2>&1";
94     }
95
96     doprint "$command ... ";
97     `$command $redirect_log`;
98
99     my $failed = $?;
100
101     if ($failed) {
102         doprint "FAILED!\n";
103     } else {
104         doprint "SUCCESS\n";
105     }
106
107     return !$failed;
108 }
109
110 sub get_grub_index {
111
112     return if (defined($grub_number));
113
114     doprint "Find grub menu ... ";
115     $grub_number = -1;
116     open(IN, "ssh $target cat /boot/grub/menu.lst |")
117         or die "unable to get menu.lst";
118     while (<IN>) {
119         if (/^\s*title\s+$opt{GRUB_MENU}\s*$/) {
120             $grub_number++;
121             last;
122         } elsif (/^\s*title\s/) {
123             $grub_number++;
124         }
125     }
126     close(IN);
127
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";
131 }
132
133 my $timeout = $opt{"TIMEOUT"};
134
135 sub wait_for_input
136 {
137     my ($fp, $time) = @_;
138     my $rin;
139     my $ready;
140     my $line;
141     my $ch;
142
143     if (!defined($time)) {
144         $time = $timeout;
145     }
146
147     $rin = '';
148     vec($rin, fileno($fp), 1) = 1;
149     $ready = select($rin, undef, undef, $time);
150
151     $line = "";
152
153     # try to read one char at a time
154     while (sysread $fp, $ch, 1) {
155         $line .= $ch;
156         last if ($ch eq "\n");
157     }
158
159     if (!length($line)) {
160         return undef;
161     }
162
163     return $line;
164 }
165
166 sub reboot_to {
167     run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
168 }
169
170 sub open_console {
171     my ($fp) = @_;
172
173     my $flags;
174
175     my $pid = open($fp, "$opt{CONSOLE}|") or
176         dodie "Can't open console $opt{CONSOLE}";
177
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";
182
183     return $pid;
184 }
185
186 sub close_console {
187     my ($fp, $pid) = @_;
188
189     doprint "kill child process $pid\n";
190     kill 2, $pid;
191
192     print "closing!\n";
193     close($fp);
194 }
195
196 sub monitor {
197     my $booted = 0;
198     my $bug = 0;
199     my $pid;
200     my $skip_call_trace = 0;
201     my $fp = \*IN;
202
203     $pid = open_console($fp);
204
205     my $line;
206     my $full_line = "";
207
208     doprint "Wait for monitor to settle down.\n";
209     # read the monitor and wait for the system to calm down
210     do {
211         $line = wait_for_input($fp, 5);
212     } while (defined($line));
213
214     reboot_to;
215
216     for (;;) {
217
218         $line = wait_for_input($fp);
219
220         last if (!defined($line));
221
222         doprint $line;
223
224         # we are not guaranteed to get a full line
225         $full_line .= $line;
226
227         if ($full_line =~ /login:/) {
228             $booted = 1;
229         }
230
231         if ($full_line =~ /\[ backtrace testing \]/) {
232             $skip_call_trace = 1;
233         }
234
235         if ($full_line =~ /call trace:/i) {
236             $bug = 1 if (!$skip_call_trace);
237         }
238
239         if ($full_line =~ /\[ end of backtrace testing \]/) {
240             $skip_call_trace = 0;
241         }
242
243         if ($full_line =~ /Kernel panic -/) {
244             $bug = 1;
245         }
246
247         if ($line =~ /\n/) {
248             $full_line = "";
249         }
250     }
251
252     close_console($fp, $pid);
253
254     if (!$booted) {
255         return 1 if ($in_bisect);
256         dodie "failed - never got a boot prompt.\n";
257     }
258
259     if ($bug) {
260         return 1 if ($in_bisect);
261         dodie "failed - got a bug report\n";
262     }
263
264     return 0;
265 }
266
267 sub install {
268
269     run_command "scp $opt{OUTPUT_DIR}/$opt{BUILD_TARGET} $target:$opt{TARGET_IMAGE}" or
270         dodie "failed to copy image";
271
272     my $install_mods = 0;
273
274     # should we process modules?
275     $install_mods = 0;
276     open(IN, "$opt{OUTPUT_DIR}/.config") or dodie("Can't read config file");
277     while (<IN>) {
278         if (/CONFIG_MODULES(=y)?/) {
279             $install_mods = 1 if (defined($1));
280             last;
281         }
282     }
283     close(IN);
284
285     if (!$install_mods) {
286         doprint "No modules needed\n";
287         return;
288     }
289
290     run_command "$make INSTALL_MOD_PATH=$opt{TMP_DIR} modules_install" or
291         dodie "Failed to install modules";
292
293     my $modlib = "/lib/modules/$version";
294     my $modtar = "autotest-mods.tar.bz2";
295
296     run_command "ssh $target rm -rf $modlib" or
297         dodie "failed to remove old mods: $modlib";
298
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";
302
303     run_command "scp $opt{TMP_DIR}/$modtar $target:/tmp" or
304         dodie "failed to copy modules";
305
306     unlink "$opt{TMP_DIR}/$modtar";
307
308     run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'" or
309         dodie "failed to tar modules";
310
311     run_command "ssh $target rm -f /tmp/$modtar";
312 }
313
314 sub build {
315     my ($type) = @_;
316     my $defconfig = "";
317     my $append = "";
318
319     if ($type =~ /^useconfig:(.*)/) {
320         run_command "cp $1 $opt{OUTPUT_DIR}/.config" or
321             dodie "could not copy $1 to .config";
322
323         $type = "oldconfig";
324     }
325
326     # old config can ask questions
327     if ($type eq "oldconfig") {
328         $append = "yes ''|";
329
330         # allow for empty configs
331         run_command "touch $opt{OUTPUT_DIR}/.config";
332
333         run_command "mv $opt{OUTPUT_DIR}/.config $opt{OUTPUT_DIR}/config_temp" or
334             dodie "moving .config";
335
336         if (!$noclean && !run_command "$make mrproper") {
337             dodie "make mrproper";
338         }
339
340         run_command "mv $opt{OUTPUT_DIR}/config_temp $opt{OUTPUT_DIR}/.config" or
341             dodie "moving config_temp";
342
343     } elsif (!$noclean) {
344         unlink "$opt{OUTPUT_DIR}/.config";
345         run_command "$make mrproper" or
346             dodie "make mrproper";
347     }
348
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";
352     close(OUT);
353
354     if (defined($minconfig)) {
355         $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
356     }
357
358     run_command "$defconfig $append $make $type" or
359         dodie "failed make config";
360
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";
365     }
366
367     return 0;
368 }
369
370 sub reboot {
371     # try to reboot normally
372     if (!run_command "ssh $target reboot") {
373         # nope? power cycle it.
374         run_command "$opt{POWER_CYCLE}";
375     }
376 }
377
378 sub halt {
379     if (!run_command "ssh $target halt" or defined($opt{"POWER_OFF"})) {
380         # nope? the zap it!
381         run_command "$opt{POWER_OFF}";
382     }
383 }
384
385 sub success {
386     my ($i) = @_;
387
388     doprint "\n\n*******************************************\n";
389     doprint     "*******************************************\n";
390     doprint     "**            SUCCESS!!!!                **\n";
391     doprint     "*******************************************\n";
392     doprint     "*******************************************\n";
393
394     if ($i != $opt{"NUM_BUILDS"}) {
395         reboot;
396         doprint "Sleeping $opt{SLEEP_TIME} seconds\n";
397         sleep "$opt{SLEEP_TIME}";
398     }
399 }
400
401 sub get_version {
402     # get the release name
403     doprint "$make kernelrelease ... ";
404     $version = `$make kernelrelease | tail -1`;
405     chomp($version);
406     doprint "$version\n";
407 }
408
409 sub child_run_test {
410     my $failed;
411
412     $failed = !run_command $run_test;
413     exit $failed;
414 }
415
416 my $child_done;
417
418 sub child_finished {
419     $child_done = 1;
420 }
421
422 sub do_run_test {
423     my $child_pid;
424     my $child_exit;
425     my $pid;
426     my $line;
427     my $full_line;
428     my $bug = 0;
429     my $fp = \*IN;
430
431     $pid = open_console($fp);
432
433     # read the monitor and wait for the system to calm down
434     do {
435         $line = wait_for_input($fp, 1);
436     } while (defined($line));
437
438     $child_done = 0;
439
440     $SIG{CHLD} = qw(child_finished);
441
442     $child_pid = fork;
443
444     child_run_test if (!$child_pid);
445
446     $full_line = "";
447
448     do {
449         $line = wait_for_input($fp, 1);
450         if (defined($line)) {
451
452             # we are not guaranteed to get a full line
453             $full_line .= $line;
454
455             if ($full_line =~ /call trace:/i) {
456                 $bug = 1;
457             }
458
459             if ($full_line =~ /Kernel panic -/) {
460                 $bug = 1;
461             }
462
463             if ($line =~ /\n/) {
464                 $full_line = "";
465             }
466         }
467     } while (!$child_done && !$bug);
468
469     if ($bug) {
470         doprint "Detected kernel crash!\n";
471         # kill the child with extreme prejudice
472         kill 9, $child_pid;
473     }
474
475     waitpid $child_pid, 0;
476     $child_exit = $?;
477
478     close_console($fp, $pid);
479
480     if ($bug || $child_exit) {
481         return 1 if $in_bisect;
482         dodie "test failed";
483     }
484     return 0;
485 }
486
487 sub run_bisect {
488     my ($type) = @_;
489
490     my $failed;
491     my $result;
492     my $output;
493     my $ret;
494
495
496     if (defined($minconfig)) {
497         $failed = build "useconfig:$minconfig";
498     } else {
499         # ?? no config to use?
500         $failed = build "oldconfig";
501     }
502
503     if ($type ne "build") {
504         dodie "Failed on build" if $failed;
505
506         # Now boot the box
507         get_grub_index;
508         get_version;
509         install;
510         $failed = monitor;
511
512         if ($type ne "boot") {
513             dodie "Failed on boot" if $failed;
514
515             $failed = do_run_test;
516         }
517     }
518
519     if ($failed) {
520         $result = "bad";
521
522         # reboot the box to a good kernel
523         if ($type eq "boot") {
524             reboot;
525             doprint "sleep a little for reboot\n";
526             sleep $opt{"BISECT_SLEEP_TIME"};
527         }
528     } else {
529         $result = "good";
530     }
531
532     doprint "git bisect $result ... ";
533     $output = `git bisect $result 2>&1`;
534     $ret = $?;
535
536     logit $output;
537
538     if ($ret) {
539         doprint "FAILED\n";
540         dodie "Failed to git bisect";
541     }
542
543     doprint "SUCCESS\n";
544     if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
545         doprint "$1 [$2]\n";
546     } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
547         $bisect_bad = $1;
548         doprint "Found bad commit... $1\n";
549         return 0;
550     } else {
551         # we already logged it, just print it now.
552         print $output;
553     }
554
555
556     return 1;
557 }
558
559 sub bisect {
560     my ($i) = @_;
561
562     my $result;
563
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]"}));
567
568     my $good = $opt{"BISECT_GOOD[$i]"};
569     my $bad = $opt{"BISECT_BAD[$i]"};
570     my $type = $opt{"BISECT_TYPE[$i]"};
571
572     $in_bisect = 1;
573
574     run_command "git bisect start" or
575         dodie "could not start bisect";
576
577     run_command "git bisect good $good" or
578         dodie "could not set bisect good to $good";
579
580     run_command "git bisect bad $bad" or
581         dodie "could not set bisect good to $bad";
582
583     # Can't have a test without having a test to run
584     if ($type eq "test" && !defined($run_test)) {
585         $type = "boot";
586     }
587
588     do {
589         $result = run_bisect $type;
590     } while ($result);
591
592     run_command "git bisect log" or
593         dodie "could not capture git bisect log";
594
595     run_command "git bisect reset" or
596         dodie "could not reset git bisect";
597
598     doprint "Bad commit was [$bisect_bad]\n";
599
600     $in_bisect = 0;
601
602     success $i;
603 }
604
605 read_config $ARGV[0];
606
607 # mandatory configs
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"}));
618
619 chdir $opt{"BUILD_DIR"} || die "can't change directory to $opt{BUILD_DIR}";
620
621 $target = "$opt{SSH_USER}\@$opt{MACHINE}";
622
623 doprint "\n\nSTARTING AUTOMATED TESTS\n";
624
625
626 $make = "$opt{MAKE_CMD} O=$opt{OUTPUT_DIR}";
627
628 sub set_build_option {
629     my ($name, $i) = @_;
630
631     my $option = "$name\[$i\]";
632
633     if (defined($opt{$option})) {
634         return $opt{$option};
635     }
636
637     if (defined($opt{$name})) {
638         return $opt{$name};
639     }
640
641     return undef;
642 }
643
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]";
647
648     if (!defined($opt{$type})) {
649         $opt{$type} = $opt{"DEFAULT_BUILD_TYPE"};
650     }
651
652     $noclean = set_build_option("BUILD_NOCLEAN", $i);
653     $minconfig = set_build_option("MIN_CONFIG", $i);
654     $run_test = set_build_option("TEST", $i);
655
656     doprint "\n\n";
657     doprint "RUNNING TEST $i of $opt{NUM_BUILDS} with option $opt{$type}\n\n";
658
659     if ($opt{$type} eq "bisect") {
660         bisect $i;
661         next;
662     }
663
664     if ($opt{$type} ne "nobuild") {
665         build $opt{$type};
666     }
667
668     get_grub_index;
669     get_version;
670     install;
671     monitor;
672
673     if (defined($run_test)) {
674         do_run_test;
675     }
676
677     success $i;
678 }
679
680 if ($opt{"POWEROFF_ON_SUCCESS"}) {
681     halt;
682 } elsif ($opt{"REBOOT_ON_SUCCESS"}) {
683     reboot;
684 }
685
686 exit 0;