1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hisysevent_tool.h"
17 
18 #include <getopt.h>
19 #include <iomanip>
20 #include <iostream>
21 #include <regex>
22 #include <regex.h>
23 #include <sstream>
24 #include <unistd.h>
25 
26 #include "hisysevent.h"
27 #include "hisysevent_tool_listener.h"
28 #include "hisysevent_tool_query.h"
29 
30 #include "ret_code.h"
31 
32 using namespace std;
33 
34 namespace OHOS {
35 namespace HiviewDFX {
36 namespace {
37 constexpr char ARG_SELECTION[] = "vrc:o:n:t:lS:s:E:e:m:dhg:";
38 constexpr uint32_t INVALID_EVENT_TYPE = 0;
39 constexpr int INVALID_ARG_OPT = -1;
40 constexpr long long DEFAULT_TIME_STAMP = -1;
41 constexpr long long SECONDS_2_MILLS = 1000;
42 
GetRuleTypeFromArg(const string & fromArgs)43 RuleType GetRuleTypeFromArg(const string& fromArgs)
44 {
45     static std::map<const string, RuleType> ruleTypeMap {
46         { "WHOLE_WORD", RuleType::WHOLE_WORD },
47         { "PREFIX", RuleType::PREFIX },
48         { "REGULAR", RuleType::REGULAR }
49     };
50     if (ruleTypeMap.find(fromArgs) != ruleTypeMap.end()) {
51         return ruleTypeMap[fromArgs];
52     }
53     return RuleType::WHOLE_WORD;
54 }
55 
GetEventTypeFromArg(const string & fromArgs)56 uint32_t GetEventTypeFromArg(const string& fromArgs)
57 {
58     static std::map<const string, HiSysEvent::EventType> eventTypeMap {
59         { "FAULT", HiSysEvent::EventType::FAULT },
60         { "STATISTIC", HiSysEvent::EventType::STATISTIC },
61         { "SECURITY", HiSysEvent::EventType::SECURITY },
62         { "BEHAVIOR", HiSysEvent::EventType::BEHAVIOR }
63     };
64     if (eventTypeMap.find(fromArgs) != eventTypeMap.end()) {
65         return static_cast<uint32_t>(eventTypeMap[fromArgs]);
66     }
67     return INVALID_EVENT_TYPE;
68 }
69 
ParseTimeStampFromArgs(const string & fromArgs)70 long long ParseTimeStampFromArgs(const string& fromArgs)
71 {
72     regex formatRegex("[0-9]{4}-"
73         "((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[2469]|11)-(0[1-9]|[12][0-9]|30))"
74         " ([01][0-9]|2[0-3])(:[0-5][0-9]){2}");
75     smatch matchRet;
76     if (!std::regex_match(fromArgs, matchRet, formatRegex)) {
77         return DEFAULT_TIME_STAMP;
78     }
79     std::istringstream is(fromArgs);
80     struct tm time = {};
81     is >> std::get_time(&time, "%Y-%m-%d %H:%M:%S");
82     return static_cast<long long>(mktime(&time)) * SECONDS_2_MILLS;
83 }
84 
GetErrorDescription(int32_t errCode)85 std::string GetErrorDescription(int32_t errCode)
86 {
87     std::map<int32_t, std::string> errMap = {
88         { ERR_SYS_EVENT_SERVICE_NOT_FOUND, "service not found." },
89         { ERR_PARCEL_DATA_IS_NULL, "parcel data is null." },
90         { ERR_REMOTE_SERVICE_IS_NULL, "remote service is null." },
91         { ERR_CAN_NOT_WRITE_DESCRIPTOR, "descriptor wrote failed." },
92         { ERR_CAN_NOT_WRITE_PARCEL, "parcel wrote failed." },
93         { ERR_CAN_NOT_WRITE_REMOTE_OBJECT, "remote object wrote failed." },
94         { ERR_CAN_NOT_SEND_REQ, "request sent failed." },
95         { ERR_CAN_NOT_READ_PARCEL, "parcel read failed." },
96         { ERR_ADD_DEATH_RECIPIENT, "add death recipient failed." },
97         { ERR_QUERY_RULE_INVALID, "invalid query rule." },
98         { ERR_TOO_MANY_WATCHERS, "too many wathers subscribed." },
99         { ERR_QUERY_TOO_FREQUENTLY, "query too frequently." },
100     };
101     return errMap.find(errCode) == errMap.end() ?
102         "unknown error." : errMap.at(errCode);
103 }
104 
InitOptHandlers(std::map<int,OptHandler> & optHandlers)105 void InitOptHandlers(std::map<int, OptHandler>& optHandlers)
106 {
107     std::map<int, OptHandler> tmpHandlers = {
108         {'v', [] (struct ArgStuct& cmdArg, const char* optarg) {
109             cmdArg.checkValidEvent = true;
110         }}, {'r', [] (struct ArgStuct& cmdArg, const char* optarg) {
111             cmdArg.real = true;
112         }}, {'c', [] (struct ArgStuct& cmdArg, const char* optarg) {
113             cmdArg.ruleType = GetRuleTypeFromArg(optarg);
114         }}, {'o', [] (struct ArgStuct& cmdArg, const char* optarg) {
115             cmdArg.domain = optarg;
116         }}, {'n', [] (struct ArgStuct& cmdArg, const char* optarg) {
117             cmdArg.eventName = optarg;
118         }}, {'t', [] (struct ArgStuct& cmdArg, const char* optarg) {
119             cmdArg.tag = optarg;
120         }}, {'l', [] (struct ArgStuct& cmdArg, const char* optarg) {
121             cmdArg.history = true;
122         }}, {'s', [] (struct ArgStuct& cmdArg, const char* optarg) {
123             cmdArg.beginTime = strtoll(optarg, nullptr, 0);
124         }}, {'S', [] (struct ArgStuct& cmdArg, const char* optarg) {
125             cmdArg.beginTime = ParseTimeStampFromArgs(std::string(optarg));
126         }}, {'e', [] (struct ArgStuct& cmdArg, const char* optarg) {
127             cmdArg.endTime = strtoll(optarg, nullptr, 0);
128         }}, {'E', [] (struct ArgStuct& cmdArg, const char* optarg) {
129             cmdArg.endTime = ParseTimeStampFromArgs(std::string(optarg));
130         }}, {'m', [] (struct ArgStuct& cmdArg, const char* optarg) {
131             cmdArg.maxEvents = strtol(optarg, nullptr, 0);
132         }}, {'d', [] (struct ArgStuct& cmdArg, const char* optarg) {
133             cmdArg.isDebug = true;
134         }}, {'g', [] (struct ArgStuct& cmdArg, const char* optarg) {
135             cmdArg.eventType = GetEventTypeFromArg(optarg);
136         }},
137     };
138     optHandlers.insert(tmpHandlers.begin(), tmpHandlers.end());
139 }
140 
IsValidRegex(const std::string & regStr)141 bool IsValidRegex(const std::string& regStr)
142 {
143     if (regStr.length() > 32) { // 32 is the length limit of regex
144         return false;
145     }
146     int flags = REG_EXTENDED;
147     regex_t reg;
148     // check whether the pattern is valid
149     int status = regcomp(&reg, regStr.c_str(), flags);
150     // free regex
151     regfree(&reg);
152     return (status == REG_OK);
153 }
154 }
155 
HiSysEventTool(bool autoExit)156 HiSysEventTool::HiSysEventTool(bool autoExit) : clientCmdArg {
157     false, false, "", "", "", RuleType::WHOLE_WORD,
158     false, false, -1, -1, 10000, 0}, autoExit(autoExit)
159 {
160     InitOptHandlers(optHandlers);
161 }
162 
ParseCmdLine(int argc,char ** argv)163 bool HiSysEventTool::ParseCmdLine(int argc, char** argv)
164 {
165     if (argv == nullptr) {
166         return false;
167     }
168     if (argc > 1) {
169         HandleInput(argc, argv, ARG_SELECTION);
170     }
171     return CheckCmdLine();
172 }
173 
CheckCmdLine()174 bool HiSysEventTool::CheckCmdLine()
175 {
176     if (!clientCmdArg.real && !clientCmdArg.history) {
177         return false;
178     }
179 
180     if (clientCmdArg.real && clientCmdArg.history) {
181         cout << "canot read both read && history hisysevent" << endl;
182         return false;
183     }
184 
185     if (clientCmdArg.isDebug && !clientCmdArg.real) {
186         cout << "debug must follow with real log" << endl;
187         return false;
188     }
189 
190     if (clientCmdArg.history) {
191         auto timestampValidCheck = clientCmdArg.endTime > 0
192             && clientCmdArg.beginTime > clientCmdArg.endTime;
193         if (timestampValidCheck) {
194             cout << "invalid time startTime must less than endTime(";
195             cout << clientCmdArg.beginTime << " > " << clientCmdArg.endTime << ")." << endl;
196             return false;
197         }
198     }
199     return true;
200 }
201 
HandleInput(int argc,char ** argv,const char * selection)202 void HiSysEventTool::HandleInput(int argc, char** argv, const char* selection)
203 {
204     int opt;
205     while ((opt = getopt(argc, argv, selection)) != INVALID_ARG_OPT) {
206         if (opt == 'h') {
207             DoCmdHelp();
208             if (autoExit) {
209                 _exit(0);
210             }
211         }
212         if (optHandlers.find(opt) != optHandlers.end()) {
213             optHandlers.at(opt)(clientCmdArg, optarg);
214         }
215     }
216 }
217 
DoCmdHelp()218 void HiSysEventTool::DoCmdHelp()
219 {
220     cout << "hisysevent [[-v] -r [-d | -c [WHOLE_WORD|PREFIX|REGULAR] -t <tag> "
221         << "| -c [WHOLE_WORD|PREFIX|REGULAR] -o <domain> -n <eventName> "
222         << "| -g [FAULT|STATISTIC|SECURITY|BEHAVIOR]] "
223         << "| -l [[-s <begin time> -e <end time> | -S <formatted begin time> -E <formatted end time>] "
224         << "-m <count> -c [WHOLE_WORD] -o <domain> -n <eventName> -g [FAULT|STATISTIC|SECURITY|BEHAVIOR]]]" << endl;
225     cout << "-r,    subscribe on all domains, event names and tags." << endl;
226     cout << "-r -c [WHOLE_WORD|PREFIX|REGULAR] -t <tag>"
227         << ", subscribe on tag." << endl;
228     cout << "-r -c [WHOLE_WORD|PREFIX|REGULAR] -o <domain> -n <eventName>"
229         << ", subscribe on domain and event name." << endl;
230     cout << "-r -g [FAULT|STATISTIC|SECURITY|BEHAVIOR]"
231         << ", subscribe on event type." << endl;
232     cout << "-r -d set debug mode, both options must appear at the same time." << endl;
233     cout << "-l -s <begin time> -e <end time> -m <max hisysevent count>"
234         << ", get history hisysevent log with time stamps, end time should not be "
235         << "earlier than begin time." << endl;
236     cout << "-l -S <formatted begin time> -E <formatted end time> -m <max hisysevent count>"
237         << ", get history hisysevent log with formatted time string, end time should not be "
238         << "earlier than begin time." << endl;
239     cout << "-l -c [WHOLE_WORD] -o <domain> -n <eventName> -m <max hisysevent count>"
240         << ", get history hisysevent log with domain and event name." << endl;
241     cout << "-l -g [FAULT|STATISTIC|SECURITY|BEHAVIOR] -m <max hisysevent count>"
242         << ", get history hisysevent log with event type." << endl;
243     cout << "-v,    open valid event checking mode." << endl;
244     cout << "-h,    help manual." << endl;
245 }
246 
DoAction()247 bool HiSysEventTool::DoAction()
248 {
249     if (clientCmdArg.ruleType == RuleType::REGULAR && (!IsValidRegex(clientCmdArg.domain)
250         || !IsValidRegex(clientCmdArg.eventName) || !IsValidRegex(clientCmdArg.tag))) {
251         cout << "invalid regex" << endl;
252         return false;
253     }
254     if (clientCmdArg.real) {
255         auto toolListener = std::make_shared<HiSysEventToolListener>(clientCmdArg.checkValidEvent);
256         if (toolListener == nullptr) {
257             return false;
258         }
259         std::vector<ListenerRule> sysRules;
260         ListenerRule listenerRule(clientCmdArg.domain, clientCmdArg.eventName,
261             clientCmdArg.tag, clientCmdArg.ruleType, clientCmdArg.eventType);
262         sysRules.emplace_back(listenerRule);
263         auto retCode = HiSysEventManager::AddListener(toolListener, sysRules);
264         if (retCode != IPC_CALL_SUCCEED ||
265             (clientCmdArg.isDebug && HiSysEventManager::SetDebugMode(toolListener, true) != 0)) {
266             cout << "failed to subscribe system event: " << GetErrorDescription(retCode) << endl;
267         }
268         return true;
269     }
270 
271     if (clientCmdArg.history) {
272         auto queryCallBack = std::make_shared<HiSysEventToolQuery>(clientCmdArg.checkValidEvent, autoExit);
273         if (queryCallBack == nullptr) {
274             return false;
275         }
276         struct QueryArg args(clientCmdArg.beginTime, clientCmdArg.endTime, clientCmdArg.maxEvents);
277         std::vector<QueryRule> queryRules;
278         if (clientCmdArg.ruleType != RuleType::WHOLE_WORD) {
279             cout << "only \"-c WHOLE_WORD\" supported with \"hisysevent -l\" cmd." << endl;
280             return false;
281         }
282         if (!clientCmdArg.domain.empty() || !clientCmdArg.eventName.empty() ||
283             clientCmdArg.eventType != INVALID_EVENT_TYPE) {
284             QueryRule rule(clientCmdArg.domain, { clientCmdArg.eventName },
285                 clientCmdArg.ruleType, clientCmdArg.eventType);
286             queryRules.push_back(rule);
287         }
288         auto retCode = HiSysEventManager::Query(args, queryRules, queryCallBack);
289         if (retCode != IPC_CALL_SUCCEED) {
290             cout << "failed to query system event: " << GetErrorDescription(retCode) << endl;
291         }
292         return true;
293     }
294     return false;
295 }
296 
WaitClient()297 void HiSysEventTool::WaitClient()
298 {
299     unique_lock<mutex> lock(mutexClient);
300     condvClient.wait(lock);
301 }
302 
NotifyClient()303 void HiSysEventTool::NotifyClient()
304 {
305     condvClient.notify_one();
306 }
307 } // namespace HiviewDFX
308 } // namespace OHOS
309