100600bfbSopenharmony_ci/*
200600bfbSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
300600bfbSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
400600bfbSopenharmony_ci * you may not use this file except in compliance with the License.
500600bfbSopenharmony_ci * You may obtain a copy of the License at
600600bfbSopenharmony_ci *
700600bfbSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
800600bfbSopenharmony_ci *
900600bfbSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1000600bfbSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1100600bfbSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1200600bfbSopenharmony_ci * See the License for the specific language governing permissions and
1300600bfbSopenharmony_ci * limitations under the License.
1400600bfbSopenharmony_ci */
1500600bfbSopenharmony_ci#include "dump_common_utils.h"
1600600bfbSopenharmony_ci#include <file_ex.h>
1700600bfbSopenharmony_ci#include <securec.h>
1800600bfbSopenharmony_ci#include <string_ex.h>
1900600bfbSopenharmony_ci#include <dirent.h>
2000600bfbSopenharmony_ci#include <fstream>
2100600bfbSopenharmony_ci#include <iostream>
2200600bfbSopenharmony_ci#include "hilog_wrapper.h"
2300600bfbSopenharmony_ci#include "sys/stat.h"
2400600bfbSopenharmony_ci#include "util/string_utils.h"
2500600bfbSopenharmony_ci#include "util/file_utils.h"
2600600bfbSopenharmony_ci
2700600bfbSopenharmony_ciusing namespace std;
2800600bfbSopenharmony_cinamespace OHOS {
2900600bfbSopenharmony_cinamespace HiviewDFX {
3000600bfbSopenharmony_cinamespace {
3100600bfbSopenharmony_ciconstexpr int LINE_ITEM_MIN = 2;
3200600bfbSopenharmony_ciconstexpr int LINE_KEY = 0;
3300600bfbSopenharmony_ciconstexpr int LINE_VALUE = 1;
3400600bfbSopenharmony_ciconstexpr int LINE_VALUE_0 = 0;
3500600bfbSopenharmony_ciconstexpr int UNSET = -1;
3600600bfbSopenharmony_cistatic const std::string CPU_STR = "cpu";
3700600bfbSopenharmony_ci}
3800600bfbSopenharmony_ci
3900600bfbSopenharmony_cistd::vector<std::string> DumpCommonUtils::GetSubNodes(const std::string &path, bool digit)
4000600bfbSopenharmony_ci{
4100600bfbSopenharmony_ci    std::vector<std::string> subNodes;
4200600bfbSopenharmony_ci    auto dir = opendir(path.c_str());
4300600bfbSopenharmony_ci    if (dir == nullptr) {
4400600bfbSopenharmony_ci        return subNodes;
4500600bfbSopenharmony_ci    }
4600600bfbSopenharmony_ci    for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
4700600bfbSopenharmony_ci        std::string childNode = ent->d_name;
4800600bfbSopenharmony_ci        if (childNode == "." || childNode == "..") {
4900600bfbSopenharmony_ci            continue;
5000600bfbSopenharmony_ci        }
5100600bfbSopenharmony_ci        if (digit && !IsNumericStr(childNode)) {
5200600bfbSopenharmony_ci            continue;
5300600bfbSopenharmony_ci        }
5400600bfbSopenharmony_ci        subNodes.push_back(childNode);
5500600bfbSopenharmony_ci    }
5600600bfbSopenharmony_ci    closedir(dir);
5700600bfbSopenharmony_ci    return subNodes;
5800600bfbSopenharmony_ci}
5900600bfbSopenharmony_ci
6000600bfbSopenharmony_ci// the parameter of path should be full.
6100600bfbSopenharmony_cibool DumpCommonUtils::IsDirectory(const std::string &path)
6200600bfbSopenharmony_ci{
6300600bfbSopenharmony_ci    struct stat statBuffer;
6400600bfbSopenharmony_ci    if (stat(path.c_str(), &statBuffer) == 0 && S_ISDIR(statBuffer.st_mode)) {
6500600bfbSopenharmony_ci        return true;
6600600bfbSopenharmony_ci    }
6700600bfbSopenharmony_ci    return false;
6800600bfbSopenharmony_ci}
6900600bfbSopenharmony_ci
7000600bfbSopenharmony_cistd::vector<std::string> DumpCommonUtils::GetSubDir(const std::string &path, bool digit)
7100600bfbSopenharmony_ci{
7200600bfbSopenharmony_ci    std::vector<std::string> subDirs;
7300600bfbSopenharmony_ci    auto dir = opendir(path.c_str());
7400600bfbSopenharmony_ci    if (dir == nullptr) {
7500600bfbSopenharmony_ci        DUMPER_HILOGE(MODULE_SERVICE, "failed to open dir: %{public}s, errno: %{public}d", path.c_str(), errno);
7600600bfbSopenharmony_ci        return subDirs;
7700600bfbSopenharmony_ci    }
7800600bfbSopenharmony_ci    for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
7900600bfbSopenharmony_ci        std::string childNode = ent->d_name;
8000600bfbSopenharmony_ci        if (childNode == "." || childNode == "..") {
8100600bfbSopenharmony_ci            continue;
8200600bfbSopenharmony_ci        }
8300600bfbSopenharmony_ci        if (digit && !IsNumericStr(childNode)) {
8400600bfbSopenharmony_ci            continue;
8500600bfbSopenharmony_ci        }
8600600bfbSopenharmony_ci        if (!IsDirectory(path + "/" + childNode)) {
8700600bfbSopenharmony_ci            continue; // skip directory
8800600bfbSopenharmony_ci        }
8900600bfbSopenharmony_ci        subDirs.push_back(childNode);
9000600bfbSopenharmony_ci    }
9100600bfbSopenharmony_ci    closedir(dir);
9200600bfbSopenharmony_ci    return subDirs;
9300600bfbSopenharmony_ci}
9400600bfbSopenharmony_ci
9500600bfbSopenharmony_cistd::vector<int32_t> DumpCommonUtils::GetAllPids()
9600600bfbSopenharmony_ci{
9700600bfbSopenharmony_ci    std::string path = "/proc";
9800600bfbSopenharmony_ci    std::vector<int32_t> pids;
9900600bfbSopenharmony_ci    std::vector<std::string> allPids = GetSubDir(path, true);
10000600bfbSopenharmony_ci    for (const auto &pid : allPids) {
10100600bfbSopenharmony_ci        if (!IsNumericStr(pid)) {
10200600bfbSopenharmony_ci            continue;
10300600bfbSopenharmony_ci        }
10400600bfbSopenharmony_ci        pids.push_back(std::stoi(pid));
10500600bfbSopenharmony_ci    }
10600600bfbSopenharmony_ci    return pids;
10700600bfbSopenharmony_ci}
10800600bfbSopenharmony_ci
10900600bfbSopenharmony_ciDumpCommonUtils::CpuInfo::CpuInfo()
11000600bfbSopenharmony_ci{
11100600bfbSopenharmony_ci    id_ = UNSET;
11200600bfbSopenharmony_ci}
11300600bfbSopenharmony_ci
11400600bfbSopenharmony_cibool DumpCommonUtils::GetCpuInfos(std::vector<CpuInfo> &infos)
11500600bfbSopenharmony_ci{
11600600bfbSopenharmony_ci    std::vector<std::string> names;
11700600bfbSopenharmony_ci    if (!GetNamesInFolder("/sys/devices/system/cpu/", names)) {
11800600bfbSopenharmony_ci        return false;
11900600bfbSopenharmony_ci    }
12000600bfbSopenharmony_ci    for (size_t i = 0; i < names.size(); i++) {
12100600bfbSopenharmony_ci        std::string name = names[i];
12200600bfbSopenharmony_ci        if (!StartWith(name, CPU_STR)) {
12300600bfbSopenharmony_ci            continue;
12400600bfbSopenharmony_ci        }
12500600bfbSopenharmony_ci        std::string cpuId = name.substr(CPU_STR.size());
12600600bfbSopenharmony_ci        if (cpuId.empty() || (!IsNumericStr(cpuId))) {
12700600bfbSopenharmony_ci            continue;
12800600bfbSopenharmony_ci        }
12900600bfbSopenharmony_ci        CpuInfo cpuInfo;
13000600bfbSopenharmony_ci        StrToInt(cpuId, cpuInfo.id_);
13100600bfbSopenharmony_ci        infos.push_back(cpuInfo);
13200600bfbSopenharmony_ci    }
13300600bfbSopenharmony_ci    return true;
13400600bfbSopenharmony_ci}
13500600bfbSopenharmony_ci
13600600bfbSopenharmony_ciDumpCommonUtils::PidInfo::PidInfo()
13700600bfbSopenharmony_ci{
13800600bfbSopenharmony_ci    Reset();
13900600bfbSopenharmony_ci}
14000600bfbSopenharmony_ci
14100600bfbSopenharmony_civoid DumpCommonUtils::PidInfo::Reset()
14200600bfbSopenharmony_ci{
14300600bfbSopenharmony_ci    pid_ = UNSET;
14400600bfbSopenharmony_ci    uid_ = UNSET;
14500600bfbSopenharmony_ci    gid_ = UNSET;
14600600bfbSopenharmony_ci    ppid_ = UNSET;
14700600bfbSopenharmony_ci    name_.clear();
14800600bfbSopenharmony_ci    cmdline_.clear();
14900600bfbSopenharmony_ci}
15000600bfbSopenharmony_ci
15100600bfbSopenharmony_cibool DumpCommonUtils::GetPidInfos(std::vector<PidInfo> &infos, bool all)
15200600bfbSopenharmony_ci{
15300600bfbSopenharmony_ci    std::vector<std::string> names;
15400600bfbSopenharmony_ci    if (!GetNamesInFolder("/proc/", names)) {
15500600bfbSopenharmony_ci        return false;
15600600bfbSopenharmony_ci    }
15700600bfbSopenharmony_ci    for (size_t i = 0; i < names.size(); i++) {
15800600bfbSopenharmony_ci        std::string name = names[i];
15900600bfbSopenharmony_ci        if (name.empty()) {
16000600bfbSopenharmony_ci            continue;
16100600bfbSopenharmony_ci        }
16200600bfbSopenharmony_ci        if (!IsNumericStr(name)) {
16300600bfbSopenharmony_ci            continue;
16400600bfbSopenharmony_ci        }
16500600bfbSopenharmony_ci        PidInfo pidInfo;
16600600bfbSopenharmony_ci        StrToInt(name, pidInfo.pid_);
16700600bfbSopenharmony_ci        GetProcessInfo(pidInfo.pid_, pidInfo);
16800600bfbSopenharmony_ci        if (all) {
16900600bfbSopenharmony_ci            GetProcessNameByPid(pidInfo.pid_, pidInfo.cmdline_);
17000600bfbSopenharmony_ci        }
17100600bfbSopenharmony_ci        infos.push_back(pidInfo);
17200600bfbSopenharmony_ci    }
17300600bfbSopenharmony_ci    return true;
17400600bfbSopenharmony_ci}
17500600bfbSopenharmony_ci
17600600bfbSopenharmony_cibool DumpCommonUtils::IsUserPid(const std::string &pid)
17700600bfbSopenharmony_ci{
17800600bfbSopenharmony_ci    string path = "/proc/" + pid + "/smaps";
17900600bfbSopenharmony_ci    string lineContent;
18000600bfbSopenharmony_ci    bool ret = FileUtils::GetInstance().LoadStringFromProcCb(path, true, false, [&](const string& line) -> void {
18100600bfbSopenharmony_ci        lineContent += line;
18200600bfbSopenharmony_ci    });
18300600bfbSopenharmony_ci    if (!ret) {
18400600bfbSopenharmony_ci        return false;
18500600bfbSopenharmony_ci    }
18600600bfbSopenharmony_ci    if (!lineContent.empty()) {
18700600bfbSopenharmony_ci        return true;
18800600bfbSopenharmony_ci    }
18900600bfbSopenharmony_ci    return false;
19000600bfbSopenharmony_ci}
19100600bfbSopenharmony_ci
19200600bfbSopenharmony_cibool DumpCommonUtils::GetUserPids(std::vector<int> &pids)
19300600bfbSopenharmony_ci{
19400600bfbSopenharmony_ci    std::vector<std::string> files;
19500600bfbSopenharmony_ci    if (!GetNamesInFolder("/proc/", files)) {
19600600bfbSopenharmony_ci        return false;
19700600bfbSopenharmony_ci    }
19800600bfbSopenharmony_ci
19900600bfbSopenharmony_ci    for (auto file : files) {
20000600bfbSopenharmony_ci        if (file.empty()) {
20100600bfbSopenharmony_ci            continue;
20200600bfbSopenharmony_ci        }
20300600bfbSopenharmony_ci        if (!IsNumericStr(file)) {
20400600bfbSopenharmony_ci            continue;
20500600bfbSopenharmony_ci        }
20600600bfbSopenharmony_ci
20700600bfbSopenharmony_ci        if (!IsUserPid(file)) {
20800600bfbSopenharmony_ci            continue;
20900600bfbSopenharmony_ci        }
21000600bfbSopenharmony_ci
21100600bfbSopenharmony_ci        int pid;
21200600bfbSopenharmony_ci        StrToInt(file, pid);
21300600bfbSopenharmony_ci
21400600bfbSopenharmony_ci        pids.push_back(pid);
21500600bfbSopenharmony_ci    }
21600600bfbSopenharmony_ci    return true;
21700600bfbSopenharmony_ci}
21800600bfbSopenharmony_ci
21900600bfbSopenharmony_cibool DumpCommonUtils::GetLinesInFile(const std::string& file, std::vector<std::string>& lines)
22000600bfbSopenharmony_ci{
22100600bfbSopenharmony_ci    std::string content;
22200600bfbSopenharmony_ci    bool ret = FileUtils::GetInstance().LoadStringFromProcCb(file, false, false, [&](const std::string& line) -> void {
22300600bfbSopenharmony_ci        content += line;
22400600bfbSopenharmony_ci    });
22500600bfbSopenharmony_ci    if (!ret) {
22600600bfbSopenharmony_ci        return false;
22700600bfbSopenharmony_ci    }
22800600bfbSopenharmony_ci    SplitStr(content, "\n", lines);
22900600bfbSopenharmony_ci    return true;
23000600bfbSopenharmony_ci}
23100600bfbSopenharmony_ci
23200600bfbSopenharmony_cibool DumpCommonUtils::GetNamesInFolder(const std::string& folder, std::vector<std::string>& names)
23300600bfbSopenharmony_ci{
23400600bfbSopenharmony_ci    bool ret = false;
23500600bfbSopenharmony_ci    DIR* dir = nullptr;
23600600bfbSopenharmony_ci    if ((dir = opendir(folder.c_str())) != nullptr) {
23700600bfbSopenharmony_ci        dirent* ptr = nullptr;
23800600bfbSopenharmony_ci        while ((ptr = readdir(dir)) != nullptr) {
23900600bfbSopenharmony_ci            std::string name = ptr->d_name;
24000600bfbSopenharmony_ci            if ((name == ".") || (name == "..")) {
24100600bfbSopenharmony_ci                continue;
24200600bfbSopenharmony_ci            }
24300600bfbSopenharmony_ci            names.push_back(name);
24400600bfbSopenharmony_ci        }
24500600bfbSopenharmony_ci        closedir(dir);
24600600bfbSopenharmony_ci        ret = true;
24700600bfbSopenharmony_ci    }
24800600bfbSopenharmony_ci    return ret;
24900600bfbSopenharmony_ci}
25000600bfbSopenharmony_ci
25100600bfbSopenharmony_cibool DumpCommonUtils::StartWith(const std::string& str, const std::string& head)
25200600bfbSopenharmony_ci{
25300600bfbSopenharmony_ci    if (str.length() < head.length()) {
25400600bfbSopenharmony_ci        return false;
25500600bfbSopenharmony_ci    }
25600600bfbSopenharmony_ci    return (str.compare(0, head.size(), head) == 0);
25700600bfbSopenharmony_ci}
25800600bfbSopenharmony_ci
25900600bfbSopenharmony_cibool DumpCommonUtils::GetProcessNameByPid(int pid, std::string& name)
26000600bfbSopenharmony_ci{
26100600bfbSopenharmony_ci    char filesysdir[128] = { 0 };
26200600bfbSopenharmony_ci    if (sprintf_s(filesysdir, sizeof(filesysdir), "/proc/%d/cmdline", pid) < 0) {
26300600bfbSopenharmony_ci        return false;
26400600bfbSopenharmony_ci    }
26500600bfbSopenharmony_ci    std::string filePath = filesysdir;
26600600bfbSopenharmony_ci    std::string content;
26700600bfbSopenharmony_ci    bool ret = FileUtils::GetInstance().LoadStringFromProcCb(filePath, false, false, [&](const string& line) -> void {
26800600bfbSopenharmony_ci        content += line;
26900600bfbSopenharmony_ci    });
27000600bfbSopenharmony_ci    if (!ret) {
27100600bfbSopenharmony_ci        return false;
27200600bfbSopenharmony_ci    }
27300600bfbSopenharmony_ci    vector<string> names;
27400600bfbSopenharmony_ci    StringUtils::GetInstance().StringSplit(content, " ", names);
27500600bfbSopenharmony_ci    if (names.empty()) {
27600600bfbSopenharmony_ci        return false;
27700600bfbSopenharmony_ci    }
27800600bfbSopenharmony_ci    vector<string> longNames;
27900600bfbSopenharmony_ci    StringUtils::GetInstance().StringSplit(names[0], "/", longNames);
28000600bfbSopenharmony_ci    if (longNames.empty()) {
28100600bfbSopenharmony_ci        return false;
28200600bfbSopenharmony_ci    }
28300600bfbSopenharmony_ci    if (names[0].find("/bin") != std::string::npos) {
28400600bfbSopenharmony_ci        name = longNames[longNames.size() - 1];
28500600bfbSopenharmony_ci    } else {
28600600bfbSopenharmony_ci        name = names[0];
28700600bfbSopenharmony_ci    }
28800600bfbSopenharmony_ci    return true;
28900600bfbSopenharmony_ci}
29000600bfbSopenharmony_ci
29100600bfbSopenharmony_cibool DumpCommonUtils::GetProcessInfo(int pid, PidInfo &info)
29200600bfbSopenharmony_ci{
29300600bfbSopenharmony_ci    info.Reset();
29400600bfbSopenharmony_ci    char filesysdir[128] = { 0 };
29500600bfbSopenharmony_ci    if (sprintf_s(filesysdir, sizeof(filesysdir), "/proc/%d/status", pid) < 0) {
29600600bfbSopenharmony_ci        return false;
29700600bfbSopenharmony_ci    }
29800600bfbSopenharmony_ci    std::string file = filesysdir;
29900600bfbSopenharmony_ci    std::vector<std::string> lines;
30000600bfbSopenharmony_ci    if (!GetLinesInFile(file, lines)) {
30100600bfbSopenharmony_ci        return false;
30200600bfbSopenharmony_ci    }
30300600bfbSopenharmony_ci    const std::string splitKeyValueToken = ":";
30400600bfbSopenharmony_ci    const std::string splitValuesToken = "\t";
30500600bfbSopenharmony_ci    for (size_t i = 0; i < lines.size(); i++) {
30600600bfbSopenharmony_ci        std::vector<std::string> keyValue;
30700600bfbSopenharmony_ci        SplitStr(lines[i], splitKeyValueToken, keyValue);
30800600bfbSopenharmony_ci        if (keyValue.size() < LINE_ITEM_MIN) {
30900600bfbSopenharmony_ci            continue;
31000600bfbSopenharmony_ci        }
31100600bfbSopenharmony_ci        std::string key = keyValue[LINE_KEY];
31200600bfbSopenharmony_ci        std::string val = TrimStr(keyValue[LINE_VALUE], '\t');
31300600bfbSopenharmony_ci        std::vector<std::string> values;
31400600bfbSopenharmony_ci        SplitStr(val, splitValuesToken, values, true);
31500600bfbSopenharmony_ci        if (values.empty()) {
31600600bfbSopenharmony_ci            continue;
31700600bfbSopenharmony_ci        }
31800600bfbSopenharmony_ci        std::string val0 = values[LINE_VALUE_0];
31900600bfbSopenharmony_ci        if (key == "Pid") {
32000600bfbSopenharmony_ci            StrToInt(val0, info.pid_);
32100600bfbSopenharmony_ci        } else if (key == "PPid") {
32200600bfbSopenharmony_ci            StrToInt(val0, info.ppid_);
32300600bfbSopenharmony_ci        } else if (key == "Uid") {
32400600bfbSopenharmony_ci            StrToInt(val0, info.uid_);
32500600bfbSopenharmony_ci        } else if (key == "Gid") {
32600600bfbSopenharmony_ci            StrToInt(val0, info.gid_);
32700600bfbSopenharmony_ci        } else if (key == "Name") {
32800600bfbSopenharmony_ci            info.name_ = val;
32900600bfbSopenharmony_ci        } else {
33000600bfbSopenharmony_ci            continue;
33100600bfbSopenharmony_ci        }
33200600bfbSopenharmony_ci        if ((info.pid_ > UNSET) && (info.ppid_ > UNSET) && (info.uid_ > UNSET) && (info.gid_ > UNSET)) {
33300600bfbSopenharmony_ci            return true;
33400600bfbSopenharmony_ci        }
33500600bfbSopenharmony_ci    }
33600600bfbSopenharmony_ci    return false;
33700600bfbSopenharmony_ci}
33800600bfbSopenharmony_ci
33900600bfbSopenharmony_ciint DumpCommonUtils::FindDigitIndex(const std::string& fullFileName)
34000600bfbSopenharmony_ci{
34100600bfbSopenharmony_ci    for (size_t i = 0; i < fullFileName.size(); i++) {
34200600bfbSopenharmony_ci        if (std::isdigit(fullFileName[i])) {
34300600bfbSopenharmony_ci            return i;
34400600bfbSopenharmony_ci        }
34500600bfbSopenharmony_ci    }
34600600bfbSopenharmony_ci    return static_cast<int>(fullFileName.size());
34700600bfbSopenharmony_ci}
34800600bfbSopenharmony_ci} // namespace HiviewDFX
34900600bfbSopenharmony_ci} // namespace OHOS
350