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