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/file_stream_dumper.h"
16 #include <dirent.h>
17 #include <unistd.h>
18 #include "dump_utils.h"
19
20 namespace OHOS {
21 namespace HiviewDFX {
FileStreamDumper()22 FileStreamDumper::FileStreamDumper()
23 :fp_(nullptr),
24 fd_(-1),
25 next_file_index_(0),
26 more_data_(false),
27 need_loop_(false)
28 {
29 }
30
~FileStreamDumper()31 FileStreamDumper::~FileStreamDumper()
32 {
33 CloseFd();
34 }
35
PreExecute(const std::shared_ptr<DumperParameter> & parameter,StringMatrix dumpDatas)36 DumpStatus FileStreamDumper::PreExecute(const std::shared_ptr<DumperParameter>& parameter,
37 StringMatrix dumpDatas)
38 {
39 if (dumpDatas.get()) {
40 result_ = dumpDatas;
41 }
42
43 // open first file!
44 if (next_file_index_ <= 0) {
45 std::string target = ptrDumpCfg_->target_;
46 bool arg_pid = false;
47 bool arg_cpuid = false;
48 int pid = 0;
49 int cpuid = 0;
50 if (ptrDumpCfg_->args_.get()) {
51 arg_pid = ptrDumpCfg_->args_->HasPid();
52 arg_cpuid = ptrDumpCfg_->args_->HasCpuId();
53 pid = ptrDumpCfg_->args_->GetPid();
54 cpuid = ptrDumpCfg_->args_->GetCpuId();
55 }
56 BuildFileNames(target, arg_pid, pid, arg_cpuid, cpuid);
57 need_loop_ = (ptrDumpCfg_->loop_ == DumperConstant::LOOP);
58
59 int ret = OpenNextFile();
60 if (ret <= 0) {
61 return DumpStatus::DUMP_FAIL;
62 }
63 }
64
65 return DumpStatus::DUMP_OK;
66 }
67
OpenNextFile()68 int FileStreamDumper::OpenNextFile()
69 {
70 // Close current file.
71 CloseFd();
72 if (next_file_index_ >= filenames_.size()) {
73 // no more files
74 return 0;
75 }
76 // Next file
77 std::string filename = filenames_[next_file_index_];
78 // Open fd and fp
79 if ((fd_ = DumpUtils::FdToRead(filename)) == -1) {
80 return -1;
81 }
82 if ((fp_ = fdopen(fd_, "r")) == nullptr) {
83 close(fd_);
84 fd_ = -1;
85 return -1;
86 }
87 next_file_index_ ++;
88 // add file name into buffer
89 std::vector<std::string> line_vector_blank;
90 line_vector_blank.push_back("");
91 std::vector<std::string> line_vector_filename;
92 line_vector_filename.push_back(filename);
93 result_->push_back(line_vector_blank);
94 result_->push_back(line_vector_filename);
95 result_->push_back(line_vector_blank);
96 return next_file_index_;
97 }
98
99 // read one line
ReadLineInFile()100 DumpStatus FileStreamDumper::ReadLineInFile()
101 {
102 DumpStatus ret = DumpStatus::DUMP_MORE_DATA;
103 if (fp_ == nullptr) {
104 return DumpStatus::DUMP_FAIL;
105 }
106 char* line_buffer = nullptr;
107 size_t len = 0;
108 ssize_t read = 0;
109 read = getline(&line_buffer, &len, fp_);
110 if (read != -1) {
111 if (line_buffer[read-1] == '\n') {
112 line_buffer[read-1] = '\0'; // replease \n
113 }
114 std::string line = line_buffer;
115 std::vector<std::string> line_vector;
116 line_vector.push_back(line);
117 result_->push_back(line_vector);
118 } else {
119 if (feof(fp_) == 0) { // ferror()
120 ret = DumpStatus::DUMP_FAIL;
121 }
122 }
123 // end of file
124 if (feof(fp_) != 0) {
125 int more_file = OpenNextFile();
126 if (more_file > 0) {
127 ret = DumpStatus::DUMP_MORE_DATA;
128 } else if (more_file == 0) {
129 ret = DumpStatus::DUMP_OK;
130 } else { // Error!
131 ret = DumpStatus::DUMP_FAIL;
132 }
133 }
134 if (line_buffer != nullptr) {
135 free(line_buffer);
136 line_buffer = nullptr;
137 }
138 more_data_ = (ret == DumpStatus::DUMP_MORE_DATA);
139 return ret;
140 }
141
Execute()142 DumpStatus FileStreamDumper::Execute()
143 {
144 DumpStatus ret = DumpStatus::DUMP_OK;
145 if (need_loop_) {
146 // file dump one line
147 return ReadLineInFile();
148 } else {
149 // file dump all line
150 do {
151 if (IsCanceled()) {
152 break;
153 }
154 ret = ReadLineInFile();
155 } while (ret == DumpStatus::DUMP_MORE_DATA);
156 }
157 return ret;
158 }
159
AfterExecute()160 DumpStatus FileStreamDumper::AfterExecute()
161 {
162 if (more_data_ && IsTimeout()) {
163 DUMPER_HILOGE(MODULE_COMMON, "error|file timeout");
164 std::vector<std::string> line_vector_timeout;
165 line_vector_timeout.push_back(GetTimeoutStr());
166 result_->push_back(line_vector_timeout);
167 more_data_ = false;
168 }
169
170 if (!more_data_) {
171 CloseFd();
172 return DumpStatus::DUMP_OK;
173 }
174 return DumpStatus::DUMP_MORE_DATA;
175 }
176
BuildFileNames(const std::string & target,bool arg_pid,int pid,bool arg_cpuid,int cpuid)177 void FileStreamDumper::BuildFileNames(const std::string& target, bool arg_pid, int pid,
178 bool arg_cpuid, int cpuid)
179 {
180 DIR* dir = opendir(target.c_str());
181 if (dir != nullptr) {
182 std::string dir_name = target;
183 // add backslash at tail of target
184 std::string backslash = "/";
185 if (dir_name.compare(dir_name.size() - backslash.size(), backslash.size(), backslash) != 0) {
186 dir_name.append(backslash);
187 }
188 dirent* ptr = nullptr;
189 while ((ptr = readdir(dir)) != nullptr) {
190 std::string d_name = ptr->d_name;
191 if ((d_name == ".") || (d_name == "..")) {
192 continue;
193 }
194 std::string filename = dir_name + d_name;
195
196 if (arg_pid) {
197 ReplacePidInFilename(filename, pid);
198 }
199 if (arg_cpuid) {
200 ReplaceCpuidInFilename(filename, cpuid);
201 }
202 filenames_.push_back(filename);
203 }
204 closedir(dir);
205 } else {
206 std::string filename = target;
207 if (arg_pid) {
208 ReplacePidInFilename(filename, pid);
209 }
210 if (arg_cpuid) {
211 ReplaceCpuidInFilename(filename, cpuid);
212 }
213 filenames_.push_back(filename);
214 }
215 }
216
ReplacePidInFilename(std::string & filename,int pid)217 void FileStreamDumper::ReplacePidInFilename(std::string& filename, int pid)
218 {
219 // replease %pid in filename
220 size_t pos = filename.find("%pid");
221 if (pos != std::string::npos) {
222 filename = filename.replace(pos, strlen("%pid"), std::to_string(pid));
223 }
224 }
225
ReplaceCpuidInFilename(std::string & filename,int cpuid)226 void FileStreamDumper::ReplaceCpuidInFilename(std::string& filename, int cpuid)
227 {
228 // replease %cpuid in filename
229 size_t pos = filename.find("%cpuid");
230 if (pos != std::string::npos) {
231 filename = filename.replace(pos, strlen("%cpuid"), std::to_string(cpuid));
232 }
233 }
234
CloseFd()235 void FileStreamDumper::CloseFd()
236 {
237 if (fp_ != nullptr) {
238 fclose(fp_);
239 fp_ = nullptr;
240 }
241 if (fd_ >= 0) {
242 close(fd_);
243 fd_ = -1;
244 }
245 };
246 } // namespace HiviewDFX
247 } // namespace OHOS
248