diff --git a/src/Ryujinx.Common/Utilities/OsUtils.cs b/src/Ryujinx.Common/Utilities/OsUtils.cs index 29c6e187c..79fe8b722 100644 --- a/src/Ryujinx.Common/Utilities/OsUtils.cs +++ b/src/Ryujinx.Common/Utilities/OsUtils.cs @@ -22,10 +22,11 @@ namespace Ryujinx.Common.Utilities } // "dumpable" attribute of the calling process + private const int PR_GET_DUMPABLE = 3; private const int PR_SET_DUMPABLE = 4; - [DllImport("libc", SetLastError = true)] - private static extern int prctl(int option, int arg2); + [LibraryImport("libc", SetLastError = true)] + private static partial int prctl(int option, int arg2); public static void SetCoreDumpable(bool dumpable) { @@ -36,5 +37,13 @@ namespace Ryujinx.Common.Utilities Debug.Assert(result == 0); } } + + // Use the below line to display dumpable status in the console: + // Console.WriteLine($"{OsUtils.IsCoreDumpable()}"); + public static bool IsCoreDumpable() + { + int result = prctl(PR_GET_DUMPABLE, 0); + return result == 1; + } } } diff --git a/src/Ryujinx/Common/ApplicationHelper.cs b/src/Ryujinx/Common/ApplicationHelper.cs index 3efd9ed62..f958c0159 100644 --- a/src/Ryujinx/Common/ApplicationHelper.cs +++ b/src/Ryujinx/Common/ApplicationHelper.cs @@ -18,6 +18,7 @@ using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.Utilities; using Ryujinx.Common.Helper; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.Loaders.Processes.Extensions; @@ -410,6 +411,8 @@ namespace Ryujinx.Ava.Common public static async Task ExtractAoc(IStorageProvider storageProvider, string updateFilePath, string updateName) { + OsUtils.SetCoreDumpable(true); + Gommon.Optional result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle] @@ -419,10 +422,17 @@ namespace Ryujinx.Ava.Common return; ExtractAoc(result.Value.Path.LocalPath, updateFilePath, updateName); + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public static async Task ExtractSection(IStorageProvider storageProvider, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0) { + OsUtils.SetCoreDumpable(true); + Gommon.Optional result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle] @@ -432,6 +442,11 @@ namespace Ryujinx.Ava.Common return; ExtractSection(result.Value.Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex); + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token) diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs index 8d03f81da..d1b85c6b0 100644 --- a/src/Ryujinx/Program.cs +++ b/src/Ryujinx/Program.cs @@ -42,6 +42,7 @@ namespace Ryujinx.Ava public static bool PreviewerDetached { get; private set; } public static bool UseHardwareAcceleration { get; private set; } public static string BackendThreadingArg { get; private set; } + public static bool CoreDumpArg { get; private set; } private const uint MbIconwarning = 0x30; @@ -81,6 +82,8 @@ namespace Ryujinx.Ava bool noGuiArg = ConsumeCommandLineArgument(ref args, "--no-gui") || ConsumeCommandLineArgument(ref args, "nogui"); bool coreDumpArg = ConsumeCommandLineArgument(ref args, "--core-dumps"); + CoreDumpArg = coreDumpArg; + // TODO: Ryujinx causes core dumps on Linux when it exits "uncleanly", eg. through an unhandled exception. // This is undesirable and causes very odd behavior during development (the process stops responding, // the .NET debugger freezes or suddenly detaches, /tmp/ gets filled etc.), unless explicitly requested by the user. diff --git a/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs index 39e53184f..0bec24945 100644 --- a/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs @@ -8,6 +8,7 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Systems.AppLibrary; using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Common.Utilities; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; @@ -128,6 +129,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async void Add() { + OsUtils.SetCoreDumpable(true); + IReadOnlyList result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle], @@ -158,6 +161,11 @@ namespace Ryujinx.Ava.UI.ViewModels { await ShowNewDlcAddedDialog(totalDlcAdded); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } private bool AddDownloadableContent(string path, out int numDlcAdded) diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index 96159a1ea..94a796125 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -1266,6 +1266,8 @@ namespace Ryujinx.Ava.UI.ViewModels private async Task LoadContentFromFolder(LocaleKeys localeMessageAddedKey, LocaleKeys localeMessageRemovedKey, LoadContentFromFolderDelegate onDirsSelected, LocaleKeys dirSelectDialogTitle) { + OsUtils.SetCoreDumpable(true); + Optional> result = await StorageProvider.OpenMultiFolderPickerAsync( new FolderPickerOpenOptions { Title = LocaleManager.Instance[dirSelectDialogTitle] }); @@ -1293,6 +1295,11 @@ namespace Ryujinx.Ava.UI.ViewModels (int)Symbol.Checkmark); }); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } #endregion @@ -1355,6 +1362,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async Task InstallFirmwareFromFile() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions { FileTypeFilter = new List @@ -1384,20 +1393,34 @@ namespace Ryujinx.Ava.UI.ViewModels { await HandleFirmwareInstallation(result.Value.Path.LocalPath); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public async Task InstallFirmwareFromFolder() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFolderPickerAsync(); if (result.HasValue) { await HandleFirmwareInstallation(result.Value.Path.LocalPath); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public async Task InstallKeysFromFile() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions { FileTypeFilter = new List @@ -1415,16 +1438,28 @@ namespace Ryujinx.Ava.UI.ViewModels { await HandleKeysInstallation(result.Value.Path.LocalPath); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public async Task InstallKeysFromFolder() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFolderPickerAsync(); if (result.HasValue) { await HandleKeysInstallation(result.Value.Path.LocalPath); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public void OpenRyujinxFolder() @@ -1528,6 +1563,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async Task OpenFile() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.LoadApplicationFromFileDialogTitle], @@ -1599,6 +1636,11 @@ namespace Ryujinx.Ava.UI.ViewModels LocaleManager.Instance[LocaleKeys.MenuBarFileOpenFromFileError]); } } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public async Task LoadDlcFromFolder() @@ -1621,6 +1663,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async Task OpenFolder() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFolderPickerAsync( new FolderPickerOpenOptions { @@ -1636,6 +1680,11 @@ namespace Ryujinx.Ava.UI.ViewModels await LoadApplication(applicationData); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public static bool InitializeUserConfig(ApplicationData application) @@ -1843,6 +1892,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async Task OpenBinFile() { + OsUtils.SetCoreDumpable(true); + if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning) { Optional result = await StorageProvider.OpenSingleFilePickerAsync( @@ -1862,6 +1913,11 @@ namespace Ryujinx.Ava.UI.ViewModels { AppHost.Device.System.ScanAmiiboFromBin(result.Value.Path.LocalPath); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } } diff --git a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs index 45e67add0..569d293e6 100644 --- a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs @@ -288,6 +288,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async void Add() { + OsUtils.SetCoreDumpable(true); + IReadOnlyList result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.SelectModDialogTitle], @@ -298,6 +300,11 @@ namespace Ryujinx.Ava.UI.ViewModels { AddMod(new DirectoryInfo(folder.Path.LocalPath)); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public void DeleteAll() diff --git a/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs index 3d34643ab..c10da7bf9 100644 --- a/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs @@ -7,6 +7,7 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Systems.AppLibrary; using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Common.Utilities; using System.Collections.Generic; using System.IO; using System.Linq; @@ -148,6 +149,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async Task Add() { + OsUtils.SetCoreDumpable(true); + IReadOnlyList result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { AllowMultiple = true, @@ -177,6 +180,11 @@ namespace Ryujinx.Ava.UI.ViewModels { await ShowNewUpdatesAddedDialog(totalUpdatesAdded); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public void Save() diff --git a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs index f0742a579..62e4e72a6 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs +++ b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs @@ -7,6 +7,7 @@ using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.Utilities; +using Ryujinx.Common.Utilities; using System.Collections.Generic; using System.IO; using System.Linq; @@ -27,6 +28,8 @@ namespace Ryujinx.Ava.UI.Views.Settings private async Task AddDirButton(TextBox addDirBox, AvaloniaList directories) { + OsUtils.SetCoreDumpable(true); + string path = addDirBox.Text; if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !directories.Contains(path)) @@ -48,6 +51,11 @@ namespace Ryujinx.Ava.UI.Views.Settings ViewModel.GameListNeedsRefresh = true; } } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } private void RemoveGameDirButton_OnClick(object sender, RoutedEventArgs e) diff --git a/src/Ryujinx/UI/Views/User/UserProfileImageSelectorView.axaml.cs b/src/Ryujinx/UI/Views/User/UserProfileImageSelectorView.axaml.cs index 3a5b7c6b7..9b9cc3303 100644 --- a/src/Ryujinx/UI/Views/User/UserProfileImageSelectorView.axaml.cs +++ b/src/Ryujinx/UI/Views/User/UserProfileImageSelectorView.axaml.cs @@ -8,6 +8,7 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; using SkiaSharp; using System.Collections.Generic; @@ -62,6 +63,8 @@ namespace Ryujinx.Ava.UI.Views.User private async void Import_OnClick(object sender, RoutedEventArgs e) { + OsUtils.SetCoreDumpable(true); + IReadOnlyList result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { AllowMultiple = false, @@ -81,6 +84,11 @@ namespace Ryujinx.Ava.UI.Views.User _profile.Image = ProcessProfileImage(File.ReadAllBytes(result[0].Path.LocalPath)); _parent.GoBack(); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } private void GoBack(object sender, RoutedEventArgs e)