11401458bSopenharmony_ci/*
21401458bSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
31401458bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
41401458bSopenharmony_ci * you may not use this file except in compliance with the License.
51401458bSopenharmony_ci * You may obtain a copy of the License at
61401458bSopenharmony_ci *
71401458bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
81401458bSopenharmony_ci *
91401458bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
101401458bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
111401458bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
121401458bSopenharmony_ci * See the License for the specific language governing permissions and
131401458bSopenharmony_ci * limitations under the License.
141401458bSopenharmony_ci */
151401458bSopenharmony_ci
161401458bSopenharmony_ci#include "hisysevent_tool.h"
171401458bSopenharmony_ci
181401458bSopenharmony_ci#include <getopt.h>
191401458bSopenharmony_ci#include <iomanip>
201401458bSopenharmony_ci#include <iostream>
211401458bSopenharmony_ci#include <regex>
221401458bSopenharmony_ci#include <regex.h>
231401458bSopenharmony_ci#include <sstream>
241401458bSopenharmony_ci#include <unistd.h>
251401458bSopenharmony_ci
261401458bSopenharmony_ci#include "hisysevent.h"
271401458bSopenharmony_ci#include "hisysevent_tool_listener.h"
281401458bSopenharmony_ci#include "hisysevent_tool_query.h"
291401458bSopenharmony_ci
301401458bSopenharmony_ci#include "ret_code.h"
311401458bSopenharmony_ci
321401458bSopenharmony_ciusing namespace std;
331401458bSopenharmony_ci
341401458bSopenharmony_cinamespace OHOS {
351401458bSopenharmony_cinamespace HiviewDFX {
361401458bSopenharmony_cinamespace {
371401458bSopenharmony_ciconstexpr char ARG_SELECTION[] = "vrc:o:n:t:lS:s:E:e:m:dhg:";
381401458bSopenharmony_ciconstexpr uint32_t INVALID_EVENT_TYPE = 0;
391401458bSopenharmony_ciconstexpr int INVALID_ARG_OPT = -1;
401401458bSopenharmony_ciconstexpr long long DEFAULT_TIME_STAMP = -1;
411401458bSopenharmony_ciconstexpr long long SECONDS_2_MILLS = 1000;
421401458bSopenharmony_ci
431401458bSopenharmony_ciRuleType GetRuleTypeFromArg(const string& fromArgs)
441401458bSopenharmony_ci{
451401458bSopenharmony_ci    static std::map<const string, RuleType> ruleTypeMap {
461401458bSopenharmony_ci        { "WHOLE_WORD", RuleType::WHOLE_WORD },
471401458bSopenharmony_ci        { "PREFIX", RuleType::PREFIX },
481401458bSopenharmony_ci        { "REGULAR", RuleType::REGULAR }
491401458bSopenharmony_ci    };
501401458bSopenharmony_ci    if (ruleTypeMap.find(fromArgs) != ruleTypeMap.end()) {
511401458bSopenharmony_ci        return ruleTypeMap[fromArgs];
521401458bSopenharmony_ci    }
531401458bSopenharmony_ci    return RuleType::WHOLE_WORD;
541401458bSopenharmony_ci}
551401458bSopenharmony_ci
561401458bSopenharmony_ciuint32_t GetEventTypeFromArg(const string& fromArgs)
571401458bSopenharmony_ci{
581401458bSopenharmony_ci    static std::map<const string, HiSysEvent::EventType> eventTypeMap {
591401458bSopenharmony_ci        { "FAULT", HiSysEvent::EventType::FAULT },
601401458bSopenharmony_ci        { "STATISTIC", HiSysEvent::EventType::STATISTIC },
611401458bSopenharmony_ci        { "SECURITY", HiSysEvent::EventType::SECURITY },
621401458bSopenharmony_ci        { "BEHAVIOR", HiSysEvent::EventType::BEHAVIOR }
631401458bSopenharmony_ci    };
641401458bSopenharmony_ci    if (eventTypeMap.find(fromArgs) != eventTypeMap.end()) {
651401458bSopenharmony_ci        return static_cast<uint32_t>(eventTypeMap[fromArgs]);
661401458bSopenharmony_ci    }
671401458bSopenharmony_ci    return INVALID_EVENT_TYPE;
681401458bSopenharmony_ci}
691401458bSopenharmony_ci
701401458bSopenharmony_cilong long ParseTimeStampFromArgs(const string& fromArgs)
711401458bSopenharmony_ci{
721401458bSopenharmony_ci    regex formatRegex("[0-9]{4}-"
731401458bSopenharmony_ci        "((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[2469]|11)-(0[1-9]|[12][0-9]|30))"
741401458bSopenharmony_ci        " ([01][0-9]|2[0-3])(:[0-5][0-9]){2}");
751401458bSopenharmony_ci    smatch matchRet;
761401458bSopenharmony_ci    if (!std::regex_match(fromArgs, matchRet, formatRegex)) {
771401458bSopenharmony_ci        return DEFAULT_TIME_STAMP;
781401458bSopenharmony_ci    }
791401458bSopenharmony_ci    std::istringstream is(fromArgs);
801401458bSopenharmony_ci    struct tm time = {};
811401458bSopenharmony_ci    is >> std::get_time(&time, "%Y-%m-%d %H:%M:%S");
821401458bSopenharmony_ci    return static_cast<long long>(mktime(&time)) * SECONDS_2_MILLS;
831401458bSopenharmony_ci}
841401458bSopenharmony_ci
851401458bSopenharmony_cistd::string GetErrorDescription(int32_t errCode)
861401458bSopenharmony_ci{
871401458bSopenharmony_ci    std::map<int32_t, std::string> errMap = {
881401458bSopenharmony_ci        { ERR_SYS_EVENT_SERVICE_NOT_FOUND, "service not found." },
891401458bSopenharmony_ci        { ERR_PARCEL_DATA_IS_NULL, "parcel data is null." },
901401458bSopenharmony_ci        { ERR_REMOTE_SERVICE_IS_NULL, "remote service is null." },
911401458bSopenharmony_ci        { ERR_CAN_NOT_WRITE_DESCRIPTOR, "descriptor wrote failed." },
921401458bSopenharmony_ci        { ERR_CAN_NOT_WRITE_PARCEL, "parcel wrote failed." },
931401458bSopenharmony_ci        { ERR_CAN_NOT_WRITE_REMOTE_OBJECT, "remote object wrote failed." },
941401458bSopenharmony_ci        { ERR_CAN_NOT_SEND_REQ, "request sent failed." },
951401458bSopenharmony_ci        { ERR_CAN_NOT_READ_PARCEL, "parcel read failed." },
961401458bSopenharmony_ci        { ERR_ADD_DEATH_RECIPIENT, "add death recipient failed." },
971401458bSopenharmony_ci        { ERR_QUERY_RULE_INVALID, "invalid query rule." },
981401458bSopenharmony_ci        { ERR_TOO_MANY_WATCHERS, "too many wathers subscribed." },
991401458bSopenharmony_ci        { ERR_QUERY_TOO_FREQUENTLY, "query too frequently." },
1001401458bSopenharmony_ci    };
1011401458bSopenharmony_ci    return errMap.find(errCode) == errMap.end() ?
1021401458bSopenharmony_ci        "unknown error." : errMap.at(errCode);
1031401458bSopenharmony_ci}
1041401458bSopenharmony_ci
1051401458bSopenharmony_civoid InitOptHandlers(std::map<int, OptHandler>& optHandlers)
1061401458bSopenharmony_ci{
1071401458bSopenharmony_ci    std::map<int, OptHandler> tmpHandlers = {
1081401458bSopenharmony_ci        {'v', [] (struct ArgStuct& cmdArg, const char* optarg) {
1091401458bSopenharmony_ci            cmdArg.checkValidEvent = true;
1101401458bSopenharmony_ci        }}, {'r', [] (struct ArgStuct& cmdArg, const char* optarg) {
1111401458bSopenharmony_ci            cmdArg.real = true;
1121401458bSopenharmony_ci        }}, {'c', [] (struct ArgStuct& cmdArg, const char* optarg) {
1131401458bSopenharmony_ci            cmdArg.ruleType = GetRuleTypeFromArg(optarg);
1141401458bSopenharmony_ci        }}, {'o', [] (struct ArgStuct& cmdArg, const char* optarg) {
1151401458bSopenharmony_ci            cmdArg.domain = optarg;
1161401458bSopenharmony_ci        }}, {'n', [] (struct ArgStuct& cmdArg, const char* optarg) {
1171401458bSopenharmony_ci            cmdArg.eventName = optarg;
1181401458bSopenharmony_ci        }}, {'t', [] (struct ArgStuct& cmdArg, const char* optarg) {
1191401458bSopenharmony_ci            cmdArg.tag = optarg;
1201401458bSopenharmony_ci        }}, {'l', [] (struct ArgStuct& cmdArg, const char* optarg) {
1211401458bSopenharmony_ci            cmdArg.history = true;
1221401458bSopenharmony_ci        }}, {'s', [] (struct ArgStuct& cmdArg, const char* optarg) {
1231401458bSopenharmony_ci            cmdArg.beginTime = strtoll(optarg, nullptr, 0);
1241401458bSopenharmony_ci        }}, {'S', [] (struct ArgStuct& cmdArg, const char* optarg) {
1251401458bSopenharmony_ci            cmdArg.beginTime = ParseTimeStampFromArgs(std::string(optarg));
1261401458bSopenharmony_ci        }}, {'e', [] (struct ArgStuct& cmdArg, const char* optarg) {
1271401458bSopenharmony_ci            cmdArg.endTime = strtoll(optarg, nullptr, 0);
1281401458bSopenharmony_ci        }}, {'E', [] (struct ArgStuct& cmdArg, const char* optarg) {
1291401458bSopenharmony_ci            cmdArg.endTime = ParseTimeStampFromArgs(std::string(optarg));
1301401458bSopenharmony_ci        }}, {'m', [] (struct ArgStuct& cmdArg, const char* optarg) {
1311401458bSopenharmony_ci            cmdArg.maxEvents = strtol(optarg, nullptr, 0);
1321401458bSopenharmony_ci        }}, {'d', [] (struct ArgStuct& cmdArg, const char* optarg) {
1331401458bSopenharmony_ci            cmdArg.isDebug = true;
1341401458bSopenharmony_ci        }}, {'g', [] (struct ArgStuct& cmdArg, const char* optarg) {
1351401458bSopenharmony_ci            cmdArg.eventType = GetEventTypeFromArg(optarg);
1361401458bSopenharmony_ci        }},
1371401458bSopenharmony_ci    };
1381401458bSopenharmony_ci    optHandlers.insert(tmpHandlers.begin(), tmpHandlers.end());
1391401458bSopenharmony_ci}
1401401458bSopenharmony_ci
1411401458bSopenharmony_cibool IsValidRegex(const std::string& regStr)
1421401458bSopenharmony_ci{
1431401458bSopenharmony_ci    if (regStr.length() > 32) { // 32 is the length limit of regex
1441401458bSopenharmony_ci        return false;
1451401458bSopenharmony_ci    }
1461401458bSopenharmony_ci    int flags = REG_EXTENDED;
1471401458bSopenharmony_ci    regex_t reg;
1481401458bSopenharmony_ci    // check whether the pattern is valid
1491401458bSopenharmony_ci    int status = regcomp(&reg, regStr.c_str(), flags);
1501401458bSopenharmony_ci    // free regex
1511401458bSopenharmony_ci    regfree(&reg);
1521401458bSopenharmony_ci    return (status == REG_OK);
1531401458bSopenharmony_ci}
1541401458bSopenharmony_ci}
1551401458bSopenharmony_ci
1561401458bSopenharmony_ciHiSysEventTool::HiSysEventTool(bool autoExit) : clientCmdArg {
1571401458bSopenharmony_ci    false, false, "", "", "", RuleType::WHOLE_WORD,
1581401458bSopenharmony_ci    false, false, -1, -1, 10000, 0}, autoExit(autoExit)
1591401458bSopenharmony_ci{
1601401458bSopenharmony_ci    InitOptHandlers(optHandlers);
1611401458bSopenharmony_ci}
1621401458bSopenharmony_ci
1631401458bSopenharmony_cibool HiSysEventTool::ParseCmdLine(int argc, char** argv)
1641401458bSopenharmony_ci{
1651401458bSopenharmony_ci    if (argv == nullptr) {
1661401458bSopenharmony_ci        return false;
1671401458bSopenharmony_ci    }
1681401458bSopenharmony_ci    if (argc > 1) {
1691401458bSopenharmony_ci        HandleInput(argc, argv, ARG_SELECTION);
1701401458bSopenharmony_ci    }
1711401458bSopenharmony_ci    return CheckCmdLine();
1721401458bSopenharmony_ci}
1731401458bSopenharmony_ci
1741401458bSopenharmony_cibool HiSysEventTool::CheckCmdLine()
1751401458bSopenharmony_ci{
1761401458bSopenharmony_ci    if (!clientCmdArg.real && !clientCmdArg.history) {
1771401458bSopenharmony_ci        return false;
1781401458bSopenharmony_ci    }
1791401458bSopenharmony_ci
1801401458bSopenharmony_ci    if (clientCmdArg.real && clientCmdArg.history) {
1811401458bSopenharmony_ci        cout << "canot read both read && history hisysevent" << endl;
1821401458bSopenharmony_ci        return false;
1831401458bSopenharmony_ci    }
1841401458bSopenharmony_ci
1851401458bSopenharmony_ci    if (clientCmdArg.isDebug && !clientCmdArg.real) {
1861401458bSopenharmony_ci        cout << "debug must follow with real log" << endl;
1871401458bSopenharmony_ci        return false;
1881401458bSopenharmony_ci    }
1891401458bSopenharmony_ci
1901401458bSopenharmony_ci    if (clientCmdArg.history) {
1911401458bSopenharmony_ci        auto timestampValidCheck = clientCmdArg.endTime > 0
1921401458bSopenharmony_ci            && clientCmdArg.beginTime > clientCmdArg.endTime;
1931401458bSopenharmony_ci        if (timestampValidCheck) {
1941401458bSopenharmony_ci            cout << "invalid time startTime must less than endTime(";
1951401458bSopenharmony_ci            cout << clientCmdArg.beginTime << " > " << clientCmdArg.endTime << ")." << endl;
1961401458bSopenharmony_ci            return false;
1971401458bSopenharmony_ci        }
1981401458bSopenharmony_ci    }
1991401458bSopenharmony_ci    return true;
2001401458bSopenharmony_ci}
2011401458bSopenharmony_ci
2021401458bSopenharmony_civoid HiSysEventTool::HandleInput(int argc, char** argv, const char* selection)
2031401458bSopenharmony_ci{
2041401458bSopenharmony_ci    int opt;
2051401458bSopenharmony_ci    while ((opt = getopt(argc, argv, selection)) != INVALID_ARG_OPT) {
2061401458bSopenharmony_ci        if (opt == 'h') {
2071401458bSopenharmony_ci            DoCmdHelp();
2081401458bSopenharmony_ci            if (autoExit) {
2091401458bSopenharmony_ci                _exit(0);
2101401458bSopenharmony_ci            }
2111401458bSopenharmony_ci        }
2121401458bSopenharmony_ci        if (optHandlers.find(opt) != optHandlers.end()) {
2131401458bSopenharmony_ci            optHandlers.at(opt)(clientCmdArg, optarg);
2141401458bSopenharmony_ci        }
2151401458bSopenharmony_ci    }
2161401458bSopenharmony_ci}
2171401458bSopenharmony_ci
2181401458bSopenharmony_civoid HiSysEventTool::DoCmdHelp()
2191401458bSopenharmony_ci{
2201401458bSopenharmony_ci    cout << "hisysevent [[-v] -r [-d | -c [WHOLE_WORD|PREFIX|REGULAR] -t <tag> "
2211401458bSopenharmony_ci        << "| -c [WHOLE_WORD|PREFIX|REGULAR] -o <domain> -n <eventName> "
2221401458bSopenharmony_ci        << "| -g [FAULT|STATISTIC|SECURITY|BEHAVIOR]] "
2231401458bSopenharmony_ci        << "| -l [[-s <begin time> -e <end time> | -S <formatted begin time> -E <formatted end time>] "
2241401458bSopenharmony_ci        << "-m <count> -c [WHOLE_WORD] -o <domain> -n <eventName> -g [FAULT|STATISTIC|SECURITY|BEHAVIOR]]]" << endl;
2251401458bSopenharmony_ci    cout << "-r,    subscribe on all domains, event names and tags." << endl;
2261401458bSopenharmony_ci    cout << "-r -c [WHOLE_WORD|PREFIX|REGULAR] -t <tag>"
2271401458bSopenharmony_ci        << ", subscribe on tag." << endl;
2281401458bSopenharmony_ci    cout << "-r -c [WHOLE_WORD|PREFIX|REGULAR] -o <domain> -n <eventName>"
2291401458bSopenharmony_ci        << ", subscribe on domain and event name." << endl;
2301401458bSopenharmony_ci    cout << "-r -g [FAULT|STATISTIC|SECURITY|BEHAVIOR]"
2311401458bSopenharmony_ci        << ", subscribe on event type." << endl;
2321401458bSopenharmony_ci    cout << "-r -d set debug mode, both options must appear at the same time." << endl;
2331401458bSopenharmony_ci    cout << "-l -s <begin time> -e <end time> -m <max hisysevent count>"
2341401458bSopenharmony_ci        << ", get history hisysevent log with time stamps, end time should not be "
2351401458bSopenharmony_ci        << "earlier than begin time." << endl;
2361401458bSopenharmony_ci    cout << "-l -S <formatted begin time> -E <formatted end time> -m <max hisysevent count>"
2371401458bSopenharmony_ci        << ", get history hisysevent log with formatted time string, end time should not be "
2381401458bSopenharmony_ci        << "earlier than begin time." << endl;
2391401458bSopenharmony_ci    cout << "-l -c [WHOLE_WORD] -o <domain> -n <eventName> -m <max hisysevent count>"
2401401458bSopenharmony_ci        << ", get history hisysevent log with domain and event name." << endl;
2411401458bSopenharmony_ci    cout << "-l -g [FAULT|STATISTIC|SECURITY|BEHAVIOR] -m <max hisysevent count>"
2421401458bSopenharmony_ci        << ", get history hisysevent log with event type." << endl;
2431401458bSopenharmony_ci    cout << "-v,    open valid event checking mode." << endl;
2441401458bSopenharmony_ci    cout << "-h,    help manual." << endl;
2451401458bSopenharmony_ci}
2461401458bSopenharmony_ci
2471401458bSopenharmony_cibool HiSysEventTool::DoAction()
2481401458bSopenharmony_ci{
2491401458bSopenharmony_ci    if (clientCmdArg.ruleType == RuleType::REGULAR && (!IsValidRegex(clientCmdArg.domain)
2501401458bSopenharmony_ci        || !IsValidRegex(clientCmdArg.eventName) || !IsValidRegex(clientCmdArg.tag))) {
2511401458bSopenharmony_ci        cout << "invalid regex" << endl;
2521401458bSopenharmony_ci        return false;
2531401458bSopenharmony_ci    }
2541401458bSopenharmony_ci    if (clientCmdArg.real) {
2551401458bSopenharmony_ci        auto toolListener = std::make_shared<HiSysEventToolListener>(clientCmdArg.checkValidEvent);
2561401458bSopenharmony_ci        if (toolListener == nullptr) {
2571401458bSopenharmony_ci            return false;
2581401458bSopenharmony_ci        }
2591401458bSopenharmony_ci        std::vector<ListenerRule> sysRules;
2601401458bSopenharmony_ci        ListenerRule listenerRule(clientCmdArg.domain, clientCmdArg.eventName,
2611401458bSopenharmony_ci            clientCmdArg.tag, clientCmdArg.ruleType, clientCmdArg.eventType);
2621401458bSopenharmony_ci        sysRules.emplace_back(listenerRule);
2631401458bSopenharmony_ci        auto retCode = HiSysEventManager::AddListener(toolListener, sysRules);
2641401458bSopenharmony_ci        if (retCode != IPC_CALL_SUCCEED ||
2651401458bSopenharmony_ci            (clientCmdArg.isDebug && HiSysEventManager::SetDebugMode(toolListener, true) != 0)) {
2661401458bSopenharmony_ci            cout << "failed to subscribe system event: " << GetErrorDescription(retCode) << endl;
2671401458bSopenharmony_ci        }
2681401458bSopenharmony_ci        return true;
2691401458bSopenharmony_ci    }
2701401458bSopenharmony_ci
2711401458bSopenharmony_ci    if (clientCmdArg.history) {
2721401458bSopenharmony_ci        auto queryCallBack = std::make_shared<HiSysEventToolQuery>(clientCmdArg.checkValidEvent, autoExit);
2731401458bSopenharmony_ci        if (queryCallBack == nullptr) {
2741401458bSopenharmony_ci            return false;
2751401458bSopenharmony_ci        }
2761401458bSopenharmony_ci        struct QueryArg args(clientCmdArg.beginTime, clientCmdArg.endTime, clientCmdArg.maxEvents);
2771401458bSopenharmony_ci        std::vector<QueryRule> queryRules;
2781401458bSopenharmony_ci        if (clientCmdArg.ruleType != RuleType::WHOLE_WORD) {
2791401458bSopenharmony_ci            cout << "only \"-c WHOLE_WORD\" supported with \"hisysevent -l\" cmd." << endl;
2801401458bSopenharmony_ci            return false;
2811401458bSopenharmony_ci        }
2821401458bSopenharmony_ci        if (!clientCmdArg.domain.empty() || !clientCmdArg.eventName.empty() ||
2831401458bSopenharmony_ci            clientCmdArg.eventType != INVALID_EVENT_TYPE) {
2841401458bSopenharmony_ci            QueryRule rule(clientCmdArg.domain, { clientCmdArg.eventName },
2851401458bSopenharmony_ci                clientCmdArg.ruleType, clientCmdArg.eventType);
2861401458bSopenharmony_ci            queryRules.push_back(rule);
2871401458bSopenharmony_ci        }
2881401458bSopenharmony_ci        auto retCode = HiSysEventManager::Query(args, queryRules, queryCallBack);
2891401458bSopenharmony_ci        if (retCode != IPC_CALL_SUCCEED) {
2901401458bSopenharmony_ci            cout << "failed to query system event: " << GetErrorDescription(retCode) << endl;
2911401458bSopenharmony_ci        }
2921401458bSopenharmony_ci        return true;
2931401458bSopenharmony_ci    }
2941401458bSopenharmony_ci    return false;
2951401458bSopenharmony_ci}
2961401458bSopenharmony_ci
2971401458bSopenharmony_civoid HiSysEventTool::WaitClient()
2981401458bSopenharmony_ci{
2991401458bSopenharmony_ci    unique_lock<mutex> lock(mutexClient);
3001401458bSopenharmony_ci    condvClient.wait(lock);
3011401458bSopenharmony_ci}
3021401458bSopenharmony_ci
3031401458bSopenharmony_civoid HiSysEventTool::NotifyClient()
3041401458bSopenharmony_ci{
3051401458bSopenharmony_ci    condvClient.notify_one();
3061401458bSopenharmony_ci}
3071401458bSopenharmony_ci} // namespace HiviewDFX
3081401458bSopenharmony_ci} // namespace OHOS
309