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 "include/GetLog.h"
16 #include "include/sp_utils.h"
17 #include "include/smartperf_command.h"
18 #include <netinet/in.h>
19 #include <sys/socket.h>
20 #include <arpa/inet.h>
21 #include <unistd.h>
22 #include <fstream>
23 #include <filesystem>
24 #include <vector>
25 #include <chrono>
26 #include <ctime>
27 namespace OHOS {
28 namespace SmartPerf {
CreateDir(const std::string & dirPath)29 void GetLog::CreateDir(const std::string &dirPath)
30 {
31 if (!SPUtils::FileAccess(dirPath)) {
32 std::string cmd = CMD_COMMAND_MAP.at(CmdCommand::CREAT_DIR) + dirPath;
33 std::string cmdResult;
34 if (!SPUtils::LoadCmd(cmd, cmdResult)) {
35 WLOGE("%s capture not be created!", dirPath.c_str());
36 } else {
37 WLOGI("%s created successfully!", dirPath.c_str());
38 }
39 }
40 }
41
RemoveDirOrFile(const std::string & dirPath)42 void GetLog::RemoveDirOrFile(const std::string &dirPath)
43 {
44 char pathChar[PATH_MAX] = {0x00};
45 if ((realpath(dirPath.c_str(), pathChar) == nullptr)) {
46 WLOGI("%s is not exist.", dirPath.c_str());
47 return;
48 }
49 LOGD("%s is exist, remove...", dirPath.c_str());
50
51 std::string cmd = CMD_COMMAND_MAP.at(CmdCommand::REMOVE) + dirPath;
52 std::string cmdResult;
53 if (!SPUtils::LoadCmd(cmd, cmdResult)) {
54 WLOGE("%s capture not be removed!", dirPath.c_str());
55 } else {
56 WLOGI("%s removed successfully!", dirPath.c_str());
57 }
58 }
59
CopyFiles(std::string cpStr)60 void GetLog::CopyFiles(std::string cpStr)
61 {
62 std::string cmd = CMD_COMMAND_MAP.at(CmdCommand::CP) + cpStr;
63 std::string cmdResult;
64 if (!SPUtils::LoadCmd(cmd, cmdResult)) {
65 WLOGE("Failed to copy files: %s", cpStr.c_str());
66 }
67 }
68
TarFiles(std::string tarStr)69 void GetLog::TarFiles(std::string tarStr)
70 {
71 std::string tarCommand = CMD_COMMAND_MAP.at(CmdCommand::TAR) + tarStr;
72 std::string cmdResult;
73 if (!SPUtils::LoadCmd(tarCommand, cmdResult)) {
74 WLOGE("Failed to tar log files");
75 }
76 }
77
GetHilogInMemory(std::vector<std::filesystem::path> & fileList)78 void GetLog::GetHilogInMemory(std::vector<std::filesystem::path> &fileList)
79 {
80 // Get current hilog in "hilog" command
81 std::string hilogTmp = hilogFileDir + "hilogTmp";
82 std::string cmd = CMD_COMMAND_MAP.at(CmdCommand::GET_HILOG) + hilogTmp;
83 std::string cmdResult;
84 if (!SPUtils::LoadCmd(cmd, cmdResult)) {
85 WLOGE("Failed to GetHilogCommand files: %s", hilogTmp.c_str());
86 }
87 if (std::filesystem::exists(hilogTmp)) {
88 currentLogSize += std::filesystem::file_size(hilogTmp);
89 fileList.push_back(hilogTmp);
90 }
91 }
92
RemoveLogFile()93 void GetLog::RemoveLogFile()
94 {
95 // Process before and after send
96 RemoveDirOrFile(logFilePath);
97 RemoveDirOrFile(hilogFileDir);
98 RemoveDirOrFile(daemonLogFileDir);
99
100 currentLogSize = 0;
101 }
102
GenerateDaemonLogFile()103 void GetLog::GenerateDaemonLogFile()
104 {
105 const std::string preLogFileName = "log.";
106 std::filesystem::path dirPath(LOG_FILE_DIR); // Log file directory
107 std::vector<std::filesystem::path> files; // Log file vector to tar
108
109 CreateDir(daemonLogFileDir); // Create daemonLog directory
110
111 // Save current working directory to restore it later
112 // Change directory to handle relative paths in tar operations
113 std::string originPath;
114 if (std::filesystem::current_path().string().empty()) {
115 WLOGE("Failed to get current working directory");
116 return;
117 }
118 originPath = std::filesystem::current_path().string();
119 std::filesystem::current_path(LOG_FILE_DIR);
120
121 // Get all log files in LOG_FILE_DIR
122 for (const auto& entry : std::filesystem::directory_iterator(dirPath)) {
123 if (std::filesystem::is_regular_file(entry)) {
124 if (entry.path().filename().string().substr(0, preLogFileName.length()) != preLogFileName) {
125 continue; // Skip files that don't start with "log."
126 }
127 files.push_back(entry.path());
128 }
129 }
130
131 // Sort log files by last write time
132 std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) {
133 return std::filesystem::last_write_time(a) > std::filesystem::last_write_time(b);
134 });
135
136 // Build tar command with relative paths only, respecting size limit
137 std::string cpCommand = "";
138 for (const auto& file : files) {
139 uintmax_t fileSize = std::filesystem::file_size(file);
140 if (currentLogSize + fileSize > logMaxSize) {
141 break; // Stop if adding this file would exceed the limit
142 }
143 currentLogSize += fileSize;
144 std::string filename = file.filename().string();
145 cpCommand += filename + " ";
146 }
147 cpCommand += daemonLogFileDir;
148 CopyFiles(cpCommand);
149
150 std::filesystem::current_path(originPath.c_str());
151 WLOGI("Created tar archive of daemonLog files successfully");
152 }
153
to_time_t(const std::filesystem::file_time_type & ftime)154 std::time_t to_time_t(const std::filesystem::file_time_type &ftime)
155 {
156 auto systemTime = std::chrono::time_point_cast<std::chrono::system_clock::duration>
157 (ftime - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());
158 return std::chrono::system_clock::to_time_t(systemTime);
159 }
160
GetHilogInData(std::vector<std::filesystem::path> & otherFiles,std::vector<std::filesystem::path> & logFiles)161 void GetLog::GetHilogInData(std::vector<std::filesystem::path> &otherFiles,
162 std::vector<std::filesystem::path> &logFiles)
163 {
164 std::filesystem::path dirPath(systemHilogFileDir);
165
166 try {
167 if (std::filesystem::exists(dirPath)) {
168 WLOGI("Success read hilog dir");
169 }
170 } catch (const std::filesystem::filesystem_error &e) {
171 WLOGE("GetHilogFiles error: %s", e.what());
172 return;
173 }
174
175 for (const auto& entry : std::filesystem::directory_iterator(dirPath)) {
176 if (!std::filesystem::is_regular_file(entry)) {
177 continue;
178 }
179
180 std::string extension = entry.path().extension().string();
181 if (extension == ".log" || extension == ".zip") {
182 otherFiles.push_back(entry.path());
183 continue;
184 }
185
186 if (extension != ".gz") {
187 continue;
188 }
189
190 // Handle .gz files
191 auto fileTime = std::filesystem::last_write_time(entry.path());
192 auto fileTimeT = to_time_t(fileTime);
193 auto nowT = to_time_t(std::filesystem::file_time_type::clock::now());
194 if (std::localtime(&fileTimeT) == nullptr || std::localtime(&nowT) == nullptr) {
195 WLOGE("Get local time is null");
196 return;
197 }
198 std::tm* fileTm = std::localtime(&fileTimeT);
199 std::tm* nowTm = std::localtime(&nowT);
200 if (fileTm == nullptr || nowTm == nullptr) {
201 WLOGE("Get local time ptr is null");
202 return;
203 }
204
205 bool isSameDay = (fileTm->tm_year == nowTm->tm_year) &&
206 (fileTm->tm_mon == nowTm->tm_mon) &&
207 (fileTm->tm_mday == nowTm->tm_mday);
208
209 if (isSameDay) {
210 logFiles.push_back(entry.path());
211 }
212 }
213 }
214
GenerateHilogFile()215 void GetLog::GenerateHilogFile()
216 {
217 std::vector<std::filesystem::path> filesLog; // Log file vector to tar
218 std::vector<std::filesystem::path> filesOther; // Other file vector to tar
219
220 CreateDir(hilogFileDir);
221 std::string originPath;
222 if (std::filesystem::current_path().string().empty()) {
223 WLOGE("Failed to get current working directory");
224 return;
225 }
226 originPath = std::filesystem::current_path().string();
227 GetHilogInMemory(filesLog);
228 GetHilogInData(filesOther, filesLog);
229
230 if (filesLog.empty() && filesOther.empty()) {
231 WLOGE("Failed to get hilog files");
232 return;
233 }
234
235 // Sort hilog files by last write time
236 std::sort(filesLog.begin(), filesLog.end(), [](const auto& a, const auto& b) {
237 return std::filesystem::last_write_time(a) > std::filesystem::last_write_time(b);
238 });
239
240 // cd LOG_FILE_DIR
241 std::filesystem::current_path(systemHilogFileDir);
242 // Build tokar command with relative paths only
243 std::string cpCommand = "";
244 for (const auto& file : filesOther) {
245 uintmax_t fileSize = std::filesystem::file_size(file);
246 if (currentLogSize + fileSize > logMaxSize) {
247 break; // Stop if adding this file would exceed the limit
248 }
249 currentLogSize += fileSize;
250 std::string filename = file.filename().string();
251 cpCommand += filename + " ";
252 }
253 for (const auto& file : filesLog) {
254 uintmax_t fileSize = std::filesystem::file_size(file);
255 if (currentLogSize + fileSize > logMaxSize) {
256 break; // Stop if adding this file would exceed the limit
257 }
258 currentLogSize += fileSize;
259 std::string filename = file.filename().string();
260 cpCommand += filename + " ";
261 }
262 cpCommand += hilogFileDir;
263 CopyFiles(cpCommand);
264
265 std::filesystem::current_path(originPath.c_str());
266 WLOGI("Created tar archive of hilog files successfully");
267 }
268
TarLogFile()269 void GetLog::TarLogFile()
270 {
271 GenerateDaemonLogFile();
272 GenerateHilogFile();
273
274 std::string originPath;
275 if (std::filesystem::current_path().string().empty()) {
276 WLOGE("Failed to get current working directory");
277 return;
278 }
279 originPath = std::filesystem::current_path().string();
280
281 // cd LOG_FILE_DIR
282 std::filesystem::current_path(LOG_FILE_DIR);
283
284 // Check if directories exist
285 if (!std::filesystem::exists("daemonLog")) {
286 WLOGE("One or both directories do not exist");
287 std::filesystem::current_path(originPath.c_str());
288 return;
289 }
290
291 // Build tar command with relative paths
292 std::string tarCommand = logFilePath + " hilog daemonLog";
293 TarFiles(tarCommand);
294
295 // Restore original working directory
296 std::filesystem::current_path(originPath.c_str());
297 WLOGI("Created tar archive of log files successfully");
298 }
299
ItemData()300 std::map<std::string, std::string> GetLog::ItemData()
301 {
302 // Remove old log tar file
303 RemoveLogFile();
304 // Create tar archive of log files
305 TarLogFile();
306 // Return empty map to satisfy interface
307 return std::map<std::string, std::string>();
308 }
309
LogFileSocketConnect()310 int GetLog::LogFileSocketConnect()
311 {
312 logFileSocket = socket(AF_INET, SOCK_STREAM, 0);
313 if (logFileSocket < 0) {
314 WLOGE("Create log file socket failed, errno: %d", errno);
315 return -1;
316 }
317 struct sockaddr_in socketAddr = {0};
318 socketAddr.sin_family = AF_INET;
319 socketAddr.sin_port = htons(logFileSocketPort);
320 socketAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
321 if (connect(logFileSocket, reinterpret_cast<struct sockaddr *>(&socketAddr), sizeof(socketAddr)) < 0) {
322 WLOGE("Connect log file socket failed, errno: %d", errno);
323 return -1;
324 }
325 WLOGI("Connect log file socket success, socket: %d", logFileSocket);
326 return logFileSocket;
327 }
328
SendLogFile()329 int GetLog::SendLogFile()
330 {
331 char logFilePathChar[PATH_MAX] = {0x00};
332 if ((realpath(logFilePath.c_str(), logFilePathChar) == nullptr)) {
333 WLOGI("%s is not exist.", logFilePath.c_str());
334 return -1;
335 }
336 std::ifstream logFile(logFilePathChar, std::ios::binary);
337 if (!logFile.is_open()) {
338 WLOGE("Open log file failed");
339 close(logFileSocket);
340 logFileSocket = -1;
341 return -1;
342 }
343 WLOGI("logfile exists, sending...");
344 // Get file size
345 logFile.seekg(0, std::ios::end);
346 std::streamsize fileSize = logFile.tellg();
347 logFile.seekg(0, std::ios::beg);
348
349 std::streamsize totalSent = 0;
350 while (!logFile.eof()) {
351 logFile.read(logSocketBuffer, sizeof(logSocketBuffer));
352 std::streamsize bytesRead = logFile.gcount();
353 ssize_t bytesSent = send(logFileSocket, logSocketBuffer, bytesRead, 0);
354 if (bytesSent < 0) {
355 WLOGE("Send log file failed");
356 logFile.close();
357 close(logFileSocket);
358 logFileSocket = -1;
359 return -1;
360 }
361 totalSent += bytesSent;
362 if (bytesSent != bytesRead) {
363 WLOGE("Incomplete send: sent %zd bytes out of %zd", bytesSent, bytesRead);
364 logFile.close();
365 close(logFileSocket);
366 logFileSocket = -1;
367 return -1;
368 }
369 }
370
371 if (totalSent != fileSize) {
372 WLOGE("File size mismatch: sent %zd bytes, file size %zd", totalSent, fileSize);
373 return -1;
374 }
375 logFile.close();
376 close(logFileSocket);
377 logFileSocket = -1;
378 WLOGI("Send log file success, bytes: %zd", totalSent);
379 RemoveLogFile();
380 return 0;
381 }
382
SetLogFileSocketPort(int port)383 void GetLog::SetLogFileSocketPort(int port)
384 {
385 logFileSocketPort = port;
386 }
387
GetLogFileSocketPort() const388 int GetLog::GetLogFileSocketPort() const
389 {
390 return logFileSocketPort;
391 }
392
SetLogFileSocket(int socket)393 void GetLog::SetLogFileSocket(int socket)
394 {
395 logFileSocket = socket;
396 }
397
GetLogFileSocket() const398 int GetLog::GetLogFileSocket() const
399 {
400 return logFileSocket;
401 }
402 } // namespace SmartPerf
403 } // namespace OHOS