~aleteoryx/muditaos

157cea8acb577741937ffbcee72c35367387de2e — Lukasz Mastalerz 2 years ago 4804015
[CP-1512] Add crashdumps indexing

Adding indexing to crashdumps to to ensure resistance to the device date
retraction.
When max crashdump count reach the file with higher index number will be
remove.
M board/rt1051/crashdump/crashcatcher_impl.cpp => board/rt1051/crashdump/crashcatcher_impl.cpp +0 -1
@@ 60,7 60,6 @@ void CrashCatcher_DumpMemory(const void *pvMemory, CrashCatcherElementSizes elem
CrashCatcherReturnCodes CrashCatcher_DumpEnd(void)
{
    cwrite.saveDump();
    cwrite.deleteOldDump();
    _exit_backtrace(-1, false);
    return CRASH_CATCHER_EXIT;
}

M board/rt1051/crashdump/crashdumpwriter_vfs.cpp => board/rt1051/crashdump/crashdumpwriter_vfs.cpp +11 -20
@@ 18,19 18,23 @@

namespace
{
    constexpr inline auto suffix = "_crashdump.hex";
    constexpr inline auto suffix     = "_crashdump.hex";
    constexpr inline auto file_index = ".1";

    // Crashdump filename pattern:
    // [serial-number]_[timestamp-in-seconds]_crashdump.hex
    // [serial-number]_[timestamp-in-seconds]_crashdump.hex.[index]
    // [index] was added to ensure resistance to the device date retraction

    inline std::string generate_crashdump_filename()
    {
        const auto crash_time =
            std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
                .count();
        auto filename = std::string("/") + crashdump::getSerialNumber() + "_" + std::to_string(crash_time) + suffix;
        auto filename =
            std::string("/") + crashdump::getSerialNumber() + "_" + std::to_string(crash_time) + suffix + file_index;
        return filename;
    }

} // namespace

namespace crashdump


@@ 41,6 45,10 @@ namespace crashdump
        const auto crashDumpFilePath = purefs::dir::getCrashDumpsPath().string() + generate_crashdump_filename();

        LOG_INFO("Crash dump %s preparing ...", crashDumpFilePath.c_str());
        if (!rotator.rotateFiles(purefs::dir::getCrashDumpsPath())) {
            LOG_FATAL("Failed to rotate crash dumps errno: %i", errno);
            _exit_backtrace(-1, false);
        }
        file = std::fopen(crashDumpFilePath.c_str(), "w");
        if (!file) {
            LOG_FATAL("Failed to open crash dump file errno %i", errno);


@@ 56,23 64,6 @@ namespace crashdump
        std::fclose(file);
    }

    void CrashDumpWriterVFS::deleteOldDump()
    {
        std::set<std::filesystem::path> crashdumps{};
        for (const auto &entry : std::filesystem::directory_iterator(purefs::dir::getCrashDumpsPath())) {
            std::cout << entry.path() << std::endl;
            crashdumps.insert(entry.path());
        }

        if (crashdumps.size() > maxFilesCount) {
            auto crashdump_to_delete = crashdumps.begin();
            LOG_INFO("Deleting %s ...", crashdump_to_delete->c_str());
            if (not std::filesystem::remove(crashdump_to_delete->c_str())) {
                LOG_WARN("File: %s was not deleted.", crashdump_to_delete->c_str());
            }
        }
    }

    void CrashDumpWriterVFS::writeBytes(const uint8_t *buff, std::size_t size)
    {
        if (std::fwrite(buff, sizeof(*buff), size, file) != size) {

M board/rt1051/crashdump/crashdumpwriter_vfs.hpp => board/rt1051/crashdump/crashdumpwriter_vfs.hpp +4 -3
@@ 3,6 3,7 @@

#pragma once

#include <rotator/Rotator.hpp>
#include <array>
#include <ctime>
#include <memory>


@@ 15,21 16,21 @@ namespace purefs::fs

namespace crashdump
{
    constexpr inline auto maxFilesCount = 5;
    constexpr inline auto maxRotationFilesCount = 5;
    class CrashDumpWriterVFS
    {
      public:
        CrashDumpWriterVFS()
        CrashDumpWriterVFS() : rotator{".hex"}
        {}
        void openDump();
        void saveDump();
        void deleteOldDump();

        void writeBytes(const std::uint8_t *buff, std::size_t size);
        void writeHalfWords(const std::uint16_t *buff, std::size_t size);
        void writeWords(const std::uint32_t *buff, std::size_t size);

      private:
        utils::Rotator<maxRotationFilesCount> rotator;
        std::FILE *file{};
    };


M module-utils/rotator/include/rotator/Rotator.hpp => module-utils/rotator/include/rotator/Rotator.hpp +56 -1
@@ 1,10 1,13 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <Utils.hpp>

#include <filesystem>
#include <string>
#include <set>

namespace utils
{


@@ 41,6 44,32 @@ namespace utils
            return path;
        }

        uint getFileNumber(const std::string &filename) const
        {
            const auto position = filename.rfind(".");
            if (position == std::string::npos) {
                return 0;
            }
            const auto indexStartPosition = position + 1;
            auto numberLength             = filename.length() - indexStartPosition;
            return utils::toNumeric(filename.substr(indexStartPosition, numberLength));
        }

        std::filesystem::path incrementFileNumber(const std::filesystem::path &crashdumpPath) const
        {
            auto newCrashdumpName = crashdumpPath.string();
            auto position         = newCrashdumpName.rfind(".");
            if (position == std::string::npos) {
                return crashdumpPath;
            }
            const auto indexStartPosition = position + 1;
            const auto numberLength       = newCrashdumpName.length() - indexStartPosition;
            auto fileNumber               = utils::toNumeric(newCrashdumpName.substr(indexStartPosition, numberLength));
            auto incrementedFileNumber    = fileNumber ? std::to_string(++fileNumber) : "hex.0";
            newCrashdumpName.replace(indexStartPosition, numberLength, incrementedFileNumber);
            return std::filesystem::path(newCrashdumpName);
        }

      public:
        explicit Rotator(std::string extension) : extension{extension}
        {}


@@ 79,5 108,31 @@ namespace utils
            std::filesystem::rename(path, rotatedLogPath, ec);
            return (ec) ? false : true;
        }

        bool rotateFiles(const std::filesystem::path &path) const
        {
            std::error_code ec;
            std::set<std::filesystem::path> crashdumps{};

            for (const auto &entry : std::filesystem::directory_iterator(path)) {
                crashdumps.insert(entry.path());
            }

            for (const auto &crashdump : crashdumps) {
                if (getFileNumber(crashdump.string()) >= maxRotationFilesCount) {
                    std::filesystem::remove(crashdump, ec);
                    if (ec) {
                        return false;
                    }
                    continue;
                }
                std::filesystem::rename(crashdump, incrementFileNumber(crashdump), ec);
                if (ec) {
                    return false;
                }
            }

            return (ec) ? false : true;
        }
    };
} // namespace utils

M module-utils/rotator/tests/test_Rotator.cpp => module-utils/rotator/tests/test_Rotator.cpp +85 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>


@@ 23,6 23,11 @@ namespace
        {
            return this->getRotatedFilePath(source, rotationCount);
        }

        std::filesystem::path incrementFileIndex(const std::filesystem::path &source)
        {
            return this->incrementFileNumber(source);
        }
    };
} // namespace



