2020-04-16 01:06:41 +01:00
/*
2020-07-03 10:31:22 +01:00
* utils . c
2020-04-16 01:06:41 +01:00
*
2020-07-06 01:10:07 +01:00
* Copyright ( c ) 2018 - 2020 , WerWolv .
2020-12-23 17:48:57 +00:00
* Copyright ( c ) 2020 - 2021 , DarkMatterCore < pabloacurielz @ gmail . com > .
2020-07-03 10:31:22 +01:00
*
* This file is part of nxdumptool ( https : //github.com/DarkMatterCore/nxdumptool).
*
* nxdumptool is free software ; you can redistribute it and / or modify it
2020-04-16 01:06:41 +01:00
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
2020-07-03 10:31:22 +01:00
* nxdumptool is distributed in the hope it will be useful , but WITHOUT
2020-04-16 01:06:41 +01:00
* 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/>.
*/
2020-12-02 06:28:35 +00:00
# include <sys/statvfs.h>
2020-11-08 19:08:30 +00:00
2020-07-03 10:31:22 +01:00
# include "utils.h"
2020-04-15 21:50:07 +01:00
//#include "freetype_helper.h"
//#include "lvgl_helper.h"
2020-04-16 11:13:11 +01:00
# include "keys.h"
2020-04-15 21:50:07 +01:00
# include "gamecard.h"
2020-04-16 11:13:11 +01:00
# include "services.h"
2020-04-21 11:23:33 +01:00
# include "nca.h"
2020-05-05 16:22:16 +01:00
# include "usb.h"
2020-07-25 06:56:35 +01:00
# include "title.h"
2020-10-14 14:23:49 +01:00
# include "bfttf.h"
2020-04-17 22:59:05 +01:00
# include "fatfs/ff.h"
2020-04-15 21:50:07 +01:00
2020-07-22 09:03:28 +01:00
# define LOGFILE_PATH ". / " APP_TITLE ".log"
2020-07-17 06:01:31 +01:00
2020-04-15 21:50:07 +01:00
/* Global variables. */
2020-12-07 04:26:59 +00:00
static bool g_resourcesInit = false , g_isDevUnit = false ;
2020-05-03 00:40:50 +01:00
static Mutex g_resourcesMutex = 0 ;
2020-12-04 06:38:44 +00:00
static PadState g_padState = { 0 } ;
2020-05-03 00:40:50 +01:00
static FsFileSystem * g_sdCardFileSystem = NULL ;
static FsStorage g_emmcBisSystemPartitionStorage = { 0 } ;
static FATFS * g_emmcBisSystemPartitionFatFsObj = NULL ;
static AppletType g_programAppletType = 0 ;
static bool g_homeButtonBlocked = false ;
static Mutex g_homeButtonMutex = 0 ;
2020-04-16 11:13:11 +01:00
static u8 g_customFirmwareType = UtilsCustomFirmwareType_Unknown ;
2020-04-15 21:50:07 +01:00
static AppletHookCookie g_systemOverclockCookie = { 0 } ;
static Mutex g_logfileMutex = 0 ;
2020-10-08 19:31:09 +01:00
static const char * g_logfileTimestampFormat = " %d-%02d-%02d %02d:%02d:%02d -> %s: " ;
static const char * g_logfileLineBreak = " \r \n " ;
2020-04-15 21:50:07 +01:00
2020-07-26 05:57:12 +01:00
static const char * g_sizeSuffixes [ ] = { " B " , " KiB " , " MiB " , " GiB " } ;
static const u32 g_sizeSuffixesCount = MAX_ELEMENTS ( g_sizeSuffixes ) ;
2021-02-12 20:35:23 +00:00
static const char * g_illegalFileSystemChars = " \\ /:*? \" <>|^ " ;
2020-04-15 21:50:07 +01:00
/* Function prototypes. */
2020-08-15 22:22:49 +01:00
static bool _utilsGetCustomFirmwareType ( void ) ;
static bool _utilsIsDevelopmentUnit ( void ) ;
2020-05-03 00:40:50 +01:00
static bool utilsMountEmmcBisSystemPartitionStorage ( void ) ;
static void utilsUnmountEmmcBisSystemPartitionStorage ( void ) ;
2020-04-15 21:50:07 +01:00
static void utilsOverclockSystemAppletHook ( AppletHookType hook , void * param ) ;
2020-05-03 00:40:50 +01:00
bool utilsInitializeResources ( void )
{
mutexLock ( & g_resourcesMutex ) ;
2020-12-07 04:26:59 +00:00
bool ret = g_resourcesInit ;
2020-07-13 07:36:17 +01:00
if ( ret ) goto end ;
2020-05-03 00:40:50 +01:00
2020-12-04 06:38:44 +00:00
/* Configure input. */
/* Up to 8 different, full controller inputs. */
/* Individual Joy-Cons not supported. */
padConfigureInput ( 8 , HidNpadStyleSet_NpadFullCtrl ) ;
padInitializeWithMask ( & g_padState , 0x1000000FFUL ) ;
/* Create logfile. */
2020-10-15 00:08:01 +01:00
utilsWriteLogBufferToLogFile ( " ________________________________________________________________ \r \n " ) ;
2020-11-01 15:04:38 +00:00
LOGFILE ( APP_TITLE " v%u.%u.%u starting. Built on " __DATE__ " - " __TIME__ " . " , VERSION_MAJOR , VERSION_MINOR , VERSION_MICRO ) ;
2020-10-15 00:08:01 +01:00
/* Log Horizon OS version. */
u32 hos_version = hosversionGet ( ) ;
LOGFILE ( " Horizon OS version: %u.%u.%u. " , HOSVER_MAJOR ( hos_version ) , HOSVER_MINOR ( hos_version ) , HOSVER_MICRO ( hos_version ) ) ;
2020-08-15 22:22:49 +01:00
/* Retrieve custom firmware type. */
if ( ! _utilsGetCustomFirmwareType ( ) ) goto end ;
2020-10-15 00:08:01 +01:00
LOGFILE ( " Detected %s CFW. " , ( g_customFirmwareType = = UtilsCustomFirmwareType_Atmosphere ? " Atmosphere " : ( g_customFirmwareType = = UtilsCustomFirmwareType_SXOS ? " SX OS " : " ReiNX " ) ) ) ;
2020-08-01 05:43:55 +01:00
2020-07-06 01:10:07 +01:00
/* Initialize needed services. */
2020-05-03 00:40:50 +01:00
if ( ! servicesInitialize ( ) )
{
LOGFILE ( " Failed to initialize needed services! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-05-03 00:40:50 +01:00
}
2020-08-15 22:22:49 +01:00
/* Check if we're not running under a development unit. */
if ( ! _utilsIsDevelopmentUnit ( ) ) goto end ;
2020-10-15 00:08:01 +01:00
LOGFILE ( " Running under %s unit. " , g_isDevUnit ? " development " : " retail " ) ;
2020-08-15 22:22:49 +01:00
2020-07-06 01:10:07 +01:00
/* Initialize USB interface. */
2020-05-05 16:22:16 +01:00
if ( ! usbInitialize ( ) )
{
LOGFILE ( " Failed to initialize USB interface! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-05-05 16:22:16 +01:00
}
2020-12-07 04:26:59 +00:00
/* Initialize USB Mass Storage interface. */
if ( ! umsInitialize ( ) ) goto end ;
2020-11-08 19:08:30 +00:00
2020-07-06 01:10:07 +01:00
/* Load NCA keyset. */
2020-05-03 00:40:50 +01:00
if ( ! keysLoadNcaKeyset ( ) )
{
LOGFILE ( " Failed to load NCA keyset! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-05-03 00:40:50 +01:00
}
2020-07-06 01:10:07 +01:00
/* Allocate NCA crypto buffer. */
2020-05-03 00:40:50 +01:00
if ( ! ncaAllocateCryptoBuffer ( ) )
{
LOGFILE ( " Unable to allocate memory for NCA crypto buffer! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-05-03 00:40:50 +01:00
}
2020-07-06 01:10:07 +01:00
/* Initialize gamecard interface. */
2020-05-03 00:40:50 +01:00
if ( ! gamecardInitialize ( ) )
{
LOGFILE ( " Failed to initialize gamecard interface! " ) ;
2020-07-13 07:36:17 +01:00
goto end ;
2020-05-03 00:40:50 +01:00
}
2020-07-25 06:56:35 +01:00
/* Initialize title interface. */
if ( ! titleInitialize ( ) )
{
LOGFILE ( " Failed to initialize the title interface! " ) ;
goto end ;
}
2020-10-14 14:23:49 +01:00
/* Initialize BFTTF interface. */
if ( ! bfttfInitialize ( ) )
{
LOGFILE ( " Failed to initialize BFTTF interface! " ) ;
goto end ;
}
2020-08-15 22:22:49 +01:00
/* Retrieve pointer to the SD card FsFileSystem element. */
if ( ! ( g_sdCardFileSystem = fsdevGetDeviceFileSystem ( " sdmc: " ) ) )
{
LOGFILE ( " Failed to retrieve FsFileSystem from SD card! " ) ;
goto end ;
}
2020-07-06 01:10:07 +01:00
/* Mount eMMC BIS System partition. */
2020-07-13 07:36:17 +01:00
if ( ! utilsMountEmmcBisSystemPartitionStorage ( ) ) goto end ;
2020-05-03 00:40:50 +01:00
2020-07-06 01:10:07 +01:00
/* Get applet type. */
2020-05-03 00:40:50 +01:00
g_programAppletType = appletGetAppletType ( ) ;
2020-10-15 00:08:01 +01:00
LOGFILE ( " Running under %s mode. " , utilsAppletModeCheck ( ) ? " applet " : " title override " ) ;
2020-05-03 00:40:50 +01:00
2020-07-06 01:10:07 +01:00
/* Disable screen dimming and auto sleep. */
2020-05-03 00:40:50 +01:00
appletSetMediaPlaybackState ( true ) ;
2020-07-06 01:10:07 +01:00
/* Overclock system. */
2020-05-03 00:40:50 +01:00
utilsOverclockSystem ( true ) ;
2020-07-06 01:10:07 +01:00
/* Setup an applet hook to change the hardware clocks after a system mode change (docked <-> undocked). */
2020-05-03 00:40:50 +01:00
appletHook ( & g_systemOverclockCookie , utilsOverclockSystemAppletHook , NULL ) ;
2020-07-06 01:10:07 +01:00
/* Initialize FreeType. */
2020-05-03 00:40:50 +01:00
//if (!freeTypeHelperInitialize()) return false;
2020-07-06 01:10:07 +01:00
/* Initialize LVGL. */
2020-05-03 00:40:50 +01:00
//if (!lvglHelperInitialize()) return false;
2020-12-07 04:26:59 +00:00
ret = g_resourcesInit = true ;
2020-05-03 00:40:50 +01:00
2020-07-13 07:36:17 +01:00
end :
2020-05-03 00:40:50 +01:00
mutexUnlock ( & g_resourcesMutex ) ;
return ret ;
}
void utilsCloseResources ( void )
{
mutexLock ( & g_resourcesMutex ) ;
2020-07-06 01:10:07 +01:00
/* Free LVGL resources. */
2020-05-03 00:40:50 +01:00
//lvglHelperExit();
2020-07-06 01:10:07 +01:00
/* Free FreeType resources. */
2020-05-03 00:40:50 +01:00
//freeTypeHelperExit();
2020-07-06 01:10:07 +01:00
/* Unset our overclock applet hook. */
2020-05-03 00:40:50 +01:00
appletUnhook ( & g_systemOverclockCookie ) ;
2020-07-06 01:10:07 +01:00
/* Restore hardware clocks. */
2020-05-03 00:40:50 +01:00
utilsOverclockSystem ( false ) ;
2020-07-06 01:10:07 +01:00
/* Enable screen dimming and auto sleep. */
2020-05-03 00:40:50 +01:00
appletSetMediaPlaybackState ( false ) ;
2020-07-06 01:10:07 +01:00
/* Unblock HOME button presses. */
2020-05-03 00:40:50 +01:00
utilsChangeHomeButtonBlockStatus ( false ) ;
2020-07-06 01:10:07 +01:00
/* Unmount eMMC BIS System partition. */
2020-05-03 00:40:50 +01:00
utilsUnmountEmmcBisSystemPartitionStorage ( ) ;
2020-10-14 14:23:49 +01:00
/* Deinitialize BFTTF interface. */
bfttfExit ( ) ;
2020-07-25 06:56:35 +01:00
/* Deinitialize title interface. */
titleExit ( ) ;
2020-07-06 01:10:07 +01:00
/* Deinitialize gamecard interface. */
2020-05-03 00:40:50 +01:00
gamecardExit ( ) ;
2020-07-06 01:10:07 +01:00
/* Free NCA crypto buffer. */
2020-05-03 00:40:50 +01:00
ncaFreeCryptoBuffer ( ) ;
2020-12-07 04:26:59 +00:00
/* Close USB Mass Storage interface. */
umsExit ( ) ;
2020-11-08 19:08:30 +00:00
2020-07-06 01:10:07 +01:00
/* Close USB interface. */
2020-05-05 16:22:16 +01:00
usbExit ( ) ;
2020-07-06 01:10:07 +01:00
/* Close initialized services. */
2020-05-03 00:40:50 +01:00
servicesClose ( ) ;
2020-12-07 04:26:59 +00:00
g_resourcesInit = false ;
2020-05-03 00:40:50 +01:00
mutexUnlock ( & g_resourcesMutex ) ;
}
2020-04-17 22:59:05 +01:00
2020-08-18 06:04:13 +01:00
bool utilsCreateThread ( Thread * out_thread , ThreadFunc func , void * arg , int cpu_id )
{
/* Core 3 is reserved for HOS, so we can only use cores 0, 1 and 2. */
/* -2 can be provided to use the default process core. */
if ( ! out_thread | | ! func | | ( cpu_id < 0 & & cpu_id ! = - 2 ) | | cpu_id > 2 )
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
Result rc = 0 ;
u64 core_mask = 0 ;
size_t stack_size = 0x20000 ; /* Same value as libnx's newlib. */
bool success = false ;
memset ( out_thread , 0 , sizeof ( Thread ) ) ;
/* Get process core mask. */
rc = svcGetInfo ( & core_mask , InfoType_CoreMask , CUR_PROCESS_HANDLE , 0 ) ;
if ( R_FAILED ( rc ) )
{
LOGFILE ( " svcGetInfo failed! (0x%08X). " , rc ) ;
goto end ;
}
/* Create thread. */
/* Enable preemptive multithreading by using priority 0x3B. */
rc = threadCreate ( out_thread , func , arg , NULL , stack_size , 0x3B , cpu_id ) ;
if ( R_FAILED ( rc ) )
{
LOGFILE ( " threadCreate failed! (0x%08X). " , rc ) ;
goto end ;
}
/* Set thread core mask. */
rc = svcSetThreadCoreMask ( out_thread - > handle , cpu_id = = - 2 ? - 1 : cpu_id , core_mask ) ;
if ( R_FAILED ( rc ) )
{
LOGFILE ( " svcSetThreadCoreMask failed! (0x%08X). " , rc ) ;
goto end ;
}
/* Start thread. */
rc = threadStart ( out_thread ) ;
if ( R_FAILED ( rc ) )
{
LOGFILE ( " threadStart failed! (0x%08X). " , rc ) ;
goto end ;
}
success = true ;
end :
if ( ! success & & out_thread - > handle ! = INVALID_HANDLE ) threadClose ( out_thread ) ;
return success ;
}
void utilsJoinThread ( Thread * thread )
{
if ( ! thread | | thread - > handle = = INVALID_HANDLE )
{
LOGFILE ( " Invalid parameters! " ) ;
return ;
}
Result rc = threadWaitForExit ( thread ) ;
if ( R_FAILED ( rc ) )
{
LOGFILE ( " threadWaitForExit failed! (0x%08X). " , rc ) ;
return ;
}
threadClose ( thread ) ;
memset ( thread , 0 , sizeof ( Thread ) ) ;
}
2020-08-15 22:22:49 +01:00
bool utilsIsDevelopmentUnit ( void )
{
mutexLock ( & g_resourcesMutex ) ;
2020-12-07 04:26:59 +00:00
bool ret = ( g_resourcesInit & & g_isDevUnit ) ;
2020-08-15 22:22:49 +01:00
mutexUnlock ( & g_resourcesMutex ) ;
return ret ;
}
2020-12-04 06:38:44 +00:00
void utilsScanPads ( void )
{
padUpdate ( & g_padState ) ;
}
u64 utilsGetButtonsDown ( void )
2020-04-15 21:50:07 +01:00
{
2020-12-04 06:38:44 +00:00
return padGetButtonsDown ( & g_padState ) ;
2020-07-29 22:02:21 +01:00
}
2020-12-04 06:38:44 +00:00
u64 utilsGetButtonsHeld ( void )
2020-07-29 22:02:21 +01:00
{
2020-12-04 06:38:44 +00:00
return padGetButtons ( & g_padState ) ;
2020-04-15 21:50:07 +01:00
}
2020-07-06 01:10:07 +01:00
void utilsWaitForButtonPress ( u64 flag )
2020-04-15 21:50:07 +01:00
{
2020-12-04 06:38:44 +00:00
/* Don't consider stick movement as button inputs. */
2020-12-24 08:49:38 +00:00
if ( ! flag ) flag = ~ ( HidNpadButton_StickLLeft | HidNpadButton_StickLRight | HidNpadButton_StickLUp | HidNpadButton_StickLDown | HidNpadButton_StickRLeft | HidNpadButton_StickRRight | \
HidNpadButton_StickRUp | HidNpadButton_StickRDown ) ;
2020-04-15 21:50:07 +01:00
while ( appletMainLoop ( ) )
{
2020-12-04 06:38:44 +00:00
utilsScanPads ( ) ;
if ( utilsGetButtonsDown ( ) & flag ) break ;
2020-04-15 21:50:07 +01:00
}
}
2020-10-02 10:53:58 +01:00
bool utilsAppendFormattedStringToBuffer ( char * * dst , size_t * dst_size , const char * fmt , . . . )
{
2020-10-15 01:06:53 +01:00
if ( ! dst | | ! dst_size | | ! fmt | | ! * fmt )
2020-10-02 10:53:58 +01:00
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
va_list args ;
va_start ( args , fmt ) ;
int formatted_str_len = 0 ;
size_t required_dst_size = 0 , dst_str_len = ( * dst ? strlen ( * dst ) : 0 ) ;
char * realloc_dst = NULL ;
bool success = false ;
if ( dst_str_len > * dst_size )
{
* * dst = ' \0 ' ;
dst_str_len = 0 ;
}
formatted_str_len = vsnprintf ( NULL , 0 , fmt , args ) ;
if ( formatted_str_len < = 0 )
{
LOGFILE ( " Failed to retrieve formatted string length! " ) ;
goto end ;
}
required_dst_size = ( dst_str_len + ( size_t ) formatted_str_len + 1 ) ;
if ( required_dst_size > * dst_size )
{
realloc_dst = realloc ( * dst , required_dst_size ) ;
if ( ! realloc_dst )
{
LOGFILE ( " Failed to reallocate destination buffer! " ) ;
goto end ;
}
* dst = realloc_dst ;
realloc_dst = NULL ;
memset ( * dst + dst_str_len , 0 , ( size_t ) formatted_str_len + 1 ) ;
* dst_size = required_dst_size ;
}
vsprintf ( * dst + dst_str_len , fmt , args ) ;
success = true ;
end :
va_end ( args ) ;
return success ;
}
2020-07-13 07:36:17 +01:00
void utilsWriteMessageToLogFile ( const char * func_name , const char * fmt , . . . )
2020-04-15 21:50:07 +01:00
{
2020-10-15 01:06:53 +01:00
if ( ! func_name | | ! * func_name | | ! fmt | | ! * fmt ) return ;
2020-07-13 07:36:17 +01:00
2020-04-15 21:50:07 +01:00
mutexLock ( & g_logfileMutex ) ;
va_list args ;
2020-10-12 21:35:47 +01:00
FILE * logfile = fopen ( LOGFILE_PATH , " a+ " ) ;
2020-07-13 07:36:17 +01:00
if ( ! logfile ) goto end ;
2020-04-15 21:50:07 +01:00
time_t now = time ( NULL ) ;
struct tm * ts = localtime ( & now ) ;
2020-10-08 19:31:09 +01:00
fprintf ( logfile , g_logfileTimestampFormat , ts - > tm_year + 1900 , ts - > tm_mon + 1 , ts - > tm_mday , ts - > tm_hour , ts - > tm_min , ts - > tm_sec , func_name ) ;
2020-04-15 21:50:07 +01:00
va_start ( args , fmt ) ;
vfprintf ( logfile , fmt , args ) ;
va_end ( args ) ;
2020-10-08 19:31:09 +01:00
fprintf ( logfile , g_logfileLineBreak ) ;
2020-04-15 21:50:07 +01:00
fclose ( logfile ) ;
2020-08-01 05:43:55 +01:00
utilsCommitSdCardFileSystemChanges ( ) ;
2020-04-15 21:50:07 +01:00
2020-07-13 07:36:17 +01:00
end :
2020-04-15 21:50:07 +01:00
mutexUnlock ( & g_logfileMutex ) ;
}
2020-10-02 10:53:58 +01:00
void utilsWriteMessageToLogBuffer ( char * * dst , size_t * dst_size , const char * func_name , const char * fmt , . . . )
2020-07-13 07:36:17 +01:00
{
2020-10-15 01:06:53 +01:00
if ( ! dst | | ! dst_size | | ! func_name | | ! * func_name | | ! fmt | | ! * fmt ) return ;
2020-07-13 07:36:17 +01:00
va_list args ;
2020-10-02 10:53:58 +01:00
va_start ( args , fmt ) ;
2020-07-13 07:36:17 +01:00
time_t now = time ( NULL ) ;
struct tm * ts = localtime ( & now ) ;
2020-10-02 10:53:58 +01:00
int timestamp_len = 0 , formatted_str_len = 0 ;
size_t required_dst_size = 0 , dst_str_len = ( * dst ? strlen ( * dst ) : 0 ) ;
char * realloc_dst = NULL ;
2020-07-13 07:36:17 +01:00
2020-10-02 10:53:58 +01:00
if ( dst_str_len > * dst_size )
{
* * dst = ' \0 ' ;
dst_str_len = 0 ;
}
2020-07-13 07:36:17 +01:00
2020-10-08 19:31:09 +01:00
timestamp_len = snprintf ( NULL , 0 , g_logfileTimestampFormat , ts - > tm_year + 1900 , ts - > tm_mon + 1 , ts - > tm_mday , ts - > tm_hour , ts - > tm_min , ts - > tm_sec , func_name ) ;
2020-10-02 10:53:58 +01:00
if ( timestamp_len < = 0 ) goto end ;
formatted_str_len = vsnprintf ( NULL , 0 , fmt , args ) ;
if ( formatted_str_len < = 0 ) goto end ;
required_dst_size = ( dst_str_len + ( size_t ) timestamp_len + ( size_t ) formatted_str_len + 3 ) ;
if ( required_dst_size > * dst_size )
{
realloc_dst = realloc ( * dst , required_dst_size ) ;
if ( ! realloc_dst ) goto end ;
* dst = realloc_dst ;
realloc_dst = NULL ;
memset ( * dst + dst_str_len , 0 , ( size_t ) timestamp_len + ( size_t ) formatted_str_len + 3 ) ;
* dst_size = required_dst_size ;
}
2020-10-08 19:31:09 +01:00
sprintf ( * dst + dst_str_len , g_logfileTimestampFormat , ts - > tm_year + 1900 , ts - > tm_mon + 1 , ts - > tm_mday , ts - > tm_hour , ts - > tm_min , ts - > tm_sec , func_name ) ;
2020-10-02 10:53:58 +01:00
vsprintf ( * dst + dst_str_len + ( size_t ) timestamp_len , fmt , args ) ;
2020-10-08 19:31:09 +01:00
sprintf ( * dst + dst_str_len + ( size_t ) timestamp_len + ( size_t ) formatted_str_len , g_logfileLineBreak ) ;
2020-07-13 07:36:17 +01:00
2020-10-02 10:53:58 +01:00
end :
va_end ( args ) ;
2020-07-13 07:36:17 +01:00
}
void utilsWriteLogBufferToLogFile ( const char * src )
{
2020-10-15 01:06:53 +01:00
if ( ! src | | ! * src ) return ;
2020-07-13 07:36:17 +01:00
mutexLock ( & g_logfileMutex ) ;
FILE * logfile = fopen ( LOGFILE_PATH , " a+ " ) ;
if ( ! logfile ) goto end ;
fprintf ( logfile , " %s " , src ) ;
fclose ( logfile ) ;
2020-08-01 05:43:55 +01:00
utilsCommitSdCardFileSystemChanges ( ) ;
2020-07-13 07:36:17 +01:00
end :
mutexUnlock ( & g_logfileMutex ) ;
}
void utilsLogFileMutexControl ( bool lock )
{
if ( lock )
{
mutexLock ( & g_logfileMutex ) ;
} else {
mutexUnlock ( & g_logfileMutex ) ;
}
}
2020-05-05 19:04:23 +01:00
void utilsReplaceIllegalCharacters ( char * str , bool ascii_only )
2020-05-03 00:40:50 +01:00
{
size_t strsize = 0 ;
2020-04-16 11:13:11 +01:00
2020-05-03 00:40:50 +01:00
if ( ! str | | ! ( strsize = strlen ( str ) ) ) return ;
2020-04-15 21:50:07 +01:00
2020-05-03 00:40:50 +01:00
for ( size_t i = 0 ; i < strsize ; i + + )
2020-04-21 11:23:33 +01:00
{
2021-02-12 20:35:23 +00:00
if ( memchr ( g_illegalFileSystemChars , str [ i ] , sizeof ( g_illegalFileSystemChars ) - 1 ) | | str [ i ] < 0x20 | | ( ! ascii_only & & str [ i ] = = 0x7F ) | | ( ascii_only & & str [ i ] > = 0x7F ) ) str [ i ] = ' _ ' ;
2020-04-21 11:23:33 +01:00
}
2020-04-15 21:50:07 +01:00
}
2020-05-03 00:40:50 +01:00
void utilsTrimString ( char * str )
2020-04-15 21:50:07 +01:00
{
2020-05-03 00:40:50 +01:00
size_t strsize = 0 ;
char * start = NULL , * end = NULL ;
2020-04-15 21:50:07 +01:00
2020-05-03 00:40:50 +01:00
if ( ! str | | ! ( strsize = strlen ( str ) ) ) return ;
2020-04-15 21:50:07 +01:00
2020-05-03 00:40:50 +01:00
start = str ;
end = ( start + strsize ) ;
2020-04-15 21:50:07 +01:00
2020-05-03 00:40:50 +01:00
while ( - - end > = start )
{
if ( ! isspace ( ( unsigned char ) * end ) ) break ;
}
2020-04-17 22:59:05 +01:00
2020-05-03 00:40:50 +01:00
* ( + + end ) = ' \0 ' ;
2020-04-17 22:59:05 +01:00
2020-05-03 00:40:50 +01:00
while ( isspace ( ( unsigned char ) * start ) ) start + + ;
2020-04-21 11:23:33 +01:00
2020-05-03 00:40:50 +01:00
if ( start ! = str ) memmove ( str , start , end - start + 1 ) ;
2020-04-16 11:13:11 +01:00
}
2020-04-17 22:59:05 +01:00
void utilsGenerateHexStringFromData ( char * dst , size_t dst_size , const void * src , size_t src_size )
{
if ( ! src | | ! src_size | | ! dst | | dst_size < ( ( src_size * 2 ) + 1 ) ) return ;
size_t i , j ;
const u8 * src_u8 = ( const u8 * ) src ;
for ( i = 0 , j = 0 ; i < src_size ; i + + )
{
2020-04-19 23:44:22 +01:00
char h_nib = ( ( src_u8 [ i ] > > 4 ) & 0xF ) ;
char l_nib = ( src_u8 [ i ] & 0xF ) ;
2020-04-17 22:59:05 +01:00
2020-04-19 23:44:22 +01:00
dst [ j + + ] = ( h_nib + ( h_nib < 0xA ? 0x30 : 0x57 ) ) ;
dst [ j + + ] = ( l_nib + ( l_nib < 0xA ? 0x30 : 0x57 ) ) ;
2020-04-17 22:59:05 +01:00
}
dst [ j ] = ' \0 ' ;
}
2020-07-26 05:57:12 +01:00
void utilsGenerateFormattedSizeString ( u64 size , char * dst , size_t dst_size )
{
if ( ! dst | | dst_size < 2 ) return ;
double converted_size = ( double ) size ;
for ( u32 i = 0 ; i < g_sizeSuffixesCount ; i + + )
{
if ( converted_size > = pow ( 1024.0 , i + 1 ) & & ( i + 1 ) < g_sizeSuffixesCount ) continue ;
converted_size / = pow ( 1024.0 , i ) ;
snprintf ( dst , dst_size , " %.*f %s " , ( converted_size > = 100.0 ? 0 : ( converted_size > = 10.0 ? 1 : 2 ) ) , converted_size , g_sizeSuffixes [ i ] ) ;
break ;
}
}
2020-12-24 08:49:38 +00:00
bool utilsGetFileSystemStatsByPath ( const char * path , u64 * out_total , u64 * out_free )
2020-08-01 05:43:55 +01:00
{
2020-12-02 06:28:35 +00:00
char * name_end = NULL , stat_path [ 32 ] = { 0 } ;
struct statvfs info = { 0 } ;
int ret = - 1 ;
2020-12-24 08:49:38 +00:00
if ( ! path | | ! * path | | ! ( name_end = strchr ( path , ' : ' ) ) | | * ( name_end + 1 ) ! = ' / ' | | ( ! out_total & & ! out_free ) )
2020-12-02 06:28:35 +00:00
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
name_end + = 2 ;
sprintf ( stat_path , " %.*s " , ( int ) ( name_end - path ) , path ) ;
if ( ( ret = statvfs ( stat_path , & info ) ) ! = 0 )
{
LOGFILE ( " statvfs failed! (%d) (errno: %d). " , ret , errno ) ;
return false ;
}
2020-12-24 08:49:38 +00:00
if ( out_total ) * out_total = ( ( u64 ) info . f_blocks * ( u64 ) info . f_frsize ) ;
if ( out_free ) * out_free = ( ( u64 ) info . f_bfree * ( u64 ) info . f_frsize ) ;
2020-12-02 06:28:35 +00:00
return true ;
2020-08-01 05:43:55 +01:00
}
bool utilsCommitSdCardFileSystemChanges ( void )
{
if ( ! g_sdCardFileSystem ) return false ;
Result rc = fsFsCommit ( g_sdCardFileSystem ) ;
return R_SUCCEEDED ( rc ) ;
2020-05-03 00:40:50 +01:00
}
bool utilsCheckIfFileExists ( const char * path )
{
2020-10-15 01:06:53 +01:00
if ( ! path | | ! * path ) return false ;
2020-05-03 00:40:50 +01:00
FILE * chkfile = fopen ( path , " rb " ) ;
if ( chkfile )
2020-04-16 11:13:11 +01:00
{
2020-05-03 00:40:50 +01:00
fclose ( chkfile ) ;
return true ;
2020-04-16 11:13:11 +01:00
}
2020-05-03 00:40:50 +01:00
return false ;
2020-04-16 11:13:11 +01:00
}
2020-10-22 05:38:14 +01:00
void utilsRemoveConcatenationFile ( const char * path )
{
if ( ! path | | ! * path ) return ;
remove ( path ) ;
fsdevDeleteDirectoryRecursively ( path ) ;
}
2020-05-03 00:40:50 +01:00
bool utilsCreateConcatenationFile ( const char * path )
2020-04-15 21:50:07 +01:00
{
2020-10-15 01:06:53 +01:00
if ( ! path | | ! * path )
2020-05-03 00:40:50 +01:00
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
2020-04-15 21:50:07 +01:00
2020-07-06 01:10:07 +01:00
/* Safety check: remove any existant file/directory at the destination path. */
2020-10-22 05:38:14 +01:00
utilsRemoveConcatenationFile ( path ) ;
2020-05-03 00:40:50 +01:00
/* Create ConcatenationFile */
2020-07-06 01:10:07 +01:00
/* If the call succeeds, the caller function will be able to operate on this file using stdio calls. */
2020-08-01 05:43:55 +01:00
Result rc = fsdevCreateFile ( path , 0 , FsCreateOption_BigFile ) ;
if ( R_FAILED ( rc ) ) LOGFILE ( " fsdevCreateFile failed for \" %s \" ! (0x%08X). " , path , rc ) ;
2020-05-03 00:40:50 +01:00
2020-08-01 05:43:55 +01:00
return R_SUCCEEDED ( rc ) ;
2020-05-03 00:40:50 +01:00
}
2020-07-29 22:02:21 +01:00
void utilsCreateDirectoryTree ( const char * path , bool create_last_element )
{
char * ptr = NULL , * tmp = NULL ;
size_t path_len = 0 ;
if ( ! path | | ! ( path_len = strlen ( path ) ) ) return ;
tmp = calloc ( path_len + 1 , sizeof ( char ) ) ;
if ( ! tmp ) return ;
ptr = strchr ( path , ' / ' ) ;
while ( ptr )
{
sprintf ( tmp , " %.*s " , ( int ) ( ptr - path ) , path ) ;
mkdir ( tmp , 0777 ) ;
ptr = strchr ( + + ptr , ' / ' ) ;
}
if ( create_last_element ) mkdir ( path , 0777 ) ;
free ( tmp ) ;
}
2020-10-21 05:27:48 +01:00
char * utilsGeneratePath ( const char * prefix , const char * filename , const char * extension )
{
2020-10-26 06:39:33 +00:00
if ( ! filename | | ! * filename | | ! extension | | ! * extension )
2020-10-21 05:27:48 +01:00
{
LOGFILE ( " Invalid parameters! " ) ;
return NULL ;
}
char * path = NULL ;
2020-10-26 06:39:33 +00:00
size_t path_len = ( strlen ( filename ) + strlen ( extension ) + 1 ) ;
if ( prefix & & * prefix ) path_len + = strlen ( prefix ) ;
2020-10-21 05:27:48 +01:00
if ( ! ( path = calloc ( path_len , sizeof ( char ) ) ) )
{
LOGFILE ( " Failed to allocate 0x%lX bytes for output path! " , path_len ) ;
return NULL ;
}
2020-10-26 06:39:33 +00:00
if ( prefix & & * prefix ) strcat ( path , prefix ) ;
strcat ( path , filename ) ;
strcat ( path , extension ) ;
2020-10-21 05:27:48 +01:00
return path ;
}
2020-05-03 00:40:50 +01:00
bool utilsAppletModeCheck ( void )
{
return ( g_programAppletType ! = AppletType_Application & & g_programAppletType ! = AppletType_SystemApplication ) ;
}
void utilsChangeHomeButtonBlockStatus ( bool block )
{
mutexLock ( & g_homeButtonMutex ) ;
2020-07-06 01:10:07 +01:00
/* Only change HOME button blocking status if we're running as a regular application or a system application, and if it's current blocking status is different than the requested one. */
2020-05-03 00:40:50 +01:00
if ( ! utilsAppletModeCheck ( ) & & block ! = g_homeButtonBlocked )
{
if ( block )
{
appletBeginBlockingHomeButtonShortAndLongPressed ( 0 ) ;
} else {
appletEndBlockingHomeButtonShortAndLongPressed ( ) ;
}
g_homeButtonBlocked = block ;
}
mutexUnlock ( & g_homeButtonMutex ) ;
}
u8 utilsGetCustomFirmwareType ( void )
{
return g_customFirmwareType ;
}
FsStorage * utilsGetEmmcBisSystemPartitionStorage ( void )
{
return & g_emmcBisSystemPartitionStorage ;
}
void utilsOverclockSystem ( bool overclock )
{
u32 cpuClkRate = ( ( overclock ? CPU_CLKRT_OVERCLOCKED : CPU_CLKRT_NORMAL ) * 1000000 ) ;
u32 memClkRate = ( ( overclock ? MEM_CLKRT_OVERCLOCKED : MEM_CLKRT_NORMAL ) * 1000000 ) ;
servicesChangeHardwareClockRates ( cpuClkRate , memClkRate ) ;
2020-04-15 21:50:07 +01:00
}
2020-04-17 22:59:05 +01:00
2020-08-15 22:22:49 +01:00
static bool _utilsGetCustomFirmwareType ( void )
{
bool has_service = false , tx_srv = false , rnx_srv = false ;
/* First, check if we're running under Atmosphere or an Atmosphere-based CFW by using a SM API extension that's only provided by it. */
if ( R_SUCCEEDED ( servicesAtmosphereHasService ( & has_service , " ncm " ) ) )
{
/* We're running under Atmosphere or an Atmosphere-based CFW. Time to check which one is it. */
tx_srv = ( R_SUCCEEDED ( servicesAtmosphereHasService ( & has_service , " tx " ) ) & & has_service ) ;
rnx_srv = ( R_SUCCEEDED ( servicesAtmosphereHasService ( & has_service , " rnx " ) ) & & has_service ) ;
} else {
/* Odds are we're not running under Atmosphere, or maybe we're running under an old Atmosphere version without SM API extensions. */
/* We'll use the smRegisterService() trick to check for running services. */
/* But first, we need to re-initialize SM in order to avoid 0xF601 (port remote dead) errors. */
smExit ( ) ;
Result rc = smInitialize ( ) ;
if ( R_FAILED ( rc ) )
{
LOGFILE ( " smInitialize failed! (0x%08X). " , rc ) ;
return false ;
}
tx_srv = servicesCheckRunningServiceByName ( " tx " ) ;
rnx_srv = servicesCheckRunningServiceByName ( " rnx " ) ;
}
/* Finally, determine the CFW type. */
g_customFirmwareType = ( rnx_srv ? UtilsCustomFirmwareType_ReiNX : ( tx_srv ? UtilsCustomFirmwareType_SXOS : UtilsCustomFirmwareType_Atmosphere ) ) ;
return true ;
}
static bool _utilsIsDevelopmentUnit ( void )
{
Result rc = 0 ;
bool tmp = false ;
rc = splIsDevelopment ( & tmp ) ;
if ( R_SUCCEEDED ( rc ) )
{
g_isDevUnit = tmp ;
} else {
LOGFILE ( " splIsDevelopment failed! (0x%08X). " , rc ) ;
}
return R_SUCCEEDED ( rc ) ;
}
2020-04-17 22:59:05 +01:00
static bool utilsMountEmmcBisSystemPartitionStorage ( void )
{
Result rc = 0 ;
FRESULT fr = FR_OK ;
rc = fsOpenBisStorage ( & g_emmcBisSystemPartitionStorage , FsBisPartitionId_System ) ;
if ( R_FAILED ( rc ) )
{
2020-07-06 01:10:07 +01:00
LOGFILE ( " Failed to open eMMC BIS System partition storage! (0x%08X). " , rc ) ;
2020-04-17 22:59:05 +01:00
return false ;
}
2020-04-19 23:44:22 +01:00
g_emmcBisSystemPartitionFatFsObj = calloc ( 1 , sizeof ( FATFS ) ) ;
if ( ! g_emmcBisSystemPartitionFatFsObj )
2020-04-17 22:59:05 +01:00
{
2020-07-03 10:31:22 +01:00
LOGFILE ( " Unable to allocate memory for FatFs element! " ) ;
2020-04-17 22:59:05 +01:00
return false ;
}
2020-11-28 06:38:01 +00:00
fr = f_mount ( g_emmcBisSystemPartitionFatFsObj , BIS_SYSTEM_PARTITION_MOUNT_NAME , 1 ) ;
2020-04-17 22:59:05 +01:00
if ( fr ! = FR_OK )
{
2020-07-06 01:10:07 +01:00
LOGFILE ( " Failed to mount eMMC BIS System partition! (%u). " , fr ) ;
2020-04-17 22:59:05 +01:00
return false ;
}
return true ;
}
static void utilsUnmountEmmcBisSystemPartitionStorage ( void )
{
2020-04-19 23:44:22 +01:00
if ( g_emmcBisSystemPartitionFatFsObj )
2020-04-17 22:59:05 +01:00
{
2020-11-28 06:38:01 +00:00
f_unmount ( BIS_SYSTEM_PARTITION_MOUNT_NAME ) ;
2020-04-19 23:44:22 +01:00
free ( g_emmcBisSystemPartitionFatFsObj ) ;
g_emmcBisSystemPartitionFatFsObj = NULL ;
2020-04-17 22:59:05 +01:00
}
if ( serviceIsActive ( & ( g_emmcBisSystemPartitionStorage . s ) ) )
{
fsStorageClose ( & g_emmcBisSystemPartitionStorage ) ;
memset ( & g_emmcBisSystemPartitionStorage , 0 , sizeof ( FsStorage ) ) ;
}
}
2020-05-03 00:40:50 +01:00
static void utilsOverclockSystemAppletHook ( AppletHookType hook , void * param )
{
( void ) param ;
if ( hook ! = AppletHookType_OnOperationMode & & hook ! = AppletHookType_OnPerformanceMode ) return ;
2020-07-06 01:10:07 +01:00
/* To do: read config here to actually know the value to use with utilsOverclockSystem. */
2020-05-03 00:40:50 +01:00
utilsOverclockSystem ( false ) ;
}