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 "audit.h"
16
17 #include <cstdint>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20
21 #include "file_util.h"
22 #include "time_util.h"
23
24 namespace OHOS {
25 namespace HiviewDFX {
26 namespace {
27 static const char AUDIT_LOG_PATH[] = "/data/log/faultlog/hiview_audit.log.0";
28 static const char AUDIT_LOG_PATH_BAK[] = "/data/log/faultlog/hiview_audit.log.1";
29 }
30
~Audit()31 Audit::~Audit()
32 {
33 enabled_ = false;
34 }
35
WriteAuditEvent(StatsEvent eventType,uint64_t eventId,const std::string & digest)36 bool Audit::WriteAuditEvent(StatsEvent eventType, uint64_t eventId, const std::string& digest)
37 {
38 static auto& instance = Audit::GetInstance();
39 if (!instance.IsEnabled()) {
40 return false;
41 }
42
43 if (digest.empty() || (digest.length() >= MAX_AUDIT_LOG_SIZE)) {
44 return false;
45 }
46
47 std::string out;
48 out.append(std::to_string(TimeUtil::GenerateTimestamp()));
49 out.push_back(DOMAIN_DELIMITER);
50 out.append(std::to_string(eventId));
51 out.push_back(DOMAIN_DELIMITER);
52 out.append(std::to_string(eventType));
53 out.push_back(DOMAIN_DELIMITER);
54 out.append(digest);
55 out.append("\n");
56 instance.WriteEvent(out);
57 return true;
58 }
59
GetAuditLog(bool loadFromFile,std::list<std::string> & ret)60 bool Audit::GetAuditLog(bool loadFromFile, std::list<std::string>& ret)
61 {
62 static auto& instance = Audit::GetInstance();
63 if (!instance.IsEnabled()) {
64 return false;
65 }
66
67 instance.GetAuditLogInner(loadFromFile, ret);
68 return true;
69 }
70
IsEnabled()71 bool Audit::IsEnabled()
72 {
73 static auto& instance = Audit::GetInstance();
74 return instance.enabled_;
75 }
76
GetAuditLogInner(bool loadFromFile,std::list<std::string> & ret)77 void Audit::GetAuditLogInner(bool loadFromFile, std::list<std::string>& ret)
78 {
79 if (!loadFromFile) {
80 return;
81 }
82
83 std::lock_guard<std::mutex> lock(mutex_);
84 std::string activeFile = GetLogFilePath(true);
85 ReadLogFromFile(activeFile, ret);
86 std::string inactiveFile = GetLogFilePath(false);
87 ReadLogFromFile(inactiveFile, ret);
88 }
89
90 // call once in platform initialization
Init(bool isBeta)91 void Audit::Init(bool isBeta)
92 {
93 if (init_) {
94 return;
95 }
96
97 std::call_once(initFlag_, [&]() { enabled_ = isBeta; });
98 std::lock_guard<std::mutex> lock(mutex_);
99 useBak_ = IsBackupFileActive();
100 std::string path = useBak_ ? AUDIT_LOG_PATH_BAK : AUDIT_LOG_PATH;
101 writeFd_ = UniqueFd(FileUtil::Open(path, O_CREAT | O_APPEND | O_RDWR,
102 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH));
103 if (writeFd_.Get() < 0) {
104 enabled_ = false;
105 }
106 writeLogCount_ = 0;
107 init_ = true;
108 }
109
Clear()110 void Audit::Clear()
111 {
112 std::lock_guard<std::mutex> lock(mutex_);
113 std::fstream logFile(AUDIT_LOG_PATH, std::ios::out);
114 std::fstream bakLogFile(AUDIT_LOG_PATH_BAK, std::ios::out);
115 }
116
WriteEvent(const std::string & content)117 void Audit::WriteEvent(const std::string& content)
118 {
119 std::lock_guard<std::mutex> lock(mutex_);
120 SaveToFileLocked(content);
121 }
122
IsActiveLogFileSizeReachTheashold()123 bool Audit::IsActiveLogFileSizeReachTheashold()
124 {
125 writeLogCount_ = 0;
126 const auto& path = GetLogFilePath(true);
127 struct stat sb;
128 if (stat(path.c_str(), &sb) == -1) {
129 return false;
130 }
131
132 return sb.st_size >= MAX_DISK_LOG_SIZE;
133 }
134
IsBackupFileActive()135 bool Audit::IsBackupFileActive()
136 {
137 struct stat originLogFileStat;
138 if (stat(AUDIT_LOG_PATH, &originLogFileStat) == -1) {
139 return false;
140 }
141
142 struct stat bakLogFileStat;
143 if (stat(AUDIT_LOG_PATH_BAK, &bakLogFileStat) == -1) {
144 return false;
145 }
146
147 if (originLogFileStat.st_size == 0) {
148 return false;
149 }
150
151 return bakLogFileStat.st_mtime >= originLogFileStat.st_mtime;
152 }
153
SaveToFileLocked(const std::string & content)154 void Audit::SaveToFileLocked(const std::string& content)
155 {
156 if ((writeLogCount_ > MAX_MEMORY_LOG_COUNT) && IsActiveLogFileSizeReachTheashold()) {
157 SwitchActiveFile();
158 }
159
160 int fd = writeFd_.Get();
161 if (fd > 0 && content.length() < MAX_AUDIT_LOG_SIZE) {
162 // no need to check the result.
163 write(fd, content.c_str(), content.length());
164 }
165 writeLogCount_ = writeLogCount_ + 1;
166 }
167
ReadLogFromFile(const std::string & path,std::list<std::string> & ret)168 bool Audit::ReadLogFromFile(const std::string& path, std::list<std::string>& ret)
169 {
170 std::list<std::string> fileLog;
171 std::ifstream logFile(path);
172 std::string line;
173 if (logFile.good()) {
174 while (getline(logFile, line)) {
175 fileLog.push_back(line);
176 }
177 } else {
178 logFile.close();
179 return false;
180 }
181 logFile.close();
182 ret.insert(ret.begin(), fileLog.begin(), fileLog.end());
183 return true;
184 }
185
GetLogFilePath(bool active)186 const std::string Audit::GetLogFilePath(bool active)
187 {
188 if ((useBak_ && active) || (!useBak_ && !active)) {
189 return AUDIT_LOG_PATH_BAK;
190 }
191 return AUDIT_LOG_PATH;
192 }
193
SwitchActiveFile()194 void Audit::SwitchActiveFile()
195 {
196 useBak_ = !useBak_;
197 const auto& path = GetLogFilePath(true);
198 writeFd_ = UniqueFd(FileUtil::Open(path, O_CREAT | O_TRUNC | O_RDWR,
199 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH));
200 }
201 } // namespace HiviewDFX
202 } // namespace OHOS
203