1#!/usr/bin/env python 2# coding: utf-8 3 4""" 5Copyright (c) 2024 Huawei Device Co., Ltd. 6Licensed under the Apache License, Version 2.0 (the "License"); 7you may not use this file except in compliance with the License. 8You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12Unless required by applicable law or agreed to in writing, software 13distributed under the License is distributed on an "AS IS" BASIS, 14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15See the License for the specific language governing permissions and 16limitations under the License. 17 18""" 19 20import os 21import argparse 22import sys 23sys.path.append(os.path.join(os.path.dirname( 24 os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))), "build")) 25from scripts.util import build_utils 26import subprocess 27import find 28 29 30def parse_args(): 31 parser = argparse.ArgumentParser() 32 parser.add_argument("--dst-dir", help="the output dest path", required=True) 33 parser.add_argument("--source-root-dir", help="project root path", required=True) 34 parser.add_argument( 35 "--policy-dir-list", help="policy dirs need to be included", required=True 36 ) 37 parser.add_argument( 38 "--components", help="system or vendor or default", required=True 39 ) 40 parser.add_argument('--depfile', 41 help='depfile', required=True) 42 parser.add_argument('--output-file', 43 help='output file', required=True) 44 parser.add_argument('--sepolicy-dir-lists', 45 help='sepolicy dir lists', required=True) 46 return parser.parse_args() 47 48 49def prepare_build_path(dir_list, root_dir, build_dir_list): 50 build_ignore_cfg_list = [ 51 "base/security/selinux_adapter/sepolicy/base", 52 "base/security/selinux_adapter/sepolicy/ohos_policy", 53 ] 54 build_ignore_cfg_list += dir_list.split(":") 55 56 for i in build_ignore_cfg_list: 57 if not i or i == "default": 58 continue 59 path = os.path.join(root_dir, i) 60 if os.path.exists(path): 61 build_dir_list.append(path) 62 else: 63 raise Exception(f"following path not exists!! {path}") 64 65 66def check_ignore_file(ignore_file, err_msg): 67 """ 68 Check the format of ignore_cfg file. 69 :param ignore_file: ignore_file 70 :return: 71 """ 72 err = "" 73 lines = [] 74 with open(ignore_file, "rb") as fp: 75 lines = fp.readlines() 76 if len(lines) == 0: 77 return 78 last_line = lines[-1] 79 if b"\n" not in last_line: 80 err = "".join((ignore_file, " : need an empty line at end ")) 81 for line in lines: 82 strip_line = line.strip() 83 if not strip_line: 84 continue 85 if line.endswith(b"\r\n") or line.endswith(b"\r"): 86 err = "".join((ignore_file, " : must be unix format")) 87 break 88 if strip_line in [b"/", b"/*"]: 89 err = "".join((ignore_file, " : line must not be only / or /*")) 90 break 91 if not (strip_line.endswith(b"/") or strip_line.endswith(b"/*")): 92 err = "".join((ignore_file, " : line must end with / or /*")) 93 break 94 if err: 95 err_msg.append(err) 96 97 98def traverse_folder_in_type(search_dir_list, file_suffix): 99 """ 100 for special folder search_dir, find all files endwith file_suffix. 101 :param search_dir: path to search 102 :param file_suffix: postfix of file name 103 :return: file list 104 """ 105 err_msg = [] 106 ignore_cfg_file_list = [] 107 for item in search_dir_list: 108 for root, _, files in sorted(os.walk(item)): 109 filtered_files = [f for f in files if f == file_suffix] 110 for each_file in filtered_files: 111 file_list_path = os.path.join(root, each_file) 112 check_ignore_file(file_list_path, err_msg) 113 ignore_cfg_file_list.append(file_list_path) 114 if err_msg: 115 err_str = "\n{}".format("\n".join(err_msg)) 116 raise Exception(err_str) 117 ignore_cfg_file_list.sort() 118 return ignore_cfg_file_list 119 120 121def check_and_add_line(lines, line): 122 line = line.strip() 123 if not line: 124 return 125 for existing_line in lines[:]: 126 if len(line) >= len(existing_line) and line.startswith(existing_line): 127 return 128 elif len(line) < len(existing_line) and existing_line.startswith(line): 129 lines.remove(existing_line) 130 lines.append(line) 131 return 132 lines.append(line) 133 134 135def get_path_lines(ignore_cfg_list): 136 lines = [] 137 for ignore_cfg in ignore_cfg_list: 138 with open(ignore_cfg, "r") as src_file: 139 for line in src_file: 140 check_and_add_line(lines, line) 141 return lines 142 143 144def filter_and_write_to_dst(lines, dst_file): 145 fd = os.open(dst_file, os.O_WRONLY | os.O_CREAT, 0o664) 146 with os.fdopen(fd, "w") as dst_f: 147 dst_f.truncate(0) 148 for line in lines: 149 if line and not line.startswith("#"): 150 line = "".join([line, "\n"]) 151 dst_f.write(line) 152 153 154def combine_ignore_cfg(ignore_cfg_list, combined_ignore_cfg): 155 lines = get_path_lines(ignore_cfg_list) 156 filter_and_write_to_dst(lines, combined_ignore_cfg) 157 158 159def traverse_folder_in_dir_name(search_dir, folder_suffix): 160 folder_list = [] 161 for root, dirs, _ in sorted(os.walk(search_dir)): 162 for dir_i in dirs: 163 if dir_i == folder_suffix: 164 folder_list.append(os.path.join(root, dir_i)) 165 return folder_list 166 167 168def build_ignore_cfg(output_path, folder_list): 169 combined_ignore_cfg = os.path.join(output_path, "ignore_cfg") 170 ignore_cfg_list = traverse_folder_in_type(folder_list, "ignore_cfg") 171 combine_ignore_cfg(ignore_cfg_list, combined_ignore_cfg) 172 173 174def build_app_allow_cfg(output_path, folder_list): 175 combined_ignore_cfg = os.path.join(output_path, "app_allow_cfg") 176 ignore_cfg_list = traverse_folder_in_type(folder_list, "app_allow_cfg") 177 combine_ignore_cfg(ignore_cfg_list, combined_ignore_cfg) 178 179 180def main(args): 181 output_path = args.dst_dir 182 print("output_path: ", output_path) 183 policy_path = [] 184 prepare_build_path(args.policy_dir_list, args.source_root_dir, policy_path) 185 print("policy_path: ", policy_path) 186 187 folder_list = [] 188 for item in policy_path: 189 public_ = traverse_folder_in_dir_name(item, "public") 190 if args.components == "system": 191 system_policy = traverse_folder_in_dir_name(item, "system") 192 folder_list += public_ + system_policy 193 elif args.components == "vendor": 194 vendor_policy = traverse_folder_in_dir_name(item, "vendor") 195 folder_list += public_ + vendor_policy 196 else: 197 system_policy = traverse_folder_in_dir_name(item, "system") 198 vendor_policy = traverse_folder_in_dir_name(item, "vendor") 199 folder_list += public_ + system_policy + vendor_policy 200 201 build_ignore_cfg(output_path, folder_list) 202 build_app_allow_cfg(output_path, folder_list) 203 print("build_ignore_cfg done") 204 205 206if __name__ == "__main__": 207 input_args = parse_args() 208 if input_args.depfile: 209 dep_file = find.get_all_sepolicy_file(input_args.sepolicy_dir_lists) 210 dep_file.sort() 211 build_utils.write_depfile(input_args.depfile, input_args.output_file, dep_file, add_pydeps=False) 212 main(input_args) 213