12498b56bSopenharmony_ci/*
22498b56bSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
32498b56bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
42498b56bSopenharmony_ci * you may not use this file except in compliance with the License.
52498b56bSopenharmony_ci * You may obtain a copy of the License at
62498b56bSopenharmony_ci *
72498b56bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
82498b56bSopenharmony_ci *
92498b56bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
102498b56bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
112498b56bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
122498b56bSopenharmony_ci * See the License for the specific language governing permissions and
132498b56bSopenharmony_ci * limitations under the License.
142498b56bSopenharmony_ci */
152498b56bSopenharmony_ci#include <cstdio>
162498b56bSopenharmony_ci#include <dirent.h>
172498b56bSopenharmony_ci#include <fstream>
182498b56bSopenharmony_ci#include <iostream>
192498b56bSopenharmony_ci#include <securec.h>
202498b56bSopenharmony_ci#include <sstream>
212498b56bSopenharmony_ci#include <sys/stat.h>
222498b56bSopenharmony_ci#include <sys/time.h>
232498b56bSopenharmony_ci#include <unistd.h>
242498b56bSopenharmony_ci
252498b56bSopenharmony_ci#include "log_persister_rotator.h"
262498b56bSopenharmony_ci
272498b56bSopenharmony_ciconstexpr uint8_t MAX_TIME_BUF_SIZE = 32;
282498b56bSopenharmony_ciconstexpr uint8_t MAX_LOG_INDEX_LEN = 4;
292498b56bSopenharmony_ci
302498b56bSopenharmony_cinamespace OHOS {
312498b56bSopenharmony_cinamespace HiviewDFX {
322498b56bSopenharmony_cistd::string GetFileNameIndex(const int index)
332498b56bSopenharmony_ci{
342498b56bSopenharmony_ci    char res[MAX_LOG_INDEX_LEN];
352498b56bSopenharmony_ci    (void)snprintf_s(res, sizeof(res), sizeof(res) - 1, "%03d", index % MAX_LOG_FILE_NUM);
362498b56bSopenharmony_ci    std::string fileNameIndex(res);
372498b56bSopenharmony_ci    return fileNameIndex;
382498b56bSopenharmony_ci}
392498b56bSopenharmony_ci
402498b56bSopenharmony_cibool LogPersisterRotator::IsOldFile(const std::string& logName, const int index)
412498b56bSopenharmony_ci{
422498b56bSopenharmony_ci    std::string fileNameHead = m_logsPath.substr(strlen(HILOG_FILE_DIR), m_logsPath.size());
432498b56bSopenharmony_ci    fileNameHead = fileNameHead + "." + GetFileNameIndex(index + 1 - m_maxLogFileNum);
442498b56bSopenharmony_ci    if (logName.find(fileNameHead) == std::string::npos) {
452498b56bSopenharmony_ci        return false;
462498b56bSopenharmony_ci    }
472498b56bSopenharmony_ci    return true;
482498b56bSopenharmony_ci}
492498b56bSopenharmony_ci
502498b56bSopenharmony_ci
512498b56bSopenharmony_ciLogPersisterRotator::LogPersisterRotator(const std::string& logsPath, uint32_t id, uint32_t maxFiles,
522498b56bSopenharmony_ci    const std::string& fileNameSuffix)
532498b56bSopenharmony_ci    : m_maxLogFileNum(maxFiles), m_logsPath(logsPath), m_fileNameSuffix(fileNameSuffix), m_id(id)
542498b56bSopenharmony_ci{
552498b56bSopenharmony_ci}
562498b56bSopenharmony_ci
572498b56bSopenharmony_ciLogPersisterRotator::~LogPersisterRotator()
582498b56bSopenharmony_ci{
592498b56bSopenharmony_ci    m_infoFile.close();
602498b56bSopenharmony_ci    remove(m_infoFilePath.c_str());
612498b56bSopenharmony_ci}
622498b56bSopenharmony_ci
632498b56bSopenharmony_ciint LogPersisterRotator::Init(const PersistRecoveryInfo& info, bool restore)
642498b56bSopenharmony_ci{
652498b56bSopenharmony_ci    if (!m_infoFile.is_open()) {
662498b56bSopenharmony_ci        if (int result = OpenInfoFile(); result != RET_SUCCESS) {
672498b56bSopenharmony_ci            return result;
682498b56bSopenharmony_ci        }
692498b56bSopenharmony_ci    }
702498b56bSopenharmony_ci
712498b56bSopenharmony_ci    m_info = info;
722498b56bSopenharmony_ci    SetFileIndex(m_info.index, restore);
732498b56bSopenharmony_ci    UpdateRotateNumber();
742498b56bSopenharmony_ci    return RET_SUCCESS;
752498b56bSopenharmony_ci}
762498b56bSopenharmony_ci
772498b56bSopenharmony_ciint LogPersisterRotator::OpenInfoFile()
782498b56bSopenharmony_ci{
792498b56bSopenharmony_ci    auto lastSeparatorIdx = m_logsPath.find_last_of('/');
802498b56bSopenharmony_ci    std::string parentDirPath = m_logsPath.substr(0, lastSeparatorIdx);
812498b56bSopenharmony_ci    if (access(parentDirPath.c_str(), F_OK) != 0) {
822498b56bSopenharmony_ci        if (errno == ENOENT) {
832498b56bSopenharmony_ci            mkdir(parentDirPath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRWXG | S_IRWXO);
842498b56bSopenharmony_ci        }
852498b56bSopenharmony_ci    }
862498b56bSopenharmony_ci    std::string infoFileName = std::string(".") + AUXILLARY_PERSISTER_PREFIX + std::to_string(m_id) + ".info";
872498b56bSopenharmony_ci    m_infoFilePath = parentDirPath + "/" + infoFileName;
882498b56bSopenharmony_ci    m_infoFile.open(m_infoFilePath, std::ios::binary | std::ios::out | std::ios::trunc);
892498b56bSopenharmony_ci    return m_infoFile.is_open() ? RET_SUCCESS : RET_FAIL;
902498b56bSopenharmony_ci}
912498b56bSopenharmony_ci
922498b56bSopenharmony_ciint LogPersisterRotator::Input(const char *buf, uint32_t length)
932498b56bSopenharmony_ci{
942498b56bSopenharmony_ci    if (length <= 0 || buf == nullptr) {
952498b56bSopenharmony_ci        return ERR_LOG_PERSIST_COMPRESS_BUFFER_EXP;
962498b56bSopenharmony_ci    }
972498b56bSopenharmony_ci    if (m_needRotate) {
982498b56bSopenharmony_ci        Rotate();
992498b56bSopenharmony_ci        m_needRotate = false;
1002498b56bSopenharmony_ci    } else if ((access(m_currentLogFileName.c_str(), F_OK) != 0) || !m_currentLogOutput.is_open()) {
1012498b56bSopenharmony_ci        CreateLogFile();
1022498b56bSopenharmony_ci    }
1032498b56bSopenharmony_ci    m_currentLogOutput.write(buf, length);
1042498b56bSopenharmony_ci    m_currentLogOutput.flush();
1052498b56bSopenharmony_ci    return 0;
1062498b56bSopenharmony_ci}
1072498b56bSopenharmony_ci
1082498b56bSopenharmony_civoid LogPersisterRotator::RemoveOldFile()
1092498b56bSopenharmony_ci{
1102498b56bSopenharmony_ci    DIR *dir = nullptr;
1112498b56bSopenharmony_ci    struct dirent *ent = nullptr;
1122498b56bSopenharmony_ci    if ((dir = opendir(HILOG_FILE_DIR)) != nullptr) {
1132498b56bSopenharmony_ci        while ((ent = readdir(dir)) != nullptr) {
1142498b56bSopenharmony_ci            size_t length = strlen(ent->d_name);
1152498b56bSopenharmony_ci            std::string pPath(ent->d_name, length);
1162498b56bSopenharmony_ci            if (IsOldFile(pPath, m_currentLogFileIdx)) {
1172498b56bSopenharmony_ci                remove((HILOG_FILE_DIR + pPath).c_str());
1182498b56bSopenharmony_ci                break;
1192498b56bSopenharmony_ci            }
1202498b56bSopenharmony_ci        }
1212498b56bSopenharmony_ci    }
1222498b56bSopenharmony_ci    if (dir != nullptr) {
1232498b56bSopenharmony_ci        closedir(dir);
1242498b56bSopenharmony_ci    }
1252498b56bSopenharmony_ci}
1262498b56bSopenharmony_ci
1272498b56bSopenharmony_civoid LogPersisterRotator::Rotate()
1282498b56bSopenharmony_ci{
1292498b56bSopenharmony_ci    std::cout << __PRETTY_FUNCTION__ << "\n";
1302498b56bSopenharmony_ci    if (m_currentLogFileIdx + 1 >= m_maxLogFileNum) {
1312498b56bSopenharmony_ci        RemoveOldFile();
1322498b56bSopenharmony_ci    }
1332498b56bSopenharmony_ci    m_currentLogFileIdx++;
1342498b56bSopenharmony_ci    CreateLogFile();
1352498b56bSopenharmony_ci    UpdateRotateNumber();
1362498b56bSopenharmony_ci}
1372498b56bSopenharmony_ci
1382498b56bSopenharmony_civoid LogPersisterRotator::CreateLogFile()
1392498b56bSopenharmony_ci{
1402498b56bSopenharmony_ci    std::cout << __PRETTY_FUNCTION__ << "\n";
1412498b56bSopenharmony_ci    time_t tnow = time(nullptr);
1422498b56bSopenharmony_ci    struct tm *tmNow = localtime(&tnow);
1432498b56bSopenharmony_ci    char timeBuf[MAX_TIME_BUF_SIZE] = {0};
1442498b56bSopenharmony_ci    if (tmNow != nullptr) {
1452498b56bSopenharmony_ci        strftime(timeBuf, sizeof(timeBuf), "%Y%m%d-%H%M%S", tmNow);
1462498b56bSopenharmony_ci    }
1472498b56bSopenharmony_ci    std::stringstream newFile;
1482498b56bSopenharmony_ci    newFile << m_logsPath << "." << GetFileNameIndex(m_currentLogFileIdx) << "." << timeBuf << m_fileNameSuffix;
1492498b56bSopenharmony_ci    std::cout << "Filename: " << newFile.str() << std::endl;
1502498b56bSopenharmony_ci    m_currentLogFileName = newFile.str();
1512498b56bSopenharmony_ci    if (m_currentLogOutput.is_open()) {
1522498b56bSopenharmony_ci        m_currentLogOutput.close();
1532498b56bSopenharmony_ci    }
1542498b56bSopenharmony_ci    m_currentLogOutput.open(newFile.str(), std::ios::out | std::ios::trunc);
1552498b56bSopenharmony_ci}
1562498b56bSopenharmony_ci
1572498b56bSopenharmony_civoid LogPersisterRotator::UpdateRotateNumber()
1582498b56bSopenharmony_ci{
1592498b56bSopenharmony_ci    m_info.index = static_cast<uint32_t>(m_currentLogFileIdx);
1602498b56bSopenharmony_ci    WriteRecoveryInfo();
1612498b56bSopenharmony_ci}
1622498b56bSopenharmony_ci
1632498b56bSopenharmony_civoid LogPersisterRotator::FinishInput()
1642498b56bSopenharmony_ci{
1652498b56bSopenharmony_ci    std::cout << __PRETTY_FUNCTION__ << "\n";
1662498b56bSopenharmony_ci
1672498b56bSopenharmony_ci    m_currentLogOutput.close();
1682498b56bSopenharmony_ci    m_needRotate = true;
1692498b56bSopenharmony_ci}
1702498b56bSopenharmony_ci
1712498b56bSopenharmony_civoid LogPersisterRotator::SetFileIndex(uint32_t index, bool forceRotate)
1722498b56bSopenharmony_ci{
1732498b56bSopenharmony_ci    m_currentLogOutput.close();
1742498b56bSopenharmony_ci    m_currentLogFileIdx = index;
1752498b56bSopenharmony_ci    if (forceRotate) {
1762498b56bSopenharmony_ci        m_needRotate = true;
1772498b56bSopenharmony_ci    }
1782498b56bSopenharmony_ci}
1792498b56bSopenharmony_ci
1802498b56bSopenharmony_civoid LogPersisterRotator::WriteRecoveryInfo()
1812498b56bSopenharmony_ci{
1822498b56bSopenharmony_ci    if (!m_infoFile.is_open()) {
1832498b56bSopenharmony_ci        std::cerr << "LogPersisterRotator has not been initialized!\n";
1842498b56bSopenharmony_ci        return;
1852498b56bSopenharmony_ci    }
1862498b56bSopenharmony_ci
1872498b56bSopenharmony_ci    std::cout << "Save Info file!\n";
1882498b56bSopenharmony_ci    uint64_t hash = GenerateHash(reinterpret_cast<char *>(&m_info), sizeof(PersistRecoveryInfo));
1892498b56bSopenharmony_ci
1902498b56bSopenharmony_ci    m_infoFile.seekp(0);
1912498b56bSopenharmony_ci    m_infoFile.write(reinterpret_cast<const char*>(&m_info), sizeof(m_info));
1922498b56bSopenharmony_ci    m_infoFile.write(reinterpret_cast<const char*>(&hash), sizeof(hash));
1932498b56bSopenharmony_ci    m_infoFile.flush();
1942498b56bSopenharmony_ci    m_infoFile.sync();
1952498b56bSopenharmony_ci}
1962498b56bSopenharmony_ci} // namespace HiviewDFX
1972498b56bSopenharmony_ci} // namespace OHOS
198