| # Lint as: python2, python3 | |
| # Copyright 2014 The Chromium OS Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| import gzip, logging, os, re | |
| from autotest_lib.client.bin import utils | |
| from autotest_lib.client.common_lib import error | |
| class KernelConfig(): | |
| """ | |
| Parse the kernel config and enable us to query it. | |
| Used to verify the kernel config (see kernel_ConfigVerify). | |
| """ | |
| def _passed(self, msg): | |
| logging.info('ok: %s', msg) | |
| def _failed(self, msg): | |
| logging.error('FAIL: %s', msg) | |
| self._failures.append(msg) | |
| def failures(self): | |
| """Return the list of failures that occured during the test. | |
| @return a list of string describing errors that occured since | |
| initialization. | |
| """ | |
| return self._failures | |
| def _fatal(self, msg): | |
| logging.error('FATAL: %s', msg) | |
| raise error.TestError(msg) | |
| def get(self, key, default): | |
| """Get the value associated to key or default if it does not exist | |
| @param key: key to look for. | |
| @param default: value returned if key is not set in self._config | |
| """ | |
| return self._config.get(key, default) | |
| def _config_required(self, name, wanted): | |
| value = self._config.get(name, None) | |
| if value in wanted: | |
| self._passed('"%s" was "%s" in kernel config' % (name, value)) | |
| else: | |
| states = [] | |
| for state in wanted: | |
| if state == None: | |
| states.append("unset") | |
| else: | |
| states.append(state) | |
| self._failed('"%s" was "%s" (wanted one of "%s") in kernel config' % | |
| (name, value, '|'.join(states))) | |
| def has_value(self, name, value): | |
| """Determine if the name config item has a specific value. | |
| @param name: name of config item to test | |
| @param value: value expected for the given config name | |
| """ | |
| self._config_required('CONFIG_%s' % (name), value) | |
| def has_builtin(self, name): | |
| """Check if the specific config item is built-in (present but not | |
| built as a module). | |
| @param name: name of config item to test | |
| """ | |
| wanted = ['y'] | |
| if name in self._missing_ok: | |
| wanted.append(None) | |
| self.has_value(name, wanted) | |
| def has_module(self, name): | |
| """Check if the specific config item is a module (present but not | |
| built-in). | |
| @param name: name of config item to test | |
| """ | |
| wanted = ['m'] | |
| if name in self._missing_ok: | |
| wanted.append(None) | |
| self.has_value(name, wanted) | |
| def is_enabled(self, name): | |
| """Check if the specific config item is present (either built-in or | |
| a module). | |
| @param name: name of config item to test | |
| """ | |
| wanted = ['y', 'm'] | |
| if name in self._missing_ok: | |
| wanted.append(None) | |
| self.has_value(name, wanted) | |
| def is_missing(self, name): | |
| """Check if the specific config item is not present (neither built-in | |
| nor a module). | |
| @param name: name of config item to test | |
| """ | |
| self.has_value(name, [None]) | |
| def is_exclusive(self, exclusive): | |
| """Given a config item regex, make sure only the expected items | |
| are present in the kernel configs. | |
| @param exclusive: hash containing "missing", "builtin", "module", | |
| "enabled" each to be checked with the corresponding | |
| has_* function based on config items matching the | |
| "regex" value. | |
| """ | |
| expected = set() | |
| for name in exclusive['missing']: | |
| self.is_missing(name) | |
| for name in exclusive['builtin']: | |
| self.has_builtin(name) | |
| expected.add('CONFIG_%s' % (name)) | |
| for name in exclusive['module']: | |
| self.has_module(name) | |
| expected.add('CONFIG_%s' % (name)) | |
| for name in exclusive['enabled']: | |
| self.is_enabled(name) | |
| expected.add('CONFIG_%s' % (name)) | |
| # Now make sure nothing else with the specified regex exists. | |
| regex = r'CONFIG_%s' % (exclusive['regex']) | |
| for name in self._config: | |
| if not re.match(regex, name): | |
| continue | |
| if not name in expected: | |
| self._failed('"%s" found for "%s" when only "%s" allowed' % | |
| (name, regex, "|".join(expected))) | |
| def _read_config(self): | |
| """Open the kernel's build config file. Attempt to use the built-in | |
| symbols from /proc first, then fall back to looking for a text file | |
| in /boot. | |
| @return readlines for fileobj | |
| """ | |
| filename = '/proc/config.gz' | |
| if not os.path.exists(filename): | |
| utils.system("modprobe configs", ignore_status=True) | |
| if os.path.exists(filename): | |
| with gzip.open(filename, "r") as rf: | |
| return rf.readlines() | |
| filename = '/boot/config-%s' % utils.system_output('uname -r') | |
| if os.path.exists(filename): | |
| logging.info('Falling back to reading %s', filename) | |
| with open(filename, "r") as rf: | |
| return rf.readlines() | |
| self._fatal("Cannot locate suitable kernel config file") | |
| def initialize(self, missing_ok=None): | |
| """Load the kernel configuration and parse it. | |
| """ | |
| file_lines = self._read_config() | |
| # Import kernel config variables into a dictionary for each searching. | |
| config = dict() | |
| for item in file_lines: | |
| item = item.strip() | |
| if not '=' in item: | |
| continue | |
| key, value = item.split('=', 1) | |
| config[key] = value | |
| # Make sure we actually loaded something sensible. | |
| if len(config) == 0: | |
| self._fatal('No CONFIG variables found!') | |
| self._config = config | |
| self._failures = [] | |
| self._missing_ok = set() | |
| if missing_ok: | |
| self._missing_ok |= set(missing_ok) |