Keep one generation back, and verify before touching the existing build
Without this, a successful transfer of a BROKEN build stranded you: the only
copy of a working test program had already been overwritten, so there was no
way to attempt another transfer without an SD card reader.
Write order is now temp -> verify -> rotate, and the ordering is the point:
- The image goes to "<name>.tmp" and is read back and compared BEFORE
anything existing is touched. If the transfer, the write or the verify
fails, the build you are running is still on the card untouched and you
can simply try again. Previously a failed write left the destination
half-overwritten.
- On success the existing build is rotated to "<name>.prev.dol" and the temp
file takes its place. So if the NEW build turns out to be broken, boot
the previous one from Swiss and transfer again from there. One generation
back is enough never to need a card reader.
The two extensions are chosen deliberately:
- the temp file has NO .dol extension, because Swiss lists .dol files and a
half-written image Swiss offers to boot is exactly what this avoids;
- the backup KEEPS .dol, because booting it from Swiss is the whole point of
keeping it.
remove()/rename() on a file that is not there is ignored -- that is just the
first update on a fresh card. If the final rename somehow fails, the message
names the .prev.dol path rather than leaving the user to guess where their
working build went.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -131,10 +131,12 @@ static void do_netboot(char *status, size_t nstatus)
|
||||
|
||||
printf("\n" C_HEAD " Self-update over the BBA" C_RESET "\n\n");
|
||||
printf(" On the host: sudo ./scripts/send-dol.py <iface> <file.dol>\n\n");
|
||||
printf(C_DIM " The received build is WRITTEN TO THE SD CARD and verified;\n"
|
||||
" it is never launched directly. This then boots /boot.dol --\n"
|
||||
" your known-good Swiss -- so a broken test build costs nothing:\n"
|
||||
" Swiss comes up and can load whatever you like.\n" C_RESET "\n");
|
||||
printf(C_DIM " The received build is written to a TEMP file, verified, and\n"
|
||||
" only then rotated in -- the previous build is kept alongside it\n"
|
||||
" as <name>.prev.dol, so if the new one is broken you can boot the\n"
|
||||
" old one from Swiss and try the transfer again.\n"
|
||||
" Nothing received is ever launched directly: this boots /boot.dol,\n"
|
||||
" your known-good Swiss.\n" C_RESET "\n");
|
||||
printf(" Blocks until done or it times out (30 s idle, 5 s mid-xfer).\n\n");
|
||||
|
||||
if (!s_stage) {
|
||||
@@ -152,7 +154,8 @@ static void do_netboot(char *status, size_t nstatus)
|
||||
if (rc < 0) {
|
||||
/* Nothing has been launched and nothing is half-written that we
|
||||
* know of, so staying in the menu is the safe outcome. */
|
||||
snprintf(status, nstatus, "SD write failed (%d) - nothing launched", rc);
|
||||
snprintf(status, nstatus,
|
||||
"SD write failed (%d) - existing build untouched", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user