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
30namespace 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.
57const char *Module::FILE_EXTENSION = SOEXT;
58
59/** Constructor.
60 * @param filename full filename of the module
61 * @param flags module flags
62 */
63Module::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 */
85void
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 */
146bool
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 */
167void
169{
170 ++ref_count_;
171}
172
173/** Decrease the reference count of this module */
174void
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 */
186bool
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 */
195unsigned 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 */
206bool
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 */
221bool
222Module::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 */
243void *
244Module::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 */
259const 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 */
268std::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 */
278std::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
Base class for exceptions in Fawkes.
Definition: exception.h:36
void append(const char *format,...) noexcept
Append messages to the message list.
Definition: exception.cpp:333
static bool is_regular(const char *filename)
Check if a file is a regular file.
Definition: file.cpp:147
Opening a module failed.
Definition: module.h:35
ModuleOpenException(const char *msg)
Constructor.
Definition: module.cpp:40
Dynamic module loader for Linux, FreeBSD, and MacOS X.
Definition: module.h:41
virtual std::string get_filename()
Get the full file name of the module.
Definition: module.cpp:269
virtual std::string get_base_filename()
Get the base file name of the module.
Definition: module.cpp:279
ModuleFlags
Flags for the loading process.
Definition: module.h:44
@ MODULE_BIND_NOW
Resolve all symbols immediately when loading the library.
Definition: module.h:59
@ MODULE_BIND_LAZY
Perform lazy binding.
Definition: module.h:49
@ MODULE_NODELETE
Do not unload the library during dlclose().
Definition: module.h:89
@ MODULE_BIND_LOCAL
Symbols defined in this library are not made available to resolve references in subsequently loaded l...
Definition: module.h:65
@ MODULE_BIND_DEEP
Place the lookup scope of the symbols in this library ahead of the global scope.
Definition: module.h:81
@ MODULE_BIND_GLOBAL
Symbols defined in this library are not made available to resolve references in subsequently loaded l...
Definition: module.h:73
virtual void * get_symbol(const char *symbol_name)
Get a symbol from the module.
Definition: module.cpp:244
virtual void unref()
Decrease the reference count of this module.
Definition: module.cpp:175
virtual ~Module()
Destructor.
Definition: module.cpp:76
virtual unsigned int get_ref_count()
Get the reference count of this module.
Definition: module.cpp:196
virtual void ref()
Increment the reference count of this module.
Definition: module.cpp:168
virtual bool operator==(const Module &cmod)
Compare to another Module instance.
Definition: module.cpp:207
virtual void open()
Open the module.
Definition: module.cpp:86
virtual bool has_symbol(const char *symbol_name)
Check if the module has the given symbol.
Definition: module.cpp:222
virtual bool close()
Close the module.
Definition: module.cpp:147
static const char * get_file_extension()
Get file extension for dl modules.
Definition: module.cpp:260
virtual bool notref()
Check if there are no reference to this module.
Definition: module.cpp:187
Module(std::string filename, ModuleFlags flags=MODULE_FLAGS_DEFAULT)
Constructor.
Definition: module.cpp:63
Fawkes library namespace.