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