• 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 struct
19import uuid
20import os
21import re
22import stat
23import logging
24
25
26PRODUCT_TA_IMAGE = 1
27PRODUCT_DYN_LIB = 2
28PRODUCT_SERVICE_IMAGE = 3
29PRODUCT_CLIENT_IMAGE = 4
30PRODUCT_DRIVER_IMAGE = 5
31logging.basicConfig(level=logging.INFO)
32
33
34class PackUuid:
35    # Structure object to align and package the TEE_UUID
36    data = struct.Struct('IHH8b')
37
38    def __init__(self, data):
39        unpacked_data = (PackUuid.data).unpack(str.encode(data))
40        self.unpacked_data = unpacked_data
41        self.time_low = unpacked_data[0]
42        self.time_mid = unpacked_data[1]
43        self.time_hi_version = unpacked_data[2]
44        self.clock_seq_node = unpacked_data[3]
45
46    def print_values(self):
47        logging.info("ATTRIBUTE / VALUE")
48        for attr, value in self.__dict__.items():
49            logging.info(attr, value)
50
51    def get_pack_data(self):
52        values = [self.time_low,
53                self.time_mid,
54                self.time_hi_version,
55                self.clock_seq_node,
56                ]
57
58        return (PackUuid.data).pack(*values)
59
60
61#----------------------------------------------------------------------------
62# Manifest
63#----------------------------------------------------------------------------
64class Manifest:
65
66    # Structure object to align and package the Manifest
67    data = struct.Struct('I' * 6)
68
69    def __init__(self, data):
70        unpacked_data = (Manifest.data).unpack(str.encode(data))
71        self.unpacked_data = unpacked_data
72        self.single_instance = unpacked_data[0]
73        self.multi_session = unpacked_data[1]
74        self.multi_command = unpacked_data[2]
75        self.heap_size = unpacked_data[3]
76        self.stack_size = unpacked_data[4]
77        self.instancekeepalive = unpacked_data[5]
78
79    def print_values(self):
80        logging.info("ATTRIBUTE / VALUE")
81        for attr, value in self.__dict__.items():
82            logging.info(attr, value)
83
84    def get_pack_data(self):
85        values = [self.single_instance,
86                self.multi_session,
87                self.multi_command,
88                self.heap_size,
89                self.stack_size,
90                self.instancekeepalive,
91                ]
92
93        return (Manifest.data).pack(*values)
94
95
96#----------------------------------------------------------------------------
97# verify property name in manifest file
98#----------------------------------------------------------------------------
99def verify_property_name(str_line):
100    logging.info("verify property name")
101    alphas = string.ascii_letters + string.digits
102    cont = "".join([alphas, '-', '_', '.'])
103    if len(str_line) > 1:
104        if str_line[0] not in alphas:
105            logging.error("invalid first letter in property name")
106            return False
107        else:
108            for otherchar in str_line[1:]:
109                if otherchar not in cont:
110                    logging.error("invalid char in property name")
111                    return False
112    else:
113        logging.error("invalid property name")
114        return False
115
116    return True
117
118
119#----------------------------------------------------------------------------
120# verify property value in manifest file
121#----------------------------------------------------------------------------
122def verify_property_value(str_line):
123    logging.info("verify property value")
124    filt_letter = chr(0) + chr(10) + chr(13)
125    for thechar in str_line:
126        if thechar in filt_letter:
127            logging.error("invalid letter in prop value")
128            return False
129    return True
130
131
132#----------------------------------------------------------------------------
133# remove tabs and space in property value
134#----------------------------------------------------------------------------
135def trailing_space_tabs(str_line):
136    logging.info('trailing space tabs in value head and trail')
137    space_tabs = chr(9) + chr(32) + chr(160)
138    space_tabs_newlines = space_tabs + chr(10) + chr(13)
139
140    index = 0
141    for thechar in str_line:
142        if thechar in space_tabs:
143            index += 1
144        else:
145            break
146    headvalue = str_line[index:]
147
148    strlen = len(headvalue)
149
150    strlen -= 1
151
152    while strlen > 0:
153        if headvalue[strlen] in space_tabs_newlines:
154            strlen -= 1
155        else:
156            break
157
158    str_ret = headvalue[0:strlen + 1] + chr(10)
159    logging.info("str ret: %s", str_ret)
160
161    return str_ret
162
163
164def update_target_type(target_info):
165    # dyn_conf_target_type is 1 means that is drv
166    dyn_conf_target_type = target_info.dyn_conf_target_type
167    service_name = target_info.service_name
168    target_type = target_info.target_type
169    service_name_len = len(service_name)
170    logging.info("service name: %s", service_name)
171    logging.info("service name len: %d", service_name_len)
172
173    max_service_len = 36
174    if dyn_conf_target_type == 1:
175        target_type = PRODUCT_DRIVER_IMAGE
176    if dyn_conf_target_type == 3:
177        target_type = PRODUCT_SERVICE_IMAGE
178    if dyn_conf_target_type == 4:
179        target_type = PRODUCT_CLIENT_IMAGE
180
181    if not re.match(r"^[A-Za-z0-9_-]*$", service_name):
182        logging.error("service name only can use [A-Z] [a-z] [0-9] '-' and '_'")
183        return (False, 0)
184
185    if service_name_len > max_service_len:
186        logging.error("service name len cannot larger than %s", str(max_service_len))
187        return (False, 0)
188    return (True, target_type)
189
190
191class TargetInfo:
192    def __init__(self, dyn_conf_target_type, service_name, target_type, uuid_val):
193        self.dyn_conf_target_type = dyn_conf_target_type
194        self.service_name = service_name
195        self.target_type = target_type
196        self.uuid_val = uuid_val
197
198
199def init_data_val():
200    #manifest default
201    manifest_val = Manifest('\0'*24)
202    manifest_val.single_instance = 1
203    manifest_val.multi_session = 0
204    manifest_val.multi_command = 0
205    manifest_val.instancekeepalive = 0
206    manifest_val.heap_size = 16384
207    manifest_val.stack_size = 2048
208
209    uuid_val = PackUuid('\0' * 16)
210    target_type = PRODUCT_TA_IMAGE
211    service_name = 'external_service'
212    dyn_conf_target_type = 0
213    target_info = TargetInfo(dyn_conf_target_type, service_name, target_type, uuid_val)
214    return manifest_val, target_info
215
216
217def update_manifest_info(prop_value_v, val, prop_name_low):
218    prop_value_low = prop_value_v.lower()
219    if 'true' == prop_value_low:
220        val = 1
221    elif 'false' == prop_value_low:
222        val = 0
223    else:
224        logging.error("%s value error!", prop_name_low)
225    return val
226
227
228def check_prop_info(prop_name, prop_value_v):
229    if verify_property_name(prop_name) is False:
230        logging.error("manifest format invalid, please check it")
231        return False
232
233    if verify_property_value(prop_value_v) is False:
234        logging.error("manifest format invalid, please check it")
235        return False
236    return True
237
238
239class PropInfo:
240    def __init__(self, prop_name, prop_name_t, prop_value_t):
241        self.prop_name = prop_name
242        self.prop_name_t = prop_name_t
243        self.prop_value_t = prop_value_t
244
245    def get_prop_value(self):
246        prop_value_t = self.prop_value_t
247        prop_value = trailing_space_tabs(prop_value_t)
248        prop_len = len(prop_value)
249        prop_value_v = prop_value[0:prop_len - 1]
250        logging.info("prop value_v: %s", prop_value_v)
251        return prop_value, prop_value_v
252
253
254def parse_prop_info(manifest_val, prop_info, mani_ext_fp, target_info):
255    prop_value, prop_value_v = PropInfo.get_prop_value(prop_info)
256    prop_name = prop_info.prop_name
257    prop_name_t = prop_info.prop_name_t
258
259    if not check_prop_info(prop_name, prop_value_v):
260        return (False, 0, 0)
261
262    # name:value to lowcase, and parse manifest
263    prop_name_low = prop_name.lower()
264    logging.info("name lower: %s", prop_name_low)
265    if 'gpd.ta.appid' == prop_name_low:
266        logging.info("compare name is srv id")
267        target_info.uuid_val = uuid.UUID(prop_value_v)
268        logging.info("uuid str %s", target_info.uuid_val)
269        logging.info("val fields %s", target_info.uuid_val.fields)
270
271    elif 'gpd.ta.singleinstance' == prop_name_low:
272        manifest_val.single_instance = update_manifest_info(prop_value_v, manifest_val.single_instance, \
273            prop_name_low)
274    elif 'gpd.ta.multisession' == prop_name_low:
275        manifest_val.multi_session = update_manifest_info(prop_value_v, manifest_val.multi_session, \
276            prop_name_low)
277    elif 'gpd.ta.multicommand' == prop_name_low:
278        manifest_val.multi_command = update_manifest_info(prop_value_v, manifest_val.multi_command, \
279            prop_name_low)
280    elif 'gpd.ta.instancekeepalive' == prop_name_low:
281        manifest_val.instancekeepalive = update_manifest_info(prop_value_v, manifest_val.instancekeepalive, \
282            prop_name_low)
283    elif 'gpd.ta.datasize' == prop_name_low:
284        manifest_val.heap_size = int(prop_value_v)
285        logging.info('b')
286    elif 'gpd.ta.stacksize' == prop_name_low:
287        manifest_val.stack_size = int(prop_value_v)
288        logging.info('b')
289    elif 'gpd.ta.service_name' == prop_name_low:
290        target_info.service_name = prop_value_v
291        logging.info('b')
292    elif 'gpd.ta.dynconf' == prop_name_low:
293        logging.error("gpd.ta.dynConf is reserved, cannot set")
294        return (False, 0, 0)
295    else:
296        logging.info('b')
297        #write have not paresed manifest into sample.manifest file
298        mani_ext_fp.write(str.encode(prop_name_t))
299        mani_ext_fp.write(str.encode(prop_value))
300        if 'gpd.ta.is_lib' == prop_name_low:
301            if 'true' == prop_value_v.lower():
302                target_info.target_type = PRODUCT_DYN_LIB
303        elif 'gpd.ta.target_type' == prop_name_low:
304            target_info.dyn_conf_target_type = int(prop_value_v)
305            if target_info.dyn_conf_target_type > 0xFFFF or target_info.dyn_conf_target_type < 0:
306                logging.error("gpd.ta.target_type must in range [0, 0xFFFF]")
307                return (False, 0, 0)
308    return (True, manifest_val, target_info)
309
310
311def gen_product_name(uuid_val, target_info):
312    service_name = target_info.service_name
313    target_type = target_info.target_type
314    uuid_str = str(uuid_val)
315    product_name = str(uuid_val)
316    if target_type == PRODUCT_TA_IMAGE:
317        logging.info("product type is ta image")
318        product_name = "".join([uuid_str, ".sec"])
319    elif target_type == PRODUCT_DRIVER_IMAGE:
320        logging.info("product type is driver")
321        product_name = "".join([service_name, ".sec"])
322    elif target_type == PRODUCT_SERVICE_IMAGE:
323        logging.info("product type is service")
324        product_name = "".join([service_name, ".sec"])
325    elif target_type == PRODUCT_CLIENT_IMAGE:
326        logging.info("product type is client")
327        product_name = "".join([service_name, ".so.sec"])
328    elif target_type == PRODUCT_DYN_LIB:
329        logging.info("product type is dyn lib")
330        product_name = "".join([uuid_str, service_name, ".so.sec"])
331    else:
332        logging.error("invalid product type!")
333        return (False, 0, 0)
334    return (True, product_name, uuid_str)
335
336
337#----------------------------------------------------------------------------
338# verify manifest file, parse manifest file, generate a new manfiest file
339#----------------------------------------------------------------------------
340def parser_manifest(manifest, manifest_data_path, mani_ext):
341    logging.info("verify manifest")
342    manifest_val, target_info = init_data_val()
343
344    with open(manifest, 'r') as mani_fp:
345        fd_ext = os.open(mani_ext, os.O_WRONLY | os.O_CREAT, \
346            stat.S_IWUSR | stat.S_IRUSR)
347        mani_ext_fp = os.fdopen(fd_ext, "wb")
348        for each_line in mani_fp:
349            logging.info(each_line)
350            if each_line.startswith("#") or not each_line.strip():
351                continue
352            index = each_line.find(':', 1, len(each_line))
353
354            prop_name = each_line[0:index]
355            prop_name_t = each_line[0:index + 1]
356            prop_value_t = each_line[index + 1:]
357            prop_info = PropInfo(prop_name, prop_name_t, prop_value_t)
358            logging.info("name is: %s; value is: %s", prop_name, prop_value_t)
359
360            result, manifest_val, target_info = parse_prop_info(manifest_val, prop_info, \
361                mani_ext_fp, target_info)
362            if result is False:
363                mani_ext_fp.close()
364                return (False, 0, 0, None)
365        mani_ext_fp.close()
366        #write the whole parsed manifest into sample.manifest file
367    uuid_val = target_info.uuid_val
368    ret, target_info.target_type = update_target_type(target_info)
369    if ret is False:
370        return (False, 0, 0, None)
371
372    # get manifest string file len
373    manifest_str_size = os.path.getsize(mani_ext)
374    logging.info('manifest str size %d', manifest_str_size)
375
376    # 2> manifest + service_name
377    logging.info("bytes len %d", len(uuid_val.bytes_le))
378    logging.info("bytes len %d", len(manifest_val.get_pack_data()))
379    logging.info("bytes len %d", len(target_info.service_name))
380
381    # 3> unparsed manifest, string manifest
382    with open(mani_ext, 'rb') as string_mani_fp:
383        logging.info("read manifest string size %d", manifest_str_size)
384        manifest_string_buf = string_mani_fp.read(manifest_str_size)
385        logging.info("manifest strint: %s", manifest_string_buf)
386
387    #---- write manifest parse context to manifest file
388    fd_out = os.open(manifest_data_path, os.O_WRONLY | os.O_CREAT, \
389        stat.S_IWUSR | stat.S_IRUSR)
390    out_manifest_fp = os.fdopen(fd_out, "wb")
391    out_manifest_fp.write(uuid_val.bytes_le)
392    out_manifest_fp.write(str.encode(target_info.service_name))
393    out_manifest_fp.write(manifest_val.get_pack_data())
394    out_manifest_fp.close()
395    ret, product_name, uuid_str = gen_product_name(uuid_val, target_info)
396    if ret is False:
397        return (False, 0, 0, None)
398
399    return (True, product_name, uuid_str, manifest_val)
400
401
402class ManifestInfo:
403    ''' get manifest info '''
404    def __init__(self, ret, product_name, uuid_str, manifest_txt_exist):
405        self.ret = ret
406        self.product_name = product_name
407        self.uuid_str = uuid_str
408        self.manifest_txt_exist = manifest_txt_exist
409
410
411def process_manifest_file(xml_config_path, manifest_path, \
412    manifest_data_path, mani_ext):
413
414    manifest_txt_exist = True
415    if not os.path.exists(manifest_path):
416        logging.info("xml trans manifest cfg")
417        manifest_txt_exist = False
418        from xml_trans_manifest import trans_xml_to_manifest
419        trans_xml_to_manifest(xml_config_path, manifest_path)
420
421    ret, product_name, uuid_str, manifest_val = parser_manifest(manifest_path, \
422        manifest_data_path, mani_ext)
423    manifest_info = ManifestInfo(ret, product_name, uuid_str, manifest_txt_exist)
424    return manifest_info, manifest_val
425