Drizzled Public API Documentation

library.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2009 Sun Microsystems, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #include <config.h>
21 
22 #include <dlfcn.h>
23 
24 #include <cerrno>
25 #include <string>
26 
27 #include <boost/filesystem.hpp>
28 
29 #include <drizzled/plugin.h>
30 #include <drizzled/definitions.h>
31 #include <drizzled/error.h>
32 #include <drizzled/errmsg_print.h>
33 #include <drizzled/module/library.h>
34 
35 using namespace std;
36 namespace fs=boost::filesystem;
37 
38 namespace drizzled
39 {
40 
41 module::Library::Library(const std::string &name_arg,
42  void *handle_arg,
43  const Manifest *manifest_arg)
44  : name(name_arg), handle(handle_arg), manifest(manifest_arg)
45 {}
46 
48 {
54 }
55 
56 const fs::path module::Library::getLibraryPath(const string &plugin_name)
57 {
58  string plugin_lib_name("lib");
59  plugin_lib_name.append(plugin_name);
60  plugin_lib_name.append("_plugin");
61 #if defined(TARGET_OS_OSX)
62  plugin_lib_name.append(".dylib");
63 #else
64  plugin_lib_name.append(".so");
65 #endif
66 
67  /* Compile dll path */
68  return plugin_dir / plugin_lib_name;
69 }
70 
71 module::Library *module::Library::loadLibrary(const string &plugin_name, bool builtin)
72 {
73  /*
74  Ensure that the dll doesn't have a path.
75  This is done to ensure that only approved libraries from the
76  plugin directory are used (to make this even remotely secure).
77  */
78  size_t found= plugin_name.find(FN_LIBCHAR);
79  if (found != string::npos)
80  {
81  errmsg_printf(error::ERROR, "%s",ER(ER_PLUGIN_NO_PATHS));
82  return NULL;
83  }
84 
85  void *dl_handle= NULL;
86  string dlpath;
87 
88  if (builtin)
89  {
90  dlpath= "<builtin>";
91  dl_handle= dlopen(NULL, RTLD_NOW|RTLD_LOCAL);
92  if (dl_handle == NULL)
93  {
94  const char *errmsg= dlerror();
95  errmsg_printf(error::ERROR, ER(ER_CANT_OPEN_LIBRARY),
96  dlpath.c_str(), errno, errmsg);
97  (void)dlerror();
98 
99  return NULL;
100  }
101  }
102  else
103  {
104  /* Open new dll handle */
105  dlpath= Library::getLibraryPath(plugin_name).file_string();
106  dl_handle= dlopen(dlpath.c_str(), RTLD_NOW|RTLD_GLOBAL);
107  if (dl_handle == NULL)
108  {
109  const char *errmsg= dlerror();
110  uint32_t dlpathlen= dlpath.length();
111  if (not dlpath.compare(0, dlpathlen, errmsg))
112  { // if errmsg starts from dlpath, trim this prefix.
113  errmsg+= dlpathlen;
114  if (*errmsg == ':') errmsg++;
115  if (*errmsg == ' ') errmsg++;
116  }
117  errmsg_printf(error::ERROR, ER(ER_CANT_OPEN_LIBRARY),
118  dlpath.c_str(), errno, errmsg);
119 
120  // This, in theory, should cause dlerror() to deallocate the error
121  // message. Found this via Google'ing :)
122  (void)dlerror();
123 
124  return NULL;
125  }
126  }
127 
128  string plugin_decl_sym("_drizzled_");
129  plugin_decl_sym.append(plugin_name);
130  plugin_decl_sym.append("_plugin_");
131 
132  /* Find plugin declarations */
133  void *sym= dlsym(dl_handle, plugin_decl_sym.c_str());
134  if (sym == NULL)
135  {
136  const char* errmsg= dlerror();
137  errmsg_printf(error::ERROR, "%s", errmsg);
138  errmsg_printf(error::ERROR, ER(ER_CANT_FIND_DL_ENTRY),
139  plugin_decl_sym.c_str(), dlpath.c_str());
140  (void)dlerror();
141  dlclose(dl_handle);
142  return NULL;
143  }
144 
145  const Manifest *module_manifest= static_cast<module::Manifest *>(sym);
146  if (module_manifest->drizzle_version != DRIZZLE_VERSION_ID)
147  {
148  errmsg_printf(error::ERROR,
149  _("Plugin module %s was compiled for version %" PRIu64 ", "
150  "which does not match the current running version of "
151  "Drizzle: %" PRIu64"."),
152  dlpath.c_str(), module_manifest->drizzle_version,
153  static_cast<uint64_t>(DRIZZLE_VERSION_ID));
154  return NULL;
155  }
156 
157  return new module::Library(plugin_name, dl_handle, module_manifest);
158 }
159 
160 } /* namespace drizzled */