pmt: Improve performance and functions

- Added two new functions
 - Improved functions
 - Reformatted code (scripts and src/ include/)
 - Increased processing speed with multi-threading
This commit is contained in:
2025-08-07 14:49:24 +03:00
parent 6294482b39
commit 8b3e886eee
17 changed files with 678 additions and 453 deletions

View File

@@ -23,6 +23,9 @@ add_compile_options(-Wall -Werror -Wno-deprecated-declarations)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_compile_options(-gdwarf-5 -fsanitize=address -fstack-protector) add_compile_options(-gdwarf-5 -fsanitize=address -fstack-protector)
add_link_options(-fsanitize=address) add_link_options(-fsanitize=address)
else()
add_compile_options(-Os)
add_link_options(-s)
endif() endif()
# Add pmt's CMake module(s) # Add pmt's CMake module(s)

View File

@@ -57,13 +57,15 @@ build()
cmake -B $BUILD_64 -S . $1 \ cmake -B $BUILD_64 -S . $1 \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \ -DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=$ANDROID_PLATFORM -DANDROID_PLATFORM=$ANDROID_PLATFORM \
-DANDROID_STL=c++_static
echo "Configuring for armeabi-v7a..." echo "Configuring for armeabi-v7a..."
cmake -B $BUILD_32 -S . $1 \ cmake -B $BUILD_32 -S . $1 \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=armeabi-v7a \ -DANDROID_ABI=armeabi-v7a \
-DANDROID_PLATFORM=$ANDROID_PLATFORM -DANDROID_PLATFORM=$ANDROID_PLATFORM \
-DANDROID_STL=c++_static
echo "Building arm64-v8a artifacts..." echo "Building arm64-v8a artifacts..."
cmake --build $BUILD_64 cmake --build $BUILD_64

View File

@@ -34,42 +34,43 @@
#define PMTF "libpmt-function-manager" #define PMTF "libpmt-function-manager"
namespace PartitionManager { namespace PartitionManager {
// All function classes must inherit from this class.
class basic_function {
public:
CLI::App *cmd = nullptr;
// All function classes must inherit from this class. virtual bool init(CLI::App &_app) = 0;
class basic_function {
public:
CLI::App* cmd = nullptr;
virtual bool init(CLI::App& _app) = 0;
virtual bool run() = 0; virtual bool run() = 0;
[[nodiscard]] virtual bool isUsed() const = 0; [[nodiscard]] virtual bool isUsed() const = 0;
[[nodiscard]] virtual const char* name() const = 0; [[nodiscard]] virtual const char *name() const = 0;
virtual ~basic_function() = default; virtual ~basic_function() = default;
}; };
// A class for function management. // A class for function management.
class basic_function_manager final { class basic_function_manager final {
private: private:
std::vector<std::unique_ptr<basic_function>> _functions; std::vector<std::unique_ptr<basic_function> > _functions;
public: public:
void registerFunction(std::unique_ptr<basic_function> _func, CLI::App& _app); void registerFunction(std::unique_ptr<basic_function> _func, CLI::App &_app);
[[nodiscard]] bool handleAll() const; [[nodiscard]] bool handleAll() const;
}; };
// Sets logs file automatically // Sets logs file automatically
class logSetter final { public: logSetter(); }; class logSetter final { public: logSetter(); };
class basic_variables final { class basic_variables final {
private: private:
logSetter setLogSetting; logSetter setLogSetting;
public: public:
basic_variables(); basic_variables();
~basic_variables(); ~basic_variables();
PartitionMap::BuildMap* PartMap; PartitionMap::BuildMap *PartMap;
std::string searchPath, logFile; std::string searchPath, logFile;
bool onLogical; bool onLogical;
@@ -77,30 +78,38 @@ public:
bool verboseMode; bool verboseMode;
bool viewVersion; bool viewVersion;
bool forceProcess; bool forceProcess;
}; };
using FunctionBase = basic_function; using FunctionBase = basic_function;
using FunctionManager = basic_function_manager; using FunctionManager = basic_function_manager;
using VariableTable = basic_variables; using VariableTable = basic_variables;
using Error = Helper::Error; using Error = Helper::Error;
extern VariableTable* Variables; extern VariableTable *Variables;
int Main(int argc, char** argv); int Main(int argc, char **argv);
// Print messages if not using quiet mode // Print messages if not using quiet mode
__attribute__((format(printf, 1, 2))) __attribute__((format(printf, 1, 2)))
void print(const char* format, ...); void print(const char *format, ...);
// If there is a delimiter in the string, CLI::detail::split returns; if not, an empty vector is returned. And checks duplicate arguments. // Format it input and return
std::vector<std::string> splitIfHasDelim(const std::string& s, char delim, bool checkForBadUsage = false); __attribute__((format(printf, 1, 2)))
std::string format(const char *format, ...);
// Process vectors with input strings. Use for [flag(s)]-[other flag(s)] situations // If there is a delimiter in the string, CLI::detail::split returns; if not, an empty vector is returned. And checks duplicate arguments.
void processCommandLine(std::vector<std::string>& vec1, std::vector<std::string>& vec2, const std::string& s1, const std::string& s2, char delim, bool checkForBadUsage = false); std::vector<std::string> splitIfHasDelim(const std::string &s, char delim, bool checkForBadUsage = false);
std::string getLibVersion(); // Process vectors with input strings. Use for [flag(s)]-[other flag(s)] situations
std::string getAppVersion(); // Not Android app version (an Android app is planned!), tells pmt version. void processCommandLine(std::vector<std::string> &vec1, std::vector<std::string> &vec2, const std::string &s1,
const std::string &s2, char delim, bool checkForBadUsage = false);
// Setting ups buffer size
void setupBufferSize(int &size, const std::string &partition);
std::string getLibVersion();
std::string getAppVersion(); // Not Android app version (an Android app is planned!), tells pmt version.
} // namespace PartitionManager } // namespace PartitionManager
#endif // #ifndef LIBPMT_LIB_HPP #endif // #ifndef LIBPMT_LIB_HPP

View File

