/* ** Copyright (C) 2001-2007 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ /* ** dynlib - glue code between a run-time dynamic library and an ** application. See dynlib.h for the details. */ #include "silk.h" RCSIDENT("$SiLK: dynlib.c 7646 2007-06-26 17:08:21Z mthomas $"); #include #include "utils.h" #include "dynlib.h" /* Length of dlerror() message we cache */ #define DYNLIB_DLERR_LENGTH 2048 /* Name of envar that if set will enable debugging output */ #define DYNLIB_DEBUG_ENVAR "SILK_DYNLIB_DEBUG" /* * Representation for a symbol name (i.e., a function) in the dynlib * or plugin. id is a unique integer for the symbol, name is a string * representing the symbol, must_exist is non-zero if the plugin must * have a the the named symbol. */ typedef struct { dynlibSymbolId id; int8_t must_exist; char *name; } dynlib_symbol_t; static const dynlib_symbol_t dynlib_sym[] = { {DYNLIB_SETUP, 1, "setup"}, {DYNLIB_TEARDOWN, 1, "teardown"}, {DYNLIB_VERSION, 0, "dynlib_api_version"}, {DYNLIB_CONFIGURE, 0, "configure"}, {DYNLIB_INITIALIZE, 0, "initialize"}, {DYNLIB_OPT_USAGE, 0, "optionsUsage"}, {DYNLIB_EXCL_FILTER, 0, "check"}, {DYNLIB_SHAR_FILTER, 0, "filter"}, {DYNLIB_CUT, 0, "cut"}, {DYNLIB_SORT, 0, "sort"}, {DYNLIB_UNIQ, 0, "uniq"}, {DYNLIB_PTOFLOW, 0, "ptoflow"}, {DYNLIB_VOID, 0, NULL} /* sentinel */ }; struct _dynlibInfoStruct { /* path to .so file */ char *dlPath; /* most recent value of dlerror() */ char dlLastError[DYNLIB_DLERR_LENGTH]; /* handle returned by dlopen */ void *dlHandle; /* application state (name, options) */ skAppContext_t *app_context; /* one of failed/will|wont process */ int dlStatus; /* non-zero if this dynlib should be called */ int dlActive; /* 1 to not call dlclose()--Oracle issue */ int dlDoNotClose; /* 1 if the initialized() routine was called */ int dlInitialized; /* type of application or library */ dynlibSymbolId dlType; /* function pointers */ dynlib_fn_t func[1+DYNLIB_VOID-DYNLIB_SETUP]; }; /* This variable is 1 to print debugging output, 0 to not debug, -1 if * the above envar is not yet checked */ static int dynlibDebug = -1; /* Function to call to open streams. Applications may set this. */ static open_data_input_fn_t open_data_input_fn; /* Copy the last dlerror() info the dlISP */ #define dynlibCacheError(dlISP) \ {strncpy((dlISP)->dlLastError, dlerror(), DYNLIB_DLERR_LENGTH-1); \ (dlISP)->dlLastError[DYNLIB_DLERR_LENGTH-1] = '\0';} /* Return path to the plug-in */ const char *dynlibGetPath(const dynlibInfoStruct_t *dlISP) { return (dlISP->dlPath); } /* Return 1 if dlISP was successfully loaded */ int dynlibCheckLoaded(const dynlibInfoStruct_t *dlISP) { return ((NULL != dlISP) && (NULL != dlISP->dlPath)); } /* Return the AppType */ dynlibSymbolId dynlibGetAppType(const dynlibInfoStruct_t *dlISP) { return (dlISP->dlType); } /* Return status from the dynlibLoad() call (ie, return from setup()) */ int dynlibGetStatus(const dynlibInfoStruct_t *dlISP) { return (dlISP->dlStatus); } /* Return application context */ skAppContext_t *dynlibGetAppContext(const dynlibInfoStruct_t *dlISP) { return (dlISP->app_context); } /* Return the active flag */ int dynlibCheckActive(const dynlibInfoStruct_t *dlISP) { return ((NULL == dlISP) ? 0 : (dlISP->dlActive)); } /* Set the active flag */ void dynlibMakeActive(dynlibInfoStruct_t *dlISP) { dlISP->dlActive = 1; } /* Clear the initialized-was-called flag */ void dynlibClearInitialized(dynlibInfoStruct_t *dlISP) { dlISP->dlInitialized = 0; } /* Set the do-no-close flag */ void dynlibSetDoNotClose(dynlibInfoStruct_t *dlISP) { dlISP->dlDoNotClose = 1; } /* Return last error message */ const char *dynlibLastError(const dynlibInfoStruct_t *dlISP) { return (dlISP->dlLastError); } /* Create and open a stream to process 'filename'. */ int dynlibOpenDataInputStream( skstream_t **stream, skcontent_t content_type, const char *filename) { int rv; assert(stream); assert(filename); if (open_data_input_fn) { return open_data_input_fn(stream, content_type, filename); } if ((rv = (skStreamCreate(stream, SK_IO_READ, content_type))) || (rv = skStreamBind((*stream), filename)) || (rv = skStreamOpen(*stream))) { skStreamPrintLastErr((*stream), rv, &skAppPrintErr); skStreamDestroy(stream); return -1; } return 0; } /* Set function that dynlibOpenDataInputStream() uses. */ void dynlibSetOpenInputFunction(open_data_input_fn_t open_fn) { open_data_input_fn = open_fn; } /* Return 1 if the named envar is defined in the environment and has a * non-empty value; 0 otherwise */ static int dynlibCheckDebugEnvar(const char *env_name) { char *env_value; env_value = getenv(env_name); if ((NULL != env_value) && ('\0' != env_value[0])) { return 1; } return 0; } /* Create the data structure pointer */ dynlibInfoStruct_t *dynlibCreate(dynlibSymbolId appType) { dynlibInfoStruct_t *dlISP; /* Check the envar if we haven't */ if (dynlibDebug < 0) { dynlibDebug = dynlibCheckDebugEnvar(DYNLIB_DEBUG_ENVAR); } /* Create the dlISP */ dlISP = calloc(1, sizeof(dynlibInfoStruct_t)); if (dlISP != NULL) { dlISP->dlType = appType; } return dlISP; } /* Load library; call its setup()--which should register options--and * set dlStatus to the return value of setup() */ int dynlibLoad(dynlibInfoStruct_t *dlISP, const char *dlPath) { int i; int version; const char *name; char pluginPath[PATH_MAX+1]; /* check input */ if (dlISP == NULL || dlPath == NULL) { return 1; } /* Attempt to find the full path to the plug-in, and set * 'pluginPath' to its path; if we cannot find the path, copy the * plug-in's name to 'pluginPath' and we'll let dlopen() handle * finding the plug-in. */ if ( !skutilsFindPluginPath(dlPath, pluginPath, PATH_MAX, dynlibDebug)) { strncpy(pluginPath, dlPath, PATH_MAX); pluginPath[PATH_MAX] = '\0'; } /* try to dlopen() the plug-in */ if (dynlibDebug > 0) { skAppPrintErr("SILK_DYNLIB_DEBUG: dlopen'ing '%s'", pluginPath); } dlISP->dlHandle = dlopen(pluginPath, RTLD_NOW); if (!dlISP->dlHandle) { dynlibCacheError(dlISP); if (dynlibDebug > 0) { skAppPrintErr("SILK_DYNLIB_DEBEG: dlopen warning: %s", dynlibLastError(dlISP)); } return 1; } if (dynlibDebug > 0) { skAppPrintErr("SILK_DYNLIB_DEBUG: dlopen() successful"); } /* Verify existence of functions in the plugin: we must be able to * find every entry in the 'dynlib_sym' array with a non-zero * value for 'must_exist', and we must have the function for this * app-type. */ for (i = 0; dynlib_sym[i].id != DYNLIB_VOID; ++i) { /* lookup function */ name = dynlib_sym[i].name; dlISP->func[dynlib_sym[i].id] = (dynlib_fn_t)dlsym(dlISP->dlHandle,name); /* if symbol was found, everything is good; goto next symbol */ if (NULL != dlISP->func[dynlib_sym[i].id]) { continue; } if (dynlibDebug > 0) { skAppPrintErr("SILK_DYNLIB_DEBUG: function %s not found", name); } if (dynlib_sym[i].must_exist || dynlib_sym[i].id == dlISP->dlType) { /* if we expect 'filter' but we have 'check', use it. */ if ((dlISP->dlType == DYNLIB_SHAR_FILTER) && (NULL != dlISP->func[DYNLIB_EXCL_FILTER])) { dlISP->func[DYNLIB_SHAR_FILTER] = dlISP->func[DYNLIB_EXCL_FILTER]; continue; } dynlibCacheError(dlISP); skAppPrintErr("dynlib: error finding symbol '%s' in %s: %s", name, pluginPath, dynlibLastError(dlISP)); return 1; } } /* Warn if both 'filter' and 'check' are defined. */ if (((dlISP->dlType == DYNLIB_EXCL_FILTER) || (dlISP->dlType == DYNLIB_SHAR_FILTER)) && dlISP->func[DYNLIB_EXCL_FILTER] && dlISP->func[DYNLIB_SHAR_FILTER] && dlISP->func[DYNLIB_EXCL_FILTER] != dlISP->func[DYNLIB_SHAR_FILTER]) { skAppPrintErr(("dynlib warning: plugin '%s' defines both\n" "\t'%s' and '%s' functions. Using '%s'"), pluginPath, dynlib_sym[DYNLIB_SHAR_FILTER].name, dynlib_sym[DYNLIB_EXCL_FILTER].name, dynlib_sym[dlISP->dlType].name); } /* Set the application context; setup() may use this */ dlISP->app_context = skAppContextGet(); /* call the plug-in's version() func */ if (NULL != dlISP->func[DYNLIB_VERSION]) { version = (*dlISP->func[DYNLIB_VERSION])(); if (version != DYNLIB_API_VERSION) { skAppPrintErr("version mismatch between plugin %s and application", pluginPath); return 1; } } /* call the plug-in's setup() func */ dlISP->dlStatus = (*(dlISP->func[DYNLIB_SETUP]))(dlISP, dlISP->dlType); if (DYNLIB_FAILED == dlISP->dlStatus) { if (dynlibDebug > 0) { skAppPrintErr("dynlib: setup() for %s returned FAILED", pluginPath); } return 1; } if (NULL == (dlISP->dlPath = strdup(pluginPath))) { skAppPrintErr("dynlib: out of memory at %s:%d!", __FILE__, __LINE__); return 1; } /* all OK */ return 0; } /* Call the configure() function on the plugin */ int dynlibConfigure(dynlibInfoStruct_t *dlISP, void *data) { if (NULL == dlISP->func[DYNLIB_CONFIGURE]) { /* function does not exist */ return 0; } /* Call plug-in's configure() function */ return (*(dlISP->func[DYNLIB_CONFIGURE]))(dlISP, data); } /* Call the dynamic library's initialize() routine to do any * "expensive" initialization */ int dynlibInitialize(dynlibInfoStruct_t *dlISP) { int status = 0; if (dlISP->dlInitialized) { /* Been here before */ return status; } if (dlISP->func[DYNLIB_INITIALIZE]) { /* Call plugin's initialize() function */ status = (*(dlISP->func[DYNLIB_INITIALIZE]))(dlISP, dlISP->dlType); } if (0 == status) { /* Either initialize() returned o.k., or there was no initialize() * function to call */ dlISP->dlInitialized = 1; } return status; } /* Print to 'fh' the usage for this dynamic library */ void dynlibOptionsUsage(dynlibInfoStruct_t *dlISP, FILE *fh) { if (dlISP->func[DYNLIB_OPT_USAGE]) { (*(dlISP->func[DYNLIB_OPT_USAGE]))(dlISP->dlType, fh); } } /* Get the processing function, caller should check dlActive first */ dynlib_fn_t dynlibGetRWProcessor(dynlibInfoStruct_t *dlISP) { return (dynlib_fn_t)dlISP->func[dlISP->dlType]; } /* Call the dynlib's teardown() method; free memory */ void dynlibTeardown(dynlibInfoStruct_t *dlISP) { if (!dlISP) { return; } if (dlISP->dlDoNotClose) { return; } if (dlISP->dlPath) { (dlISP->func[DYNLIB_TEARDOWN])(dlISP->dlType); dlclose(dlISP->dlHandle); free(dlISP->dlPath); dlISP->dlPath = (char *)NULL; } free(dlISP); dlISP = NULL; return; } /* ** Local Variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */