Home | History | Annotate | Download | only in cros
      1 # Copyright 2014 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import gzip, logging, os, re
      6 from autotest_lib.client.bin import utils
      7 from autotest_lib.client.common_lib import error
      8 
      9 class KernelConfig():
     10     """
     11     Parse the kernel config and enable us to query it.
     12     Used to verify the kernel config (see kernel_ConfigVerify).
     13     """
     14 
     15     def _passed(self, msg):
     16         logging.info('ok: %s', msg)
     17 
     18     def _failed(self, msg):
     19         logging.error('FAIL: %s', msg)
     20         self._failures.append(msg)
     21 
     22     def failures(self):
     23         """Return the list of failures that occured during the test.
     24 
     25         @return a list of string describing errors that occured since
     26                 initialization.
     27         """
     28         return self._failures
     29 
     30     def _fatal(self, msg):
     31         logging.error('FATAL: %s', msg)
     32         raise error.TestError(msg)
     33 
     34     def get(self, key, default):
     35         """Get the value associated to key or default if it does not exist
     36 
     37         @param key: key to look for.
     38         @param default: value returned if key is not set in self._config
     39         """
     40         return self._config.get(key, default)
     41 
     42     def _config_required(self, name, wanted):
     43         value = self._config.get(name, None)
     44         if value in wanted:
     45             self._passed('"%s" was "%s" in kernel config' % (name, value))
     46         else:
     47             states = []
     48             for state in wanted:
     49                 if state == None:
     50                     states.append("unset")
     51                 else:
     52                     states.append(state)
     53             self._failed('"%s" was "%s" (wanted one of "%s") in kernel config' %
     54                          (name, value, '|'.join(states)))
     55 
     56     def has_value(self, name, value):
     57         """Determine if the name config item has a specific value.
     58 
     59         @param name: name of config item to test
     60         @param value: value expected for the given config name
     61         """
     62         self._config_required('CONFIG_%s' % (name), value)
     63 
     64     def has_builtin(self, name):
     65         """Check if the specific config item is built-in (present but not
     66         built as a module).
     67 
     68         @param name: name of config item to test
     69         """
     70         wanted = ['y']
     71         if name in self._missing_ok:
     72             wanted.append(None)
     73         self.has_value(name, wanted)
     74 
     75     def has_module(self, name):
     76         """Check if the specific config item is a module (present but not
     77         built-in).
     78 
     79         @param name: name of config item to test
     80         """
     81         wanted = ['m']
     82         if name in self._missing_ok:
     83             wanted.append(None)
     84         self.has_value(name, wanted)
     85 
     86     def is_enabled(self, name):
     87         """Check if the specific config item is present (either built-in or
     88         a module).
     89 
     90         @param name: name of config item to test
     91         """
     92         wanted = ['y', 'm']
     93         if name in self._missing_ok:
     94             wanted.append(None)
     95         self.has_value(name, wanted)
     96 
     97     def is_missing(self, name):
     98         """Check if the specific config item is not present (neither built-in
     99         nor a module).
    100 
    101         @param name: name of config item to test
    102         """
    103         self.has_value(name, [None])
    104 
    105     def is_exclusive(self, exclusive):
    106         """Given a config item regex, make sure only the expected items
    107         are present in the kernel configs.
    108 
    109         @param exclusive: hash containing "missing", "builtin", "module",
    110                           "enabled" each to be checked with the corresponding
    111                           has_* function based on config items matching the
    112                           "regex" value.
    113         """
    114         expected = set()
    115         for name in exclusive['missing']:
    116             self.is_missing(name)
    117         for name in exclusive['builtin']:
    118             self.has_builtin(name)
    119             expected.add('CONFIG_%s' % (name))
    120         for name in exclusive['module']:
    121             self.has_module(name)
    122             expected.add('CONFIG_%s' % (name))
    123         for name in exclusive['enabled']:
    124             self.is_enabled(name)
    125             expected.add('CONFIG_%s' % (name))
    126 
    127         # Now make sure nothing else with the specified regex exists.
    128         regex = r'CONFIG_%s' % (exclusive['regex'])
    129         for name in self._config:
    130             if not re.match(regex, name):
    131                 continue
    132             if not name in expected:
    133                 self._failed('"%s" found for "%s" when only "%s" allowed' %
    134                              (name, regex, "|".join(expected)))
    135 
    136     def _open_config(self):
    137         """Open the kernel's build config file. Attempt to use the built-in
    138         symbols from /proc first, then fall back to looking for a text file
    139         in /boot.
    140 
    141         @return fileobj for open config file
    142         """
    143         filename = '/proc/config.gz'
    144         if not os.path.exists(filename):
    145             utils.system("modprobe configs", ignore_status=True)
    146         if os.path.exists(filename):
    147             return gzip.open(filename, "r")
    148 
    149         filename = '/boot/config-%s' % utils.system_output('uname -r')
    150         if os.path.exists(filename):
    151             logging.info('Falling back to reading %s', filename)
    152             return file(filename, "r")
    153 
    154         self._fatal("Cannot locate suitable kernel config file")
    155 
    156     def initialize(self, missing_ok=None):
    157         """Load the kernel configuration and parse it.
    158         """
    159         fileobj = self._open_config()
    160         # Import kernel config variables into a dictionary for each searching.
    161         config = dict()
    162         for item in fileobj.readlines():
    163             item = item.strip()
    164             if not '=' in item:
    165                 continue
    166             key, value = item.split('=', 1)
    167             config[key] = value
    168 
    169         # Make sure we actually loaded something sensible.
    170         if len(config) == 0:
    171             self._fatal('No CONFIG variables found!')
    172 
    173         self._config = config
    174         self._failures = []
    175         self._missing_ok = set()
    176         if missing_ok:
    177             self._missing_ok |= set(missing_ok)
    178