blob: 79da57f3023b734d19e4cd358587db0469241293 [file] [log] [blame]
Steven Rostedt2545eb62010-11-02 15:01:32 -04001#!/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
Steven Rostedt5c42fc52010-11-02 14:57:01 -040021$opt{"BUILD_NOCLEAN"} = 0;
Steven Rostedt75c3fda72010-11-02 14:57:21 -040022$opt{"REBOOT_ON_ERROR"} = 0;
Steven Rostedt5c42fc52010-11-02 14:57:01 -040023$opt{"POWEROFF_ON_ERROR"} = 0;
24$opt{"POWEROFF_ON_SUCCESS"} = 0;
Steven Rostedt75c3fda72010-11-02 14:57:21 -040025$opt{"BUILD_OPTIONS"} = "";
Steven Rostedt2545eb62010-11-02 15:01:32 -040026
27my $version;
28my $install_mods;
29my $grub_number;
30my $target;
31my $make;
Steven Rostedt5c42fc52010-11-02 14:57:01 -040032my $noclean;
Steven Rostedt2545eb62010-11-02 15:01:32 -040033
34sub read_config {
35 my ($config) = @_;
36
37 open(IN, $config) || die "can't read file $config";
38
39 while (<IN>) {
40
41 # ignore blank lines and comments
42 next if (/^\s*$/ || /\s*\#/);
43
44 if (/^\s*(\S+)\s*=\s*(.*?)\s*$/) {
45 my $lvalue = $1;
46 my $rvalue = $2;
47
48 $opt{$lvalue} = $rvalue;
49 }
50 }
51
52 close(IN);
53}
54
55sub doprint {
56 print @_;
57
58 if (defined($opt{"LOG_FILE"})) {
59 open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
60 print OUT @_;
61 close(OUT);
62 }
63}
64
Steven Rostedt5c42fc52010-11-02 14:57:01 -040065sub dodie {
66 doprint "CRITICAL FAILURE... ", @_;
67
Steven Rostedt75c3fda72010-11-02 14:57:21 -040068 if ($opt{"REBOOT_ON_ERROR"}) {
69 doprint "REBOOTING\n";
70 `$opt{"POWER_CYCLE"}`;
71
72 } elsif ($opt{"POWEROFF_ON_ERROR"} && defined($opt{"POWER_OFF"})) {
Steven Rostedt5c42fc52010-11-02 14:57:01 -040073 doprint "POWERING OFF\n";
74 `$opt{"POWER_OFF"}`;
75 }
Steven Rostedt75c3fda72010-11-02 14:57:21 -040076
Steven Rostedt5c42fc52010-11-02 14:57:01 -040077 die @_;
78}
79
Steven Rostedt2545eb62010-11-02 15:01:32 -040080sub run_command {
81 my ($command) = @_;
82 my $redirect = "";
83
84 if (defined($opt{"LOG_FILE"})) {
85 $redirect = " >> $opt{LOG_FILE} 2>&1";
86 }
87
88 doprint "$command ... ";
89 `$command $redirect`;
90
91 my $failed = $?;
92
93 if ($failed) {
94 doprint "FAILED!\n";
95 } else {
96 doprint "SUCCESS\n";
97 }
98
99 return $failed;
100}
101
102my $timeout = $opt{"TIMEOUT"};
103
104sub wait_for_input
105{
106 my ($fp, $time) = @_;
107 my $rin;
108 my $ready;
109 my $line;
110 my $ch;
111
112 if (!defined($time)) {
113 $time = $timeout;
114 }
115
116 $rin = '';
117 vec($rin, fileno($fp), 1) = 1;
118 $ready = select($rin, undef, undef, $time);
119
120 $line = "";
121
122 # try to read one char at a time
123 while (sysread $fp, $ch, 1) {
124 $line .= $ch;
125 last if ($ch eq "\n");
126 }
127
128 if (!length($line)) {
129 return undef;
130 }
131
132 return $line;
133}
134
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400135sub reboot_to {
Steven Rostedt2545eb62010-11-02 15:01:32 -0400136 run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
137}
138
139sub monitor {
140 my $flags;
141 my $booted = 0;
142 my $bug = 0;
143 my $pid;
144 my $doopen2 = 0;
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400145 my $skip_call_trace = 0;
Steven Rostedt2545eb62010-11-02 15:01:32 -0400146
147 if ($doopen2) {
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400148 $pid = open2(\*IN, \*OUT, $opt{"CONSOLE"});
Steven Rostedt2545eb62010-11-02 15:01:32 -0400149 if ($pid < 0) {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400150 dodie "Failed to connect to the console";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400151 }
152 } else {
153 $pid = open(IN, "$opt{CONSOLE} |");
154 }
155
156 $flags = fcntl(IN, F_GETFL, 0) or
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400157 dodie "Can't get flags for the socket: $!\n";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400158
159 $flags = fcntl(IN, F_SETFL, $flags | O_NONBLOCK) or
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400160 dodie "Can't set flags for the socket: $!\n";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400161
162 my $line;
163 my $full_line = "";
164
165 doprint "Wait for monitor to settle down.\n";
166 # read the monitor and wait for the system to calm down
167 do {
168 $line = wait_for_input(\*IN, 5);
169 } while (defined($line));
170
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400171 reboot_to;
Steven Rostedt2545eb62010-11-02 15:01:32 -0400172
173 for (;;) {
174
175 $line = wait_for_input(\*IN);
176
177 last if (!defined($line));
178
179 doprint $line;
180
181 # we are not guaranteed to get a full line
182 $full_line .= $line;
183
184 if ($full_line =~ /login:/) {
185 $booted = 1;
186 }
187
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400188 if ($full_line =~ /\[ backtrace testing \]/) {
189 $skip_call_trace = 1;
190 }
191
Steven Rostedt2545eb62010-11-02 15:01:32 -0400192 if ($full_line =~ /call trace:/i) {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400193 $bug = 1 if (!$skip_call_trace);
194 }
195
196 if ($full_line =~ /\[ end of backtrace testing \]/) {
197 $skip_call_trace = 0;
198 }
199
200 if ($full_line =~ /Kernel panic -/) {
Steven Rostedt2545eb62010-11-02 15:01:32 -0400201 $bug = 1;
202 }
203
204 if ($line =~ /\n/) {
205 $full_line = "";
206 }
207 }
208
209 doprint "kill child process $pid\n";
210 kill 2, $pid;
211
212 print "closing!\n";
213 close(IN);
214
215 if (!$booted) {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400216 dodie "failed - never got a boot prompt.\n";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400217 }
218
219 if ($bug) {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400220 dodie "failed - got a bug report\n";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400221 }
222}
223
224sub install {
225
226 if (run_command "scp $opt{OUTPUT_DIR}/$opt{BUILD_TARGET} $target:$opt{TARGET_IMAGE}") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400227 dodie "failed to copy image";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400228 }
229
230 if ($install_mods) {
231 my $modlib = "/lib/modules/$version";
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400232 my $modtar = "autotest-mods.tar.bz2";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400233
234 if (run_command "ssh $target rm -rf $modlib") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400235 dodie "failed to remove old mods: $modlib";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400236 }
237
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400238 # would be nice if scp -r did not follow symbolic links
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400239 if (run_command "cd $opt{TMP_DIR} && tar -cjf $modtar lib/modules/$version") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400240 dodie "making tarball";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400241 }
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400242
243 if (run_command "scp $opt{TMP_DIR}/$modtar $target:/tmp") {
244 dodie "failed to copy modules";
245 }
246
247 unlink "$opt{TMP_DIR}/$modtar";
248
249 if (run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'") {
250 dodie "failed to tar modules";
251 }
252
253 run_command "ssh $target rm -f /tmp/$modtar";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400254 }
255
256}
257
258sub build {
259 my ($type) = @_;
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400260 my $defconfig = "";
261 my $append = "";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400262
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400263 if ($type =~ /^useconfig:(.*)/) {
264 if (run_command "cp $1 $opt{OUTPUT_DIR}/.config") {
265 dodie "could not copy $1 to .config";
266 }
267 $type = "oldconfig";
268 }
269
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400270 # old config can ask questions
271 if ($type eq "oldconfig") {
272 $append = "yes ''|";
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400273
274 # allow for empty configs
275 run_command "touch $opt{OUTPUT_DIR}/.config";
276
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400277 if (run_command "mv $opt{OUTPUT_DIR}/.config $opt{OUTPUT_DIR}/config_temp") {
278 dodie "moving .config";
279 }
Steven Rostedt2545eb62010-11-02 15:01:32 -0400280
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400281 if (!$noclean && run_command "$make mrproper") {
282 dodie "make mrproper";
283 }
284
285 if (run_command "mv $opt{OUTPUT_DIR}/config_temp $opt{OUTPUT_DIR}/.config") {
286 dodie "moving config_temp";
287 }
288
289 } elsif (!$noclean) {
290 unlink "$opt{OUTPUT_DIR}/.config";
291 if (run_command "$make mrproper") {
292 dodie "make mrproper";
293 }
294 }
Steven Rostedt2545eb62010-11-02 15:01:32 -0400295
296 # add something to distinguish this build
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400297 open(OUT, "> $opt{OUTPUT_DIR}/localversion") or dodie("Can't make localversion file");
Steven Rostedt2545eb62010-11-02 15:01:32 -0400298 print OUT "$opt{LOCALVERSION}\n";
299 close(OUT);
300
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400301 if (defined($opt{"MIN_CONFIG"})) {
302 $defconfig = "KCONFIG_ALLCONFIG=$opt{MIN_CONFIG}";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400303 }
304
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400305 if (run_command "$defconfig $append $make $type") {
306 dodie "failed make config";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400307 }
308
309 if (run_command "$make $opt{BUILD_OPTIONS}") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400310 dodie "failed build";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400311 }
312}
313
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400314sub reboot {
315 # try to reboot normally
316 if (run_command "ssh $target reboot") {
317 # nope? power cycle it.
318 run_command "$opt{POWER_CYCLE}";
319 }
320}
321
322sub halt {
323 if ((run_command "ssh $target halt") or defined($opt{"POWER_OFF"})) {
324 # nope? the zap it!
325 run_command "$opt{POWER_OFF}";
326 }
327}
328
Steven Rostedt2545eb62010-11-02 15:01:32 -0400329read_config $ARGV[0];
330
331# mandatory configs
332die "MACHINE not defined\n" if (!defined($opt{"MACHINE"}));
333die "SSH_USER not defined\n" if (!defined($opt{"SSH_USER"}));
334die "BUILD_DIR not defined\n" if (!defined($opt{"BUILD_DIR"}));
335die "OUTPUT_DIR not defined\n" if (!defined($opt{"OUTPUT_DIR"}));
336die "BUILD_TARGET not defined\n" if (!defined($opt{"BUILD_TARGET"}));
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400337die "TARGET_IMAGE not defined\n" if (!defined($opt{"TARGET_IMAGE"}));
Steven Rostedt2545eb62010-11-02 15:01:32 -0400338die "POWER_CYCLE not defined\n" if (!defined($opt{"POWER_CYCLE"}));
339die "CONSOLE not defined\n" if (!defined($opt{"CONSOLE"}));
340die "LOCALVERSION not defined\n" if (!defined($opt{"LOCALVERSION"}));
341die "GRUB_MENU not defined\n" if (!defined($opt{"GRUB_MENU"}));
342
343chdir $opt{"BUILD_DIR"} || die "can't change directory to $opt{BUILD_DIR}";
344
345$target = "$opt{SSH_USER}\@$opt{MACHINE}";
346
347doprint "\n\nSTARTING AUTOMATED TESTS\n";
348
349doprint "Find grub menu ... ";
350$grub_number = -1;
351open(IN, "ssh $target cat /boot/grub/menu.lst |")
352 or die "unable to get menu.lst";
353while (<IN>) {
354 if (/^\s*title\s+$opt{GRUB_MENU}\s*$/) {
355 $grub_number++;
356 last;
357 } elsif (/^\s*title\s/) {
358 $grub_number++;
359 }
360}
361close(IN);
362die "Could not find '$opt{GRUB_MENU}' in /boot/grub/menu on $opt{MACHINE}"
363 if ($grub_number < 0);
364doprint "$grub_number\n";
365
366$make = "$opt{MAKE_CMD} O=$opt{OUTPUT_DIR}";
367
368# First we need to do is the builds
369for (my $i = 1; $i <= $opt{"NUM_BUILDS"}; $i++) {
370 my $type = "BUILD_TYPE[$i]";
371
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400372 if (defined($opt{"BUILD_NOCLEAN[$i]"}) &&
373 $opt{"BUILD_NOCLEAN[$i]"} != 0) {
374 $noclean = 1;
375 } else {
376 $noclean = $opt{"BUILD_NOCLEAN"};
377 }
378
Steven Rostedt2545eb62010-11-02 15:01:32 -0400379 if (!defined($opt{$type})) {
380 $opt{$type} = $opt{"DEFAULT_BUILD_TYPE"};
381 }
382
383 doprint "\n\n";
384 doprint "RUNNING TEST $i of $opt{NUM_BUILDS} with option $opt{$type}\n\n";
385
386 if ($opt{$type} ne "nobuild") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400387 build $opt{$type};
Steven Rostedt2545eb62010-11-02 15:01:32 -0400388 }
389
390 # get the release name
391 doprint "$make kernelrelease ... ";
392 $version = `$make kernelrelease | tail -1`;
393 chomp($version);
394 doprint "$version\n";
395
396 # should we process modules?
397 $install_mods = 0;
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400398 open(IN, "$opt{OUTPUT_DIR}/.config") or dodie("Can't read config file");
Steven Rostedt2545eb62010-11-02 15:01:32 -0400399 while (<IN>) {
400 if (/CONFIG_MODULES(=y)?/) {
401 $install_mods = 1 if (defined($1));
402 last;
403 }
404 }
405 close(IN);
406
407 if ($install_mods) {
408 if (run_command "$make INSTALL_MOD_PATH=$opt{TMP_DIR} modules_install") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400409 dodie "Failed to install modules";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400410 }
411 } else {
412 doprint "No modules needed\n";
413 }
414
415 install;
416
417 monitor;
418
419 doprint "\n\n*******************************************\n";
420 doprint "*******************************************\n";
421 doprint "** SUCCESS!!!! **\n";
422 doprint "*******************************************\n";
423 doprint "*******************************************\n";
424
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400425 if ($i != $opt{"NUM_BUILDS"}) {
426 reboot;
427 sleep "$opt{SLEEP_TIME}";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400428 }
Steven Rostedt2545eb62010-11-02 15:01:32 -0400429}
430
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400431if ($opt{"POWEROFF_ON_SUCCESS"}) {
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400432 halt;
433} else {
434 reboot;
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400435}
Steven Rostedt75c3fda72010-11-02 14:57:21 -0400436
Steven Rostedt2545eb62010-11-02 15:01:32 -0400437exit 0;