diff --git a/DEBUG_INI.md b/DEBUG_INI.md
index fb297b9..ba91a46 100644
--- a/DEBUG_INI.md
+++ b/DEBUG_INI.md
@@ -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.
diff --git a/Makefile b/Makefile
index 818e888..53245f0 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/bdk/utils/sprintf.c b/bdk/utils/sprintf.c
index c53f15c..0a6389b 100644
--- a/bdk/utils/sprintf.c
+++ b/bdk/utils/sprintf.c
@@ -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 .
- */
-
-#include "sprintf.h"
-
-#include
-
-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 .
+ */
+
+#include "sprintf.h"
+
+#include
+
+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;
}
\ No newline at end of file
diff --git a/bdk/utils/sprintf.h b/bdk/utils/sprintf.h
index 0737775..7e2ef57 100644
--- a/bdk/utils/sprintf.h
+++ b/bdk/utils/sprintf.h
@@ -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 .
- */
-
-#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 .
+ */
+
+#ifndef _SPRINTF_H_
+#define _SPRINTF_H_
+
+#include "types.h"
+#include
+
+u32 s_printf(char *buffer, const char *fmt, ...);
+u32 s_vprintf(char *buffer, const char *fmt, va_list ap);
+
+#endif
diff --git a/source/fs.c b/source/fs.c
index 62053b5..7002a34 100644
--- a/source/fs.c
+++ b/source/fs.c
@@ -9,14 +9,15 @@
#include
#include
#include
-#include
#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
diff --git a/source/fs.h b/source/fs.h
index 9af9e22..2fb1309 100644
--- a/source/fs.h
+++ b/source/fs.h
@@ -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);
diff --git a/source/install.c b/source/install.c
index e649c74..8dec1b9 100644
--- a/source/install.c
+++ b/source/install.c
@@ -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);