@@ 92,3 97,82 @@ TEST_CASE("Rotation of hex dump files")
        }
    }
}

TEST_CASE("Rotate files with serial_number and timestamp")
{
    HexRotator rotator;
    std::string path("./rotator_tests");

    SECTION("Increment filename index")
    {
        std::string filename          = "123_12345_crashdump.hex.1";
        std::string expected_filename = "123_12345_crashdump.hex.2";
        auto result                   = rotator.incrementFileIndex(std::filesystem::path(filename));
        REQUIRE(result == expected_filename);
    }

    SECTION("Rotate files")
    {

        std::vector<std::string> test_filenames = {
            "/123_12345_crashdump.hex.1", "/123_12346_crashdump.hex.2", "/123_12347_crashdump.hex.3"};
        std::vector<std::string> expected_test_filenames = {
            "/123_12345_crashdump.hex.2", "/123_12346_crashdump.hex.3", "/123_12347_crashdump.hex.4"};

        std::filesystem::create_directory(path);

        for (const auto &tf : test_filenames) {
            std::ofstream(std::string(path + tf).c_str());
        }
        REQUIRE(rotator.rotateFiles(std::filesystem::path(path)));
        for (const auto &etf : expected_test_filenames) {
            REQUIRE(std::filesystem::exists(std::string(path + etf)));
        }

        std::filesystem::remove_all(path);
    }

    SECTION("Rotate files - max number reach")
    {

        std::vector<std::string> test_filenames = {"/123_12345_crashdump.hex.1",
                                                   "/123_12346_crashdump.hex.2",
                                                   "/123_12347_crashdump.hex.3",
                                                   "/123_12349_crashdump.hex.4",
                                                   "/123_12351_crashdump.hex.5"};

        std::vector<std::string> expected_test_filenames = {"/123_12345_crashdump.hex.2",
                                                            "/123_12346_crashdump.hex.3",
                                                            "/123_12347_crashdump.hex.4",
                                                            "/123_12349_crashdump.hex.5"};

        std::string file_expected_to_not_exist = "/123_12351_crashdump.hex.6";

        std::filesystem::create_directory(path);

        for (const auto &tf : test_filenames) {
            std::ofstream(std::string(path + tf).c_str());
        }
        REQUIRE(rotator.rotateFiles(std::filesystem::path(path)));
        for (const auto &tf : test_filenames) {
            REQUIRE_FALSE(std::filesystem::exists(std::string(path + tf)));
        }
        for (const auto &etf : expected_test_filenames) {
            REQUIRE(std::filesystem::exists(std::string(path + etf)));
        }
        REQUIRE_FALSE(std::filesystem::exists(std::string(path + file_expected_to_not_exist)));

        std::filesystem::remove_all(path);
    }

    SECTION("Increment filename - no number at the end")
    {
        std::string filename          = "123_12345_crashdump.hex";
        std::string expected_filename = "123_12345_crashdump.hex.0";
        auto result                   = rotator.incrementFileIndex(std::filesystem::path(filename));
        REQUIRE(result == expected_filename);
    }

    // in case of fail in earlier tests
    std::filesystem::remove_all(path);
}