#ifndef __XRDSYSPLUGIN__
#define __XRDSYSPLUGIN__
/******************************************************************************/
/* */
/* X r d S y s P l u g i n . h h */
/* */
/* (c) 2005 by the Board of Trustees of the Leland Stanford, Jr., University */
/* All Rights Reserved */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include
struct XrdVersionInfo;
class XrdSysError;
//------------------------------------------------------------------------------
//! Handy class to load run-time plugins and optionally check if the version
//! is compatible with the caller's version number. Version numbers are defined
//! as "aaa.bb.cc" where aaa is a decimnal major version, bb is a decimal minor
//! version, and cc is the decimal patch version number. Only the major and,
//! optionally, minor version numbers are checked. The checking rules are
//! defined in XrdVersion.hh and are rather liberal in nature. In order to
//! check versions, the plugin versioning rule must be defined in XrdVersion.hh
//! and constructor #2 or #3 must be used. The symbolic name of the plugin's
//! version information is the plugin symbol being looked up appended with
//! "Version" and must be defined as an XrdVersionInfo structure.
//------------------------------------------------------------------------------
class XrdSysPlugin
{
public:
//------------------------------------------------------------------------------
//! Prepare shared library for use (optional call).
//!
//! @param allMsgs When true messages all messages are handled as directed by
//! the constructor. Otherwise, only messages regarding ENOENT
//! (file not found ) are suppressed.
//! @param global when true then the symbols defined in the plug-in shared
//! library are made available for symbol resolution of
//! subsequently loaded libraries.
//!
//! @return !0 Library successfully prepared.
//! =0 Library cannot be prepared; if mBuff is supplied, it
//! contains the error message. If the file was not found,
//! errno is set to ENOENT; otherwise to ENOEXEC.
//!
//! @note This method is implicitly called when calling getPlugin().
//------------------------------------------------------------------------------
void *getLibrary(bool allMsgs=true, bool global=false);
//------------------------------------------------------------------------------
//! Get the address of a plugin from a shared library, opening the plug-in
//! shared library if not already open. Symbols in the library are local.
//!
//! @param pname the plug-in extern "C" symbolic name
//! @param optional when 0 then issue error message when symbol isn't found.
//! Otherwise, the mising symbol is treated as an error.
//!
//! @return Success: the address of the symbol in the shared library/executable.
//! The address becomes invalid when this object is deleted
//! unless Persist() is called prior to deletion.
//! Failure: Null
//------------------------------------------------------------------------------
void *getPlugin(const char *pname, int optional=0);
//------------------------------------------------------------------------------
//! Get the address of a plugin from a shared library, opening the plug-in
//! shared library if not already open and optionally make the symbols global.
//!
//! @param pname the plug-in extern "C" symbolic name
//! @param optional when 0 then issue error message when symbol isn't found.
//! Otherwise, the mising symbol is treated as an error. When
//! optional is greater than 1, the load message is suppressed.
//! @param global when true then the symbols defined in the plug-in shared
//! library are made available for symbol resolution of
//! subsequently loaded libraries.
//! @return Success: the address of the symbol in the shared library/executable.
//! The address becomes invalid when this object is deleted
//! unless Persist() is called prior to deletion.
//! Failure: Null
//------------------------------------------------------------------------------
void *getPlugin(const char *pname, int optional, bool global);
//------------------------------------------------------------------------------
//! Make library persistent even when the plugin object is deleted. Note that
//! if getPlugin() is called afterwards, the library will be re-opened!
//!
//! @return pointer to the opened shared library.
//------------------------------------------------------------------------------
void *Persist() {void *lHan = libHandle; libHandle = 0; return lHan;}
//------------------------------------------------------------------------------
//! Preload a shared library. This method is meant for those threading models
//! that require libraries to be opened in the main thread (e.g. MacOS). This
//! method is meant to be called before therads start and is not thread-safe.
//!
//! @param path -> to the library path, typically this should just be the
//! library filename so that LD_LIBRARY_PATH is used to
//! discover the directory path. This allows getPlugin()
//! to properly match preloaded libraries.
//! @param ebuff -> buffer where eror message is to be placed. The message
//! will always end with a null byte. If no error buffer
//! is supplied, any error messages are discarded.
//! @param eblen -> length of the supplied buffer, eBuff.
//!
//! @return True The library was preloaded.
//! False The library could not be preloaded, ebuff, if supplied,
//! contains the error message text.
//------------------------------------------------------------------------------
static
bool Preload(const char *path, char *ebuff=0, int eblen=0);
//------------------------------------------------------------------------------
//! Compare two versions for compatibility, optionally printing a warning.
//!
//! @param vInf1 -> Version information for source.
//! @param vInf2 -> Version information for target.
//! @param noMsg -> If true, no error messages are written to stderr.
//!
//! @return True if versions are compatible (i.e. major and minor versions are
//! identical as required for locally linked code); false otherwise.
//------------------------------------------------------------------------------
static
bool VerCmp(XrdVersionInfo &vInf1, XrdVersionInfo &vInf2, bool noMsg=false);
//------------------------------------------------------------------------------
//! Constructor #1 (version number checking is not to be performed)
//!
//! @param erp -> error message object to display error messages.
//! @param path -> path to the shared library containing a plug-in. If NULL
//! the the executable image is searched for the plug-in.
//! Storage must persist while this object is alive.
//------------------------------------------------------------------------------
XrdSysPlugin(XrdSysError *erp, const char *path)
: eDest(erp), libName(0), libPath(path ? strdup(path) : 0),
libHandle(0), myInfo(0), eBuff(0), eBLen(0), msgCnt(-1) {}
//------------------------------------------------------------------------------
//! Constructor #2 (version number checking may be performed)
//!
//! @param erp -> error message object to display error messages.
//! @param path -> path to the shared library containing a plug-in. If NULL
//! the the executable image is searched for the plug-in.
//! Storage must persist while this object is alive.
//! @param lname -> logical name of the plugin library (e.g. osslib) to be
//! used in any error messages.
//! Storage must persist while this object is alive.
//! @param vinf -> permanent version information of the plug-in loader.
//! If zero, then no version checking is performed.
//! @param msgNum -> Number of times getPlugin() is to produce a version
//! message for a loaded plugin. The default is always.
//------------------------------------------------------------------------------
XrdSysPlugin(XrdSysError *erp, const char *path, const char *lname,
XrdVersionInfo *vinf=0, int msgNum=-1)
: eDest(erp), libName(lname),
libPath(path ? strdup(path) : 0), libHandle(0),
myInfo(vinf), eBuff(0), eBLen(0), msgCnt(msgNum) {}
//------------------------------------------------------------------------------
//! Constructor #3 (version number checking may be performed and any error
//! is returned in a supplied buffer)
//!
//! @param ebuff -> buffer where eror message is to be placed. The message
//! will always end with a null byte.
//! @param eblen -> length of the supplied buffer, eBuff.
//! @param path -> path to the shared library containing a plug-in. If NULL
//! the the executable image is searched for the plug-in.
//! Storage must persist while this object is alive.
//! @param lname -> logical name of the plugin library (e.g. osslib) to be
//! used in any error messages.
//! Storage must persist while this object is alive.
//! @param vinf -> permanent version information of the plug-in loader.
//! If Zero, then no version checking is performed.
//! @param msgNum -> Number of times getPlugin() is to produce a version
//! message for a loaded plugin. The default is always.
//------------------------------------------------------------------------------
XrdSysPlugin(char *ebuff, int eblen, const char *path, const char *lname,
XrdVersionInfo *vinf=0, int msgNum=-1)
: eDest(0), libName(lname),
libPath(path ? strdup(path) : 0), libHandle(0),
myInfo(vinf), eBuff(ebuff), eBLen(eblen), msgCnt(msgNum) {}
//------------------------------------------------------------------------------
//! Destructor
//------------------------------------------------------------------------------
~XrdSysPlugin();
private:
enum cvResult {cvBad = 0, cvNone, cvMissing, cvClean, cvDirty};
cvResult badVersion(XrdVersionInfo &urInfo,char mmv,int majv,int minv);
cvResult chkVersion(XrdVersionInfo &urInfo, const char *pname, void *lh);
static int DLflags();
static void *Find(const char *libname);
void Inform(const char *txt1, const char *txt2=0, const char *txt3=0,
const char *txt4=0, const char *txt5=0, int noHush=0);
cvResult libMsg(const char *txt1, const char *txt2, const char *mSym=0);
const char *msgSuffix(const char *Word, char *buff, int bsz);
XrdSysError *eDest;
const char *libName;
char *libPath;
void *libHandle;
XrdVersionInfo *myInfo;
char *eBuff;
int eBLen;
int msgCnt;
struct PLlist {PLlist *next;
char *libPath;
void *libHandle;
};
static PLlist *plList;
};
#endif