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