Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * module.cpp - interface for modules (i.e. shared object, dynamic library) 00004 * 00005 * Created: Wed May 09 11:03:40 2007 00006 * Copyright 2006-2007 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <utils/system/dynamic_module/module.h> 00025 #include <utils/system/file.h> 00026 00027 #include <cstring> 00028 #include <dlfcn.h> 00029 00030 namespace fawkes { 00031 00032 /** @class ModuleOpenException <utils/system/dynamic_module/module.h> 00033 * Opening a module failed. 00034 * Thrown if a call to Module::open() failed. 00035 */ 00036 00037 /** Constructor. 00038 * @param msg message 00039 */ 00040 ModuleOpenException::ModuleOpenException(const char *msg) 00041 : Exception(msg) 00042 { 00043 } 00044 00045 /** @class Module <utils/system/dynamic_module/module.h> 00046 * Dynamic module loader for Linux, FreeBSD, and MacOS X. 00047 * A Module implementation for the dl dynamic loader library that comes 00048 * with glibc, applicable for Linux, FreeBSD, and MacOS X Systems. 00049 * 00050 * For nice reading and hints about using dynamic module loading with C++ you 00051 * should have a look at 00052 * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html 00053 * @author Tim Niemueller 00054 */ 00055 00056 // SOEXT is a macro passed in from the build system and set in config.mk or 00057 // a build type specific config file. 00058 const char * Module::FILE_EXTENSION = SOEXT; 00059 00060 /** Constructor. 00061 * @param filename full filename of the module 00062 * @param flags module flags 00063 */ 00064 Module::Module(std::string filename, Module::ModuleFlags flags) 00065 { 00066 __filename = filename; 00067 __flags = flags; 00068 00069 __handle = NULL; 00070 00071 __is_resident = false; 00072 __ref_count = 0; 00073 } 00074 00075 00076 /** Destructor. 00077 * Closes the module. */ 00078 Module::~Module() 00079 { 00080 close(); 00081 } 00082 00083 /** Open the module 00084 * @return true if the module could be opened, false otherwise 00085 * @exception ModuleOpenException thrown if there was any problem 00086 * while loading the module 00087 */ 00088 void 00089 Module::open() 00090 { 00091 if ( __handle != NULL ) return; 00092 00093 // Note: We assume Linux-style shared objects 00094 std::string full_filename = ""; 00095 full_filename = __filename; 00096 // . SOEXT 00097 if ( full_filename.find("."SOEXT, 0) != (full_filename.length() - 1 - strlen(FILE_EXTENSION)) ) { 00098 // filename has no proper ending 00099 full_filename += "."SOEXT; 00100 } 00101 00102 int tflags = 0; 00103 tflags |= ((__flags & MODULE_BIND_LAZY) != 0) ? RTLD_LAZY : RTLD_NOW; 00104 tflags |= ((__flags & MODULE_BIND_NOW) != 0) ? RTLD_NOW : 0; 00105 tflags |= ((__flags & MODULE_BIND_LOCAL) != 0) ? RTLD_LOCAL : 0; 00106 tflags |= ((__flags & MODULE_BIND_GLOBAL) != 0) ? RTLD_GLOBAL : 0; 00107 tflags |= ((__flags & MODULE_NODELETE) != 0) ? RTLD_NODELETE : 0; 00108 #ifdef linux 00109 tflags |= ((__flags & MODULE_BIND_DEEP) != 0) ? RTLD_DEEPBIND : 0; 00110 #endif 00111 00112 if ( full_filename == "") { 00113 __handle = dlopen (NULL, tflags); 00114 00115 __filename = "main"; 00116 __is_resident = true; 00117 __ref_count = 1; 00118 } else { 00119 00120 // check whether we have a readable file right away 00121 if (File::is_regular(full_filename.c_str())) { 00122 // ok, try loading the module 00123 __handle = dlopen(full_filename.c_str(), tflags); 00124 00125 if ( NULL == __handle) { 00126 const char *err = dlerror(); 00127 if ( NULL == err ) { 00128 throw ModuleOpenException("dlopen failed with an unknown error"); 00129 } else { 00130 ModuleOpenException e("dlopen failed"); 00131 e.append("dlerror: %s", err); 00132 throw e; 00133 } 00134 } else { 00135 __is_resident = false; 00136 __ref_count = 1; 00137 } 00138 } else { 00139 ModuleOpenException e("Cannot open module"); 00140 e.append("File '%s' does not exist", full_filename.c_str()); 00141 throw e; 00142 } 00143 } 00144 } 00145 00146 00147 /** Close the module 00148 * @return Returns true if the module could be closed, false otherwise 00149 */ 00150 bool 00151 Module::close() 00152 { 00153 if ( __handle == NULL ) return true; 00154 00155 if ( __ref_count > 0 ) --__ref_count; 00156 00157 if ( (__ref_count == 0) && ! __is_resident ) { 00158 if ( dlclose(__handle) != 0 ) { 00159 __handle = NULL; 00160 return false; 00161 } 00162 __handle = NULL; 00163 } 00164 00165 return true; 00166 } 00167 00168 00169 /** Increment the reference count of this module */ 00170 void 00171 Module::ref() 00172 { 00173 ++__ref_count; 00174 } 00175 00176 00177 /** Decrease the reference count of this module */ 00178 void 00179 Module::unref() 00180 { 00181 if ( __ref_count > 0 ) { 00182 --__ref_count; 00183 } 00184 } 00185 00186 00187 /** Check if there are no reference to this module 00188 * @return Returns true if there are no references to this module, 00189 * false if there is at least one reference 00190 */ 00191 bool 00192 Module::notref() 00193 { 00194 return (__ref_count == 0); 00195 } 00196 00197 00198 /** Get the reference count of this module 00199 * @return Returns the number of references to this module 00200 */ 00201 unsigned int 00202 Module::get_ref_count() 00203 { 00204 return __ref_count; 00205 } 00206 00207 00208 /** Compare to another Module instance 00209 * @param cmod a reference to the other comparison instance 00210 * @return Returns true, if the full file names of both modules are the 00211 * same, false otherwise 00212 */ 00213 bool 00214 Module::operator==(const Module &cmod) 00215 { 00216 return (__filename == cmod.__filename); 00217 } 00218 00219 00220 /** Check if the module has the given symbol 00221 * @param symbol_name The name of the symbol. 00222 * NOTE: C++ symbols are mangled with type info and thus are not plainly 00223 * available as symbol name. Use extern "C" to avoid this. 00224 * Read 00225 * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html 00226 * for more information on this topic. 00227 * @return Returns true if the symbol was found, false otherwise 00228 */ 00229 bool 00230 Module::has_symbol(const char *symbol_name) 00231 { 00232 if( symbol_name == NULL ) { 00233 return false; 00234 } 00235 if ( __handle == NULL ) { 00236 return false; 00237 } 00238 00239 return ( dlsym( __handle, symbol_name ) != NULL ); 00240 } 00241 00242 00243 /** Get a symbol from the module 00244 * @param symbol_name The name of the symbol. 00245 * NOTE: C++ symbols are mangled with type info and thus are not plainly 00246 * available as symbol name. Use extern "C" to avoid this. 00247 * Read 00248 * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html 00249 * for more information on this topic. 00250 * @return Returns a pointer to the symbol or NULL if symbol was not found 00251 */ 00252 void * 00253 Module::get_symbol(const char *symbol_name) 00254 { 00255 if( symbol_name == NULL ) return NULL; 00256 if ( __handle == NULL ) return NULL; 00257 00258 return dlsym( __handle, symbol_name ); 00259 } 00260 00261 00262 /** Get file extension for dl modules 00263 * @return Returns the file extension for dl modules, this is "so" on Linux 00264 * and FreeBSD systems, and dylib on MacOS X. It is defined at compile time 00265 * in config.mk. 00266 */ 00267 const char * 00268 Module::get_file_extension() 00269 { 00270 return FILE_EXTENSION; 00271 } 00272 00273 00274 /** Get the full file name of the module 00275 * @return Returns a string with the full file name of the module 00276 */ 00277 std::string 00278 Module::get_filename() 00279 { 00280 return __filename; 00281 } 00282 00283 00284 /** Get the base file name of the module 00285 * @return Returns the base file name of the module. On Unix systems this is 00286 * everything after the last slash 00287 */ 00288 std::string 00289 Module::get_base_filename() 00290 { 00291 if ( __filename.find("/", 0) != std::string::npos ) { 00292 std::string rv = __filename.substr(__filename.rfind("/", __filename.length()) + 1, __filename.length()); 00293 return rv; 00294 } else { 00295 return __filename.c_str(); 00296 } 00297 } 00298 00299 } // end namespace fawkes