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:hg:";
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 }}, {'g', [] (struct ArgStuct& cmdArg, const char* optarg) {
133 cmdArg.eventType = GetEventTypeFromArg(optarg);
134 }},
135 };
136 optHandlers.insert(tmpHandlers.begin(), tmpHandlers.end());
137 }
138
IsValidRegex(const std::string & regStr)139 bool IsValidRegex(const std::string& regStr)
140 {
141 if (regStr.length() > 32) { // 32 is the length limit of regex
142 return false;
143 }
144 int flags = REG_EXTENDED;
145 regex_t reg;
146 // check whether the pattern is valid
147 int status = regcomp(®, regStr.c_str(), flags);
148 // free regex
149 regfree(®);
150 return (status == REG_OK);
151 }
152 }
153
HiSysEventTool(bool autoExit)154 HiSysEventTool::HiSysEventTool(bool autoExit) : clientCmdArg {
155 false, false, "", "", "", RuleType::WHOLE_WORD,
156 false, -1, -1, 10000, 0}, autoExit(autoExit)
157 {
158 InitOptHandlers(optHandlers);
159 }
160
ParseCmdLine(int argc,char ** argv)161 bool HiSysEventTool::ParseCmdLine(int argc, char** argv)
162 {
163 if (argv == nullptr) {
164 return false;
165 }
166 if (argc > 1) {
167 HandleInput(argc, argv, ARG_SELECTION);
168 }
169 return CheckCmdLine();
170 }
171
CheckCmdLine()172 bool HiSysEventTool::CheckCmdLine()
173 {
174 if (!clientCmdArg.real && !clientCmdArg.history) {
175 return false;
176 }
177
178 if (clientCmdArg.real && clientCmdArg.history) {
179 cout << "canot read both read && history hisysevent" << endl;
180 return false;
181 }
182
183 if (clientCmdArg.history) {
184 auto timestampValidCheck = clientCmdArg.endTime > 0
185 && clientCmdArg.beginTime > clientCmdArg.endTime;
186 if (timestampValidCheck) {
187 cout << "invalid time startTime must less than endTime(";
188 cout << clientCmdArg.beginTime << " > " << clientCmdArg.endTime << ")." << endl;
189 return false;
190 }
191 }
192 return true;
193 }
194
HandleInput(int argc,char ** argv,const char * selection)195 void HiSysEventTool::HandleInput(int argc, char** argv, const char* selection)
196 {
197 int opt;
198 while ((opt = getopt(argc, argv, selection)) != INVALID_ARG_OPT) {
199 if (opt == 'h') {
200 DoCmdHelp();
201 if (autoExit) {
202 _exit(0);
203 }
204 }
205 if (optHandlers.find(opt) != optHandlers.end()) {
206 optHandlers.at(opt)(clientCmdArg, optarg);
207 }
208 }
209 }
210
DoCmdHelp()211 void HiSysEventTool::DoCmdHelp()
212 {
213 cout << "hisysevent [[-v] -r [-c [WHOLE_WORD|PREFIX|REGULAR] -t <tag> "
214 << "| -c [WHOLE_WORD|PREFIX|REGULAR] -o <domain> -n <eventName> "
215 << "| -g [FAULT|STATISTIC|SECURITY|BEHAVIOR]] "
216 << "| -l [[-s <begin time> -e <end time> | -S <formatted begin time> -E <formatted end time>] "
217 << "-m <count> -c [WHOLE_WORD] -o <domain> -n <eventName> -g [FAULT|STATISTIC|SECURITY|BEHAVIOR]]]" << endl;
218 cout << "-r, subscribe on all domains, event names and tags." << endl;
219 cout << "-r -c [WHOLE_WORD|PREFIX|REGULAR] -t <tag>"
220 << ", subscribe on tag." << endl;
221 cout << "-r -c [WHOLE_WORD|PREFIX|REGULAR] -o <domain> -n <eventName>"
222 << ", subscribe on domain and event name." << endl;
223 cout << "-r -g [FAULT|STATISTIC|SECURITY|BEHAVIOR]"
224 << ", subscribe on event type." << endl;
225 cout << "-l -s <begin time> -e <end time> -m <max hisysevent count>"
226 << ", get history hisysevent log with time stamps, end time should not be "
227 << "earlier than begin time." << endl;
228 cout << "-l -S <formatted begin time> -E <formatted end time> -m <max hisysevent count>"
229 << ", get history hisysevent log with formatted time string, end time should not be "
230 << "earlier than begin time." << endl;
231 cout << "-l -c [WHOLE_WORD] -o <domain> -n <eventName> -m <max hisysevent count>"
232 << ", get history hisysevent log with domain and event name." << endl;
233 cout << "-l -g [FAULT|STATISTIC|SECURITY|BEHAVIOR] -m <max hisysevent count>"
234 << ", get history hisysevent log with event type." << endl;
235 cout << "-v, open valid event checking mode." << endl;
236 cout << "-h, help manual." << endl;
237 }
238
DoAction()239 bool HiSysEventTool::DoAction()
240 {
241 if (clientCmdArg.ruleType == RuleType::REGULAR && (!IsValidRegex(clientCmdArg.domain)
242 || !IsValidRegex(clientCmdArg.eventName) || !IsValidRegex(clientCmdArg.tag))) {
243 cout << "invalid regex" << endl;
244 return false;
245 }
246 if (clientCmdArg.real) {
247 auto toolListener = std::make_shared<HiSysEventToolListener>(clientCmdArg.checkValidEvent);
248 if (toolListener == nullptr) {
249 return false;
250 }
251 std::vector<ListenerRule> sysRules;
252 ListenerRule listenerRule(clientCmdArg.domain, clientCmdArg.eventName,
253 clientCmdArg.tag, clientCmdArg.ruleType, clientCmdArg.eventType);
254 sysRules.emplace_back(listenerRule);
255 auto retCode = HiSysEventManager::AddListener(toolListener, sysRules);
256 if (retCode != IPC_CALL_SUCCEED) {
257 cout << "failed to subscribe system event: " << GetErrorDescription(retCode) << endl;
258 }
259 return true;
260 }
261
262 if (clientCmdArg.history) {
263 auto queryCallBack = std::make_shared<HiSysEventToolQuery>(clientCmdArg.checkValidEvent, autoExit);
264 if (queryCallBack == nullptr) {
265 return false;
266 }
267 struct QueryArg args(clientCmdArg.beginTime, clientCmdArg.endTime, clientCmdArg.maxEvents);
268 std::vector<QueryRule> queryRules;
269 if (clientCmdArg.ruleType != RuleType::WHOLE_WORD) {
270 cout << "only \"-c WHOLE_WORD\" supported with \"hisysevent -l\" cmd." << endl;
271 return false;
272 }
273 if (!clientCmdArg.domain.empty() || !clientCmdArg.eventName.empty() ||
274 clientCmdArg.eventType != INVALID_EVENT_TYPE) {
275 QueryRule rule(clientCmdArg.domain, { clientCmdArg.eventName },
276 clientCmdArg.ruleType, clientCmdArg.eventType);
277 queryRules.push_back(rule);
278 }
279 auto retCode = HiSysEventManager::Query(args, queryRules, queryCallBack);
280 if (retCode != IPC_CALL_SUCCEED) {
281 cout << "failed to query system event: " << GetErrorDescription(retCode) << endl;
282 }
283 return true;
284 }
285 return false;
286 }
287
WaitClient()288 void HiSysEventTool::WaitClient()
289 {
290 unique_lock<mutex> lock(mutexClient);
291 condvClient.wait(lock);
292 }
293
NotifyClient()294 void HiSysEventTool::NotifyClient()
295 {
296 condvClient.notify_one();
297 }
298 } // namespace HiviewDFX
299 } // namespace OHOS
300