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