Fixed parsing of explicit module init symbol
/*
* The contents of this file are subject to the AOLserver Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://aolserver.com/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is AOLserver Code and related documentation
* distributed by AOL.
*
* The Initial Developer of the Original Code is America Online,
* Inc. Portions created by AOL are Copyright (C) 1999 America Online,
* Inc. All Rights Reserved.
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License (the "GPL"), in which case the
* provisions of GPL are applicable instead of those above. If you wish
* to allow use of your version of this file only under the terms of the
* GPL and not to allow others to use your version of this file under the
* License, indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by the GPL.
* If you do not delete the provisions above, a recipient may use your
* version of this file under either the License or the GPL.
*/
/*
* modload.c --
*
* Load .so files into the server and initialize them.
*/
static const char *RCSID = "@(#) $Header: /cvsroot/aolserver/aolserver/nsd/modload.c,v 1.16 2003/04/16 20:20:21 mpagenva Exp $, compiled: " __DATE__ " " __TIME__;
#include "nsd.h"
#if defined(USE_DLSHL)
#include <dl.h>
#elif defined(USE_DYLD)
#include <mach-o/dyld.h>
static char *dylderr = "";
#elif !defined(_WIN32)
#include <dlfcn.h>
#ifdef USE_RTLD_LAZY
#ifdef RTLD_NOW
#undef RTLD_NOW
#endif
#define RTLD_NOW RTLD_LAZY
#endif
#ifndef RTLD_GLOBAL
#define RTLD_GLOBAL 0
#endif
#ifndef RTLD_NOW
#define RTLD_NOW 0
#endif
#endif
/*
* The following structure is used for static module loading.
*/
typedef struct Module {
struct Module *nextPtr;
char *name;
Ns_ModuleInitProc *proc;
} Module;
/*
* Static variables defined in this file.
*/
static Tcl_HashTable modulesTable;
static void *DlOpen(char *file);
static void *DlSym(void *handle, char *name);
static void *DlSym2(void *handle, char *name);
static char *DlError(void);
static Module *firstPtr;
/*
*----------------------------------------------------------------------
*
* NsInitModLoad --
*
* Initialize module table.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
NsInitModLoad(void)
{
#ifdef _WIN32
Tcl_InitHashTable(&modulesTable, TCL_STRING_KEYS);
#else
Tcl_InitHashTable(&modulesTable, FILE_KEYS);
#endif
}
/*
*----------------------------------------------------------------------
*
* Ns_RegisterModule --
*
* Register a static module. This routine can only be called from
* a Ns_ServerInitProc passed to Ns_Main or within the Ns_ModuleInit
* proc of a loadable module. It registers a module callback for
* for the currently initializing server.
*
* Results:
* None.
*
* Side effects:
* Proc will be called after dynamic modules are loaded.
*
*----------------------------------------------------------------------
*/
void
Ns_RegisterModule(char *name, Ns_ModuleInitProc *proc)
{
Module *modPtr, **nextPtrPtr;
modPtr = ns_malloc(sizeof(Module));
modPtr->name = ns_strcopy(name);
modPtr->proc = proc;
modPtr->nextPtr = NULL;
nextPtrPtr = &firstPtr;
while (*nextPtrPtr != NULL) {
nextPtrPtr = &((*nextPtrPtr)->nextPtr);
}
*nextPtrPtr = modPtr;
}
/*
*----------------------------------------------------------------------
*
* Ns_ModuleLoad --
*
* Load a module and initialize it. The result code from modules
* without the version symbol are ignored.
*
* Results:
* NS_OK or NS_ERROR
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Ns_ModuleLoad(char *server, char *module, char *file, char *init)
{
Ns_ModuleInitProc *initProc;
int status = NS_OK;
int *verPtr;
initProc = Ns_ModuleSymbol(file, init);
if (initProc == NULL) {
return NS_ERROR;
}
verPtr = Ns_ModuleSymbol(file, "Ns_ModuleVersion");
status = (*initProc) (server, module);
if (verPtr == NULL || *verPtr < 1) {
status = NS_OK;
} else if (status != NS_OK) {
Ns_Log(Error, "modload: init %s of %s returned: %d", file, init, status);
}
return status;
}
/*
*----------------------------------------------------------------------
*
* Ns_ModuleSymbol --
*
* Load a module if it's not already loaded, and extract a
* requested symbol from it.
*
* Results:
* A pointer to the symbol's value.
*
* Side effects:
* May load the module if it hasn't been loaded yet.
*
*----------------------------------------------------------------------
*/
void *
Ns_ModuleSymbol(char *file, char *name)
{
Tcl_HashEntry *hPtr;
Ns_DString ds;
int new;
void *module;
void *symbol;
struct stat st;
#ifndef _WIN32
FileKey key;
#endif
symbol = NULL;
Ns_DStringInit(&ds);
if (!Ns_PathIsAbsolute(file)) {
file = Ns_HomePath(&ds, "bin", file, NULL);
}
if (stat(file, &st) != 0) {
Ns_Log(Notice, "modload: stat(%s) failed: %s", file, strerror(errno));
goto done;
}
#ifdef _WIN32
hPtr = Tcl_CreateHashEntry(&modulesTable, file, &new);
#else
key.dev = st.st_dev;
key.ino = st.st_ino;
hPtr = Tcl_CreateHashEntry(&modulesTable, (char *) &key, &new);
#endif
if (!new) {
module = Tcl_GetHashValue(hPtr);
} else {
Ns_Log(Notice, "modload: loading '%s'", file);
module = DlOpen(file);
if (module == NULL) {
Ns_Log(Warning, "modload: could not load %s: %s", file, DlError());
Tcl_DeleteHashEntry(hPtr);
goto done;
}
Tcl_SetHashValue(hPtr, module);
}
symbol = DlSym(module, name);
if (symbol == NULL) {
Ns_Log(Warning, "modload: could not find %s in %s", name, file);
}
done:
Ns_DStringFree(&ds);
return symbol;
}
/*
*----------------------------------------------------------------------
*
* Ns_ModuleGetSymbol --
*
* Locate a given symbol in the program's symbol table and
* return the address of it. This differs from the other Module
* functions in that it doesn't require the shared library file
* name - this should sniff the entire symbol space.
*
* Results:
* A pointer to the requested symbol's value.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void *
Ns_ModuleGetSymbol(char *name)
{
return DlSym(NULL, name);
}
/*
*----------------------------------------------------------------------
*
* NsLoadModules --
*
* Load all modules for given server.
*
* Results:
* None.
*
* Side effects:
* Will load and initialize modules.
*
*----------------------------------------------------------------------
*/
void
NsLoadModules(char *server)
{
Ns_Set *modules;
int i;
char *file, *module, *init = NULL, *s, *e = NULL;
Module *modPtr, *nextPtr;
modules = Ns_ConfigGetSection(Ns_ConfigGetPath(server, NULL, "modules", NULL));
for (i = 0; modules != NULL && i < Ns_SetSize(modules); ++i) {
module = Ns_SetKey(modules, i);
file = Ns_SetValue(modules, i);
/*
* Check for specific module init after filename.
*/
s = strchr(file, '(');
if (s == NULL) {
init = "Ns_ModuleInit";
} else {
*s = '\0';
init = s + 1;
e = strchr(init, ')');
if (e != NULL) {
*e = '\0';
}
}
/*
* Load the module if it's not the reserved "tcl" name.
*/
if (!STRIEQ(file, "tcl") && Ns_ModuleLoad(server, module, file, init) != NS_OK) {
Ns_Fatal("modload: failed to load module '%s'", file);
}
/*
* Add this module to the server Tcl init list.
*/
Ns_TclInitModule(server, module);
if (s != NULL) {
*s = '(';
if (e != NULL) {
*e = ')';
}
}
}
/*
* Initialize the static modules (if any). Note that a static
* module could add a new static module and so the loop is
* repeated until they're all gone.
*/
while (firstPtr != NULL) {
modPtr = firstPtr;
firstPtr = NULL;
while (modPtr != NULL) {
nextPtr = modPtr->nextPtr;
Ns_Log(Notice, "modload: initializing module '%s'", modPtr->name);
if ((*modPtr->proc)(server, modPtr->name) != NS_OK) {
Ns_Fatal("modload: failed to initialize %s", modPtr->name);
}
ns_free(modPtr->name);
ns_free(modPtr);
modPtr = nextPtr;
}
}
}
/*
*----------------------------------------------------------------------
*
* DlOpen --
*
* Load a dynamic library
*
* Results:
* An Ns_ModHandle, or NULL on failure.
*
* Side effects:
* See shl_load
*
*----------------------------------------------------------------------
*/
static void *
DlOpen(char *file)
{
#if defined(USE_DYLD)
int retry;
NSObjectFileImage image;
NSModule module;
NSObjectFileImageReturnCode err;
module = NULL;
retry = 0;
err = NSCreateObjectFileImageFromFile(file, &image);
switch (err) {
case NSObjectFileImageSuccess:
module = NSLinkModule(image, file, TRUE);
break;
case NSObjectFileImageInappropriateFile:
dylderr = "Inappropriate Mach-O file";
retry = 1;
break;
case NSObjectFileImageArch:
dylderr = "Inappropriate Mach-O architecture";
break;
case NSObjectFileImageFormat:
dylderr = "Invalid Mach-O file format";
retry = 1;
break;
case NSObjectFileImageAccess:
dylderr = "Permission denied";
break;
default:
dylderr = "Unknown error";
break;
}
if (retry) {
/*
* Fallback to open shared library.
*/
module = (void *)NSAddImage(file,
NSADDIMAGE_OPTION_WITH_SEARCHING |
NSADDIMAGE_OPTION_RETURN_ON_ERROR);
}
return (void *) module;
#elif defined(_WIN32)
return (void *) LoadLibrary(file);
#elif defined(USE_DLSHL)
return (void *) shl_load(file, BIND_VERBOSE|BIND_IMMEDIATE|BIND_RESTRICTED, 0);
#else
return dlopen(file, RTLD_NOW|RTLD_GLOBAL);
#endif
}
/*
*----------------------------------------------------------------------
*
* DlSym --
*
* Load a symbol from a shared object
*
* Results:
* A symbol pointer or null on error.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void *
DlSym(void *handle, char *name)
{
Ns_DString ds;
void *symbol;
symbol = DlSym2(handle, name);
if (symbol == NULL) {
/*
* Some BSD platforms (e.g., OS/X) prepend an underscore
* to all symbols.
*/
Ns_DStringInit(&ds);
Ns_DStringVarAppend(&ds, "_", name, NULL);
symbol = DlSym2(handle, ds.string);
Ns_DStringFree(&ds);
}
return symbol;
}
static void *
DlSym2(void *handle, char *name)
{
void *symbol = NULL;
#if defined(USE_DLSHL)
if (shl_findsym((shl_t *) &handle, name, TYPE_UNDEFINED, &symbol) == -1) {
symbol = NULL;
}
#elif defined(_WIN32)
symbol = (void *) GetProcAddress((HMODULE) handle, name);
#elif (USE_DYLD)
symbol = (void *) NSLookupSymbolInModule(handle, name);
if (symbol == NULL) {
/*
* Fallback to get symbol from shared library
*/
symbol = (void *) NSLookupSymbolInImage(handle, name,
NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW |
NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
}
if (symbol != NULL) {
symbol = (void *) NSAddressOfSymbol(symbol);
}
#else
symbol = dlsym(handle, name);
#endif
return symbol;
}
/*
*----------------------------------------------------------------------
*
* DlError --
*
* Return the error code from trying to load a shared object
*
* Results:
* A string error.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static char *
DlError(void)
{
#if defined(USE_DLSHL)
return strerror(errno);
#elif defined(_WIN32)
return NsWin32ErrMsg(GetLastError());
#elif defined(USE_DYLD)
return dylderr;
#else
return (char *) dlerror();
#endif
}
|
Back to SourceForge.net Powered by ViewCVS 1.0-dev |