81fb2e431058a668f428eb711eb8ab36929e87ca
[linux-2.6.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
22 my $version;
23 my $install_mods;
24 my $grub_number;
25 my $target;
26 my $make;
27
28 sub read_config {
29     my ($config) = @_;
30
31     open(IN, $config) || die "can't read file $config";
32
33     while (<IN>) {
34
35         # ignore blank lines and comments
36         next if (/^\s*$/ || /\s*\#/);
37
38         if (/^\s*(\S+)\s*=\s*(.*?)\s*$/) {
39             my $lvalue = $1;
40             my $rvalue = $2;
41
42             $opt{$lvalue} = $rvalue;
43         }
44     }
45
46     close(IN);
47 }
48
49 sub doprint {
50     print @_;
51
52     if (defined($opt{"LOG_FILE"})) {
53         open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
54         print OUT @_;
55         close(OUT);
56     }
57 }
58
59 sub run_command {
60     my ($command) = @_;
61     my $redirect = "";
62
63     if (defined($opt{"LOG_FILE"})) {
64         $redirect = " >> $opt{LOG_FILE} 2>&1";
65     }
66
67     doprint "$command ... ";
68     `$command $redirect`;
69
70     my $failed = $?;
71
72     if ($failed) {
73         doprint "FAILED!\n";
74     } else {
75         doprint "SUCCESS\n";
76     }
77
78     return $failed;
79 }
80
81 my $timeout = $opt{"TIMEOUT"};
82
83 sub wait_for_input
84 {
85     my ($fp, $time) = @_;
86     my $rin;
87     my $ready;
88     my $line;
89     my $ch;
90
91     if (!defined($time)) {
92         $time = $timeout;
93     }
94
95     $rin = '';
96     vec($rin, fileno($fp), 1) = 1;
97     $ready = select($rin, undef, undef, $time);
98
99     $line = "";
100
101     # try to read one char at a time
102     while (sysread $fp, $ch, 1) {
103         $line .= $ch;
104         last if ($ch eq "\n");
105     }
106
107     if (!length($line)) {
108         return undef;
109     }
110
111     return $line;
112 }
113
114 sub reboot {
115     run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
116 }
117
118 sub monitor {
119     my $flags;
120     my $booted = 0;
121     my $bug = 0;
122     my $pid;
123     my $doopen2 = 0;
124
125     if ($doopen2) {
126         $pid = open2(\*IN, \*OUT, $opt{CONSOLE});
127         if ($pid < 0) {
128             die "Failed to connect to the console";
129         }
130     } else {
131         $pid = open(IN, "$opt{CONSOLE} |");
132     }
133
134     $flags = fcntl(IN, F_GETFL, 0) or
135         die "Can't get flags for the socket: $!\n";
136
137     $flags = fcntl(IN, F_SETFL, $flags | O_NONBLOCK) or
138         die "Can't set flags for the socket: $!\n";
139
140     my $line;
141     my $full_line = "";
142
143     doprint "Wait for monitor to settle down.\n";
144     # read the monitor and wait for the system to calm down
145     do {
146         $line = wait_for_input(\*IN, 5);
147     } while (defined($line));
148
149     reboot;
150
151     for (;;) {
152
153         $line = wait_for_input(\*IN);
154
155         last if (!defined($line));
156
157         doprint $line;
158
159         # we are not guaranteed to get a full line
160         $full_line .= $line;
161
162         if ($full_line =~ /login:/) {
163             $booted = 1;
164         }
165
166         if ($full_line =~ /call trace:/i) {
167             $bug = 1;
168         }
169
170         if ($line =~ /\n/) {
171             $full_line = "";
172         }
173     }
174
175     doprint "kill child process $pid\n";
176     kill 2, $pid;
177
178     print "closing!\n";
179     close(IN);
180
181     if (!$booted) {
182         die "failed - never got a boot prompt.\n";
183     }
184
185     if ($bug) {
186         die "failed - got a bug report\n";
187     }
188 }
189
190 sub install {
191
192     if (run_command "scp $opt{OUTPUT_DIR}/$opt{BUILD_TARGET} $target:$opt{TARGET_IMAGE}") {
193         die "failed to copy image";
194     }
195
196     if ($install_mods) {
197         my $modlib = "/lib/modules/$version";
198
199         if (run_command "ssh $target rm -rf $modlib") {
200             die "failed to remove old mods: $modlib";
201         }
202
203         if (run_command "scp -r $opt{TMP_DIR}/lib $target:/lib/modules/$version") {
204             die "failed to copy modules";
205         }
206     }
207
208 }
209
210 sub build {
211     my ($type) = @_;
212
213     unlink "$opt{OUTPUT_DIR}/.config";
214
215     run_command "$make mrproper";
216
217     # add something to distinguish this build
218     open(OUT, "> $opt{OUTPUT_DIR}/localversion") or die("Can't make localversion file");
219     print OUT "$opt{LOCALVERSION}\n";
220     close(OUT);
221
222     if (run_command "$make $opt{$type}") {
223         die "failed make config";
224     }
225
226     if (defined($opt{"MIN_CONFIG"})) {
227         run_command "cat $opt{MIN_CONFIG} >> $opt{OUTPUT_DIR}/.config";
228         run_command "yes '' | $make oldconfig";
229     }
230
231     if (run_command "$make $opt{BUILD_OPTIONS}") {
232         die "failed build";
233     }
234 }
235
236 read_config $ARGV[0];
237
238 # mandatory configs
239 die "MACHINE not defined\n"             if (!defined($opt{"MACHINE"}));
240 die "SSH_USER not defined\n"            if (!defined($opt{"SSH_USER"}));
241 die "BUILD_DIR not defined\n"           if (!defined($opt{"BUILD_DIR"}));
242 die "OUTPUT_DIR not defined\n"          if (!defined($opt{"OUTPUT_DIR"}));
243 die "BUILD_TARGET not defined\n"        if (!defined($opt{"BUILD_TARGET"}));
244 die "POWER_CYCLE not defined\n"         if (!defined($opt{"POWER_CYCLE"}));
245 die "CONSOLE not defined\n"             if (!defined($opt{"CONSOLE"}));
246 die "LOCALVERSION not defined\n"        if (!defined($opt{"LOCALVERSION"}));
247 die "GRUB_MENU not defined\n"           if (!defined($opt{"GRUB_MENU"}));
248
249 chdir $opt{"BUILD_DIR"} || die "can't change directory to $opt{BUILD_DIR}";
250
251 $target = "$opt{SSH_USER}\@$opt{MACHINE}";
252
253 doprint "\n\nSTARTING AUTOMATED TESTS\n";
254
255 doprint "Find grub menu ... ";
256 $grub_number = -1;
257 open(IN, "ssh $target cat /boot/grub/menu.lst |")
258     or die "unable to get menu.lst";
259 while (<IN>) {
260     if (/^\s*title\s+$opt{GRUB_MENU}\s*$/) {
261         $grub_number++;
262         last;
263     } elsif (/^\s*title\s/) {
264         $grub_number++;
265     }
266 }
267 close(IN);
268 die "Could not find '$opt{GRUB_MENU}' in /boot/grub/menu on $opt{MACHINE}"
269     if ($grub_number < 0);
270 doprint "$grub_number\n";
271
272 $make = "$opt{MAKE_CMD} O=$opt{OUTPUT_DIR}";
273
274 # First we need to do is the builds
275 for (my $i = 1; $i <= $opt{"NUM_BUILDS"}; $i++) {
276     my $type = "BUILD_TYPE[$i]";
277
278     if (!defined($opt{$type})) {
279         $opt{$type} = $opt{"DEFAULT_BUILD_TYPE"};
280     }
281
282     doprint "\n\n";
283     doprint "RUNNING TEST $i of $opt{NUM_BUILDS} with option $opt{$type}\n\n";
284
285     if ($opt{$type} ne "nobuild") {
286         build $type;
287     }
288
289     # get the release name
290     doprint "$make kernelrelease ... ";
291     $version = `$make kernelrelease | tail -1`;
292     chomp($version);
293     doprint "$version\n";
294
295     # should we process modules?
296     $install_mods = 0;
297     open(IN, "$opt{OUTPUT_DIR}/.config") or die("Can't read config file");
298     while (<IN>) {
299         if (/CONFIG_MODULES(=y)?/) {
300             $install_mods = 1 if (defined($1));
301             last;
302         }
303     }
304     close(IN);
305
306     if ($install_mods) {
307         if (run_command "$make INSTALL_MOD_PATH=$opt{TMP_DIR} modules_install") {
308             die "Failed to install modules";
309         }
310     } else {
311         doprint "No modules needed\n";
312     }
313
314     install;
315
316     monitor;
317
318     doprint "\n\n*******************************************\n";
319     doprint     "*******************************************\n";
320     doprint     "**            SUCCESS!!!!                **\n";
321     doprint     "*******************************************\n";
322     doprint     "*******************************************\n";
323
324     # try to reboot normally
325
326     if (run_command "ssh $target reboot") {
327         # nope? power cycle it.
328         run_command "$opt{POWER_CYCLE}";
329     }
330
331     sleep "$opt{SLEEP_TIME}";
332 }
333
334 exit 0;