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