1#!/usr/bin/env python3 2# coding: utf-8 3# Copyright (c) 2023 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import os 17import subprocess 18 19 20def run_cmd(cmd: str): 21 res = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, 22 stderr=subprocess.PIPE) 23 sout, serr = res.communicate(timeout=60) 24 25 return res.pid, res.returncode, sout, serr 26 27 28def get_needed_lib(file_path: str) -> list: 29 cmd = " ".join(["readelf", "-d", file_path]) 30 res = run_cmd(cmd) 31 if res[1] != 0: 32 print("error run readelf -d {}".format(file_path)) 33 print(" ".join(["pid ", str(res[0]), " ret ", str(res[1]), "\n", 34 res[2].decode(), res[3].decode()])) 35 return [] 36 needed_lib_name = [] 37 lib_info = res[2].decode().split() 38 for i, val in enumerate(lib_info): 39 # lib_info : ... (NEEDED) Shared library: [libc++.so] ... 40 if val == "(NEEDED)" and lib_info[i + 3].startswith("[") and lib_info[i + 3].endswith("]"): 41 needed_lib_name.append(lib_info[i + 3][1 : -1]) 42 return needed_lib_name 43 44 45def judge_updater_binary_available(updater_root_path: str) -> bool: 46 updater_binary_path = os.path.join(updater_root_path, "bin", "updater_binary") 47 updater_binary_needed_lib = get_needed_lib(updater_binary_path) 48 # The ASAN version does not set restriction 49 for lib_name in updater_binary_needed_lib: 50 if lib_name.endswith('asan.so'): 51 return True 52 updater_binary_lib_scope = {'libc.so', 'libc++.so', 'libselinux.z.so', 'librestorecon.z.so', 'libssl_openssl.z.so', 53 'libbegetutil.z.so', 'libcjson.z.so', 'libpartition_slot_manager.z.so'} 54 extra_lib = set(updater_binary_needed_lib) - updater_binary_lib_scope 55 if len(extra_lib) != 0: 56 print("Reason: not allow updater_binary to depend dynamic library: {}".format(" ".join(extra_lib))) 57 return False 58 return True 59 60 61def judge_lib_available(lib_name: str, lib_chain: list, available_libs: list, lib_to_path: dict) -> bool: 62 if lib_name in available_libs: 63 return True 64 lib_path = lib_to_path.get(lib_name) 65 if lib_path is None: 66 return False 67 for next_lib in get_needed_lib(lib_path): 68 if next_lib not in lib_chain: 69 lib_chain.append(next_lib) 70 if not judge_lib_available(next_lib, lib_chain, available_libs, lib_to_path): 71 return False 72 lib_chain.remove(next_lib) 73 available_libs.add(lib_name) 74 return True 75 76 77def judge_updater_available(updater_root_path: str) -> bool: 78 lib_to_path = dict() 79 for path in [os.path.join(updater_root_path, "lib64"), os.path.join(updater_root_path, "lib")]: 80 for root, dirs, files in os.walk(path): 81 for file in files: 82 lib_to_path[file] = os.path.join(root, file) 83 lib_to_path["updater"] = os.path.join(updater_root_path, "bin", "updater") 84 lib_chain = ["updater"] 85 available_libs = set() 86 if not judge_lib_available("updater", lib_chain, available_libs, lib_to_path): 87 print("Reason: not allow updater to depend dynamic library which not exist in updater.img. {}"\ 88 .format("->".join(lib_chain))) 89 print("Solution: add updater in install_images field when compiling {}".format(lib_chain[-1])) 90 return False 91 return True 92 93 94def judge_updater_img_available(updater_root_path: str) -> bool: 95 return judge_updater_binary_available(updater_root_path) and\ 96 judge_updater_available(updater_root_path)