• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5import gzip, logging, os, re
6from autotest_lib.client.bin import utils
7from autotest_lib.client.common_lib import error
8
9class 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