@@ -23,6 +23,8 @@ set(PMT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/functions/FlashFunction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/FlashFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/InfoFunction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/InfoFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/PartitionSizeFunction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/PartitionSizeFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/RealPathFunction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/functions/RealLinkPathFunction.cpp
) )
# Add pmt # Add pmt
@@ -34,10 +36,3 @@ target_link_libraries(pmt PRIVATE helper_shared PRIVATE partition_map_shared)
target_link_libraries(pmt_static PRIVATE helper_static PRIVATE partition_map_static) target_link_libraries(pmt_static PRIVATE helper_static PRIVATE partition_map_static)
target_link_options(pmt PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib") target_link_options(pmt PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib")
target_link_options(pmt_static PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib") target_link_options(pmt_static PRIVATE "LINKER:-rpath,/data/data/com.termux/files/usr/lib")
if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
target_compile_options(pmt PRIVATE -Os)
target_compile_options(pmt_static PRIVATE -Os)
target_link_options(pmt PRIVATE -s)
target_link_options(pmt_static PRIVATE -s)
endif()

View File

@@ -21,44 +21,47 @@
#include <PartitionManager/PartitionManager.hpp> #include <PartitionManager/PartitionManager.hpp>
namespace PartitionManager { namespace PartitionManager {
std::vector<std::string> splitIfHasDelim(const std::string &s, const char delim, const bool checkForBadUsage) {
std::vector<std::string> splitIfHasDelim(const std::string& s, const char delim, const bool checkForBadUsage)
{
if (s.find(delim) == std::string::npos) return {}; if (s.find(delim) == std::string::npos) return {};
auto vec = CLI::detail::split(s, delim); auto vec = CLI::detail::split(s, delim);
if (checkForBadUsage) { if (checkForBadUsage) {
std::unordered_set<std::string> set; std::unordered_set<std::string> set;
for (const auto& str : vec) { for (const auto &str: vec) {
if (set.find(str) != set.end()) throw CLI::ValidationError("Duplicate element in your inputs!"); if (set.find(str) != set.end()) throw CLI::ValidationError("Duplicate element in your inputs!");
set.insert(str); set.insert(str);
} }
} }
return vec; return vec;
} }
void processCommandLine(std::vector<std::string>& vec1, std::vector<std::string>& vec2, const std::string& s1, const std::string& s2, const char delim, const bool checkForBadUsage) void setupBufferSize(int &size, const std::string &partition) {
{ if (Variables->PartMap->sizeOf(partition) % size != 0) {
print("%sWARNING%s: Specified buffer size is invalid! Using 1 byte as buffer size.", YELLOW, STYLE_RESET);
size = 1;
}
}
void processCommandLine(std::vector<std::string> &vec1, std::vector<std::string> &vec2, const std::string &s1,
const std::string &s2, const char delim, const bool checkForBadUsage) {
vec1 = splitIfHasDelim(s1, delim, checkForBadUsage); vec1 = splitIfHasDelim(s1, delim, checkForBadUsage);
vec2 = splitIfHasDelim(s2, delim, checkForBadUsage); vec2 = splitIfHasDelim(s2, delim, checkForBadUsage);
if (vec1.empty() && !s1.empty()) vec1.push_back(s1); if (vec1.empty() && !s1.empty()) vec1.push_back(s1);
if (vec2.empty() && !s2.empty()) vec2.push_back(s2); if (vec2.empty() && !s2.empty()) vec2.push_back(s2);
} }
void basic_function_manager::registerFunction(std::unique_ptr<basic_function> _func, CLI::App& _app) void basic_function_manager::registerFunction(std::unique_ptr<basic_function> _func, CLI::App &_app) {
{
LOGN(PMTF, INFO) << "registering function: " << _func->name() << std::endl; LOGN(PMTF, INFO) << "registering function: " << _func->name() << std::endl;
if (!_func->init(_app)) throw Error("Cannot init function: %s\n", _func->name()); if (!_func->init(_app)) throw Error("Cannot init function: %s\n", _func->name());
_functions.push_back(std::move(_func)); _functions.push_back(std::move(_func));
LOGN(PMTF, INFO) << _functions.back()->name() << " successfully registered." << std::endl; LOGN(PMTF, INFO) << _functions.back()->name() << " successfully registered." << std::endl;
} }
bool basic_function_manager::handleAll() const bool basic_function_manager::handleAll() const {
{
LOGN(PMTF, INFO) << "running caught function commands in command-line." << std::endl; LOGN(PMTF, INFO) << "running caught function commands in command-line." << std::endl;
for (const auto& func : _functions) { for (const auto &func: _functions) {
if (func->isUsed()) { if (func->isUsed()) {
LOGN(PMTF, INFO) << func->name() << " is calling because used in command-line." << std::endl; LOGN(PMTF, INFO) << func->name() << " is calling because used in command-line." << std::endl;
return func->run(); return func->run();
@@ -68,6 +71,5 @@ bool basic_function_manager::handleAll() const
LOGN(PMTF, INFO) << "not found any used function from command-line." << std::endl; LOGN(PMTF, INFO) << "not found any used function from command-line." << std::endl;
print("Target progress is not specified. Specify a progress."); print("Target progress is not specified. Specify a progress.");
return false; return false;
} }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -23,38 +23,42 @@
#include "functions/functions.hpp" #include "functions/functions.hpp"
namespace PartitionManager { namespace PartitionManager {
auto Variables = new VariableTable();
auto Variables = new VariableTable(); logSetter::logSetter() { Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log"); }
logSetter::logSetter() { Helper::LoggingProperties::setLogFile("/sdcard/Documents/last_pmt_logs.log"); } basic_variables::~basic_variables() { delete PartMap; }
basic_variables::~basic_variables() { delete PartMap; } basic_variables::basic_variables() : PartMap(new PartitionMap::BuildMap()),
basic_variables::basic_variables() : PartMap(new PartitionMap::BuildMap()),
logFile("/sdcard/Documents/last_pmt_logs.log"), logFile("/sdcard/Documents/last_pmt_logs.log"),
onLogical(false), onLogical(false),
quietProcess(false), quietProcess(false),
verboseMode(false), verboseMode(false),
viewVersion(false), viewVersion(false),
forceProcess(false) forceProcess(false)
{} {}
int Main(int argc, char** argv) int Main(int argc, char **argv) {
{ try {
try { // try-catch start // try-catch start
CLI::App AppMain{"Partition Manager Tool"}; CLI::App AppMain{"Partition Manager Tool"};
FunctionManager FuncManager; FunctionManager FuncManager;
AppMain.fallthrough(true);
AppMain.set_help_all_flag("--help-all", "Print full help message"); AppMain.set_help_all_flag("--help-all", "Print full help message");
AppMain.footer("Partition Manager Tool is written by YZBruh\nThis project licensed under Apache 2.0 license\nReport bugs to https://github.com/ShawkTeam/pmt-renovated/issues"); AppMain.footer("Partition Manager Tool is written by YZBruh\nThis project licensed under Apache 2.0 license\nReport bugs to https://github.com/ShawkTeam/pmt-renovated/issues");
AppMain.add_option("-S,--search-path", Variables->searchPath, "Set partition search path")->check([&](const std::string& val) { AppMain.add_option("-S,--search-path", Variables->searchPath, "Set partition search path")->check(
if (val.find("/block/") == std::string::npos) throw CLI::ValidationError("Partition search path is unexpected! Couldn't find 'block' in input path!"); [&](const std::string &val) {
if (val.find("/block") == std::string::npos) throw CLI::ValidationError(
"Partition search path is unexpected! Couldn't find 'block' in input path!");
return std::string(); return std::string();
}); });
AppMain.add_option("-L,--log-file", Variables->logFile, "Set log file"); AppMain.add_option("-L,--log-file", Variables->logFile, "Set log file");
AppMain.add_flag("-f,--force", Variables->forceProcess, "Force process to be processed"); AppMain.add_flag("-f,--force", Variables->forceProcess, "Force process to be processed");
AppMain.add_flag("-l,--logical", Variables->onLogical, "Specify that the target partition is dynamic"); AppMain.add_flag("-l,--logical", Variables->onLogical, "Specify that the target partition is dynamic");
AppMain.add_flag("-q,--quiet", Variables->quietProcess, "Quiet process"); AppMain.add_flag("-q,--quiet", Variables->quietProcess, "Quiet process");
AppMain.add_flag("-V,--verbose", Variables->verboseMode, "Detailed information is written on the screen while the transaction is being carried out"); AppMain.add_flag("-V,--verbose", Variables->verboseMode,
"Detailed information is written on the screen while the transaction is being carried out");
AppMain.add_flag("-v,--version", Variables->viewVersion, "Print version and exit"); AppMain.add_flag("-v,--version", Variables->viewVersion, "Print version and exit");
if (argc < 2) { if (argc < 2) {
@@ -67,6 +71,8 @@ try { // try-catch start
FuncManager.registerFunction(std::make_unique<eraseFunction>(), AppMain); FuncManager.registerFunction(std::make_unique<eraseFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<partitionSizeFunction>(), AppMain); FuncManager.registerFunction(std::make_unique<partitionSizeFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<infoFunction>(), AppMain); FuncManager.registerFunction(std::make_unique<infoFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<realPathFunction>(), AppMain);
FuncManager.registerFunction(std::make_unique<realLinkPathFunction>(), AppMain);
CLI11_PARSE(AppMain, argc, argv); CLI11_PARSE(AppMain, argc, argv);
@@ -81,39 +87,46 @@ try { // try-catch start
if (!Variables->PartMap && Variables->searchPath.empty()) if (!Variables->PartMap && Variables->searchPath.empty())
throw Error("No default search entries were found. Specify a search directory with -S (--search-path)"); throw Error("No default search entries were found. Specify a search directory with -S (--search-path)");
if (!Helper::hasSuperUser()) throw Error("This program requires super-user privileges!");
return FuncManager.handleAll() == true ? EXIT_SUCCESS : EXIT_FAILURE; return FuncManager.handleAll() == true ? EXIT_SUCCESS : EXIT_FAILURE;
} catch (Helper::Error &error) {
// catch Helper::Error
} catch (Helper::Error &error) { // catch Helper::Error if (!Variables->quietProcess) fprintf(stderr, "%s%sERROR(S) OCCURRED%s:\n%s", RED, BOLD, STYLE_RESET,
error.what());
if (!Variables->quietProcess) fprintf(stderr, "%s: %s.\n", argv[0], error.what());
delete Variables; delete Variables;
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (CLI::Error &error) {
} catch (CLI::Error &error) { // catch CLI::Error // catch CLI::Error
delete Variables; delete Variables;
fprintf(stderr, "%s: FLAG PARSE ERROR: %s\n", argv[0], error.what()); fprintf(stderr, "%s: %s%sFLAG PARSE ERROR:%s %s\n", argv[0], RED, BOLD, STYLE_RESET, error.what());
return EXIT_FAILURE; return EXIT_FAILURE;
} // try-catch block end
}
} // try-catch block end void print(const char *format, ...) {
}
void print(const char* format, ...)
{
va_list args; va_list args;
va_start(args, format); va_start(args, format);
if (!Variables->quietProcess) vfprintf(stdout, format, args); if (!Variables->quietProcess) vfprintf(stdout, format, args);
va_end(args); va_end(args);
} }
std::string getLibVersion() std::string format(const char *format, ...) {
{ va_list args;
va_start(args, format);
char str[1024];
vsnprintf(str, sizeof(str), format, args);
va_end(args);
return str;
}
std::string getLibVersion() {
MKVERSION(PMT); MKVERSION(PMT);
} }
std::string getAppVersion() std::string getAppVersion() {
{
MKVERSION(PMTE); MKVERSION(PMTE);
} }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2025 Yağız Zengin Copyright 2025 Yağız Zengin
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -18,62 +18,47 @@ Copyright 2025 Yağız Zengin
#include <fcntl.h> #include <fcntl.h>
#include <cerrno> #include <cerrno>
#include <unistd.h> #include <unistd.h>
#include <future>
#include <chrono>
#include <PartitionManager/PartitionManager.hpp> #include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp" #include "functions.hpp"
#define BFUN "backupFunction" #define BFUN "backupFunction"
namespace PartitionManager { namespace PartitionManager {
pair backupFunction::runAsync(const std::string &partitionName, const std::string &outputName, int bufferSize) {
if (!Variables->PartMap->hasPartition(partitionName)) return {
format("Couldn't find partition: %s", partitionName.data()), false
};
bool backupFunction::init(CLI::App &_app) LOGN(BFUN, INFO) << "back upping " << partitionName << " as " << outputName << std::endl;
{
LOGN(BFUN, INFO) << "Initializing variables of backup function." << std::endl;
cmd = _app.add_subcommand("backup", "Backup partition(s) to file(s)");
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")->required();
cmd->add_option("output(s)", rawOutputNames, "File name(s) (or path(s)) to save the partition image(s)");
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for reading partition(s) and writing to file(s)");
return true;
}
bool backupFunction::run()
{
processCommandLine(partitions, outputNames, rawPartitions, rawOutputNames, ',', true);
if (!outputNames.empty() && partitions.size() != outputNames.size())
throw CLI::ValidationError("You must provide an output name(s) as long as the partition name(s)");
for (size_t i = 0; i < partitions.size(); i++) {
std::string partitionName = partitions[i];
std::string outputName = outputNames.empty() ? partitionName + ".img" : outputNames[i];
LOGN(BFUN, INFO) << "backupping " << partitionName << " as " << outputName << std::endl;
if (!Variables->PartMap->hasPartition(partitionName))
throw Error("Couldn't find partition: %s", partitionName.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
if (Variables->forceProcess) LOGN(BFUN, WARNING) << "Partition " << partitionName << " is exists but not logical. Ignoring (from --force, -f)." << std::endl; if (Variables->forceProcess)
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()); LOGN(BFUN, WARNING) << "Partition " << partitionName <<
" is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else return {
format("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()), false
};
} }
if (Helper::fileIsExists(outputName) && !Variables->forceProcess) throw Error("%s is exists. Remove it, or use --force (-f) flag.", outputName.data()); if (Helper::fileIsExists(outputName) && !Variables->forceProcess) return {
else LOGN(BFUN, INFO) << outputName << " is exists but ignoring (from --force, -f). Re-creating." << std::endl; format("%s is exists. Remove it, or use --force (-f) flag.", outputName.data()), false
};
bufferSize = (Variables->PartMap->sizeOf(partitionName) % bufferSize == 0) ? bufferSize : 1; setupBufferSize(bufferSize, partitionName);
LOGN(BFUN, INFO) << "Using buffer size: " << bufferSize << std::endl; LOGN(BFUN, INFO) << "Using buffer size (for back upping " << partitionName << "): " << bufferSize << std::endl;
const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_RDONLY); const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_RDONLY);
if (pfd < 0) if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false};
throw Error("Can't open partition: %s: %s", partitionName.data(), strerror(errno));
const int ffd = open(outputName.data(), O_WRONLY | O_CREAT | O_TRUNC, 0644); const int ffd = open(outputName.data(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (ffd < 0) { if (ffd < 0) {
close(pfd); close(pfd);
throw Error("Can't create/open output file %s: %s", outputName.data(), strerror(errno)); return {format("Can't create/open output file %s: %s", outputName.data(), strerror(errno)), false};
} }
LOGN(BFUN, INFO) << "Writing partition " << partitionName << " to file: " << outputName << std::endl; LOGN(BFUN, INFO) << "Writing partition " << partitionName << " to file: " << outputName << std::endl;
auto* buffer = new char[bufferSize]; auto *buffer = new char[bufferSize];
memset(buffer, 0x00, bufferSize); memset(buffer, 0x00, bufferSize);
ssize_t bytesRead; ssize_t bytesRead;
while ((bytesRead = read(pfd, buffer, bufferSize)) > 0) { while ((bytesRead = read(pfd, buffer, bufferSize)) > 0) {
@@ -81,21 +66,61 @@ bool backupFunction::run()
close(pfd); close(pfd);
close(ffd); close(ffd);
delete[] buffer; delete[] buffer;
throw Error("Can't write partition to output file %s: %s", outputName.data(), strerror(errno)); return {
format("Can't write partition to output file %s: %s", outputName.data(), strerror(errno)), false
};
} }
} }
close(pfd); close(pfd);
close(ffd); close(ffd);
delete[] buffer; delete[] buffer;
return {format("%s partition successfully back upped to %s", partitionName.data(), outputName.data()), true};
} }
LOGN(BFUN, INFO) << "Operation successfully completed." << std::endl; bool backupFunction::init(CLI::App &_app) {
LOGN(BFUN, INFO) << "Initializing variables of backup function." << std::endl;
cmd = _app.add_subcommand("backup", "Backup partition(s) to file(s)");
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")->required();
cmd->add_option("output(s)", rawOutputNames, "File name(s) (or path(s)) to save the partition image(s)");
cmd->add_option("-O,--output-directory", outputDirectory, "Directory to save the partition image(s)")->check(
CLI::ExistingDirectory);
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for reading partition(s) and writing to file(s)");
return true; return true;
} }
bool backupFunction::isUsed() const { return cmd->parsed(); } bool backupFunction::run() {
processCommandLine(partitions, outputNames, rawPartitions, rawOutputNames, ',', true);
if (!outputNames.empty() && partitions.size() != outputNames.size())
throw CLI::ValidationError("You must provide an output name(s) as long as the partition name(s)");
const char* backupFunction::name() const { return BFUN; } std::vector<std::future<pair> > futures;
for (size_t i = 0; i < partitions.size(); i++) {
std::string partitionName = partitions[i];
std::string outputName = outputNames.empty() ? partitionName + ".img" : outputNames[i];
if (!outputDirectory.empty()) outputName.insert(0, outputDirectory + '/');
futures.push_back(std::async(std::launch::async, runAsync, partitionName, outputName, bufferSize));
LOGN(BFUN, INFO) << "Created thread backup upping " << partitionName << std::endl;
}
std::string end;
bool endResult = true;
for (auto &future: futures) {
auto [fst, snd] = future.get();
if (!snd) { end += fst + '\n'; endResult = false; }
else print("%s\n", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str());
LOGN(BFUN, INFO) << "Operation successfully completed." << std::endl;
return endResult;
}
bool backupFunction::isUsed() const { return cmd->parsed(); }
const char *backupFunction::name() const { return BFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -17,6 +17,7 @@ Copyright 2025 Yağız Zengin
#include <cstdlib> #include <cstdlib>
#include <fcntl.h> #include <fcntl.h>
#include <cerrno> #include <cerrno>
#include <future>
#include <unistd.h> #include <unistd.h>
#include <PartitionManager/PartitionManager.hpp> #include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp" #include "functions.hpp"
@@ -24,38 +25,31 @@ Copyright 2025 Yağız Zengin
#define EFUN "eraseFunction" #define EFUN "eraseFunction"
namespace PartitionManager { namespace PartitionManager {
pair eraseFunction::runAsync(const std::string &partitionName, int bufferSize) {
bool eraseFunction::init(CLI::App &_app) if (!Variables->PartMap->hasPartition(partitionName)) return {
{ format("Couldn't find partition: %s", partitionName.data()), false
LOGN(EFUN, INFO) << "Initializing variables of erase function." << std::endl; };
cmd = _app.add_subcommand("erase", "Writes zero bytes to partition(s)");
cmd->add_option("partition(s)", partitions, "Partition name(s)")->required()->delimiter(',');
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for writing zero bytes to partition(s)");
return true;
}
bool eraseFunction::run()
{
for (const auto& partitionName : partitions) {
if (!Variables->PartMap->hasPartition(partitionName))
throw Error("Couldn't find partition: %s", partitionName.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
if (Variables->forceProcess) LOGN(EFUN, WARNING) << "Partition " << partitionName << " is exists but not logical. Ignoring (from --force, -f)." << std::endl; if (Variables->forceProcess)
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()); LOGN(EFUN, WARNING) << "Partition " << partitionName <<
" is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else return {
format("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()), false
};
} }
bufferSize = (Variables->PartMap->sizeOf(partitionName) % bufferSize == 0) ? bufferSize : 1; setupBufferSize(bufferSize, partitionName);
LOGN(EFUN, INFO) << "Using buffer size: " << bufferSize; LOGN(EFUN, INFO) << "Using buffer size: " << bufferSize;
const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_WRONLY); const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_WRONLY);
if (pfd < 0) if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false};
throw Error("Can't open partition: %s: %s", partitionName.data(), strerror(errno));
if (!Variables->forceProcess) Helper::confirmPropt("Are you sure you want to continue? This could render your device unusable! Do not continue if you do not know what you are doing!"); if (!Variables->forceProcess) Helper::confirmPropt(
"Are you sure you want to continue? This could render your device unusable! Do not continue if you do not know what you are doing!");
LOGN(EFUN, INFO) << "Writing zero bytes to partition: " << partitionName << std::endl; LOGN(EFUN, INFO) << "Writing zero bytes to partition: " << partitionName << std::endl;
auto* buffer = new char[bufferSize]; auto *buffer = new char[bufferSize];
memset(buffer, 0x00, bufferSize); memset(buffer, 0x00, bufferSize);
ssize_t bytesWritten = 0; ssize_t bytesWritten = 0;
const uint64_t partitionSize = Variables->PartMap->sizeOf(partitionName); const uint64_t partitionSize = Variables->PartMap->sizeOf(partitionName);
@@ -67,20 +61,48 @@ bool eraseFunction::run()
if (const ssize_t result = write(pfd, buffer, toWrite); result == -1) { if (const ssize_t result = write(pfd, buffer, toWrite); result == -1) {
close(pfd); close(pfd);
delete[] buffer; delete[] buffer;
throw Error("Can't write zero bytes to partition: %s: %s", partitionName.data(), strerror(errno)); return {
format("Can't write zero bytes to partition: %s: %s", partitionName.data(), strerror(errno)), false
};
} else bytesWritten += result; } else bytesWritten += result;
} }
close(pfd); close(pfd);
delete[] buffer; delete[] buffer;
return {format("Successfully wrote zero bytes to the %s partition\n", partitionName.data()), true};
} }
LOGN(EFUN, INFO) << "Operation successfully completed." << std::endl; bool eraseFunction::init(CLI::App &_app) {
LOGN(EFUN, INFO) << "Initializing variables of erase function." << std::endl;
cmd = _app.add_subcommand("erase", "Writes zero bytes to partition(s)");
cmd->add_option("partition(s)", partitions, "Partition name(s)")->required()->delimiter(',');
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for writing zero bytes to partition(s)");
return true; return true;
} }
bool eraseFunction::isUsed() const { return cmd->parsed(); } bool eraseFunction::run() {
std::vector<std::future<pair> > futures;
for (const auto &partitionName: partitions) {
futures.push_back(std::async(std::launch::async, runAsync, partitionName, bufferSize));
LOGN(EFUN, INFO) << "Created thread for writing zero bytes to " << partitionName << std::endl;
}
const char* eraseFunction::name() const { return EFUN; } std::string end;
bool endResult = true;
for (auto &future: futures) {
auto [fst, snd] = future.get();
if (!snd) { end += fst + '\n'; endResult = false; }
else print("%s\n", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str());
LOGN(EFUN, INFO) << "Operation successfully completed." << std::endl;
return endResult;
}
bool eraseFunction::isUsed() const { return cmd->parsed(); }
const char *eraseFunction::name() const { return EFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -17,6 +17,7 @@ Copyright 2025 Yağız Zengin
#include <cstdlib> #include <cstdlib>
#include <fcntl.h> #include <fcntl.h>
#include <cerrno> #include <cerrno>
#include <future>
#include <unistd.h> #include <unistd.h>
#include <PartitionManager/PartitionManager.hpp> #include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp" #include "functions.hpp"
@@ -24,58 +25,37 @@ Copyright 2025 Yağız Zengin
#define FFUN "flashFunction" #define FFUN "flashFunction"
namespace PartitionManager { namespace PartitionManager {
pair flashFunction::runAsync(const std::string &partitionName, const std::string &imageName, int bufferSize) {
bool flashFunction::init(CLI::App &_app) if (!Helper::fileIsExists(imageName)) return {format("Couldn't find image file: %s", imageName.data()), false};
{ if (!Variables->PartMap->hasPartition(partitionName)) return {
LOGN(FFUN, INFO) << "Initializing variables of flash function." << std::endl; format("Couldn't find partition: %s", partitionName.data()), false
cmd = _app.add_subcommand("flash", "Flash image(s) to partition(s)"); };
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")->required();
cmd->add_option("imageFile(s)", rawImageNames, "Name(s) of image file(s)")->required()->check([&](const std::string& val) {
const std::vector<std::string> inputs = splitIfHasDelim(val, ',');
for (const auto& input : inputs) {
if (!Helper::fileIsExists(input)) return std::string("Couldn't find image file: " + input);
}
return std::string();
});
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for reading image(s) and writing to partition(s)");
return true;
}
bool flashFunction::run()
{
processCommandLine(partitions, imageNames, rawPartitions, rawImageNames, ',', true);
if (partitions.size() != imageNames.size())
throw CLI::ValidationError("You must provide an image file(s) as long as the partition name(s)");
for (size_t i = 0; i < partitions.size(); i++) {
std::string& partitionName = partitions[i];
std::string& imageName = imageNames[i];
LOGN(FFUN, INFO) << "flashing " << imageName << " to " << partitionName << std::endl; LOGN(FFUN, INFO) << "flashing " << imageName << " to " << partitionName << std::endl;
if (!Variables->PartMap->hasPartition(partitionName))
throw Error("Couldn't find partition: %s", partitionName.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partitionName)) {
if (Variables->forceProcess) LOGN(FFUN, WARNING) << "Partition " << partitionName << " is exists but not logical. Ignoring (from --force, -f)." << std::endl; if (Variables->forceProcess)
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()); LOGN(FFUN, WARNING) << "Partition " << partitionName <<
" is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else return {
format("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()), false
};
} }
bufferSize = (Helper::fileSize(imageName) % bufferSize == 0) ? bufferSize : 1; setupBufferSize(bufferSize, imageName);
LOGN(FFUN, INFO) << "Using buffer size: " << bufferSize; LOGN(FFUN, INFO) << "Using buffer size: " << bufferSize;
const int ffd = open(imageName.data(), O_RDONLY); const int ffd = open(imageName.data(), O_RDONLY);
if (ffd < 0) throw Error("Can't open image file %s: %s", imageName.data(), strerror(errno)); if (ffd < 0) return {format("Can't open image file %s: %s", imageName.data(), strerror(errno)), false};
const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_RDWR | O_TRUNC); const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_RDWR | O_TRUNC);
if (pfd < 0) { if (pfd < 0) {
close(ffd); close(ffd);
throw Error("Can't open partition: %s: %s", partitionName.data(), strerror(errno)); return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false};
} }
LOGN(FFUN, INFO) << "Writing image " << imageName << " to partition: " << partitionName << std::endl; LOGN(FFUN, INFO) << "Writing image " << imageName << " to partition: " << partitionName << std::endl;
auto* buffer = new char[bufferSize]; auto *buffer = new char[bufferSize];
memset(buffer, 0x00, bufferSize); memset(buffer, 0x00, bufferSize);
ssize_t bytesRead; ssize_t bytesRead;
while ((bytesRead = read(ffd, buffer, bufferSize)) > 0) { while ((bytesRead = read(ffd, buffer, bufferSize)) > 0) {
@@ -83,22 +63,61 @@ bool flashFunction::run()
close(pfd); close(pfd);
close(ffd); close(ffd);
delete[] buffer; delete[] buffer;
throw Error("Can't write partition to output file %s: %s", imageName.data(), strerror(errno)); return {
format("Can't write partition to output file %s: %s", imageName.data(), strerror(errno)), false
};
} }
} }
close(pfd); close(pfd);
close(ffd); close(ffd);
delete[] buffer; delete[] buffer;
return {format("%s is successfully wrote to %s partition\n", imageName.data(), partitionName.data()), true};
} }
LOGN(FFUN, INFO) << "Operation successfully completed." << std::endl; bool flashFunction::init(CLI::App &_app) {
LOGN(FFUN, INFO) << "Initializing variables of flash function." << std::endl;
cmd = _app.add_subcommand("flash", "Flash image(s) to partition(s)");
cmd->add_option("partition(s)", rawPartitions, "Partition name(s)")->required();
cmd->add_option("imageFile(s)", rawImageNames, "Name(s) of image file(s)")->required();
cmd->add_option("-b,--buffer-size", bufferSize, "Buffer size for reading image(s) and writing to partition(s)");
cmd->add_option("-I,--image-directory", imageDirectory, "Directory to find image(s) and flash to partition(s)");
return true; return true;
} }
bool flashFunction::isUsed() const { return cmd->parsed(); } bool flashFunction::run() {
processCommandLine(partitions, imageNames, rawPartitions, rawImageNames, ',', true);
if (partitions.size() != imageNames.size())
throw CLI::ValidationError("You must provide an image file(s) as long as the partition name(s)");
const char* flashFunction::name() const { return FFUN; } std::vector<std::future<pair> > futures;
for (size_t i = 0; i < partitions.size(); i++) {
std::string imageName = imageNames[i];
if (!imageDirectory.empty()) imageName.insert(0, imageDirectory + '/');
futures.push_back(std::async(std::launch::async, runAsync, partitions[i], imageName, bufferSize));
LOGN(FFUN, INFO) << "Created thread for flashing image to " << partitions[i] << std::endl;
}
std::string end;
bool endResult = true;
for (auto &future: futures) {
auto [fst, snd] = future.get();
if (!snd) {
end += fst + '\n';
endResult = false;
} else print("%s", fst.c_str());
}
if (!endResult) throw Error("%s", end.c_str());
LOGN(FFUN, INFO) << "Operation successfully completed." << std::endl;
return endResult;
}
bool flashFunction::isUsed() const { return cmd->parsed(); }
const char *flashFunction::name() const { return FFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -24,35 +24,37 @@ Copyright 2025 Yağız Zengin
#define IFUN "infoFunction" #define IFUN "infoFunction"
namespace PartitionManager { namespace PartitionManager {
bool infoFunction::init(CLI::App &_app) {
bool infoFunction::init(CLI::App &_app)
{
LOGN(IFUN, INFO) << "Initializing variables of info printer function." << std::endl; LOGN(IFUN, INFO) << "Initializing variables of info printer function." << std::endl;
cmd = _app.add_subcommand("info", "Tell info(s) of input partition list")->footer("Use get-all as partition name for getting info's of all partitions."); cmd = _app.add_subcommand("info", "Tell info(s) of input partition list")->footer(
"Use get-all or getvar-all as partition name for getting info's of all partitions.");
cmd->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(','); cmd->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(',');
cmd->add_flag("-J,--json", jsonFormat, "Print info(s) as JSON body. The body of each partition will be written separately"); cmd->add_flag("-J,--json", jsonFormat,
"Print info(s) as JSON body. The body of each partition will be written separately");
cmd->add_option("--json-partition-name", jNamePartition, "Speficy partition name element for JSON body"); cmd->add_option("--json-partition-name", jNamePartition, "Speficy partition name element for JSON body");
cmd->add_option("--json-size-name", jNameSize, "Speficy size element name for JSON body"); cmd->add_option("--json-size-name", jNameSize, "Speficy size element name for JSON body");
cmd->add_option("--json-logical-name", jNameLogical, "Speficy logical element name for JSON body"); cmd->add_option("--json-logical-name", jNameLogical, "Speficy logical element name for JSON body");
return true; return true;
}
bool infoFunction::run()
{
if (partitions.back() == "get-all") {
partitions.clear();
const auto parts = Variables->PartMap->getPartitionList();
if (!parts) throw Error("Cannot get list of all partitions! See logs for more information (%s)", Helper::LoggingProperties::FILE.data());
for (const auto& name : *parts) partitions.push_back(name);
} }
for (const auto& partition : partitions) { bool infoFunction::run() {
if (partitions.back() == "get-all" || partitions.back() == "getvar-all") {
partitions.clear();
const auto parts = Variables->PartMap->getPartitionList();
if (!parts) throw Error("Cannot get list of all partitions! See logs for more information (%s)",
Helper::LoggingProperties::FILE.data());
for (const auto &name: *parts) partitions.push_back(name);
}
for (const auto &partition: partitions) {
if (!Variables->PartMap->hasPartition(partition)) if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data()); throw Error("Couldn't find partition: %s", partition.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
if (Variables->forceProcess) LOGN(IFUN, WARNING) << "Partition " << partition << " is exists but not logical. Ignoring (from --force, -f)." << std::endl; if (Variables->forceProcess)
LOGN(IFUN, WARNING) << "Partition " << partition <<
" is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data()); else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data());
} }
@@ -80,10 +82,9 @@ bool infoFunction::run()
} }
return true; return true;
} }
bool infoFunction::isUsed() const { return cmd->parsed(); } bool infoFunction::isUsed() const { return cmd->parsed(); }
const char* infoFunction::name() const { return IFUN; };
const char *infoFunction::name() const { return IFUN; };
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -19,8 +19,7 @@ Copyright 2025 Yağız Zengin
#define SFUN "partitionSizeFunction" #define SFUN "partitionSizeFunction"
std::string convertTo(const uint64_t size, const std::string& multiple) std::string convertTo(const uint64_t size, const std::string &multiple) {
{
if (multiple == "KB") return std::to_string(TO_KB(size)); if (multiple == "KB") return std::to_string(TO_KB(size));
if (multiple == "MB") return std::to_string(TO_MB(size)); if (multiple == "MB") return std::to_string(TO_MB(size));
if (multiple == "GB") return std::to_string(TO_GB(size)); if (multiple == "GB") return std::to_string(TO_GB(size));
@@ -28,9 +27,7 @@ std::string convertTo(const uint64_t size, const std::string& multiple)
} }
namespace PartitionManager { namespace PartitionManager {
bool partitionSizeFunction::init(CLI::App &_app) {
bool partitionSizeFunction::init(CLI::App& _app)
{
LOGN(SFUN, INFO) << "Initializing variables of partition size getter function." << std::endl; LOGN(SFUN, INFO) << "Initializing variables of partition size getter function." << std::endl;
cmd = _app.add_subcommand("sizeof", "Tell size(s) of input partition list"); cmd = _app.add_subcommand("sizeof", "Tell size(s) of input partition list");
cmd->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(','); cmd->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(',');
@@ -40,33 +37,34 @@ bool partitionSizeFunction::init(CLI::App& _app)
cmd->add_flag("--as-gigabyte", asGiga, "Tell input size of partition list as gigabyte."); cmd->add_flag("--as-gigabyte", asGiga, "Tell input size of partition list as gigabyte.");
cmd->add_flag("--only-size", onlySize, "Tell input size of partition list as not printing multiple."); cmd->add_flag("--only-size", onlySize, "Tell input size of partition list as not printing multiple.");
return true; return true;
} }
bool partitionSizeFunction::run() bool partitionSizeFunction::run() {
{ for (const auto &partition: partitions) {
for (const auto& partition : partitions) {
if (!Variables->PartMap->hasPartition(partition)) if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data()); throw Error("Couldn't find partition: %s", partition.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) { if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
if (Variables->forceProcess) LOGN(SFUN, WARNING) << "Partition " << partition << " is exists but not logical. Ignoring (from --force, -f)." << std::endl; if (Variables->forceProcess)
LOGN(SFUN, WARNING) << "Partition " << partition <<
" is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data()); else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data());
} }
std::string multiple; std::string multiple = "MB";
if (asByte) multiple = "B"; if (asByte) multiple = "B";
if (asKiloBytes) multiple = "KB"; if (asKiloBytes) multiple = "KB";
if (asMega) multiple = "MB"; if (asMega) multiple = "MB";
if (asGiga) multiple = "GB"; if (asGiga) multiple = "GB";
print("%s: %s%s\n", partition.data(), convertTo(Variables->PartMap->sizeOf(partition), multiple).data(), multiple.data()); print("%s: %s%s\n", partition.data(), convertTo(Variables->PartMap->sizeOf(partition), multiple).data(),
multiple.data());
} }
return true; return true;
} }
bool partitionSizeFunction::isUsed() const { return cmd->parsed(); } bool partitionSizeFunction::isUsed() const { return cmd->parsed(); }
const char* partitionSizeFunction::name() const { return SFUN; }
const char *partitionSizeFunction::name() const { return SFUN; }
} // namespace PartitionManager } // namespace PartitionManager

View File

@@ -0,0 +1,51 @@
/*
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.
*/
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#define RLPFUN "realPathFunction"
namespace PartitionManager {
bool realLinkPathFunction::init(CLI::App &_app) {
LOGN(RLPFUN, INFO) << "Initializing variables of real link path function." << std::endl;
cmd = _app.add_subcommand("real-linkpath", "Tell real link paths of partition(s)");
cmd->add_option("partition(s)", partitions, "Partition name(s)")->required();
return true;
}
bool realLinkPathFunction::run() {
for (const auto &partition: partitions) {
if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
if (Variables->forceProcess)
LOGN(RLPFUN, WARNING) << "Partition " << partition <<
" is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data());
}
print("%s\n", Variables->PartMap->getRealPathOf(partition).data());
}
return true;
}
bool realLinkPathFunction::isUsed() const { return cmd->parsed(); }
const char *realLinkPathFunction::name() const { return RLPFUN; }
} // namespace PartitionManager

View File

@@ -0,0 +1,51 @@
/*
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.
*/
#include <PartitionManager/PartitionManager.hpp>
#include "functions.hpp"
#define RPFUN "realPathFunction"
namespace PartitionManager {
bool realPathFunction::init(CLI::App &_app) {
LOGN(RPFUN, INFO) << "Initializing variables of real path function." << std::endl;
cmd = _app.add_subcommand("real-path", "Tell real paths of partition(s)");
cmd->add_option("partition(s)", partitions, "Partition name(s)")->required();
return true;
}
bool realPathFunction::run() {
for (const auto &partition: partitions) {
if (!Variables->PartMap->hasPartition(partition))
throw Error("Couldn't find partition: %s", partition.data());
if (Variables->onLogical && !Variables->PartMap->isLogical(partition)) {
if (Variables->forceProcess)
LOGN(RPFUN, WARNING) << "Partition " << partition <<
" is exists but not logical. Ignoring (from --force, -f)." << std::endl;
else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data());
}
print("%s\n", Variables->PartMap->getRealPathOf(partition).data());
}
return true;
}
bool realPathFunction::isUsed() const { return cmd->parsed(); }
const char *realPathFunction::name() const { return RPFUN; }
} // namespace PartitionManager

View File

@@ -18,88 +18,125 @@
#define FUNCTIONS_HPP #define FUNCTIONS_HPP
#include <PartitionManager/PartitionManager.hpp> #include <PartitionManager/PartitionManager.hpp>
#include <utility>
#include <vector> #include <vector>
namespace PartitionManager { namespace PartitionManager {
using pair = std::pair<std::string, bool>;
// Back-up function // Back-up function
class backupFunction final : public FunctionBase { class backupFunction final : public FunctionBase {
private: private:
std::vector<std::string> partitions, outputNames; std::vector<std::string> partitions, outputNames;
std::string rawPartitions, rawOutputNames; std::string rawPartitions, rawOutputNames, outputDirectory;
int bufferSize = 2048; int bufferSize = 4096;
public: public:
CLI::App* cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App& _app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override; static pair runAsync(const std::string &partitionName, const std::string &outputName, int bufferSize);
[[nodiscard]] const char* name() const override;
};
// Image flasher function [[nodiscard]] bool isUsed() const override;
class flashFunction final : public FunctionBase { [[nodiscard]] const char *name() const override;
private: };
// Image flasher function
class flashFunction final : public FunctionBase {
private:
std::vector<std::string> partitions, imageNames; std::vector<std::string> partitions, imageNames;
std::string rawPartitions, rawImageNames; std::string rawPartitions, rawImageNames, imageDirectory;
int bufferSize = 2048; int bufferSize = 4096;
public: public:
CLI::App* cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App& _app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override; static pair runAsync(const std::string &partitionName, const std::string &imageName, int bufferSize);
[[nodiscard]] const char* name() const override;
};
// Eraser function (writes zero bytes to partition) [[nodiscard]] bool isUsed() const override;
class eraseFunction final : public FunctionBase { [[nodiscard]] const char *name() const override;
private: };
// Eraser function (writes zero bytes to partition)
class eraseFunction final : public FunctionBase {
private:
std::vector<std::string> partitions; std::vector<std::string> partitions;
int bufferSize = 2048; int bufferSize = 4096;
public: public:
CLI::App* cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App& _app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override; static pair runAsync(const std::string &partitionName, int bufferSize);
[[nodiscard]] const char* name() const override;
};
// Partition size getter function [[nodiscard]] bool isUsed() const override;
class partitionSizeFunction final : public FunctionBase { [[nodiscard]] const char *name() const override;
private: };
// Partition size getter function
class partitionSizeFunction final : public FunctionBase {
private:
std::vector<std::string> partitions; std::vector<std::string> partitions;
bool onlySize = false, asByte = false, asKiloBytes = false, asMega = true, asGiga = false; bool onlySize = false, asByte = false, asKiloBytes = false, asMega = false, asGiga = false;
public: public:
CLI::App* cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App& _app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char* name() const override;
};
// Partition info getter function [[nodiscard]] bool isUsed() const override;
class infoFunction final : public FunctionBase { [[nodiscard]] const char *name() const override;
private: };
// Partition info getter function
class infoFunction final : public FunctionBase {
private:
std::vector<std::string> partitions; std::vector<std::string> partitions;
std::string jNamePartition = "name", jNameSize = "size", jNameLogical = "isLogical"; std::string jNamePartition = "name", jNameSize = "size", jNameLogical = "isLogical";
bool jsonFormat = false; bool jsonFormat = false;
public: public:
CLI::App* cmd = nullptr; CLI::App *cmd = nullptr;
bool init(CLI::App& _app) override; bool init(CLI::App &_app) override;
bool run() override; bool run() override;
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char* name() const override;
};
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override;
};
class realPathFunction final : public FunctionBase {
private:
std::vector<std::string> partitions;
public:
CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override;
bool run() override;
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override;
};
class realLinkPathFunction final : public FunctionBase {
private:
std::vector<std::string> partitions;
public:
CLI::App *cmd = nullptr;
bool init(CLI::App &_app) override;
bool run() override;
[[nodiscard]] bool isUsed() const override;
[[nodiscard]] const char *name() const override;
};
} // namespace PartitionManager } // namespace PartitionManager
#endif // #ifndef FUNCTIONS_HPP #endif // #ifndef FUNCTIONS_HPP

View File

@@ -42,7 +42,7 @@ struct _entry {
* The main type of the library. The Builder class is designed * The main type of the library. The Builder class is designed
* to be easily manipulated and modified only on this class. * to be easily manipulated and modified only on this class.
*/ */
class basic_partition_map { class basic_partition_map final {
private: private:
void _resize_map(); void _resize_map();
[[nodiscard]] int _index_of(std::string_view name) const; [[nodiscard]] int _index_of(std::string_view name) const;
@@ -116,7 +116,7 @@ public:
using Map_t = basic_partition_map; using Map_t = basic_partition_map;
class basic_partition_map_builder { class basic_partition_map_builder final {
private: private:
Map_t _current_map; Map_t _current_map;
std::string _workdir; std::string _workdir;

View File

@@ -81,7 +81,7 @@ std::string basic_partition_map_builder::getRealPathOf(const std::string_view na
{ {
_map_build_check(); _map_build_check();
std::string full = _workdir + "/" + name.data(); const std::string full = (isLogical(name)) ? std::string("/dev/block/mapper/") + name.data() : _workdir + "/" + name.data();
if (!_current_map.find(name) if (!_current_map.find(name)
|| !std::filesystem::is_symlink(full)) || !std::filesystem::is_symlink(full))
return {}; return {};

View File

@@ -156,24 +156,21 @@ void basic_partition_map::merge(const basic_partition_map& map)
uint64_t basic_partition_map::get_size(const std::string_view name) const uint64_t basic_partition_map::get_size(const std::string_view name) const
{ {
int pos = _index_of(name); if (const int pos = _index_of(name); name == _data[pos].name) return _data[pos].props.size;
if (name == _data[pos].name) return _data[pos].props.size;
return 0; return 0;
} }
bool basic_partition_map::is_logical(const std::string_view name) const bool basic_partition_map::is_logical(const std::string_view name) const
{ {
int pos = _index_of(name); if (const int pos = _index_of(name); name == _data[pos].name) return _data[pos].props.isLogical;
if (name == _data[pos].name) return _data[pos].props.isLogical;
return false; return false;
} }
basic_partition_map::_returnable_entry basic_partition_map::get_all(const std::string_view name) const basic_partition_map::_returnable_entry basic_partition_map::get_all(const std::string_view name) const
{ {
int pos = _index_of(name); if (const int pos = _index_of(name); name == _data[pos].name)
if (name == _data[pos].name)
return _returnable_entry{_data[pos].props.size, _data[pos].props.isLogical}; return _returnable_entry{_data[pos].props.size, _data[pos].props.isLogical};
return _returnable_entry{}; return _returnable_entry{};