1import os, shutil, copy, pickle, re, glob, time, logging 2from autotest_lib.client.bin import kernel_config, os_dep, kernelexpand, test 3from autotest_lib.client.bin import utils 4from autotest_lib.client.common_lib import log, error, packages 5 6 7def tee_output_logdir_mark(fn): 8 def tee_logdir_mark_wrapper(self, *args, **dargs): 9 mark = self.__class__.__name__ + "." + fn.__name__ 10 logging.info("--- START %s ---", mark) 11 self.job.logging.tee_redirect_debug_dir(self.log_dir) 12 try: 13 result = fn(self, *args, **dargs) 14 finally: 15 self.job.logging.restore() 16 logging.info("--- END %s ---", mark) 17 18 return result 19 20 tee_logdir_mark_wrapper.__name__ = fn.__name__ 21 return tee_logdir_mark_wrapper 22 23 24def _add_kernel_to_bootloader(bootloader, base_args, tag, args, image, initrd): 25 """ 26 Add a kernel with the specified tag to the boot config using the given 27 bootloader object. Also process the base_args and args kernel arguments 28 by removing all root= options and give the last root= option value to 29 the bootloader as a root device. 30 31 @param bootloader: bootloader object 32 @param base_args: base cmdline kernel arguments 33 @param tag: kernel tag 34 @param args: kernel cmdline arguments that are merged with base_args; a 35 root= option in "args" will override any from base_args 36 @param image: kernel image file 37 @param initrd: initrd file 38 """ 39 # remove existing entry if present 40 bootloader.remove_kernel(tag) 41 42 if base_args: 43 args = ' '.join((base_args, args)) 44 45 root_prefix = 'root=' 46 # stores the last root= value 47 root = None 48 # a list with all arguments that don't start with root= so we give them 49 # later to bootloader.add_kernel() 50 arglist = [] 51 52 for arg in args.split(): 53 if arg.startswith(root_prefix): 54 # set the current root value with the one from the argument 55 # thus after processing all the arguments we keep the last 56 # root value (so root= options from args overrides any from 57 # base_args) 58 root = arg[len(root_prefix):] 59 else: 60 arglist.append(arg) 61 62 # Add the kernel entry. it will keep all arguments from the default entry. 63 # args='_dummy_' is used to workaround a boottool limitation of not being 64 # able to add arguments to a kernel that does not already have any of its 65 # own by way of its own append= section below the image= line in lilo.conf. 66 bootloader.add_kernel(image, tag, initrd=initrd, root=root, args='_dummy_') 67 # Now, for each argument in arglist, try to add it to the kernel that was 68 # just added. In each step, if the arg already existed on the args string, 69 # that particular arg will be skipped 70 for a in arglist: 71 bootloader.add_args(kernel=tag, args=a) 72 bootloader.remove_args(kernel=tag, args='_dummy_') 73 74 75class BootableKernel(object): 76 77 def __init__(self, job): 78 self.job = job 79 self.installed_as = None # kernel choice in bootloader menu 80 self.image = None 81 self.initrd = '' 82 83 84 def _boot_kernel(self, args, ident_check, expected_ident, subdir, notes): 85 """ 86 Boot a kernel, with post-boot kernel id check 87 88 @param args: kernel cmdline arguments 89 @param ident_check: check kernel id after boot 90 @param expected_ident: 91 @param subdir: job-step qualifier in status log 92 @param notes: additional comment in status log 93 """ 94 # If we can check the kernel identity do so. 95 if ident_check: 96 when = int(time.time()) 97 args += " IDENT=%d" % when 98 self.job.next_step_prepend(["job.end_reboot_and_verify", when, 99 expected_ident, subdir, notes]) 100 else: 101 self.job.next_step_prepend(["job.end_reboot", subdir, 102 expected_ident, notes]) 103 104 self.add_to_bootloader(args) 105 106 # defer fsck for next reboot, to avoid reboots back to default kernel 107 utils.system('touch /fastboot') # this file is removed automatically 108 109 # Boot it. 110 self.job.start_reboot() 111 self.job.reboot(tag=self.installed_as) 112 113 114 def add_to_bootloader(self, args=''): 115 # Point bootloader to the selected tag. 116 _add_kernel_to_bootloader(self.job.bootloader, 117 self.job.config_get('boot.default_args'), 118 self.installed_as, args, self.image, 119 self.initrd) 120 121 122class kernel(BootableKernel): 123 """ Class for compiling kernels. 124 125 Data for the object includes the src files 126 used to create the kernel, patches applied, config (base + changes), 127 the build directory itself, and logged output 128 129 Properties: 130 job 131 Backpointer to the job object we're part of 132 autodir 133 Path to the top level autotest dir (/usr/local/autotest) 134 src_dir 135 <tmp_dir>/src/ 136 build_dir 137 <tmp_dir>/linux/ 138 config_dir 139 <results_dir>/config/ 140 log_dir 141 <results_dir>/debug/ 142 results_dir 143 <results_dir>/results/ 144 """ 145 146 autodir = '' 147 148 def __init__(self, job, base_tree, subdir, tmp_dir, build_dir, leave=False): 149 """Initialize the kernel build environment 150 151 job 152 which job this build is part of 153 base_tree 154 base kernel tree. Can be one of the following: 155 1. A local tarball 156 2. A URL to a tarball 157 3. A local directory (will symlink it) 158 4. A shorthand expandable (eg '2.6.11-git3') 159 subdir 160 subdir in the results directory (eg "build") 161 (holds config/, debug/, results/) 162 tmp_dir 163 164 leave 165 Boolean, whether to leave existing tmpdir or not 166 """ 167 super(kernel, self).__init__(job) 168 self.autodir = job.autodir 169 170 self.src_dir = os.path.join(tmp_dir, 'src') 171 self.build_dir = os.path.join(tmp_dir, build_dir) 172 # created by get_kernel_tree 173 self.config_dir = os.path.join(subdir, 'config') 174 self.log_dir = os.path.join(subdir, 'debug') 175 self.results_dir = os.path.join(subdir, 'results') 176 self.subdir = os.path.basename(subdir) 177 178 if not leave: 179 if os.path.isdir(self.src_dir): 180 utils.system('rm -rf ' + self.src_dir) 181 if os.path.isdir(self.build_dir): 182 utils.system('rm -rf ' + self.build_dir) 183 184 if not os.path.exists(self.src_dir): 185 os.mkdir(self.src_dir) 186 for path in [self.config_dir, self.log_dir, self.results_dir]: 187 if os.path.exists(path): 188 utils.system('rm -rf ' + path) 189 os.mkdir(path) 190 191 logpath = os.path.join(self.log_dir, 'build_log') 192 self.logfile = open(logpath, 'w+') 193 self.applied_patches = [] 194 195 self.target_arch = None 196 self.build_target = 'bzImage' 197 self.build_image = None 198 199 arch = utils.get_current_kernel_arch() 200 if arch == 's390' or arch == 's390x': 201 self.build_target = 'image' 202 elif arch == 'ia64': 203 self.build_target = 'all' 204 self.build_image = 'vmlinux.gz' 205 206 if not leave: 207 self.logfile.write('BASE: %s\n' % base_tree) 208 209 # Where we have direct version hint record that 210 # for later configuration selection. 211 shorthand = re.compile(r'^\d+\.\d+\.\d+') 212 if shorthand.match(base_tree): 213 self.base_tree_version = base_tree 214 else: 215 self.base_tree_version = None 216 217 # Actually extract the tree. Make sure we know it occured 218 self.extract(base_tree) 219 220 221 def kernelexpand(self, kernel): 222 # If we have something like a path, just use it as it is 223 if '/' in kernel: 224 return [kernel] 225 226 # Find the configured mirror list. 227 mirrors = self.job.config_get('mirror.mirrors') 228 if not mirrors: 229 # LEGACY: convert the kernel.org mirror 230 mirror = self.job.config_get('mirror.ftp_kernel_org') 231 if mirror: 232 korg = 'http://www.kernel.org/pub/linux/kernel' 233 mirrors = [ 234 [ korg + '/v2.6', mirror + '/v2.6' ], 235 [ korg + '/people/akpm/patches/2.6', mirror + '/akpm' ], 236 [ korg + '/people/mbligh', mirror + '/mbligh' ], 237 ] 238 239 patches = kernelexpand.expand_classic(kernel, mirrors) 240 print patches 241 242 return patches 243 244 245 @log.record 246 @tee_output_logdir_mark 247 def extract(self, base_tree): 248 if os.path.exists(base_tree): 249 self.get_kernel_tree(base_tree) 250 else: 251 base_components = self.kernelexpand(base_tree) 252 print 'kernelexpand: ' 253 print base_components 254 self.get_kernel_tree(base_components.pop(0)) 255 if base_components: # apply remaining patches 256 self.patch(*base_components) 257 258 259 @log.record 260 @tee_output_logdir_mark 261 def patch(self, *patches): 262 """Apply a list of patches (in order)""" 263 if not patches: 264 return 265 print 'Applying patches: ', patches 266 self.apply_patches(self.get_patches(patches)) 267 268 269 @log.record 270 @tee_output_logdir_mark 271 def config(self, config_file = '', config_list = None, defconfig = False, make = None): 272 self.set_cross_cc() 273 config = kernel_config.kernel_config(self.job, self.build_dir, 274 self.config_dir, config_file, config_list, 275 defconfig, self.base_tree_version, make) 276 277 278 def get_patches(self, patches): 279 """fetch the patches to the local src_dir""" 280 local_patches = [] 281 for patch in patches: 282 dest = os.path.join(self.src_dir, os.path.basename(patch)) 283 # FIXME: this isn't unique. Append something to it 284 # like wget does if it's not there? 285 print "get_file %s %s %s %s" % (patch, dest, self.src_dir, 286 os.path.basename(patch)) 287 utils.get_file(patch, dest) 288 # probably safer to use the command, not python library 289 md5sum = utils.system_output('md5sum ' + dest).split()[0] 290 local_patches.append((patch, dest, md5sum)) 291 return local_patches 292 293 294 def apply_patches(self, local_patches): 295 """apply the list of patches, in order""" 296 builddir = self.build_dir 297 os.chdir(builddir) 298 299 if not local_patches: 300 return None 301 for (spec, local, md5sum) in local_patches: 302 if local.endswith('.bz2') or local.endswith('.gz'): 303 ref = spec 304 else: 305 ref = utils.force_copy(local, self.results_dir) 306 ref = self.job.relative_path(ref) 307 patch_id = "%s %s %s" % (spec, ref, md5sum) 308 log = "PATCH: " + patch_id + "\n" 309 print log 310 utils.cat_file_to_cmd(local, 'patch -p1 > /dev/null') 311 self.logfile.write(log) 312 self.applied_patches.append(patch_id) 313 314 315 def get_kernel_tree(self, base_tree): 316 """Extract/link base_tree to self.build_dir""" 317 318 # if base_tree is a dir, assume uncompressed kernel 319 if os.path.isdir(base_tree): 320 print 'Symlinking existing kernel source' 321 if os.path.islink(self.build_dir): 322 os.remove(self.build_dir) 323 os.symlink(base_tree, self.build_dir) 324 325 # otherwise, extract tarball 326 else: 327 os.chdir(os.path.dirname(self.src_dir)) 328 # Figure out local destination for tarball 329 tarball = os.path.join(self.src_dir, os.path.basename(base_tree.split(';')[0])) 330 utils.get_file(base_tree, tarball) 331 print 'Extracting kernel tarball:', tarball, '...' 332 utils.extract_tarball_to_dir(tarball, self.build_dir) 333 334 335 def extraversion(self, tag, append=True): 336 os.chdir(self.build_dir) 337 extraversion_sub = r's/^CONFIG_LOCALVERSION=\s*"\(.*\)"/CONFIG_LOCALVERSION=' 338 cfg = self.build_dir + '/.config' 339 if append: 340 p = extraversion_sub + '"\\1-%s"/' % tag 341 else: 342 p = extraversion_sub + '"-%s"/' % tag 343 utils.system('mv %s %s.old' % (cfg, cfg)) 344 utils.system("sed '%s' < %s.old > %s" % (p, cfg, cfg)) 345 self.config(make='oldconfig') 346 347 348 @log.record 349 @tee_output_logdir_mark 350 def build(self, make_opts = '', logfile = '', extraversion='autotest'): 351 """build the kernel 352 353 make_opts 354 additional options to make, if any 355 """ 356 os_dep.commands('gcc', 'make') 357 if logfile == '': 358 logfile = os.path.join(self.log_dir, 'kernel_build') 359 os.chdir(self.build_dir) 360 if extraversion: 361 self.extraversion(extraversion) 362 self.set_cross_cc() 363 # setup_config_file(config_file, config_overrides) 364 365 # Not needed on 2.6, but hard to tell -- handle failure 366 utils.system('make dep', ignore_status=True) 367 threads = 2 * utils.count_cpus() 368 build_string = 'make -j %d %s %s' % (threads, make_opts, 369 self.build_target) 370 # eg make bzImage, or make zImage 371 print build_string 372 utils.system(build_string) 373 if kernel_config.modules_needed('.config'): 374 utils.system('make -j %d modules' % (threads)) 375 376 kernel_version = self.get_kernel_build_ver() 377 kernel_version = re.sub('-autotest', '', kernel_version) 378 self.logfile.write('BUILD VERSION: %s\n' % kernel_version) 379 380 utils.force_copy(self.build_dir+'/System.map', 381 self.results_dir) 382 383 384 def build_timed(self, threads, timefile = '/dev/null', make_opts = '', 385 output = '/dev/null'): 386 """time the bulding of the kernel""" 387 os.chdir(self.build_dir) 388 self.set_cross_cc() 389 390 self.clean() 391 build_string = "/usr/bin/time -o %s make %s -j %s vmlinux" \ 392 % (timefile, make_opts, threads) 393 build_string += ' > %s 2>&1' % output 394 print build_string 395 utils.system(build_string) 396 397 if (not os.path.isfile('vmlinux')): 398 errmsg = "no vmlinux found, kernel build failed" 399 raise error.TestError(errmsg) 400 401 402 @log.record 403 @tee_output_logdir_mark 404 def clean(self): 405 """make clean in the kernel tree""" 406 os.chdir(self.build_dir) 407 print "make clean" 408 utils.system('make clean > /dev/null 2> /dev/null') 409 410 411 @log.record 412 @tee_output_logdir_mark 413 def mkinitrd(self, version, image, system_map, initrd): 414 """Build kernel initrd image. 415 Try to use distro specific way to build initrd image. 416 Parameters: 417 version 418 new kernel version 419 image 420 new kernel image file 421 system_map 422 System.map file 423 initrd 424 initrd image file to build 425 """ 426 vendor = utils.get_os_vendor() 427 428 if os.path.isfile(initrd): 429 print "Existing %s file, will remove it." % initrd 430 os.remove(initrd) 431 432 args = self.job.config_get('kernel.mkinitrd_extra_args') 433 434 # don't leak 'None' into mkinitrd command 435 if not args: 436 args = '' 437 438 # It is important to match the version with a real directory inside 439 # /lib/modules 440 real_version_list = glob.glob('/lib/modules/%s*' % version) 441 rl = len(real_version_list) 442 if rl == 0: 443 logging.error("No directory %s found under /lib/modules. Initramfs" 444 "creation will most likely fail and your new kernel" 445 "will fail to build", version) 446 else: 447 if rl > 1: 448 logging.warning("Found more than one possible match for " 449 "kernel version %s under /lib/modules", version) 450 version = os.path.basename(real_version_list[0]) 451 452 if vendor in ['Red Hat', 'Fedora Core']: 453 try: 454 cmd = os_dep.command('dracut') 455 full_cmd = '%s -f %s %s' % (cmd, initrd, version) 456 except ValueError: 457 cmd = os_dep.command('mkinitrd') 458 full_cmd = '%s %s %s %s' % (cmd, args, initrd, version) 459 utils.system(full_cmd) 460 elif vendor in ['SUSE']: 461 utils.system('mkinitrd %s -k %s -i %s -M %s' % 462 (args, image, initrd, system_map)) 463 elif vendor in ['Debian', 'Ubuntu']: 464 if os.path.isfile('/usr/sbin/mkinitrd'): 465 cmd = '/usr/sbin/mkinitrd' 466 elif os.path.isfile('/usr/sbin/mkinitramfs'): 467 cmd = '/usr/sbin/mkinitramfs' 468 else: 469 raise error.TestError('No Debian initrd builder') 470 utils.system('%s %s -o %s %s' % (cmd, args, initrd, version)) 471 else: 472 raise error.TestError('Unsupported vendor %s' % vendor) 473 474 475 def set_build_image(self, image): 476 self.build_image = image 477 478 479 @log.record 480 @tee_output_logdir_mark 481 def install(self, tag='autotest', prefix = '/'): 482 """make install in the kernel tree""" 483 484 # Record that we have installed the kernel, and 485 # the tag under which we installed it. 486 self.installed_as = tag 487 488 os.chdir(self.build_dir) 489 490 if not os.path.isdir(prefix): 491 os.mkdir(prefix) 492 self.boot_dir = os.path.join(prefix, 'boot') 493 if not os.path.isdir(self.boot_dir): 494 os.mkdir(self.boot_dir) 495 496 if not self.build_image: 497 images = glob.glob('arch/*/boot/' + self.build_target) 498 if len(images): 499 self.build_image = images[0] 500 else: 501 self.build_image = self.build_target 502 503 # remember installed files 504 self.vmlinux = self.boot_dir + '/vmlinux-' + tag 505 if (self.build_image != 'vmlinux'): 506 self.image = self.boot_dir + '/vmlinuz-' + tag 507 else: 508 self.image = self.vmlinux 509 self.system_map = self.boot_dir + '/System.map-' + tag 510 self.config_file = self.boot_dir + '/config-' + tag 511 self.initrd = '' 512 513 # copy to boot dir 514 utils.force_copy('vmlinux', self.vmlinux) 515 if (self.build_image != 'vmlinux'): 516 utils.force_copy(self.build_image, self.image) 517 utils.force_copy('System.map', self.system_map) 518 utils.force_copy('.config', self.config_file) 519 520 if not kernel_config.modules_needed('.config'): 521 return 522 523 utils.system('make modules_install INSTALL_MOD_PATH=%s' % prefix) 524 if prefix == '/': 525 self.initrd = self.boot_dir + '/initrd-' + tag 526 self.mkinitrd(self.get_kernel_build_ver(), self.image, 527 self.system_map, self.initrd) 528 529 530 def get_kernel_build_arch(self, arch=None): 531 """ 532 Work out the current kernel architecture (as a kernel arch) 533 """ 534 if not arch: 535 arch = utils.get_current_kernel_arch() 536 if re.match('i.86', arch): 537 return 'i386' 538 elif re.match('sun4u', arch): 539 return 'sparc64' 540 elif re.match('arm.*', arch): 541 return 'arm' 542 elif re.match('sa110', arch): 543 return 'arm' 544 elif re.match('s390x', arch): 545 return 's390' 546 elif re.match('parisc64', arch): 547 return 'parisc' 548 elif re.match('ppc.*', arch): 549 return 'powerpc' 550 elif re.match('mips.*', arch): 551 return 'mips' 552 else: 553 return arch 554 555 556 def get_kernel_build_release(self): 557 releasem = re.compile(r'.*UTS_RELEASE\s+"([^"]+)".*'); 558 versionm = re.compile(r'.*UTS_VERSION\s+"([^"]+)".*'); 559 560 release = None 561 version = None 562 563 for f in [self.build_dir + "/include/linux/version.h", 564 self.build_dir + "/include/linux/utsrelease.h", 565 self.build_dir + "/include/linux/compile.h", 566 self.build_dir + "/include/generated/utsrelease.h", 567 self.build_dir + "/include/generated/compile.h"]: 568 if os.path.exists(f): 569 fd = open(f, 'r') 570 for line in fd.readlines(): 571 m = releasem.match(line) 572 if m: 573 release = m.groups()[0] 574 m = versionm.match(line) 575 if m: 576 version = m.groups()[0] 577 fd.close() 578 579 return (release, version) 580 581 582 def get_kernel_build_ident(self): 583 (release, version) = self.get_kernel_build_release() 584 585 if not release or not version: 586 raise error.JobError('kernel has no identity') 587 588 return release + '::' + version 589 590 591 def boot(self, args='', ident=True): 592 """ install and boot this kernel, do not care how 593 just make it happen. 594 """ 595 596 # If the kernel has not yet been installed, 597 # install it now as default tag. 598 if not self.installed_as: 599 self.install() 600 601 expected_ident = self.get_kernel_build_ident() 602 self._boot_kernel(args, ident, expected_ident, 603 self.subdir, self.applied_patches) 604 605 606 def get_kernel_build_ver(self): 607 """Check Makefile and .config to return kernel version""" 608 version = patchlevel = sublevel = extraversion = localversion = '' 609 610 for line in open(self.build_dir + '/Makefile', 'r').readlines(): 611 if line.startswith('VERSION'): 612 version = line[line.index('=') + 1:].strip() 613 if line.startswith('PATCHLEVEL'): 614 patchlevel = line[line.index('=') + 1:].strip() 615 if line.startswith('SUBLEVEL'): 616 sublevel = line[line.index('=') + 1:].strip() 617 if line.startswith('EXTRAVERSION'): 618 extraversion = line[line.index('=') + 1:].strip() 619 620 for line in open(self.build_dir + '/.config', 'r').readlines(): 621 if line.startswith('CONFIG_LOCALVERSION='): 622 localversion = line.rstrip().split('"')[1] 623 624 return "%s.%s.%s%s%s" %(version, patchlevel, sublevel, extraversion, localversion) 625 626 627 def set_build_target(self, build_target): 628 if build_target: 629 self.build_target = build_target 630 print 'BUILD TARGET: %s' % self.build_target 631 632 633 def set_cross_cc(self, target_arch=None, cross_compile=None, 634 build_target='bzImage'): 635 """Set up to cross-compile. 636 This is broken. We need to work out what the default 637 compile produces, and if not, THEN set the cross 638 compiler. 639 """ 640 641 if self.target_arch: 642 return 643 644 # if someone has set build_target, don't clobber in set_cross_cc 645 # run set_build_target before calling set_cross_cc 646 if not self.build_target: 647 self.set_build_target(build_target) 648 649 # If no 'target_arch' given assume native compilation 650 if target_arch is None: 651 target_arch = utils.get_current_kernel_arch() 652 if target_arch == 'ppc64': 653 if self.build_target == 'bzImage': 654 self.build_target = 'vmlinux' 655 656 if not cross_compile: 657 cross_compile = self.job.config_get('kernel.cross_cc') 658 659 if cross_compile: 660 os.environ['CROSS_COMPILE'] = cross_compile 661 else: 662 if os.environ.has_key('CROSS_COMPILE'): 663 del os.environ['CROSS_COMPILE'] 664 665 return # HACK. Crap out for now. 666 667 # At this point I know what arch I *want* to build for 668 # but have no way of working out what arch the default 669 # compiler DOES build for. 670 671 def install_package(package): 672 raise NotImplementedError("I don't exist yet!") 673 674 if target_arch == 'ppc64': 675 install_package('ppc64-cross') 676 cross_compile = os.path.join(self.autodir, 'sources/ppc64-cross/bin') 677 678 elif target_arch == 'x86_64': 679 install_package('x86_64-cross') 680 cross_compile = os.path.join(self.autodir, 'sources/x86_64-cross/bin') 681 682 os.environ['ARCH'] = self.target_arch = target_arch 683 684 self.cross_compile = cross_compile 685 if self.cross_compile: 686 os.environ['CROSS_COMPILE'] = self.cross_compile 687 688 689 def pickle_dump(self, filename): 690 """dump a pickle of ourself out to the specified filename 691 692 we can't pickle the backreference to job (it contains fd's), 693 nor would we want to. Same for logfile (fd's). 694 """ 695 temp = copy.copy(self) 696 temp.job = None 697 temp.logfile = None 698 pickle.dump(temp, open(filename, 'w')) 699 700 701class rpm_kernel(BootableKernel): 702 """ 703 Class for installing a binary rpm kernel package 704 """ 705 706 def __init__(self, job, rpm_package, subdir): 707 super(rpm_kernel, self).__init__(job) 708 self.rpm_package = rpm_package 709 self.log_dir = os.path.join(subdir, 'debug') 710 self.subdir = os.path.basename(subdir) 711 if os.path.exists(self.log_dir): 712 utils.system('rm -rf ' + self.log_dir) 713 os.mkdir(self.log_dir) 714 715 716 def build(self, *args, **dargs): 717 """ 718 Dummy function, binary kernel so nothing to build. 719 """ 720 pass 721 722 723 @log.record 724 @tee_output_logdir_mark 725 def install(self, tag='autotest', install_vmlinux=True): 726 self.installed_as = tag 727 728 self.image = None 729 self.initrd = '' 730 for rpm_pack in self.rpm_package: 731 rpm_name = utils.system_output('rpm -qp ' + rpm_pack) 732 733 # install 734 utils.system('rpm -i --force ' + rpm_pack) 735 736 # get file list 737 files = utils.system_output('rpm -ql ' + rpm_name).splitlines() 738 739 # search for vmlinuz 740 for file in files: 741 if file.startswith('/boot/vmlinuz'): 742 self.full_version = file[len('/boot/vmlinuz-'):] 743 self.image = file 744 self.rpm_flavour = rpm_name.split('-')[1] 745 746 # get version and release number 747 self.version, self.release = utils.system_output( 748 'rpm --queryformat="%{VERSION}\\n%{RELEASE}\\n" -q ' 749 + rpm_name).splitlines()[0:2] 750 751 # prefer /boot/kernel-version before /boot/kernel 752 if self.full_version: 753 break 754 755 # search for initrd 756 for file in files: 757 if file.startswith('/boot/init'): 758 self.initrd = file 759 # prefer /boot/initrd-version before /boot/initrd 760 if len(file) > len('/boot/initrd'): 761 break 762 763 if self.image == None: 764 errmsg = "specified rpm file(s) don't contain /boot/vmlinuz" 765 raise error.TestError(errmsg) 766 767 # install vmlinux 768 if install_vmlinux: 769 for rpm_pack in self.rpm_package: 770 vmlinux = utils.system_output( 771 'rpm -q -l -p %s | grep /boot/vmlinux' % rpm_pack) 772 utils.system('cd /; rpm2cpio %s | cpio -imuv .%s 2>&1' 773 % (rpm_pack, vmlinux)) 774 if not os.path.exists(vmlinux): 775 raise error.TestError('%s does not exist after installing %s' 776 % (vmlinux, rpm_pack)) 777 778 779 def boot(self, args='', ident=True): 780 """ install and boot this kernel 781 """ 782 783 # If the kernel has not yet been installed, 784 # install it now as default tag. 785 if not self.installed_as: 786 self.install() 787 788 expected_ident = self.full_version 789 if not expected_ident: 790 expected_ident = '-'.join([self.version, 791 self.rpm_flavour, 792 self.release]) 793 794 self._boot_kernel(args, ident, expected_ident, 795 None, 'rpm') 796 797 798class rpm_kernel_suse(rpm_kernel): 799 """ Class for installing openSUSE/SLE rpm kernel package 800 """ 801 802 def install(self): 803 # do not set the new kernel as the default one 804 os.environ['PBL_AUTOTEST'] = '1' 805 806 rpm_kernel.install(self, 'dummy') 807 self.installed_as = self.job.bootloader.get_title_for_kernel(self.image) 808 if not self.installed_as: 809 errmsg = "cannot find installed kernel in bootloader configuration" 810 raise error.TestError(errmsg) 811 812 813 def add_to_bootloader(self, tag='dummy', args=''): 814 """ Set parameters of this kernel in bootloader 815 """ 816 817 # pull the base argument set from the job config 818 baseargs = self.job.config_get('boot.default_args') 819 if baseargs: 820 args = baseargs + ' ' + args 821 822 self.job.bootloader.add_args(tag, args) 823 824 825def rpm_kernel_vendor(job, rpm_package, subdir): 826 vendor = utils.get_os_vendor() 827 if vendor == "SUSE": 828 return rpm_kernel_suse(job, rpm_package, subdir) 829 else: 830 return rpm_kernel(job, rpm_package, subdir) 831 832 833# just make the preprocessor a nop 834def _preprocess_path_dummy(path): 835 return path.strip() 836 837 838# pull in some optional site-specific path pre-processing 839preprocess_path = utils.import_site_function(__file__, 840 "autotest_lib.client.bin.site_kernel", "preprocess_path", 841 _preprocess_path_dummy) 842 843 844def auto_kernel(job, path, subdir, tmp_dir, build_dir, leave=False): 845 """ 846 Create a kernel object, dynamically selecting the appropriate class to use 847 based on the path provided. 848 """ 849 kernel_paths = [preprocess_path(path)] 850 if kernel_paths[0].endswith('.list'): 851 # Fetch the list of packages to install 852 kernel_list = os.path.join(tmp_dir, 'kernel.list') 853 utils.get_file(kernel_paths[0], kernel_list) 854 kernel_paths = [p.strip() for p in open(kernel_list).readlines()] 855 856 if kernel_paths[0].endswith('.rpm'): 857 rpm_paths = [] 858 for kernel_path in kernel_paths: 859 if os.path.exists(kernel_path): 860 rpm_paths.append(kernel_path) 861 else: 862 # Fetch the rpm into the job's packages directory and pass it to 863 # rpm_kernel 864 rpm_name = os.path.basename(kernel_path) 865 866 # If the preprocessed path (kernel_path) is only a name then 867 # search for the kernel in all the repositories, else fetch the 868 # kernel from that specific path. 869 job.pkgmgr.fetch_pkg(rpm_name, os.path.join(job.pkgdir, rpm_name), 870 repo_url=os.path.dirname(kernel_path)) 871 872 rpm_paths.append(os.path.join(job.pkgdir, rpm_name)) 873 return rpm_kernel_vendor(job, rpm_paths, subdir) 874 else: 875 if len(kernel_paths) > 1: 876 raise error.TestError("don't know what to do with more than one non-rpm kernel file") 877 return kernel(job,kernel_paths[0], subdir, tmp_dir, build_dir, leave) 878