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