Home | History | Annotate | Download | only in bin
      1 import os, shutil, copy, pickle, re, glob, time, logging
      2 from autotest_lib.client.bin import kernel_config, os_dep, kernelexpand, test
      3 from autotest_lib.client.bin import utils
      4 from autotest_lib.client.common_lib import log, error, packages
      5 
      6 
      7 def 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 
     24 def _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 
     75 class 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 
    122 class 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 
    701 class 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 
    798 class 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 
    825 def 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
    834 def _preprocess_path_dummy(path):
    835     return path.strip()
    836 
    837 
    838 # pull in some optional site-specific path pre-processing
    839 preprocess_path = utils.import_site_function(__file__,
    840     "autotest_lib.client.bin.site_kernel", "preprocess_path",
    841     _preprocess_path_dummy)
    842 
    843 
    844 def 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