• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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