• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&reg, regStr.c_str(), flags);
148     // free regex
149     regfree(&reg);
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