-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmain.cpp
executable file
·666 lines (584 loc) · 23.4 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
#include "cert_patches/cert_backup_strategy.hpp"
#include "cert_patches/cert_backup.hpp"
#include "cert_patches/cert_hashes.hpp"
#include "menu/menu_done.hpp"
#include "menu/menu_loading.hpp"
#include "menu/menu_miiverse_confirm.hpp"
#include "menu/menu.hpp"
#include "rpx_patches/rpx_backup_strategy.hpp"
#include "rpx_patches/rpx_backup.hpp"
#include "rpx_patches/rpx_hashes.hpp"
#include "rpx_patches/rpx_patch.hpp"
#include "util/log.h"
#include "util/copy_file.hpp"
#include "util/util.hpp"
#include "util/titles.hpp"
#include "util/iosu_fs.hpp"
#include "version.h"
#include <cstdio>
#include <array>
#include <map>
#include <fstream>
#include <sstream>
#include <string>
#include <filesystem>
#include <whb/log_console.h>
#include <whb/proc.h>
#include <coreinit/mcp.h>
#include <vpad/input.h>
#include <romfs-wiiu.h>
#define REBOOT_TID 0xFFFFFFFFFFFFFFFEllu
extern "C" {
//remove when wut adds it
void OSLaunchTitlel(uint64_t titleId, int argc, ...);
void FSAInit();
int FSAAddClient(void *asyncAttachData);
int FSAFlushVolume(int handle, const char *path);
int FSADelClient(int handle);
}
static constexpr int task_percent(int task, int TasksNumber) { return (task * 100) / TasksNumber; };
int main(int argc, char **argv) {
int ret;
bool bret;
int task = 0;
LOGInit();
ramfsInit();
//WHBLogConsoleInit();
WHBProcInit();
OnLeavingScope _log_c([&] {
WHBProcShutdown();
//WHBLogConsoleFree();
ramfsExit();
LOGShutdown();
});
FSAInit();
int fsaHandle = FSAAddClient(NULL);
printf("FSA handle: %08x\n", fsaHandle);
OnLeavingScope _fsa_c([&] {
if (!(fsaHandle < 0)) {
FSADelClient(fsaHandle);
fsaHandle = 0;
}
});
bret = InitMenu();
if (!bret) {
printf("failed to set up menu!\n");
return -1;
}
OnLeavingScope _mnu_c([&] { QuitMenu(); });
printf(APP_NAME " " APP_VERSION "\n");
RenderMenuLoading(task_percent(task++, 5), "Finding Miiverse title...");
PresentMenu();
std::filesystem::path miiverse_path;
/* Haxchi requires MCP functions to be kept somewhat isolated, so we get
* them all out of the way early before we set up iosuhax. */
{
auto mcp = MCP_Open();
if (mcp < 0) {
printf("couldn't open MCP: %d\n", mcp);
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_MCP_FAIL);
PresentMenu();
}
return -1;
}
OnLeavingScope _mcp_c([&] {
MCP_Close(mcp);
mcp = -1;
});
miiverse_path = GetTitlePath(mcp, MCP_APP_TYPE_MIIVERSE);
if (miiverse_path.empty()) {
printf("couldn't find Miiverse title!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_NO_MIIVERSE);
PresentMenu();
}
return -1;
}
printf("miiverse found at %s\n", miiverse_path.c_str());
}
/* No more MCP functions from here on out. OK to set up iosuhax. */
RenderMenuLoading(task_percent(task++, 5), "Checking CFW...");
PresentMenu();
ret = iosu_fs_setup();
if (ret < 0) {
printf("failed to set up iosuhax!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_NO_CFW);
PresentMenu();
}
return -1;
}
OnLeavingScope _ios_c([&] {
iosu_fs_stop();
});
//goal: get a state together; ready to show a menu or something
//https://marcan.st/2011/01/safe-hacking/
std::filesystem::path wave_path = miiverse_path / "code/wave.rpx";
std::filesystem::path wave_bak_path = miiverse_path / "code/wave.rpx.orig";
std::filesystem::path wave_patched_path = miiverse_path / "code/wave.rpx.patched";
std::filesystem::path pn_olv_path = miiverse_path / "code/pn_olv.rpl";
std::filesystem::path nn_olv_path = "iosu:/vol/system_slc/title/00050010/1000400a/code/nn_olv.rpl";
std::filesystem::path pn_olv_patched_path = miiverse_path / "code/pn_olv.rpl.patched";
std::filesystem::path cert_path = "iosu:/vol/storage_mlc01/sys/title/0005001b/10054000/content/scerts/THAWTE_PREMIUM_SERVER_CA.der";
std::filesystem::path cert_bak_path = "iosu:/vol/storage_mlc01/sys/title/0005001b/10054000/content/scerts/THAWTE_PREMIUM_SERVER_CA.der.orig";
std::filesystem::path cert_patched_path = "resin:/pkcazroot.der";
std::error_code fserr;
RenderMenuLoading(task_percent(task++, 5), "Examining current Miiverse state... (wave.rpx)");
PresentMenu();
BackupState wave_state = GetBackupStrategy(wave_path, wave_bak_path);
if (!wave_state.strategy) {
//couldn't come up with a way to continue
printf("Could not find a suitable backup strategy!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_NO_BACKUP);
PresentMenu();
}
return -1;
}
BackupStrategy wave_strategy = *wave_state.strategy;
RenderMenuLoading(task_percent(task++, 5), "Examining current Miiverse state... (nn_olv.rpl)");
PresentMenu();
//we can be a bit less careful with nn_olv, since we always have the stock file on hand
//if the stock file is bad, the patcher should catch it
BackupStrategy olv_strategy = {
.need_confirmation = false,
.backup_action = B_DO_NOTHING,
.patch_action = P_PATCH_FROM_BACKUP,
};
RenderMenuLoading(task_percent(task++, 5), "Examining current Miiverse state... (NSSL cert)");
PresentMenu();
//certs use a different strategy, since we're always overwriting from resin
auto cert_strategy_o = GetCertBackupStrategy(cert_path, cert_bak_path);
if (!cert_strategy_o) {
//couldn't continue
printf("Could not find a suitable certificate backup strategy!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_NO_CERT_BACKUP);
PresentMenu();
}
return -1;
}
BackupStrategy cert_strategy = *cert_strategy_o;
bool proc = true;
bool IsPatching;
bool AllowUninstalling = false;
//Checks if a healthy backup to see if it can unintstall
std::ifstream isc(wave_bak_path, std::ios::binary);
auto hash = rpx_hash(isc);
if (wave_state.backup_exists && hash.patch == RPX_PATCH_STATE_STOCK) {
AllowUninstalling = true;
}
while ((proc = WHBProcIsRunning())) {
VPADStatus vpad;
VPADReadError error;
VPADRead(VPAD_CHAN_0, &vpad, 1, &error);
if (error == VPAD_READ_SUCCESS) {
if (vpad.trigger & VPAD_BUTTON_A) {
IsPatching = true;
break;
}
else if (vpad.trigger & VPAD_BUTTON_Y && AllowUninstalling) {
IsPatching = false;
break;
}
}
RenderMenuMiiverseConfirm(wave_state);
if (AllowUninstalling) { RenderUninstallText(); }
PresentMenu();
}
if (!proc) {
//loop broke because user quit from menu overlay
return 0;
}
//otherwise we can continue
//check if user wants to patch or restore
if (IsPatching) {
task = 0;
RenderMenuLoading(task_percent(task++, 14), "Creating Miiverse backup... (wave.rpx)");
PresentMenu();
bret = backup_rpx(wave_strategy.backup_action, wave_path, wave_bak_path);
if (!bret) {
printf("Failed to backup wave!\n");
wave_strategy.patch_action = P_DO_NOTHING;
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_BACKUP_FAIL);
PresentMenu();
}
return -1;
}
RenderMenuLoading(task_percent(task++, 14), "Creating Miiverse backup... (pn_olv.rpl)");
PresentMenu();
bret = backup_rpx(olv_strategy.backup_action, pn_olv_path, nn_olv_path);
if (!bret) {
printf("Failed to backup olv!\n");
olv_strategy.patch_action = P_DO_NOTHING;
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_BACKUP_FAIL);
PresentMenu();
}
return -1;
}
RenderMenuLoading(task_percent(task++, 14), "Creating Miiverse backup... (NSSL cert)");
PresentMenu();
bret = backup_cert(cert_strategy.backup_action, cert_path, cert_bak_path);
if (!bret) {
printf("Failed to backup cert!\n");
cert_strategy.patch_action = P_DO_NOTHING;
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_BACKUP_FAIL);
PresentMenu();
}
return -1;
}
RenderMenuLoading(task_percent(task++, 14), "Applying Miiverse patches... (wave.rpx)");
PresentMenu();
bret = patch_rpx(wave_strategy.patch_action, wave_path, wave_bak_path, wave_patched_path,
"resin:/patches/wave.d.v113.p1.bps");
if (!bret) {
printf("Failed to patch wave!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL);
PresentMenu();
}
return -1;
}
RenderMenuLoading(task_percent(task++, 14), "Applying Miiverse patches... (nn_olv.rpl)");
PresentMenu();
//DANGER: getting argument order wrong here could cause brickable writes to OSv10!
bret = patch_rpx(olv_strategy.patch_action, pn_olv_path, nn_olv_path, pn_olv_patched_path,
"resin:/patches/nn_olv.d.v15072.p1.bps");
if (!bret) {
printf("Failed to patch olv!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL);
PresentMenu();
}
return -1;
}
RenderMenuLoading(task_percent(task++, 14), "Verifying patched files... (wave.rpx)");
PresentMenu();
{
std::ifstream is(wave_patched_path, std::ios::binary);
auto hash = rpx_hash(is);
if (hash.id != CURRENT_PRETENDO_WAVE) {
printf("Patcher made a corrupt file!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_BAD);
PresentMenu();
}
return -1;
}
}
RenderMenuLoading(task_percent(task++, 14), "Verifying patched files... (nn_olv.rpl)");
PresentMenu();
{
std::ifstream is(pn_olv_patched_path, std::ios::binary);
auto hash = rpx_hash(is);
if (hash.id != CURRENT_PRETENDO_NN_OLV) {
printf("Patcher made a corrupt file!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_BAD);
PresentMenu();
}
return -1;
}
}
RenderMenuLoading(task_percent(task++, 14), "Verifying patched files... (NSSL cert)");
PresentMenu();
{
std::ifstream is(cert_patched_path, std::ios::binary);
auto hash = cert_hash(is);
if (hash.id != CURRENT_PRETENDO_CERT) {
printf("New SSL cert is corrupt!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_BAD);
PresentMenu();
}
return -1;
}
}
//the point of no return
RenderMenuLoading(task_percent(task++, 14), "Committing changes... (wave.rpx)");
PresentMenu();
bret = fast_copy_file(wave_patched_path, wave_path);
if (!bret) {
printf("Final file copy failed!\n");
//the next step is verification. on the off chance the copy 100% failed
//and the stock wave is still there, we could still quit gracefully, so
//we don't hard-fail here.
}
RenderMenuLoading(task_percent(task++, 14), "Committing changes... (nn_olv.rpl)");
PresentMenu();
bret = fast_copy_file(pn_olv_patched_path, pn_olv_path);
if (!bret) {
printf("Final olv file copy failed!\n");
}
RenderMenuLoading(task_percent(task++, 14), "Committing changes... (NSSL cert)");
PresentMenu();
bret = fast_copy_file(cert_patched_path, cert_path);
if (!bret) {
printf("Final olv file copy failed!\n");
}
RenderMenuLoading(task_percent(task++, 14), "Verifying final patches... (wave.rpx)");
PresentMenu();
{
std::ifstream is(wave_path, std::ios::binary);
auto hash = rpx_hash(is);
if (hash.patch == RPX_PATCH_STATE_STOCK) {
printf("Failed to commit patches - stock wave in place\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL);
PresentMenu();
}
return -1;
} else if (hash.id != CURRENT_PRETENDO_WAVE) {
printf("Failed to commit patches - wave corrupt!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_DANGEROUS);
PresentMenu();
}
return -1;
}
}
RenderMenuLoading(task_percent(task++, 14), "Verifying final patches... (nn_olv.rpl)");
PresentMenu();
{
std::ifstream is(pn_olv_path, std::ios::binary);
auto hash = rpx_hash(is);
if (hash.id != CURRENT_PRETENDO_NN_OLV) {
//we've already modified wave, so this is always dangerous
printf("Failed to commit patches - pn_olv corrupt!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_DANGEROUS);
PresentMenu();
}
return -1;
}
}
RenderMenuLoading(task_percent(task++, 14), "Verifying final patches... (NSSL cert)");
PresentMenu();
{
std::ifstream is(cert_path, std::ios::binary);
auto hash = cert_hash(is);
if (hash.id != CURRENT_PRETENDO_CERT) {
//we've already modified wave, so this is always dangerous
printf("Failed to commit patches - nssl cert corrupt!\n");
//oh shit, this could brick - restore backup
bret = fast_copy_file(cert_bak_path, cert_path);
if (!bret) {
printf("Reverting nssl patches failed!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_CERT_BRICK);
PresentMenu();
}
return -1;
}
std::ifstream is2(cert_path, std::ios::binary);
auto hash2 = cert_hash(is2);
if (hash2.patch != CERT_PATCH_STATE_STOCK) {
printf("Reverting nssl patches failed!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_CERT_BRICK);
PresentMenu();
}
return -1;
} else if (hash2.id != CURRENT_SACRIFICIAL_CERT) {
printf("Reverting NSSL cert resulted in the wrong cert?\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_DANGEROUS);
PresentMenu();
}
return -1;
}
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_DANGEROUS);
PresentMenu();
}
return -1;
}
}
//Flush Volumes
RenderMenuLoading(task_percent(task++, 14), "Flushing volumes...");
PresentMenu();
ret = FSAFlushVolume(fsaHandle, "/vol/storage_mlc01");
printf("FSAFlushVolume: %08x\n", ret);
//woo!
while (true) {
VPADStatus vpad;
VPADReadError error;
VPADRead(VPAD_CHAN_0, &vpad, 1, &error);
if (error == VPAD_READ_SUCCESS) {
if (vpad.trigger & VPAD_BUTTON_A) break;
}
RenderMenuDone(MENU_DONE_NO_ERROR);
PresentMenu();
}
printf("rebooting\n");
OSLaunchTitlel(REBOOT_TID, 0);
while (WHBProcIsRunning()) {}
return 0;
} else {
task = 0;
//User wants to Restore to Stock
//Check if Backup Exists
RenderMenuLoading(task_percent(task++, 7), "Checking for Backup... (wave.rpx)");
PresentMenu();
std::ifstream is(wave_bak_path, std::ios::binary);
auto hash = rpx_hash(is);
if (!wave_state.backup_exists || hash.patch != RPX_PATCH_STATE_STOCK) {
//No Backup for wave.rpx or corrupt
printf("Failed - No Backup Exists (wave.rpx)\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_NO_BACKUP);
PresentMenu();
}
return -1;
}
RenderMenuLoading(task_percent(task++, 7), "Checking for Backup... (NSSL cert)");
PresentMenu();
std::ifstream is2(cert_bak_path, std::ios::binary);
auto hash2 = cert_hash(is2);
if (hash2.patch != CERT_PATCH_STATE_STOCK || hash2.id != CERT_ID_THWATE_PREMIUM_SERVER) {
//No Backup for NSSL or corrupt
printf("Failed - No Backup Exists (NSSL cert)\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_NO_CERT_BACKUP);
PresentMenu();
}
return -1;
}
//Restore Backup
RenderMenuLoading(task_percent(task++, 7), "Restoring Miiverse backup... (wave.rpx)");
PresentMenu();
bret = backup_rpx(B_RESTORE_BACKUP, wave_path, wave_bak_path);
if (!bret) {
printf("Failed to restore wave!\n");
wave_strategy.patch_action = P_DO_NOTHING;
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_RESTORE_FAIL);
PresentMenu();
}
return -1;
}
/* RenderMenuLoading(task_percent(task++,7), "Removing Custom RPL... (pn_olv.rpl)");
PresentMenu();
std::filesystem::remove(pn_olv_path) */ //It Wont hurt not to remove them lol
RenderMenuLoading(task_percent(task++, 7), "Restoring Miiverse backup... (NSSL cert)");
PresentMenu();
bret = backup_cert(B_RESTORE_BACKUP, cert_path, cert_bak_path);
if (!bret) {
// ashquarky: better to leave it alone and let the Verify step catch it
// it might have copied succesfully or done nothing, so verify will check the hash
// the only time this fix is needed is in case of a partial copy
printf("Failed to restore NSSL cert - bricky bricky!\n");
//SHIT, QUICK ATTEMPT TO FIX
// bret = fast_copy_file(cert_bak_path, cert_path);
// if (!bret) {
// printf("Reverting nssl patches failed!\n");
// while (WHBProcIsRunning()) { RenderMenuDone(MENU_DONE_PATCH_FAIL_CERT_BRICK); PresentMenu(); }
// return -1;
// }
}
RenderMenuLoading(task_percent(task++, 7), "Verifying final patches... (wave.rpx)");
PresentMenu();
{
std::ifstream is(wave_path, std::ios::binary);
auto hash = rpx_hash(is);
if (hash.patch == RPX_PATCH_STATE_PRETENDO) {
printf("Failed to commit patches - Pretendo still in place\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_RESTORE_FAIL);
PresentMenu();
}
return -1;
} else if (hash.patch != RPX_PATCH_STATE_STOCK) {
printf("Failed to commit patches - It may be Corrupted\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_DANGEROUS);
PresentMenu();
}
return -1;
}
}
RenderMenuLoading(task_percent(task++, 7), "Verifying final patches... (nn_olv.rpl)");
PresentMenu();
{
std::ifstream is(nn_olv_path, std::ios::binary);
auto hash = rpx_hash(is);
if (hash.patch != RPX_PATCH_STATE_STOCK) {
//Just checking if it is not damaged
printf("Failed to commit patches - nn_olv corrupt!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_DANGEROUS);
PresentMenu();
}
return -1;
}
}
RenderMenuLoading(task_percent(task++, 7), "Verifying final patches... (NSSL cert)");
PresentMenu();
{
std::ifstream is(cert_path, std::ios::binary);
auto hash = cert_hash(is);
if (hash.id != CERT_ID_THWATE_PREMIUM_SERVER) {
//we've already modified wave, so this is always dangerous
printf("Failed to commit patches - nssl cert corrupt!\n");
//oh shit, this could brick - restore backup
bret = fast_copy_file(cert_bak_path, cert_path);
if (!bret) {
printf("Reverting nssl patches failed!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_CERT_BRICK);
PresentMenu();
}
return -1;
}
std::ifstream is2(cert_path, std::ios::binary);
auto hash2 = cert_hash(is2);
if (hash2.patch != CERT_PATCH_STATE_STOCK) {
printf("Reverting nssl patches failed!\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_CERT_BRICK);
PresentMenu();
}
return -1;
} else if (hash2.id != CURRENT_SACRIFICIAL_CERT) {
printf("Reverting NSSL cert resulted in the wrong cert?\n");
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_PATCH_FAIL_DANGEROUS);
PresentMenu();
}
return -1;
}
// if we got here, the cert is now the correct one
// still, some weird shit went down, so throw a soft error (not PATCH_FAIL_DANGEROUS though)
while (WHBProcIsRunning()) {
RenderMenuDone(MENU_DONE_RESTORE_FAIL);
PresentMenu();
}
return -1;
}
}
//Flush Volumes
RenderMenuLoading(task_percent(8, 8), "Flushing volumes...");
PresentMenu();
ret = FSAFlushVolume(fsaHandle, "/vol/storage_mlc01");
printf("FSAFlushVolume: %08x\n", ret);
//woo!
while (true) {
VPADStatus vpad;
VPADReadError error;
VPADRead(VPAD_CHAN_0, &vpad, 1, &error);
if (error == VPAD_READ_SUCCESS) {
if (vpad.trigger & VPAD_BUTTON_A) break;
}
RenderMenuDone(MENU_DONE_RESTORE_DONE);
PresentMenu();
}
printf("rebooting\n");
OSLaunchTitlel(REBOOT_TID, 0);
while (WHBProcIsRunning()) {}
return 0;
}
}