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(®, regStr.c_str(), flags);
150 // free regex
151 regfree(®);
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