Fawkes API  Fawkes Development Version
module.cpp
1 
2 /***************************************************************************
3  * module.cpp - interface for modules (i.e. shared object, dynamic library)
4  *
5  * Created: Wed May 09 11:03:40 2007
6  * Copyright 2006-2007 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <utils/system/dynamic_module/module.h>
25 #include <utils/system/file.h>
26 
27 #include <cstring>
28 #include <dlfcn.h>
29 
30 namespace fawkes {
31 
32 /** @class ModuleOpenException <utils/system/dynamic_module/module.h>
33  * Opening a module failed.
34  * Thrown if a call to Module::open() failed.
35  */
36 
37 /** Constructor.
38  * @param msg message
39  */
41 {
42 }
43 
44 /** @class Module <utils/system/dynamic_module/module.h>
45  * Dynamic module loader for Linux, FreeBSD, and MacOS X.
46  * A Module implementation for the dl dynamic loader library that comes
47  * with glibc, applicable for Linux, FreeBSD, and MacOS X Systems.
48  *
49  * For nice reading and hints about using dynamic module loading with C++ you
50  * should have a look at
51  * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html
52  * @author Tim Niemueller
53  */
54 
55 // SOEXT is a macro passed in from the build system and set in config.mk or
56 // a build type specific config file.
57 const char *Module::FILE_EXTENSION = SOEXT;
58 
59 /** Constructor.
60  * @param filename full filename of the module
61  * @param flags module flags
62  */
63 Module::Module(std::string filename, Module::ModuleFlags flags)
64 {
65  filename_ = filename;
66  flags_ = flags;
67 
68  handle_ = NULL;
69 
70  is_resident_ = false;
71  ref_count_ = 0;
72 }
73 
74 /** Destructor.
75  * Closes the module. */
77 {
78  close();
79 }
80 
81 /** Open the module
82  * @exception ModuleOpenException thrown if there was any problem
83  * while loading the module
84  */
85 void
87 {
88  if (handle_ != NULL)
89  return;
90 
91  // Note: We assume Linux-style shared objects
92  std::string full_filename = "";
93  full_filename = filename_;
94  // . SOEXT
95  if (full_filename.find("." SOEXT, 0) != (full_filename.length() - 1 - strlen(FILE_EXTENSION))) {
96  // filename has no proper ending
97  full_filename += "." SOEXT;
98  }
99 
100  int tflags = 0;
101  tflags |= ((flags_ & MODULE_BIND_LAZY) != 0) ? RTLD_LAZY : RTLD_NOW;
102  tflags |= ((flags_ & MODULE_BIND_NOW) != 0) ? RTLD_NOW : 0;
103  tflags |= ((flags_ & MODULE_BIND_LOCAL) != 0) ? RTLD_LOCAL : 0;
104  tflags |= ((flags_ & MODULE_BIND_GLOBAL) != 0) ? RTLD_GLOBAL : 0;
105  tflags |= ((flags_ & MODULE_NODELETE) != 0) ? RTLD_NODELETE : 0;
106 #ifdef linux
107  tflags |= ((flags_ & MODULE_BIND_DEEP) != 0) ? RTLD_DEEPBIND : 0;
108 #endif
109 
110  if (full_filename == "") {
111  handle_ = dlopen(NULL, tflags);
112 
113  filename_ = "main";
114  is_resident_ = true;
115  ref_count_ = 1;
116  } else {
117  // check whether we have a readable file right away
118  if (File::is_regular(full_filename.c_str())) {
119  // ok, try loading the module
120  handle_ = dlopen(full_filename.c_str(), tflags);
121 
122  if (NULL == handle_) {
123  const char *err = dlerror();
124  if (NULL == err) {
125  throw ModuleOpenException("dlopen failed with an unknown error");
126  } else {
127  ModuleOpenException e("dlopen failed");
128  e.append("dlerror: %s", err);
129  throw e;
130  }
131  } else {
132  is_resident_ = false;
133  ref_count_ = 1;
134  }
135  } else {
136  ModuleOpenException e("Cannot open module");
137  e.append("File '%s' does not exist", full_filename.c_str());
138  throw e;
139  }
140  }
141 }
142 
143 /** Close the module
144  * @return Returns true if the module could be closed, false otherwise
145  */
146 bool
148 {
149  if (handle_ == NULL)
150  return true;
151 
152  if (ref_count_ > 0)
153  --ref_count_;
154 
155  if ((ref_count_ == 0) && !is_resident_) {
156  if (dlclose(handle_) != 0) {
157  handle_ = NULL;
158  return false;
159  }
160  handle_ = NULL;
161  }
162 
163  return true;
164 }
165 
166 /** Increment the reference count of this module */
167 void
169 {
170  ++ref_count_;
171 }
172 
173 /** Decrease the reference count of this module */
174 void
176 {
177  if (ref_count_ > 0) {
178  --ref_count_;
179  }
180 }
181 
182 /** Check if there are no reference to this module
183  * @return Returns true if there are no references to this module,
184  * false if there is at least one reference
185  */
186 bool
188 {
189  return (ref_count_ == 0);
190 }
191 
192 /** Get the reference count of this module
193  * @return Returns the number of references to this module
194  */
195 unsigned int
197 {
198  return ref_count_;
199 }
200 
201 /** Compare to another Module instance
202  * @param cmod a reference to the other comparison instance
203  * @return Returns true, if the full file names of both modules are the
204  * same, false otherwise
205  */
206 bool
208 {
209  return (filename_ == cmod.filename_);
210 }
211 
212 /** Check if the module has the given symbol
213  * @param symbol_name The name of the symbol.
214  * NOTE: C++ symbols are mangled with type info and thus are not plainly
215  * available as symbol name. Use extern "C" to avoid this.
216  * Read
217  * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html
218  * for more information on this topic.
219  * @return Returns true if the symbol was found, false otherwise
220  */
221 bool
222 Module::has_symbol(const char *symbol_name)
223 {
224  if (symbol_name == NULL) {
225  return false;
226  }
227  if (handle_ == NULL) {
228  return false;
229  }
230 
231  return (dlsym(handle_, symbol_name) != NULL);
232 }
233 
234 /** Get a symbol from the module
235  * @param symbol_name The name of the symbol.
236  * NOTE: C++ symbols are mangled with type info and thus are not plainly
237  * available as symbol name. Use extern "C" to avoid this.
238  * Read
239  * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html
240  * for more information on this topic.
241  * @return Returns a pointer to the symbol or NULL if symbol was not found
242  */
243 void *
244 Module::get_symbol(const char *symbol_name)
245 {
246  if (symbol_name == NULL)
247  return NULL;
248  if (handle_ == NULL)
249  return NULL;
250 
251  return dlsym(handle_, symbol_name);
252 }
253 
254 /** Get file extension for dl modules
255  * @return Returns the file extension for dl modules, this is "so" on Linux
256  * and FreeBSD systems, and dylib on MacOS X. It is defined at compile time
257  * in config.mk.
258  */
259 const char *
261 {
262  return FILE_EXTENSION;
263 }
264 
265 /** Get the full file name of the module
266  * @return Returns a string with the full file name of the module
267  */
268 std::string
270 {
271  return filename_;
272 }
273 
274 /** Get the base file name of the module
275  * @return Returns the base file name of the module. On Unix systems this is
276  * everything after the last slash
277  */
278 std::string
280 {
281  if (filename_.find("/", 0) != std::string::npos) {
282  std::string rv =
283  filename_.substr(filename_.rfind("/", filename_.length()) + 1, filename_.length());
284  return rv;
285  } else {
286  return filename_.c_str();
287  }
288 }
289 
290 } // end namespace fawkes
fawkes::ModuleOpenException::ModuleOpenException
ModuleOpenException(const char *msg)
Constructor.
Definition: module.cpp:40
fawkes::Module::ModuleFlags
ModuleFlags
Flags for the loading process.
Definition: module.h:44
fawkes::Module::notref
virtual bool notref()
Check if there are no reference to this module.
Definition: module.cpp:187
fawkes::File::is_regular
static bool is_regular(const char *filename)
Check if a file is a regular file.
Definition: file.cpp:147
fawkes::ModuleOpenException
Opening a module failed.
Definition: module.h:35
fawkes::Module::MODULE_BIND_LAZY
@ MODULE_BIND_LAZY
Perform lazy binding.
Definition: module.h:49
fawkes::Module::get_base_filename
virtual std::string get_base_filename()
Get the base file name of the module.
Definition: module.cpp:279
fawkes::Module::MODULE_BIND_LOCAL
@ MODULE_BIND_LOCAL
Symbols defined in this library are not made available to resolve references in subsequently loaded l...
Definition: module.h:65
fawkes::Module::get_filename
virtual std::string get_filename()
Get the full file name of the module.
Definition: module.cpp:269
fawkes::Module::operator==
virtual bool operator==(const Module &cmod)
Compare to another Module instance.
Definition: module.cpp:207
fawkes::Module::unref
virtual void unref()
Decrease the reference count of this module.
Definition: module.cpp:175
fawkes::Module::get_symbol
virtual void * get_symbol(const char *symbol_name)
Get a symbol from the module.
Definition: module.cpp:244
fawkes::Exception::append
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:333
fawkes::Module::close
virtual bool close()
Close the module.
Definition: module.cpp:147
fawkes::Module::Module
Module(std::string filename, ModuleFlags flags=MODULE_FLAGS_DEFAULT)
Constructor.
Definition: module.cpp:63
fawkes::Module::MODULE_BIND_GLOBAL
@ MODULE_BIND_GLOBAL
Symbols defined in this library are not made available to resolve references in subsequently loaded l...
Definition: module.h:73
fawkes::Module::has_symbol
virtual bool has_symbol(const char *symbol_name)
Check if the module has the given symbol.
Definition: module.cpp:222
fawkes
Fawkes library namespace.
fawkes::Module::get_file_extension
static const char * get_file_extension()
Get file extension for dl modules.
Definition: module.cpp:260
fawkes::Module::MODULE_NODELETE
@ MODULE_NODELETE
Do not unload the library during dlclose().
Definition: module.h:89
fawkes::Module::open
virtual void open()
Open the module.
Definition: module.cpp:86
fawkes::Module::MODULE_BIND_NOW
@ MODULE_BIND_NOW
Resolve all symbols immediately when loading the library.
Definition: module.h:59
fawkes::Module::ref
virtual void ref()
Increment the reference count of this module.
Definition: module.cpp:168
fawkes::Module::get_ref_count
virtual unsigned int get_ref_count()
Get the reference count of this module.
Definition: module.cpp:196
fawkes::Module::MODULE_BIND_DEEP
@ MODULE_BIND_DEEP
Place the lookup scope of the symbols in this library ahead of the global scope.
Definition: module.h:81
fawkes::Module::~Module
virtual ~Module()
Destructor.
Definition: module.cpp:76
fawkes::Module
Dynamic module loader for Linux, FreeBSD, and MacOS X.
Definition: module.h:41
fawkes::Exception
Base class for exceptions in Fawkes.
Definition: exception.h:36