mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-23 04:41:12 +00:00
pgl: Implement ProcessControlTask
This commit is contained in:
parent
cfe0597385
commit
469e3290f6
10 changed files with 311 additions and 16 deletions
|
@ -25,6 +25,8 @@ namespace ams::pm::shell {
|
||||||
/* Shell API. */
|
/* Shell API. */
|
||||||
Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 launch_flags);
|
Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 launch_flags);
|
||||||
Result TerminateProcess(os::ProcessId process_id);
|
Result TerminateProcess(os::ProcessId process_id);
|
||||||
|
Result GetProcessEventEvent(os::SystemEvent *out);
|
||||||
|
Result GetProcessEventInfo(ProcessEventInfo *out);
|
||||||
Result GetApplicationProcessIdForShell(os::ProcessId *out);
|
Result GetApplicationProcessIdForShell(os::ProcessId *out);
|
||||||
Result BoostSystemMemoryResourceLimit(u64 size);
|
Result BoostSystemMemoryResourceLimit(u64 size);
|
||||||
Result EnableApplicationExtraThread();
|
Result EnableApplicationExtraThread();
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace ams::pm {
|
||||||
|
|
||||||
constexpr inline u32 LaunchFlagsMask = (1 << 6) - 1;
|
constexpr inline u32 LaunchFlagsMask = (1 << 6) - 1;
|
||||||
|
|
||||||
enum class ProcessEvent {
|
enum class ProcessEvent : u32 {
|
||||||
None = 0,
|
None = 0,
|
||||||
Exited = 1,
|
Exited = 1,
|
||||||
Started = 2,
|
Started = 2,
|
||||||
|
@ -63,7 +63,7 @@ namespace ams::pm {
|
||||||
DebugBreak = 5,
|
DebugBreak = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ProcessEventDeprecated {
|
enum class ProcessEventDeprecated : u32 {
|
||||||
None = 0,
|
None = 0,
|
||||||
Exception = 1,
|
Exception = 1,
|
||||||
Exited = 2,
|
Exited = 2,
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "settings/settings_types.hpp"
|
#include "settings/settings_types.hpp"
|
||||||
#include "settings/settings_fwdbg_types.hpp"
|
#include "settings/settings_fwdbg_types.hpp"
|
||||||
#include "settings/settings_fwdbg_api.hpp"
|
#include "settings/settings_fwdbg_api.hpp"
|
||||||
|
#include "settings/system/settings_error_report.hpp"
|
||||||
#include "settings/system/settings_firmware_version.hpp"
|
#include "settings/system/settings_firmware_version.hpp"
|
||||||
#include "settings/system/settings_product_model.hpp"
|
#include "settings/system/settings_product_model.hpp"
|
||||||
#include "settings/system/settings_region.hpp"
|
#include "settings/system/settings_region.hpp"
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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 <vapours.hpp>
|
||||||
|
#include <stratosphere/settings/settings_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::system {
|
||||||
|
|
||||||
|
enum ErrorReportSharePermission {
|
||||||
|
ErrorReportSharePermission_NotConfirmed = 0,
|
||||||
|
ErrorReportSharePermission_Granted = 1,
|
||||||
|
ErrorReportSharePermission_Denied = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
ErrorReportSharePermission GetErrorReportSharePermission();
|
||||||
|
|
||||||
|
}
|
|
@ -28,19 +28,19 @@ namespace ams::lr {
|
||||||
public:
|
public:
|
||||||
/* Actual commands. */
|
/* Actual commands. */
|
||||||
virtual Result ResolveProgramPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
virtual Result ResolveProgramPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
||||||
return lrLrResolveProgramPath(std::addressof(this->srv), static_cast<u64>(id), out->str);
|
return lrLrResolveProgramPath(std::addressof(this->srv), id.value, out->str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result RedirectProgramPath(const Path &path, ncm::ProgramId id) override {
|
virtual Result RedirectProgramPath(const Path &path, ncm::ProgramId id) override {
|
||||||
return lrLrRedirectProgramPath(std::addressof(this->srv), static_cast<u64>(id), path.str);
|
return lrLrRedirectProgramPath(std::addressof(this->srv), id.value, path.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result ResolveApplicationControlPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
virtual Result ResolveApplicationControlPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
||||||
return lrLrResolveApplicationControlPath(std::addressof(this->srv), static_cast<u64>(id), out->str);
|
return lrLrResolveApplicationControlPath(std::addressof(this->srv), id.value, out->str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result ResolveApplicationHtmlDocumentPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
virtual Result ResolveApplicationHtmlDocumentPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
||||||
return lrLrResolveApplicationHtmlDocumentPath(std::addressof(this->srv), static_cast<u64>(id), out->str);
|
return lrLrResolveApplicationHtmlDocumentPath(std::addressof(this->srv), id.value, out->str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result ResolveDataPath(sf::Out<Path> out, ncm::DataId id) override {
|
virtual Result ResolveDataPath(sf::Out<Path> out, ncm::DataId id) override {
|
||||||
|
@ -48,31 +48,31 @@ namespace ams::lr {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result RedirectApplicationControlPathDeprecated(const Path &path, ncm::ProgramId id) override {
|
virtual Result RedirectApplicationControlPathDeprecated(const Path &path, ncm::ProgramId id) override {
|
||||||
return lrLrRedirectApplicationControlPath(std::addressof(this->srv), static_cast<u64>(id), 0, path.str);
|
return lrLrRedirectApplicationControlPath(std::addressof(this->srv), id.value, 0, path.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result RedirectApplicationControlPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
|
virtual Result RedirectApplicationControlPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
|
||||||
return lrLrRedirectApplicationControlPath(std::addressof(this->srv), static_cast<u64>(id), static_cast<u64>(owner_id), path.str);
|
return lrLrRedirectApplicationControlPath(std::addressof(this->srv), id.value, owner_id.value, path.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result RedirectApplicationHtmlDocumentPathDeprecated(const Path &path, ncm::ProgramId id) override {
|
virtual Result RedirectApplicationHtmlDocumentPathDeprecated(const Path &path, ncm::ProgramId id) override {
|
||||||
return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), static_cast<u64>(id), 0, path.str);
|
return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), id.value, 0, path.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result RedirectApplicationHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
|
virtual Result RedirectApplicationHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
|
||||||
return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), static_cast<u64>(id), static_cast<u64>(owner_id), path.str);
|
return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), id.value, owner_id.value, path.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result ResolveApplicationLegalInformationPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
virtual Result ResolveApplicationLegalInformationPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
||||||
return lrLrResolveApplicationLegalInformationPath(std::addressof(this->srv), static_cast<u64>(id), out->str);
|
return lrLrResolveApplicationLegalInformationPath(std::addressof(this->srv), id.value, out->str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result RedirectApplicationLegalInformationPathDeprecated(const Path &path, ncm::ProgramId id) override {
|
virtual Result RedirectApplicationLegalInformationPathDeprecated(const Path &path, ncm::ProgramId id) override {
|
||||||
return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), static_cast<u64>(id), 0, path.str);
|
return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), id.value, 0, path.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result RedirectApplicationLegalInformationPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
|
virtual Result RedirectApplicationLegalInformationPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
|
||||||
return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), static_cast<u64>(id), static_cast<u64>(owner_id), path.str);
|
return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), id.value, owner_id.value, path.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result Refresh() override {
|
virtual Result Refresh() override {
|
||||||
|
@ -100,8 +100,7 @@ namespace ams::lr {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result EraseProgramRedirection(ncm::ProgramId id) override {
|
virtual Result EraseProgramRedirection(ncm::ProgramId id) override {
|
||||||
/* TODO: libnx bindings */
|
return lrLrEraseProgramRedirection(std::addressof(this->srv), id.value);
|
||||||
AMS_ABORT();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result EraseApplicationControlRedirection(ncm::ProgramId id) override {
|
virtual Result EraseApplicationControlRedirection(ncm::ProgramId id) override {
|
||||||
|
|
|
@ -140,8 +140,182 @@ namespace ams::pgl::srv {
|
||||||
return pm::shell::LaunchProgram(std::addressof(dummy_process_id), ncm::ProgramLocation::Make(ncm::SystemDebugAppletId::SnapShotDumper, ncm::StorageId::BuiltInSystem), pm::LaunchFlags_None);
|
return pm::shell::LaunchProgram(std::addressof(dummy_process_id), ncm::ProgramLocation::Make(ncm::SystemDebugAppletId::SnapShotDumper, ncm::StorageId::BuiltInSystem), pm::LaunchFlags_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShouldSnapShotAutoDump() {
|
||||||
|
bool dump;
|
||||||
|
const size_t sz = settings::fwdbg::GetSettingsItemValue(std::addressof(dump), sizeof(dump), "snap_shot_dump", "auto_dump");
|
||||||
|
return sz == sizeof(dump) && dump;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldSnapShotFullDump() {
|
||||||
|
bool dump;
|
||||||
|
const size_t sz = settings::fwdbg::GetSettingsItemValue(std::addressof(dump), sizeof(dump), "snap_shot_dump", "full_dump");
|
||||||
|
return sz == sizeof(dump) && dump;
|
||||||
|
}
|
||||||
|
|
||||||
|
SnapShotDumpType GetSnapShotDumpType() {
|
||||||
|
if (ShouldSnapShotAutoDump()) {
|
||||||
|
if (ShouldSnapShotFullDump()) {
|
||||||
|
return SnapShotDumpType::Full;
|
||||||
|
} else {
|
||||||
|
return SnapShotDumpType::Auto;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return SnapShotDumpType::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TriggerSnapShotDumper(os::ProcessId process_id) {
|
||||||
|
TriggerSnapShotDumper(process_id, GetSnapShotDumpType(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 GetCrashReportDetailedArgument(u32 data_flags) {
|
||||||
|
if (((data_flags & ProcessDataFlag_DetailedCrashReportAllowed) != 0) && ((data_flags & ProcessDataFlag_DetailedCrashReportEnabled) != 0)) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 GetCrashReportScreenShotArgument(u32 data_flags) {
|
||||||
|
if (settings::system::GetErrorReportSharePermission() == settings::system::ErrorReportSharePermission_Granted) {
|
||||||
|
return ((data_flags & ProcessDataFlag_EnableCrashReportScreenShot) != 0) ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TriggerCrashReport(os::ProcessId process_id) {
|
||||||
|
static os::ProcessId s_crashed_process_id = os::InvalidProcessId;
|
||||||
|
static os::ProcessId s_creport_process_id = os::InvalidProcessId;
|
||||||
|
|
||||||
|
/* If the program that crashed is creport, we should just terminate both processes and return. */
|
||||||
|
if (process_id == s_creport_process_id) {
|
||||||
|
TerminateProcess(s_crashed_process_id);
|
||||||
|
TerminateProcess(s_creport_process_id);
|
||||||
|
s_crashed_process_id = os::InvalidProcessId;
|
||||||
|
s_creport_process_id = os::InvalidProcessId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the data flags for the process. */
|
||||||
|
u32 data_flags;
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(g_process_data_mutex);
|
||||||
|
if (auto *data = FindProcessData(process_id); data != nullptr) {
|
||||||
|
data_flags = data->flags;
|
||||||
|
} else {
|
||||||
|
data_flags = ProcessDataFlag_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate arguments. */
|
||||||
|
char arguments[0x40];
|
||||||
|
const size_t len = std::snprintf(arguments, sizeof(arguments), "%ld %d %d", static_cast<s64>(static_cast<u64>(process_id)), GetCrashReportDetailedArgument(data_flags), GetCrashReportScreenShotArgument(data_flags));
|
||||||
|
if (R_FAILED(ldr::SetProgramArgument(ncm::SystemProgramId::Creport, arguments, len + 1))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Launch creport. */
|
||||||
|
os::ProcessId creport_process_id;
|
||||||
|
if (R_FAILED(pm::shell::LaunchProgram(std::addressof(creport_process_id), ncm::ProgramLocation::Make(ncm::SystemProgramId::Creport, ncm::StorageId::BuiltInSystem), pm::LaunchFlags_None))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the globals. */
|
||||||
|
s_crashed_process_id = process_id;
|
||||||
|
s_creport_process_id = creport_process_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleException(os::ProcessId process_id) {
|
||||||
|
if (g_enable_jit_debug) {
|
||||||
|
/* If jit debug is enabled, we want to try to launch snap shot dumper. */
|
||||||
|
ProcessData *data = nullptr;
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(g_process_data_mutex);
|
||||||
|
data = FindProcessData(process_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're tracking the process, we can launch dumper. Otherwise we should just terminate. */
|
||||||
|
if (data != nullptr) {
|
||||||
|
TriggerSnapShotDumper(process_id);
|
||||||
|
} else {
|
||||||
|
TerminateProcess(process_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Otherwise, we want to launch creport. */
|
||||||
|
TriggerCrashReport(process_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleExit(os::ProcessId process_id) {
|
||||||
|
std::scoped_lock lk(g_process_data_mutex);
|
||||||
|
if (auto *data = FindProcessData(process_id); data != nullptr) {
|
||||||
|
data->process_id = os::InvalidProcessId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnProcessEvent(const pm::ProcessEventInfo &event_info) {
|
||||||
|
/* Determine if we're tracking the process. */
|
||||||
|
ProcessData *data = nullptr;
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(g_process_data_mutex);
|
||||||
|
data = FindProcessData(event_info.process_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we are, we're going to want to notify our listeners. */
|
||||||
|
if (data != nullptr) {
|
||||||
|
/* If we closed the process, note that. */
|
||||||
|
if (static_cast<pm::ProcessEvent>(event_info.event) == pm::ProcessEvent::Exited) {
|
||||||
|
HandleExit(event_info.process_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify all observers. */
|
||||||
|
std::scoped_lock lk(g_observer_list_mutex);
|
||||||
|
for (auto &observer : g_observer_list) {
|
||||||
|
observer.Notify(event_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the process crashed, handle that. */
|
||||||
|
if (static_cast<pm::ProcessEvent>(event_info.event) == pm::ProcessEvent::Exception) {
|
||||||
|
HandleException(event_info.process_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ProcessControlTask(void *) {
|
void ProcessControlTask(void *) {
|
||||||
/* TODO */
|
/* Get the process event event from pm. */
|
||||||
|
os::SystemEvent process_event;
|
||||||
|
R_ABORT_UNLESS(pm::shell::GetProcessEventEvent(std::addressof(process_event)));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
/* Wait for an event to come in, and clear our signal. */
|
||||||
|
process_event.Wait();
|
||||||
|
process_event.Signal();
|
||||||
|
|
||||||
|
bool continue_getting_event = true;
|
||||||
|
while (continue_getting_event) {
|
||||||
|
/* Try to get an event info. */
|
||||||
|
pm::ProcessEventInfo event_info;
|
||||||
|
if (R_FAILED(pm::shell::GetProcessEventInfo(std::addressof(event_info)))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the event. */
|
||||||
|
switch (static_cast<pm::ProcessEvent>(event_info.event)) {
|
||||||
|
case pm::ProcessEvent::None:
|
||||||
|
continue_getting_event = false;
|
||||||
|
break;
|
||||||
|
case pm::ProcessEvent::Exited:
|
||||||
|
case pm::ProcessEvent::Started:
|
||||||
|
case pm::ProcessEvent::Exception:
|
||||||
|
case pm::ProcessEvent::DebugRunning:
|
||||||
|
case pm::ProcessEvent::DebugBreak:
|
||||||
|
OnProcessEvent(event_info);
|
||||||
|
break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,18 @@ namespace ams::pm::shell {
|
||||||
return ::pmshellTerminateProcess(static_cast<u64>(process_id));
|
return ::pmshellTerminateProcess(static_cast<u64>(process_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GetProcessEventEvent(os::SystemEvent *out) {
|
||||||
|
::Event evt;
|
||||||
|
R_TRY(::pmshellGetProcessEventHandle(std::addressof(evt)));
|
||||||
|
out->Attach(evt.revent, true, svc::InvalidHandle, false, os::EventClearMode_ManualClear);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetProcessEventInfo(ProcessEventInfo *out) {
|
||||||
|
static_assert(sizeof(*out) == sizeof(::PmProcessEventInfo));
|
||||||
|
return ::pmshellGetProcessEventInfo(reinterpret_cast<::PmProcessEventInfo *>(out));
|
||||||
|
}
|
||||||
|
|
||||||
Result GetApplicationProcessIdForShell(os::ProcessId *out) {
|
Result GetApplicationProcessIdForShell(os::ProcessId *out) {
|
||||||
static_assert(sizeof(*out) == sizeof(u64));
|
static_assert(sizeof(*out) == sizeof(u64));
|
||||||
return ::pmshellGetApplicationProcessIdForShell(reinterpret_cast<u64 *>(out));
|
return ::pmshellGetApplicationProcessIdForShell(reinterpret_cast<u64 *>(out));
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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_error_report_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
Result GetErrorReportSharePermission(s32 *out) {
|
||||||
|
static_assert(sizeof(*out) == sizeof(::SetSysErrorReportSharePermission));
|
||||||
|
return ::setsysGetErrorReportSharePermission(reinterpret_cast<::SetSysErrorReportSharePermission *>(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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::impl {
|
||||||
|
|
||||||
|
Result GetErrorReportSharePermission(s32 *out);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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 "impl/settings_error_report_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::system {
|
||||||
|
|
||||||
|
ErrorReportSharePermission GetErrorReportSharePermission() {
|
||||||
|
s32 perm = 0;
|
||||||
|
R_ABORT_UNLESS(settings::impl::GetErrorReportSharePermission(std::addressof(perm)));
|
||||||
|
return static_cast<ErrorReportSharePermission>(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue