8cb6a1893e
Test: Checked diff and hash of before and after output files, same. Test: Tested build for basic boot and functionality. Change-Id: If7806427e3a2a9ddb7a2c9aa14e1e4f9bf696acf Signed-off-by: William Roberts <william.c.roberts@intel.com>
294 lines
8.5 KiB
Python
Executable file
294 lines
8.5 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
import ConfigParser
|
|
import re
|
|
import sys
|
|
|
|
|
|
GENERATED = '''
|
|
/*
|
|
* THIS IS AN AUTOGENERATED FILE! DO NOT MODIFY
|
|
*/
|
|
'''
|
|
|
|
INCLUDE = '#include <private/android_filesystem_config.h>'
|
|
|
|
DEFINE_NO_DIRS = '#define NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS\n'
|
|
DEFINE_NO_FILES = '#define NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES\n'
|
|
|
|
DEFAULT_WARNING = '#warning No device-supplied android_filesystem_config.h, using empty default.'
|
|
|
|
NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS_ENTRY = '{ 00000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_dirs" },'
|
|
NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES_ENTRY = '{ 00000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_files" },'
|
|
|
|
IFDEF_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS = '#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS'
|
|
ENDIF = '#endif'
|
|
|
|
OPEN_FILE_STRUCT = 'static const struct fs_path_config android_device_files[] = {'
|
|
OPEN_DIR_STRUCT = 'static const struct fs_path_config android_device_dirs[] = {'
|
|
CLOSE_FILE_STRUCT = '};'
|
|
|
|
GENERIC_DEFINE = "#define %s\t%s"
|
|
|
|
FILE_COMMENT = '// Defined in file: \"%s\"'
|
|
|
|
# from system/core/include/private/android_filesystem_config.h
|
|
AID_OEM_RESERVED_RANGES = [
|
|
(2900, 2999),
|
|
(5000, 5999),
|
|
]
|
|
|
|
|
|
AID_MATCH = re.compile('AID_[a-zA-Z]+')
|
|
|
|
def handle_aid(file_name, section_name, config, aids, seen_aids):
|
|
value = config.get(section_name, 'value')
|
|
|
|
errmsg = '%s for: \"' + section_name + '" file: \"' + file_name + '\"'
|
|
|
|
if not value:
|
|
raise Exception(errmsg % 'Found specified but unset "value"')
|
|
|
|
v = convert_int(value)
|
|
if not v:
|
|
raise Exception(errmsg % ('Invalid "value", not a number, got: \"%s\"' % value))
|
|
|
|
# Values must be within OEM range
|
|
if not any(lower <= v <= upper for (lower, upper) in AID_OEM_RESERVED_RANGES):
|
|
s = '"value" not in valid range %s, got: %s'
|
|
s = s % (str(AID_OEM_RESERVED_RANGES), value)
|
|
raise Exception(errmsg % s)
|
|
|
|
# use the normalized int value in the dict and detect
|
|
# duplicate definitions of the same vallue
|
|
v = str(v)
|
|
if v in seen_aids[1]:
|
|
# map of value to aid name
|
|
a = seen_aids[1][v]
|
|
|
|
# aid name to file
|
|
f = seen_aids[0][a]
|
|
|
|
s = 'Duplicate AID value "%s" found on AID: "%s".' % (value, seen_aids[1][v])
|
|
s += ' Previous found in file: "%s."' % f
|
|
raise Exception(errmsg % s)
|
|
|
|
seen_aids[1][v] = section_name
|
|
|
|
# Append a tuple of (AID_*, base10(value), str(value))
|
|
# We keep the str version of value so we can print that out in the
|
|
# generated header so investigating parties can identify parts.
|
|
# We store the base10 value for sorting, so everything is ascending
|
|
# later.
|
|
aids.append((file_name, section_name, v, value))
|
|
|
|
def convert_int(num):
|
|
|
|
try:
|
|
if num.startswith('0x'):
|
|
return int(num, 16)
|
|
elif num.startswith('0b'):
|
|
return int(num, 2)
|
|
elif num.startswith('0'):
|
|
return int(num, 8)
|
|
else:
|
|
return int(num, 10)
|
|
except ValueError:
|
|
pass
|
|
return None
|
|
|
|
def handle_path(file_name, section_name, config, files, dirs):
|
|
|
|
mode = config.get(section_name, 'mode')
|
|
user = config.get(section_name, 'user')
|
|
group = config.get(section_name, 'group')
|
|
caps = config.get(section_name, 'caps')
|
|
|
|
errmsg = 'Found specified but unset option: \"%s" in file: \"' + file_name + '\"'
|
|
|
|
if not mode:
|
|
raise Exception(errmsg % 'mode')
|
|
|
|
if not user:
|
|
raise Exception(errmsg % 'user')
|
|
|
|
if not group:
|
|
raise Exception(errmsg % 'group')
|
|
|
|
if not caps:
|
|
raise Exception(errmsg % 'caps')
|
|
|
|
caps = caps.split()
|
|
|
|
tmp = []
|
|
for x in caps:
|
|
if convert_int(x):
|
|
tmp.append('(' + x + ')')
|
|
else:
|
|
tmp.append('(1ULL << CAP_' + x.upper() + ')')
|
|
|
|
caps = tmp
|
|
|
|
path = '"' + section_name + '"'
|
|
|
|
if len(mode) == 3:
|
|
mode = '0' + mode
|
|
|
|
try:
|
|
int(mode, 8)
|
|
except:
|
|
raise Exception('Mode must be octal characters, got: "' + mode + '"')
|
|
|
|
if len(mode) != 4:
|
|
raise Exception('Mode must be 3 or 4 characters, got: "' + mode + '"')
|
|
|
|
|
|
caps = '|'.join(caps)
|
|
|
|
x = [ mode, user, group, caps, section_name ]
|
|
if section_name[-1] == '/':
|
|
dirs.append((file_name, x))
|
|
else:
|
|
files.append((file_name, x))
|
|
|
|
def handle_dup(name, file_name, section_name, seen):
|
|
if section_name in seen:
|
|
dups = '"' + seen[section_name] + '" and '
|
|
dups += file_name
|
|
raise Exception('Duplicate ' + name + ' "' + section_name + '" found in files: ' + dups)
|
|
|
|
def parse(file_name, files, dirs, aids, seen_paths, seen_aids):
|
|
|
|
config = ConfigParser.ConfigParser()
|
|
config.read(file_name)
|
|
|
|
for s in config.sections():
|
|
|
|
if AID_MATCH.match(s) and config.has_option(s, 'value'):
|
|
handle_dup('AID', file_name, s, seen_aids[0])
|
|
seen_aids[0][s] = file_name
|
|
handle_aid(file_name, s, config, aids, seen_aids)
|
|
else:
|
|
handle_dup('path', file_name, s, seen_paths)
|
|
seen_paths[s] = file_name
|
|
handle_path(file_name, s, config, files, dirs)
|
|
|
|
def generate(files, dirs, aids):
|
|
print GENERATED
|
|
print INCLUDE
|
|
print
|
|
|
|
are_dirs = len(dirs) > 0
|
|
are_files = len(files) > 0
|
|
are_aids = len(aids) > 0
|
|
|
|
if are_aids:
|
|
for a in aids:
|
|
# use the preserved str value
|
|
print FILE_COMMENT % a[0]
|
|
print GENERIC_DEFINE % (a[1], a[2])
|
|
|
|
print
|
|
|
|
if not are_dirs:
|
|
print DEFINE_NO_DIRS
|
|
|
|
if not are_files:
|
|
print DEFINE_NO_FILES
|
|
|
|
if not are_files and not are_dirs and not are_aids:
|
|
print DEFAULT_WARNING
|
|
return
|
|
|
|
if are_files:
|
|
print OPEN_FILE_STRUCT
|
|
for tup in files:
|
|
f = tup[0]
|
|
c = tup[1]
|
|
c[4] = '"' + c[4] + '"'
|
|
c = '{ ' + ' ,'.join(c) + ' },'
|
|
print FILE_COMMENT % f
|
|
print ' ' + c
|
|
|
|
if not are_dirs:
|
|
print IFDEF_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
|
|
print ' ' + NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS_ENTRY
|
|
print ENDIF
|
|
print CLOSE_FILE_STRUCT
|
|
|
|
if are_dirs:
|
|
print OPEN_DIR_STRUCT
|
|
for d in dirs:
|
|
f[4] = '"' + f[4] + '"'
|
|
d = '{ ' + ' ,'.join(d) + ' },'
|
|
print ' ' + d
|
|
|
|
print CLOSE_FILE_STRUCT
|
|
|
|
def file_key(x):
|
|
|
|
# Wrapper class for custom prefix matching strings
|
|
class S(object):
|
|
def __init__(self, str):
|
|
|
|
self.orig = str
|
|
self.is_prefix = str[-1] == '*'
|
|
if self.is_prefix:
|
|
self.str = str[:-1]
|
|
else:
|
|
self.str = str
|
|
|
|
def __lt__(self, other):
|
|
|
|
# if were both suffixed the smallest string
|
|
# is 'bigger'
|
|
if self.is_prefix and other.is_prefix:
|
|
b = len(self.str) > len(other.str)
|
|
# If I am an the suffix match, im bigger
|
|
elif self.is_prefix:
|
|
b = False
|
|
# If other is the suffix match, he's bigger
|
|
elif other.is_prefix:
|
|
b = True
|
|
# Alphabetical
|
|
else:
|
|
b = self.str < other.str
|
|
return b
|
|
|
|
return S(x[4])
|
|
|
|
def main():
|
|
|
|
files = []
|
|
dirs = []
|
|
aids = []
|
|
seen_paths = {}
|
|
|
|
# (name to file, value to aid)
|
|
seen_aids = ({}, {})
|
|
|
|
for x in sys.argv[1:]:
|
|
parse(x, files, dirs, aids, seen_paths, seen_aids)
|
|
|
|
# sort entries:
|
|
# * specified path before prefix match
|
|
# ** ie foo before f*
|
|
# * lexicographical less than before other
|
|
# ** ie boo before foo
|
|
# Given these paths:
|
|
# paths=['ac', 'a', 'acd', 'an', 'a*', 'aa', 'ac*']
|
|
# The sort order would be:
|
|
# paths=['a', 'aa', 'ac', 'acd', 'an', 'ac*', 'a*']
|
|
# Thus the fs_config tools will match on specified paths before attempting
|
|
# prefix, and match on the longest matching prefix.
|
|
files.sort(key= lambda x: file_key(x[1]))
|
|
|
|
# sort on value of (file_name, name, value, strvalue)
|
|
# This is only cosmetic so AIDS are arranged in ascending order
|
|
# within the generated file.
|
|
aids.sort(key=lambda x: x[2])
|
|
|
|
generate(files, dirs, aids)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|