blob: 1acb0e1ab0f41a650ac976ee919605a6fcbb2849 [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;
22$opt{"POWEROFF_ON_ERROR"} = 0;
23$opt{"POWEROFF_ON_SUCCESS"} = 0;
Steven Rostedt2545eb62010-11-02 15:01:32 -040024
25my $version;
26my $install_mods;
27my $grub_number;
28my $target;
29my $make;
Steven Rostedt5c42fc52010-11-02 14:57:01 -040030my $noclean;
Steven Rostedt2545eb62010-11-02 15:01:32 -040031
32sub read_config {
33 my ($config) = @_;
34
35 open(IN, $config) || die "can't read file $config";
36
37 while (<IN>) {
38
39 # ignore blank lines and comments
40 next if (/^\s*$/ || /\s*\#/);
41
42 if (/^\s*(\S+)\s*=\s*(.*?)\s*$/) {
43 my $lvalue = $1;
44 my $rvalue = $2;
45
46 $opt{$lvalue} = $rvalue;
47 }
48 }
49
50 close(IN);
51}
52
53sub doprint {
54 print @_;
55
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);
60 }
61}
62
Steven Rostedt5c42fc52010-11-02 14:57:01 -040063sub dodie {
64 doprint "CRITICAL FAILURE... ", @_;
65
66 if ($opt{"POWEROFF_ON_ERROR"} && defined($opt{"POWER_OFF"})) {
67 doprint "POWERING OFF\n";
68 `$opt{"POWER_OFF"}`;
69 }
70 die @_;
71}
72
Steven Rostedt2545eb62010-11-02 15:01:32 -040073sub run_command {
74 my ($command) = @_;
75 my $redirect = "";
76
77 if (defined($opt{"LOG_FILE"})) {
78 $redirect = " >> $opt{LOG_FILE} 2>&1";
79 }
80
81 doprint "$command ... ";
82 `$command $redirect`;
83
84 my $failed = $?;
85
86 if ($failed) {
87 doprint "FAILED!\n";
88 } else {
89 doprint "SUCCESS\n";
90 }
91
92 return $failed;
93}
94
95my $timeout = $opt{"TIMEOUT"};
96
97sub wait_for_input
98{
99 my ($fp, $time) = @_;
100 my $rin;
101 my $ready;
102 my $line;
103 my $ch;
104
105 if (!defined($time)) {
106 $time = $timeout;
107 }
108
109 $rin = '';
110 vec($rin, fileno($fp), 1) = 1;
111 $ready = select($rin, undef, undef, $time);
112
113 $line = "";
114
115 # try to read one char at a time
116 while (sysread $fp, $ch, 1) {
117 $line .= $ch;
118 last if ($ch eq "\n");
119 }
120
121 if (!length($line)) {
122 return undef;
123 }
124
125 return $line;
126}
127
128sub reboot {
129 run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
130}
131
132sub monitor {
133 my $flags;
134 my $booted = 0;
135 my $bug = 0;
136 my $pid;
137 my $doopen2 = 0;
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400138 my $skip_call_trace = 0;
Steven Rostedt2545eb62010-11-02 15:01:32 -0400139
140 if ($doopen2) {
141 $pid = open2(\*IN, \*OUT, $opt{CONSOLE});
142 if ($pid < 0) {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400143 dodie "Failed to connect to the console";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400144 }
145 } else {
146 $pid = open(IN, "$opt{CONSOLE} |");
147 }
148
149 $flags = fcntl(IN, F_GETFL, 0) or
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400150 dodie "Can't get flags for the socket: $!\n";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400151
152 $flags = fcntl(IN, F_SETFL, $flags | O_NONBLOCK) or
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400153 dodie "Can't set flags for the socket: $!\n";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400154
155 my $line;
156 my $full_line = "";
157
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));
163
164 reboot;
165
166 for (;;) {
167
168 $line = wait_for_input(\*IN);
169
170 last if (!defined($line));
171
172 doprint $line;
173
174 # we are not guaranteed to get a full line
175 $full_line .= $line;
176
177 if ($full_line =~ /login:/) {
178 $booted = 1;
179 }
180
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400181 if ($full_line =~ /\[ backtrace testing \]/) {
182 $skip_call_trace = 1;
183 }
184
Steven Rostedt2545eb62010-11-02 15:01:32 -0400185 if ($full_line =~ /call trace:/i) {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400186 $bug = 1 if (!$skip_call_trace);
187 }
188
189 if ($full_line =~ /\[ end of backtrace testing \]/) {
190 $skip_call_trace = 0;
191 }
192
193 if ($full_line =~ /Kernel panic -/) {
Steven Rostedt2545eb62010-11-02 15:01:32 -0400194 $bug = 1;
195 }
196
197 if ($line =~ /\n/) {
198 $full_line = "";
199 }
200 }
201
202 doprint "kill child process $pid\n";
203 kill 2, $pid;
204
205 print "closing!\n";
206 close(IN);
207
208 if (!$booted) {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400209 dodie "failed - never got a boot prompt.\n";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400210 }
211
212 if ($bug) {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400213 dodie "failed - got a bug report\n";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400214 }
215}
216
217sub install {
218
219 if (run_command "scp $opt{OUTPUT_DIR}/$opt{BUILD_TARGET} $target:$opt{TARGET_IMAGE}") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400220 dodie "failed to copy image";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400221 }
222
223 if ($install_mods) {
224 my $modlib = "/lib/modules/$version";
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400225 my $modtar = "autotest-mods.tar.bz2";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400226
227 if (run_command "ssh $target rm -rf $modlib") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400228 dodie "failed to remove old mods: $modlib";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400229 }
230
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400231 # 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";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400234 }
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400235
236 if (run_command "scp $opt{TMP_DIR}/$modtar $target:/tmp") {
237 dodie "failed to copy modules";
238 }
239
240 unlink "$opt{TMP_DIR}/$modtar";
241
242 if (run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'") {
243 dodie "failed to tar modules";
244 }
245
246 run_command "ssh $target rm -f /tmp/$modtar";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400247 }
248
249}
250
251sub build {
252 my ($type) = @_;
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400253 my $defconfig = "";
254 my $append = "";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400255
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400256 # 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";
261 }
Steven Rostedt2545eb62010-11-02 15:01:32 -0400262
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400263 if (!$noclean && run_command "$make mrproper") {
264 dodie "make mrproper";
265 }
266
267 if (run_command "mv $opt{OUTPUT_DIR}/config_temp $opt{OUTPUT_DIR}/.config") {
268 dodie "moving config_temp";
269 }
270
271 } elsif (!$noclean) {
272 unlink "$opt{OUTPUT_DIR}/.config";
273 if (run_command "$make mrproper") {
274 dodie "make mrproper";
275 }
276 }
Steven Rostedt2545eb62010-11-02 15:01:32 -0400277
278 # add something to distinguish this build
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400279 open(OUT, "> $opt{OUTPUT_DIR}/localversion") or dodie("Can't make localversion file");
Steven Rostedt2545eb62010-11-02 15:01:32 -0400280 print OUT "$opt{LOCALVERSION}\n";
281 close(OUT);
282
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400283 if (defined($opt{"MIN_CONFIG"})) {
284 $defconfig = "KCONFIG_ALLCONFIG=$opt{MIN_CONFIG}";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400285 }
286
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400287 if (run_command "$defconfig $append $make $type") {
288 dodie "failed make config";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400289 }
290
291 if (run_command "$make $opt{BUILD_OPTIONS}") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400292 dodie "failed build";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400293 }
294}
295
296read_config $ARGV[0];
297
298# mandatory configs
299die "MACHINE not defined\n" if (!defined($opt{"MACHINE"}));
300die "SSH_USER not defined\n" if (!defined($opt{"SSH_USER"}));
301die "BUILD_DIR not defined\n" if (!defined($opt{"BUILD_DIR"}));
302die "OUTPUT_DIR not defined\n" if (!defined($opt{"OUTPUT_DIR"}));
303die "BUILD_TARGET not defined\n" if (!defined($opt{"BUILD_TARGET"}));
304die "POWER_CYCLE not defined\n" if (!defined($opt{"POWER_CYCLE"}));
305die "CONSOLE not defined\n" if (!defined($opt{"CONSOLE"}));
306die "LOCALVERSION not defined\n" if (!defined($opt{"LOCALVERSION"}));
307die "GRUB_MENU not defined\n" if (!defined($opt{"GRUB_MENU"}));
308
309chdir $opt{"BUILD_DIR"} || die "can't change directory to $opt{BUILD_DIR}";
310
311$target = "$opt{SSH_USER}\@$opt{MACHINE}";
312
313doprint "\n\nSTARTING AUTOMATED TESTS\n";
314
315doprint "Find grub menu ... ";
316$grub_number = -1;
317open(IN, "ssh $target cat /boot/grub/menu.lst |")
318 or die "unable to get menu.lst";
319while (<IN>) {
320 if (/^\s*title\s+$opt{GRUB_MENU}\s*$/) {
321 $grub_number++;
322 last;
323 } elsif (/^\s*title\s/) {
324 $grub_number++;
325 }
326}
327close(IN);
328die "Could not find '$opt{GRUB_MENU}' in /boot/grub/menu on $opt{MACHINE}"
329 if ($grub_number < 0);
330doprint "$grub_number\n";
331
332$make = "$opt{MAKE_CMD} O=$opt{OUTPUT_DIR}";
333
334# First we need to do is the builds
335for (my $i = 1; $i <= $opt{"NUM_BUILDS"}; $i++) {
336 my $type = "BUILD_TYPE[$i]";
337
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400338 if (defined($opt{"BUILD_NOCLEAN[$i]"}) &&
339 $opt{"BUILD_NOCLEAN[$i]"} != 0) {
340 $noclean = 1;
341 } else {
342 $noclean = $opt{"BUILD_NOCLEAN"};
343 }
344
Steven Rostedt2545eb62010-11-02 15:01:32 -0400345 if (!defined($opt{$type})) {
346 $opt{$type} = $opt{"DEFAULT_BUILD_TYPE"};
347 }
348
349 doprint "\n\n";
350 doprint "RUNNING TEST $i of $opt{NUM_BUILDS} with option $opt{$type}\n\n";
351
352 if ($opt{$type} ne "nobuild") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400353 build $opt{$type};
Steven Rostedt2545eb62010-11-02 15:01:32 -0400354 }
355
356 # get the release name
357 doprint "$make kernelrelease ... ";
358 $version = `$make kernelrelease | tail -1`;
359 chomp($version);
360 doprint "$version\n";
361
362 # should we process modules?
363 $install_mods = 0;
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400364 open(IN, "$opt{OUTPUT_DIR}/.config") or dodie("Can't read config file");
Steven Rostedt2545eb62010-11-02 15:01:32 -0400365 while (<IN>) {
366 if (/CONFIG_MODULES(=y)?/) {
367 $install_mods = 1 if (defined($1));
368 last;
369 }
370 }
371 close(IN);
372
373 if ($install_mods) {
374 if (run_command "$make INSTALL_MOD_PATH=$opt{TMP_DIR} modules_install") {
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400375 dodie "Failed to install modules";
Steven Rostedt2545eb62010-11-02 15:01:32 -0400376 }
377 } else {
378 doprint "No modules needed\n";
379 }
380
381 install;
382
383 monitor;
384
385 doprint "\n\n*******************************************\n";
386 doprint "*******************************************\n";
387 doprint "** SUCCESS!!!! **\n";
388 doprint "*******************************************\n";
389 doprint "*******************************************\n";
390
391 # try to reboot normally
392
393 if (run_command "ssh $target reboot") {
394 # nope? power cycle it.
395 run_command "$opt{POWER_CYCLE}";
396 }
397
398 sleep "$opt{SLEEP_TIME}";
399}
400
Steven Rostedt5c42fc52010-11-02 14:57:01 -0400401if ($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}";
405 }
406}
Steven Rostedt2545eb62010-11-02 15:01:32 -0400407exit 0;