diff --git a/CMakeLists.txt b/CMakeLists.txt index a8c8f1b..c420c86 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,9 @@ add_compile_options(-Wall -Werror -Wno-deprecated-declarations) if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") add_compile_options(-gdwarf-5 -fsanitize=address -fstack-protector) add_link_options(-fsanitize=address) +else() + add_compile_options(-Os) + add_link_options(-s) endif() # Add pmt's CMake module(s) diff --git a/build.sh b/build.sh index 370f6c9..eeea693 100755 --- a/build.sh +++ b/build.sh @@ -57,13 +57,15 @@ build() cmake -B $BUILD_64 -S . $1 \ -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ -DANDROID_ABI=arm64-v8a \ - -DANDROID_PLATFORM=$ANDROID_PLATFORM + -DANDROID_PLATFORM=$ANDROID_PLATFORM \ + -DANDROID_STL=c++_static echo "Configuring for armeabi-v7a..." cmake -B $BUILD_32 -S . $1 \ -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ -DANDROID_ABI=armeabi-v7a \ - -DANDROID_PLATFORM=$ANDROID_PLATFORM + -DANDROID_PLATFORM=$ANDROID_PLATFORM \ + -DANDROID_STL=c++_static echo "Building arm64-v8a artifacts..." cmake --build $BUILD_64 diff --git a/include/PartitionManager/PartitionManager.hpp b/include/PartitionManager/PartitionManager.hpp index c2478fc..c556465 100755 --- a/include/PartitionManager/PartitionManager.hpp +++ b/include/PartitionManager/PartitionManager.hpp @@ -34,73 +34,82 @@ #define PMTF "libpmt-function-manager" 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. -class basic_function { -public: - CLI::App* cmd = nullptr; + virtual bool init(CLI::App &_app) = 0; + virtual bool run() = 0; - virtual bool init(CLI::App& _app) = 0; - virtual bool run() = 0; - [[nodiscard]] virtual bool isUsed() const = 0; - [[nodiscard]] virtual const char* name() const = 0; - virtual ~basic_function() = default; -}; + [[nodiscard]] virtual bool isUsed() const = 0; + [[nodiscard]] virtual const char *name() const = 0; -// A class for function management. -class basic_function_manager final { -private: - std::vector> _functions; + virtual ~basic_function() = default; + }; -public: - void registerFunction(std::unique_ptr _func, CLI::App& _app); + // A class for function management. + class basic_function_manager final { + private: + std::vector > _functions; - [[nodiscard]] bool handleAll() const; -}; + public: + void registerFunction(std::unique_ptr _func, CLI::App &_app); -// Sets logs file automatically -class logSetter final { public: logSetter(); }; + [[nodiscard]] bool handleAll() const; + }; -class basic_variables final { -private: - logSetter setLogSetting; + // Sets logs file automatically + class logSetter final { public: logSetter(); }; -public: - basic_variables(); - ~basic_variables(); + class basic_variables final { + private: + logSetter setLogSetting; - PartitionMap::BuildMap* PartMap; + public: + basic_variables(); + ~basic_variables(); - std::string searchPath, logFile; - bool onLogical; - bool quietProcess; - bool verboseMode; - bool viewVersion; - bool forceProcess; -}; + PartitionMap::BuildMap *PartMap; -using FunctionBase = basic_function; -using FunctionManager = basic_function_manager; -using VariableTable = basic_variables; -using Error = Helper::Error; + std::string searchPath, logFile; + bool onLogical; + bool quietProcess; + bool verboseMode; + bool viewVersion; + bool forceProcess; + }; -extern VariableTable* Variables; + using FunctionBase = basic_function; + using FunctionManager = basic_function_manager; + using VariableTable = basic_variables; + using Error = Helper::Error; -int Main(int argc, char** argv); + extern VariableTable *Variables; -// Print messages if not using quiet mode -__attribute__((format(printf, 1, 2))) -void print(const char* format, ...); + int Main(int argc, char **argv); -// If there is a delimiter in the string, CLI::detail::split returns; if not, an empty vector is returned. And checks duplicate arguments. -std::vector splitIfHasDelim(const std::string& s, char delim, bool checkForBadUsage = false); + // Print messages if not using quiet mode + __attribute__((format(printf, 1, 2))) + void print(const char *format, ...); -// Process vectors with input strings. Use for [flag(s)]-[other flag(s)] situations -void processCommandLine(std::vector& vec1, std::vector& vec2, const std::string& s1, const std::string& s2, char delim, bool checkForBadUsage = false); + // Format it input and return + __attribute__((format(printf, 1, 2))) + std::string format(const char *format, ...); -std::string getLibVersion(); -std::string getAppVersion(); // Not Android app version (an Android app is planned!), tells pmt version. + // If there is a delimiter in the string, CLI::detail::split returns; if not, an empty vector is returned. And checks duplicate arguments. + std::vector splitIfHasDelim(const std::string &s, char delim, bool checkForBadUsage = false); + // Process vectors with input strings. Use for [flag(s)]-[other flag(s)] situations + void processCommandLine(std::vector &vec1, std::vector &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 #endif // #ifndef LIBPMT_LIB_HPP diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2ea811f..4100d55 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,8 @@ set(PMT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/functions/FlashFunction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/InfoFunction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/PartitionSizeFunction.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/functions/RealPathFunction.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/functions/RealLinkPathFunction.cpp ) # 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_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") - -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() diff --git a/src/FunctionManager.cpp b/src/FunctionManager.cpp index fe250e3..4be2f52 100755 --- a/src/FunctionManager.cpp +++ b/src/FunctionManager.cpp @@ -21,53 +21,55 @@ #include namespace PartitionManager { + std::vector splitIfHasDelim(const std::string &s, const char delim, const bool checkForBadUsage) { + if (s.find(delim) == std::string::npos) return {}; + auto vec = CLI::detail::split(s, delim); -std::vector splitIfHasDelim(const std::string& s, const char delim, const bool checkForBadUsage) -{ - if (s.find(delim) == std::string::npos) return {}; - auto vec = CLI::detail::split(s, delim); + if (checkForBadUsage) { + std::unordered_set set; + for (const auto &str: vec) { + if (set.find(str) != set.end()) throw CLI::ValidationError("Duplicate element in your inputs!"); + set.insert(str); + } + } - if (checkForBadUsage) { - std::unordered_set set; - for (const auto& str : vec) { - if (set.find(str) != set.end()) throw CLI::ValidationError("Duplicate element in your inputs!"); - set.insert(str); + return vec; + } + + 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; } } - return vec; -} + void processCommandLine(std::vector &vec1, std::vector &vec2, const std::string &s1, + const std::string &s2, const char delim, const bool checkForBadUsage) { + vec1 = splitIfHasDelim(s1, delim, checkForBadUsage); + vec2 = splitIfHasDelim(s2, delim, checkForBadUsage); -void processCommandLine(std::vector& vec1, std::vector& vec2, const std::string& s1, const std::string& s2, const char delim, const bool checkForBadUsage) -{ - vec1 = splitIfHasDelim(s1, delim, checkForBadUsage); - vec2 = splitIfHasDelim(s2, delim, checkForBadUsage); - - if (vec1.empty() && !s1.empty()) vec1.push_back(s1); - if (vec2.empty() && !s2.empty()) vec2.push_back(s2); -} - -void basic_function_manager::registerFunction(std::unique_ptr _func, CLI::App& _app) -{ - LOGN(PMTF, INFO) << "registering function: " << _func->name() << std::endl; - if (!_func->init(_app)) throw Error("Cannot init function: %s\n", _func->name()); - _functions.push_back(std::move(_func)); - LOGN(PMTF, INFO) << _functions.back()->name() << " successfully registered." << std::endl; -} - -bool basic_function_manager::handleAll() const -{ - LOGN(PMTF, INFO) << "running caught function commands in command-line." << std::endl; - for (const auto& func : _functions) { - if (func->isUsed()) { - LOGN(PMTF, INFO) << func->name() << " is calling because used in command-line." << std::endl; - return func->run(); - } + if (vec1.empty() && !s1.empty()) vec1.push_back(s1); + if (vec2.empty() && !s2.empty()) vec2.push_back(s2); } - LOGN(PMTF, INFO) << "not found any used function from command-line." << std::endl; - print("Target progress is not specified. Specify a progress."); - return false; -} + void basic_function_manager::registerFunction(std::unique_ptr _func, CLI::App &_app) { + LOGN(PMTF, INFO) << "registering function: " << _func->name() << std::endl; + if (!_func->init(_app)) throw Error("Cannot init function: %s\n", _func->name()); + _functions.push_back(std::move(_func)); + LOGN(PMTF, INFO) << _functions.back()->name() << " successfully registered." << std::endl; + } + bool basic_function_manager::handleAll() const { + LOGN(PMTF, INFO) << "running caught function commands in command-line." << std::endl; + for (const auto &func: _functions) { + if (func->isUsed()) { + LOGN(PMTF, INFO) << func->name() << " is calling because used in command-line." << std::endl; + return func->run(); + } + } + + LOGN(PMTF, INFO) << "not found any used function from command-line." << std::endl; + print("Target progress is not specified. Specify a progress."); + return false; + } } // namespace PartitionManager diff --git a/src/PartitionManager.cpp b/src/PartitionManager.cpp index 4eec033..f72a137 100755 --- a/src/PartitionManager.cpp +++ b/src/PartitionManager.cpp @@ -23,97 +23,110 @@ #include "functions/functions.hpp" 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()), - logFile("/sdcard/Documents/last_pmt_logs.log"), - onLogical(false), - quietProcess(false), - verboseMode(false), - viewVersion(false), - forceProcess(false) -{} + basic_variables::basic_variables() : PartMap(new PartitionMap::BuildMap()), + logFile("/sdcard/Documents/last_pmt_logs.log"), + onLogical(false), + quietProcess(false), + verboseMode(false), + viewVersion(false), + forceProcess(false) + {} -int Main(int argc, char** argv) -{ -try { // try-catch start - CLI::App AppMain{"Partition Manager Tool"}; - FunctionManager FuncManager; + int Main(int argc, char **argv) { + try { + // try-catch start + CLI::App AppMain{"Partition Manager Tool"}; + FunctionManager FuncManager; - 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.add_option("-S,--search-path", Variables->searchPath, "Set partition search path")->check([&](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(); - }); - 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("-l,--logical", Variables->onLogical, "Specify that the target partition is dynamic"); - 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,--version", Variables->viewVersion, "Print version and exit"); + AppMain.fallthrough(true); + 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.add_option("-S,--search-path", Variables->searchPath, "Set partition search path")->check( + [&](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(); + }); + 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("-l,--logical", Variables->onLogical, "Specify that the target partition is dynamic"); + 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,--version", Variables->viewVersion, "Print version and exit"); - if (argc < 2) { - print("Usage: %s [OPTIONS] [SUBCOMMAND]\nUse --help for more information.\n", argv[0]); - return EXIT_FAILURE; + if (argc < 2) { + print("Usage: %s [OPTIONS] [SUBCOMMAND]\nUse --help for more information.\n", argv[0]); + return EXIT_FAILURE; + } + + FuncManager.registerFunction(std::make_unique(), AppMain); + FuncManager.registerFunction(std::make_unique(), AppMain); + FuncManager.registerFunction(std::make_unique(), AppMain); + FuncManager.registerFunction(std::make_unique(), AppMain); + FuncManager.registerFunction(std::make_unique(), AppMain); + FuncManager.registerFunction(std::make_unique(), AppMain); + FuncManager.registerFunction(std::make_unique(), AppMain); + + CLI11_PARSE(AppMain, argc, argv); + + if (Variables->verboseMode) Helper::LoggingProperties::setPrinting(YES); + if (Variables->viewVersion) { + print("%s\n", getAppVersion().data()); + return EXIT_SUCCESS; + } + + if (!Variables->searchPath.empty()) (*Variables->PartMap)(Variables->searchPath); + + if (!Variables->PartMap && Variables->searchPath.empty()) + 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; + } 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()); + delete Variables; + return EXIT_FAILURE; + } catch (CLI::Error &error) { + // catch CLI::Error + + delete Variables; + fprintf(stderr, "%s: %s%sFLAG PARSE ERROR:%s %s\n", argv[0], RED, BOLD, STYLE_RESET, error.what()); + return EXIT_FAILURE; + } // try-catch block end } - FuncManager.registerFunction(std::make_unique(), AppMain); - FuncManager.registerFunction(std::make_unique(), AppMain); - FuncManager.registerFunction(std::make_unique(), AppMain); - FuncManager.registerFunction(std::make_unique(), AppMain); - FuncManager.registerFunction(std::make_unique(), AppMain); - - CLI11_PARSE(AppMain, argc, argv); - - if (Variables->verboseMode) Helper::LoggingProperties::setPrinting(YES); - if (Variables->viewVersion) { - print("%s\n", getAppVersion().data()); - return EXIT_SUCCESS; + void print(const char *format, ...) { + va_list args; + va_start(args, format); + if (!Variables->quietProcess) vfprintf(stdout, format, args); + va_end(args); } - if (!Variables->searchPath.empty()) (*Variables->PartMap)(Variables->searchPath); + 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; + } - if (!Variables->PartMap && Variables->searchPath.empty()) - throw Error("No default search entries were found. Specify a search directory with -S (--search-path)"); - - return FuncManager.handleAll() == true ? EXIT_SUCCESS : EXIT_FAILURE; - -} catch (Helper::Error &error) { // catch Helper::Error - - if (!Variables->quietProcess) fprintf(stderr, "%s: %s.\n", argv[0], error.what()); - delete Variables; - return EXIT_FAILURE; - -} catch (CLI::Error &error) { // catch CLI::Error - - delete Variables; - fprintf(stderr, "%s: FLAG PARSE ERROR: %s\n", argv[0], error.what()); - return EXIT_FAILURE; - -} // try-catch block end -} - -void print(const char* format, ...) -{ - va_list args; - va_start(args, format); - if (!Variables->quietProcess) vfprintf(stdout, format, args); - va_end(args); -} - -std::string getLibVersion() -{ - MKVERSION(PMT); -} - -std::string getAppVersion() -{ - MKVERSION(PMTE); -} + std::string getLibVersion() { + MKVERSION(PMT); + } + std::string getAppVersion() { + MKVERSION(PMTE); + } } // namespace PartitionManager diff --git a/src/functions/BackupFunction.cpp b/src/functions/BackupFunction.cpp index 6988d42..c0b5436 100644 --- a/src/functions/BackupFunction.cpp +++ b/src/functions/BackupFunction.cpp @@ -1,5 +1,5 @@ /* -Copyright 2025 Yağız Zengin + 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. @@ -18,62 +18,47 @@ Copyright 2025 Yağız Zengin #include #include #include +#include +#include #include #include "functions.hpp" #define BFUN "backupFunction" 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) << "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()); + LOGN(BFUN, INFO) << "back upping " << partitionName << " as " << outputName << std::endl; 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; - else throw Error("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()); + if (Variables->forceProcess) + 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()); - else LOGN(BFUN, INFO) << outputName << " is exists but ignoring (from --force, -f). Re-creating." << std::endl; + if (Helper::fileIsExists(outputName) && !Variables->forceProcess) return { + format("%s is exists. Remove it, or use --force (-f) flag.", outputName.data()), false + }; - bufferSize = (Variables->PartMap->sizeOf(partitionName) % bufferSize == 0) ? bufferSize : 1; - LOGN(BFUN, INFO) << "Using buffer size: " << bufferSize << std::endl; + setupBufferSize(bufferSize, partitionName); + LOGN(BFUN, INFO) << "Using buffer size (for back upping " << partitionName << "): " << bufferSize << std::endl; const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_RDONLY); - if (pfd < 0) - throw Error("Can't open partition: %s: %s", partitionName.data(), strerror(errno)); - + if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false}; const int ffd = open(outputName.data(), O_WRONLY | O_CREAT | O_TRUNC, 0644); if (ffd < 0) { 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; - auto* buffer = new char[bufferSize]; + auto *buffer = new char[bufferSize]; memset(buffer, 0x00, bufferSize); ssize_t bytesRead; while ((bytesRead = read(pfd, buffer, bufferSize)) > 0) { @@ -81,21 +66,61 @@ bool backupFunction::run() close(pfd); close(ffd); 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(ffd); delete[] buffer; + + return {format("%s partition successfully back upped to %s", partitionName.data(), outputName.data()), true}; } - LOGN(BFUN, INFO) << "Operation successfully completed." << std::endl; - return true; -} + 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)"); -bool backupFunction::isUsed() const { return cmd->parsed(); } + return true; + } -const char* backupFunction::name() const { return BFUN; } + 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)"); + std::vector > 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 diff --git a/src/functions/EraseFunction.cpp b/src/functions/EraseFunction.cpp index 866f283..622c89c 100644 --- a/src/functions/EraseFunction.cpp +++ b/src/functions/EraseFunction.cpp @@ -17,6 +17,7 @@ Copyright 2025 Yağız Zengin #include #include #include +#include #include #include #include "functions.hpp" @@ -24,38 +25,31 @@ Copyright 2025 Yağız Zengin #define EFUN "eraseFunction" namespace PartitionManager { - -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; -} - -bool eraseFunction::run() -{ - for (const auto& partitionName : partitions) { - if (!Variables->PartMap->hasPartition(partitionName)) - throw Error("Couldn't find partition: %s", partitionName.data()); + pair eraseFunction::runAsync(const std::string &partitionName, int bufferSize) { + if (!Variables->PartMap->hasPartition(partitionName)) return { + format("Couldn't find partition: %s", partitionName.data()), false + }; 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; - else throw Error("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()); + if (Variables->forceProcess) + 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; const int pfd = open(Variables->PartMap->getRealPathOf(partitionName).data(), O_WRONLY); - if (pfd < 0) - throw Error("Can't open partition: %s: %s", partitionName.data(), strerror(errno)); + if (pfd < 0) return {format("Can't open partition: %s: %s", partitionName.data(), strerror(errno)), false}; - 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; - auto* buffer = new char[bufferSize]; + auto *buffer = new char[bufferSize]; memset(buffer, 0x00, bufferSize); ssize_t bytesWritten = 0; 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) { close(pfd); 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; } close(pfd); delete[] buffer; + + return {format("Successfully wrote zero bytes to the %s partition\n", partitionName.data()), true}; } - LOGN(EFUN, INFO) << "Operation successfully completed." << std::endl; - return true; -} + 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; + } -bool eraseFunction::isUsed() const { return cmd->parsed(); } + bool eraseFunction::run() { + std::vector > 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 diff --git a/src/functions/FlashFunction.cpp b/src/functions/FlashFunction.cpp index 2631043..6d72673 100644 --- a/src/functions/FlashFunction.cpp +++ b/src/functions/FlashFunction.cpp @@ -17,6 +17,7 @@ Copyright 2025 Yağız Zengin #include #include #include +#include #include #include #include "functions.hpp" @@ -24,58 +25,37 @@ Copyright 2025 Yağız Zengin #define FFUN "flashFunction" namespace PartitionManager { - -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()->check([&](const std::string& val) { - const std::vector 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]; + pair flashFunction::runAsync(const std::string &partitionName, const std::string &imageName, int bufferSize) { + if (!Helper::fileIsExists(imageName)) return {format("Couldn't find image file: %s", imageName.data()), false}; + if (!Variables->PartMap->hasPartition(partitionName)) return { + format("Couldn't find partition: %s", partitionName.data()), false + }; 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->forceProcess) LOGN(FFUN, WARNING) << "Partition " << partitionName << " is exists but not logical. Ignoring (from --force, -f)." << std::endl; - else throw Error("Used --logical (-l) flag but is not logical partition: %s", partitionName.data()); + if (Variables->forceProcess) + 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; 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); if (pfd < 0) { 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; - auto* buffer = new char[bufferSize]; + auto *buffer = new char[bufferSize]; memset(buffer, 0x00, bufferSize); ssize_t bytesRead; while ((bytesRead = read(ffd, buffer, bufferSize)) > 0) { @@ -83,22 +63,61 @@ bool flashFunction::run() close(pfd); close(ffd); 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(ffd); 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; - return true; -} + 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)"); -bool flashFunction::isUsed() const { return cmd->parsed(); } + return true; + } -const char* flashFunction::name() const { return FFUN; } + 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)"); + std::vector > 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 - diff --git a/src/functions/InfoFunction.cpp b/src/functions/InfoFunction.cpp index 91f8f8f..25ac1d8 100644 --- a/src/functions/InfoFunction.cpp +++ b/src/functions/InfoFunction.cpp @@ -24,66 +24,67 @@ Copyright 2025 Yağız Zengin #define IFUN "infoFunction" namespace PartitionManager { - -bool infoFunction::init(CLI::App &_app) -{ - 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->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_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-logical-name", jNameLogical, "Speficy logical element name for JSON body"); - 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); + bool infoFunction::init(CLI::App &_app) { + 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 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_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-size-name", jNameSize, "Speficy size element name for JSON body"); + cmd->add_option("--json-logical-name", jNameLogical, "Speficy logical element name for JSON body"); + return true; } - for (const auto& partition : partitions) { - if (!Variables->PartMap->hasPartition(partition)) - throw Error("Couldn't find partition: %s", partition.data()); + 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()); - 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; - else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data()); - } + for (const auto &name: *parts) partitions.push_back(name); + } - if (jsonFormat) + 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(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()); + } + + if (jsonFormat) #ifdef __LP64__ - print("{\"%s\": \"%s\", \"%s\": %lu, \"%s\": %s}\n", + print("{\"%s\": \"%s\", \"%s\": %lu, \"%s\": %s}\n", #else - print("{\"%s\": \"%s\", \"%s\": %llu, \"%s\": %s}\n", + print("{\"%s\": \"%s\", \"%s\": %llu, \"%s\": %s}\n", #endif - jNamePartition.data(), - partition.data(), - jNameSize.data(), - Variables->PartMap->sizeOf(partition), - jNameLogical.data(), - Variables->PartMap->isLogical(partition) ? "true" : "false"); - else + jNamePartition.data(), + partition.data(), + jNameSize.data(), + Variables->PartMap->sizeOf(partition), + jNameLogical.data(), + Variables->PartMap->isLogical(partition) ? "true" : "false"); + else #ifdef __LP64__ - print("partition=%s size=%lu isLogical=%s\n", + print("partition=%s size=%lu isLogical=%s\n", #else - print("partition=%s size=%llu isLogical=%s\n", + print("partition=%s size=%llu isLogical=%s\n", #endif - partition.data(), - Variables->PartMap->sizeOf(partition), - Variables->PartMap->isLogical(partition) ? "true" : "false"); - } + partition.data(), + Variables->PartMap->sizeOf(partition), + Variables->PartMap->isLogical(partition) ? "true" : "false"); + } - return true; -} + return true; + } -bool infoFunction::isUsed() const { return cmd->parsed(); } - -const char* infoFunction::name() const { return IFUN; }; + bool infoFunction::isUsed() const { return cmd->parsed(); } + const char *infoFunction::name() const { return IFUN; }; } // namespace PartitionManager diff --git a/src/functions/PartitionSizeFunction.cpp b/src/functions/PartitionSizeFunction.cpp index 6f9fdcf..971871d 100644 --- a/src/functions/PartitionSizeFunction.cpp +++ b/src/functions/PartitionSizeFunction.cpp @@ -19,8 +19,7 @@ Copyright 2025 Yağız Zengin #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 == "MB") return std::to_string(TO_MB(size)); if (multiple == "GB") return std::to_string(TO_GB(size)); @@ -28,45 +27,44 @@ std::string convertTo(const uint64_t size, const std::string& multiple) } namespace PartitionManager { - -bool partitionSizeFunction::init(CLI::App& _app) -{ - 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->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(','); - cmd->add_flag("--as-byte", asByte, "Tell input size of partition list as byte."); - cmd->add_flag("--as-kilobyte", asKiloBytes, "Tell input size of partition list as kilobyte."); - cmd->add_flag("--as-megabyte", asMega, "Tell input size of partition list as megabyte."); - 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."); - return true; -} - -bool partitionSizeFunction::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(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()); - } - - std::string multiple; - if (asByte) multiple = "B"; - if (asKiloBytes) multiple = "KB"; - if (asMega) multiple = "MB"; - if (asGiga) multiple = "GB"; - - print("%s: %s%s\n", partition.data(), convertTo(Variables->PartMap->sizeOf(partition), multiple).data(), multiple.data()); + bool partitionSizeFunction::init(CLI::App &_app) { + 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->add_option("partition(s)", partitions, "Partition name(s).")->required()->delimiter(','); + cmd->add_flag("--as-byte", asByte, "Tell input size of partition list as byte."); + cmd->add_flag("--as-kilobyte", asKiloBytes, "Tell input size of partition list as kilobyte."); + cmd->add_flag("--as-megabyte", asMega, "Tell input size of partition list as megabyte."); + 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."); + return true; } - return true; -} + bool partitionSizeFunction::run() { + for (const auto &partition: partitions) { + if (!Variables->PartMap->hasPartition(partition)) + throw Error("Couldn't find partition: %s", partition.data()); -bool partitionSizeFunction::isUsed() const { return cmd->parsed(); } + 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; + else throw Error("Used --logical (-l) flag but is not logical partition: %s", partition.data()); + } -const char* partitionSizeFunction::name() const { return SFUN; } + std::string multiple = "MB"; + if (asByte) multiple = "B"; + if (asKiloBytes) multiple = "KB"; + if (asMega) multiple = "MB"; + if (asGiga) multiple = "GB"; + print("%s: %s%s\n", partition.data(), convertTo(Variables->PartMap->sizeOf(partition), multiple).data(), + multiple.data()); + } + + return true; + } + + bool partitionSizeFunction::isUsed() const { return cmd->parsed(); } + + const char *partitionSizeFunction::name() const { return SFUN; } } // namespace PartitionManager diff --git a/src/functions/RealLinkPathFunction.cpp b/src/functions/RealLinkPathFunction.cpp new file mode 100644 index 0000000..1dd7378 --- /dev/null +++ b/src/functions/RealLinkPathFunction.cpp @@ -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 +#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 diff --git a/src/functions/RealPathFunction.cpp b/src/functions/RealPathFunction.cpp new file mode 100644 index 0000000..2b42c41 --- /dev/null +++ b/src/functions/RealPathFunction.cpp @@ -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 +#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 diff --git a/src/functions/functions.hpp b/src/functions/functions.hpp index f797b3a..248712b 100755 --- a/src/functions/functions.hpp +++ b/src/functions/functions.hpp @@ -18,88 +18,125 @@ #define FUNCTIONS_HPP #include +#include #include namespace PartitionManager { + using pair = std::pair; -// Back-up function -class backupFunction final : public FunctionBase { -private: - std::vector partitions, outputNames; - std::string rawPartitions, rawOutputNames; - int bufferSize = 2048; + // Back-up function + class backupFunction final : public FunctionBase { + private: + std::vector partitions, outputNames; + std::string rawPartitions, rawOutputNames, outputDirectory; + int bufferSize = 4096; -public: - CLI::App* cmd = nullptr; + 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; -}; + bool init(CLI::App &_app) override; + bool run() override; + static pair runAsync(const std::string &partitionName, const std::string &outputName, int bufferSize); -// Image flasher function -class flashFunction final : public FunctionBase { -private: - std::vector partitions, imageNames; - std::string rawPartitions, rawImageNames; - int bufferSize = 2048; + [[nodiscard]] bool isUsed() const override; + [[nodiscard]] const char *name() const override; + }; -public: - CLI::App* cmd = nullptr; + // Image flasher function + class flashFunction final : public FunctionBase { + private: + std::vector partitions, imageNames; + std::string rawPartitions, rawImageNames, imageDirectory; + int bufferSize = 4096; - bool init(CLI::App& _app) override; - bool run() override; - [[nodiscard]] bool isUsed() const override; - [[nodiscard]] const char* name() const override; -}; + public: + CLI::App *cmd = nullptr; -// Eraser function (writes zero bytes to partition) -class eraseFunction final : public FunctionBase { -private: - std::vector partitions; - int bufferSize = 2048; + bool init(CLI::App &_app) override; + bool run() override; + static pair runAsync(const std::string &partitionName, const std::string &imageName, int bufferSize); -public: - CLI::App* cmd = nullptr; + [[nodiscard]] bool isUsed() const override; + [[nodiscard]] const char *name() const override; + }; - bool init(CLI::App& _app) override; - bool run() override; - [[nodiscard]] bool isUsed() const override; - [[nodiscard]] const char* name() const override; -}; + // Eraser function (writes zero bytes to partition) + class eraseFunction final : public FunctionBase { + private: + std::vector partitions; + int bufferSize = 4096; -// Partition size getter function -class partitionSizeFunction final : public FunctionBase { -private: - std::vector partitions; - bool onlySize = false, asByte = false, asKiloBytes = false, asMega = true, asGiga = false; + public: + CLI::App *cmd = nullptr; -public: - CLI::App* cmd = nullptr; + bool init(CLI::App &_app) override; + bool run() override; + static pair runAsync(const std::string &partitionName, int bufferSize); - bool init(CLI::App& _app) 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; + }; -// Partition info getter function -class infoFunction final : public FunctionBase { -private: - std::vector partitions; - std::string jNamePartition = "name", jNameSize = "size", jNameLogical = "isLogical"; - bool jsonFormat = false; + // Partition size getter function + class partitionSizeFunction final : public FunctionBase { + private: + std::vector partitions; + bool onlySize = false, asByte = false, asKiloBytes = false, asMega = false, asGiga = false; -public: - CLI::App* cmd = nullptr; + 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; -}; + bool init(CLI::App &_app) override; + bool run() override; + [[nodiscard]] bool isUsed() const override; + [[nodiscard]] const char *name() const override; + }; + + // Partition info getter function + class infoFunction final : public FunctionBase { + private: + std::vector partitions; + std::string jNamePartition = "name", jNameSize = "size", jNameLogical = "isLogical"; + bool jsonFormat = false; + + 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 realPathFunction final : public FunctionBase { + private: + std::vector 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 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 #endif // #ifndef FUNCTIONS_HPP diff --git a/srclib/libpartition_map/include/libpartition_map/lib.hpp b/srclib/libpartition_map/include/libpartition_map/lib.hpp index dea3112..d7779be 100755 --- a/srclib/libpartition_map/include/libpartition_map/lib.hpp +++ b/srclib/libpartition_map/include/libpartition_map/lib.hpp @@ -42,7 +42,7 @@ struct _entry { * The main type of the library. The Builder class is designed * to be easily manipulated and modified only on this class. */ -class basic_partition_map { +class basic_partition_map final { private: void _resize_map(); [[nodiscard]] int _index_of(std::string_view name) const; @@ -116,7 +116,7 @@ public: using Map_t = basic_partition_map; -class basic_partition_map_builder { +class basic_partition_map_builder final { private: Map_t _current_map; std::string _workdir; diff --git a/srclib/libpartition_map/src/Getters.cpp b/srclib/libpartition_map/src/Getters.cpp index 5ae026a..6c0d2ab 100755 --- a/srclib/libpartition_map/src/Getters.cpp +++ b/srclib/libpartition_map/src/Getters.cpp @@ -81,7 +81,7 @@ std::string basic_partition_map_builder::getRealPathOf(const std::string_view na { _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) || !std::filesystem::is_symlink(full)) return {}; diff --git a/srclib/libpartition_map/src/Type.cpp b/srclib/libpartition_map/src/Type.cpp index d4f8079..6c50be3 100755 --- a/srclib/libpartition_map/src/Type.cpp +++ b/srclib/libpartition_map/src/Type.cpp @@ -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 { - int pos = _index_of(name); - if (name == _data[pos].name) return _data[pos].props.size; + if (const int pos = _index_of(name); name == _data[pos].name) return _data[pos].props.size; return 0; } bool basic_partition_map::is_logical(const std::string_view name) const { - int pos = _index_of(name); - if (name == _data[pos].name) return _data[pos].props.isLogical; + if (const int pos = _index_of(name); name == _data[pos].name) return _data[pos].props.isLogical; return false; } basic_partition_map::_returnable_entry basic_partition_map::get_all(const std::string_view name) const { - int pos = _index_of(name); - if (name == _data[pos].name) + if (const int pos = _index_of(name); name == _data[pos].name) return _returnable_entry{_data[pos].props.size, _data[pos].props.isLogical}; return _returnable_entry{};