00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00024 #include "config.h"
00025
00026 #include <algorithm>
00027 #include <cctype>
00028 #include <cerrno>
00029 #include <cstdio>
00030 #include <cstring>
00031 #include <dlfcn.h>
00032 #include <functional>
00033 #include <iostream>
00034 #include <memory>
00035 #include <strings.h>
00036 #include <sys/stat.h>
00037 #include <sys/types.h>
00038 #include <unistd.h>
00039
00040 #include <scalestack/kernel/core.h>
00041 #include <scalestack/kernel/delete_pointer.h>
00042 #include <scalestack/kernel/exception.h>
00043 #include <scalestack/kernel/module.h>
00044 #include <scalestack/kernel/option.h>
00045
00046 using namespace std;
00047
00048 namespace scalestack
00049 {
00050 namespace kernel
00051 {
00052
00053
00054
00055
00056
00057 module::~module()
00058 {
00059 log_info(_("Destructing"));
00060 _unload();
00061 for_each(_options.begin(), _options.end(), delete_pointer());
00062 _close_object();
00063 log_info(_("Destructed"));
00064 }
00065
00066 core& module::get_core(void) const
00067 {
00068 return _core;
00069 }
00070
00071 const string& module::get_name(void) const
00072 {
00073 return _name;
00074 }
00075
00076 string module::get_normalized_name(void) const
00077 {
00078 return normalize_name(_name);
00079 }
00080
00081 const string& module::get_pathname(void) const
00082 {
00083 return _pathname;
00084 }
00085
00086 const string& module::get_version(void) const
00087 {
00088 return _version;
00089 }
00090
00091 const string& module::get_author(void) const
00092 {
00093 return _author;
00094 }
00095
00096 const string& module::get_title(void) const
00097 {
00098 return _title;
00099 }
00100
00101 const string& module::get_license(void) const
00102 {
00103 return _license;
00104 }
00105
00106 const string& module::get_dependencies(void) const
00107 {
00108 return _dependencies;
00109 }
00110
00111 size_t module::get_parent_count(void) const
00112 {
00113 return _parents.size();
00114 }
00115
00116 module* module::begin_parent(void)
00117 {
00118 _parent_iterator = _parents.begin();
00119 return next_parent();
00120 }
00121
00122 module* module::next_parent(void)
00123 {
00124 if (_parent_iterator == _parents.end())
00125 return NULL;
00126
00127 return *(_parent_iterator++);
00128 }
00129
00130 size_t module::get_child_count(void) const
00131 {
00132 return _children.size();
00133 }
00134
00135 module* module::begin_child(void)
00136 {
00137 _child_iterator = _children.begin();
00138 return next_child();
00139 }
00140
00141 module* module::next_child(void)
00142 {
00143 if (_child_iterator == _children.end())
00144 return NULL;
00145
00146 return *(_child_iterator++);
00147 }
00148
00149 bool module::is_loaded(void) const
00150 {
00151 return _is_loaded;
00152 }
00153
00154 option& module::add_option(const std::string& name,
00155 const std::string& help,
00156 const std::string& value_name,
00157 const std::string& default_value)
00158 {
00159 option& option = _get_or_add_option(name);
00160 if (option.is_valid())
00161 log_fatal(_("Duplicate option added: %s"), name.c_str());
00162
00163 option._set_help(help);
00164 option._set_value_name(value_name);
00165 option._set_default_value(default_value);
00166 option._set_value(default_value, false);
00167 option._set_valid(true);
00168 return option;
00169 }
00170
00171 option& module::get_option(const std::string& name) const
00172 {
00173 option* option = _get_option(name);
00174 if (option == NULL)
00175 log_fatal(_("Could not find option: %s"), name.c_str());
00176
00177 return *option;
00178 }
00179
00180 size_t module::get_option_count(void) const
00181 {
00182 return _options.size();
00183 }
00184
00185 option* module::begin_option(void)
00186 {
00187 _option_iterator = _options.begin();
00188 return next_option();
00189 }
00190
00191 option* module::next_option(void)
00192 {
00193 if (_option_iterator == _options.end())
00194 return NULL;
00195
00196 return *(_option_iterator++);
00197 }
00198
00199 void module::run(void)
00200 {
00201 if (!_is_started)
00202 return;
00203
00204 _need_run = true;
00205 _core._notify();
00206 }
00207
00208 string module::normalize_name(const std::string& name)
00209 {
00210 string filename;
00211
00212 for (string::const_iterator c = name.begin(); c != name.end(); ++c)
00213 {
00214 if (*c == ':')
00215 {
00216 ++c;
00217 filename.push_back('_');
00218 }
00219 else
00220 filename.push_back(static_cast<char>(tolower(*c)));
00221 }
00222
00223 return filename;
00224 }
00225
00226
00227
00228
00229
00230 module::module(core& core, const std::string& name, size_t threshold):
00231 logger(threshold),
00232 _is_loading(),
00233 _is_loaded(),
00234 _is_started(),
00235 _need_run(true),
00236 _need_reconfigure(true),
00237 _core(core),
00238 _handle(),
00239 _definition(),
00240 _name(name),
00241 _pathname(),
00242 _version(),
00243 _author(),
00244 _title(),
00245 _license(),
00246 _dependencies(),
00247 _parents(),
00248 _parent_iterator(_parents.begin()),
00249 _children(),
00250 _child_iterator(_children.begin()),
00251 _options(),
00252 _option_iterator(_options.begin())
00253 {
00254 log_info(_("Constructed"));
00255 }
00256
00257 void module::_load(void)
00258 {
00259 if (is_loaded())
00260 return;
00261
00262 if (_is_loading)
00263 log_fatal(_("Module dependency loop detected"));
00264
00265 _load_dependencies();
00266
00267 _is_loading = true;
00268
00269 if (_dependencies.size() > 0)
00270 {
00271 size_t comma;
00272 size_t start = 0;
00273
00274 do
00275 {
00276 comma = _dependencies.find(",", start);
00277 string module_name(_dependencies, start, comma - start);
00278
00279 if (module_name.size() > 0)
00280 {
00281 module& parent = _core.get_or_add_module(module_name);
00282 _parents.push_back(&parent);
00283 parent._children.push_back(this);
00284 parent._load();
00285 }
00286
00287 start = comma + 1;
00288 }
00289 while (comma != string::npos);
00290 }
00291
00292 _open_object(RTLD_NOW | RTLD_GLOBAL);
00293
00294 _name = _definition->name;
00295 _version = _definition->version;
00296 _author = _definition->author;
00297 _title = _definition->title;
00298 _license = _definition->license;
00299
00300 _is_loading = false;
00301 _is_loaded = true;
00302
00303 if (_definition->options != NULL)
00304 _definition->options(*this);
00305
00306 log_notice(_("Loaded"));
00307 log_debug(_("Version: %s"), _version.c_str());
00308 log_debug(_("Author: %s"), _author.c_str());
00309 log_debug(_("Title: %s"), _title.c_str());
00310 log_debug(_("License: %s"), _license.c_str());
00311 }
00312
00313 void module::_load_dependencies(void)
00314 {
00315 string filename(normalize_name(_name));
00316 core::paths::const_iterator path;
00317 for (path = _core._paths.begin(); path != _core._paths.end(); ++path)
00318 {
00319 _pathname = *(path) + "/lib" + filename + "_module." +
00320 SCALESTACK_MODULE_EXTENSION;
00321 log_debug(_("Checking pathname: %s"), _pathname.c_str());
00322
00323 struct stat stat_buffer;
00324 int stat_return = stat(_pathname.c_str(), &stat_buffer);
00325 if (stat_return == 0)
00326 break;
00327 else if (stat_return == -1 && errno != ENOENT)
00328 {
00329 log_fatal(_("Could not stat() pathname: %s (%s:%d)"),
00330 _pathname.c_str(), strerror(errno), errno);
00331 }
00332 }
00333
00334 if (path == _core._paths.end())
00335 log_fatal(_("Could not find this module"));
00336
00337 log_info(_("Loading from: %s"), _pathname.c_str());
00338
00339 _open_object(RTLD_LAZY);
00340
00341 _dependencies = _definition->dependencies;
00342
00343 log_debug(_("Dependencies: %s"), _dependencies.c_str());
00344
00345 _close_object();
00346 }
00347
00348 void module::_unload(void)
00349 {
00350 if (!is_loaded())
00351 return;
00352
00353 log_info(_("Unloading"));
00354
00355 for_each(_children.begin(), _children.end(), mem_fun(&module::_unload));
00356
00357 log_info(_("Stopping"));
00358
00359 if (_is_started && _definition->stop != NULL)
00360 _definition->stop(*this);
00361
00362 _is_started = false;
00363
00364 log_notice(_("Unloaded"));
00365
00366 _is_loaded = false;
00367 }
00368
00369 void module::_start(void)
00370 {
00371 if (_is_started)
00372 return;
00373
00374 for_each(_parents.begin(), _parents.end(), mem_fun(&module::_start));
00375
00376 log_info(_("Starting"));
00377
00378 if (_definition->start != NULL)
00379 _definition->start(*this);
00380
00381 _is_started = true;
00382 }
00383
00384 void module::_run(void)
00385 {
00386 if (!_need_run || _definition->run == NULL)
00387 return;
00388
00389 log_debug(_("Running"));
00390 _need_run = false;
00391 _definition->run(*this);
00392 }
00393
00394 void module::_reconfigure(void)
00395 {
00396 if (!_need_reconfigure || _definition->reconfigure == NULL)
00397 return;
00398
00399 log_debug(_("Reconfiguring"));
00400 _need_reconfigure = false;
00401 _definition->reconfigure(*this);
00402 }
00403
00404 void module::_open_object(int flags)
00405 {
00406 _handle = dlopen(_pathname.c_str(), flags);
00407 if (_handle == NULL)
00408 log_fatal(_("Could not open shared object file: %s"), dlerror());
00409
00410 _definition = static_cast<module::definition*>(dlsym(
00411 _handle, "_scalestack_kernel_module_definition"));
00412 if (_definition == NULL)
00413 {
00414
00415 char error[SCALESTACK_MAX_MESSAGE_SIZE];
00416 snprintf(error, SCALESTACK_MAX_MESSAGE_SIZE, "%s", dlerror());
00417 (void) dlclose(_handle);
00418 _handle = NULL;
00419 log_fatal(_("Could not find definition symbol in shared object: %s"),
00420 error);
00421 }
00422 }
00423
00424 void module::_close_object(void)
00425 {
00426 if (_handle == NULL)
00427 return;
00428
00429 if (dlclose(_handle) != 0)
00430 log_fatal(_("Could not close shared object file: %s"), dlerror());
00431
00432 _definition = NULL;
00433 _handle = NULL;
00434 }
00435
00436 option* module::_get_option(const std::string& name) const
00437 {
00438
00439
00440
00441
00442
00443 for (options::const_iterator option = _options.begin();
00444 option != _options.end();
00445 ++option)
00446 {
00447 if (!strcasecmp((*option)->get_name().c_str(), name.c_str()))
00448 return *option;
00449 }
00450
00451 return NULL;
00452 }
00453
00454 option& module::_get_or_add_option(const std::string& name)
00455 {
00456 option* option = _get_option(name);
00457 if (option != NULL)
00458 return *option;
00459
00460 auto_ptr<kernel::option> new_option(new kernel::option(*this, name));
00461 _options.push_back(new_option.get());
00462 return *(new_option.release());
00463 }
00464
00465 void module::_set_option_value(const std::string& name,
00466 const std::string& value)
00467 {
00468
00469 if (value == "" && name.find_first_not_of("v") == string::npos)
00470 {
00471 set_threshold(name.size());
00472 return;
00473 }
00474
00475 if (name == "v")
00476 {
00477 set_threshold(atoi(value.c_str()));
00478 return;
00479 }
00480
00481 option& option = _get_or_add_option(name);
00482 option._set_value(value, true);
00483
00484 if (_is_started)
00485 {
00486 _need_reconfigure = true;
00487 _core._notify();
00488 }
00489 }
00490
00491 void module::_check_options(void) const
00492 {
00493 options::const_iterator option = find_if(_options.begin(),
00494 _options.end(),
00495 not1(mem_fun(&option::is_valid)));
00496 if (option != _options.end())
00497 log_fatal(_("Invalid option: %s"), (*option)->get_name().c_str());
00498 }
00499
00500 void module::_set_fatal_message(const char* format,
00501 std::va_list arguments) const
00502 {
00503 char message[SCALESTACK_MAX_MESSAGE_SIZE];
00504 vsnprintf(message, SCALESTACK_MAX_MESSAGE_SIZE, format, arguments);
00505 throw kernel::exception(_name.c_str(), message);
00506 }
00507
00508 void module::_log_message(log::level log_level,
00509 const char* format,
00510 std::va_list arguments) const
00511 {
00512 _core._log(log_level, _name.c_str(), format, arguments);
00513 }
00514
00515 void module::_print_help(void)
00516 {
00517 if (_options.empty())
00518 return;
00519
00520 cout << _name << endl;
00521 for_each(_options.begin(), _options.end(), mem_fun(&option::_print_help));
00522 cout << endl;
00523 }
00524
00525 void module::_print_config(void)
00526 {
00527 for_each(_options.begin(), _options.end(), mem_fun(&option::_print_config));
00528 }
00529
00530 }
00531 }