1 /*
2 * Copyright (c) 2024 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
16 #include "hi_audit.h"
17
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <iomanip>
21 #include <sstream>
22 #include <unistd.h>
23
24 #include "storage_service_log.h"
25 #include "zip_util.h"
26
27 namespace OHOS {
28 struct HiAuditConfig {
29 std::string logPath;
30 std::string logName;
31 uint32_t logSize; // kb
32 uint32_t fileSize;
33 uint32_t fileCount;
34 };
35
36 const HiAuditConfig HIAUDIT_CONFIG = {
37 "/data/log/hiaudit/storageservice/", "storageservice", 2 * 1024, 3 * 1024 * 1024, 10};
38 constexpr int8_t MILLISECONDS_LENGTH = 3;
39 constexpr int64_t SEC_TO_MILLISEC = 1000;
40 constexpr int MAX_TIME_BUFF = 64; // 64 : for example 2021-05-27-01-01-01
41 const std::string HIAUDIT_LOG_NAME = HIAUDIT_CONFIG.logPath + HIAUDIT_CONFIG.logName + "_audit.csv";
42
HiAudit()43 HiAudit::HiAudit()
44 {
45 Init();
46 }
47
~HiAudit()48 HiAudit::~HiAudit()
49 {
50 if (writeFd_ >= 0) {
51 close(writeFd_);
52 }
53 }
54
GetInstance()55 HiAudit& HiAudit::GetInstance()
56 {
57 static HiAudit hiAudit;
58 return hiAudit;
59 }
60
Init()61 void HiAudit::Init()
62 {
63 if (access(HIAUDIT_CONFIG.logPath.c_str(), F_OK) != 0) {
64 int32_t ret = mkdir(HIAUDIT_CONFIG.logPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
65 if (ret != 0) {
66 LOGE("Failed to create directory %{public}s.", HIAUDIT_CONFIG.logPath.c_str());
67 }
68 }
69
70 std::lock_guard<std::mutex> lock(mutex_);
71 writeFd_ = open(HIAUDIT_LOG_NAME.c_str(), O_CREAT | O_APPEND | O_RDWR,
72 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
73 if (writeFd_ < 0) {
74 LOGE("writeFd_ open error");
75 }
76 struct stat st;
77 writeLogSize_ = stat(HIAUDIT_LOG_NAME.c_str(), &st) ? 0 : static_cast<uint64_t>(st.st_size);
78 LOGI("writeLogSize: %{public}u", writeLogSize_.load());
79 }
80
GetMilliseconds()81 uint64_t HiAudit::GetMilliseconds()
82 {
83 auto now = std::chrono::system_clock::now();
84 auto millisecs = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
85 return millisecs.count();
86 }
87
GetFormattedTimestamp(time_t timeStamp,const std::string & format)88 std::string HiAudit::GetFormattedTimestamp(time_t timeStamp, const std::string& format)
89 {
90 auto seconds = timeStamp / SEC_TO_MILLISEC;
91 char date[MAX_TIME_BUFF] = {0};
92 struct tm result {};
93 if (localtime_r(&seconds, &result) != nullptr) {
94 strftime(date, MAX_TIME_BUFF, format.c_str(), &result);
95 }
96 return std::string(date);
97 }
98
GetFormattedTimestampEndWithMilli()99 std::string HiAudit::GetFormattedTimestampEndWithMilli()
100 {
101 uint64_t milliSeconds = GetMilliseconds();
102 std::string formattedTimeStamp = GetFormattedTimestamp(milliSeconds, "%Y%m%d%H%M%S");
103 std::stringstream ss;
104 ss << formattedTimeStamp;
105 milliSeconds = milliSeconds % SEC_TO_MILLISEC;
106 ss << std::setfill('0') << std::setw(MILLISECONDS_LENGTH) << milliSeconds;
107 return ss.str();
108 }
109
Write(const AuditLog & auditLog)110 void HiAudit::Write(const AuditLog& auditLog)
111 {
112 LOGI("write storageservice audit log");
113 std::lock_guard<std::mutex> lock(mutex_);
114 if (writeLogSize_ == 0) {
115 WriteToFile(auditLog.TitleString() + "\n");
116 }
117 std::string writeLog = GetFormattedTimestampEndWithMilli() + ", " +
118 HIAUDIT_CONFIG.logName + ", NO, " + auditLog.ToString();
119 LOGI("write %{public}s.", writeLog.c_str());
120 if (writeLog.length() > HIAUDIT_CONFIG.logSize) {
121 writeLog = writeLog.substr(0, HIAUDIT_CONFIG.logSize);
122 }
123 writeLog = writeLog + "\n";
124 WriteToFile(writeLog);
125 }
126
GetWriteFilePath()127 void HiAudit::GetWriteFilePath()
128 {
129 if (writeLogSize_ < HIAUDIT_CONFIG.fileSize) {
130 return;
131 }
132
133 close(writeFd_);
134 ZipAuditLog();
135 CleanOldAuditFile();
136
137 writeFd_ = open(HIAUDIT_LOG_NAME.c_str(), O_CREAT | O_TRUNC | O_RDWR,
138 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
139 if (writeFd_ < 0) {
140 LOGE("fd open error");
141 }
142
143 writeLogSize_ = 0;
144 }
145
CleanOldAuditFile()146 void HiAudit::CleanOldAuditFile()
147 {
148 uint32_t zipFileSize = 0;
149 std::string oldestAuditFile;
150 DIR* dir = opendir(HIAUDIT_CONFIG.logPath.c_str());
151 if (dir == nullptr) {
152 LOGE("failed open dir, errno: %{public}d.", errno);
153 return;
154 }
155 while (true) {
156 struct dirent* ptr = readdir(dir);
157 if (ptr == nullptr) {
158 break;
159 }
160 if (std::string(ptr->d_name).find(HIAUDIT_CONFIG.logName) != std::string::npos &&
161 std::string(ptr->d_name).find("zip") != std::string::npos) {
162 zipFileSize = zipFileSize + 1;
163 if (oldestAuditFile.empty()) {
164 oldestAuditFile = HIAUDIT_CONFIG.logPath + std::string(ptr->d_name);
165 continue;
166 }
167 struct stat st;
168 stat((HIAUDIT_CONFIG.logPath + std::string(ptr->d_name)).c_str(), &st);
169 struct stat oldestSt;
170 stat(oldestAuditFile.c_str(), &oldestSt);
171 if (st.st_mtime < oldestSt.st_mtime) {
172 oldestAuditFile = HIAUDIT_CONFIG.logPath + std::string(ptr->d_name);
173 }
174 }
175 }
176 closedir(dir);
177 if (zipFileSize > HIAUDIT_CONFIG.fileCount) {
178 remove(oldestAuditFile.c_str());
179 }
180 }
181
WriteToFile(const std::string & content)182 void HiAudit::WriteToFile(const std::string& content)
183 {
184 GetWriteFilePath();
185 if (writeFd_ < 0) {
186 LOGE("fd invalid.");
187 return;
188 }
189 write(writeFd_, content.c_str(), content.length());
190 writeLogSize_ = writeLogSize_ + content.length();
191 }
192
ZipAuditLog()193 void HiAudit::ZipAuditLog()
194 {
195 std::string zipFileName = HIAUDIT_CONFIG.logPath + HIAUDIT_CONFIG.logName + "_audit_" +
196 GetFormattedTimestamp(GetMilliseconds(), "%Y%m%d%H%M%S");
197 std::rename(HIAUDIT_LOG_NAME.c_str(), (zipFileName + ".csv").c_str());
198 zipFile compressZip = StorageDaemon::ZipUtil::CreateZipFile(zipFileName + ".zip");
199 if (compressZip == nullptr) {
200 LOGW("open zip file failed.");
201 return;
202 }
203 if (StorageDaemon::ZipUtil::AddFileInZip(compressZip, zipFileName + ".csv", StorageDaemon::KEEP_NONE_PARENT_PATH) ==
204 0) {
205 remove((zipFileName + ".csv").c_str());
206 }
207 StorageDaemon::ZipUtil::CloseZipFile(compressZip);
208 }
209 } // namespace OHOS