Proto support and bux fixes

This commit is contained in:
rmc 2024-04-24 07:59:02 -04:00 committed by Edoardo Lolletti
parent 89c6f3ed87
commit 52cc3acad1

View File

@ -11,6 +11,7 @@
bool programEnd = false; bool programEnd = false;
bool sdnandMode = true; bool sdnandMode = true;
bool hasTitleTmdMatchingLauncher = true; bool hasTitleTmdMatchingLauncher = true;
bool notProto = true;
bool unlaunchInstallerFound = false; bool unlaunchInstallerFound = false;
bool unlaunchFound = false; bool unlaunchFound = false;
bool unlaunchPatches = false; bool unlaunchPatches = false;
@ -243,6 +244,19 @@ bool restoreMainTmd(const char* path)
fclose(launcherTmd); fclose(launcherTmd);
return true; return true;
} }
bool restoreProtoTmd(const char* path)
{
bool hnaaBackupExists = false;
hnaaBackupExists = (access("nand:/title/00030017/484e4141/content/title.tmd.bak", F_OK) == 0);
if (!hnaaBackupExists)
{
messageBox("\x1B[31mError:\x1B[33m No original tmd found!\nCan't uninstall unlaunch.\n");
return false;
}
copyFile("nand:/title/00030017/484e4141/content/title.tmd.bak", path);
return true;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
srand(time(0)); srand(time(0));
@ -277,7 +291,9 @@ int main(int argc, char **argv)
//check for unlaunch and region //check for unlaunch and region
char launcherTmdPath[64]; char launcherTmdPath[64];
char hnaaTmdPath[64];
{ {
sprintf(hnaaTmdPath, "nand:/title/00030017/484e4141/content/title.tmd");
FILE *file = fopen("nand:/sys/HWINFO_S.dat", "rb"); FILE *file = fopen("nand:/sys/HWINFO_S.dat", "rb");
if (file) if (file)
{ {
@ -287,6 +303,13 @@ int main(int argc, char **argv)
fclose(file); fclose(file);
region = launcherTid & 0xFF; region = launcherTid & 0xFF;
// I own and know of many people with retail and dev prototypes
// These can normally be identified by having the region set to ALL (41)
if (region == 0x41 || region == 0xFF)
{
notProto = false;
hasTitleTmdMatchingLauncher = true;
}
sprintf(launcherTmdPath, "nand:/title/00030017/%08lx/content/title.tmd", launcherTid); sprintf(launcherTmdPath, "nand:/title/00030017/%08lx/content/title.tmd", launcherTid);
unsigned long long tmdSize = getFileSizePath(launcherTmdPath); unsigned long long tmdSize = getFileSizePath(launcherTmdPath);
@ -299,15 +322,20 @@ int main(int argc, char **argv)
{ {
hasTitleTmdMatchingLauncher = false; hasTitleTmdMatchingLauncher = false;
} }
// HWINFO_S may not always exist (PRE_IMPORT). Fill in defaults if that happens.
} else {
sprintf(launcherTmdPath, "nand:/title/00030017/484e4141/content/title.tmd");
notProto = false;
hasTitleTmdMatchingLauncher = true;
} }
if (!unlaunchFound) if (!unlaunchFound)
{ {
unsigned long long tmdSize = getFileSizePath("nand:/title/00030017/484e4141/content/title.tmd"); unsigned long long tmdSize = getFileSizePath(hnaaTmdPath);
if (tmdSize > 520) if (tmdSize > 520)
{ {
unlaunchFound = true; unlaunchFound = true;
unlaunchPatches = checkIfUnlaunchHasPatches("nand:/title/00030017/484e4141/content/title.tmd"); unlaunchPatches = checkIfUnlaunchHasPatches(hnaaTmdPath);
} }
} }
@ -351,11 +379,19 @@ int main(int argc, char **argv)
case MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL: case MAIN_MENU_SAFE_UNLAUNCH_UNINSTALL:
if(hasTitleTmdMatchingLauncher && nandio_unlock_writing()) if(hasTitleTmdMatchingLauncher && nandio_unlock_writing())
{ {
if (!toggleReadOnly(launcherTmdPath, false) || !restoreMainTmd(launcherTmdPath)) if (notProto) {
{ if (!toggleReadOnly(launcherTmdPath, false) || !restoreMainTmd(launcherTmdPath))
messageBox("\x1B[31mError:\x1B[33m Uninstall failed\n"); {
nandio_lock_writing(); messageBox("\x1B[31mError:\x1B[33m Uninstall failed\n");
break; nandio_lock_writing();
break;
}
} else {
if (!toggleReadOnly(launcherTmdPath, false) || !restoreProtoTmd(launcherTmdPath)) {
messageBox("\x1B[31mError:\x1B[33m Uninstall failed\n");
nandio_lock_writing();
break;
}
} }
nandio_lock_writing(); nandio_lock_writing();
} }
@ -370,50 +406,146 @@ int main(int argc, char **argv)
FILE* unlaunchInstaller = fopen("sd:/unlaunch.dsi", "rb"); FILE* unlaunchInstaller = fopen("sd:/unlaunch.dsi", "rb");
if (!unlaunchInstaller) if (!unlaunchInstaller)
{ {
messageBox("\x1B[31mError:\x1B[33m Failed to open unlaunch installer\n"); messageBox("\x1B[31mError:\x1B[33m Failed to open unlaunch installer\n(sd:/unlaunch.dsi)\n");
nandio_lock_writing();
break;
}
//Create HNAA launcher folder
if (!safeCreateDir("nand:/title/00030017")
|| !safeCreateDir("nand:/title/00030017/484e4141")
|| !safeCreateDir("nand:/title/00030017/484e4141/content")) {
nandio_lock_writing(); nandio_lock_writing();
break; break;
} }
FILE* targetTmd = fopen("nand:/title/00030017/484e4141/content/title.tmd", "wb"); // Treat protos differently
if (!targetTmd) if (!notProto)
{ {
fclose(unlaunchInstaller); if (choiceBox("Your DSi has a non-standard\nregion.\n\x1B[31mInstalling unlaunch may be\nunsafe.\x1B[33m\nCancelling is recommended!\n\nContinue anyways?") == YES)
messageBox("\x1B[31mError:\x1B[33m Failed to open target unlaunch tmd\n"); {
rmdir("nand:/title/00030017/484e4141/content"); // Prototypes DSis are always HNAA. We can't use code that will nuke their launcher.
rmdir("nand:/title/00030017/484e4141");
nandio_lock_writing(); // Also some justification for adding proto support: they're really common.
break; // "Real" protos (X3, X4, etc) are hard to find but there are tons of release
// version DSis that are running prototype firmware.
// Likely factory rejects that never had production firmware flashed.
// We have to remove write protect otherwise reinstalling will fail.
if (access(hnaaTmdPath, F_OK) == 0) {
if (!toggleReadOnly(hnaaTmdPath, false))
{
fclose(unlaunchInstaller);
messageBox("\x1B[31mError:\x1B[33m Can't remove launcher tmd write protect\n");
nandio_lock_writing();
break;
}
}
bool hnaaBackupExists = false;
hnaaBackupExists = (access("nand:/title/00030017/484e4141/content/title.tmd.bak", F_OK) == 0);
// Back up the TMD since we'll be writing to it directly.
if (!hnaaBackupExists)
{
copyFile(hnaaTmdPath, "nand:/title/00030017/484e4141/content/title.tmd.bak");
}
FILE* targetTmd = fopen(hnaaTmdPath, "wb");
if (!targetTmd)
{
fclose(unlaunchInstaller);
messageBox("\x1B[31mError:\x1B[33m Failed to open target unlaunch tmd\n");
nandio_lock_writing();
break;
}
{
char buffer[1024] = {0};
//write the first 520 bytes as 0, as that's the size of a tmd, but it can be whatever content
if (fwrite(buffer, sizeof(char), 520, targetTmd) != 520)
{
fclose(unlaunchInstaller);
fclose(targetTmd);
messageBox("\x1B[31mError:\x1B[33m Failed write to unlaunch to tmd\n");
copyFile("nand:/title/00030017/484e4141/content/title.tmd.bak", hnaaTmdPath);
nandio_lock_writing();
break;
}
size_t n;
bool failed = false;
while ((n = fread(buffer, sizeof(char), sizeof(buffer), unlaunchInstaller)) > 0)
{
if (fwrite(buffer, sizeof(char), n, targetTmd) != n)
{
fclose(unlaunchInstaller);
fclose(targetTmd);
messageBox("\x1B[31mError:\x1B[33m Failed write unlaunch to tmd\n");
copyFile("nand:/title/00030017/484e4141/content/title.tmd.bak", hnaaTmdPath);
nandio_lock_writing();
failed = true;
break;
}
}
if (failed)
break;
if (!feof(unlaunchInstaller) || ferror(unlaunchInstaller))
{
fclose(unlaunchInstaller);
fclose(targetTmd);
messageBox("\x1B[31mError:\x1B[33m Failed read unlaunch installer\n");
copyFile("nand:/title/00030017/484e4141/content/title.tmd.bak", hnaaTmdPath);
nandio_lock_writing();
break;
}
}
fclose(unlaunchInstaller);
fclose(targetTmd);
// Mark the tmd as readonly
if (!toggleReadOnly(hnaaTmdPath, true))
{
// There is nothing that can be done at this point.
messageBox("\x1B[31mError:\x1B[33m Failed to mark tmd as read only\n");
}
nandio_lock_writing();
unlaunchFound = true;
messageBox("Unlaunch has been installed.\n");
} else {
nandio_lock_writing();
messageBox("Unlaunch install cancelled.\n");
break;
}
} }
// Do things normally for production units
else
{ {
char buffer[1024] = {0}; //Create HNAA launcher folder
//write the first 520 bytes as 0, as that's the size of a tmd, but it can be whatever content if (!safeCreateDir("nand:/title/00030017")
if (fwrite(buffer, sizeof(char), 520, targetTmd) != 520) || !safeCreateDir("nand:/title/00030017/484e4141")
|| !safeCreateDir("nand:/title/00030017/484e4141/content")) {
nandio_lock_writing();
break;
}
// We have to remove write protect otherwise reinstalling will fail.
if (access(hnaaTmdPath, F_OK) == 0) {
if (!toggleReadOnly(hnaaTmdPath, false))
{
fclose(unlaunchInstaller);
messageBox("\x1B[31mError:\x1B[33m Can't remove launcher tmd write protect\n");
nandio_lock_writing();
break;
}
}
FILE* targetTmd = fopen(hnaaTmdPath, "wb");
if (!targetTmd)
{ {
fclose(unlaunchInstaller); fclose(unlaunchInstaller);
fclose(targetTmd); messageBox("\x1B[31mError:\x1B[33m Failed to open target unlaunch tmd\n");
messageBox("\x1B[31mError:\x1B[33m Failed write to target unlaunch tmd\n");
remove("nand:/title/00030017/484e4141/content/title.tmd");
rmdir("nand:/title/00030017/484e4141/content"); rmdir("nand:/title/00030017/484e4141/content");
rmdir("nand:/title/00030017/484e4141"); rmdir("nand:/title/00030017/484e4141");
nandio_lock_writing(); nandio_lock_writing();
break; break;
} }
size_t n;
bool failed = false;
while ((n = fread(buffer, sizeof(char), sizeof(buffer), unlaunchInstaller)) > 0)
{ {
if (fwrite(buffer, sizeof(char), n, targetTmd) != n) char buffer[1024] = {0};
//write the first 520 bytes as 0, as that's the size of a tmd, but it can be whatever content
if (fwrite(buffer, sizeof(char), 520, targetTmd) != 520)
{ {
fclose(unlaunchInstaller); fclose(unlaunchInstaller);
fclose(targetTmd); fclose(targetTmd);
@ -422,70 +554,88 @@ int main(int argc, char **argv)
rmdir("nand:/title/00030017/484e4141/content"); rmdir("nand:/title/00030017/484e4141/content");
rmdir("nand:/title/00030017/484e4141"); rmdir("nand:/title/00030017/484e4141");
nandio_lock_writing(); nandio_lock_writing();
failed = true;
break; break;
} }
}
if (failed) size_t n;
break; bool failed = false;
if (!feof(unlaunchInstaller) || ferror(unlaunchInstaller))
while ((n = fread(buffer, sizeof(char), sizeof(buffer), unlaunchInstaller)) > 0)
{
if (fwrite(buffer, sizeof(char), n, targetTmd) != n)
{
fclose(unlaunchInstaller);
fclose(targetTmd);
messageBox("\x1B[31mError:\x1B[33m Failed write to target unlaunch tmd\n");
remove("nand:/title/00030017/484e4141/content/title.tmd");
rmdir("nand:/title/00030017/484e4141/content");
rmdir("nand:/title/00030017/484e4141");
nandio_lock_writing();
failed = true;
break;
}
}
if (failed)
break;
if (!feof(unlaunchInstaller) || ferror(unlaunchInstaller))
{
fclose(unlaunchInstaller);
fclose(targetTmd);
messageBox("\x1B[31mError:\x1B[33m Failed read unlaunch installer\n");
remove("nand:/title/00030017/484e4141/content/title.tmd");
rmdir("nand:/title/00030017/484e4141/content");
rmdir("nand:/title/00030017/484e4141");
nandio_lock_writing();
break;
}
}
fclose(unlaunchInstaller);
fclose(targetTmd);
//Mark the tmd as readonly
if(!toggleReadOnly(hnaaTmdPath, true))
{ {
fclose(unlaunchInstaller); messageBox("\x1B[31mError:\x1B[33m Failed to mark unlaunch's title.tmd as read only\n");
fclose(targetTmd);
messageBox("\x1B[31mError:\x1B[33m Failed read unlaunch installer\n");
remove("nand:/title/00030017/484e4141/content/title.tmd"); remove("nand:/title/00030017/484e4141/content/title.tmd");
rmdir("nand:/title/00030017/484e4141/content"); rmdir("nand:/title/00030017/484e4141/content");
rmdir("nand:/title/00030017/484e4141"); rmdir("nand:/title/00030017/484e4141");
nandio_lock_writing(); nandio_lock_writing();
break; break;
} }
}
fclose(unlaunchInstaller);
fclose(targetTmd);
//Mark the tmd as readonly //Finally patch the default launcher tmd to be invalid
if(toggleReadOnly("nand:/title/00030017/484e4141/content/title.tmd", true)) //If there isn't a title.tmd matching the language region in the hwinfo
{ // nothing else has to be done, could be a language patch, or a dev system, the user will know what they have done
messageBox("\x1B[31mError:\x1B[33m Failed to mark unlaunch's title.tmd as read only\n"); if (hasTitleTmdMatchingLauncher)
remove("nand:/title/00030017/484e4141/content/title.tmd"); {
rmdir("nand:/title/00030017/484e4141/content"); if(!patchMainTmd(launcherTmdPath))
rmdir("nand:/title/00030017/484e4141"); {
if(!toggleReadOnly(hnaaTmdPath, false))
{
messageBox("\x1B[31mError:\x1B[33m Failed to mark unlaunch's title.tmd as writable\nLeaving as is\n");
}
else
{
remove("nand:/title/00030017/484e4141/content/title.tmd");
rmdir("nand:/title/00030017/484e4141/content");
rmdir("nand:/title/00030017/484e4141");
}
nandio_lock_writing();
break;
}
if (!toggleReadOnly(launcherTmdPath, true))
{
#if 0
// TODO: Rollback or live with it?
messageBox("\x1B[31mError:\x1B[33m Failed to mark default launcher's title.tmd\nas read only, reverting the changes\n");
restoreMainTmd(launcherTmdPath)
#endif
}
}
nandio_lock_writing(); nandio_lock_writing();
break; unlaunchFound = true;
messageBox("Unlaunch has been installed.\n");
} }
//Finally patch the default launcher tmd to be invalid
//If there isn't a title.tmd matching the language region in the hwinfo
// nothing else has to be done, could be a language patch, or a dev system, the user will know what they have done
if (hasTitleTmdMatchingLauncher)
{
if(!patchMainTmd(launcherTmdPath))
{
if(!toggleReadOnly("nand:/title/00030017/484e4141/content/title.tmd", false))
{
messageBox("\x1B[31mError:\x1B[33m Failed to mark unlaunch's title.tmd as writable\nLeaving as is\n");
}
else
{
remove("nand:/title/00030017/484e4141/content/title.tmd");
rmdir("nand:/title/00030017/484e4141/content");
rmdir("nand:/title/00030017/484e4141");
}
nandio_lock_writing();
break;
}
if (!toggleReadOnly(launcherTmdPath, true))
{
#if 0
// TODO: Rollback or live with it?
messageBox("\x1B[31mError:\x1B[33m Failed to mark default launcher's title.tmd\nas read only, reverting the changes\n");
restoreMainTmd(launcherTmdPath)
#endif
}
}
nandio_lock_writing();
unlaunchFound = true;
messageBox("Unlaunch has been installed.\n");
} }
break; break;