1020a203aSopenharmony_ci/*
2020a203aSopenharmony_ci * Copyright (C) 2023 Huawei Device Co., Ltd.
3020a203aSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4020a203aSopenharmony_ci * you may not use this file except in compliance with the License.
5020a203aSopenharmony_ci * You may obtain a copy of the License at
6020a203aSopenharmony_ci *
7020a203aSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8020a203aSopenharmony_ci *
9020a203aSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10020a203aSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11020a203aSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12020a203aSopenharmony_ci * See the License for the specific language governing permissions and
13020a203aSopenharmony_ci * limitations under the License.
14020a203aSopenharmony_ci */
15020a203aSopenharmony_ci#include "dmesg_catcher.h"
16020a203aSopenharmony_ci
17020a203aSopenharmony_ci#include <string>
18020a203aSopenharmony_ci#include <sys/klog.h>
19020a203aSopenharmony_ci#include <unistd.h>
20020a203aSopenharmony_ci#include <fcntl.h>
21020a203aSopenharmony_ci#include <sys/stat.h>
22020a203aSopenharmony_ci#include <sys/types.h>
23020a203aSopenharmony_ci
24020a203aSopenharmony_ci#include "hiview_logger.h"
25020a203aSopenharmony_ci#include "log_catcher_utils.h"
26020a203aSopenharmony_ci#include "common_utils.h"
27020a203aSopenharmony_ci#include "file_util.h"
28020a203aSopenharmony_ci#include "time_util.h"
29020a203aSopenharmony_ci#include "securec.h"
30020a203aSopenharmony_cinamespace OHOS {
31020a203aSopenharmony_cinamespace HiviewDFX {
32020a203aSopenharmony_ciDEFINE_LOG_LABEL(0xD002D01, "EventLogger-DmesgCatcher");
33020a203aSopenharmony_cinamespace {
34020a203aSopenharmony_ci    constexpr int SYSLOG_ACTION_READ_ALL = 3;
35020a203aSopenharmony_ci    constexpr int SYSLOG_ACTION_SIZE_BUFFER = 10;
36020a203aSopenharmony_ci    constexpr mode_t DEFAULT_LOG_FILE_MODE = 0644;
37020a203aSopenharmony_ci    static constexpr const char* const FULL_DIR = "/data/log/eventlog/";
38020a203aSopenharmony_ci}
39020a203aSopenharmony_ciDmesgCatcher::DmesgCatcher() : EventLogCatcher()
40020a203aSopenharmony_ci{
41020a203aSopenharmony_ci    event_ = nullptr;
42020a203aSopenharmony_ci    name_ = "DmesgCatcher";
43020a203aSopenharmony_ci}
44020a203aSopenharmony_ci
45020a203aSopenharmony_cibool DmesgCatcher::Initialize(const std::string& packageNam  __UNUSED,
46020a203aSopenharmony_ci    int isWriteNewFile  __UNUSED, int intParam)
47020a203aSopenharmony_ci{
48020a203aSopenharmony_ci    isWriteNewFile_ = isWriteNewFile;
49020a203aSopenharmony_ci    needWriteSysrq_ = intParam;
50020a203aSopenharmony_ci    return true;
51020a203aSopenharmony_ci}
52020a203aSopenharmony_ci
53020a203aSopenharmony_cibool DmesgCatcher::Init(std::shared_ptr<SysEvent> event)
54020a203aSopenharmony_ci{
55020a203aSopenharmony_ci    event_ = event;
56020a203aSopenharmony_ci    return true;
57020a203aSopenharmony_ci}
58020a203aSopenharmony_ci
59020a203aSopenharmony_cibool DmesgCatcher::DumpDmesgLog(int fd)
60020a203aSopenharmony_ci{
61020a203aSopenharmony_ci    if (fd < 0) {
62020a203aSopenharmony_ci        return false;
63020a203aSopenharmony_ci    }
64020a203aSopenharmony_ci    int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
65020a203aSopenharmony_ci    if (size <= 0) {
66020a203aSopenharmony_ci        return false;
67020a203aSopenharmony_ci    }
68020a203aSopenharmony_ci    char *data = (char *)malloc(size + 1);
69020a203aSopenharmony_ci    if (data == nullptr) {
70020a203aSopenharmony_ci        return false;
71020a203aSopenharmony_ci    }
72020a203aSopenharmony_ci
73020a203aSopenharmony_ci    memset_s(data, size + 1, 0, size + 1);
74020a203aSopenharmony_ci    int readSize = klogctl(SYSLOG_ACTION_READ_ALL, data, size);
75020a203aSopenharmony_ci    if (readSize < 0) {
76020a203aSopenharmony_ci        free(data);
77020a203aSopenharmony_ci        return false;
78020a203aSopenharmony_ci    }
79020a203aSopenharmony_ci    bool res = FileUtil::SaveStringToFd(fd, data);
80020a203aSopenharmony_ci    free(data);
81020a203aSopenharmony_ci    return res;
82020a203aSopenharmony_ci}
83020a203aSopenharmony_ci
84020a203aSopenharmony_cibool DmesgCatcher::WriteSysrq()
85020a203aSopenharmony_ci{
86020a203aSopenharmony_ci    FILE* file = fopen("/proc/sysrq-trigger", "w");
87020a203aSopenharmony_ci    if (file == nullptr) {
88020a203aSopenharmony_ci        HIVIEW_LOGE("Can't read sysrq,errno: %{public}d", errno);
89020a203aSopenharmony_ci        return false;
90020a203aSopenharmony_ci    }
91020a203aSopenharmony_ci    fwrite("w", 1, 1, file);
92020a203aSopenharmony_ci    fflush(file);
93020a203aSopenharmony_ci
94020a203aSopenharmony_ci    fwrite("l", 1, 1, file);
95020a203aSopenharmony_ci    sleep(1);
96020a203aSopenharmony_ci    fclose(file);
97020a203aSopenharmony_ci    return true;
98020a203aSopenharmony_ci}
99020a203aSopenharmony_ci
100020a203aSopenharmony_cistd::string DmesgCatcher::DmesgSaveTofile()
101020a203aSopenharmony_ci{
102020a203aSopenharmony_ci    auto logTime = TimeUtil::GetMilliseconds() / TimeUtil::SEC_TO_MILLISEC;
103020a203aSopenharmony_ci    std::string sysrqTime = TimeUtil::TimestampFormatToDate(logTime, "%Y%m%d%H%M%S");
104020a203aSopenharmony_ci    std::string fullPath = std::string(FULL_DIR) + "sysrq-" + sysrqTime + ".log";
105020a203aSopenharmony_ci    if (FileUtil::FileExists(fullPath)) {
106020a203aSopenharmony_ci        HIVIEW_LOGW("filename: %{public}s is existed, direct use.", fullPath.c_str());
107020a203aSopenharmony_ci        return fullPath;
108020a203aSopenharmony_ci    }
109020a203aSopenharmony_ci
110020a203aSopenharmony_ci    auto fd = open(fullPath.c_str(), O_CREAT | O_WRONLY | O_TRUNC, DEFAULT_LOG_FILE_MODE);
111020a203aSopenharmony_ci    if (fd < 0) {
112020a203aSopenharmony_ci        HIVIEW_LOGI("Fail to create %s.", fullPath.c_str());
113020a203aSopenharmony_ci        return "";
114020a203aSopenharmony_ci    }
115020a203aSopenharmony_ci    bool dumpRet = DumpDmesgLog(fd);
116020a203aSopenharmony_ci    close(fd);
117020a203aSopenharmony_ci
118020a203aSopenharmony_ci    if (!dumpRet) {
119020a203aSopenharmony_ci        return "";
120020a203aSopenharmony_ci    }
121020a203aSopenharmony_ci    if (event_ != nullptr) {
122020a203aSopenharmony_ci        event_->SetEventValue("SYSRQ_TIME", sysrqTime);
123020a203aSopenharmony_ci    }
124020a203aSopenharmony_ci    return fullPath;
125020a203aSopenharmony_ci}
126020a203aSopenharmony_ci
127020a203aSopenharmony_ciint DmesgCatcher::Catch(int fd, int jsonFd)
128020a203aSopenharmony_ci{
129020a203aSopenharmony_ci    if (needWriteSysrq_ && !WriteSysrq()) {
130020a203aSopenharmony_ci        return 0;
131020a203aSopenharmony_ci    }
132020a203aSopenharmony_ci
133020a203aSopenharmony_ci    description_ = needWriteSysrq_ ? "\nSysrqCatcher -- " : "DmesgCatcher -- ";
134020a203aSopenharmony_ci
135020a203aSopenharmony_ci    auto originSize = GetFdSize(fd);
136020a203aSopenharmony_ci    if (isWriteNewFile_) {
137020a203aSopenharmony_ci        std::string fullPath = DmesgSaveTofile();
138020a203aSopenharmony_ci        if (fullPath.empty()) {
139020a203aSopenharmony_ci            return 0;
140020a203aSopenharmony_ci        }
141020a203aSopenharmony_ci        description_ += "fullPath:" + fullPath + "\n";
142020a203aSopenharmony_ci        FileUtil::SaveStringToFd(fd, description_);
143020a203aSopenharmony_ci    } else {
144020a203aSopenharmony_ci        description_ += "\n";
145020a203aSopenharmony_ci        FileUtil::SaveStringToFd(fd, description_);
146020a203aSopenharmony_ci        DumpDmesgLog(fd);
147020a203aSopenharmony_ci    }
148020a203aSopenharmony_ci    logSize_ = GetFdSize(fd) - originSize;
149020a203aSopenharmony_ci    return logSize_;
150020a203aSopenharmony_ci}
151020a203aSopenharmony_ci} // namespace HiviewDFX
152020a203aSopenharmony_ci} // namespace OHOS
153