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 #include "executor/cmd_dumper.h"
16
17 #include "dump_common_utils.h"
18 #include "securec.h"
19
20 namespace OHOS {
21 namespace HiviewDFX {
22 const std::string CMD_PREFIX = "/system/bin/";
CMDDumper()23 CMDDumper::CMDDumper() : fp_(nullptr)
24 {
25 }
26
~CMDDumper()27 CMDDumper::~CMDDumper()
28 {
29 if (fp_ != nullptr) {
30 pclose(fp_);
31 fp_ = nullptr;
32 }
33 }
34
PreExecute(const std::shared_ptr<DumperParameter>& parameter, StringMatrix dumpDatas)35 DumpStatus CMDDumper::PreExecute(const std::shared_ptr<DumperParameter>& parameter,
36 StringMatrix dumpDatas)
37 {
38 if (dumpDatas.get() == nullptr) {
39 return DumpStatus::DUMP_FAIL;
40 }
41 std::string cmd = ptrDumpCfg_->target_;
42 if (ptrDumpCfg_->args_ != nullptr) {
43 if (ptrDumpCfg_->args_->HasPid()) {
44 int pid = ptrDumpCfg_->args_->GetPid();
45 if (ptrDumpCfg_->name_ == "dumper_stack" && !DumpCommonUtils::IsUserPid(std::to_string(pid))) {
46 return DumpStatus::DUMP_FAIL;
47 }
48 ReplacePidInCmd(cmd, pid);
49 }
50 if (ptrDumpCfg_->args_->HasCpuId()) {
51 int cpuId = ptrDumpCfg_->args_->GetCpuId();
52 ReplaceCpuIdInCmd(cmd, cpuId);
53 }
54 }
55 cmd_ = cmd;
56 needLoop_ = (ptrDumpCfg_->loop_ == DumperConstant::LOOP);
57 if (fp_ == nullptr) {
58 if ((fp_ = popen((CMD_PREFIX + cmd_).c_str(), "r")) == nullptr) {
59 return DumpStatus::DUMP_FAIL;
60 }
61 }
62 dumpDatas_ = dumpDatas;
63
64 // Add only once!
65 if (lineData_.size() <= 0) {
66 std::string lineStr = "\ncmd is: ";
67 lineStr = lineStr + cmd_ + "\n\n";
68 lineData_.push_back(lineStr);
69 dumpDatas_->push_back(lineData_);
70 }
71 return DumpStatus::DUMP_OK;
72 }
73
Execute()74 DumpStatus CMDDumper::Execute()
75 {
76 DUMPER_HILOGI(MODULE_COMMON, "info|CMDDumper Execute");
77 DumpStatus ret = DumpStatus::DUMP_OK;
78 if (needLoop_) {
79 // cmd dump one line
80 return ReadLineInCmd();
81 } else {
82 // cmd dump all line
83 do {
84 if (IsCanceled()) {
85 break;
86 }
87 ret = ReadLineInCmd();
88 } while (ret == DumpStatus::DUMP_MORE_DATA);
89 }
90 DUMPER_HILOGI(MODULE_COMMON, "info|CMDDumper Execute end");
91 return ret;
92 }
93
AfterExecute()94 DumpStatus CMDDumper::AfterExecute()
95 {
96 if (!moreData_) {
97 if (fp_ != nullptr) {
98 pclose(fp_);
99 fp_ = nullptr;
100 }
101 return DumpStatus::DUMP_OK;
102 }
103 return DumpStatus::DUMP_MORE_DATA;
104 }
105
106 // provide interface to others
GetCmdInterface(const std::string& cmd, StringMatrix dumpDatas)107 DumpStatus CMDDumper::GetCmdInterface(const std::string& cmd, StringMatrix dumpDatas)
108 {
109 DumpStatus ret = DumpStatus::DUMP_MORE_DATA;
110 FILE* fp = popen((CMD_PREFIX + cmd).c_str(), "r");
111 if (fp == nullptr) {
112 return DumpStatus::DUMP_FAIL;
113 }
114 do {
115 ret = GetLineData(fp, dumpDatas);
116 } while (ret == DumpStatus::DUMP_MORE_DATA);
117 pclose(fp);
118 return ret;
119 }
120
GetLineData(FILE* fp, StringMatrix dumpDatas)121 DumpStatus CMDDumper::GetLineData(FILE* fp, StringMatrix dumpDatas)
122 {
123 DumpStatus ret = DumpStatus::DUMP_MORE_DATA;
124 char* line_buffer = nullptr;
125 size_t len = 0;
126 ssize_t read = 0;
127 read = getline(&line_buffer, &len, fp);
128 if (read != -1) {
129 if (line_buffer[read - 1] == '\n') {
130 line_buffer[read - 1] = '\0'; // replease \n
131 }
132 std::string line = line_buffer;
133 std::vector<std::string> line_vector;
134 line_vector.push_back(line);
135 dumpDatas->push_back(line_vector);
136 } else {
137 if (feof(fp) == 0) { // ferror()
138 ret = DumpStatus::DUMP_FAIL;
139 } else {
140 ret = DumpStatus::DUMP_OK;
141 }
142 }
143 if (line_buffer != nullptr) {
144 free(line_buffer);
145 line_buffer = nullptr;
146 }
147 return ret;
148 }
149
150 // read one line
ReadLineInCmd()151 DumpStatus CMDDumper::ReadLineInCmd()
152 {
153 if (fp_ == nullptr) {
154 return DumpStatus::DUMP_FAIL;
155 }
156 DumpStatus ret = GetLineData(fp_, dumpDatas_);
157 moreData_ = (ret == DumpStatus::DUMP_MORE_DATA);
158 return ret;
159 }
160
ReplacePidInCmd(std::string &cmd, int pid)161 void CMDDumper::ReplacePidInCmd(std::string &cmd, int pid)
162 {
163 size_t pos = cmd.find("%pid");
164 if (pos != std::string::npos) {
165 cmd = cmd.replace(pos, strlen("%pid"), std::to_string(pid));
166 cmd_ = cmd;
167 }
168 }
169
ReplaceCpuIdInCmd(std::string &cmd, int cpuId)170 void CMDDumper::ReplaceCpuIdInCmd(std::string &cmd, int cpuId)
171 {
172 size_t pos = cmd.find("%cpuid");
173 if (pos != std::string::npos) {
174 cmd = cmd.replace(pos, strlen("%cpuid"), std::to_string(cpuId));
175 cmd_ = cmd;
176 }
177 }
178 } // namespace HiviewDFX
179 } // namespace OHOS
180