mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-28 01:20:58 +01:00
ams_mitm: Implement system settings mitm
This commit is contained in:
parent
55610694c8
commit
c10ba67973
54
stratosphere/ams_mitm/source/amsmitm_debug.cpp
Normal file
54
stratosphere/ams_mitm/source/amsmitm_debug.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 <stratosphere.hpp>
|
||||
#include "amsmitm_debug.hpp"
|
||||
|
||||
namespace ams::mitm {
|
||||
|
||||
namespace {
|
||||
|
||||
os::Mutex g_throw_lock;
|
||||
bool g_threw;
|
||||
Result g_throw_result;
|
||||
|
||||
|
||||
void DebugThrowThreadFunc(void *arg);
|
||||
|
||||
constexpr size_t DebugThrowThreadStackSize = 0x4000;
|
||||
constexpr int DebugThrowThreadPriority = 49;
|
||||
os::StaticThread<DebugThrowThreadStackSize> g_debug_throw_thread(&DebugThrowThreadFunc, nullptr, DebugThrowThreadPriority);
|
||||
|
||||
void DebugThrowThreadFunc(void *arg) {
|
||||
/* TODO: Better heuristic for fatal startup than sleep. */
|
||||
svcSleepThread(10'000'000'000ul);
|
||||
fatalThrow(g_throw_result.GetValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ThrowResultForDebug(Result res) {
|
||||
std::scoped_lock lk(g_throw_lock);
|
||||
|
||||
if (g_threw) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_throw_result = res;
|
||||
g_threw = true;
|
||||
R_ASSERT(g_debug_throw_thread.Start());
|
||||
}
|
||||
|
||||
}
|
23
stratosphere/ams_mitm/source/amsmitm_debug.hpp
Normal file
23
stratosphere/ams_mitm/source/amsmitm_debug.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::mitm {
|
||||
|
||||
void ThrowResultForDebug(Result res);
|
||||
|
||||
}
|
@ -26,7 +26,7 @@ namespace ams::mitm::fs {
|
||||
|
||||
/* Helpers. */
|
||||
Result EnsureSdInitialized() {
|
||||
R_UNLESS(mitm::IsInitialized(), ams::fs::ResultSdCardNotPresent());
|
||||
R_UNLESS(serviceIsActive(&g_sd_filesystem.s), ams::fs::ResultSdCardNotPresent());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <stratosphere.hpp>
|
||||
#include "amsmitm_initialization.hpp"
|
||||
#include "amsmitm_fs_utils.hpp"
|
||||
#include "bpc_mitm/bpc_ams_power_utils.hpp"
|
||||
|
||||
namespace ams::mitm {
|
||||
|
||||
@ -35,11 +36,15 @@ namespace ams::mitm {
|
||||
/* Wait for the SD card to be ready. */
|
||||
cfg::WaitSdCardInitialized();
|
||||
|
||||
/* TODO: Other initialization tasks. */
|
||||
|
||||
/* Open global SD card file system, so that other threads can begin using the SD. */
|
||||
mitm::fs::OpenGlobalSdCardFileSystem();
|
||||
|
||||
/* Initialize the reboot manager (load a payload off the SD). */
|
||||
/* Discard result, since it doesn't need to succeed. */
|
||||
mitm::bpc::LoadRebootPayload();
|
||||
|
||||
/* TODO: Other initialization tasks. */
|
||||
|
||||
/* Signal to waiters that we are ready. */
|
||||
g_init_event.Signal();
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
#include "amsmitm_initialization.hpp"
|
||||
#include "amsmitm_module_management.hpp"
|
||||
#include "bpc_mitm/bpc_ams_power_utils.hpp"
|
||||
|
||||
extern "C" {
|
||||
extern u32 __start__;
|
||||
@ -50,8 +51,7 @@ namespace ams {
|
||||
/* Override. */
|
||||
void ExceptionHandler(FatalErrorContext *ctx) {
|
||||
/* We're bpc-mitm (or ams_mitm, anyway), so manually reboot to fatal error. */
|
||||
/* Utils::RebootToFatalError(ctx); */
|
||||
while (1) { /* ... */ }
|
||||
mitm::bpc::RebootForFatalError(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,10 +41,6 @@ namespace ams::mitm::bpc {
|
||||
/* Wait until initialization is complete. */
|
||||
mitm::WaitInitialized();
|
||||
|
||||
/* Initialize the reboot manager (load a payload off the SD). */
|
||||
/* Discard result, since it doesn't need to succeed. */
|
||||
LoadRebootPayload();
|
||||
|
||||
/* Create bpc:ams. */
|
||||
{
|
||||
Handle bpcams_h;
|
||||
|
@ -13,9 +13,11 @@
|
||||
* 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 "../amsmitm_initialization.hpp"
|
||||
#include "setmitm_module.hpp"
|
||||
#include "set_mitm_service.hpp"
|
||||
#include "setsys_mitm_service.hpp"
|
||||
#include "settings_sd_kvs.hpp"
|
||||
|
||||
namespace ams::mitm::settings {
|
||||
|
||||
@ -40,6 +42,9 @@ namespace ams::mitm::settings {
|
||||
/* Wait until initialization is complete. */
|
||||
mitm::WaitInitialized();
|
||||
|
||||
/* Load settings off the SD card. */
|
||||
ams::settings::fwdbg::InitializeSdCardKeyValueStore();
|
||||
|
||||
/* Create mitm servers. */
|
||||
R_ASSERT(g_server_manager.RegisterMitmServer<SetMitmService>(SetMitmServiceName));
|
||||
R_ASSERT(g_server_manager.RegisterMitmServer<SetSysMitmService>(SetSysMitmServiceName));
|
||||
|
@ -14,6 +14,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "setsys_mitm_service.hpp"
|
||||
#include "settings_sd_kvs.hpp"
|
||||
|
||||
namespace ams::mitm::settings {
|
||||
|
||||
@ -98,5 +99,22 @@ namespace ams::mitm::settings {
|
||||
return GetFirmwareVersionImpl(out.GetPointer(), this->client_info);
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetSettingsItemValueSize(sf::Out<u64> out_size, const settings::fwdbg::SettingsName &name, const settings::fwdbg::SettingsItemKey &key) {
|
||||
R_TRY_CATCH(settings::fwdbg::GetSdCardKeyValueStoreSettingsItemValueSize(out_size.GetPointer(), name.value, key.value)) {
|
||||
R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged)
|
||||
R_CONVERT_ALL(sm::mitm::ResultShouldForwardToSession());
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetSettingsItemValue(sf::Out<u64> out_size, const sf::OutBuffer &out, const settings::fwdbg::SettingsName &name, const settings::fwdbg::SettingsItemKey &key) {
|
||||
R_TRY_CATCH(settings::fwdbg::GetSdCardKeyValueStoreSettingsItemValue(out_size.GetPointer(), out.GetPointer(), out.GetSize(), name.value, key.value)) {
|
||||
R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged)
|
||||
R_CONVERT_ALL(sm::mitm::ResultShouldForwardToSession());
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ namespace ams::mitm::settings {
|
||||
enum class CommandId {
|
||||
GetFirmwareVersion = 3,
|
||||
GetFirmwareVersion2 = 4,
|
||||
|
||||
GetSettingsItemValueSize = 37,
|
||||
GetSettingsItemValue = 38,
|
||||
};
|
||||
public:
|
||||
static bool ShouldMitm(const sm::MitmProcessInfo &client_info) {
|
||||
@ -36,10 +39,14 @@ namespace ams::mitm::settings {
|
||||
protected:
|
||||
Result GetFirmwareVersion(sf::Out<ams::settings::FirmwareVersion> out);
|
||||
Result GetFirmwareVersion2(sf::Out<ams::settings::FirmwareVersion> out);
|
||||
Result GetSettingsItemValueSize(sf::Out<u64> out_size, const ams::settings::fwdbg::SettingsName &name, const ams::settings::fwdbg::SettingsItemKey &key);
|
||||
Result GetSettingsItemValue(sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::fwdbg::SettingsName &name, const ams::settings::fwdbg::SettingsItemKey &key);
|
||||
public:
|
||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||
MAKE_SERVICE_COMMAND_META(GetFirmwareVersion),
|
||||
MAKE_SERVICE_COMMAND_META(GetFirmwareVersion2),
|
||||
MAKE_SERVICE_COMMAND_META(GetSettingsItemValueSize),
|
||||
MAKE_SERVICE_COMMAND_META(GetSettingsItemValue),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 <stratosphere.hpp>
|
||||
#include "settings_sd_kvs.hpp"
|
||||
|
||||
namespace ams::settings::fwdbg {
|
||||
|
||||
size_t GetSettingsItemValueSize(const char *name, const char *key) {
|
||||
u64 size = 0;
|
||||
|
||||
if (R_SUCCEEDED(GetSdCardKeyValueStoreSettingsItemValueSize(&size, name, key))) {
|
||||
return size;
|
||||
}
|
||||
|
||||
R_ASSERT(setsysGetSettingsItemValueSize(name, key, &size));
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t GetSettingsItemValue(void *dst, size_t dst_size, const char *name, const char *key) {
|
||||
u64 size = 0;
|
||||
|
||||
if (R_SUCCEEDED(GetSdCardKeyValueStoreSettingsItemValue(&size, dst, dst_size, name, key))) {
|
||||
return size;
|
||||
}
|
||||
|
||||
R_ASSERT(setsysGetSettingsItemValue(name, key, dst, dst_size, &size));
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
346
stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp
Normal file
346
stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 "../amsmitm_debug.hpp"
|
||||
#include "../amsmitm_fs_utils.hpp"
|
||||
#include "settings_sd_kvs.hpp"
|
||||
|
||||
namespace ams::settings::fwdbg {
|
||||
|
||||
namespace {
|
||||
|
||||
struct SdKeyValueStoreEntry {
|
||||
const char *name;
|
||||
const char *key;
|
||||
void *value;
|
||||
size_t value_size;
|
||||
|
||||
constexpr inline bool HasValue() const { return this->value != nullptr; }
|
||||
|
||||
constexpr inline void GetNameAndKey(char *dst) const {
|
||||
size_t offset = 0;
|
||||
for (size_t i = 0; i < std::strlen(this->name); i++) {
|
||||
dst[offset++] = this->name[i];
|
||||
}
|
||||
dst[offset++] = '!';
|
||||
for (size_t i = 0; i < std::strlen(this->key); i++) {
|
||||
dst[offset++] = this->key[i];
|
||||
}
|
||||
dst[offset] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(std::is_pod<SdKeyValueStoreEntry>::value);
|
||||
|
||||
constexpr inline bool operator==(const SdKeyValueStoreEntry &lhs, const SdKeyValueStoreEntry &rhs) {
|
||||
if (lhs.HasValue() != rhs.HasValue()) {
|
||||
return false;
|
||||
}
|
||||
return lhs.HasValue() && std::strcmp(lhs.name, rhs.name) == 0 && std::strcmp(lhs.key, rhs.key) == 0;
|
||||
}
|
||||
|
||||
inline bool operator<(const SdKeyValueStoreEntry &lhs, const SdKeyValueStoreEntry &rhs) {
|
||||
AMS_ASSERT(lhs.HasValue());
|
||||
AMS_ASSERT(rhs.HasValue());
|
||||
|
||||
char lhs_name_key[SettingsNameLengthMax + 1 + SettingsItemKeyLengthMax + 1];
|
||||
char rhs_name_key[SettingsNameLengthMax + 1 + SettingsItemKeyLengthMax + 1];
|
||||
|
||||
lhs.GetNameAndKey(lhs_name_key);
|
||||
rhs.GetNameAndKey(rhs_name_key);
|
||||
|
||||
return std::strcmp(lhs_name_key, rhs_name_key) < 0;
|
||||
}
|
||||
|
||||
constexpr size_t MaxEntries = 0x200;
|
||||
constexpr size_t SettingsItemValueStorageSize = 0x10000;
|
||||
|
||||
SettingsName g_names[MaxEntries];
|
||||
SettingsItemKey g_item_keys[MaxEntries];
|
||||
u8 g_value_storage[SettingsItemValueStorageSize];
|
||||
size_t g_allocated_value_storage_size;
|
||||
|
||||
SdKeyValueStoreEntry g_entries[MaxEntries];
|
||||
size_t g_num_entries;
|
||||
|
||||
constexpr bool IsValidSettingsFormat(const char *str, size_t len) {
|
||||
AMS_ASSERT(str != nullptr);
|
||||
|
||||
if (len > 0 && str[len - 1] == '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
const char c = str[i];
|
||||
|
||||
if ('a' <= c && c <= 'z') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('0' <= c && c <= '9') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '-' || c == '.' || c == '_') {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool IsHexadecimal(const char *str) {
|
||||
while (*str) {
|
||||
if (std::isxdigit(static_cast<unsigned char>(*str))) {
|
||||
str++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr inline char hextoi(char c) {
|
||||
if ('a' <= c && c <= 'f') return c - 'a' + 0xA;
|
||||
if ('A' <= c && c <= 'F') return c - 'A' + 0xA;
|
||||
if ('0' <= c && c <= '9') return c - '0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result ValidateSettingsName(const char *name) {
|
||||
R_UNLESS(name != nullptr, ResultSettingsNameNull());
|
||||
const size_t len = strnlen(name, SettingsNameLengthMax + 1);
|
||||
R_UNLESS(len > 0, ResultSettingsNameEmpty());
|
||||
R_UNLESS(len <= SettingsNameLengthMax, ResultSettingsNameTooLong());
|
||||
R_UNLESS(IsValidSettingsFormat(name, len), ResultSettingsNameInvalidFormat());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ValidateSettingsItemKey(const char *key) {
|
||||
R_UNLESS(key != nullptr, ResultSettingsNameNull());
|
||||
const size_t len = strnlen(key, SettingsItemKeyLengthMax + 1);
|
||||
R_UNLESS(len > 0, ResultSettingsItemKeyEmpty());
|
||||
R_UNLESS(len <= SettingsNameLengthMax, ResultSettingsItemKeyTooLong());
|
||||
R_UNLESS(IsValidSettingsFormat(key, len), ResultSettingsItemKeyInvalidFormat());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result AllocateValue(void **out, size_t size) {
|
||||
R_UNLESS(g_allocated_value_storage_size + size <= sizeof(g_value_storage), ResultSettingsItemValueAllocationFailed());
|
||||
|
||||
*out = g_value_storage + g_allocated_value_storage_size;
|
||||
g_allocated_value_storage_size += size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result FindSettingsName(const char **out, const char *name) {
|
||||
for (auto &stored : g_names) {
|
||||
if (std::strcmp(stored.value, name) == 0) {
|
||||
*out = stored.value;
|
||||
return ResultSuccess();
|
||||
} else if (std::strcmp(stored.value, "") == 0) {
|
||||
*out = stored.value;
|
||||
std::strcpy(stored.value, name);
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ResultSettingsItemKeyAllocationFailed();
|
||||
}
|
||||
|
||||
Result FindSettingsItemKey(const char **out, const char *key) {
|
||||
for (auto &stored : g_item_keys) {
|
||||
if (std::strcmp(stored.value, key) == 0) {
|
||||
*out = stored.value;
|
||||
return ResultSuccess();
|
||||
} else if (std::strcmp(stored.value, "") == 0) {
|
||||
std::strcpy(stored.value, key);
|
||||
*out = stored.value;
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ResultSettingsItemKeyAllocationFailed();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Result ParseSettingsItemIntegralValue(SdKeyValueStoreEntry &out, const char *value_str) {
|
||||
R_TRY(AllocateValue(&out.value, sizeof(T)));
|
||||
out.value_size = sizeof(T);
|
||||
|
||||
T value = static_cast<T>(strtoul(value_str, nullptr, 0));
|
||||
std::memcpy(out.value, &value, sizeof(T));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetEntry(SdKeyValueStoreEntry **out, const char *name, const char *key) {
|
||||
/* Validate name/key. */
|
||||
R_TRY(ValidateSettingsName(name));
|
||||
R_TRY(ValidateSettingsItemKey(key));
|
||||
|
||||
u8 dummy_value = 0;
|
||||
SdKeyValueStoreEntry test_entry { .name = name, .key = key, .value = &dummy_value, .value_size = sizeof(dummy_value) };
|
||||
|
||||
auto *begin = g_entries;
|
||||
auto *end = begin + g_num_entries;
|
||||
auto it = std::lower_bound(begin, end, test_entry);
|
||||
R_UNLESS(it != end, ResultSettingsItemNotFound());
|
||||
R_UNLESS(*it == test_entry, ResultSettingsItemNotFound());
|
||||
|
||||
*out = &*it;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ParseSettingsItemValueImpl(const char *name, const char *key, const char *val_tup) {
|
||||
const char *delimiter = strchr(val_tup, '!');
|
||||
const char *value_str = delimiter + 1;
|
||||
const char *type = val_tup;
|
||||
|
||||
R_UNLESS(delimiter != nullptr, ResultSettingsItemValueInvalidFormat());
|
||||
|
||||
while (std::isspace(static_cast<unsigned char>(*type)) && type != delimiter) {
|
||||
type++;
|
||||
}
|
||||
|
||||
const size_t type_len = delimiter - type;
|
||||
const size_t value_len = strlen(value_str);
|
||||
R_UNLESS(type_len > 0, ResultSettingsItemValueInvalidFormat());
|
||||
R_UNLESS(value_len > 0, ResultSettingsItemValueInvalidFormat());
|
||||
|
||||
/* Create new value. */
|
||||
SdKeyValueStoreEntry new_value = {};
|
||||
|
||||
/* Find name and key. */
|
||||
R_TRY(FindSettingsName(&new_value.name, name));
|
||||
R_TRY(FindSettingsItemKey(&new_value.key, key));
|
||||
|
||||
if (strncasecmp(type, "str", type_len) == 0 || strncasecmp(type, "string", type_len) == 0) {
|
||||
const size_t size = value_len + 1;
|
||||
R_TRY(AllocateValue(&new_value.value, size));
|
||||
std::memcpy(new_value.value, value_str, size);
|
||||
new_value.value_size = size;
|
||||
} else if (strncasecmp(type, "hex", type_len) == 0 || strncasecmp(type, "bytes", type_len) == 0) {
|
||||
R_UNLESS(value_len > 0, ResultSettingsItemValueInvalidFormat());
|
||||
R_UNLESS(value_len % 2 == 0, ResultSettingsItemValueInvalidFormat());
|
||||
R_UNLESS(IsHexadecimal(value_str), ResultSettingsItemValueInvalidFormat());
|
||||
|
||||
const size_t size = value_len / 2;
|
||||
R_TRY(AllocateValue(&new_value.value, size));
|
||||
new_value.value_size = size;
|
||||
|
||||
u8 *data = reinterpret_cast<u8 *>(new_value.value);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
data[i >> 1] = hextoi(value_str[i]) << (4 * (i & 1));
|
||||
}
|
||||
} else if (strncasecmp(type, "u8", type_len) == 0) {
|
||||
R_TRY((ParseSettingsItemIntegralValue<u8>(new_value, value_str)));
|
||||
} else if (strncasecmp(type, "u16", type_len) == 0) {
|
||||
R_TRY((ParseSettingsItemIntegralValue<u16>(new_value, value_str)));
|
||||
} else if (strncasecmp(type, "u32", type_len) == 0) {
|
||||
R_TRY((ParseSettingsItemIntegralValue<u32>(new_value, value_str)));
|
||||
} else if (strncasecmp(type, "u64", type_len) == 0) {
|
||||
R_TRY((ParseSettingsItemIntegralValue<u64>(new_value, value_str)));
|
||||
} else {
|
||||
return ResultSettingsItemValueInvalidFormat();
|
||||
}
|
||||
|
||||
/* Insert the entry. */
|
||||
bool inserted = false;
|
||||
for (auto &entry : g_entries) {
|
||||
if (!entry.HasValue() || entry == new_value) {
|
||||
entry = new_value;
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
R_UNLESS(inserted, ResultSettingsItemValueAllocationFailed());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ParseSettingsItemValue(const char *name, const char *key, const char *value) {
|
||||
R_TRY(ValidateSettingsName(name));
|
||||
R_TRY(ValidateSettingsItemKey(key));
|
||||
return ParseSettingsItemValueImpl(name, key, value);
|
||||
}
|
||||
|
||||
static int SystemSettingsIniHandler(void *user, const char *name, const char *key, const char *value) {
|
||||
Result *parse_res = reinterpret_cast<Result *>(user);
|
||||
|
||||
/* Once we fail to parse a value, don't parse further. */
|
||||
if (R_FAILED(*parse_res)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*parse_res = ParseSettingsItemValue(name, key, value);
|
||||
return R_SUCCEEDED(*parse_res) ? 1 : 0;
|
||||
}
|
||||
|
||||
Result LoadSdCardKeyValueStore() {
|
||||
/* Open file. */
|
||||
FsFile config_file;
|
||||
R_TRY(ams::mitm::fs::OpenAtmosphereSdFile(&config_file, "/system_settings.ini", FsOpenMode_Read));
|
||||
ON_SCOPE_EXIT { fsFileClose(&config_file); };
|
||||
|
||||
Result parse_result = ResultSuccess();
|
||||
util::ini::ParseFile(&config_file, &parse_result, SystemSettingsIniHandler);
|
||||
R_TRY(parse_result);
|
||||
|
||||
for (size_t i = 0; i < util::size(g_entries); i++) {
|
||||
if (!g_entries[i].HasValue()) {
|
||||
g_num_entries = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_num_entries) {
|
||||
std::sort(g_entries, g_entries + g_num_entries);
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeSdCardKeyValueStore() {
|
||||
const Result parse_result = LoadSdCardKeyValueStore();
|
||||
if (R_FAILED(parse_result)) {
|
||||
ams::mitm::ThrowResultForDebug(parse_result);
|
||||
}
|
||||
}
|
||||
|
||||
Result GetSdCardKeyValueStoreSettingsItemValueSize(size_t *out_size, const char *name, const char *key) {
|
||||
SdKeyValueStoreEntry *entry = nullptr;
|
||||
R_TRY(GetEntry(&entry, name, key));
|
||||
|
||||
*out_size = entry->value_size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetSdCardKeyValueStoreSettingsItemValue(size_t *out_size, void *dst, size_t dst_size, const char *name, const char *key) {
|
||||
R_UNLESS(dst != nullptr, ResultSettingsItemValueBufferNull());
|
||||
|
||||
SdKeyValueStoreEntry *entry = nullptr;
|
||||
R_TRY(GetEntry(&entry, name, key));
|
||||
|
||||
const size_t size = std::min(entry->value_size, dst_size);
|
||||
if (size > 0) {
|
||||
std::memcpy(dst, entry->value, size);
|
||||
}
|
||||
*out_size = size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
26
stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.hpp
Normal file
26
stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::settings::fwdbg {
|
||||
|
||||
void InitializeSdCardKeyValueStore();
|
||||
|
||||
Result GetSdCardKeyValueStoreSettingsItemValueSize(size_t *out_size, const char *name, const char *key);
|
||||
Result GetSdCardKeyValueStoreSettingsItemValue(size_t *out_size, void *dst, size_t dst_size, const char *name, const char *key);
|
||||
|
||||
}
|
@ -191,14 +191,13 @@ namespace ams::dmnt::cheat::impl {
|
||||
|
||||
/* Learn whether we should enable cheats by default. */
|
||||
{
|
||||
u64 size_out;
|
||||
u8 en = 0;
|
||||
if (R_SUCCEEDED(setsysGetSettingsItemValue("atmosphere", "dmnt_cheats_enabled_by_default", &en, sizeof(en), &size_out))) {
|
||||
if (settings::fwdbg::GetSettingsItemValue(&en, sizeof(en), "atmosphere", "dmnt_cheats_enabled_by_default") == sizeof(en)) {
|
||||
this->enable_cheats_by_default = (en != 0);
|
||||
}
|
||||
|
||||
en = 0;
|
||||
if (R_SUCCEEDED(setsysGetSettingsItemValue("atmosphere", "dmnt_always_save_cheat_toggles", &en, sizeof(en), &size_out))) {
|
||||
if (settings::fwdbg::GetSettingsItemValue( &en, sizeof(en), "atmosphere", "dmnt_always_save_cheat_toggles") == sizeof(en)) {
|
||||
this->always_save_cheat_toggles = (en != 0);
|
||||
}
|
||||
}
|
||||
|
@ -59,13 +59,12 @@ namespace ams::fatal::srv {
|
||||
this->UpdateLanguageCode();
|
||||
|
||||
/* Read information from settings. */
|
||||
u64 set_size_out;
|
||||
setsysGetSettingsItemValue("fatal", "transition_to_fatal", &this->transition_to_fatal, sizeof(this->transition_to_fatal), &set_size_out);
|
||||
setsysGetSettingsItemValue("fatal", "show_extra_info", &this->show_extra_info, sizeof(this->show_extra_info), &set_size_out);
|
||||
setsysGetSettingsItemValue("fatal", "quest_reboot_interval_second", &this->quest_reboot_interval_second, sizeof(this->quest_reboot_interval_second), &set_size_out);
|
||||
settings::fwdbg::GetSettingsItemValue(&this->transition_to_fatal, sizeof(this->transition_to_fatal), "fatal", "transition_to_fatal");
|
||||
settings::fwdbg::GetSettingsItemValue(&this->show_extra_info, sizeof(this->show_extra_info), "fatal", "show_extra_info");
|
||||
settings::fwdbg::GetSettingsItemValue(&this->quest_reboot_interval_second, sizeof(this->quest_reboot_interval_second), "fatal", "quest_reboot_interval_second");
|
||||
|
||||
/* Atmosphere extension for automatic reboot. */
|
||||
if (R_SUCCEEDED(setsysGetSettingsItemValue("atmosphere", "fatal_auto_reboot_interval", &this->fatal_auto_reboot_interval, sizeof(this->fatal_auto_reboot_interval), &set_size_out))) {
|
||||
if (settings::fwdbg::GetSettingsItemValue(&this->fatal_auto_reboot_interval, sizeof(this->fatal_auto_reboot_interval), "atmosphere", "fatal_auto_reboot_interval") == sizeof(this->fatal_auto_reboot_interval)) {
|
||||
this->fatal_auto_reboot_enabled = this->fatal_auto_reboot_interval != 0;
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ include $(DEVKITPRO)/libnx/switch_rules
|
||||
# INCLUDES is a list of directories containing header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
SOURCES := source source/ams source/hos source/result source/os source/os/impl source/dd source/sf source/sf/cmif source/sf/hipc source/dmnt source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb source/boot2
|
||||
SOURCES := source source/ams source/hos source/result source/os source/os/impl source/dd source/sf source/sf/cmif source/sf/hipc source/dmnt source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb source/settings source/boot2
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
|
||||
|
@ -271,6 +271,9 @@ namespace ams::result::impl {
|
||||
#define R_CONVERT_ALL(convert_type) \
|
||||
R_CATCH_ALL() { return static_cast<::ams::Result>(convert_type); }
|
||||
|
||||
#define R_CATCH_RETHROW(catch_type) \
|
||||
R_CONVERT(catch_type, R_CURRENT_RESULT)
|
||||
|
||||
#define R_END_TRY_CATCH \
|
||||
else if (R_FAILED(R_CURRENT_RESULT)) { \
|
||||
return R_CURRENT_RESULT; \
|
||||
|
@ -21,11 +21,11 @@ namespace ams::settings {
|
||||
|
||||
R_DEFINE_NAMESPACE_RESULT_MODULE(105);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(ItemNotFound, 11);
|
||||
R_DEFINE_ERROR_RESULT(SettingsItemNotFound, 11);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(InternalError, 100, 149);
|
||||
R_DEFINE_ERROR_RESULT(ItemKeyAllocationFailed, 101);
|
||||
R_DEFINE_ERROR_RESULT(ItemValueAllocationFailed, 102);
|
||||
R_DEFINE_ERROR_RESULT(SettingsItemKeyAllocationFailed, 101);
|
||||
R_DEFINE_ERROR_RESULT(SettingsItemValueAllocationFailed, 102);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(InvalidArgument, 200, 399);
|
||||
R_DEFINE_ERROR_RESULT(SettingsNameNull, 201);
|
||||
|
@ -17,3 +17,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "settings/settings_types.hpp"
|
||||
#include "settings/settings_fwdbg_types.hpp"
|
||||
#include "settings/settings_fwdbg_api.hpp"
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <atmosphere/common.hpp>
|
||||
#include "settings_fwdbg_types.hpp"
|
||||
|
||||
namespace ams::settings::fwdbg {
|
||||
|
||||
bool IsDebugModeEnabled();
|
||||
|
||||
size_t GetSettingsItemValueSize(const char *name, const char *key);
|
||||
size_t GetSettingsItemValue(void *dst, size_t dst_size, const char *name, const char *key);
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <atmosphere/common.hpp>
|
||||
#include "../sf/sf_buffer_tags.hpp"
|
||||
|
||||
namespace ams::settings::fwdbg {
|
||||
|
||||
constexpr size_t SettingsNameLengthMax = 0x40;
|
||||
constexpr size_t SettingsItemKeyLengthMax = 0x40;
|
||||
|
||||
struct SettingsName : sf::LargeData {
|
||||
char value[util::AlignUp(SettingsNameLengthMax + 1, alignof(u64))];
|
||||
};
|
||||
|
||||
static_assert(std::is_pod<SettingsName>::value && sizeof(SettingsName) > SettingsNameLengthMax);
|
||||
|
||||
struct SettingsItemKey : sf::LargeData {
|
||||
char value[util::AlignUp(SettingsItemKeyLengthMax + 1, alignof(u64))];
|
||||
};
|
||||
|
||||
static_assert(std::is_pod<SettingsItemKey>::value && sizeof(SettingsItemKey) > SettingsItemKeyLengthMax);
|
||||
|
||||
}
|
@ -176,8 +176,7 @@ namespace ams::boot2 {
|
||||
/* Contact set:sys, retrieve boot!force_maintenance. */
|
||||
{
|
||||
u8 force_maintenance = 1;
|
||||
u64 size_out;
|
||||
setsysGetSettingsItemValue("boot", "force_maintenance", &force_maintenance, sizeof(force_maintenance), &size_out);
|
||||
settings::fwdbg::GetSettingsItemValue(&force_maintenance, sizeof(force_maintenance), "boot", "force_maintenance");
|
||||
if (force_maintenance != 0) {
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::settings::fwdbg {
|
||||
|
||||
/* TODO: Implement when libnx wrapper is added. */
|
||||
bool IsDebugModeEnabled();
|
||||
|
||||
size_t WEAK GetSettingsItemValueSize(const char *name, const char *key) {
|
||||
u64 size = 0;
|
||||
R_ASSERT(setsysGetSettingsItemValueSize(name, key, &size));
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t WEAK GetSettingsItemValue(void *dst, size_t dst_size, const char *name, const char *key) {
|
||||
u64 size = 0;
|
||||
R_ASSERT(setsysGetSettingsItemValue(name, key, dst, dst_size, &size));
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
@ -45,7 +45,7 @@ namespace ams::sf::cmif {
|
||||
|
||||
/* Forward forwardable results, otherwise ensure we can send result to user. */
|
||||
R_TRY_CATCH(command_result) {
|
||||
R_CATCH(sf::impl::ResultRequestContextChanged) { return R_CURRENT_RESULT; }
|
||||
R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged)
|
||||
R_CATCH_ALL() { AMS_ASSERT(out_header != nullptr); }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
@ -92,7 +92,7 @@ namespace ams::sf::cmif {
|
||||
R_CATCH(sm::mitm::ResultShouldForwardToSession) {
|
||||
return ctx.session->ForwardRequest(ctx);
|
||||
}
|
||||
R_CATCH(sf::impl::ResultRequestContextChanged) { return R_CURRENT_RESULT; }
|
||||
R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged)
|
||||
R_CATCH_ALL() { AMS_ASSERT(out_header != nullptr); }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
|
@ -102,7 +102,7 @@ int ini_parse_string(const char* string, ini_handler handler, void* user);
|
||||
/* Maximum line length for any line in INI file (stack or heap). Note that
|
||||
this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */
|
||||
#ifndef INI_MAX_LINE
|
||||
#define INI_MAX_LINE 200
|
||||
#define INI_MAX_LINE 0x480
|
||||
#endif
|
||||
|
||||
/* Nonzero to allow heap line buffer to grow via realloc(), zero for a
|
||||
|
@ -315,15 +315,14 @@ namespace ams::ro::impl {
|
||||
|
||||
bool ShouldEaseNroRestriction() {
|
||||
/* Retrieve whether we should ease restrictions from set:sys. */
|
||||
bool should_ease = false;
|
||||
u64 size_out;
|
||||
if (R_FAILED(setsysGetSettingsItemValue("ro", "ease_nro_restriction", &should_ease, sizeof(should_ease), &size_out))) {
|
||||
u8 should_ease = 0;
|
||||
if (settings::fwdbg::GetSettingsItemValue(&should_ease, sizeof(should_ease), "ro", "ease_nro_restriction") != sizeof(should_ease)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Nintendo only allows easing restriction on dev, we will allow on production, as well. */
|
||||
/* should_ease &= IsDevelopmentFunctionEnabled(); */
|
||||
return should_ease;
|
||||
return should_ease != 0;
|
||||
}
|
||||
|
||||
/* Context utilities. */
|
||||
|
Loading…
Reference in New Issue
Block a user