Skip to content

Instantly share code, notes, and snippets.

@swillits
Last active August 29, 2015 13:55
Show Gist options
  • Save swillits/8725895 to your computer and use it in GitHub Desktop.
Save swillits/8725895 to your computer and use it in GitHub Desktop.
void *Sys_LoadDll( const char *name, char *fqpath,
int( **entryPoint ) ( int, ... ),
int ( *systemcalls )( int, ... ) ) {
void *libHandle;
void ( *dllEntry )( int ( *syscallptr )( int, ... ) );
char fname[MAX_OSPATH];
char *pwdpath;
char *homepath;
char *basepath;
char *gamedir;
char *fn;
const char* err = NULL; // bk001206 // rb0101023 - now const
#if !defined( DEDICATED )
char *cvar_name = NULL;
#endif
*fqpath = 0 ; // added 2/15/02 by T.Ray
// bk001206 - let's have some paranoia
assert( name );
Q_strncpyz( fname, Sys_GetDLLName( name ), sizeof( fname ) );
// bk001129 - was RTLD_LAZY
#define Q_RTLD RTLD_NOW
pwdpath = Sys_Cwd();
homepath = Cvar_VariableString( "fs_homepath" );
basepath = Cvar_VariableString( "fs_basepath" );
gamedir = Cvar_VariableString( "fs_game" );
// this is relevant to client only
// this code is in for full client hosting a game, but it's not affected by it
#if !defined( DEDICATED )
// do a first scan to identify what we are going to dlopen
// we need to pass this to FS_ExtractFromPakFile so that it checksums the right file
// NOTE: if something fails (not found, or file operation failed), we will ERR_FATAL (in the checksum itself, we only ERR_DROP)
#ifndef NDEBUG
fn = FS_BuildOSPath( pwdpath, gamedir, fname );
if ( access( fn, R_OK ) == -1 ) {
#endif
fn = FS_BuildOSPath( homepath, gamedir, fname );
if ( access( fn, R_OK ) == 0 ) {
// there is a .so in fs_homepath, but is it a valid one version-wise?
// we use a persistent variable in config.cfg to make sure
// this is set in FS_CL_ExtractFromPakFile when the file is extracted
cvar_t *lastVersion;
cvar_name = va( "cl_lastVersion%s", name );
lastVersion = Cvar_Get( cvar_name, "(uninitialized)", CVAR_ARCHIVE );
if ( Q_stricmp( Cvar_VariableString( "version" ), lastVersion->string ) ) {
Com_DPrintf( "clearing non matching version of %s .so: %s\n", name, fn );
if ( remove( fn ) == -1 ) {
Com_Error( ERR_FATAL, "failed to remove outdated '%s' file:\n\"%s\"\n", fn, strerror( errno ) );
}
// we cancelled fs_homepath, go work on basepath now
fn = FS_BuildOSPath( basepath, gamedir, fname );
if ( access( fn, R_OK ) == -1 ) {
// we may be dealing with a media-only mod, check wether we can find 'reference' DLLs and copy them over
if ( !CopyDLLForMod( &fn, gamedir, pwdpath, homepath, basepath, fname ) ) {
Com_Error( ERR_FATAL, "Sys_LoadDll(%s) failed, no corresponding .so file found in fs_homepath or fs_basepath\n", name );
}
}
}
// the .so in fs_homepath is valid version-wise .. FS_CL_ExtractFromPakFile will have to decide wether it's valid pk3-wise later
} else {
fn = FS_BuildOSPath( basepath, gamedir, fname );
if ( access( fn, R_OK ) == -1 ) {
// we may be dealing with a media-only mod, check wether we can find 'reference' DLLs and copy them over
if ( !CopyDLLForMod( &fn, gamedir, pwdpath, homepath, basepath, fname ) ) {
Com_Error( ERR_FATAL, "Sys_LoadDll(%s) failed, no corresponding .so file found in fs_homepath or fs_basepath\n", name );
}
}
}
#ifndef NDEBUG
}
#endif
// NERVE - SMF - extract dlls from pak file for security
// we have to handle the game dll a little differently
// NOTE #2: we may have found a file in fs_basepath, and if the checksum is wrong, FS_Extract will write in fs_homepath
// won't be a problem since we start a brand new scan next
if ( cl_connectedToPureServer && Q_strncmp( name, "qagame", 6 ) ) {
if ( !FS_CL_ExtractFromPakFile( fn, gamedir, fname, cvar_name ) ) {
Com_Error( ERR_DROP, "Game code(%s) failed Pure Server check", fname );
}
}
#endif
#ifndef NDEBUG
// current directory
// NOTE: only for debug build, see Sys_LoadDll discussion
fn = FS_BuildOSPath( pwdpath, gamedir, fname );
Com_Printf( "Sys_LoadDll(%s)... ", fn );
libHandle = dlopen( fn, Q_RTLD );
if ( !libHandle ) {
Com_Printf( "\nSys_LoadDll(%s) failed:\n\"%s\"\n", fn, dlerror() );
#endif
// homepath
fn = FS_BuildOSPath( homepath, gamedir, fname );
Com_Printf( "Sys_LoadDll(%s)... ", fn );
libHandle = dlopen( fn, Q_RTLD );
if ( !libHandle ) {
Com_Printf( "\nSys_LoadDll(%s) failed:\n\"%s\"\n", fn, dlerror() );
// basepath
fn = FS_BuildOSPath( basepath, gamedir, fname );
Com_Printf( "Sys_LoadDll(%s)... ", fn );
libHandle = dlopen( fn, Q_RTLD );
if ( !libHandle ) {
// report any problem
Com_Printf( "\nSys_LoadDll(%s) failed:\n\"%s\"\n", fn, dlerror() );
} else {
Com_Printf( "ok\n" );
}
// not found, bail
if ( !libHandle ) {
#ifndef NDEBUG // in debug abort on failure
Com_Error( ERR_FATAL, "Sys_LoadDll(%s) failed dlopen() completely!\n", name );
#else
Com_Printf( "Sys_LoadDll(%s) failed dlopen() completely!\n", name );
#endif
return NULL;
}
} else {
Com_Printf( "ok\n" );
}
#ifndef NDEBUG
} else {
Com_Printf( "ok\n" );
}
#endif
Q_strncpyz( fqpath, fn, MAX_QPATH ) ; // added 2/15/02 by T.Ray
dllEntry = dlsym( libHandle, "dllEntry" );
*entryPoint = dlsym( libHandle, "vmMain" );
if ( !*entryPoint || !dllEntry ) {
err = dlerror();
#ifndef NDEBUG // in debug abort on failure
Com_Error( ERR_FATAL, "Sys_LoadDll(%s) failed dlsym(vmMain):\n\"%s\" !\n", name, err );
#else
Com_Printf( "Sys_LoadDll(%s) failed dlsym(vmMain):\n\"%s\" !\n", name, err );
#endif
dlclose( libHandle );
err = dlerror();
if ( err != NULL ) {
Com_Printf( "Sys_LoadDll(%s) failed dlcose:\n\"%s\"\n", name, err );
}
return NULL;
}
Com_Printf( "Sys_LoadDll(%s) found **vmMain** at %p \n", name, *entryPoint );
dllEntry( systemcalls );
Com_Printf( "Sys_LoadDll(%s) succeeded!\n", name );
return libHandle;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment