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