/** * @brief Loads a mod library. * #1 look in fs_homepath * #2 look in fs_basepath * #3 try to revert to the default mod library */ void *Sys_LoadGameDll(const char *name, intptr_t(**entryPoint) (int, ...), intptr_t (*systemcalls)(intptr_t, ...)) { void *libHandle; void (*dllEntry)(intptr_t (*syscallptr)(intptr_t, ...)); char fname[MAX_OSPATH]; char *basepath; char *homepath; char *gamedir; assert(name); Com_sprintf(fname, sizeof(fname), Sys_GetDLLName("%s"), name); // TODO: use fs_searchpaths from files.c basepath = Cvar_VariableString("fs_basepath"); homepath = Cvar_VariableString("fs_homepath"); gamedir = Cvar_VariableString("fs_game"); #ifndef DEDICATED // if the server is pure, extract the dlls from the mod_bin.pk3 so // that they can be referenced if (Cvar_VariableValue("sv_pure") && Q_stricmp(name, "qagame")) { Com_Printf("Sys_LoadGameDll -> FS_CL_ExtractFromPakFile(%s, %s, %s)\n", homepath, gamedir, fname); FS_CL_ExtractFromPakFile(homepath, gamedir, fname); } #endif libHandle = Sys_TryLibraryLoad(homepath, gamedir, fname); if (!libHandle && basepath) { libHandle = Sys_TryLibraryLoad(basepath, gamedir, fname); } #ifndef DEDICATED // According to the code above, if the server is not pure, then the // lib must either already be in the homepath, or in the basepath, // without being in a pak. For a pure server, it always grabs the lib // from within a pak. This means there must be two copies of the lib! // // So now, if connecting to an impure server, and the lib was not // loaded from homepath or the basepath, let's pull it out of the pak. // This means we only *need* the copy that's in the pak, and will use // it if another copy isn't found first. if (!libHandle && !Cvar_VariableValue("sv_pure") && Q_stricmp(name, "qagame")) { Com_Printf("Sys_LoadGameDll -> FS_CL_ExtractFromPakFile(%s, %s, %s)\n", homepath, gamedir, fname); FS_CL_ExtractFromPakFile(homepath, gamedir, fname); libHandle = Sys_TryLibraryLoad(homepath, gamedir, fname); } #endif // HACK: sometimes a library is loaded from the mod dir when it shouldn't. Why? if (!libHandle && strcmp(gamedir, DEFAULT_MODGAME)) { Com_Printf("Sys_LoadDll: failed to load the mod library. Trying to revert to the default one.\n"); libHandle = Sys_TryLibraryLoad(basepath, DEFAULT_MODGAME, fname); } if (!libHandle) { Com_Printf("Sys_LoadDll(%s) failed to load library\n", name); return NULL; } dllEntry = (void (QDECL *)(intptr_t (QDECL *)(intptr_t, ...)))Sys_LoadFunction(libHandle, "dllEntry"); *entryPoint = (intptr_t (QDECL *)(int, ...))Sys_LoadFunction(libHandle, "vmMain"); if (!*entryPoint || !dllEntry) { Com_Printf("Sys_LoadDll(%s) failed to find vmMain function:\n\"%s\" !\n", name, Sys_LibraryError()); Sys_UnloadLibrary(libHandle); return NULL; } Com_Printf("Sys_LoadDll(%s) found vmMain function at %p\n", name, *entryPoint); dllEntry(systemcalls); return libHandle; }
/** * @brief Loads a mod library. * #1 look in fs_homepath * #2 look in fs_basepath * #3 try to revert to the default mod library */ void *Sys_LoadGameDll(const char *name, qboolean extract, intptr_t(**entryPoint) (int, ...), intptr_t (*systemcalls)(intptr_t, ...)) { void *libHandle; void (*dllEntry)(intptr_t (*syscallptr)(intptr_t, ...)); char fname[MAX_OSPATH]; char *basepath; char *homepath; char *gamedir; assert(name); Com_sprintf(fname, sizeof(fname), Sys_GetDLLName("%s"), name); // TODO: use fs_searchpaths from files.c basepath = Cvar_VariableString("fs_basepath"); homepath = Cvar_VariableString("fs_homepath"); gamedir = Cvar_VariableString("fs_game"); // STORY TIME // //When doing an debug build just load the mod lib from the basepath as that will have the debug pointers // // Now the code always just unpacks new libraries from the packs on release builds. // So the libraryfiles in the homepath are always refreshed with latest from the packs. // This fixes many issues with clients loading old libraries from the mod paths. // // The way it used to work is described under (or in debug mode).. // // if the server is pure, extract the dlls from the mod_bin.pk3 so // that they can be referenced // // If the server is not pure, then the // lib must either already be in the homepath, or in the basepath, // without being in a pak. For a pure server, it always grabs the lib // from within a pak. This means there must be two copies of the lib! // // So now, if connecting to an impure server, and the lib was not // loaded from homepath or the basepath, let's pull it out of the pak. // This means we only *need* the copy that's in the pak, and will use // it if another copy isn't found first. #ifdef LEGACY_DEBUG #define SEARCHPATH1 basepath #define SEARCHPATH2 homepath #define LIB_DO_UNPACK Cvar_VariableIntegerValue("sv_pure") #else #define LIB_DO_UNPACK qtrue #define SEARCHPATH1 homepath #define SEARCHPATH2 basepath #endif #ifndef DEDICATED if (LIB_DO_UNPACK && extract) { Com_Printf("Sys_LoadGameDll -> FS_CL_ExtractFromPakFile(%s, %s, %s)\n", homepath, gamedir, fname); FS_CL_ExtractFromPakFile(homepath, gamedir, fname); } #endif libHandle = Sys_TryLibraryLoad(SEARCHPATH1, gamedir, fname); if (!libHandle && SEARCHPATH2) { libHandle = Sys_TryLibraryLoad(SEARCHPATH2, gamedir, fname); } #ifndef DEDICATED if (!libHandle && !LIB_DO_UNPACK && extract) { Com_Printf("Sys_LoadGameDll -> FS_CL_ExtractFromPakFile(%s, %s, %s)\n", homepath, gamedir, fname); FS_CL_ExtractFromPakFile(homepath, gamedir, fname); libHandle = Sys_TryLibraryLoad(homepath, gamedir, fname); } #endif if (!libHandle) { Com_Printf("Sys_LoadDll(%s/%s) failed to load library\n", gamedir, name); return NULL; } dllEntry = (void (QDECL *)(intptr_t (QDECL *)(intptr_t, ...)))Sys_LoadFunction(libHandle, "dllEntry"); *entryPoint = (intptr_t (QDECL *)(int, ...))Sys_LoadFunction(libHandle, "vmMain"); if (!*entryPoint || !dllEntry) { Com_Printf("Sys_LoadDll(%s/%s) failed to find vmMain function:\n\"%s\" !\n", gamedir, name, Sys_LibraryError()); Sys_UnloadLibrary(libHandle); return NULL; } Com_Printf("Sys_LoadDll(%s/%s) found vmMain function at %p\n", gamedir, name, *entryPoint); dllEntry(systemcalls); return libHandle; }
/* ================= Sys_LoadDll Used to load a development dll instead of a virtual machine #1 look in fs_homepath #2 look in fs_basepath #4 look in fs_libpath under FreeBSD ================= */ void *QDECL Sys_LoadDll( const char *name, char *fqpath, intptr_t (QDECL **entryPoint)(int, ...), intptr_t (QDECL *systemcalls)(intptr_t, ...) ) { void *libHandle = NULL, (QDECL *dllEntry)( intptr_t (QDECL *syscallptr)(intptr_t, ...) ); char fname[MAX_QPATH], *basepath, *homepath, *gamedir, *libpath; assert( name ); //Q_snprintf (fname, sizeof(fname), Sys_GetDLLName( "%s" ), name); Q_strncpyz(fname, Sys_GetDLLName(name), sizeof(fname)); // TODO: use fs_searchpaths from files.c basepath = Cvar_VariableString( "fs_basepath" ); homepath = Cvar_VariableString( "fs_homepath" ); gamedir = Cvar_VariableString( "fs_game" ); libpath = Cvar_VariableString( "fs_libpath" ); #ifndef DEDICATED // if the server is pure, extract the dlls from the mp_bin.pk3 so // that they can be referenced if ( Cvar_VariableValue( "sv_pure" ) && Q_stricmp( name, "qagame" ) ) { FS_CL_ExtractFromPakFile( homepath, gamedir, fname ); } #endif libHandle = Sys_TryLibraryLoad(homepath, gamedir, fname, fqpath); if (!libHandle && libpath && libpath[0]) { libHandle = Sys_TryLibraryLoad(libpath, gamedir, fname, fqpath); } if(!libHandle && basepath) { libHandle = Sys_TryLibraryLoad(basepath, gamedir, fname, fqpath); } if(!libHandle) { Com_Printf( "Sys_LoadDll(%s) could not find it\n", fname ); return NULL; } if(!libHandle) { Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", name, Sys_LibraryError() ); return NULL; } // Try to load the dllEntry and vmMain function. dllEntry = ( void ( QDECL * )( intptr_t ( QDECL * )( intptr_t, ... ) ) )Sys_LoadFunction( libHandle, "dllEntry" ); *entryPoint = ( intptr_t ( QDECL * )( int,... ) )Sys_LoadFunction( libHandle, "vmMain" ); if ( !*entryPoint || !dllEntry ) { #ifndef NDEBUG if (!dllEntry) { Com_Error ( ERR_FATAL, "Sys_LoadDll(%s) failed SDL_LoadFunction(dllEntry):\n\"%p\" !\n", name, Sys_LibraryError() ); } else { Com_Error ( ERR_FATAL, "Sys_LoadDll(%s) failed SDL_LoadFunction(vmMain):\n\"%p\" !\n", name, Sys_LibraryError() ); } #else if (!dllEntry) { Com_Printf ( "Sys_LoadDll(%s) failed SDL_LoadFunction(dllEntry):\n\"%p\" !\n", name, Sys_LibraryError() ); } else { Com_Printf ( "Sys_LoadDll(%s) failed SDL_LoadFunction(vmMain):\n\"%p\" !\n", name, Sys_LibraryError() ); } #endif Sys_UnloadLibrary(libHandle); return NULL; } Com_Printf ( "Sys_LoadDll(%s) found vmMain function at %p\n", name, *entryPoint ); dllEntry( systemcalls ); Com_Printf ( "Sys_LoadDll(%s) succeeded!\n", name ); // Copy the fname to fqpath. Q_strncpyz ( fqpath , fname , MAX_QPATH ) ; return libHandle; }
/** * @brief Loads a mod library. * #1 look in fs_homepath * #2 look in fs_basepath * #3 try to revert to the default mod library */ void *Sys_LoadDll(const char *name, intptr_t(**entryPoint) (int, ...), intptr_t (*systemcalls)(intptr_t, ...)) { void *libHandle; void (*dllEntry)(intptr_t (*syscallptr)(intptr_t, ...)); char fname[MAX_OSPATH]; char *basepath; char *homepath; char *gamedir; assert(name); Com_sprintf(fname, sizeof(fname), Sys_GetDLLName("%s"), name); // TODO: use fs_searchpaths from files.c basepath = Cvar_VariableString("fs_basepath"); homepath = Cvar_VariableString("fs_homepath"); gamedir = Cvar_VariableString("fs_game"); #ifndef DEDICATED // if the server is pure, extract the dlls from the mp_bin.pk3 so // that they can be referenced if (Cvar_VariableValue("sv_pure") && Q_stricmp(name, "qagame")) { FS_CL_ExtractFromPakFile(homepath, gamedir, fname); } #endif libHandle = Sys_TryLibraryLoad(homepath, gamedir, fname); if (!libHandle && basepath) { libHandle = Sys_TryLibraryLoad(basepath, gamedir, fname); } // HACK: sometimes a library is loaded from the mod dir when it shouldn't. Why? if (!libHandle && strcmp(gamedir, DEFAULT_MODGAME)) { Com_Printf("Sys_LoadDll: failed to load the mod library. Trying to revert to the default one.\n"); libHandle = Sys_TryLibraryLoad(basepath, DEFAULT_MODGAME, fname); } if (!libHandle) { Com_Printf("Sys_LoadDll(%s) failed to load library\n", name); return NULL; } dllEntry = (void (QDECL *)(intptr_t (QDECL *)(intptr_t, ...)))Sys_LoadFunction(libHandle, "dllEntry"); *entryPoint = (intptr_t (QDECL *)(int, ...))Sys_LoadFunction(libHandle, "vmMain"); if (!*entryPoint || !dllEntry) { Com_Printf("Sys_LoadDll(%s) failed to find vmMain function:\n\"%s\" !\n", name, Sys_LibraryError()); Sys_UnloadLibrary(libHandle); return NULL; } Com_Printf("Sys_LoadDll(%s) found vmMain function at %p\n", name, *entryPoint); dllEntry(systemcalls); return libHandle; }
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; }