Add the option to uninstall Aroma

This commit is contained in:
rw-r-r-0644 2020-12-01 02:05:24 +01:00
parent 6e5b719676
commit 592dca6679
4 changed files with 233 additions and 15 deletions

View File

@ -34,7 +34,9 @@ void ApplicationState::render() {
WiiUScreen::drawLine("Getting app information");
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE) {
WiiUScreen::drawLine("Check if console can be patched.");
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE_DONE) {
} else if (this->state == STATE_CHECK_REMOVAL_POSSIBLE) {
WiiUScreen::drawLine("Check if Aroma can be removed.");
} else if (this->state == STATE_INSTALL_MENU) {
WiiUScreen::drawLinef("Compatible title:");
WiiUScreen::drawLinef("%s", appInfo->appName);
WiiUScreen::drawLine();
@ -74,12 +76,24 @@ void ApplicationState::render() {
WiiUScreen::drawLine();
WiiUScreen::drawLine("Press A to return to the Wii U Menu");
} else {
std::string options = "";
WiiUScreen::drawLine("Do you want to install Aroma?");
WiiUScreen::drawLine("");
if (this->selectedOption == 0) {
WiiUScreen::drawLine("> Install Exit");
} else if (this->selectedOption == 1) {
WiiUScreen::drawLine(" Install > Exit");
if (this->removalPossible) {
if (this->selectedOption == 0) {
WiiUScreen::drawLine("> Exit Install Remove");
} else if (this->selectedOption == 1) {
WiiUScreen::drawLine(" Exit > Install Remove");
} else if (this->selectedOption == 2) {
WiiUScreen::drawLine(" Exit Install > Remove");
}
} else {
if (this->selectedOption == 0) {
WiiUScreen::drawLine("> Exit Install");
} else if (this->selectedOption == 1) {
WiiUScreen::drawLine(" Exit > Install");
}
}
}
} else if (this->state == STATE_INSTALL_CHOOSE_COLDBOOT) {
@ -104,7 +118,7 @@ void ApplicationState::render() {
if (this->selectedOption == 0) {
WiiUScreen::drawLine("> Back Install without Coldboot");
} else if (this->selectedOption == 1) {
WiiUScreen::drawLine("> Back > Install without Coldboot");
WiiUScreen::drawLine(" Back > Install without Coldboot");
}
} else if (this->state == STATE_INSTALL_CONFIRM_DIALOG) {
WiiUScreen::drawLine("Are you REALLY sure you want to install Aroma?");
@ -143,6 +157,28 @@ void ApplicationState::render() {
WiiUScreen::drawLine("Aroma was successfully installed");
WiiUScreen::drawLine();
WiiUScreen::drawLine("Press A to shutdown the console");
} else if (this->state == STATE_REMOVE_CONFIRM_DIALOG) {
WiiUScreen::drawLine("Are you REALLY sure you want to remove Aroma?");
WiiUScreen::drawLine("If you have installed unsigned system");
WiiUScreen::drawLine("applications or modified system files");
WiiUScreen::drawLine("this could make your console unusable");
WiiUScreen::drawLine();
WiiUScreen::drawLine();
if (this->selectedOption == 0) {
WiiUScreen::drawLine("> Back Remove");
} else if (this->selectedOption == 1) {
WiiUScreen::drawLine(" Back > Remove");
}
} else if (this->state == STATE_REMOVE_STARTED) {
WiiUScreen::drawLine("Removing...");
} else if (this->state == STATE_REMOVE_COLDBOOT) {
WiiUScreen::drawLine("... remove system.xml coldboot patches");
} else if (this->state == STATE_REMOVE_AROMA) {
WiiUScreen::drawLine("... remove Aroma application patches");
} else if (this->state == STATE_REMOVE_SUCCESS) {
WiiUScreen::drawLine("Aroma was successfully removed");
WiiUScreen::drawLine();
WiiUScreen::drawLine("Press A to shutdown the console");
}
printFooter();
WiiUScreen::flipBuffers();
@ -169,17 +205,21 @@ void ApplicationState::update(Input *input) {
getAppInformation();
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE) {
checkPatchPossible();
} else if (this->state == STATE_CHECK_PATCH_POSSIBLE_DONE) {
} else if (this->state == STATE_CHECK_REMOVAL_POSSIBLE) {
checkRemovalPossible();
} else if (this->state == STATE_INSTALL_MENU) {
if (this->fstPatchPossible && this->cosPatchPossible) {
proccessMenuNavigation(input, 2);
proccessMenuNavigation(input, 2 + (this->removalPossible ? 1 : 0));
if (entrySelected(input)) {
if (this->selectedOption == 0) {
if (this->selectedOption == 1) {
if (systemXMLPatchPossible) {
this->state = STATE_INSTALL_CHOOSE_COLDBOOT;
this->installColdboot = false;
} else {
this->state = STATE_INSTALL_CONFIRM_DIALOG;
}
} else if ((this->selectedOption == 2) && this->removalPossible) {
this->state = STATE_REMOVE_CONFIRM_DIALOG;
} else {
SYSLaunchMenu();
}
@ -202,7 +242,7 @@ void ApplicationState::update(Input *input) {
proccessMenuNavigation(input, 3);
if (entrySelected(input)) {
if (this->selectedOption == 0) { // Back
this->state = STATE_CHECK_PATCH_POSSIBLE_DONE;
this->state = STATE_INSTALL_MENU;
} else {
if (selectedOption == 1) { // Install with coldboot
this->installColdboot = true;
@ -216,7 +256,7 @@ void ApplicationState::update(Input *input) {
proccessMenuNavigation(input, 2);
if (entrySelected(input)) {
if (this->selectedOption == 0) {
this->state = STATE_CHECK_PATCH_POSSIBLE_DONE;
this->state = STATE_INSTALL_MENU;
} else {
this->state = STATE_INSTALL_CONFIRM_DIALOG;
}
@ -226,7 +266,7 @@ void ApplicationState::update(Input *input) {
proccessMenuNavigation(input, 2);
if (entrySelected(input)) {
if (this->selectedOption == 0) {
this->state = STATE_CHECK_PATCH_POSSIBLE_DONE;
this->state = STATE_INSTALL_MENU;
} else {
this->state = STATE_INSTALL_STARTED;
OSEnableHomeButtonMenu(false);
@ -296,6 +336,52 @@ void ApplicationState::update(Input *input) {
if (entrySelected(input)) {
OSShutdown();
}
} else if (this->state == STATE_REMOVE_CONFIRM_DIALOG) {
proccessMenuNavigation(input, 2);
if (entrySelected(input)) {
if (this->selectedOption == 0) {
this->state = STATE_INSTALL_MENU;
} else {
this->state = STATE_REMOVE_STARTED;
OSEnableHomeButtonMenu(false);
}
this->selectedOption = 0;
return;
}
} else if (this->state == STATE_REMOVE_STARTED) {
this->state = STATE_REMOVE_COLDBOOT;
} else if (this->state == STATE_REMOVE_COLDBOOT) {
auto result = InstallerService::patchSystemXML("storage_slc_installer:/config", *this->systemMenuTitleId);
if (result != InstallerService::SUCCESS) {
setError(ERROR_INSTALLER_ERROR);
this->installerError = result;
} else {
auto fsaFd = IOSUHAX_FSA_Open();
if (fsaFd >= 0) {
if (IOSUHAX_FSA_FlushVolume(fsaFd, "/vol/storage_mlc01") == 0) {
DEBUG_FUNCTION_LINE("Flushed mlc");
}
if (IOSUHAX_FSA_FlushVolume(fsaFd, "/vol/system") == 0) {
DEBUG_FUNCTION_LINE("Flushed slc");
}
IOSUHAX_FSA_Close(fsaFd);
} else {
DEBUG_FUNCTION_LINE("Failed to open fsa");
}
this->state = STATE_REMOVE_AROMA;
}
} else if (this->state == STATE_REMOVE_AROMA) {
auto result = InstallerService::restoreAppFiles(this->appInfo->path);
if (result != InstallerService::SUCCESS) {
setError(ERROR_INSTALLER_ERROR);
this->installerError = result;
} else {
this->state = STATE_REMOVE_SUCCESS;
}
} else if (this->state == STATE_REMOVE_SUCCESS) {
if (entrySelected(input)) {
OSShutdown();
}
}
}
@ -345,8 +431,24 @@ void ApplicationState::checkPatchPossible() {
if (result != InstallerService::SUCCESS) {
DEBUG_FUNCTION_LINE("ERROR: %s", InstallerService::ErrorMessage(result).c_str());
}
this->state = STATE_CHECK_PATCH_POSSIBLE_DONE;
if (this->rpxAlreadyPatched) {
this->state = STATE_CHECK_REMOVAL_POSSIBLE;
} else {
this->state = STATE_INSTALL_MENU;
}
}
void ApplicationState::checkRemovalPossible() {
this->removalPossible = false;
this->systemMenuTitleId = InstallerService::getSystemMenuTitleId();
if (this->systemMenuTitleId) {
this->removalPossible = InstallerService::checkSystemXML("storage_slc_installer:/config", *this->systemMenuTitleId) == InstallerService::SUCCESS;
this->removalPossible &= InstallerService::isBackupAvailable(this->appInfo->path);
}
this->state = STATE_INSTALL_MENU;
}
void ApplicationState::getAppInformation() {

View File

@ -21,7 +21,8 @@ public:
STATE_WELCOME_SCREEN,
STATE_GET_APP_INFORMATION,
STATE_CHECK_PATCH_POSSIBLE,
STATE_CHECK_PATCH_POSSIBLE_DONE,
STATE_CHECK_REMOVAL_POSSIBLE,
STATE_INSTALL_MENU,
STATE_INSTALL_CHOOSE_COLDBOOT,
STATE_INSTALL_NO_COLDBOOT_ALLOWED,
STATE_INSTALL_CONFIRM_DIALOG,
@ -31,7 +32,12 @@ public:
STATE_INSTALL_COS,
STATE_INSTALL_RPX,
STATE_INSTALL_SYSTEM_XML,
STATE_INSTALL_SUCCESS
STATE_INSTALL_SUCCESS,
STATE_REMOVE_CONFIRM_DIALOG,
STATE_REMOVE_STARTED,
STATE_REMOVE_COLDBOOT,
STATE_REMOVE_AROMA,
STATE_REMOVE_SUCCESS
};
ApplicationState();
@ -44,6 +50,8 @@ public:
void checkPatchPossible();
void checkRemovalPossible();
void getAppInformation();
std::optional<appInformation> appInfo;
@ -69,11 +77,13 @@ private:
bool fstPatchPossible = false;
bool cosPatchPossible = false;
bool systemXMLPatchPossible = false;
bool removalPossible = false;
eGameState state;
eErrorState error = ERROR_NONE;
uint64_t coldbootTitleId;
_gList_t *coldbootTitle;
std::optional<uint64_t> systemMenuTitleId;
bool fstAlreadyPatched;
bool rpxAlreadyPatched;
bool cosAlreadyPatched;

View File

@ -186,6 +186,35 @@ std::optional<appInformation> InstallerService::getInstalledAppInformation() {
return {};
}
std::optional<uint64_t> InstallerService::getSystemMenuTitleId() {
auto mcpHandle = (int32_t) MCP_Open();
auto titleCount = (uint32_t) 1;
auto *titleList = (MCPTitleListType *) memalign(32, sizeof(MCPTitleListType) * titleCount);
MCP_TitleListByAppType(mcpHandle, MCP_APP_TYPE_SYSTEM_MENU, &titleCount, titleList, sizeof(MCPTitleListType) * titleCount);
MCP_Close(mcpHandle);
if (titleCount != 1) {
DEBUG_FUNCTION_LINE("More than 1 System Menu title!? Found %d", titleCount);
return {};
}
if ((titleList->titleId != 0x0005001010040000L) &&
(titleList->titleId != 0x0005001010040100L) &&
(titleList->titleId != 0x0005001010040200L))
{
DEBUG_FUNCTION_LINE("Unrecognized System Menu title");
return {};
}
uint64_t menuTid = titleList->titleId;
free(titleList);
return menuTid;
}
InstallerService::eResults InstallerService::patchFSTData(uint8_t *fstData, uint32_t size) {
auto *fstHeader = (FSTHeader *) fstData;
if (strncmp(FSTHEADER_MAGIC, fstHeader->magic, 3) != 0) {
@ -317,6 +346,77 @@ std::string InstallerService::ErrorMessage(InstallerService::eResults error) {
}
bool InstallerService::isBackupAvailable(const std::string &path) {
std::string backupList[] = {
{"/content/title.fst.bak"},
{"/content/cos.xml.bak" },
{"/content/safe.rpx.bak" },
};
for (auto &backupEntry : backupList) {
std::string backupFile = path + backupEntry;
std::string backupSha1 = backupFile + ".sha1";
if (!FSUtils::CheckFile(backupFile.c_str())) {
return false;
}
if (!FSUtils::CheckFile(backupSha1.c_str())) {
continue;
}
uint8_t *sha1FileCont;
uint32_t sha1FileSize;
FSUtils::LoadFileToMem(backupSha1.c_str(), &sha1FileCont, &sha1FileSize);
if (!sha1FileCont) {
return false;
}
std::string savedHash = std::string(sha1FileCont, sha1FileCont + sha1FileSize);
std::string fileHash = Utils::hashFile(backupFile);
if (fileHash != savedHash) {
return false;
}
}
return true;
}
InstallerService::eResults InstallerService::restoreAppFiles(const std::string &path) {
std::string backupList[][2] = {
{"/code/title.fst", "/content/title.fst.bak"},
{"/code/cos.xml", "/content/cos.xml.bak" },
{"/code/safe.rpx", "/content/safe.rpx.bak" },
};
for (auto &backupOp : backupList) {
std::string destPath = path + backupOp[0];
std::string backupPath = path + backupOp[1];
if (!FSUtils::copyFile(backupPath, destPath)) {
DEBUG_FUNCTION_LINE("Failed to copy files");
return FAILED_TO_COPY_FILES;
}
std::string srcHash = Utils::hashFile(backupPath);
std::string dstHash = Utils::hashFile(destPath);
if (srcHash != dstHash) {
DEBUG_FUNCTION_LINE("Hashes do not match. %s %s", srcHash.c_str(), dstHash.c_str());
return FAILED_TO_CHECK_HASH_COPIED_FILES;
}
}
for (auto &backupOp : backupList) {
std::string backupPath = path + backupOp[1];
std::string backupSha1Path = backupPath + ".sha1";
::remove(backupPath.c_str());
::remove(backupSha1Path.c_str());
}
DEBUG_FUNCTION_LINE("Successfully restored app files");
return SUCCESS;
}
InstallerService::eResults InstallerService::backupAppFiles(const std::string &path) {
std::string backupList[][2] = {
{"/code/title.fst", "/content/title.fst.bak"},

View File

@ -43,6 +43,10 @@ public:
return false;
}
static bool isBackupAvailable(const std::string &path);
static eResults restoreAppFiles(const std::string &path);
static eResults backupAppFiles(const std::string &path);
static eResults patchCOS(const std::string &path, char *hash);
@ -55,6 +59,8 @@ public:
static std::optional<appInformation> getInstalledAppInformation();
static std::optional<uint64_t> getSystemMenuTitleId();
static std::string ErrorMessage(eResults error);
static std::string ErrorDescription(eResults error);