1#!/usr/bin/env python 2# coding:utf-8 3 4# 5# Copyright (C) 2022 Huawei Technologies Co., Ltd. 6# Licensed under the Mulan PSL v2. 7# You can use this software according to the terms and conditions of the Mulan 8# PSL v2. 9# You may obtain a copy of Mulan PSL v2 at: 10# http://license.coscl.org.cn/MulanPSL2 11# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY 12# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 13# NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14# See the Mulan PSL v2 for more details. 15# 16 17import string 18import os 19import sys 20import stat 21import logging 22from defusedxml import ElementTree as ET 23from dyn_conf_checker import dyn_perm_check 24from dyn_conf_checker import check_and_classify_attr 25from dyn_conf_checker import check_csv_sym 26from dyn_conf_checker import check_ta_config 27from dyn_conf_checker import dyn_conf_clean 28 29 30type_trans = {"TYPE_NONE": "-1", 31 "TYPE_CLASS": "0", 32 "TYPE_BOOL": "1", 33 "TYPE_INT": "2", 34 "TYPE_CHAR": "3"} 35 36# the length len in tlv 37DYN_CONF_LEN_LEN = 4 38 39MAP_REGIONS_NUM = 0 40 41tag_dict = {} 42type_dict = {} 43trans_dict = {} 44 45 46def get_csv_size(path): 47 48 with open(path, "r", encoding="utf-8") as csvfile: 49 lines = csvfile.readlines() 50 return len(lines) 51 return 0 52 53 54def get_csv_data(path, lnum, rnum): 55 56 with open(path, "r", encoding="utf-8") as csvfile: 57 count = 0 58 lines = csvfile.readlines() 59 for line in lines: 60 if count == lnum: 61 return str(line.split(",")[rnum]).strip() 62 count = count + 1 63 return "" 64 65 66def classify_tag(tag): 67 68 while len(tag) < 3: 69 tag = "0%s" % (tag) 70 71 return tag 72 73 74# save tag type and trans dict 75def handle_tag_dict(path): 76 77 for i in range(0, get_csv_size(path)): 78 dyn_sym = get_csv_data(path, i, 0) 79 tag_dict[dyn_sym] = classify_tag(get_csv_data(path, i, 1)) 80 type_dict[dyn_sym] = type_trans.get(get_csv_data(path, i, 2)) 81 trans_dict[dyn_sym] = get_csv_data(path, i, 3) 82 83 84def check_target_data_been_found(sym, find_out, path): 85 86 if find_out == 1: 87 raise RuntimeError(sym + " can only set one time in " + path) 88 89 90# trans value sym by trans dict 91def handle_trans(value, path): 92 93 datas = value.split("|") 94 95 for i, data in enumerate(datas): 96 find_out = 0 97 target_data = data 98 for j in range(0, get_csv_size(path)): 99 sym = get_csv_data(path, j, 0) 100 tag = get_csv_data(path, j, 1) 101 check_csv_sym(sym) 102 check_csv_sym(tag) 103 if sym == target_data: 104 # if one sym has been set more than one time in csv 105 check_target_data_been_found(sym, find_out, path) 106 datas[i] = tag 107 find_out = 1 # means we find sym in dict 108 109 if find_out == 0: 110 raise RuntimeError("cannot find {} in {}".format(datas[i], path)) 111 112 ans = datas[0] 113 for i in range(1, len(datas)): 114 ans = "%s|%s" % (ans, datas[i]) 115 116 return ans 117 118 119def get_value_by_name_in_config(config_name, in_path): 120 121 config_file = os.path.join(in_path, config_name) 122 if not os.path.exists(config_file): 123 logging.error("configs.xml file doesn't exist") 124 return "" 125 xml_tree = ET.parse(config_file) 126 drv_perm = xml_tree.find('./TA_Basic_Info/service_name') 127 return drv_perm.text 128 129 130def get_value_by_name_in_manifest(manifest_name, in_path): 131 132 manifest = os.path.join(in_path, "manifest.txt") 133 if not os.path.exists(manifest): 134 name = get_value_by_name_in_config("configs.xml", in_path) 135 if name != "": 136 return name 137 else: 138 with open(manifest, 'r') as mani_fp: 139 for each_line in mani_fp: 140 if each_line.startswith("#") or not each_line.strip(): 141 continue 142 name = each_line.split(":")[0].strip() 143 if "{" + name + "}" == manifest_name: 144 return str(each_line.split(":")[1].strip()) 145 146 raise RuntimeError("{" + manifest_name + "}" + \ 147 "cannot find in " + manifest) 148 149 150def get_value_trans(old_item, value, attrib, key, in_path): 151 152 # if name contains '.csv' means 153 # we can transform value by {manifest_name}.csv 154 # manifest_name must in manifest.txt 155 if ".csv" in trans_dict.get(key): 156 manifest_name = trans_dict.get(key).split(".csv")[0] 157 manifest_value = get_value_by_name_in_manifest(manifest_name, in_path) 158 trans_file_path = os.path.join(in_path, "{}.csv".format(manifest_value)) 159 return handle_trans(value, trans_file_path) 160 # if name not contains '.csv' means 161 # we can transform value by {attrib[attri]}.csv 162 # attrib[attri] must in xml file 163 for attri in attrib: 164 if old_item + attri == trans_dict.get(key): 165 if len(attrib[attri]) == 0: 166 raise RuntimeError("you should set drv name while \ 167 you set drv permission") 168 trans_file_path = os.path.join(in_path, 169 "{}.csv".format(attrib[attri])) 170 return handle_trans(value, trans_file_path) 171 172 raise RuntimeError("cannot find second trans file",\ 173 key, trans_dict.get(key)) 174 175 176def item_zip(old_item, attr, value, attrib, in_path): 177 178 dyn_key = old_item + attr 179 dyn_type = type_dict.get(dyn_key) 180 origin_value = value 181 182 if dyn_type is None: 183 raise RuntimeError("tag " + dyn_key + " is not support!") 184 185 if len(trans_dict.get(dyn_key)) > 0: 186 value = get_value_trans(old_item, value, attrib, dyn_key, in_path) 187 188 # check the xml is invalid for dyn perm 189 dyn_perm_check(dyn_key, attrib, value, origin_value) 190 191 if dyn_type == type_trans.get("TYPE_BOOL"): 192 if value.lower() == "true": 193 return "1" 194 elif value.lower() == "false": 195 return "0" 196 else: 197 raise Exception("bool can only be true or false") 198 elif dyn_type == type_trans.get("TYPE_INT"): 199 if '0x' in value: 200 return str(int(value, base=16)) 201 elif '0b' in value: 202 return str(int(value, base=2)) 203 else: 204 return str(int(value, base=10)) 205 elif dyn_type == type_trans.get("TYPE_CHAR"): 206 return value 207 else: 208 raise RuntimeError("unknown type") 209 210 211def get_length(value): 212 213 length = len(value) 214 off = int((DYN_CONF_LEN_LEN / 2 - 1) * 8) 215 ans = "" 216 217 for _ in range(int(DYN_CONF_LEN_LEN / 2)): 218 tmp = "" 219 dyn_len = (length >> off) & 0xFF; 220 if dyn_len >= 0 and dyn_len <= 0xF: 221 tmp = "0" 222 tmp += str(hex(dyn_len)).split("x")[1] 223 ans += tmp 224 off -= 8 225 226 return ans 227 228 229def check_map_regions(length): 230 if int(length, 16) > 1279: 231 logging.error("regions string is too long\n") 232 raise RuntimeError("regions has invalid length", int(length, 16)) 233 234 235def do_parser_dyn_conf(old_item, ele, in_path): 236 237 attrs = "" 238 if len(ele.attrib) > 0: 239 for attr in ele.attrib: 240 ele.attrib[attr] = check_and_classify_attr(old_item,\ 241 attr, ele.attrib.get(attr)) 242 tag = tag_dict.get(old_item + attr) 243 dyn_type = type_dict.get(old_item + attr) 244 if dyn_type == type_trans.get("TYPE_NONE"): 245 continue 246 247 value = item_zip(old_item, attr, ele.attrib[attr], 248 ele.attrib, in_path) 249 length = get_length(value) 250 attrs = attrs + tag + dyn_type + length + value 251 if tag == "037" and dyn_type == "3": 252 check_map_regions(length) 253 global MAP_REGIONS_NUM 254 MAP_REGIONS_NUM += 1 255 else: 256 for child in ele: 257 tmp_attrs = do_parser_dyn_conf(old_item + child.tag + "/", 258 child, in_path) 259 if tmp_attrs == "": 260 continue 261 attrs = attrs + tmp_attrs 262 263 # handle inner context 264 if check_ta_config(old_item, ele.text) is True and \ 265 ele.text is not None and len(ele.text.strip()) > 0: 266 inner_text = item_zip(old_item + ele.tag, "", ele.text, {}, in_path) 267 attrs = attrs + tag_dict.get(old_item + ele.tag) + \ 268 type_dict.get(old_item + ele.tag) + \ 269 get_length(inner_text) + inner_text 270 271 if len(tag_dict.get(old_item)) == 0 or attrs == "": 272 return "" 273 274 return tag_dict.get(old_item) + type_dict.get(old_item) + \ 275 get_length(attrs) + attrs 276 277 278def parser_dyn_conf(dyn_conf_xml_file_path, manifest_ext_path, 279 tag_parse_dict_path, in_path): 280 281 if not os.path.exists(dyn_conf_xml_file_path): 282 logging.error("dyn perm xml file doesn't exist") 283 return 284 285 if not os.path.exists(tag_parse_dict_path): 286 logging.error("tag_parse_dict.csv file doesn't exist") 287 return 288 289 handle_tag_dict(tag_parse_dict_path) 290 tree = ET.parse(dyn_conf_xml_file_path) 291 root = tree.getroot() 292 293 ans = do_parser_dyn_conf(root.tag + "/", root, in_path) 294 dyn_conf_clean() 295 if MAP_REGIONS_NUM > 1: 296 raise RuntimeError("regions has invalid num", MAP_REGIONS_NUM) 297 298 if ans == "": 299 ans = "00000" 300 301 ans = "gpd.ta.dynConf:" + ans + "\n" 302 303 if not os.path.exists(manifest_ext_path): 304 out_tlv = os.path.join(in_path, "config_tlv") 305 with os.fdopen(os.open(out_tlv, \ 306 os.O_RDWR | os.O_TRUNC | os.O_CREAT, \ 307 stat.S_IWUSR | stat.S_IRUSR), 'w+') as conf: 308 conf.write(ans) 309 else: 310 #write items to mani_ext 311 manifest_ext_path_fd = os.open(manifest_ext_path, os.O_RDWR, 0o600) 312 with os.fdopen(manifest_ext_path_fd, 'a+') as mani_ext_fp: 313 mani_ext_fp.write(ans) 314 315 316def parser_config_xml(config_xml_file_path, tag_parse_dict_path, \ 317 out_path, in_path): 318 319 if not os.path.exists(config_xml_file_path): 320 logging.error("config xml file doesn't exist") 321 return 322 if not os.path.exists(tag_parse_dict_path): 323 logging.error("tag_parse_dict.csv file doesn't exist") 324 return 325 326 handle_tag_dict(tag_parse_dict_path) 327 tree = ET.parse(config_xml_file_path) 328 root = tree.getroot() 329 330 ans = do_parser_dyn_conf(root.tag + "/", root, in_path) 331 dyn_conf_clean() 332 if ans == "": 333 ans = "00000" 334 335 # write items to mani_ext 336 config_path_fd = os.open(out_path, os.O_CREAT | os.O_RDWR, 0o600) 337 with os.fdopen(config_path_fd, 'a+') as config_fp: 338 config_fp.write(ans) 339