• 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 "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