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 "process_data_plugin.h"
16
17 #include <sstream>
18
19 #include "buffer_splitter.h"
20 #include "securec.h"
21
22 namespace {
23 constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
24 constexpr int DEC_BASE = 10;
25 } // namespace
26
ProcessDataPlugin()27 ProcessDataPlugin::ProcessDataPlugin()
28 : buffer_(new (std::nothrow) uint8_t[READ_BUFFER_SIZE]), err_(-1)
29 {
30 SetPath(const_cast<char*>("/proc"));
31 }
32
~ProcessDataPlugin()33 ProcessDataPlugin::~ProcessDataPlugin()
34 {
35 HILOG_INFO(LOG_CORE, "%s:~ProcessDataPlugin!", __func__);
36
37 buffer_ = nullptr;
38
39 return;
40 }
41
42
Start(const uint8_t * configData,uint32_t configSize)43 int ProcessDataPlugin::Start(const uint8_t* configData, uint32_t configSize)
44 {
45 if (buffer_ == nullptr) {
46 HILOG_ERROR(LOG_CORE, "%s:buffer_ == null", __func__);
47 return RET_FAIL;
48 }
49
50 if (protoConfig_.ParseFromArray(configData, configSize) <= 0) {
51 HILOG_ERROR(LOG_CORE, "%s:parseFromArray failed!", __func__);
52 return RET_FAIL;
53 }
54
55 HILOG_INFO(LOG_CORE, "%s:start success!", __func__);
56 return RET_SUCC;
57 }
58
ParseNumber(std::string line)59 int ProcessDataPlugin::ParseNumber(std::string line)
60 {
61 return atoi(line.substr(line.find_first_of("01234567890")).c_str());
62 }
63
64
Report(uint8_t * data,uint32_t dataSize)65 int ProcessDataPlugin::Report(uint8_t* data, uint32_t dataSize)
66 {
67 ProcessData dataProto;
68 uint32_t length;
69
70 if (protoConfig_.report_process_tree()) {
71 WriteProcesseList(dataProto);
72 }
73
74 length = dataProto.ByteSizeLong();
75 if (length > dataSize) {
76 return -length;
77 }
78 if (dataProto.SerializeToArray(data, length) > 0) {
79 return length;
80 }
81 return 0;
82 }
83
Stop()84 int ProcessDataPlugin::Stop()
85 {
86 HILOG_INFO(LOG_CORE, "%s:stop success!", __func__);
87 return 0;
88 }
89
90
ReadFile(int fd)91 int32_t ProcessDataPlugin::ReadFile(int fd)
92 {
93 if ((buffer_.get() == nullptr) || (fd == -1)) {
94 return RET_FAIL;
95 }
96 int readsize = pread(fd, buffer_.get(), READ_BUFFER_SIZE - 1, 0);
97 if (readsize <= 0) {
98 HILOG_ERROR(LOG_CORE, "%s:failed to read(%d), errno=%d", __func__, fd, errno);
99 err_ = errno;
100 return RET_FAIL;
101 }
102 return readsize;
103 }
104
OpenDestDir(const char * dirPath)105 DIR* ProcessDataPlugin::OpenDestDir(const char* dirPath)
106 {
107 DIR* destDir = nullptr;
108
109 destDir = opendir(dirPath);
110 if (destDir == nullptr) {
111 HILOG_ERROR(LOG_CORE, "%s:failed to opendir(%s), errno=%d", __func__, dirPath, errno);
112 }
113
114 return destDir;
115 }
116
GetValidPid(DIR * dirp)117 int32_t ProcessDataPlugin::GetValidPid(DIR* dirp)
118 {
119 if (!dirp) return 0;
120 while (struct dirent* dirEnt = readdir(dirp)) {
121 if (dirEnt->d_type != DT_DIR) {
122 continue;
123 }
124
125 int32_t pid = atoi(dirEnt->d_name);
126 if (pid) {
127 return pid;
128 }
129 }
130 return 0;
131 }
132
ReadProcPidFile(int32_t pid,const char * pFileName)133 int32_t ProcessDataPlugin::ReadProcPidFile(int32_t pid, const char* pFileName)
134 {
135 char fileName[PATH_MAX + 1] = {0};
136 char realPath[PATH_MAX + 1] = {0};
137 int fd = -1;
138 ssize_t bytesRead = 0;
139
140 if (snprintf_s(fileName, sizeof(fileName), sizeof(fileName) - 1, "%s/%d/%s", testpath_, pid, pFileName) < 0) {
141 HILOG_ERROR(LOG_CORE, "%s:snprintf_s error", __func__);
142 }
143 if (realpath(fileName, realPath) == nullptr) {
144 HILOG_ERROR(LOG_CORE, "%s:realpath failed, errno=%d", __func__, errno);
145 return RET_FAIL;
146 }
147 fd = open(realPath, O_RDONLY | O_CLOEXEC);
148 if (fd == -1) {
149 HILOG_INFO(LOG_CORE, "%s:failed to open(%s), errno=%d", __func__, fileName, errno);
150 err_ = errno;
151 return RET_FAIL;
152 }
153 if (buffer_.get() == nullptr) {
154 HILOG_INFO(LOG_CORE, "%s:empty address, buffer_ is NULL", __func__);
155 err_ = RET_NULL_ADDR;
156 close(fd);
157 return RET_FAIL;
158 }
159 bytesRead = read(fd, buffer_.get(), READ_BUFFER_SIZE - 1);
160 if (bytesRead <= 0) {
161 close(fd);
162 HILOG_INFO(LOG_CORE, "%s:failed to read(%s), errno=%d", __func__, fileName, errno);
163 err_ = errno;
164 return RET_FAIL;
165 }
166 buffer_.get()[bytesRead] = '\0';
167 close(fd);
168
169 return bytesRead;
170 }
171
BufnCmp(const char * src,int srcLen,const char * key,int keyLen)172 bool ProcessDataPlugin::BufnCmp(const char* src, int srcLen, const char* key, int keyLen)
173 {
174 if (!src || !key || (srcLen < keyLen)) {
175 return false;
176 }
177 for (int i = 0; i < keyLen; i++) {
178 if (*src++ != *key++) {
179 return false;
180 }
181 }
182 return true;
183 }
184
addPidBySort(int32_t pid)185 bool ProcessDataPlugin::addPidBySort(int32_t pid)
186 {
187 auto pidsEnd = seenPids_.end();
188 auto it = std::lower_bound(seenPids_.begin(), pidsEnd, pid);
189 if (it != pidsEnd && *it == pid) {
190 return false;
191 }
192 it = seenPids_.insert(it, std::move(pid));
193 return true;
194 }
195
WriteProcess(ProcessInfo * processinfo,const char * pFile,uint32_t fileLen,int32_t pid)196 void ProcessDataPlugin::WriteProcess(ProcessInfo* processinfo, const char* pFile, uint32_t fileLen, int32_t pid)
197 {
198 BufferSplitter totalbuffer(const_cast<const char*>(pFile), fileLen + 1);
199
200 do {
201 totalbuffer.NextWord(':');
202 if (!totalbuffer.CurWord()) {
203 return;
204 }
205
206 if (BufnCmp(totalbuffer.CurWord(), totalbuffer.CurWordSize(), "Name", strlen("Name"))) {
207 totalbuffer.NextWord('\n');
208 if (!totalbuffer.CurWord()) {
209 return;
210 }
211 processinfo->set_name(totalbuffer.CurWord(), totalbuffer.CurWordSize());
212 } else if (BufnCmp(totalbuffer.CurWord(), totalbuffer.CurWordSize(), "Tgid", strlen("Tgid"))) {
213 totalbuffer.NextWord('\n');
214 if (!totalbuffer.CurWord()) {
215 return;
216 }
217 char* end = nullptr;
218 int32_t value = static_cast<int32_t>(strtoul(totalbuffer.CurWord(), &end, DEC_BASE));
219 if (value <= 0) {
220 HILOG_ERROR(LOG_CORE, "%s:strtoull value failed", __func__);
221 }
222 processinfo->set_pid(value);
223 break;
224 }
225
226 totalbuffer.NextWord('\n');
227 if (!totalbuffer.CurWord()) {
228 continue;
229 }
230 } while (totalbuffer.NextLine());
231 // update process name
232 int32_t ret = ReadProcPidFile(pid, "cmdline");
233 if (ret > 0) {
234 processinfo->set_name(reinterpret_cast<char*>(buffer_.get()), strlen(reinterpret_cast<char*>(buffer_.get())));
235 }
236 }
237
SetEmptyProcessInfo(ProcessInfo * processinfo)238 void ProcessDataPlugin::SetEmptyProcessInfo(ProcessInfo* processinfo)
239 {
240 processinfo->set_pid(-1);
241 processinfo->set_name("null");
242 }
243
WriteProcessInfo(ProcessData & data,int32_t pid)244 void ProcessDataPlugin::WriteProcessInfo(ProcessData& data, int32_t pid)
245 {
246 int32_t ret = ReadProcPidFile(pid, "status");
247 if (ret == RET_FAIL) {
248 SetEmptyProcessInfo(data.add_processesinfo());
249 return;
250 }
251 if ((buffer_.get() == nullptr) || (ret == 0)) {
252 return;
253 }
254 auto* processinfo = data.add_processesinfo();
255 WriteProcess(processinfo, (char*)buffer_.get(), ret, pid);
256 }
257
WriteProcesseList(ProcessData & data)258 void ProcessDataPlugin::WriteProcesseList(ProcessData& data)
259 {
260 DIR* procDir = nullptr;
261
262 procDir = OpenDestDir(testpath_);
263 if (procDir == nullptr) {
264 return;
265 }
266
267 seenPids_.clear();
268 while (int32_t pid = GetValidPid(procDir)) {
269 addPidBySort(pid);
270 }
271
272 for (unsigned int i = 0; i < seenPids_.size(); i++) {
273 WriteProcessInfo(data, seenPids_[i]);
274 }
275 closedir(procDir);
276 }
277