/* By YZBruh */ /** * Copyright 2024 Partition Manager * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define INC_MAIN_LIBS #define INC_DEBUGERS #define INC_STAT #define INC_LIBGEN #define INC_STRINGKEYS #define IS_MAIN #include #include #include #include #include /* add value to variables that are added globally and are not worth */ namespace PartitionManager { namespace Strings { string OutputName = ""; string CustomSearchPath = ""; string TargetPartition = ""; string TargetFlashFile = ""; string TargetFormatFS = ""; string PartitionType = ""; string ExecutingName = ""; string CurrentLanguage = ""; } /* namespace Strings */ namespace Integers { int PartSizeViewType = VIEW_AS_MIB; } /* namespace Integers */ } /* namespace PartitionManager */ /* configure struct body */ struct Configuration Config { .UseLogical = false, .UseCustomSearchPath = false, .UsesSlots = false, .UsesLogical = false, .OnlyViewSize = false, .SilentEnabled = false, .FlashMode = false, .BackupMode = false, .FormatMode = false, .PartSizeViewMode = false, .ForceMode = false, .VerboseMode = false, .InstalledOnTermux = false }; /* some variables. for parsing and processing arguments */ static bool ViewHelp = false; static bool ViewVersion = false; static bool LogicalSpeficy = false; static bool ListRequired = false; static bool MultipleViewers = false; static bool SetLanguageReq = false; static bool SomeSpec = false; static bool PartSizeArgSpeficed = false; static char* SpeficedLanguagePr; static string Option; static string Target; static string SymbolRule; static int StdinArgcTotal; static int SearchOnMainInt; namespace PartitionManager { /** * He controls whether the '-' sign at * the beginning of the given word */ static void CheckOptSymbol(const string& Symbol) { if (!Symbol.empty()) { if (strncmp(Symbol.c_str(), "-", 1) == 0) LOGE("%s\n", SymbolRule.c_str()); } } static bool ControlArg(char* &ArgvHolder) { if (ArgvHolder[0] != '-') return true; return false; } } /* namespace PartitionManager */ static void deprecated(const char &opt, const char* &deprecation_message, const char* opt_long = "ISNULL") { VLOGE("Deprecated Option: -%c (--%s). Printing error...\n", opt, opt_long); DEPR_HANDLE(opt, opt_long, deprecation_message); exit(1); } static void PrSpInput(const string& sp) { Config.UseCustomSearchPath = true; PartitionManager::Strings::CustomSearchPath = sp; PartitionManager::CheckOptSymbol(PartitionManager::Strings::CustomSearchPath); } class PartitionManagerBase { protected: char* BaseFunctionName = nullptr; int StartCode = -1; bool IsRequiredOnlyOneArg = false; public: void CallTargetBaseFunction(void) { VLOGD("[class]: Call PartitionManagerMain(%d)\n", StartCode); PartitionManager::PartitionManagerMain(StartCode); } void GenericNumericalController(int& searchOn, int& total, const char* &MissingArgMessage) { if (total <= searchOn) { VLOGE("[class]: Missing argument total (for %s function).\n", BaseFunctionName); LOGE("%s 0.\n", MissingArgMessage); } if (!IsRequiredOnlyOneArg) { if (total <= (searchOn + 1)) { VLOGE("[class]: Missing argument total (for %s function).\n", BaseFunctionName); LOGE("%s 1.\n", MissingArgMessage); } } } virtual void ArgumentProcessor(int& searchOn, int& total, char** &arguments) { /* dummy */ } }; class PartitionManagerBackup : public PartitionManagerBase { public: void ArgumentProcessor(int& searchOn, int& total, char** &arguments) override { BaseFunctionName = "backup"; StartCode = 1; IsRequiredOnlyOneArg = true; GenericNumericalController(searchOn, total, PartitionManager::Display::UsingDispString->expected_backup_arg); if (PartitionManager::ControlArg(arguments[searchOn])) PartitionManager::Strings::TargetPartition = arguments[searchOn]; else LOGE("%s.\n", PartitionManager::Display::UsingDispString->not_spec_opt); PartitionManager::Strings::OutputName = PartitionManager::Strings::TargetPartition; if (total > (searchOn + 1) && PartitionManager::ControlArg(arguments[(searchOn + 1)])) { VLOGD("[class]: Non-mandatory argument was detected and retrieved (for %s function).\n", BaseFunctionName); PartitionManager::Strings::OutputName = arguments[(searchOn + 1)]; } PartitionManager::CheckOptSymbol(PartitionManager::Strings::TargetPartition); PartitionManager::CheckOptSymbol(PartitionManager::Strings::OutputName); } }; class PartitionManagerFlash : public PartitionManagerBase { public: void ArgumentProcessor(int& searchOn, int& total, char** &arguments) override { BaseFunctionName = "flash"; StartCode = 2; IsRequiredOnlyOneArg = false; GenericNumericalController(searchOn, total, PartitionManager::Display::UsingDispString->expected_flash_arg); if (PartitionManager::ControlArg(arguments[searchOn])) PartitionManager::Strings::TargetPartition = arguments[searchOn]; else LOGE("%s.\n", PartitionManager::Display::UsingDispString->not_spec_opt); if (PartitionManager::ControlArg(arguments[(searchOn + 1)])) PartitionManager::Strings::TargetFlashFile = arguments[(searchOn + 1)]; else LOGE("%s.\n", PartitionManager::Display::UsingDispString->not_spec_opt); PartitionManager::CheckOptSymbol(PartitionManager::Strings::TargetFlashFile); PartitionManager::CheckOptSymbol(PartitionManager::Strings::TargetPartition); } }; class PartitionManagerFormat : public PartitionManagerBase { public: void ArgumentProcessor(int& searchOn, int& total, char** &arguments) override { BaseFunctionName = "format"; StartCode = 3; IsRequiredOnlyOneArg = false; GenericNumericalController(searchOn, total, PartitionManager::Display::UsingDispString->expected_format_arg); if (PartitionManager::ControlArg(arguments[searchOn])) PartitionManager::Strings::TargetPartition = arguments[searchOn]; else LOGE("%s.\n", PartitionManager::Display::UsingDispString->not_spec_opt); if (PartitionManager::ControlArg(arguments[(searchOn + 1)])) PartitionManager::Strings::TargetFormatFS = arguments[(searchOn + 1)]; else LOGE("%s.\n", PartitionManager::Display::UsingDispString->not_spec_opt); PartitionManager::CheckOptSymbol(PartitionManager::Strings::TargetFormatFS); PartitionManager::CheckOptSymbol(PartitionManager::Strings::TargetPartition); } }; class PartitionManagerPartSize : public PartitionManagerBase { public: void ArgumentProcessor(int& searchOn, int& total, char** &arguments) override { BaseFunctionName = "partition-size"; StartCode = 4; IsRequiredOnlyOneArg = true; GenericNumericalController(searchOn, total, PartitionManager::Display::UsingDispString->expected_partsz_arg); if (PartitionManager::ControlArg(arguments[searchOn])) PartitionManager::Strings::TargetPartition = arguments[searchOn]; else LOGE("%s.\n", PartitionManager::Display::UsingDispString->not_spec_opt); PartitionManager::CheckOptSymbol(PartitionManager::Strings::TargetPartition); } }; /* Generate classes */ PartitionManagerBase* Base; PartitionManagerBase BaseTemplate; PartitionManagerBackup BackupArgProcessorBase; PartitionManagerFlash FlashArgProcessorBase; PartitionManagerFormat FormatArgProcessorBase; PartitionManagerPartSize PartSizeArgProcessorBase; namespace PartitionManager { static void ParseMainOperations(int argc, char** argv) { SearchOnMainInt = -1; Base = &BaseTemplate; VLOGD("Starting cycle for trapping main options...\n"); while (1) { if ((argc - 1) == 0) { VLOGD("argc - 1 = 0. Breaking...\n"); break; } if (argv[(argc - 1)][0] == '-') { VLOGD("argv[%d] starts with '-'. Continue.\n", (argc - 1)); argc--; continue; } else { Target = argv[(argc - 1)]; SearchOnMainInt = argc; VLOGD("argv[%d] = %s\n", (argc - 1), argv[(argc - 1)]); VLOGD("Variable of \"Target\" (string): %s\n", Target.c_str()); if (Target == "backup") { Base = &BackupArgProcessorBase; Config.BackupMode = true; break; } else if (Target == "flash") { Base = &FlashArgProcessorBase; Config.FlashMode = true; break; } else if (Target == "format") { Base = &FormatArgProcessorBase; Config.FormatMode = true; break; } else if (Target == "partition-size") { Base = &PartSizeArgProcessorBase; Config.PartSizeViewMode = true; break; } else { Target = ""; SearchOnMainInt = -1; argc--; continue; } } break; } } static char** ParseStdin(int argc, char** argv) { StdinArgcTotal = 0; char buf[256]; VLOGD("Checking stdin status...\n"); if (!isatty(fileno(stdin))) { VLOGD("stdin is not empty.\n"); VLOGD("Parsing stdin arguments...\n"); while (fgets(buf, sizeof(buf), stdin) != nullptr) { buf[strcspn(buf, "\n")] = 0; argv[argc] = strdup(buf); argc++; StdinArgcTotal++; } VLOGD("Parsing completed.\n"); } VLOGD("stdin empty.\n"); return argv; } static void ParseOptions(int argc, char** argv) { argc--; argv++; VLOGD("Parsing standart arguments...\n"); while (argc && argv[0] != nullptr) { if (argv[0][0] != '-') { argc--; argv++; continue; } for (int x = 1; true; x++) { Option = argv[0]; SomeSpec = true; switch (argv[0][x]) { case '-': if (Option == "--backup") deprecated('b', PartitionManager::Display::UsingDispString->depr_backup_opt, "backup"); else if (Option == "--flash") deprecated('F', PartitionManager::Display::UsingDispString->depr_flash_opt, "flash"); else if (Option == "--format") deprecated('r', PartitionManager::Display::UsingDispString->depr_format_opt, "format"); else if (Option == "--license") deprecated('L', PartitionManager::Display::UsingDispString->depr_Vlicense_opt, "license"); else if (Option == "--context") deprecated('c', PartitionManager::Display::UsingDispString->depr_ch_sp_opt, "context"); else if (Option == "--logical") { VLOGD("Logical partition type specified.\n"); LogicalSpeficy = true; break; } else if (Option == "--search-path") { VLOGD("Custom search path specified.\n"); if (argc > 1) PrSpInput(argv[1]); else LOGE("--search-path: %s.\n%s `%s --help' %s.\n", \ PartitionManager::Display::UsingDispString->is_requires_arg, \ PartitionManager::Display::UsingDispString->try_h, \ PartitionManager::Strings::ExecutingName.c_str(), \ PartitionManager::Display::UsingDispString->for_more); break; } else if (Option == "--list") { VLOGD("It was requested to list the partitions.\n"); ListRequired = true; if (ViewVersion || ViewHelp) MultipleViewers = true; break; } else if (Option == "--force") { VLOGD("Force mode speficed.\n"); Config.ForceMode = true; break; } else if (Option == "--verbose") { VLOGD("Verbose mode speficed.\n"); Config.VerboseMode = true; break; } else if (Option == "--silent") { VLOGD("Silent mode speficed.\n"); Config.SilentEnabled = true; break; } else if (Option == "--set-language") { VLOGD("It was requested to adjust the language.\n"); if (argc > 1) { VLOGE("Language inputs: getting inputs...\n"); SetLanguageReq = true; SpeficedLanguagePr = argv[1]; } else LOGE("--set-language: %s.\n%s `%s --help' %s.\n", PartitionManager::Display::UsingDispString->is_requires_arg, PartitionManager::Display::UsingDispString->try_h, PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->for_more); break; } else if (Option == "--as-byte") { PartSizeArgSpeficed = true; PartitionManager::Integers::PartSizeViewType = VIEW_AS_BYTE; break; } else if (Option == "--as-kilobyte") { PartSizeArgSpeficed = true; PartitionManager::Integers::PartSizeViewType = VIEW_AS_KIB; break; } else if (Option == "--as-megabyte") { PartSizeArgSpeficed = true; PartitionManager::Integers::PartSizeViewType = VIEW_AS_MIB; break; } else if (Option == "--as-gigabyte") { PartSizeArgSpeficed = true; PartitionManager::Integers::PartSizeViewType = VIEW_AS_GIB; break; } else if (Option == "--only-size") { PartSizeArgSpeficed = true; Config.OnlyViewSize = true; break; } else if (Option == "--version") { VLOGD("The version info was requested to be displayed.\n"); ViewVersion = true; if (ListRequired || ViewHelp) MultipleViewers = true; break; } else if (Option == "--help") { VLOGD("The help message was requested to be displayed.\n"); ViewHelp = true; if (ViewVersion || ListRequired) MultipleViewers = true; break; } else { VLOGE("Unknown Option: %s\n", argv[0]); LOGE("%s: %s.\n%s `%s --help' %s.\n", argv[0], PartitionManager::Display::UsingDispString->unknw_arg, PartitionManager::Display::UsingDispString->try_h, PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->for_more); } break; case 'b': deprecated('b', PartitionManager::Display::UsingDispString->depr_backup_opt, "backup"); break; case 'F': deprecated('F', PartitionManager::Display::UsingDispString->depr_flash_opt, "flash"); break; case 'r': deprecated('r', PartitionManager::Display::UsingDispString->depr_format_opt, "format"); break; case 'L': deprecated('L', PartitionManager::Display::UsingDispString->depr_Vlicense_opt, "license"); break; case 'D': deprecated('D', PartitionManager::Display::UsingDispString->depr_ch_list_opt); break; case 'c': deprecated('c', PartitionManager::Display::UsingDispString->depr_ch_sp_opt, "context"); case 'l': VLOGD("Logical partition type specified.\n"); LogicalSpeficy = true; continue; case 'P': VLOGD("Custom search path speficed.\n"); if (argc > 1) { VLOGE("Search-path inputs: getting inputs...\n"); PrSpInput(argv[1]); continue; } else LOGE("-P: %s.\n%s `%s --help' %s.\n", PartitionManager::Display::UsingDispString->is_requires_arg, PartitionManager::Display::UsingDispString->try_h, PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->for_more); break; case 'p': VLOGD("It was requested to list the partitions.\n"); ListRequired = true; if (ViewVersion || ViewHelp) MultipleViewers = true; continue; case 'f': VLOGD("Force mode speficed.\n"); Config.ForceMode = true; continue; case 'V': VLOGD("Verbose mode speficed.\n"); Config.VerboseMode = true; continue; case 's': VLOGD("Silent mode speficed.\n"); Config.SilentEnabled = true; continue; case 'S': VLOGD("It was requested to adjust the language.\n"); if (argc > 1) { VLOGE("Language inputs: getting inputs...\n"); SetLanguageReq = true; SpeficedLanguagePr = argv[1]; continue; } else LOGE("-S: %s.\n%s `%s --help' %s.\n", PartitionManager::Display::UsingDispString->is_requires_arg, PartitionManager::Display::UsingDispString->try_h, PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->for_more); case 'v': VLOGD("The version info was requested to be displayed.\n"); ViewVersion = true; if (ListRequired || ViewHelp) MultipleViewers = true; continue; case '\0': break; default: VLOGE("Unknown Option: -%c\n", argv[0][x]); LOGE("-%c: %s.\n%s `%s --help' %s.\n", argv[0][x], PartitionManager::Display::UsingDispString->unknw_arg, PartitionManager::Display::UsingDispString->try_h, PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->for_more); } break; } argc--; argv++; } } } /* namespace PartitionManager */ int main(int argc, char** argv) { PartitionManager::Strings::ExecutingName = basename(argv[0]); for (int i = 0; i <= (argc - 1); i++) { if (strncmp(argv[i], "-V", 2) == 0 || strcmp(argv[i], "--verbose") == 0) Config.VerboseMode = true; else continue; } VLOGD("Main function started. Setting up locale. Calling 'setlocale '\n"); setlocale(LC_ALL, ""); char** args = PartitionManager::ParseStdin(argc, argv); argc = (argc + StdinArgcTotal); /* It's not gonna be okay even 0. */ /* load language */ VLOGD("Loading language... Calling LoadLanguage()...\n"); if (!PartitionManager::LoadLanguage()) { cout << "LoadLanguage() process failed..!" << endl; abort(); } SymbolRule = PartitionManager::Display::UsingDispString->symbol_rule; int SearchResult = 3; PartitionManager::ParseOptions(argc, argv); PartitionManager::ParseMainOperations(argc, argv); if (Config.SilentEnabled && Config.VerboseMode) { VLOGE("Silent and verbose mode is one-way.\n"); cout << PartitionManager::Strings::ExecutingName << ": " << PartitionManager::Display::UsingDispString->s_and_v << endl; exit(1); } VLOGD("Checking last language switch status...\n"); if (PartitionManager::CleanSWPoint()) { VLOGD("Last transactions found that language was changed between.\n"); if (PartitionManager::Display::UsingDispString->welcome_ != nullptr) LOGD("%s", PartitionManager::Display::UsingDispString->welcome_); LOGD("%s %s %s %s.\n", PartitionManager::Display::UsingDispString->language, PartitionManager::Display::UsingDispString->welcome, PartitionManager::Display::UsingDispString->by_str, PartitionManager::Display::UsingDispString->lang_by_s); } /* check argument total */ VLOGD("argc (arguments) total: %d.\n", argc); if (argc < 2) LOGE("%s.\n%s '%s --help' %s.\n", PartitionManager::Display::UsingDispString->missing_operand, PartitionManager::Display::UsingDispString->try_h, PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->for_more); /* stop the program if multiple viewer is used */ if (MultipleViewers) { VLOGE("Multiple viewer option selected!\n"); LOGE("%s\n", PartitionManager::Display::UsingDispString->multiple_wiewers); } if (!Config.PartSizeViewMode && PartSizeArgSpeficed) { VLOGE("Related flags were detected, although some partition size was not requested.\n"); LOGE("%s.\n", PartitionManager::Display::UsingDispString->only_partsz_args); } /* controller to handle viewer */ if (ViewHelp) { VLOGD("The help message was asked to display. It's displayed... Calling DisplayHelp()\n"); PartitionManager::DisplayHelp(); return 0; } else if (ViewVersion) { VLOGD("The version info message was asked to display. It's displayed... Calling DisplayVersion()\n"); PartitionManager::DisplayVersion(); return 0; } else if (ListRequired) { VLOGD("Partitions were asked to be listed. It's listed... Calling CheckRoot() (root check is required), CheckDevPoint() (for generating warnings etc.) and ListPartitions()\n"); PartitionManager::CheckRoot(); VLOGD("CheckRoot() completed.\n"); PartitionManager::CheckDevPoint(); VLOGD("CheckDevPoint() completed.\n"); return PartitionManager::ListPartitions(); } if (SetLanguageReq) { VLOGD("The language was asked to adjust. Calling SetLanguage()...\n"); LOGD("%s: %s\n", PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->switching_lang); PartitionManager::SetLanguage(SpeficedLanguagePr, 0); sleep(2); VLOGD("SetLanguage() completed.\n"); LOGD("%s: %s.\n", PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->please_rerun); return 0; } if (Target.empty()) { VLOGE("There's no job to do.\n"); LOGD("%s: %s.\n", PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->missing_operand); if (SomeSpec) LOGD("%s.\n", PartitionManager::Display::UsingDispString->some_spec); LOGD("%s '%s --help' %s.\n", PartitionManager::Display::UsingDispString->try_h, PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->for_more); exit(1); } Base->ArgumentProcessor(SearchOnMainInt, argc, args); if (Config.FormatMode) { VLOGD("File system name specified for formatting is being contaminated...\n"); if (PartitionManager::Strings::TargetFormatFS != "ext4" \ && PartitionManager::Strings::TargetFormatFS != "ext3" \ && PartitionManager::Strings::TargetFormatFS != "ext2") { VLOGE("Unsupported file system: %s.\n", PartitionManager::Strings::TargetFormatFS.c_str()); LOGE("%s: %s\n", PartitionManager::Display::UsingDispString->unsupported_fs, PartitionManager::Strings::TargetFormatFS.c_str()); } } /* checks */ VLOGD("Checking root status... Calling CheckRoot()...\n"); PartitionManager::CheckRoot(); VLOGD("Checking A/B and logical device status... Calling CheckDevPoint()...\n"); PartitionManager::CheckDevPoint(); if (LogicalSpeficy) { VLOGD("Logical partition type speficed. Checking partition statust's...\n"); if (Config.UsesLogical) Config.UseLogical = true; else LOGE("%s\n", PartitionManager::Display::UsingDispString->not_logical); } if (Config.FlashMode) { VLOGD("The status of the specified file for flashing is being checked...\n"); SearchResult = PartitionManager::GetState(PartitionManager::Strings::TargetFlashFile); if (SearchResult == 1) LOGE("%s: `%s': %s\n", PartitionManager::Display::UsingDispString->cannot_stat, PartitionManager::Strings::TargetFlashFile.c_str(), strqerror()); else if (SearchResult == -1) LOGE("`%s': %s\n", PartitionManager::Strings::TargetFlashFile.c_str(), PartitionManager::Display::UsingDispString->not_file); } /* custom search path checker */ if (Config.UseCustomSearchPath) { VLOGD("The status of the \"dev\" is controlled in the specified custom /dev search path...\n"); if (strncmp(PartitionManager::Strings::CustomSearchPath.c_str(), "/dev", 4) != 0) { if (!Config.ForceMode) LOGE("%s\n", PartitionManager::Display::UsingDispString->not_in_dev); } VLOGD("The specified custom /dev search path is being put in countless...\n"); SearchResult = PartitionManager::GetState(PartitionManager::Strings::CustomSearchPath, "dir"); if (SearchResult == 1) LOGE("%s: `%s': %s\n", PartitionManager::Display::UsingDispString->cannot_stat, PartitionManager::Strings::CustomSearchPath.c_str(), strqerror()); else if (SearchResult == -1) LOGE("`%s': %s\n", PartitionManager::Strings::CustomSearchPath.c_str(), PartitionManager::Display::UsingDispString->not_dir); } VLOGD("The partition specification status is controlled...\n"); if (PartitionManager::Strings::TargetPartition.empty()) { if (!Config.ForceMode) LOGE("%s\n%s `%s --help' %s\n", PartitionManager::Display::UsingDispString->req_part_name, PartitionManager::Display::UsingDispString->try_h, PartitionManager::Strings::ExecutingName.c_str(), PartitionManager::Display::UsingDispString->for_more); } else { VLOGD("The call of main operations is being checked in case of the call...\n"); if (!Target.empty()) Base->CallTargetBaseFunction(); } } /* end of code */