Drizzled Public API Documentation

library.cc

00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2009 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <dlfcn.h>
00023 
00024 #include <cerrno>
00025 #include <string>
00026 
00027 #include <boost/filesystem.hpp>
00028 
00029 #include <drizzled/plugin.h>
00030 #include <drizzled/definitions.h>
00031 #include <drizzled/error.h>
00032 #include <drizzled/errmsg_print.h>
00033 #include <drizzled/module/library.h>
00034 
00035 using namespace std;
00036 namespace fs=boost::filesystem;
00037 
00038 namespace drizzled
00039 {
00040 
00041 module::Library::Library(const std::string &name_arg,
00042                          void *handle_arg,
00043                          const Manifest *manifest_arg)
00044  : name(name_arg), handle(handle_arg), manifest(manifest_arg)
00045 {}
00046 
00047 module::Library::~Library()
00048 {
00054 }
00055 
00056 const fs::path module::Library::getLibraryPath(const string &plugin_name)
00057 {
00058   string plugin_lib_name("lib");
00059   plugin_lib_name.append(plugin_name);
00060   plugin_lib_name.append("_plugin");
00061 #if defined(TARGET_OS_OSX)
00062   plugin_lib_name.append(".dylib");
00063 #else
00064   plugin_lib_name.append(".so");
00065 #endif
00066 
00067   /* Compile dll path */
00068   return plugin_dir / plugin_lib_name;
00069 }
00070 
00071 module::Library *module::Library::loadLibrary(const string &plugin_name, bool builtin)
00072 {
00073   /*
00074     Ensure that the dll doesn't have a path.
00075     This is done to ensure that only approved libraries from the
00076     plugin directory are used (to make this even remotely secure).
00077   */
00078   size_t found= plugin_name.find(FN_LIBCHAR);
00079   if (found != string::npos)
00080   {
00081     errmsg_printf(error::ERROR, "%s",ER(ER_PLUGIN_NO_PATHS));
00082     return NULL;
00083   }
00084 
00085   void *dl_handle= NULL;
00086   string dlpath("");
00087 
00088   if (builtin)
00089   {
00090     dlpath.assign("<builtin>");
00091     dl_handle= dlopen(NULL, RTLD_NOW|RTLD_LOCAL);
00092     if (dl_handle == NULL)
00093     {
00094       const char *errmsg= dlerror();
00095       errmsg_printf(error::ERROR, ER(ER_CANT_OPEN_LIBRARY),
00096                     dlpath.c_str(), errno, errmsg);
00097       (void)dlerror();
00098 
00099       return NULL;
00100     }
00101   }
00102   else
00103   {
00104   /* Open new dll handle */
00105     dlpath.assign(Library::getLibraryPath(plugin_name).file_string());
00106     dl_handle= dlopen(dlpath.c_str(), RTLD_NOW|RTLD_GLOBAL);
00107     if (dl_handle == NULL)
00108     {
00109       const char *errmsg= dlerror();
00110       uint32_t dlpathlen= dlpath.length();
00111       if (not dlpath.compare(0, dlpathlen, errmsg))
00112       { // if errmsg starts from dlpath, trim this prefix.
00113         errmsg+= dlpathlen;
00114         if (*errmsg == ':') errmsg++;
00115         if (*errmsg == ' ') errmsg++;
00116       }
00117       errmsg_printf(error::ERROR, ER(ER_CANT_OPEN_LIBRARY),
00118                     dlpath.c_str(), errno, errmsg);
00119 
00120       // This, in theory, should cause dlerror() to deallocate the error
00121       // message. Found this via Google'ing :)
00122       (void)dlerror();
00123 
00124       return NULL;
00125     }
00126   }
00127 
00128   string plugin_decl_sym("_drizzled_");
00129   plugin_decl_sym.append(plugin_name);
00130   plugin_decl_sym.append("_plugin_");
00131 
00132   /* Find plugin declarations */
00133   void *sym= dlsym(dl_handle, plugin_decl_sym.c_str());
00134   if (sym == NULL)
00135   {
00136     const char* errmsg= dlerror();
00137     errmsg_printf(error::ERROR, errmsg);
00138     errmsg_printf(error::ERROR, ER(ER_CANT_FIND_DL_ENTRY),
00139                   plugin_decl_sym.c_str(), dlpath.c_str());
00140     (void)dlerror();
00141     dlclose(dl_handle);
00142     return NULL;
00143   }
00144 
00145   const Manifest *module_manifest= static_cast<module::Manifest *>(sym); 
00146   if (module_manifest->drizzle_version != DRIZZLE_VERSION_ID)
00147   {
00148     errmsg_printf(error::ERROR,
00149                   _("Plugin module %s was compiled for version %" PRIu64 ", "
00150                     "which does not match the current running version of "
00151                     "Drizzle: %" PRIu64"."),
00152                  dlpath.c_str(), module_manifest->drizzle_version,
00153                  static_cast<uint64_t>(DRIZZLE_VERSION_ID));
00154     return NULL;
00155   }
00156 
00157   return new (nothrow) module::Library(plugin_name, dl_handle, module_manifest);
00158 }
00159 
00160 } /* namespace drizzled */