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