1 /*
2 * Copyright (c) 2022 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 "hisysevent_plugin.h"
16
17 #include <fcntl.h>
18 #include <cinttypes>
19 #include <csignal>
20 #include <sstream>
21 #include <cstdio>
22 #include <sys/syscall.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26
27 namespace {
28 constexpr int PIPE_LEN = 2;
29
30 constexpr int READ = 0;
31 constexpr int WRITE = 1;
32 static pid_t volatile g_child;
33
34 constexpr int MAX_STRING_LEN = 256 * 1024;
35 constexpr int MIN_STRING_LEN = 10;
36 constexpr int BYTE_BUFFER_SIZE = 1024;
37
38 std::atomic<uint64_t> g_id(1);
39 }
40
HisyseventPlugin()41 HisyseventPlugin::HisyseventPlugin():fp_(nullptr, nullptr) {}
42
~HisyseventPlugin()43 HisyseventPlugin::~HisyseventPlugin()
44 {
45 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
46 std::unique_lock<std::mutex> locker(mutex_);
47
48 if (running_) {
49 running_ = false;
50 if (workThread_.joinable()) {
51 workThread_.join();
52 }
53 }
54
55 locker.unlock();
56
57 if (fp_ != nullptr) {
58 fp_.reset();
59 }
60
61 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
62 }
63
SetWriter(WriterStruct * writer)64 int HisyseventPlugin::SetWriter(WriterStruct* writer)
65 {
66 resultWriter_ = writer;
67
68 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
69 return 0;
70 }
71
Start(const uint8_t * configData,uint32_t configSize)72 int HisyseventPlugin::Start(const uint8_t* configData, uint32_t configSize)
73 {
74 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
75 if (configData == nullptr || configSize <= 0) {
76 HILOG_ERROR(LOG_CORE, "NOTE %s: param invalid", __func__);
77 return -1;
78 }
79
80 if (protoConfig_.ParseFromArray(configData, configSize) <= 0) {
81 HILOG_ERROR(LOG_CORE, "NOTE HisyseventPlugin: ParseFromArray failed");
82 return -1;
83 }
84
85 HILOG_DEBUG(LOG_CORE, "NOTE configData ParseFromArray sucessed,sourse data:%s", protoConfig_.msg().c_str());
86
87 if (!InitHisyseventCmd()) {
88 HILOG_ERROR(LOG_CORE, "TODO HisyseventPlugin: Init HisyseventCmd failed");
89 return -1;
90 }
91
92 fp_ = std::unique_ptr<FILE, int (*)(FILE*)>(CustomPopen(&fullCmd_[0], "r"), CustomPclose);
93 CHECK_NOTNULL(fp_.get(), -1, "HisyseventPlugin: fullCmd_ Failed, errno(%d)", errno);
94 CHECK_NOTNULL(resultWriter_, -1, "HisyseventPlugin: Writer is no set!!");
95 CHECK_NOTNULL(resultWriter_->write, -1, "HisyseventPlugin: Writer.write is no set!!");
96 CHECK_NOTNULL(resultWriter_->flush, -1, "HisyseventPlugin: Writer.flush is no set!!");
97
98 g_id = 1;
99 std::unique_lock<std::mutex> locker(mutex_);
100 running_ = true;
101 workThread_ = std::thread(&HisyseventPlugin::Run, this);
102
103 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
104 return 0;
105 }
106
Stop()107 int HisyseventPlugin::Stop()
108 {
109 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
110 std::unique_lock<std::mutex> locker(mutex_);
111 running_ = false;
112 locker.unlock();
113 if (workThread_.joinable()) {
114 workThread_.join();
115 }
116 HILOG_INFO(LOG_CORE, "HisyseventPlugin: stop thread success!");
117
118 fp_.reset();
119
120 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
121 return 0;
122 }
123
Run(void)124 void HisyseventPlugin::Run(void)
125 {
126 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
127 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(MAX_STRING_LEN);
128
129 if (buffer == nullptr) {
130 return;
131 }
132
133 HILOG_DEBUG(LOG_CORE, "NOTE hisysevent_plugin_result.proto->HisyseventInfo:dataProto;Ready to output the result!");
134 HisyseventInfo dataProto;
135 fcntl(fileno(fp_.get()), F_SETFL, O_NONBLOCK);
136
137 while (running_) {
138 if (fgets(reinterpret_cast<char*>(buffer.get()), MAX_STRING_LEN, fp_.get()) != nullptr) {
139 auto cptr = reinterpret_cast<char*>(buffer.get());
140 if (!ParseSyseventLineInfo(cptr, strlen(cptr), dataProto))
141 continue;
142 }
143
144 if (dataProto.ByteSizeLong() >= BYTE_BUFFER_SIZE) {
145 // Cmd result resize and SerializeToArray and after save to protoBuffer_ ;write and flush;clear_info
146 protoBuffer_.resize(dataProto.ByteSizeLong());
147 dataProto.SerializeToArray(protoBuffer_.data(), protoBuffer_.size());
148
149 // SerializeToArray after data=%s",protoBuffer_.data()
150 resultWriter_->write(resultWriter_, protoBuffer_.data(), protoBuffer_.size());
151 resultWriter_->flush(resultWriter_);
152 dataProto.clear_info();
153 }
154 }
155
156 protoBuffer_.resize(dataProto.ByteSizeLong());
157 dataProto.SerializeToArray(protoBuffer_.data(), protoBuffer_.size());
158 resultWriter_->write(resultWriter_, protoBuffer_.data(), protoBuffer_.size());
159 resultWriter_->flush(resultWriter_);
160 dataProto.clear_info();
161
162 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
163 }
164
ParseSyseventLineInfo(const char * data,size_t len,HisyseventInfo & dataProto)165 inline bool HisyseventPlugin::ParseSyseventLineInfo(const char* data, size_t len, HisyseventInfo& dataProto)
166 {
167 if (data == nullptr || len < MIN_STRING_LEN) {
168 HILOG_ERROR(LOG_CORE, "NOTE %s: param invalid", __func__);
169 return false;
170 }
171
172 if (google::protobuf::internal::IsStructurallyValidUTF8(data, strlen(data) - 1)) {
173 auto* info = dataProto.add_info();
174 info->set_id(g_id);
175 info->set_context(data, strlen(data) - 1); // - \n
176 g_id++;
177 } else {
178 HILOG_ERROR(LOG_CORE, "NOTE HisyseventPlugin: hisysevent context include invalid UTF-8 data");
179 return false;
180 }
181
182 return true;
183 }
184
InitHisyseventCmd()185 inline bool HisyseventPlugin::InitHisyseventCmd()
186 {
187 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
188 if (fullCmd_.size() > 0) {
189 HILOG_INFO(LOG_CORE, "fullCmd_ is dirty.Clear().");
190 fullCmd_.clear();
191 }
192
193 fullCmd_.push_back(const_cast<char *>("hisysevent"));
194 fullCmd_.push_back(const_cast<char *>("-rd"));
195 fullCmd_.push_back(nullptr);
196
197 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
198 return true;
199 }
200
GetCmdline()201 std::string HisyseventPlugin::GetCmdline()
202 {
203 std::string cmdline;
204 for (size_t i = 0; i < fullCmd_.size() - 1 ; i++)
205 cmdline.append(fullCmd_[i]).append(" ");
206
207 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
208 return cmdline;
209 }
210
CustomPopen(char * const command[],const char * type)211 FILE* HisyseventPlugin::CustomPopen(char* const command[], const char* type)
212 {
213 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
214 if (command == nullptr || type == nullptr) {
215 HILOG_ERROR(LOG_CORE, "HisyseventPlugin:%s param invalid", __func__);
216 return nullptr;
217 }
218
219 int fd[PIPE_LEN];
220 pipe(fd);
221
222 pid_t pid = fork();
223 if (pid == -1) {
224 perror("fork");
225 exit(1);
226 }
227
228 if (pid == 0) {
229 if (!strncmp(type, "r", strlen(type))) {
230 close(fd[READ]);
231 dup2(fd[WRITE], 1); // Redirect stdout to pipe
232 dup2(fd[WRITE], 2); // 2: Redirect stderr to pipe
233 } else {
234 close(fd[WRITE]);
235 dup2(fd[READ], 0); // Redirect stdin to pipe
236 }
237 setpgid(pid, pid);
238 execvp("hisysevent", &command[0]);
239 exit(0);
240 } else {
241 if (!strncmp(type, "r", strlen(type))) {
242 // Close the WRITE end of the pipe since parent's fd is read-only
243 close(fd[WRITE]);
244 } else {
245 // Close the READ end of the pipe since parent's fd is write-only
246 close(fd[READ]);
247 }
248 }
249
250 g_child = pid;
251
252 if (!strncmp(type, "r", strlen(type))) {
253 return fdopen(fd[READ], "r");
254 }
255
256 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
257 return fdopen(fd[WRITE], "w");
258 }
259
CustomPclose(FILE * fp)260 int HisyseventPlugin::CustomPclose(FILE* fp)
261 {
262 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
263 CHECK_NOTNULL(fp, -1, "NOTE %s: fp is null", __func__);
264
265 int stat = 0;
266 int ret = fclose(fp);
267 CHECK_TRUE(ret == 0, -1, "NOTE %s: fclose failed! errno(%d)", __func__, errno);
268 kill(g_child, SIGKILL);
269 if (waitpid(g_child, &stat, 0) == -1) {
270 if (errno != EINTR) {
271 return stat;
272 }
273 }
274
275 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
276 return stat;
277 }
278