ktest: Added reboot on success
[deliverable/linux.git] / tools / testing / ktest / ktest.pl
CommitLineData
2545eb61
SR
1#!/usr/bin/perl -w
2
3use strict;
4use IPC::Open2;
5use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
6use FileHandle;
7
8$#ARGV >= 0 || die "usage: autotest.pl config-file\n";
9
10$| = 1;
11
12my %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
5c42fc5b 21$opt{"BUILD_NOCLEAN"} = 0;
75c3fda7 22$opt{"REBOOT_ON_ERROR"} = 0;
5c42fc5b 23$opt{"POWEROFF_ON_ERROR"} = 0;
1a5cfce3 24$opt{"REBOOT_ON_SUCCESS"} = 1;
5c42fc5b 25$opt{"POWEROFF_ON_SUCCESS"} = 0;
75c3fda7 26$opt{"BUILD_OPTIONS"} = "";
5a391fbf 27$opt{"BISECT_SLEEP_TIME"} = 10; # sleep time between bisects
2545eb61
SR
28
29my $version;
2545eb61
SR
30my $grub_number;
31my $target;
32my $make;
5c42fc5b 33my $noclean;
5f9b6ced
SR
34my $minconfig;
35my $in_bisect = 0;
36my $bisect_bad = "";
5a391fbf 37my $run_test;
2545eb61
SR
38
39sub 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
5f9b6ced 60sub logit {
2545eb61
SR
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
5f9b6ced
SR
68sub doprint {
69 print @_;
70 logit @_;
71}
72
5c42fc5b 73sub dodie {
5a391fbf 74 doprint "CRITICAL FAILURE... ", @_, "\n";
5c42fc5b 75
75c3fda7
SR
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"})) {
5c42fc5b
SR
81 doprint "POWERING OFF\n";
82 `$opt{"POWER_OFF"}`;
83 }
75c3fda7 84
5c42fc5b
SR
85 die @_;
86}
87
2545eb61
SR
88sub run_command {
89 my ($command) = @_;
5a391fbf 90 my $redirect_log = "";
2545eb61
SR
91
92 if (defined($opt{"LOG_FILE"})) {
5a391fbf 93 $redirect_log = " >> $opt{LOG_FILE} 2>&1";
2545eb61
SR
94 }
95
96 doprint "$command ... ";
5a391fbf 97 `$command $redirect_log`;
2545eb61
SR
98
99 my $failed = $?;
100
101 if ($failed) {
102 doprint "FAILED!\n";
103 } else {
104 doprint "SUCCESS\n";
105 }
106
5f9b6ced
SR
107 return !$failed;
108}
109
110sub get_grub_index {
111
5a391fbf 112 return if (defined($grub_number));
5f9b6ced
SR
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";
2545eb61
SR
131}
132
133my $timeout = $opt{"TIMEOUT"};
134
135sub 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
75c3fda7 166sub reboot_to {
2545eb61
SR
167 run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
168}
169
5a391fbf
SR
170sub open_console {
171 my ($fp) = @_;
172
2545eb61 173 my $flags;
5a391fbf
SR
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
186sub 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
196sub monitor {
2545eb61
SR
197 my $booted = 0;
198 my $bug = 0;
199 my $pid;
5c42fc5b 200 my $skip_call_trace = 0;
5a391fbf 201 my $fp = \*IN;
2545eb61 202
5a391fbf 203 $pid = open_console($fp);
2545eb61
SR
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 {
5a391fbf 211 $line = wait_for_input($fp, 5);
2545eb61
SR
212 } while (defined($line));
213
75c3fda7 214 reboot_to;
2545eb61
SR
215
216 for (;;) {
217
5a391fbf 218 $line = wait_for_input($fp);
2545eb61
SR
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
5c42fc5b
SR
231 if ($full_line =~ /\[ backtrace testing \]/) {
232 $skip_call_trace = 1;
233 }
234
2545eb61 235 if ($full_line =~ /call trace:/i) {
5c42fc5b
SR
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 -/) {
2545eb61
SR
244 $bug = 1;
245 }
246
247 if ($line =~ /\n/) {
248 $full_line = "";
249 }
250 }
251
5a391fbf 252 close_console($fp, $pid);
2545eb61
SR
253
254 if (!$booted) {
5a391fbf 255 return 1 if ($in_bisect);
5c42fc5b 256 dodie "failed - never got a boot prompt.\n";
2545eb61
SR
257 }
258
259 if ($bug) {
5a391fbf 260 return 1 if ($in_bisect);
5c42fc5b 261 dodie "failed - got a bug report\n";
2545eb61 262 }
5f9b6ced
SR
263
264 return 0;
2545eb61
SR
265}
266
267sub install {
268
5f9b6ced 269 run_command "scp $opt{OUTPUT_DIR}/$opt{BUILD_TARGET} $target:$opt{TARGET_IMAGE}" or
5c42fc5b 270 dodie "failed to copy image";
2545eb61 271
5f9b6ced 272 my $install_mods = 0;
2545eb61 273
5f9b6ced
SR
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;
5c42fc5b 281 }
5f9b6ced
SR
282 }
283 close(IN);
5c42fc5b 284
5f9b6ced
SR
285 if (!$install_mods) {
286 doprint "No modules needed\n";
287 return;
288 }
2545eb61 289
5f9b6ced
SR
290 run_command "$make INSTALL_MOD_PATH=$opt{TMP_DIR} modules_install" or
291 dodie "Failed to install modules";
5c42fc5b 292
5f9b6ced
SR
293 my $modlib = "/lib/modules/$version";
294 my $modtar = "autotest-mods.tar.bz2";
5c42fc5b 295
5f9b6ced
SR
296 run_command "ssh $target rm -rf $modlib" or
297 dodie "failed to remove old mods: $modlib";
5c42fc5b 298
5f9b6ced
SR
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";
2545eb61 310
5f9b6ced 311 run_command "ssh $target rm -f /tmp/$modtar";
2545eb61
SR
312}
313
314sub build {
315 my ($type) = @_;
5c42fc5b
SR
316 my $defconfig = "";
317 my $append = "";
318
75c3fda7 319 if ($type =~ /^useconfig:(.*)/) {
5f9b6ced 320 run_command "cp $1 $opt{OUTPUT_DIR}/.config" or
75c3fda7 321 dodie "could not copy $1 to .config";
5f9b6ced 322
75c3fda7
SR
323 $type = "oldconfig";
324 }
325
5c42fc5b
SR
326 # old config can ask questions
327 if ($type eq "oldconfig") {
328 $append = "yes ''|";
75c3fda7
SR
329
330 # allow for empty configs
331 run_command "touch $opt{OUTPUT_DIR}/.config";
332
5f9b6ced 333 run_command "mv $opt{OUTPUT_DIR}/.config $opt{OUTPUT_DIR}/config_temp" or
5c42fc5b 334 dodie "moving .config";
2545eb61 335
5f9b6ced 336 if (!$noclean && !run_command "$make mrproper") {
5c42fc5b
SR
337 dodie "make mrproper";
338 }
2545eb61 339
5f9b6ced 340 run_command "mv $opt{OUTPUT_DIR}/config_temp $opt{OUTPUT_DIR}/.config" or
5c42fc5b 341 dodie "moving config_temp";
5c42fc5b
SR
342
343 } elsif (!$noclean) {
344 unlink "$opt{OUTPUT_DIR}/.config";
5f9b6ced 345 run_command "$make mrproper" or
5c42fc5b 346 dodie "make mrproper";
5c42fc5b 347 }
2545eb61
SR
348
349 # add something to distinguish this build
5c42fc5b 350 open(OUT, "> $opt{OUTPUT_DIR}/localversion") or dodie("Can't make localversion file");
2545eb61
SR
351 print OUT "$opt{LOCALVERSION}\n";
352 close(OUT);
353
5f9b6ced
SR
354 if (defined($minconfig)) {
355 $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
2545eb61
SR
356 }
357
5f9b6ced 358 run_command "$defconfig $append $make $type" or
5c42fc5b 359 dodie "failed make config";
2545eb61 360
5f9b6ced
SR
361 if (!run_command "$make $opt{BUILD_OPTIONS}") {
362 # bisect may need this to pass
363 return 1 if ($in_bisect);
5c42fc5b 364 dodie "failed build";
2545eb61 365 }
5f9b6ced
SR
366
367 return 0;
2545eb61
SR
368}
369
75c3fda7
SR
370sub reboot {
371 # try to reboot normally
5f9b6ced 372 if (!run_command "ssh $target reboot") {
75c3fda7
SR
373 # nope? power cycle it.
374 run_command "$opt{POWER_CYCLE}";
375 }
376}
377
378sub halt {
5f9b6ced 379 if (!run_command "ssh $target halt" or defined($opt{"POWER_OFF"})) {
75c3fda7
SR
380 # nope? the zap it!
381 run_command "$opt{POWER_OFF}";
382 }
383}
384
5f9b6ced
SR
385sub 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
401sub 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
5a391fbf
SR
409sub child_run_test {
410 my $failed;
411
412 $failed = !run_command $run_test;
413 exit $failed;
414}
415
416my $child_done;
417
418sub child_finished {
419 $child_done = 1;
420}
421
422sub 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
5f9b6ced
SR
487sub 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;
5a391fbf
SR
514
515 $failed = do_run_test;
5f9b6ced
SR
516 }
517 }
518
519 if ($failed) {
520 $result = "bad";
5a391fbf
SR
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 }
5f9b6ced
SR
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";
5a391fbf 544 if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
5f9b6ced
SR
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;
5a391fbf
SR
550 } else {
551 # we already logged it, just print it now.
552 print $output;
5f9b6ced
SR
553 }
554
555
556 return 1;
557}
558
559sub 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
5a391fbf
SR
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
5f9b6ced
SR
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
2545eb61
SR
605read_config $ARGV[0];
606
607# mandatory configs
608die "MACHINE not defined\n" if (!defined($opt{"MACHINE"}));
609die "SSH_USER not defined\n" if (!defined($opt{"SSH_USER"}));
610die "BUILD_DIR not defined\n" if (!defined($opt{"BUILD_DIR"}));
611die "OUTPUT_DIR not defined\n" if (!defined($opt{"OUTPUT_DIR"}));
612die "BUILD_TARGET not defined\n" if (!defined($opt{"BUILD_TARGET"}));
75c3fda7 613die "TARGET_IMAGE not defined\n" if (!defined($opt{"TARGET_IMAGE"}));
2545eb61
SR
614die "POWER_CYCLE not defined\n" if (!defined($opt{"POWER_CYCLE"}));
615die "CONSOLE not defined\n" if (!defined($opt{"CONSOLE"}));
616die "LOCALVERSION not defined\n" if (!defined($opt{"LOCALVERSION"}));
617die "GRUB_MENU not defined\n" if (!defined($opt{"GRUB_MENU"}));
618
619chdir $opt{"BUILD_DIR"} || die "can't change directory to $opt{BUILD_DIR}";
620
621$target = "$opt{SSH_USER}\@$opt{MACHINE}";
622
623doprint "\n\nSTARTING AUTOMATED TESTS\n";
624
2545eb61
SR
625
626$make = "$opt{MAKE_CMD} O=$opt{OUTPUT_DIR}";
627
5a391fbf
SR
628sub set_build_option {
629 my ($name, $i) = @_;
2545eb61 630
5a391fbf 631 my $option = "$name\[$i\]";
5c42fc5b 632
5a391fbf
SR
633 if (defined($opt{$option})) {
634 return $opt{$option};
5f9b6ced
SR
635 }
636
5a391fbf
SR
637 if (defined($opt{$name})) {
638 return $opt{$name};
2545eb61
SR
639 }
640
5a391fbf
SR
641 return undef;
642}
643
644# First we need to do is the builds
645for (my $i = 1; $i <= $opt{"NUM_BUILDS"}; $i++) {
646 my $type = "BUILD_TYPE[$i]";
647
1a5cfce3
SR
648 if (!defined($opt{$type})) {
649 $opt{$type} = $opt{"DEFAULT_BUILD_TYPE"};
650 }
651
5a391fbf
SR
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
2545eb61
SR
656 doprint "\n\n";
657 doprint "RUNNING TEST $i of $opt{NUM_BUILDS} with option $opt{$type}\n\n";
658
5f9b6ced
SR
659 if ($opt{$type} eq "bisect") {
660 bisect $i;
661 next;
2545eb61 662 }
2545eb61 663
5f9b6ced
SR
664 if ($opt{$type} ne "nobuild") {
665 build $opt{$type};
2545eb61
SR
666 }
667
5f9b6ced
SR
668 get_grub_index;
669 get_version;
2545eb61 670 install;
2545eb61 671 monitor;
5a391fbf
SR
672
673 if (defined($run_test)) {
674 do_run_test;
675 }
676
5f9b6ced 677 success $i;
2545eb61
SR
678}
679
5c42fc5b 680if ($opt{"POWEROFF_ON_SUCCESS"}) {
75c3fda7 681 halt;
1a5cfce3 682} elsif ($opt{"REBOOT_ON_SUCCESS"}) {
75c3fda7 683 reboot;
5c42fc5b 684}
75c3fda7 685
2545eb61 686exit 0;
This page took 0.080806 seconds and 5 git commands to generate.