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 32using namespace std; 33 34namespace OHOS { 35namespace HiviewDFX { 36namespace { 37constexpr char ARG_SELECTION[] = "vrc:o:n:t:lS:s:E:e:m:dhg:"; 38constexpr uint32_t INVALID_EVENT_TYPE = 0; 39constexpr int INVALID_ARG_OPT = -1; 40constexpr long long DEFAULT_TIME_STAMP = -1; 41constexpr long long SECONDS_2_MILLS = 1000; 42 43RuleType 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 56uint32_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 70long 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 85std::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 105void 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 141bool 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 156HiSysEventTool::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 163bool 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 174bool 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 202void 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 218void 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 247bool 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 297void HiSysEventTool::WaitClient() 298{ 299 unique_lock<mutex> lock(mutexClient); 300 condvClient.wait(lock); 301} 302 303void HiSysEventTool::NotifyClient() 304{ 305 condvClient.notify_one(); 306} 307} // namespace HiviewDFX 308} // namespace OHOS 309