blob: e66e2958175101e1c8e097d4a7da51d2e4d52999 [file] [log] [blame]
William Robertsc950a352016-03-04 18:12:29 -08001#!/usr/bin/env python
2
3import ConfigParser
4import re
5import sys
6
7
8GENERATED = '''
9/*
10 * THIS IS AN AUTOGENERATED FILE! DO NOT MODIFY
11 */
12'''
13
14INCLUDE = '#include <private/android_filesystem_config.h>'
15
16DEFINE_NO_DIRS = '#define NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS\n'
17DEFINE_NO_FILES = '#define NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES\n'
18
19DEFAULT_WARNING = '#warning No device-supplied android_filesystem_config.h, using empty default.'
20
21NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS_ENTRY = '{ 00000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_dirs" },'
22NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES_ENTRY = '{ 00000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_files" },'
23
24IFDEF_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS = '#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS'
25ENDIF = '#endif'
26
27OPEN_FILE_STRUCT = 'static const struct fs_path_config android_device_files[] = {'
28OPEN_DIR_STRUCT = 'static const struct fs_path_config android_device_dirs[] = {'
29CLOSE_FILE_STRUCT = '};'
30
31GENERIC_DEFINE = "#define %s\t%s"
32
33FILE_COMMENT = '// Defined in file: \"%s\"'
34
35# from system/core/include/private/android_filesystem_config.h
36AID_OEM_RESERVED_START = 2900
37AID_OEM_RESERVED_END = 2999
38
39
40AID_MATCH = re.compile('AID_[a-zA-Z]+')
41
42def handle_aid(file_name, section_name, config, aids, seen_aids):
43 value = config.get(section_name, 'value')
44
45 errmsg = '%s for: \"' + section_name + '" file: \"' + file_name + '\"'
46
47 if not value:
48 raise Exception(errmsg % 'Found specified but unset "value"')
49
50 v = convert_int(value)
51 if not v:
52 raise Exception(errmsg % ('Invalid "value", not a number, got: \"%s\"' % value))
53
54 # Values must be within OEM range
55 if (v < AID_OEM_RESERVED_START) or (v > AID_OEM_RESERVED_END):
56 s = '"value" not in valid range %d - %d, got: %s'
57 s = s % (AID_OEM_RESERVED_START, AID_OEM_RESERVED_END, value)
58 raise Exception(errmsg % s)
59
60 # use the normalized int value in the dict and detect
61 # duplicate definitions of the same vallue
62 v = str(v)
63 if v in seen_aids[1]:
64 # map of value to aid name
65 a = seen_aids[1][v]
66
67 # aid name to file
68 f = seen_aids[0][a]
69
70 s = 'Duplicate AID value "%s" found on AID: "%s".' % (value, seen_aids[1][v])
71 s += ' Previous found in file: "%s."' % f
72 raise Exception(errmsg % s)
73
74 seen_aids[1][v] = section_name
75
76 # Append a tuple of (AID_*, base10(value), str(value))
77 # We keep the str version of value so we can print that out in the
78 # generated header so investigating parties can identify parts.
79 # We store the base10 value for sorting, so everything is ascending
80 # later.
81 aids.append((file_name, section_name, v, value))
82
83def convert_int(num):
84
85 try:
86 if num.startswith('0x'):
87 return int(num, 16)
88 elif num.startswith('0b'):
89 return int(num, 2)
90 elif num.startswith('0'):
91 return int(num, 8)
92 else:
93 return int(num, 10)
94 except ValueError:
95 pass
96 return None
97
98def handle_path(file_name, section_name, config, files, dirs):
99
100 mode = config.get(section_name, 'mode')
101 user = config.get(section_name, 'user')
102 group = config.get(section_name, 'group')
103 caps = config.get(section_name, 'caps')
104
105 errmsg = 'Found specified but unset option: \"%s" in file: \"' + file_name + '\"'
106
107 if not mode:
108 raise Exception(errmsg % 'mode')
109
110 if not user:
111 raise Exception(errmsg % 'user')
112
113 if not group:
114 raise Exception(errmsg % 'group')
115
116 if not caps:
117 raise Exception(errmsg % 'caps')
118
119 caps = caps.split()
120
121 tmp = []
122 for x in caps:
123 if convert_int(x):
124 tmp.append('(' + x + ')')
125 else:
126 tmp.append('(1ULL << CAP_' + x.upper() + ')')
127
128 caps = tmp
129
130 path = '"' + section_name + '"'
131
132 if len(mode) == 3:
133 mode = '0' + mode
134
135 try:
136 int(mode, 8)
137 except:
138 raise Exception('Mode must be octal characters, got: "' + mode + '"')
139
140 if len(mode) != 4:
141 raise Exception('Mode must be 3 or 4 characters, got: "' + mode + '"')
142
143
144 caps = '|'.join(caps)
145
146 x = [ mode, user, group, caps, section_name ]
147 if section_name[-1] == '/':
148 dirs.append((file_name, x))
149 else:
150 files.append((file_name, x))
151
152def handle_dup(name, file_name, section_name, seen):
153 if section_name in seen:
154 dups = '"' + seen[section_name] + '" and '
155 dups += file_name
156 raise Exception('Duplicate ' + name + ' "' + section_name + '" found in files: ' + dups)
157
158def parse(file_name, files, dirs, aids, seen_paths, seen_aids):
159
160 config = ConfigParser.ConfigParser()
161 config.read(file_name)
162
163 for s in config.sections():
164
165 if AID_MATCH.match(s) and config.has_option(s, 'value'):
166 handle_dup('AID', file_name, s, seen_aids[0])
167 seen_aids[0][s] = file_name
168 handle_aid(file_name, s, config, aids, seen_aids)
169 else:
170 handle_dup('path', file_name, s, seen_paths)
171 seen_paths[s] = file_name
172 handle_path(file_name, s, config, files, dirs)
173
174def generate(files, dirs, aids):
175 print GENERATED
176 print INCLUDE
177 print
178
179 are_dirs = len(dirs) > 0
180 are_files = len(files) > 0
181 are_aids = len(aids) > 0
182
183 if are_aids:
184 # sort on value of (file_name, name, value, strvalue)
185 aids.sort(key=lambda x: x[2])
186 for a in aids:
187 # use the preserved str value
188 print FILE_COMMENT % a[0]
189 print GENERIC_DEFINE % (a[1], a[2])
190
191 print
192
193 if not are_dirs:
194 print DEFINE_NO_DIRS
195
196 if not are_files:
197 print DEFINE_NO_FILES
198
199 if not are_files and not are_dirs and not are_aids:
200 print DEFAULT_WARNING
201 return
202
203 if are_files:
204 print OPEN_FILE_STRUCT
205 for tup in files:
206 f = tup[0]
207 c = tup[1]
208 c[4] = '"' + c[4] + '"'
209 c = '{ ' + ' ,'.join(c) + ' },'
210 print FILE_COMMENT % f
211 print ' ' + c
212
213 if not are_dirs:
214 print IFDEF_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
215 print ' ' + NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS_ENTRY
216 print ENDIF
217 print CLOSE_FILE_STRUCT
218
219 if are_dirs:
220 print OPEN_DIR_STRUCT
221 for d in dirs:
222 f[4] = '"' + f[4] + '"'
223 d = '{ ' + ' ,'.join(d) + ' },'
224 print ' ' + d
225
226 print CLOSE_FILE_STRUCT
227
228def file_key(x):
229
230 # Wrapper class for custom prefix matching strings
231 class S(object):
232 def __init__(self, str):
233
234 self.orig = str
235 self.is_prefix = str[-1] == '*'
236 if self.is_prefix:
237 self.str = str[:-1]
238 else:
239 self.str = str
240
241 def __lt__(self, other):
242
243 # if were both suffixed the smallest string
244 # is 'bigger'
245 if self.is_prefix and other.is_prefix:
246 b = len(self.str) > len(other.str)
247 # If I am an the suffix match, im bigger
248 elif self.is_prefix:
249 b = False
250 # If other is the suffix match, he's bigger
251 elif other.is_prefix:
252 b = True
253 # Alphabetical
254 else:
255 b = self.str < other.str
256 return b
257
258 return S(x[4])
259
260def main():
261
262 files = []
263 dirs = []
264 aids = []
265 seen_paths = {}
266
267 # (name to file, value to aid)
268 seen_aids = ({}, {})
269
270 for x in sys.argv[1:]:
271 parse(x, files, dirs, aids, seen_paths, seen_aids)
272
273 files.sort(key= lambda x: file_key(x[1]))
274 generate(files, dirs, aids)
275
276if __name__ == '__main__':
277 main()