pmt: The basis of the system for adding features was created and improvements were made.

- The basic header contents of the system, designed to easily add features, were written.
 - The [CLI11](https://github.com/CLIUtils/CLI11) project was included to provide a better experience for the project.
 - Improved logging system.
 - Unnecessary code cleaned.
This commit is contained in:
2025-07-24 17:38:31 +03:00
parent 18b5700cbd
commit 9cd97a085e
16 changed files with 11763 additions and 46 deletions

11527
include/CLI/CLI11.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -22,9 +22,60 @@
#include <string_view>
#include <functional>
#include <vector>
#include <libpartition_map/lib.hpp>
#include <libhelper/lib.hpp>
#include <libpartition_map/lib.hpp>
namespace PartitionManager {} // namespace PartitionManager
#ifdef NEED_BASIC_FUNCTION_CLASSES
#include <memory>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignore "-Wdeprecated-declarations"
#include <CLI/CLI11.hpp>
#pragma GCC diagnostic pop
#endif // #ifdef NEED_BASIC_FUNCTION_CLASSES
namespace PartitionManager {
#ifdef NEED_BASIC_FUNCTION_CLASSES
class basic_function {
/**
* Example variables for writing your function:
* private:
* CLI::App _cmd* = nullptr;
*/
public:
virtual bool init(CLI::App& _app) = 0;
virtual bool run() = 0;
virtual const char* name() = 0;
virtual ~basic_function() = default;
};
class basic_function_manager {
private:
std::vector<std::unique_ptr<basic_function>> _functions;
public:
void registerFunction(std::unique_ptr<basic_function> _func, CLI::App& _app);
void startUsedFunctions();
};
using FunctionBase = basic_function;
using FunctionManager = basic_function_manager;
#endif // #ifdef NEED_BASIC_FUNCTION_CLASSES
namespace Variables {
extern PartitionMap::BuildMap PartMap;
} // namespace Variables
int Main(int argc, char** argv);
std::string getLibVersion();
std::string getAppVersion();
} // namespace PartitionManager
#endif // #ifndef LIBPMT_LIB_HPP

0
src/Lib.cpp Normal file
View File

0
src/Main.cpp Normal file
View File

View File

@@ -0,0 +1,66 @@
/*
Copyright 2025 Yağız Zengin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#define NEED_BASIC_FUNCTION_CLASSES
#include <libpmt/lib.hpp>
namespace PartitionManager {
// Back-up function
class backupFunction : public PartitionManager::FunctionBase {
private:
CLI::App* _cmd = nullptr;
public:
bool init(CLI::App& _app) override;
bool run() override;
const char* name() override;
};
// Image flasher function
class flashFunction : public PartitionManager::FunctionBase {
private:
CLI::App* _cmd = nullptr;
public:
bool init(CLI::App& _app) override;
bool run() override;
const char* name() override;
};
// Eraser function (only the partition content is cleared)
class eraseFunction : public PartitionManager::FunctionBase {
private:
CLI::App* _cmd = nullptr;
public:
bool init(CLI::App& _app) override;
bool run() override;
const char* name() override;
};
// Partition size getter function
class partitionSizeFunction : public PartitionManager::FunctionBase {
private:
CLI::App* _cmd = nullptr;
public:
bool init(CLI::App& _app) override;
bool run() override;
const char* name() override;
};
} // namespace PartitionManager

View File

@@ -26,10 +26,10 @@
#ifndef ONLY_HELPER_MACROS
enum LogLevels {
INFO = (int)'I',
INFO = (int)'I',
WARNING = (int)'W',
ERROR = (int)'E',
ABORT = (int)'A'
ERROR = (int)'E',
ABORT = (int)'A'
};
constexpr mode_t DEFAULT_FILE_PERMS = 0644;
@@ -60,18 +60,6 @@ public:
Logger& operator<<(std::ostream& (*msg)(std::ostream&));
};
class LoggingProperties {
public:
static std::string_view FILE, NAME;
static bool PRINT;
static void set(std::string_view name, std::string_view file);
static void setProgramName(std::string_view name);
static void setLogFile(std::string_view file);
static void setPrinting(int state);
static void reset();
};
// Throwable error class
class Error : public std::exception {
private:
@@ -83,6 +71,20 @@ public:
const char* what() const noexcept override;
};
namespace LoggingProperties {
extern std::string_view FILE, NAME;
extern bool PRINT, DISABLE;
void set(std::string_view name, std::string_view file);
void setProgramName(std::string_view name);
void setLogFile(std::string_view file);
void setPrinting(int state);
void setLoggingState(int state); // Disable/enable logginf
void reset();
} // namespace LoggingProperties
// Checkers
bool hasSuperUser();
bool isExists(const std::string_view entry);
@@ -135,10 +137,15 @@ std::string getLibVersion();
#endif // #ifndef ONLY_HELPER_MACROS
#define HELPER "libhelper"
#define KB(x) (x * 1024) // KB(8) = 8192 (8 * 1024)
#define MB(x) (KB(x) * 1024) // MB(4) = 4194304 (KB(4) * 1024)
#define GB(x) (MB(x) * 1024) // GB(1) = 1073741824 (MB(1) * 1024)
#define TO_MB(x) (x / 1024) // TO_MB(2048) (2048 / 1024)
#define TO_GB(x) (TO_GB(x) / 1024) // TO_GB(1048576) (TO_MB(1048576) / 1024)
#define STYLE_RESET "\033[0m"
#define BOLD "\033[1m"
#define FAINT "\033[2m"
@@ -178,5 +185,14 @@ std::string getLibVersion();
#endif // #ifndef NO_C_TYPE_HANDLERS
#define LOG(level) Helper::Logger(level, Helper::LoggingProperties::FILE.data(), Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
#define LOGN(name, level) Helper::Logger(level, Helper::LoggingProperties::FILE.data(), name, __FILE__, __LINE__)
#define LOGNF(name, file, level) Helper::Logger(level, file, name, __FILE__, __LINE__)
#define LOG_IF(level, condition) \
if (condition) Helper::Logger(level, Helper::LoggingProperties::FILE.data(), Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__)
#define LOGN_IF(name, level, condition) \
if (condition) Helper::Logger(level, Helper::LoggingProperties::FILE.data(), name, __FILE__, __LINE__)
#define LOGNF_IF(name, file, level, condition) \
if (condition) Helper::Logger(level, file, name, __FILE__, __LINE__)
#endif // #ifndef LIBHELPER_LIB_HPP

View File

@@ -25,9 +25,6 @@
namespace Helper {
std::string_view LoggingProperties::FILE = "last_logs.log", LoggingProperties::NAME = "main";
bool LoggingProperties::PRINT = NO;
Error::Error(const char* format, ...)
{
char buf[1024];
@@ -36,6 +33,7 @@ Error::Error(const char* format, ...)
vsnprintf(buf, sizeof(buf), format, args);
va_end(args);
_message = std::string(buf);
LOGN(HELPER, ERROR) << "Error::Error(): " << _message << std::endl;
}
const char* Error::what() const noexcept
@@ -47,6 +45,7 @@ Logger::Logger(LogLevels level, const char* file, const char* name, const char*
Logger::~Logger()
{
if (LoggingProperties::DISABLE) return;
char str[1024];
snprintf(str, sizeof(str), "<%c> [ <prog %s> <on %s:%d> %s %s] %s",
(char)_level,
@@ -58,15 +57,14 @@ Logger::~Logger()
_oss.str().data());
if (!isExists(_logFile)) createFile(_logFile);
FILE* fp = fopen(_logFile, "a");
if (fp != NULL) {
fprintf(fp, "%s", str);
fclose(fp);
}
if (LoggingProperties::PRINT) printf("%s\n", str);
if (_level == ERROR) exit(1);
else if (_level == ABORT) abort();
if (LoggingProperties::PRINT) printf("%s\n", str);
}
Logger& Logger::operator<<(std::ostream& (*msg)(std::ostream&))
@@ -75,22 +73,4 @@ Logger& Logger::operator<<(std::ostream& (*msg)(std::ostream&))
return *this;
}
void LoggingProperties::reset()
{
FILE = "last_logs.log";
NAME = "main";
PRINT = NO;
}
void LoggingProperties::set(std::string_view file, std::string_view name)
{
FILE = file;
NAME = name;
}
void LoggingProperties::setProgramName(std::string_view name) { NAME = name; }
void LoggingProperties::setLogFile(std::string_view file) { FILE = file; }
void LoggingProperties::setPrinting(int state) { PRINT = state; }
} // namespace Helper

View File

@@ -41,17 +41,20 @@ namespace Helper {
bool writeFile(const std::string_view file, const std::string_view text)
{
LOGN(HELPER, INFO) << __func__ << "(): write \"" << text << "\" to " << file << "requested." << std::endl;
FILE* fp = open_file(file, "a");
if (fp == nullptr) return false;
fprintf(fp, "%s", text.data());
fclose(fp);
LOGN(HELPER, INFO) << __func__ << "(): write " << file << " successfull." << std::endl;
return true;
}
std::optional<std::string> readFile(const std::string_view file)
{
LOGN(HELPER, INFO) << __func__ << "(): read " << file << " requested." << std::endl;
FILE* fp = open_file(file, "r");
if (fp == nullptr) return std::nullopt;
@@ -60,11 +63,14 @@ std::optional<std::string> readFile(const std::string_view file)
while (fgets(buffer, sizeof(buffer), fp)) str += buffer;
fclose(fp);
LOGN(HELPER, INFO) << __func__ << "(): read " << file << " successfull, readed text: \"" << str << "\"" << std::endl;
return str;
}
bool copyFile(const std::string_view file, const std::string_view dest)
{
LOGN(HELPER, INFO) << __func__ << "(): copy " << file << " to " << dest << " requested." << std::endl;
int src_fd = open(file.data(), O_RDONLY);
if (src_fd == - 1) {
throw Error("Cannot open %s: %s", file.data(), strerror(errno));
@@ -97,17 +103,21 @@ bool copyFile(const std::string_view file, const std::string_view dest)
return false;
}
LOGN(HELPER, INFO) << __func__ << "(); copy " << file << " to " << dest << " successfull." << std::endl;
return true;
}
bool makeDirectory(const std::string_view path)
{
if (isExists(path)) return false;
LOGN(HELPER, INFO) << __func__ << "(): trying making directory: " << path << std::endl;
return (mkdir(path.data(), DEFAULT_DIR_PERMS) == 0) ? true : false;
}
bool makeRecursiveDirectory(const std::string_view paths)
{
LOGN(HELPER, INFO) << __func__ << "(): make recursive directory requested: " << paths << std::endl;
char tmp[PATH_MAX], *p;
size_t len;
@@ -136,11 +146,14 @@ bool makeRecursiveDirectory(const std::string_view paths)
}
}
LOGN(HELPER, INFO) << __func__ << "(): " << paths << " successfully created." << std::endl;
return true;
}
bool createFile(const std::string_view path)
{
LOGN(HELPER, INFO) << __func__ << "(): create file request: " << path << std::endl;
if (isExists(path)) {
throw Error("%s: is exists", path.data());
return false;
@@ -153,29 +166,35 @@ bool createFile(const std::string_view path)
}
close(fd);
LOGN(HELPER, INFO) << __func__ << "(): create file \"" << path << "\" successfull." << std::endl;
return true;
}
bool createSymlink(const std::string_view entry1, const std::string_view entry2)
{
LOGN(HELPER, INFO) << __func__ << "(): symlink \"" << entry1 << "\" to \"" << entry2 << "\" requested." << std::endl;
int ret = symlink(entry1.data(), entry2.data());
if (ret != 0)
throw Error("Cannot symlink %s: %s", entry2.data(), strerror(errno));
LOGN_IF(HELPER, INFO, ret == 0) << __func__ << "(): \"" << entry1 << "\" symlinked to \"" << entry2 << "\" successfully." << std::endl;
return (ret == 0);
}
bool eraseEntry(const std::string_view entry)
{
LOGN(HELPER, INFO) << __func__ << "(): erase \"" << entry << "\" requested." << std::endl;
int ret = remove(entry.data());
if (ret != 0)
throw Error("Cannot remove %s: %s", entry.data(), strerror(errno));
LOGN_IF(HELPER, INFO, ret == 0) << __func__ << "(): \"" << entry << "\" erased successfully." << std::endl;
return (ret == 0);
}
bool eraseDirectoryRecursive(const std::string_view directory)
{
LOGN(HELPER, INFO) << __func__ << "(): erase recursive requested: " << directory << std::endl;
struct stat buf;
struct dirent *entry;
@@ -220,11 +239,13 @@ bool eraseDirectoryRecursive(const std::string_view directory)
return false;
}
LOGN(HELPER, INFO) << __func__ << "(): \"" << directory << "\" successfully erased." << std::endl;
return true;
}
std::string readSymlink(const std::string_view entry)
{
LOGN(HELPER, INFO) << __func__ << "(): read symlink request: " << entry << std::endl;
char target[PATH_MAX];
ssize_t len = readlink(entry.data(), target, (sizeof(target) - 1));
if (len == -1) {
@@ -233,11 +254,13 @@ std::string readSymlink(const std::string_view entry)
}
target[len] = '\0';
LOGN(HELPER, INFO) << __func__ << "(): \"" << entry << "\" symlink to \"" << target << "\"" << std::endl;
return target;
}
size_t fileSize(const std::string_view file)
{
LOGN(HELPER, INFO) << __func__ << "(): get file size request: " << file << std::endl;
struct stat st;
if (stat(file.data(), &st) != 0) return false;
return static_cast<size_t>(st.st_size);

View File

@@ -27,6 +27,7 @@ namespace Helper {
std::optional<std::string> sha256Of(const std::string_view path)
{
LOGN(HELPER, INFO) << __func__ << "(): get sha256 of \"" << path << "\" request." << std::endl;
if (!fileIsExists(path)) {
throw Error("Is not exists or not file: %s", path.data());
return std::nullopt;
@@ -40,14 +41,17 @@ std::optional<std::string> sha256Of(const std::string_view path)
std::vector<unsigned char> hash(picosha2::k_digest_size);
picosha2::hash256(path, hash.begin(), hash.end());
LOGN(HELPER, INFO) << __func__ << "(): get sha256 of \"" << path << "\" successfull." << std::endl;
return picosha2::bytes_to_hex_string(hash.begin(), hash.end());
}
bool sha256Compare(const std::string_view file1, const std::string_view file2)
{
LOGN(HELPER, INFO) << __func__ << "(): comparing sha256 signatures of input files." << std::endl;
auto f1 = sha256Of(file1);
auto f2 = sha256Of(file2);
if (f1->empty() || f2->empty()) return false;
LOGN_IF(HELPER, INFO, *f1 == *f2) << "(): input files is contains same sha256 signature." << std::endl;
return (*f1 == *f2);
}

View File

@@ -17,6 +17,7 @@
#include <iostream>
#include <memory>
#include <string>
#include <string_view>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -27,14 +28,50 @@
#include <generated/buildInfo.hpp>
namespace Helper {
namespace LoggingProperties {
std::string_view FILE = "last_logs.log", NAME = "main";
bool PRINT = NO, DISABLE = NO;
void reset()
{
FILE = "last_logs.log";
NAME = "main";
PRINT = NO;
}
void set(std::string_view file, std::string_view name)
{
if (file.data() != nullptr) FILE = file;
if (name.data() != nullptr) NAME = name;
}
void setProgramName(std::string_view name) { NAME = name; }
void setLogFile(std::string_view file) { FILE = file; }
void setPrinting(int state)
{
if (state == 1 || state == 0) PRINT = state;
else PRINT = NO;
}
void setLoggingState(int state)
{
if (state == 1 || state == 0) DISABLE = state;
else DISABLE = NO;
}
} // namespace LoggingProperties
bool runCommand(const std::string_view cmd)
{
LOGN(HELPER, INFO) << __func__ << "(): run command request: " << cmd << std::endl;
return (system(cmd.data()) == 0) ? true : false;
}
bool confirmPropt(const std::string_view message)
{
LOGN(HELPER, INFO) << __func__ << "(): create confirm propt request. Creating." << std::endl;
char p;
printf("%s [ y / n ]: ", message.data());
@@ -85,6 +122,7 @@ std::string currentTime()
std::string runCommandWithOutput(const std::string_view cmd)
{
LOGN(HELPER, INFO) << __func__ << "(): run command and catch out request: " << cmd << std::endl;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.data(), "r"), pclose);
if (!pipe) {
throw Error("Cannot run command: %s", cmd.data());

View File

@@ -20,7 +20,6 @@ set(LIBPARTITION_MAP_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/PartitionMap.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Type.cpp
)
set(LIBPARTITION_MAP_FLAGS -DLOG_FILE="/storage/emulated/0/.last_pmt.log" -DPROGRAM_NAME="libpartition_map")
# Add targets
add_library(partition_map_shared SHARED ${LIBPARTITION_MAP_SOURCES})
@@ -31,10 +30,7 @@ add_executable(libpartition_map_test tests/test.cpp)
set_target_properties(partition_map_shared PROPERTIES OUTPUT_NAME "partition_map")
set_target_properties(partition_map_static PROPERTIES OUTPUT_NAME "partition_map")
# Set compiler flags
target_compile_options(partition_map_shared PRIVATE ${LIBPARTITION_MAP_FLAGS})
target_compile_options(partition_map_static PRIVATE ${LIBPARTITION_MAP_FLAGS})
target_compile_options(libpartition_map_test PRIVATE ${LIBPARTITION_MAP_FLAGS})
# Set linker flags
target_link_options(libpartition_map_test PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib")
target_link_options(partition_map_shared PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib")
target_link_libraries(libpartition_map_test PRIVATE partition_map_shared PRIVATE helper_shared)

View File

@@ -325,4 +325,6 @@ using Map = basic_partition_map_builder;
} // namespace PartitionMap
#define MAP "libpartition_map"
#endif // #ifndef LIBPARTITION_MAP_LIB_HPP

View File

@@ -55,12 +55,14 @@ Map_t basic_partition_map_builder::_build_map(std::string_view path, bool logica
return a.path().filename() < b.path().filename();
});
LOGN_IF(MAP, WARNING, entries.empty()) << __func__ << "(): " << path << "is exists but generated vector is empty (std::vector<std::filesystem::directory_entry>)." << std::endl;
for (const auto& entry : entries) {
if (entry.path().filename() != "by-uuid"
&& std::string(entry.path()).find("com.") == std::string::npos)
map.insert(entry.path().filename().string(), _get_size(entry.path()), logical);
}
LOGN(MAP, INFO) << std::boolalpha << __func__ << "(): Map generated successfully. is_logical_map=" << logical << std::endl;
return map;
}
@@ -94,6 +96,8 @@ uint64_t basic_partition_map_builder::_get_size(const std::string path)
basic_partition_map_builder::basic_partition_map_builder()
{
LOGN(MAP, INFO) << __func__ << "(): default constructor called. Starting build." << std::endl;
for (const auto& path : defaultEntryList) {
if (std::filesystem::exists(path)) {
_current_map = _build_map(path);
@@ -110,12 +114,15 @@ basic_partition_map_builder::basic_partition_map_builder()
if (_current_map.empty())
throw Error("Cannot build map by any default search entry.");
LOGN(MAP, INFO) << __func__ << "(): default constructor successfully ended work." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
}
basic_partition_map_builder::basic_partition_map_builder(const std::string_view path)
{
LOGN(MAP, INFO) << __func__ << "(): argument-based constructor called. Starting build." << std::endl;
if (std::filesystem::exists(path)) {
_is_real_block_dir(path);
_current_map = _build_map(path);
@@ -124,6 +131,7 @@ basic_partition_map_builder::basic_partition_map_builder(const std::string_view
} else
throw Error("Cannot find directory: %s. Cannot build partition map!", path.data());
LOGN(MAP, INFO) << __func__ << "(): argument-based constructor successfully ended work." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
}
@@ -150,6 +158,7 @@ void basic_partition_map_builder::clear()
bool basic_partition_map_builder::readDirectory(const std::string_view path)
{
_map_builded = false;
LOGN(MAP, INFO) << __func__ << "(): read " << path << " directory request." << std::endl;
if (std::filesystem::exists(path)) {
if (!_is_real_block_dir(path)) return false;
@@ -161,6 +170,7 @@ bool basic_partition_map_builder::readDirectory(const std::string_view path)
} else
throw Error("Cannot find directory: %s. Cannot build partition map!", path.data());
LOGN(MAP, INFO) << __func__ << "(): read " << path << " successfull." << std::endl;
_insert_logicals(_build_map("/dev/block/mapper", true));
_map_builded = true;
return true;

View File

@@ -142,13 +142,16 @@ bool basic_partition_map::insert(const std::string name, uint64_t size, bool log
if (_count == _capacity) _resize_map();
_data[_count++] = {name, {size, logical}};
LOGN(MAP, INFO) << std::boolalpha << __func__ << "(): partition " << name << " inserted (size=" << size << ", is_logical=" << logical << ")." << std::endl;
return true;
}
void basic_partition_map::merge(const basic_partition_map& map)
{
LOGN(MAP, INFO) << __func__ << "(): map merge request." << std::endl;
for (const auto& [name, props] : map)
insert(name, props.size, props.isLogical);
LOGN(MAP, INFO) << __func__ << "(): map merged successfully." << std::endl;
}
uint64_t basic_partition_map::get_size(const std::string_view name) const
@@ -203,6 +206,7 @@ bool basic_partition_map::empty() const
void basic_partition_map::clear()
{
LOGN(MAP, INFO) << __func__ << "(): map clean requested. Map is empty now." << std::endl;
delete[] _data;
_count = 0;
_capacity = 6;