• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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