From 86fa14086588d3ae49d18aa153a94ff94c6b305b Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 2 Jul 2024 20:33:18 -0700 Subject: [PATCH] Implement all of AccessLogService --- src/LibHac/FsSrv/AccessLogService.cs | 66 ++++++++++++++--- src/LibHac/FsSrv/AccessLogServiceImpl.cs | 73 +++++++++++++------ .../FsSrv/FileSystemServerInitializer.cs | 2 +- 3 files changed, 109 insertions(+), 32 deletions(-) diff --git a/src/LibHac/FsSrv/AccessLogService.cs b/src/LibHac/FsSrv/AccessLogService.cs index e81e3018..5bd6dbe3 100644 --- a/src/LibHac/FsSrv/AccessLogService.cs +++ b/src/LibHac/FsSrv/AccessLogService.cs @@ -1,15 +1,34 @@ using System; +using LibHac.Common; using LibHac.Fs; using LibHac.FsSrv.Impl; using LibHac.Sf; +using static LibHac.FsSrv.Anonymous; namespace LibHac.FsSrv; +file static class Anonymous +{ + public static Result GetProgramInfo(FileSystemServer fsServer, out ProgramInfo programInfo, ulong processId) + { + var programRegistry = new ProgramRegistryImpl(fsServer); + return programRegistry.GetProgramInfo(out programInfo, processId).Ret(); + } +} + +/// +/// Handles access log calls for . +/// +/// This struct handles checking a process' permissions before forwarding +/// requests to the object. +/// Based on nnSdk 18.3.0 (FS 18.0.0) internal readonly struct AccessLogService { private readonly AccessLogServiceImpl _serviceImpl; private readonly ulong _processId; + private FileSystemServer FsServer => _serviceImpl.FsServer; + public AccessLogService(AccessLogServiceImpl serviceImpl, ulong processId) { _serviceImpl = serviceImpl; @@ -18,7 +37,7 @@ internal readonly struct AccessLogService public Result SetAccessLogMode(GlobalAccessLogMode mode) { - Result res = GetProgramInfo(out ProgramInfo programInfo); + Result res = GetProgramInfo(FsServer, out ProgramInfo programInfo, _processId); if (res.IsFailure()) return res.Miss(); if (!programInfo.AccessControl.CanCall(OperationType.SetGlobalAccessLogMode)) @@ -36,15 +55,46 @@ internal readonly struct AccessLogService public Result OutputAccessLogToSdCard(InBuffer textBuffer) { - Result res = GetProgramInfo(out ProgramInfo programInfo); + Result res = GetProgramInfo(FsServer, out ProgramInfo programInfo, _processId); if (res.IsFailure()) return res.Miss(); - return _serviceImpl.OutputAccessLogToSdCard(textBuffer.Buffer, programInfo.ProgramIdValue, _processId); + return _serviceImpl.OutputAccessLogToSdCard(textBuffer.Buffer, programInfo.ProgramIdValue, _processId).Ret(); } + private static ReadOnlySpan OutputAccessLog => "FS_ACCESS: { multi_program_tag: true }\n"u8; + private static ReadOnlySpan OutputLogTagUnknown => "FS_ACCESS: { application_info_tag: { launch_type: Unknown } }\n"u8; + private static ReadOnlySpan OutputHead => "FS_ACCESS: { application_info_tag: { launch_type: "u8; + private static ReadOnlySpan OutputApplicationId => "Application, application_id: 0x"u8; + private static ReadOnlySpan OutputPatchId => "Patch, application_id: 0x"u8; + private static ReadOnlySpan OutputVersion => ", release_version: 0x"u8; + private static ReadOnlySpan OutputTail => " } }\n"u8; + public Result OutputApplicationInfoAccessLog(in ApplicationInfo applicationInfo) { - throw new NotImplementedException(); + if (applicationInfo.IsMultiProgram) + { + _serviceImpl.OutputAccessLogToSdCard(OutputAccessLog, applicationInfo.ApplicationId.Value, _processId).IgnoreResult(); + } + + if (applicationInfo.LaunchType == 0) + { + _serviceImpl.OutputAccessLogToSdCard(OutputLogTagUnknown, applicationInfo.ApplicationId.Value, _processId).IgnoreResult(); + } + else + { + Span buffer = stackalloc byte[0x80]; + ReadOnlySpan outputId = applicationInfo.LaunchType == 1 ? OutputApplicationId : OutputPatchId; + + var sb = new U8StringBuilder(buffer, autoExpand: true); + sb.Append(OutputHead) + .Append(outputId).AppendFormat(applicationInfo.ApplicationId.Value, 'X', 16) + .Append(OutputVersion).AppendFormat(applicationInfo.Version >> 16, 'X', 4) + .Append(OutputTail); + + _serviceImpl.OutputAccessLogToSdCard(sb.Buffer, applicationInfo.ApplicationId.Value, _processId); + } + + return Result.Success; } public Result OutputMultiProgramTagAccessLog() @@ -55,12 +105,8 @@ internal readonly struct AccessLogService public Result FlushAccessLogOnSdCard() { - throw new NotImplementedException(); - } - - private Result GetProgramInfo(out ProgramInfo programInfo) - { - return _serviceImpl.GetProgramInfo(out programInfo, _processId); + _serviceImpl.FlushAccessLogSdCardWriter(); + return Result.Success; } /// "FS_ACCESS: { multi_program_tag: true }\n" diff --git a/src/LibHac/FsSrv/AccessLogServiceImpl.cs b/src/LibHac/FsSrv/AccessLogServiceImpl.cs index a919208c..90cba0dd 100644 --- a/src/LibHac/FsSrv/AccessLogServiceImpl.cs +++ b/src/LibHac/FsSrv/AccessLogServiceImpl.cs @@ -1,34 +1,56 @@ using System; +using LibHac.Diag; using LibHac.Fs; using LibHac.FsSrv.Impl; +using LibHac.Os; +using Utility = LibHac.FsSrv.Impl.Utility; namespace LibHac.FsSrv; +/// +/// Writes to the FS access log file on the SD card, filtering messages based on the current global log mode +/// and the sending program's ID. +/// +/// Based on nnSdk 18.3.0 (FS 18.0.0) public class AccessLogServiceImpl : IDisposable { private Configuration _config; private GlobalAccessLogMode _accessLogMode; + private AccessLogSdCardWriter _sdCardWriter; + private SdkMutexType _mutex; - public AccessLogServiceImpl(in Configuration configuration) - { - _config = configuration; - } - - public void Dispose() - { - - } + public FileSystemServer FsServer => _config.FsServer; public struct Configuration { - public ulong MinimumProgramIdForSdCardLog; + public ulong ProgramIdWithoutPlatformIdMinForAccessLog; // LibHac additions public FileSystemServer FsServer; } + public AccessLogServiceImpl(in Configuration configuration) + { + _config = configuration; + _accessLogMode = GlobalAccessLogMode.None; + _sdCardWriter = new AccessLogSdCardWriter(configuration.FsServer.Hos.Fs); + _mutex = new SdkMutexType(); + } + + public void Dispose() + { + _sdCardWriter.Dispose(); + } + public void SetAccessLogMode(GlobalAccessLogMode mode) { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + if (_accessLogMode.HasFlag(GlobalAccessLogMode.SdCard) && !mode.HasFlag(GlobalAccessLogMode.SdCard)) + { + _sdCardWriter.Flush(); + } + _accessLogMode = mode; } @@ -44,22 +66,31 @@ public class AccessLogServiceImpl : IDisposable public Result OutputAccessLogToSdCard(ReadOnlySpan text, ulong programId, ulong processId) { - throw new NotImplementedException(); + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + if (!_accessLogMode.HasFlag(GlobalAccessLogMode.SdCard)) + return Result.Success; + + Assert.SdkRequiresNotEqual(_config.ProgramIdWithoutPlatformIdMinForAccessLog, 0ul); + + if (Utility.ClearPlatformIdInProgramId(processId) >= _config.ProgramIdWithoutPlatformIdMinForAccessLog) + { + _sdCardWriter.AppendLog(text, programId); + } + + return Result.Success; } - public Result FlushAccessLogSdCardWriter() + public void FlushAccessLogSdCardWriter() { - throw new NotImplementedException(); + if (_accessLogMode.HasFlag(GlobalAccessLogMode.SdCard)) + { + _sdCardWriter.Flush(); + } } - public Result FinalizeAccessLogSdCardWriter() + public void FinalizeAccessLogSdCardWriter() { - throw new NotImplementedException(); - } - - internal Result GetProgramInfo(out ProgramInfo programInfo, ulong processId) - { - var registry = new ProgramRegistryImpl(_config.FsServer); - return registry.GetProgramInfo(out programInfo, processId); + _sdCardWriter.FinalizeObject(); } } \ No newline at end of file diff --git a/src/LibHac/FsSrv/FileSystemServerInitializer.cs b/src/LibHac/FsSrv/FileSystemServerInitializer.cs index 7c401007..4f5f77ef 100644 --- a/src/LibHac/FsSrv/FileSystemServerInitializer.cs +++ b/src/LibHac/FsSrv/FileSystemServerInitializer.cs @@ -170,7 +170,7 @@ public static class FileSystemServerInitializer var statusReportService = new StatusReportServiceImpl(in statusReportServiceConfig); var accessLogServiceConfig = new AccessLogServiceImpl.Configuration(); - accessLogServiceConfig.MinimumProgramIdForSdCardLog = 0x0100000000003000; + accessLogServiceConfig.ProgramIdWithoutPlatformIdMinForAccessLog = 0x3000; accessLogServiceConfig.FsServer = server; var accessLogService = new AccessLogServiceImpl(in accessLogServiceConfig);