1 /*
2 * Copyright (C) 2023 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 "dmesg_catcher.h"
16
17 #include <cstdio>
18 #include <string>
19 #include <sys/klog.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <sstream>
25 #include <iostream>
26
27 #include "hiview_logger.h"
28 #include "log_catcher_utils.h"
29 #include "common_utils.h"
30 #include "file_util.h"
31 #include "time_util.h"
32 #include "securec.h"
33 namespace OHOS {
34 namespace HiviewDFX {
35 #ifdef DMESG_CATCHER_ENABLE
36 DEFINE_LOG_LABEL(0xD002D01, "EventLogger-DmesgCatcher");
37 namespace {
38 constexpr int SYSLOG_ACTION_READ_ALL = 3;
39 constexpr int SYSLOG_ACTION_SIZE_BUFFER = 10;
40 constexpr mode_t DEFAULT_LOG_FILE_MODE = 0644;
41 static constexpr const char* const FULL_DIR = "/data/log/eventlog/";
42 }
DmesgCatcher()43 DmesgCatcher::DmesgCatcher() : EventLogCatcher()
44 {
45 event_ = nullptr;
46 name_ = "DmesgCatcher";
47 }
48
Initialize(const std::string & packageNam __UNUSED,int isWriteNewFile __UNUSED,int needWriteSysrq)49 bool DmesgCatcher::Initialize(const std::string& packageNam __UNUSED,
50 int isWriteNewFile __UNUSED, int needWriteSysrq)
51 {
52 isWriteNewFile_ = isWriteNewFile;
53 needWriteSysrq_ = needWriteSysrq;
54 return true;
55 }
56
Init(std::shared_ptr<SysEvent> event)57 bool DmesgCatcher::Init(std::shared_ptr<SysEvent> event)
58 {
59 event_ = event;
60 return true;
61 }
62
DumpSysrqToFile(int fd,char * data,int size)63 bool DmesgCatcher::DumpSysrqToFile(int fd, char *data, int size)
64 {
65 std::string dataStr = std::string(data, size);
66 std::stringstream ss(dataStr);
67 std::string line;
68 bool res = false;
69
70 while (std::getline(ss, line)) {
71 if (line.find("hguard-worker") != std::string::npos) {
72 line += "\n";
73 res = FileUtil::SaveStringToFd(fd, line);
74 }
75 }
76 return res;
77 }
78
DumpDmesgLog(int fd)79 bool DmesgCatcher::DumpDmesgLog(int fd)
80 {
81 if (fd < 0) {
82 return false;
83 }
84 int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
85 if (size <= 0) {
86 return false;
87 }
88 char *data = (char *)malloc(size + 1);
89 if (data == nullptr) {
90 return false;
91 }
92
93 memset_s(data, size + 1, 0, size + 1);
94 int readSize = klogctl(SYSLOG_ACTION_READ_ALL, data, size);
95 if (readSize < 0) {
96 free(data);
97 return false;
98 }
99 bool res = needWriteSysrq_ ? DumpSysrqToFile(fd, data, size) : FileUtil::SaveStringToFd(fd, data);
100 free(data);
101 return res;
102 }
103
WriteSysrq()104 bool DmesgCatcher::WriteSysrq()
105 {
106 FILE* file = fopen("/proc/sysrq-trigger", "w");
107 if (file == nullptr) {
108 HIVIEW_LOGE("Can't read sysrq,errno: %{public}d", errno);
109 return false;
110 }
111 fwrite("w", 1, 1, file);
112 fflush(file);
113
114 fwrite("l", 1, 1, file);
115 sleep(1);
116 fclose(file);
117 return true;
118 }
119
Catch(int fd,int jsonFd)120 int DmesgCatcher::Catch(int fd, int jsonFd)
121 {
122 if (needWriteSysrq_ && !WriteSysrq()) {
123 return 0;
124 }
125 description_ = needWriteSysrq_ ? "\nSysrqCatcher -- \n" : "DmesgCatcher -- \n";
126 auto originSize = GetFdSize(fd);
127 FileUtil::SaveStringToFd(fd, description_);
128 DumpDmesgLog(fd);
129 logSize_ = GetFdSize(fd) - originSize;
130 return logSize_;
131 }
132
WriteNewSysrq()133 void DmesgCatcher::WriteNewSysrq()
134 {
135 if (needWriteSysrq_ && !WriteSysrq()) {
136 return;
137 }
138 std::string sysrqTime = event_->GetEventValue("SYSRQ_TIME");
139 std::string fullPath = std::string(FULL_DIR) + "sysrq-" + sysrqTime + ".log";
140 HIVIEW_LOGI("write new sysrq start, fullPath : %{public}s", fullPath.c_str());
141 if (FileUtil::FileExists(fullPath)) {
142 HIVIEW_LOGW("filename: %{public}s is existed, direct use.", fullPath.c_str());
143 return;
144 }
145 FILE* fp = fopen(fullPath.c_str(), "w");
146 chmod(fullPath.c_str(), DEFAULT_LOG_FILE_MODE);
147 if (fp == nullptr) {
148 HIVIEW_LOGI("Fail to create %{public}s, errno: %{public}d.", fullPath.c_str(), errno);
149 return;
150 }
151 auto fd = fileno(fp);
152 DumpDmesgLog(fd);
153 if (fclose(fp)) {
154 HIVIEW_LOGE("fclose is failed");
155 }
156 fp = nullptr;
157 HIVIEW_LOGI("write new sysrq end, fullPath : %{public}s", fullPath.c_str());
158 }
159 #endif // DMESG_CATCHER_ENABLE
160 } // namespace HiviewDFX
161 } // namespace OHOS
162