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  */
40 ModuleOpenException::ModuleOpenException(const char *msg) : Exception(msg)
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. */
76 Module::~Module()
77 {
78  close();
79 }
80 
81 /** Open the module
82  * @return true if the module could be opened, false otherwise
83  * @exception ModuleOpenException thrown if there was any problem
84  * while loading the module
85  */
86 void
87 Module::open()
88 {
89  if (handle_ != NULL)
90  return;
91 
92  // Note: We assume Linux-style shared objects
93  std::string full_filename = "";
94  full_filename = filename_;
95  // . SOEXT
96  if (full_filename.find("." SOEXT, 0) != (full_filename.length() - 1 - strlen(FILE_EXTENSION))) {
97  // filename has no proper ending
98  full_filename += "." SOEXT;
99  }
100 
101  int tflags = 0;
102  tflags |= ((flags_ & MODULE_BIND_LAZY) != 0) ? RTLD_LAZY : RTLD_NOW;
103  tflags |= ((flags_ & MODULE_BIND_NOW) != 0) ? RTLD_NOW : 0;
104  tflags |= ((flags_ & MODULE_BIND_LOCAL) != 0) ? RTLD_LOCAL : 0;
105  tflags |= ((flags_ & MODULE_BIND_GLOBAL) != 0) ? RTLD_GLOBAL : 0;
106  tflags |= ((flags_ & MODULE_NODELETE) != 0) ? RTLD_NODELETE : 0;
107 #ifdef linux
108  tflags |= ((flags_ & MODULE_BIND_DEEP) != 0) ? RTLD_DEEPBIND : 0;
109 #endif
110 
111  if (full_filename == "") {
112  handle_ = dlopen(NULL, tflags);
113 
114  filename_ = "main";
115  is_resident_ = true;
116  ref_count_ = 1;
117  } else {
118  // check whether we have a readable file right away
119  if (File::is_regular(full_filename.c_str())) {
120  // ok, try loading the module
121  handle_ = dlopen(full_filename.c_str(), tflags);
122 
123  if (NULL == handle_) {
124  const char *err = dlerror();
125  if (NULL == err) {
126  throw ModuleOpenException("dlopen failed with an unknown error");
127  } else {
128  ModuleOpenException e("dlopen failed");
129  e.append("dlerror: %s", err);
130  throw e;
131  }
132  } else {
133  is_resident_ = false;
134  ref_count_ = 1;
135  }
136  } else {
137  ModuleOpenException e("Cannot open module");
138  e.append("File '%s' does not exist", full_filename.c_str());
139  throw e;
140  }
141  }
142 }
143 
144 /** Close the module
145  * @return Returns true if the module could be closed, false otherwise
146  */
147 bool
148 Module::close()
149 {
150  if (handle_ == NULL)
151  return true;
152 
153  if (ref_count_ > 0)
154  --ref_count_;
155 
156  if ((ref_count_ == 0) && !is_resident_) {
157  if (dlclose(handle_) != 0) {
158  handle_ = NULL;
159  return false;
160  }
161  handle_ = NULL;
162  }
163 
164  return true;
165 }
166 
167 /** Increment the reference count of this module */
168 void
169 Module::ref()
170 {
171  ++ref_count_;
172 }
173 
174 /** Decrease the reference count of this module */
175 void
176 Module::unref()
177 {
178  if (ref_count_ > 0) {
179  --ref_count_;
180  }
181 }
182 
183 /** Check if there are no reference to this module
184  * @return Returns true if there are no references to this module,
185  * false if there is at least one reference
186  */
187 bool
188 Module::notref()
189 {
190  return (ref_count_ == 0);
191 }
192 
193 /** Get the reference count of this module
194  * @return Returns the number of references to this module
195  */
196 unsigned int
197 Module::get_ref_count()
198 {
199  return ref_count_;
200 }
201 
202 /** Compare to another Module instance
203  * @param cmod a reference to the other comparison instance
204  * @return Returns true, if the full file names of both modules are the
205  * same, false otherwise
206  */
207 bool
208 Module::operator==(const Module &cmod)
209 {
210  return (filename_ == cmod.filename_);
211 }
212 
213 /** Check if the module has the given symbol
214  * @param symbol_name The name of the symbol.
215  * NOTE: C++ symbols are mangled with type info and thus are not plainly
216  * available as symbol name. Use extern "C" to avoid this.
217  * Read
218  * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html
219  * for more information on this topic.
220  * @return Returns true if the symbol was found, false otherwise
221  */
222 bool
223 Module::has_symbol(const char *symbol_name)
224 {
225  if (symbol_name == NULL) {
226  return false;
227  }
228  if (handle_ == NULL) {
229  return false;
230  }
231 
232  return (dlsym(handle_, symbol_name) != NULL);
233 }
234 
235 /** Get a symbol from the module
236  * @param symbol_name The name of the symbol.
237  * NOTE: C++ symbols are mangled with type info and thus are not plainly
238  * available as symbol name. Use extern "C" to avoid this.
239  * Read
240  * http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html
241  * for more information on this topic.
242  * @return Returns a pointer to the symbol or NULL if symbol was not found
243  */
244 void *
245 Module::get_symbol(const char *symbol_name)
246 {
247  if (symbol_name == NULL)
248  return NULL;
249  if (handle_ == NULL)
250  return NULL;
251 
252  return dlsym(handle_, symbol_name);
253 }
254 
255 /** Get file extension for dl modules
256  * @return Returns the file extension for dl modules, this is "so" on Linux
257  * and FreeBSD systems, and dylib on MacOS X. It is defined at compile time
258  * in config.mk.
259  */
260 const char *
261 Module::get_file_extension()
262 {
263  return FILE_EXTENSION;
264 }
265 
266 /** Get the full file name of the module
267  * @return Returns a string with the full file name of the module
268  */
269 std::string
270 Module::get_filename()
271 {
272  return filename_;
273 }
274 
275 /** Get the base file name of the module
276  * @return Returns the base file name of the module. On Unix systems this is
277  * everything after the last slash
278  */
279 std::string
280 Module::get_base_filename()
281 {
282  if (filename_.find("/", 0) != std::string::npos) {
283  std::string rv =
284  filename_.substr(filename_.rfind("/", filename_.length()) + 1, filename_.length());
285  return rv;
286  } else {
287  return filename_.c_str();
288  }
289 }
290 
291 } // end namespace fawkes
fawkes::ModuleOpenException::ModuleOpenException
ModuleOpenException(const char *msg)
Constructor.
Definition: module.cpp:44
fawkes::Module::ModuleFlags
ModuleFlags
Flags for the loading process.
Definition: module.h:49
fawkes
fawkes::Module
Definition: module.h:45