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_ && IsTimeout()) {
97 DUMPER_HILOGE(MODULE_COMMON, "error|cmd timeout");
98 std::vector<std::string> line_vector_timeout;
99 line_vector_timeout.push_back(GetTimeoutStr());
100 dumpDatas_->push_back(line_vector_timeout);
101 moreData_ = false;
102 }
103
104 if (!moreData_) {
105 if (fp_ != nullptr) {
106 pclose(fp_);
107 fp_ = nullptr;
108 }
109 return DumpStatus::DUMP_OK;
110 }
111 return DumpStatus::DUMP_MORE_DATA;
112 }
113
114 // provide interface to others
GetCmdInterface(const std::string & cmd,StringMatrix dumpDatas)115 DumpStatus CMDDumper::GetCmdInterface(const std::string& cmd, StringMatrix dumpDatas)
116 {
117 DumpStatus ret = DumpStatus::DUMP_MORE_DATA;
118 FILE* fp = popen((CMD_PREFIX + cmd).c_str(), "r");
119 if (fp == nullptr) {
120 return DumpStatus::DUMP_FAIL;
121 }
122 do {
123 ret = GetLineData(fp, dumpDatas);
124 } while (ret == DumpStatus::DUMP_MORE_DATA);
125 pclose(fp);
126 return ret;
127 }
128
GetLineData(FILE * fp,StringMatrix dumpDatas)129 DumpStatus CMDDumper::GetLineData(FILE* fp, StringMatrix dumpDatas)
130 {
131 DumpStatus ret = DumpStatus::DUMP_MORE_DATA;
132 char* line_buffer = nullptr;
133 size_t len = 0;
134 ssize_t read = 0;
135 read = getline(&line_buffer, &len, fp);
136 if (read != -1) {
137 if (line_buffer[read - 1] == '\n') {
138 line_buffer[read - 1] = '\0'; // replease \n
139 }
140 std::string line = line_buffer;
141 std::vector<std::string> line_vector;
142 line_vector.push_back(line);
143 dumpDatas->push_back(line_vector);
144 } else {
145 if (feof(fp) == 0) { // ferror()
146 ret = DumpStatus::DUMP_FAIL;
147 } else {
148 ret = DumpStatus::DUMP_OK;
149 }
150 }
151 if (line_buffer != nullptr) {
152 free(line_buffer);
153 line_buffer = nullptr;
154 }
155 return ret;
156 }
157
158 // read one line
ReadLineInCmd()159 DumpStatus CMDDumper::ReadLineInCmd()
160 {
161 if (fp_ == nullptr) {
162 return DumpStatus::DUMP_FAIL;
163 }
164 DumpStatus ret = GetLineData(fp_, dumpDatas_);
165 moreData_ = (ret == DumpStatus::DUMP_MORE_DATA);
166 return ret;
167 }
168
ReplacePidInCmd(std::string & cmd,int pid)169 void CMDDumper::ReplacePidInCmd(std::string &cmd, int pid)
170 {
171 size_t pos = cmd.find("%pid");
172 if (pos != std::string::npos) {
173 cmd = cmd.replace(pos, strlen("%pid"), std::to_string(pid));
174 cmd_ = cmd;
175 }
176 }
177
ReplaceCpuIdInCmd(std::string & cmd,int cpuId)178 void CMDDumper::ReplaceCpuIdInCmd(std::string &cmd, int cpuId)
179 {
180 size_t pos = cmd.find("%cpuid");
181 if (pos != std::string::npos) {
182 cmd = cmd.replace(pos, strlen("%cpuid"), std::to_string(cpuId));
183 cmd_ = cmd;
184 }
185 }
186 } // namespace HiviewDFX
187 } // namespace OHOS
188