Drop newlib printf: log via BDK s_vprintf, add debug.ini log switch
log_write was the only vsnprintf user and pulled in newlib's printf, dtoa, malloc and soft-float code (~44 KB). The payload now fits the RCM limit again (146800 -> 102801 bytes); the build fails if it grows past it. debug.ini log=1 writes sd:/config/omninx/install.log.
This commit is contained in:
1 parent
555ff07ae4
commit
702cce7d3e
7 files changed
+205
-156
No files matched your search
@@ -45,6 +45,12 @@ Create the folder `sd:/config/omninx/` on the SD card if it does not exist. Same
|
||||
|-----|-----------------|
|
||||
| `skip_hekate_8gb_post_copy` | After a successful copy: the optional `hekate_8GB` / RAM menu and related file moves (see `install_hekate_8gb_post_copy` in `install.c`) |
|
||||
|
||||
### Logging
|
||||
|
||||
| Key | Effect |
|
||||
|-----|--------|
|
||||
| `log` | Writes `sd:/config/omninx/install.log` with every deleted path, every copied file and the final result. Nothing is skipped. Slower on large packs; meant for test runs. |
|
||||
|
||||
## Behaviour
|
||||
|
||||
- On startup, if `debug.ini` exists and parses successfully, the payload prints a **DEBUG-MODUS** banner listing which skips are active.
|
||||
|
||||
@@ -60,7 +60,7 @@ OBJS_RAMTEST := $(filter-out $(BUILDDIR)/$(TARGET)/main.o,$(OBJS)) \
|
||||
all: $(OUTPUTDIR)/$(OUTPUT_NAME)
|
||||
$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(OUTPUT_NAME)))
|
||||
@echo "Payload size is $(BIN_SIZE) bytes (max $(MAX_PAYLOAD_SIZE) for RCM)"
|
||||
@if [ $(BIN_SIZE) -gt $(MAX_PAYLOAD_SIZE) ]; then echo "WARNING: payload exceeds the RCM size limit"; fi
|
||||
@if [ $(BIN_SIZE) -gt $(MAX_PAYLOAD_SIZE) ]; then echo "ERROR: payload exceeds the RCM size limit"; exit 1; fi
|
||||
|
||||
clean:
|
||||
@rm -rf $(BUILDDIR)
|
||||
|
||||
+127
-122
@@ -1,123 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sprintf.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static void _putc(char *buffer, const char c) {
|
||||
*buffer = c;
|
||||
}
|
||||
|
||||
static u32 _puts(char *buffer, const char *s) {
|
||||
u32 count = 0;
|
||||
for (; *s; s++, count++)
|
||||
_putc(buffer + count, *s);
|
||||
return count;
|
||||
}
|
||||
|
||||
static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt) {
|
||||
char buf[0x121];
|
||||
static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
char *p;
|
||||
int c = fcnt;
|
||||
|
||||
if (base > 36)
|
||||
return 0;
|
||||
|
||||
p = buf + 0x120;
|
||||
*p = 0;
|
||||
do {
|
||||
c--;
|
||||
*--p = digits[v % base];
|
||||
v /= base;
|
||||
} while (v);
|
||||
|
||||
if (fill != 0) {
|
||||
while (c > 0) {
|
||||
*--p = fill;
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
return _puts(buffer, p);
|
||||
}
|
||||
|
||||
u32 s_printf(char *buffer, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
int fill, fcnt;
|
||||
u32 count = 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
while(*fmt) {
|
||||
if (*fmt == '%') {
|
||||
fmt++;
|
||||
fill = 0;
|
||||
fcnt = 0;
|
||||
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') {
|
||||
fcnt = *fmt;
|
||||
fmt++;
|
||||
if (*fmt >= '0' && *fmt <= '9') {
|
||||
fill = fcnt;
|
||||
fcnt = *fmt - '0';
|
||||
fmt++;
|
||||
} else {
|
||||
fill = ' ';
|
||||
fcnt -= '0';
|
||||
}
|
||||
}
|
||||
switch (*fmt) {
|
||||
case 'c':
|
||||
_putc(buffer + count, va_arg(ap, u32));
|
||||
count++;
|
||||
break;
|
||||
case 's':
|
||||
count += _puts(buffer + count, va_arg(ap, char *));
|
||||
break;
|
||||
case 'd':
|
||||
count += _putn(buffer + count, va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'x':
|
||||
case 'X':
|
||||
count += _putn(buffer + count, va_arg(ap, u32), 16, fill, fcnt);
|
||||
break;
|
||||
case '%':
|
||||
_putc(buffer + count, '%');
|
||||
count++;
|
||||
break;
|
||||
case '\0':
|
||||
goto out;
|
||||
default:
|
||||
_putc(buffer + count, '%');
|
||||
count++;
|
||||
_putc(buffer + count, *fmt);
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_putc(buffer + count, *fmt);
|
||||
count++;
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
|
||||
out:
|
||||
buffer[count] = 0;
|
||||
va_end(ap);
|
||||
return count;
|
||||
/*
|
||||
* Copyright (c) 2019-2020 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sprintf.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static void _putc(char *buffer, const char c) {
|
||||
*buffer = c;
|
||||
}
|
||||
|
||||
static u32 _puts(char *buffer, const char *s) {
|
||||
u32 count = 0;
|
||||
for (; *s; s++, count++)
|
||||
_putc(buffer + count, *s);
|
||||
return count;
|
||||
}
|
||||
|
||||
static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt) {
|
||||
char buf[0x121];
|
||||
static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
char *p;
|
||||
int c = fcnt;
|
||||
|
||||
if (base > 36)
|
||||
return 0;
|
||||
|
||||
p = buf + 0x120;
|
||||
*p = 0;
|
||||
do {
|
||||
c--;
|
||||
*--p = digits[v % base];
|
||||
v /= base;
|
||||
} while (v);
|
||||
|
||||
if (fill != 0) {
|
||||
while (c > 0) {
|
||||
*--p = fill;
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
return _puts(buffer, p);
|
||||
}
|
||||
|
||||
u32 s_vprintf(char *buffer, const char *fmt, va_list ap) {
|
||||
int fill, fcnt;
|
||||
u32 count = 0;
|
||||
|
||||
while(*fmt) {
|
||||
if (*fmt == '%') {
|
||||
fmt++;
|
||||
fill = 0;
|
||||
fcnt = 0;
|
||||
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') {
|
||||
fcnt = *fmt;
|
||||
fmt++;
|
||||
if (*fmt >= '0' && *fmt <= '9') {
|
||||
fill = fcnt;
|
||||
fcnt = *fmt - '0';
|
||||
fmt++;
|
||||
} else {
|
||||
fill = ' ';
|
||||
fcnt -= '0';
|
||||
}
|
||||
}
|
||||
switch (*fmt) {
|
||||
case 'c':
|
||||
_putc(buffer + count, va_arg(ap, u32));
|
||||
count++;
|
||||
break;
|
||||
case 's':
|
||||
count += _puts(buffer + count, va_arg(ap, char *));
|
||||
break;
|
||||
case 'd':
|
||||
count += _putn(buffer + count, va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'x':
|
||||
case 'X':
|
||||
count += _putn(buffer + count, va_arg(ap, u32), 16, fill, fcnt);
|
||||
break;
|
||||
case '%':
|
||||
_putc(buffer + count, '%');
|
||||
count++;
|
||||
break;
|
||||
case '\0':
|
||||
goto out;
|
||||
default:
|
||||
_putc(buffer + count, '%');
|
||||
count++;
|
||||
_putc(buffer + count, *fmt);
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_putc(buffer + count, *fmt);
|
||||
count++;
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
|
||||
out:
|
||||
buffer[count] = 0;
|
||||
return count;
|
||||
}
|
||||
|
||||
u32 s_printf(char *buffer, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
u32 count = s_vprintf(buffer, fmt, ap);
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
||||
+26
-24
@@ -1,24 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SPRINTF_H_
|
||||
#define _SPRINTF_H_
|
||||
|
||||
#include "types.h"
|
||||
|
||||
u32 s_printf(char *buffer, const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2019-2020 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SPRINTF_H_
|
||||
#define _SPRINTF_H_
|
||||
|
||||
#include "types.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
u32 s_printf(char *buffer, const char *fmt, ...);
|
||||
u32 s_vprintf(char *buffer, const char *fmt, va_list ap);
|
||||
|
||||
#endif
|
||||
+13
-7
@@ -9,14 +9,15 @@
|
||||
#include <string.h>
|
||||
#include <utils/sprintf.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FS_BUFFER_SIZE 0x100000 // 1MB copy buffer
|
||||
#define LOG_BUFFER_SIZE 512
|
||||
#define LOG_BUFFER_SIZE 1024 // fits two 255-char paths plus text
|
||||
#define LOG_SYNC_EVERY 16
|
||||
|
||||
// Log file handle
|
||||
static FIL log_file;
|
||||
static bool log_enabled = false;
|
||||
static u32 log_lines;
|
||||
static char log_buf[LOG_BUFFER_SIZE];
|
||||
|
||||
// Initialize log file
|
||||
@@ -24,6 +25,7 @@ void log_init(const char *path) {
|
||||
int res = f_open(&log_file, path, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
if (res == FR_OK) {
|
||||
log_enabled = true;
|
||||
log_lines = 0;
|
||||
log_write("=== OmniNX Installer Log ===\n\n");
|
||||
}
|
||||
}
|
||||
@@ -44,15 +46,19 @@ void log_write(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
// Format the message
|
||||
vsnprintf(log_buf, LOG_BUFFER_SIZE, fmt, args);
|
||||
// BDK formatter (no newlib printf). Callers keep paths <= 255 chars.
|
||||
u32 len = s_vprintf(log_buf, fmt, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
// Write to file
|
||||
UINT bw;
|
||||
f_write(&log_file, log_buf, strlen(log_buf), &bw);
|
||||
f_sync(&log_file); // Flush to ensure data is written
|
||||
f_write(&log_file, log_buf, len, &bw);
|
||||
if (++log_lines % LOG_SYNC_EVERY == 0)
|
||||
f_sync(&log_file);
|
||||
}
|
||||
|
||||
bool log_is_enabled(void) {
|
||||
return log_enabled;
|
||||
}
|
||||
|
||||
// Convert FatFS error code to string
|
||||
|
||||
@@ -18,3 +18,4 @@ int folder_delete(const char *path);
|
||||
void log_init(const char *path);
|
||||
void log_close(void);
|
||||
void log_write(const char *fmt, ...);
|
||||
bool log_is_enabled(void);
|
||||
+31
-2
@@ -289,7 +289,9 @@ int folder_copy_with_progress_v2(const char *src, const char *dst, const char *d
|
||||
install_set_color(COLOR_WHITE);
|
||||
|
||||
// Perform the copy with progress updates
|
||||
log_write("COPY TREE %s -> %s (%d Eintraege)\n", src, dst, (u32)total);
|
||||
res = folder_copy_progress_recursive(src, dst, &copied, total, start_x, start_y, display_name, &last_percent);
|
||||
log_write("COPY TREE %s: %s\n", src, fs_error_str(res));
|
||||
|
||||
// Final update - overwrite the same line
|
||||
gfx_con_setpos(start_x, start_y);
|
||||
@@ -499,6 +501,7 @@ int delete_path_lists_grouped(const char *folder_display_name, ...) {
|
||||
res = f_unlink(path);
|
||||
}
|
||||
|
||||
log_write("DELETE %s: %s\n", path, fs_error_str(res));
|
||||
if (res == FR_OK || res == FR_NO_FILE)
|
||||
deleted++;
|
||||
else
|
||||
@@ -1343,6 +1346,7 @@ static void install_extras_post_copy(void)
|
||||
}
|
||||
|
||||
#define INSTALL_DEBUG_INI "sd:/config/omninx/debug.ini"
|
||||
#define INSTALL_LOG_PATH "sd:/config/omninx/install.log"
|
||||
|
||||
typedef struct {
|
||||
bool active;
|
||||
@@ -1356,6 +1360,7 @@ typedef struct {
|
||||
bool skip_update_staging_cleanup;
|
||||
bool skip_update_horizon_oc;
|
||||
bool skip_hekate_8gb_post_copy;
|
||||
bool log;
|
||||
} install_debug_opts_t;
|
||||
|
||||
static void install_debug_load(install_debug_opts_t *d)
|
||||
@@ -1397,6 +1402,8 @@ static void install_debug_load(install_debug_opts_t *d)
|
||||
d->skip_update_horizon_oc = install_ini_kv_truth(kv->val);
|
||||
else if (strcmp(kv->key, "skip_hekate_8gb_post_copy") == 0)
|
||||
d->skip_hekate_8gb_post_copy = install_ini_kv_truth(kv->val);
|
||||
else if (strcmp(kv->key, "log") == 0)
|
||||
d->log = install_ini_kv_truth(kv->val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1405,7 +1412,7 @@ static void install_debug_load(install_debug_opts_t *d)
|
||||
d->active = d->skip_clean_backup || d->skip_clean_wipe || d->skip_clean_restore
|
||||
|| d->skip_clean_install || d->skip_clean_staging_cleanup || d->skip_update_cleanup
|
||||
|| d->skip_update_install || d->skip_update_staging_cleanup || d->skip_update_horizon_oc
|
||||
|| d->skip_hekate_8gb_post_copy;
|
||||
|| d->skip_hekate_8gb_post_copy || d->log;
|
||||
}
|
||||
|
||||
static void install_debug_print_banner(const install_debug_opts_t *d)
|
||||
@@ -1435,17 +1442,39 @@ static void install_debug_print_banner(const install_debug_opts_t *d)
|
||||
gfx_printf(" ueberspringe: HorizonOC Update (Backup/Restore)\n");
|
||||
if (d->skip_hekate_8gb_post_copy)
|
||||
gfx_printf(" ueberspringe: extras RAM / Hekate-Auswahl / Post-Copy\n");
|
||||
if (d->log)
|
||||
gfx_printf(" Log: %s\n", INSTALL_LOG_PATH);
|
||||
install_set_color(COLOR_WHITE);
|
||||
gfx_printf("\n");
|
||||
}
|
||||
|
||||
static int perform_installation_steps(omninx_variant_t pack_variant, install_mode_t mode, const install_debug_opts_t *d);
|
||||
|
||||
// Main installation function
|
||||
int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
|
||||
int res;
|
||||
install_debug_opts_t dbg;
|
||||
install_debug_load(&dbg);
|
||||
install_debug_print_banner(&dbg);
|
||||
|
||||
if (dbg.log) {
|
||||
log_init(INSTALL_LOG_PATH);
|
||||
log_write("Version: %s\nModus: %s\nVariante: %d\n\n", VERSION,
|
||||
mode == INSTALL_MODE_UPDATE ? "Update" : "Clean", (u32)pack_variant);
|
||||
}
|
||||
|
||||
int res = perform_installation_steps(pack_variant, mode, &dbg);
|
||||
|
||||
if (log_is_enabled()) {
|
||||
log_write("\n=== Ende: res=%d (%s) ===\n", (u32)res, fs_error_str(res));
|
||||
log_close();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int perform_installation_steps(omninx_variant_t pack_variant, install_mode_t mode, const install_debug_opts_t *d) {
|
||||
int res;
|
||||
const install_debug_opts_t dbg = *d;
|
||||
|
||||
if (mode == INSTALL_MODE_UPDATE) {
|
||||
if (pack_variant == VARIANT_OC && !dbg.skip_update_horizon_oc) {
|
||||
bool had_horizon_cfg = install_path_exists(HORIZON_OC_CONFIG_PATH);
|
||||
|
||||
Reference in new issue
Block a user