# 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)
