• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "faultlog_dump.h"
16 
17 #include <functional>
18 
19 #include "accesstoken_kit.h"
20 #include "bundle_mgr_client.h"
21 #include "constants.h"
22 #include "faultlog_bundle_util.h"
23 #include "file_util.h"
24 #include "hiview_logger.h"
25 #include "ipc_skeleton.h"
26 #include "time_util.h"
27 #include "string_util.h"
28 
29 namespace OHOS {
30 namespace HiviewDFX {
31 DEFINE_LOG_LABEL(0xD002D11, "Faultlogger");
32 using namespace FaultLogger;
33 namespace {
34 const char * const FILE_SEPARATOR = "******";
35 constexpr uint32_t DUMP_MAX_NUM = 100;
36 constexpr int DUMP_PARSE_CMD = 0;
37 constexpr int DUMP_PARSE_FILE_NAME = 1;
38 constexpr int DUMP_PARSE_TIME = 2;
39 constexpr int DUMP_START_PARSE_MODULE_NAME = 3;
40 constexpr uint32_t MAX_NAME_LENGTH = 4096;
IsLogNameValid(const std::string & name)41 bool IsLogNameValid(const std::string& name)
42 {
43     const int32_t idxOfType = 0;
44     const int32_t idxOfMoudle = 1;
45     const int32_t idxOfUid = 2;
46     const int32_t idxOfTime = 3;
47     const int32_t expectedVecSize = 4;
48     const size_t tailWithMillSecLen = 7u;
49     if (name.empty() || name.size() > MAX_NAME_LENGTH) {
50         HIVIEW_LOGI("invalid log name.");
51         return false;
52     }
53 
54     std::vector<std::string> out;
55     StringUtil::SplitStr(name, "-", out, true, false);
56     if (out.size() != expectedVecSize) {
57         return false;
58     }
59 
60     std::regex reType("^[a-z]+$");
61     if (!std::regex_match(out[idxOfType], reType)) {
62         HIVIEW_LOGI("invalid type.");
63         return false;
64     }
65 
66     if (!IsModuleNameValid(out[idxOfMoudle])) {
67         HIVIEW_LOGI("invalid module name.");
68         return false;
69     }
70 
71     std::regex reDigits("^[0-9]*$");
72     if (!std::regex_match(out[idxOfUid], reDigits)) {
73         HIVIEW_LOGI("invalid uid.");
74         return false;
75     }
76 
77     if (StringUtil::EndWith(out[idxOfTime], ".log") && out[idxOfTime].length() > tailWithMillSecLen) {
78         out[idxOfTime] = out[idxOfTime].substr(0, out[idxOfTime].length() - tailWithMillSecLen);
79     }
80 
81     if (!std::regex_match(out[idxOfTime], reDigits)) {
82         HIVIEW_LOGI("invalid digits.");
83         return false;
84     }
85     return true;
86 }
87 
FillDumpRequest(DumpRequest & request,int status,const std::string & item)88 bool FillDumpRequest(DumpRequest& request, int status, const std::string& item)
89 {
90     switch (status) {
91         case DUMP_PARSE_FILE_NAME:
92             if (!IsLogNameValid(item)) {
93                 return false;
94             }
95             request.fileName = item;
96             break;
97         case DUMP_PARSE_TIME:
98             if (item.size() == 14) { // 14 : BCD time size
99                 request.time = TimeUtil::StrToTimeStamp(item, "%Y%m%d%H%M%S");
100             } else {
101                 StringUtil::ConvertStringTo<time_t>(item, request.time);
102             }
103             break;
104         case DUMP_START_PARSE_MODULE_NAME:
105             if (!IsModuleNameValid(item)) {
106                 return false;
107             }
108             request.moduleName = item;
109             break;
110         default:
111             HIVIEW_LOGI("Unknown status.");
112             break;
113     }
114     return true;
115 }
116 }  // namespace
117 
DumpByFileName(const DumpRequest & request) const118 bool FaultLogDump::DumpByFileName(const DumpRequest& request) const
119 {
120     if (!request.fileName.empty()) {
121         std::string content;
122         if (faultLogManager_->GetFaultLogContent(request.fileName, content)) {
123             dprintf(fd_, "%s\n", content.c_str());
124         } else {
125             dprintf(fd_, "Fail to dump the log.\n");
126         }
127         return true;
128     }
129     return false;
130 }
131 
PrintFileMaps(const DumpRequest & request,std::map<std::string,std::string> fileNameMap) const132 void FaultLogDump::PrintFileMaps(const DumpRequest& request, std::map<std::string, std::string> fileNameMap) const
133 {
134     dprintf(fd_, "Fault log list:\n");
135     dprintf(fd_, "%s\n", FILE_SEPARATOR);
136     for (auto it = fileNameMap.begin(); it != fileNameMap.end(); ++it) {
137         dprintf(fd_, "%s\n", it->first.c_str());
138         if (request.requestDetail) {
139             std::string content;
140             std::string fullFileName = FAULTLOG_FAULT_LOGGER_FOLDER + it->second;
141             if (FileUtil::LoadStringFromFile(fullFileName, content)) {
142                 dprintf(fd_, "%s\n", content.c_str());
143             } else {
144                 dprintf(fd_, "Fail to dump detail log.\n");
145             }
146             dprintf(fd_, "%s\n", FILE_SEPARATOR);
147         }
148     }
149     dprintf(fd_, "%s\n", FILE_SEPARATOR);
150 }
151 
FindByModule(const DumpRequest & request) const152 std::map<std::string, std::string> FaultLogDump::FindByModule(const DumpRequest& request) const
153 {
154     auto fileList = faultLogManager_->GetFaultLogFileList(request.moduleName, request.time, -1, 0, DUMP_MAX_NUM);
155     if (fileList.empty()) {
156         dprintf(fd_, "No fault log exist.\n");
157         return {};
158     }
159     std::map<std::string, std::string> fileNameMap;
160     const size_t tailWithMillisecLen = 7;
161     for (const auto &file : fileList) {
162         std::string fileName = FileUtil::ExtractFileName(file);
163         if (fileName.length() <= tailWithMillisecLen) {
164             continue;
165         }
166         if (!request.compatFlag && StringUtil::EndWith(fileName, ".log") == false) {
167             continue;
168         } else if (request.compatFlag && StringUtil::EndWith(fileName, ".log")) {
169             if (fileNameMap[fileName.substr(0, fileName.length() - tailWithMillisecLen)].compare(fileName) < 0) {
170                 fileNameMap[fileName.substr(0, fileName.length() - tailWithMillisecLen)] = fileName;
171             }
172             continue;
173         }
174         fileNameMap[fileName] = fileName;
175     }
176     return fileNameMap;
177 }
178 
DumpByModule(const DumpRequest & request) const179 void FaultLogDump::DumpByModule(const DumpRequest& request) const
180 {
181     auto fileNameMap = FindByModule(request);
182     PrintFileMaps(request, fileNameMap);
183 }
184 
DumpByRequest(const DumpRequest & request) const185 void FaultLogDump::DumpByRequest(const DumpRequest& request) const
186 {
187     if (DumpByFileName(request)) {
188         return;
189     }
190     DumpByModule(request);
191 }
192 
HandleCommandOption(const std::string & cmd,int32_t & status,DumpRequest & request) const193 ParseCmdResult FaultLogDump::HandleCommandOption(const std::string& cmd, int32_t& status, DumpRequest& request) const
194 {
195     const std::map<std::string, std::function<void(int32_t&, DumpRequest&)>> cmdHandlers = {
196         {"-f", [](int32_t& status, DumpRequest& request) { status = DUMP_PARSE_FILE_NAME; }},
197         {"-l", [](int32_t& status, DumpRequest& request) { request.requestList = true; }},
198         {"-t", [](int32_t& status, DumpRequest& request) { status = DUMP_PARSE_TIME; }},
199         {"-m", [](int32_t& status, DumpRequest& request) { status = DUMP_START_PARSE_MODULE_NAME; }},
200         {"-d", [](int32_t& status, DumpRequest& request) { request.requestDetail = true; }},
201         {"Faultlogger", [](int32_t& status, DumpRequest& request) { request.compatFlag = true; }},
202         {"-LogSuffixWithMs", [](int32_t& status, DumpRequest& request) { request.compatFlag = false; }}
203     };
204 
205     if (cmdHandlers.count(cmd)) {
206         cmdHandlers.at(cmd)(status, request);
207         return ParseCmdResult::SUCCESS;
208     }
209 
210     if (!cmd.empty() && cmd.at(0) == '-') {
211         dprintf(fd_, "Unknown command.\n");
212         return ParseCmdResult::UNKNOWN;
213     }
214     return ParseCmdResult::MAX;
215 }
216 
ParseDumpCommands(const std::vector<std::string> & cmds,DumpRequest & request,int32_t & status) const217 bool FaultLogDump::ParseDumpCommands(const std::vector<std::string>& cmds, DumpRequest& request, int32_t& status) const
218 {
219     for (const auto& cmd: cmds) {
220         auto result = HandleCommandOption(cmd, status, request);
221         if (result == ParseCmdResult::SUCCESS) {
222             continue;
223         } else if (result == ParseCmdResult::UNKNOWN) {
224             return false;
225         }
226         if (!FillDumpRequest(request, status, cmd)) {
227             dprintf(fd_, "invalid parameters.\n");
228             return false;
229         }
230         status = DUMP_PARSE_CMD;
231     }
232     return true;
233 }
234 
DumpByCommands(const std::vector<std::string> & cmds) const235 void FaultLogDump::DumpByCommands(const std::vector<std::string>& cmds) const
236 {
237     if (!VerifiedDumpPermission()) {
238         dprintf(fd_, "dump operation is not permitted.\n");
239         return;
240     }
241     DumpRequest request;
242     int32_t status = DUMP_PARSE_CMD;
243     if (!ParseDumpCommands(cmds, request, status)) {
244         return;
245     }
246     if (status != DUMP_PARSE_CMD) {
247         dprintf(fd_, "empty parameters.\n");
248         return;
249     }
250 
251     HIVIEW_LOGI("DumpRequest: detail:%{public}d, list:%{public}d, file:%{public}s, name:%{public}s, time:%{public}lld",
252         request.requestDetail, request.requestList, request.fileName.c_str(), request.moduleName.c_str(),
253         static_cast<long long>(request.time));
254     DumpByRequest(request);
255 }
VerifiedDumpPermission() const256 bool FaultLogDump::VerifiedDumpPermission() const
257 {
258     using namespace Security::AccessToken;
259     auto tokenId = IPCSkeleton::GetCallingTokenID();
260     return AccessTokenKit::VerifyAccessToken(tokenId, "ohos.permission.DUMP") == PermissionState::PERMISSION_GRANTED;
261 }
262 }  // namespace HiviewDFX
263 }  // namespace OHOS
264