ktest: New features: noclean, dodie, poweroff on error and success
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / tools / testing / ktest / ktest.pl
blob1acb0e1ab0f41a650ac976ee919605a6fcbb2849
1 #!/usr/bin/perl -w
3 use strict;
4 use IPC::Open2;
5 use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
6 use FileHandle;
8 $#ARGV >= 0 || die "usage: autotest.pl config-file\n";
10 $| = 1;
12 my %opt;
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{"POWEROFF_ON_ERROR"} = 0;
23 $opt{"POWEROFF_ON_SUCCESS"} = 0;
25 my $version;
26 my $install_mods;
27 my $grub_number;
28 my $target;
29 my $make;
30 my $noclean;
32 sub read_config {
33 my ($config) = @_;
35 open(IN, $config) || die "can't read file $config";
37 while (<IN>) {
39 # ignore blank lines and comments
40 next if (/^\s*$/ || /\s*\#/);
42 if (/^\s*(\S+)\s*=\s*(.*?)\s*$/) {
43 my $lvalue = $1;
44 my $rvalue = $2;
46 $opt{$lvalue} = $rvalue;
50 close(IN);
53 sub doprint {
54 print @_;
56 if (defined($opt{"LOG_FILE"})) {
57 open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
58 print OUT @_;
59 close(OUT);
63 sub dodie {
64 doprint "CRITICAL FAILURE... ", @_;
66 if ($opt{"POWEROFF_ON_ERROR"} && defined($opt{"POWER_OFF"})) {
67 doprint "POWERING OFF\n";
68 `$opt{"POWER_OFF"}`;
70 die @_;
73 sub run_command {
74 my ($command) = @_;
75 my $redirect = "";
77 if (defined($opt{"LOG_FILE"})) {
78 $redirect = " >> $opt{LOG_FILE} 2>&1";
81 doprint "$command ... ";
82 `$command $redirect`;
84 my $failed = $?;
86 if ($failed) {
87 doprint "FAILED!\n";
88 } else {
89 doprint "SUCCESS\n";
92 return $failed;
95 my $timeout = $opt{"TIMEOUT"};
97 sub wait_for_input
99 my ($fp, $time) = @_;
100 my $rin;
101 my $ready;
102 my $line;
103 my $ch;
105 if (!defined($time)) {
106 $time = $timeout;
109 $rin = '';
110 vec($rin, fileno($fp), 1) = 1;
111 $ready = select($rin, undef, undef, $time);
113 $line = "";
115 # try to read one char at a time
116 while (sysread $fp, $ch, 1) {
117 $line .= $ch;
118 last if ($ch eq "\n");
121 if (!length($line)) {
122 return undef;
125 return $line;
128 sub reboot {
129 run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
132 sub monitor {
133 my $flags;
134 my $booted = 0;
135 my $bug = 0;
136 my $pid;
137 my $doopen2 = 0;
138 my $skip_call_trace = 0;
140 if ($doopen2) {
141 $pid = open2(\*IN, \*OUT, $opt{CONSOLE});
142 if ($pid < 0) {
143 dodie "Failed to connect to the console";
145 } else {
146 $pid = open(IN, "$opt{CONSOLE} |");
149 $flags = fcntl(IN, F_GETFL, 0) or
150 dodie "Can't get flags for the socket: $!\n";
152 $flags = fcntl(IN, F_SETFL, $flags | O_NONBLOCK) or
153 dodie "Can't set flags for the socket: $!\n";
155 my $line;
156 my $full_line = "";
158 doprint "Wait for monitor to settle down.\n";
159 # read the monitor and wait for the system to calm down
160 do {
161 $line = wait_for_input(\*IN, 5);
162 } while (defined($line));
164 reboot;
166 for (;;) {
168 $line = wait_for_input(\*IN);
170 last if (!defined($line));
172 doprint $line;
174 # we are not guaranteed to get a full line
175 $full_line .= $line;
177 if ($full_line =~ /login:/) {
178 $booted = 1;
181 if ($full_line =~ /\[ backtrace testing \]/) {
182 $skip_call_trace = 1;
185 if ($full_line =~ /call trace:/i) {
186 $bug = 1 if (!$skip_call_trace);
189 if ($full_line =~ /\[ end of backtrace testing \]/) {
190 $skip_call_trace = 0;
193 if ($full_line =~ /Kernel panic -/) {
194 $bug = 1;
197 if ($line =~ /\n/) {
198 $full_line = "";
202 doprint "kill child process $pid\n";
203 kill 2, $pid;
205 print "closing!\n";
206 close(IN);
208 if (!$booted) {
209 dodie "failed - never got a boot prompt.\n";
212 if ($bug) {
213 dodie "failed - got a bug report\n";
217 sub install {
219 if (run_command "scp $opt{OUTPUT_DIR}/$opt{BUILD_TARGET} $target:$opt{TARGET_IMAGE}") {
220 dodie "failed to copy image";
223 if ($install_mods) {
224 my $modlib = "/lib/modules/$version";
225 my $modtar = "autotest-mods.tar.bz2";
227 if (run_command "ssh $target rm -rf $modlib") {
228 dodie "failed to remove old mods: $modlib";
231 # would be nice if scp -r did not follow symbolic links
232 if (run_command "cd $opt{TMP_DIR}; tar -cjf $modtar lib/modules/$version") {
233 dodie "making tarball";
236 if (run_command "scp $opt{TMP_DIR}/$modtar $target:/tmp") {
237 dodie "failed to copy modules";
240 unlink "$opt{TMP_DIR}/$modtar";
242 if (run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'") {
243 dodie "failed to tar modules";
246 run_command "ssh $target rm -f /tmp/$modtar";
251 sub build {
252 my ($type) = @_;
253 my $defconfig = "";
254 my $append = "";
256 # old config can ask questions
257 if ($type eq "oldconfig") {
258 $append = "yes ''|";
259 if (run_command "mv $opt{OUTPUT_DIR}/.config $opt{OUTPUT_DIR}/config_temp") {
260 dodie "moving .config";
263 if (!$noclean && run_command "$make mrproper") {
264 dodie "make mrproper";
267 if (run_command "mv $opt{OUTPUT_DIR}/config_temp $opt{OUTPUT_DIR}/.config") {
268 dodie "moving config_temp";
271 } elsif (!$noclean) {
272 unlink "$opt{OUTPUT_DIR}/.config";
273 if (run_command "$make mrproper") {
274 dodie "make mrproper";
278 # add something to distinguish this build
279 open(OUT, "> $opt{OUTPUT_DIR}/localversion") or dodie("Can't make localversion file");
280 print OUT "$opt{LOCALVERSION}\n";
281 close(OUT);
283 if (defined($opt{"MIN_CONFIG"})) {
284 $defconfig = "KCONFIG_ALLCONFIG=$opt{MIN_CONFIG}";
287 if (run_command "$defconfig $append $make $type") {
288 dodie "failed make config";
291 if (run_command "$make $opt{BUILD_OPTIONS}") {
292 dodie "failed build";
296 read_config $ARGV[0];
298 # mandatory configs
299 die "MACHINE not defined\n" if (!defined($opt{"MACHINE"}));
300 die "SSH_USER not defined\n" if (!defined($opt{"SSH_USER"}));
301 die "BUILD_DIR not defined\n" if (!defined($opt{"BUILD_DIR"}));
302 die "OUTPUT_DIR not defined\n" if (!defined($opt{"OUTPUT_DIR"}));
303 die "BUILD_TARGET not defined\n" if (!defined($opt{"BUILD_TARGET"}));
304 die "POWER_CYCLE not defined\n" if (!defined($opt{"POWER_CYCLE"}));
305 die "CONSOLE not defined\n" if (!defined($opt{"CONSOLE"}));
306 die "LOCALVERSION not defined\n" if (!defined($opt{"LOCALVERSION"}));
307 die "GRUB_MENU not defined\n" if (!defined($opt{"GRUB_MENU"}));
309 chdir $opt{"BUILD_DIR"} || die "can't change directory to $opt{BUILD_DIR}";
311 $target = "$opt{SSH_USER}\@$opt{MACHINE}";
313 doprint "\n\nSTARTING AUTOMATED TESTS\n";
315 doprint "Find grub menu ... ";
316 $grub_number = -1;
317 open(IN, "ssh $target cat /boot/grub/menu.lst |")
318 or die "unable to get menu.lst";
319 while (<IN>) {
320 if (/^\s*title\s+$opt{GRUB_MENU}\s*$/) {
321 $grub_number++;
322 last;
323 } elsif (/^\s*title\s/) {
324 $grub_number++;
327 close(IN);
328 die "Could not find '$opt{GRUB_MENU}' in /boot/grub/menu on $opt{MACHINE}"
329 if ($grub_number < 0);
330 doprint "$grub_number\n";
332 $make = "$opt{MAKE_CMD} O=$opt{OUTPUT_DIR}";
334 # First we need to do is the builds
335 for (my $i = 1; $i <= $opt{"NUM_BUILDS"}; $i++) {
336 my $type = "BUILD_TYPE[$i]";
338 if (defined($opt{"BUILD_NOCLEAN[$i]"}) &&
339 $opt{"BUILD_NOCLEAN[$i]"} != 0) {
340 $noclean = 1;
341 } else {
342 $noclean = $opt{"BUILD_NOCLEAN"};
345 if (!defined($opt{$type})) {
346 $opt{$type} = $opt{"DEFAULT_BUILD_TYPE"};
349 doprint "\n\n";
350 doprint "RUNNING TEST $i of $opt{NUM_BUILDS} with option $opt{$type}\n\n";
352 if ($opt{$type} ne "nobuild") {
353 build $opt{$type};
356 # get the release name
357 doprint "$make kernelrelease ... ";
358 $version = `$make kernelrelease | tail -1`;
359 chomp($version);
360 doprint "$version\n";
362 # should we process modules?
363 $install_mods = 0;
364 open(IN, "$opt{OUTPUT_DIR}/.config") or dodie("Can't read config file");
365 while (<IN>) {
366 if (/CONFIG_MODULES(=y)?/) {
367 $install_mods = 1 if (defined($1));
368 last;
371 close(IN);
373 if ($install_mods) {
374 if (run_command "$make INSTALL_MOD_PATH=$opt{TMP_DIR} modules_install") {
375 dodie "Failed to install modules";
377 } else {
378 doprint "No modules needed\n";
381 install;
383 monitor;
385 doprint "\n\n*******************************************\n";
386 doprint "*******************************************\n";
387 doprint "** SUCCESS!!!! **\n";
388 doprint "*******************************************\n";
389 doprint "*******************************************\n";
391 # try to reboot normally
393 if (run_command "ssh $target reboot") {
394 # nope? power cycle it.
395 run_command "$opt{POWER_CYCLE}";
398 sleep "$opt{SLEEP_TIME}";
401 if ($opt{"POWEROFF_ON_SUCCESS"}) {
402 if (run_command "ssh $target halt" && defined($opt{"POWER_OFF"})) {
403 # nope? the zap it!
404 run_command "$opt{POWER_OFF}";
407 exit 0;