blob: 17d5d5ad5218b57422c32361d70a0cfc46c662dd [file] [log] [blame]
Rishabh Bhatnagarf6619422018-04-05 14:19:20 -07001#! /usr/bin/env python
Rishabh Bhatnagare9a05bb2018-12-10 11:09:45 -08002# SPDX-License-Identifier: GPL-2.0-only
Rishabh Bhatnagarf6619422018-04-05 14:19:20 -07003
4# Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
5
6"""
7Android kernel configuration validator.
8
9The Android kernel reference trees contain some config stubs of
10configuration options that are required for Android to function
11correctly, and additional ones that are recommended.
12
13This script can help compare these base configs with the ".config"
14output of the compiler to determine if the proper configs are defined.
15"""
16
17from collections import namedtuple
18from optparse import OptionParser
19import re
20import sys
21
22version = "check-config.py, version 0.0.1"
23
24req_re = re.compile(r'''^CONFIG_(.*)=(.*)$''')
25forb_re = re.compile(r'''^# CONFIG_(.*) is not set$''')
26comment_re = re.compile(r'''^(#.*|)$''')
27
28Enabled = namedtuple('Enabled', ['name', 'value'])
29Disabled = namedtuple('Disabled', ['name'])
30
31def walk_config(name):
32 with open(name, 'r') as fd:
33 for line in fd:
34 line = line.rstrip()
35 m = req_re.match(line)
36 if m:
37 yield Enabled(m.group(1), m.group(2))
38 continue
39
40 m = forb_re.match(line)
41 if m:
42 yield Disabled(m.group(1))
43 continue
44
45 m = comment_re.match(line)
46 if m:
47 continue
48
49 print "WARNING: Unknown .config line: ", line
50
51class Checker():
52 def __init__(self):
53 self.required = {}
54 self.exempted = set()
55 self.forbidden = set()
56
57 def add_required(self, fname):
58 for ent in walk_config(fname):
59 if type(ent) is Enabled:
60 self.required[ent.name] = ent.value
61 elif type(ent) is Disabled:
62 if ent.name in self.required:
63 del self.required[ent.name]
64 self.forbidden.add(ent.name)
65
66 def add_exempted(self, fname):
67 with open(fname, 'r') as fd:
68 for line in fd:
69 line = line.rstrip()
70 self.exempted.add(line)
71
72 def check(self, path):
73 failure = False
74
75 # Don't run this for mdm targets
76 if re.search('mdm', path):
77 print "Not applicable to mdm targets... bypassing"
78 else:
79 for ent in walk_config(path):
80 # Go to the next iteration if this config is exempt
81 if ent.name in self.exempted:
82 continue
83
84 if type(ent) is Enabled:
85 if ent.name in self.forbidden:
86 print "error: Config should not be present: %s" %ent.name
87 failure = True
88
89 if ent.name in self.required and ent.value != self.required[ent.name]:
90 print "error: Config has wrong value: %s %s expecting: %s" \
91 %(ent.name, ent.value, self.required[ent.name])
92 failure = True
93
94 elif type(ent) is Disabled:
95 if ent.name in self.required:
96 print "error: Config should be present, but is disabled: %s" %ent.name
97 failure = True
98
99 if failure:
100 sys.exit(1)
101
102def main():
103 usage = """%prog [options] path/to/.config"""
104 parser = OptionParser(usage=usage, version=version)
105 parser.add_option('-r', '--required', dest="required",
106 action="append")
107 parser.add_option('-e', '--exempted', dest="exempted",
108 action="append")
109 (options, args) = parser.parse_args()
110 if len(args) != 1:
111 parser.error("Expecting a single path argument to .config")
112 elif options.required is None or options.exempted is None:
113 parser.error("Expecting a file containing required configurations")
114
115 ch = Checker()
116 for r in options.required:
117 ch.add_required(r)
118 for e in options.exempted:
119 ch.add_exempted(e)
120
121 ch.check(args[0])
122
123if __name__ == '__main__':
124 main()