mirror of
https://github.com/rvtr/unlaunch-installer_dev.git
synced 2026-01-26 13:43:08 -05:00
Proto support and bux fixes
This commit is contained in:
parent
89c6f3ed87
commit
52cc3acad1
324
arm9/src/main.c
324
arm9/src/main.c
@ -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;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user