diff --git a/Makefile b/Makefile index 46276e5..40c7fc0 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ MAKEFILES := sysmod overlay TARGETS := $(foreach dir,$(MAKEFILES),$(CURDIR)/$(dir)) # the below was taken from atmosphere + switch-examples makefile -export VERSION := 1.5.5 +export VERSION := 1.5.6 ifneq ($(strip $(shell git symbolic-ref --short HEAD 2>/dev/null)),) export GIT_BRANCH := $(shell git symbolic-ref --short HEAD) diff --git a/README.md b/README.md index f1940d8..82f05f7 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ patch_sysmmc=1 ; 1=(default) patch sysmmc, 0=don't patch sysmmc patch_emummc=1 ; 1=(default) patch emummc, 0=don't patch emummc enable_logging=1 ; 1=(default) output /config/sys-patch/log.ini 0=no log version_skip=1 ; 1=(default) skips out of date patterns, 0=search all patterns +clean_config=1 ; 1=(default) clean the config file 0=don't clean the config file ``` --- @@ -43,7 +44,7 @@ The overlay can be used to change the config options and to see what patches are - Install [devkitpro](https://devkitpro.org/wiki/Getting_Started) - Run the following: ```sh - git clone --recurse-submodules https://github.com/ITotalJustice/sys-patch.git + git clone --recurse-submodules https://github.com/impeeza/sys-patch.git cd ./sys-patch make ``` diff --git a/common/minIni/minGlue.c b/common/minIni/minGlue.c index 631ca1e..4ddd798 100644 --- a/common/minIni/minGlue.c +++ b/common/minIni/minGlue.c @@ -75,6 +75,35 @@ bool ini_read(char* buffer, u64 size, struct NxFile* nxfile) { return true; } +bool ini_read2(char* buffer, u64 size, struct NxFile* nxfile) { + u64 bytes_read = 0; + + if (R_FAILED(fsFileRead(&nxfile->file, nxfile->offset, buffer, size - 1, FsReadOption_None, &bytes_read))) { + return false; + } + + if (bytes_read == 0) { + return false; + } + + buffer[bytes_read] = '\0'; + + char* eol = strchr(buffer, '\n'); + if (!eol) { + eol = strchr(buffer, '\r'); + } + + if (eol) { + *eol = '\0'; + nxfile->offset += (eol - buffer + 1); + } else { + nxfile->offset += bytes_read; + return true; + } + + return true; +} + bool ini_write(const char* buffer, struct NxFile* nxfile) { const size_t size = strlen(buffer); if (R_FAILED(fsFileWrite(&nxfile->file, nxfile->offset, buffer, size, FsWriteOption_None))) { diff --git a/common/minIni/minGlue.h b/common/minIni/minGlue.h index 261f13d..1a40bec 100644 --- a/common/minIni/minGlue.h +++ b/common/minIni/minGlue.h @@ -22,6 +22,7 @@ bool ini_openwrite(const char* filename, struct NxFile* nxfile); bool ini_openrewrite(const char* filename, struct NxFile* nxfile); bool ini_close(struct NxFile* nxfile); bool ini_read(char* buffer, u64 size, struct NxFile* nxfile); +bool ini_read2(char* buffer, u64 size, struct NxFile* nxfile); bool ini_write(const char* buffer, struct NxFile* nxfile); bool ini_tell(struct NxFile* nxfile, s64* pos); bool ini_seek(struct NxFile* nxfile, s64* pos); diff --git a/common/minIni/minIni.c b/common/minIni/minIni.c index 90ee57b..96dd764 100644 --- a/common/minIni/minIni.c +++ b/common/minIni/minIni.c @@ -3,7 +3,7 @@ * These routines are in part based on the article "Multiplatform .INI Files" * by Joseph J. Graf in the March 1994 issue of Dr. Dobb's Journal. * - * Copyright (c) CompuPhase, 2008-2021 + * Copyright (c) CompuPhase, 2008-2024 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -949,4 +949,18 @@ int ini_putf(const TCHAR *Section, const TCHAR *Key, INI_REAL Value, const TCHAR return ini_puts(Section, Key, LocalBuffer, Filename); } #endif /* INI_REAL */ + +/** ini_putbool() + * \param Section the name of the section to write the value in + * \param Key the name of the entry to write + * \param Value the value to write; it should be 0 or 1. + * \param Filename the name and full path of the .ini file to write to + * + * \return 1 if successful, otherwise 0 + */ +int ini_putbool(const TCHAR *Section, const TCHAR *Key, int Value, const TCHAR *Filename) +{ + return ini_puts(Section, Key, Value ? __T("true") : __T("false"), Filename); +} + #endif /* !INI_READONLY */ diff --git a/common/minIni/minIni.h b/common/minIni/minIni.h index b63451c..9a68c87 100644 --- a/common/minIni/minIni.h +++ b/common/minIni/minIni.h @@ -1,6 +1,6 @@ /* minIni - Multi-Platform INI file parser, suitable for embedded systems * - * Copyright (c) CompuPhase, 2008-2021 + * Copyright (c) CompuPhase, 2008-2024 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -37,24 +37,25 @@ extern "C" { #endif -int ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename); -long ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename); -int ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); -int ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); -int ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); +int ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename); +long ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename); +int ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); +int ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); +int ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); -int ini_hassection(const mTCHAR *Section, const mTCHAR *Filename); -int ini_haskey(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Filename); +int ini_hassection(const mTCHAR *Section, const mTCHAR *Filename); +int ini_haskey(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Filename); #if defined INI_REAL INI_REAL ini_getf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL DefValue, const mTCHAR *Filename); #endif #if !defined INI_READONLY -int ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename); -int ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename); +int ini_putbool(const mTCHAR *Section, const mTCHAR *Key, int Value, const mTCHAR *Filename); +int ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename); +int ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename); #if defined INI_REAL -int ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename); +int ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename); #endif #endif /* INI_READONLY */ @@ -124,15 +125,15 @@ int ini_browse(INI_CALLBACK Callback, void *UserData, const mTCHAR *Filename); #endif #if ! defined INI_READONLY + bool put(const std::string& Section, const std::string& Key, bool Value) + { return ini_putbool(Section.c_str(), Key.c_str(), (int)Value, iniFilename.c_str()) != 0; } + bool put(const std::string& Section, const std::string& Key, long Value) { return ini_putl(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; } bool put(const std::string& Section, const std::string& Key, int Value) { return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; } - bool put(const std::string& Section, const std::string& Key, bool Value) - { return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; } - bool put(const std::string& Section, const std::string& Key, const std::string& Value) { return ini_puts(Section.c_str(), Key.c_str(), Value.c_str(), iniFilename.c_str()) != 0; } diff --git a/overlay/src/main.cpp b/overlay/src/main.cpp index 2afb6f3..d2fecf4 100644 --- a/overlay/src/main.cpp +++ b/overlay/src/main.cpp @@ -79,6 +79,7 @@ class GuiOptions final : public tsl::Gui { list->addItem(config_patch_emummc.create_list_item("Patch emuMMC")); list->addItem(config_logging.create_list_item("Logging")); list->addItem(config_version_skip.create_list_item("Version skip")); + list->addItem(config_clean_config.create_list_item("Clean configuration")); frame->setContent(list); return frame; @@ -88,6 +89,7 @@ class GuiOptions final : public tsl::Gui { ConfigEntry config_patch_emummc{"options", "patch_emummc", true}; ConfigEntry config_logging{"options", "enable_logging", true}; ConfigEntry config_version_skip{"options", "version_skip", true}; + ConfigEntry config_clean_config{"options", "clean_config", true}; }; class GuiToggle final : public tsl::Gui { diff --git a/sysmod/src/main.cpp b/sysmod/src/main.cpp index 005b2fd..6f00fd2 100644 --- a/sysmod/src/main.cpp +++ b/sysmod/src/main.cpp @@ -18,7 +18,15 @@ u32 AMS_VERSION{}; // set on startup u32 AMS_TARGET_VERSION{}; // set on startup u8 AMS_KEYGEN{}; // set on startup u64 AMS_HASH{}; // set on startup +bool patch_sysmmc; // set on startup +bool patch_emummc; // set on startup +bool enable_logging; // set on startup bool VERSION_SKIP{}; // set on startup +bool CLEAN_CONFIG{}; // set on startup + +constexpr auto ini_path = "/config/sys-patch/config.ini"; +constexpr auto log_path = "/config/sys-patch/log.ini"; +constexpr auto temp_path = "/config/sys-patch/temp.ini"; struct DebugEventInfo { u32 event_type; @@ -597,21 +605,208 @@ void keygen_to_str(char* s, u8 keygen) { num_2_str(s, keygen); } +char* strdup(const char* str) { + size_t len = strlen(str) + 1; + char* copy = (char*)malloc(len); + if (copy != NULL) { +strncpy(copy, str, len); + } + return copy; +} + +void trim(char* str) { + if (str == NULL) + return; + + char* start = str; + while (*start && isspace((unsigned char)*start)) + ++start; + + size_t len = strlen(start); + char* end = start + len - 1; + while (end > start && isspace((unsigned char)*end)) + --end; + + *(end + 1) = '\0'; + + if (start != str) + memmove(str, start, len - (start - str) + 1); +} + +int clean_config_file() { + ini_remove(temp_path); + NxFile file; + bool rc=ini_openread(ini_path, &file); + char line[128]; + char *line_trim = {}; + char *actual_section = {}; +if (!rc) { + return 1; + } + bool need_rewrite = false; + bool keep_section = false; + bool keep_config = false; + size_t buffer_length=sizeof(line); + size_t line_trim_alloc = buffer_length + 1; + bool first_line_init = false; + int count_buff_line_passed = 0; + int z = 0; + while (ini_read2(line, buffer_length, &file)) { + if (!first_line_init) { + line_trim = (char*) calloc(1, line_trim_alloc); + if (!line_trim) { + ini_close(&file); + return -1; + } + first_line_init = true; + } + strcat(line_trim, line); + if ((line_trim[strlen(line_trim) - 1] != '\r' && line_trim[strlen(line_trim) - 1] != '\n') && strlen(line_trim) > 0) { + z++; + if (z > count_buff_line_passed) { + line_trim_alloc += buffer_length; + line_trim = (char*) realloc(line_trim, line_trim_alloc); + if (!line_trim) { + if (actual_section) free(actual_section); + if (line_trim) free(line_trim); + ini_close(&file); + return -1; + } + count_buff_line_passed++; + } + continue; + } + z = 0; + trim(line_trim); + if (line_trim[0] == '\0' || line_trim[0] == ';' || line_trim[0] == '\n' || line_trim[0] == '\r') { + memset(line_trim, '\0', line_trim_alloc); + continue; + } + if (line_trim[0] == '[' && line_trim[strlen(line_trim) - 1] == ']') { + keep_section = false; + line_trim[strlen(line_trim) - 1] = '\0'; + if (actual_section) { + free(actual_section); + } + actual_section = strdup(line_trim + 1); + if (strcmp(actual_section, "options") == 0) { + keep_section = true; + memset(line_trim, '\0', line_trim_alloc); + continue; + } + for (auto& patch : patches) { + if (strcmp(patch.name, actual_section) == 0) { + keep_section = true; + break; + } + } + if (!keep_section) { + need_rewrite = true; + break; + } + } else { + keep_config = false; + if (!keep_section) { + need_rewrite = true; + break; + } + char *pos = strchr(line_trim, '='); + if (pos != NULL) { + *pos = '\0'; + trim(line_trim); + if ((strcmp(actual_section, "options") == 0) && (strcmp(line_trim, "patch_sysmmc") == 0 || strcmp(line_trim, "patch_emummc") == 0 || strcmp(line_trim, "enable_logging") == 0 || strcmp(line_trim, "version_skip") == 0 || strcmp(line_trim, "clean_config") == 0)) { + memset(line_trim, '\0', line_trim_alloc); + continue; + } + for (auto& patch : patches) { + for (auto& p : patch.patterns) { + if (strcmp(p.patch_name, line_trim) == 0) { + keep_config = true; + break; + } + } + if (keep_config) { + break; + } + } + if (!keep_config) { + need_rewrite = true; + break; + } + } + } + memset(line_trim, '\0', line_trim_alloc); + } + ini_close(&file); + if (line_trim) { + free(line_trim); + } + if (actual_section) { + free(actual_section); + } + + if (!need_rewrite) { + return 0; + } + + bool user_val = ini_getbool("options", "patch_sysmmc", 1, ini_path); + if (ini_putl("options", "patch_sysmmc", user_val, temp_path) == 0) { + return -1; + } + user_val = ini_getbool("options", "patch_emummc", 1, ini_path); + if (ini_putl("options", "patch_emummc", user_val, temp_path) == 0) { + return -1; + } + user_val = ini_getbool("options", "enable_logging", 1, ini_path); + if (ini_putl("options", "enable_logging", user_val, temp_path) == 0) { + return -1; + } + user_val = ini_getbool("options", "version_skip", 1, ini_path); + if (ini_putl("options", "version_skip", user_val, temp_path) == 0) { + return -1; + } + user_val = ini_getbool("options", "clean_config", 1, ini_path); + if (ini_putl("options", "clean_config", user_val, temp_path) == 0) { + return -1; + } + + for (auto& patch : patches) { + for (auto& p : patch.patterns) { + user_val = ini_getbool(patch.name, p.patch_name, p.enabled, ini_path); + if (ini_putl(patch.name, p.patch_name, user_val, temp_path) == 0) { + return -1; + } + } + } + ini_remove(ini_path); +ini_rename(temp_path, ini_path); + return 1; +} + } // namespace int main(int argc, char* argv[]) { - constexpr auto ini_path = "/config/sys-patch/config.ini"; - constexpr auto log_path = "/config/sys-patch/log.ini"; - create_dir("/config/"); create_dir("/config/sys-patch/"); ini_remove(log_path); // load options - const auto patch_sysmmc = ini_load_or_write_default("options", "patch_sysmmc", 1, ini_path); - const auto patch_emummc = ini_load_or_write_default("options", "patch_emummc", 1, ini_path); - const auto enable_logging = ini_load_or_write_default("options", "enable_logging", 1, ini_path); + patch_sysmmc = ini_load_or_write_default("options", "patch_sysmmc", 1, ini_path); + patch_emummc = ini_load_or_write_default("options", "patch_emummc", 1, ini_path); + enable_logging = ini_load_or_write_default("options", "enable_logging", 1, ini_path); VERSION_SKIP = ini_load_or_write_default("options", "version_skip", 1, ini_path); + CLEAN_CONFIG = ini_load_or_write_default("options", "clean_config", 1, ini_path); + + if (CLEAN_CONFIG) { + int rc = clean_config_file(); + if (rc == 0) { + ini_puts("clean_config_file", "result", "Nicht noetig", log_path); + } else if (rc == 1) { + ini_puts("clean_config_file", "result", "Bereinigt", log_path); + } else { + ini_puts("clean_config_file", "result", "Fehler beim bereinigen", log_path); + } + } // load patch toggles for (auto& patch : patches) { @@ -681,7 +876,7 @@ int main(int argc, char* argv[]) { // defined in the Makefile #define DATE (DATE_DAY "." DATE_MONTH "." DATE_YEAR " " DATE_HOUR ":" DATE_MIN ":" DATE_SEC) - ini_puts("stats", "version", VERSION_WITH_HASH, log_path); + ini_puts("stats", "Version", VERSION_WITH_HASH, log_path); ini_puts("stats", "build_date", DATE, log_path); ini_puts("stats", "fw_version", fw_version, log_path); ini_puts("stats", "ams_version", ams_version, log_path);