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