15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# coding=utf-8
35f9996aaSopenharmony_ci
45f9996aaSopenharmony_ci#
55f9996aaSopenharmony_ci# Copyright (c) 2024 Huawei Device Co., Ltd.
65f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
75f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
85f9996aaSopenharmony_ci# You may obtain a copy of the License at
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
115f9996aaSopenharmony_ci#
125f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
135f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
145f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
155f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
165f9996aaSopenharmony_ci# limitations under the License.
175f9996aaSopenharmony_ci#
185f9996aaSopenharmony_ci
195f9996aaSopenharmony_ciimport os
205f9996aaSopenharmony_ciimport sys
215f9996aaSopenharmony_ciimport subprocess
225f9996aaSopenharmony_ciimport json
235f9996aaSopenharmony_cifrom collections import OrderedDict
245f9996aaSopenharmony_ci
255f9996aaSopenharmony_cisys.path.append(
265f9996aaSopenharmony_ci    os.path.dirname(os.path.dirname(os.path.dirname(
275f9996aaSopenharmony_ci        os.path.abspath(__file__)))))
285f9996aaSopenharmony_cifrom scripts.util.file_utils import read_json_file
295f9996aaSopenharmony_ci
305f9996aaSopenharmony_ci
315f9996aaSopenharmony_ciclass KernelPermission():
325f9996aaSopenharmony_ci
335f9996aaSopenharmony_ci
345f9996aaSopenharmony_ci    @staticmethod
355f9996aaSopenharmony_ci    def run(out_path, root_path):
365f9996aaSopenharmony_ci        target_out_path = os.path.join(root_path, out_path.lstrip("//"))
375f9996aaSopenharmony_ci        print("target_out_path", target_out_path)
385f9996aaSopenharmony_ci        KernelPermission.execute_kernel_permission_cmd(target_out_path, root_path)
395f9996aaSopenharmony_ci
405f9996aaSopenharmony_ci
415f9996aaSopenharmony_ci    @staticmethod
425f9996aaSopenharmony_ci    def scan_file(out_path):
435f9996aaSopenharmony_ci        """scan path uild_configs/kernel_permission/
445f9996aaSopenharmony_ci        return file_list include kernel_permission.json
455f9996aaSopenharmony_ci        """
465f9996aaSopenharmony_ci        file_list = []
475f9996aaSopenharmony_ci        file_path = file_path = os.path.join(out_path, "build_configs/kernel_permission/")
485f9996aaSopenharmony_ci        for root, subdirs, files in os.walk(file_path):
495f9996aaSopenharmony_ci            for _filename in files:
505f9996aaSopenharmony_ci                content = read_json_file(os.path.join(root, _filename))
515f9996aaSopenharmony_ci                file_list.append(content[0])
525f9996aaSopenharmony_ci        return file_list
535f9996aaSopenharmony_ci
545f9996aaSopenharmony_ci
555f9996aaSopenharmony_ci    @staticmethod
565f9996aaSopenharmony_ci    def execute_kernel_permission_cmd(out_path, root_path):
575f9996aaSopenharmony_ci        """execute cmd
585f9996aaSopenharmony_ci        llvm-object --add-section .kernelpermission=json_file xx/xx.so
595f9996aaSopenharmony_ci        """
605f9996aaSopenharmony_ci        print("begin run kernel permission cmd")
615f9996aaSopenharmony_ci
625f9996aaSopenharmony_ci        try:
635f9996aaSopenharmony_ci            llvm_tool = KernelPermission.regist_llvm_objcopy_path(root_path)
645f9996aaSopenharmony_ci        except FileNotFoundError as e:
655f9996aaSopenharmony_ci            print("regist_llvm_objcopy_path failed:{}".format(e))
665f9996aaSopenharmony_ci        file_list = KernelPermission.scan_file(out_path)
675f9996aaSopenharmony_ci
685f9996aaSopenharmony_ci        cmds = KernelPermission.gen_cmds(file_list, out_path, llvm_tool)
695f9996aaSopenharmony_ci        if cmds:
705f9996aaSopenharmony_ci            for cmd in cmds:
715f9996aaSopenharmony_ci                print("llvm cmd: {}".format(cmd))
725f9996aaSopenharmony_ci                KernelPermission.exec_command(cmd)
735f9996aaSopenharmony_ci        else:
745f9996aaSopenharmony_ci            print("There is no kernel permission json file,no need to run llvm-object cmd.")
755f9996aaSopenharmony_ci
765f9996aaSopenharmony_ci
775f9996aaSopenharmony_ci    @staticmethod
785f9996aaSopenharmony_ci    def regist_llvm_objcopy_path(root_path):
795f9996aaSopenharmony_ci        """find llvm_objcopy_path executable
805f9996aaSopenharmony_ci        :raise FileNotFoundError: when can't find the llvm_objcopy_path excutable
815f9996aaSopenharmony_ci        """
825f9996aaSopenharmony_ci        llvm_objcopy_path = os.path.join(root_path, "prebuilts/clang/ohos/linux-x86_64/llvm/bin/llvm-objcopy")
835f9996aaSopenharmony_ci        if os.path.exists(llvm_objcopy_path):
845f9996aaSopenharmony_ci            return llvm_objcopy_path
855f9996aaSopenharmony_ci        else:
865f9996aaSopenharmony_ci            raise FileNotFoundError(
875f9996aaSopenharmony_ci                'There is no llvm-object executable file at {}'.format(llvm_objcopy_path), '0001')
885f9996aaSopenharmony_ci
895f9996aaSopenharmony_ci
905f9996aaSopenharmony_ci    @staticmethod
915f9996aaSopenharmony_ci    def gen_cmds(file_list, out_path, llvm_path):
925f9996aaSopenharmony_ci        """generate cmd
935f9996aaSopenharmony_ci        llvm-object --add-section .kernelpermission=json_file xx/xx.so
945f9996aaSopenharmony_ci        """
955f9996aaSopenharmony_ci        cmds = []
965f9996aaSopenharmony_ci        cmd = []
975f9996aaSopenharmony_ci        for info in file_list:
985f9996aaSopenharmony_ci            kernel_permission_file = os.path.join(out_path, info.get("kernel_permission_path"))
995f9996aaSopenharmony_ci            if not KernelPermission.check_json_file(kernel_permission_file):
1005f9996aaSopenharmony_ci                raise FileExistsError(
1015f9996aaSopenharmony_ci                    'kernel_permission json file {} invalid!'.format(kernel_permission_file), '0001')
1025f9996aaSopenharmony_ci            target_name = info.get("target_name")
1035f9996aaSopenharmony_ci            output_extension = info.get("gn_output_extension")
1045f9996aaSopenharmony_ci            output_name = info.get("gn_output_name")
1055f9996aaSopenharmony_ci            part_name = info.get("part_name")
1065f9996aaSopenharmony_ci            subsystem_name = info.get("subsystem_name")
1075f9996aaSopenharmony_ci            target_type = info.get("type")
1085f9996aaSopenharmony_ci            module_name = target_name
1095f9996aaSopenharmony_ci            if output_name == "" and output_extension == "":
1105f9996aaSopenharmony_ci                if target_type == "lib" and target_name.startswith("lib"):
1115f9996aaSopenharmony_ci                    module_name = "{}.z.so".format(target_name)
1125f9996aaSopenharmony_ci                elif target_type == "lib" and not target_name.startswith("lib"):
1135f9996aaSopenharmony_ci                    module_name = "lib{}.z.so".format(target_name)
1145f9996aaSopenharmony_ci            print("module_name:{}".format(module_name))
1155f9996aaSopenharmony_ci            module_path = os.path.join(subsystem_name, part_name)
1165f9996aaSopenharmony_ci            module_path = os.path.join(module_path, module_name)
1175f9996aaSopenharmony_ci            print("module_path:{}".format(module_path))
1185f9996aaSopenharmony_ci            target_source = os.path.join(out_path, module_path)
1195f9996aaSopenharmony_ci            if os.path.exists(target_source):
1205f9996aaSopenharmony_ci                cmd = [llvm_path,
1215f9996aaSopenharmony_ci                        "--add-section",
1225f9996aaSopenharmony_ci                        ".kernelpermission=" + kernel_permission_file,
1235f9996aaSopenharmony_ci                        target_source
1245f9996aaSopenharmony_ci                        ]
1255f9996aaSopenharmony_ci                cmds.append(cmd)
1265f9996aaSopenharmony_ci        return cmds
1275f9996aaSopenharmony_ci
1285f9996aaSopenharmony_ci
1295f9996aaSopenharmony_ci    @staticmethod
1305f9996aaSopenharmony_ci    def check_json_file(file_path):
1315f9996aaSopenharmony_ci        try:
1325f9996aaSopenharmony_ci            with os.fdopen(os.open(file_path, os.O_RDWR, 0o640), 'r') as file:
1335f9996aaSopenharmony_ci                json_data = json.load(file)
1345f9996aaSopenharmony_ci                if KernelPermission.check_json_content(json_data):
1355f9996aaSopenharmony_ci                    return True
1365f9996aaSopenharmony_ci                else:
1375f9996aaSopenharmony_ci                    print("encaps.json is invalid")
1385f9996aaSopenharmony_ci                    return False
1395f9996aaSopenharmony_ci        except FileNotFoundError:
1405f9996aaSopenharmony_ci            print("encaps.json is not found")
1415f9996aaSopenharmony_ci            return False
1425f9996aaSopenharmony_ci        except json.JSONDecodeError:
1435f9996aaSopenharmony_ci            print("encaps.json doesn't conform to json format")
1445f9996aaSopenharmony_ci            return False
1455f9996aaSopenharmony_ci        except Exception:
1465f9996aaSopenharmony_ci            print("encaps.json error")
1475f9996aaSopenharmony_ci            return False
1485f9996aaSopenharmony_ci
1495f9996aaSopenharmony_ci
1505f9996aaSopenharmony_ci    @staticmethod
1515f9996aaSopenharmony_ci    def check_json_content(json_data):
1525f9996aaSopenharmony_ci        if len(json_data) == 1 and "encaps" in json_data:
1535f9996aaSopenharmony_ci            return KernelPermission.check_json_value(json_data)
1545f9996aaSopenharmony_ci        else:
1555f9996aaSopenharmony_ci            return False
1565f9996aaSopenharmony_ci
1575f9996aaSopenharmony_ci
1585f9996aaSopenharmony_ci    @staticmethod
1595f9996aaSopenharmony_ci    def check_json_value(json_data):
1605f9996aaSopenharmony_ci        encaps_data = json_data["encaps"]
1615f9996aaSopenharmony_ci        for key, value in encaps_data.items():
1625f9996aaSopenharmony_ci            if not isinstance(value, (bool, int)):
1635f9996aaSopenharmony_ci                return False
1645f9996aaSopenharmony_ci        return True
1655f9996aaSopenharmony_ci
1665f9996aaSopenharmony_ci
1675f9996aaSopenharmony_ci    @staticmethod
1685f9996aaSopenharmony_ci    def exec_command(cmd: list, exec_env=None, **kwargs):
1695f9996aaSopenharmony_ci        process = subprocess.Popen(cmd,
1705f9996aaSopenharmony_ci                                   stdout=subprocess.PIPE,
1715f9996aaSopenharmony_ci                                   stderr=subprocess.STDOUT,
1725f9996aaSopenharmony_ci                                   encoding='utf-8',
1735f9996aaSopenharmony_ci                                   errors='ignore',
1745f9996aaSopenharmony_ci                                   env=exec_env,
1755f9996aaSopenharmony_ci                                   **kwargs)
1765f9996aaSopenharmony_ci        for line in iter(process.stdout.readline, ''):
1775f9996aaSopenharmony_ci            print(line)
1785f9996aaSopenharmony_ci
1795f9996aaSopenharmony_ci        process.wait()
1805f9996aaSopenharmony_ci        ret_code = process.returncode
1815f9996aaSopenharmony_ci
1825f9996aaSopenharmony_ci        if ret_code != 0:
1835f9996aaSopenharmony_ci            raise Exception(
1845f9996aaSopenharmony_ci                'Please check llvm cmd: {}'.format(cmd))
1855f9996aaSopenharmony_ci
1865f9996aaSopenharmony_ciif __name__ == "__main__":
1875f9996aaSopenharmony_ci    pass