1#!/usr/bin/env python
2#coding=utf-8
3
4#
5# Copyright (c) 2023-2024 Huawei Device Co., Ltd.
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19import os
20import json
21
22from .base_rule import BaseRule
23
24
25class CmdRule(BaseRule):
26    RULE_NAME = "NO-Config-Cmds-In-Init"
27
28    def __init__(self, mgr, args):
29        super().__init__(mgr, args)
30        self._cmds = {}
31        self._start_modes = {}
32        self._boot_list = {}
33        self._condition_list = {}
34        self._start_cmd_list = {}
35
36    def __check__(self):
37        return self.check_config_cmd()
38
39    def check_config_cmd(self):
40        passed = True
41        self._parse_while_list()
42        cfg_parser = self.get_mgr().get_parser_by_name('config_parser')
43        self._get_json_service()
44
45        start_passed = self._check_start_cmd(cfg_parser)
46        secon_passed = self._check_selinux(cfg_parser)
47        cmd_passed = self._check_cmdline_in_parser(cfg_parser)
48        start_mode_passed = self._check_service(cfg_parser)
49        passed = start_passed and secon_passed and cmd_passed and start_mode_passed
50        return passed
51
52    def _get_json_service(self):
53        for _, start_mode in enumerate(self._start_modes):
54            if start_mode.get("start-mode") == "boot":
55                self._boot_list = start_mode.get("service")
56            elif start_mode.get("start-mode") == "condition":
57                self._condition_list = start_mode.get("service")
58        pass
59
60    def _get_start_cmds(self, parser):
61        lists = {}
62        for cmd in parser._cmds:
63            if cmd["name"] == "start":
64                lists[cmd["content"]] = cmd["fileId"]
65                pass
66        return lists
67
68    def _parse_while_list(self):
69        white_lists = self.get_white_lists()[0]
70        for key, item in white_lists.items():
71            if key == "cmds":
72                self._cmds = item
73            if key == "start-modes":
74                self._start_modes = item
75            if key == "start-cmd":
76                self._start_cmd_list = item
77
78    def _check_condition_start_mode(self, cmd_list, service_name, passed):
79        if service_name in self._condition_list and service_name in cmd_list:
80            pass
81        else:
82            self.warn("\'%s\' cannot be started in conditional mode" % service_name)
83        return passed
84
85
86    def _check_service(self, parser):
87        boot_passed = True
88        condition_passed = True
89        start_cmd_list = self._get_start_cmds(parser).keys()
90        for key, item in parser._services.items():
91            if item.get("start_mode") == "boot":
92                if key not in self._boot_list:
93                    self.warn("\'%s\' cannot be started in boot mode" % key)
94            elif item.get("on_demand") is not True and item.get("start_mode") == "condition":
95                condition_passed = self._check_condition_start_mode(start_cmd_list, key, condition_passed)
96        return boot_passed and condition_passed
97
98    def _check_file_id_in_cmds(self, cmdlist, cmdline):
99        file_id_list = set()
100        for _, cmd in enumerate(cmdlist):
101            if cmdline == cmd["name"]:
102                file_id_list.add(cmd["fileId"])
103        return file_id_list
104
105    def _check_cmdline_in_parser(self, parser):
106        passed = True
107        cmdline = []
108        file_id_list = set()
109        parser_cmds = parser._cmds
110
111        for cmd in self._cmds:
112            cmdline = cmd["cmd"]
113            file_id_list = self._check_file_id_in_cmds(parser_cmds, cmdline)
114            file_lists = cmd["location"]
115            for key, item in parser._files.items():
116                if item["fileId"] in file_id_list and key not in file_lists:
117                    output = "\'{}\' is timeout command, in {}".format(cmd["cmd"], key)
118                    self.error("%s" % str(output))
119                    passed = False
120            file_id_list.clear()
121        return passed
122
123    def _check_selinux(self, parser):
124        if parser._selinux != 'enforcing':
125            self.warn("selinux status is %s" % parser._selinux)
126            return True
127
128        passed = True
129        for key, item in parser._services.items():
130            if item.get("secon") == "":
131                output_str = "%s \'secon\' is empty" % key
132                self.error("%s" % str(output_str))
133                passed = False
134        return passed
135
136    def _check_start_cmd(self, parser):
137        passed = True
138        start_cmd_list = self._get_start_cmds(parser)
139        for cmd, file_id in start_cmd_list.items():
140            if cmd in list(self._start_cmd_list):
141                pass
142            else:
143                for key, item in parser._files.items():
144                    if item["fileId"] == file_id:
145                        log_str = "{} is not in start cmd list. path:{}".format(cmd, item["file_name"])
146                        self.warn("%s" % log_str)
147                        passed = False
148                    pass
149        return passed
150