00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "services.h"
00011 #include "modules.h"
00012 #include "users.h"
00013 #include "regchannel.h"
00014
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #ifndef _WIN32
00018 #include <dirent.h>
00019 #include <sys/types.h>
00020 #include <dlfcn.h>
00021 #endif
00022
00023 std::list<Module *> ModuleManager::Modules;
00024 std::vector<Module *> ModuleManager::EventHandlers[I_END];
00025
00026 void ModuleManager::CleanupRuntimeDirectory()
00027 {
00028 Anope::string dirbuf = Anope::DataDir + "/runtime";
00029
00030 Log(LOG_DEBUG) << "Cleaning out Module run time directory (" << dirbuf << ") - this may take a moment please wait";
00031
00032 DIR *dirp = opendir(dirbuf.c_str());
00033 if (!dirp)
00034 {
00035 Log(LOG_DEBUG) << "Cannot open directory (" << dirbuf << ")";
00036 return;
00037 }
00038
00039 for (dirent *dp; (dp = readdir(dirp));)
00040 {
00041 if (!dp->d_ino)
00042 continue;
00043 if (Anope::string(dp->d_name).equals_cs(".") || Anope::string(dp->d_name).equals_cs(".."))
00044 continue;
00045 Anope::string filebuf = dirbuf + "/" + dp->d_name;
00046 unlink(filebuf.c_str());
00047 }
00048
00049 closedir(dirp);
00050 }
00051
00061 static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &output)
00062 {
00063 Anope::string input = Anope::ModuleDir + "/modules/" + name + ".so";
00064
00065 struct stat s;
00066 if (stat(input.c_str(), &s) == -1)
00067 return MOD_ERR_NOEXIST;
00068 else if (!S_ISREG(s.st_mode))
00069 return MOD_ERR_NOEXIST;
00070
00071 std::ifstream source(input.c_str(), std::ios_base::in | std::ios_base::binary);
00072 if (!source.is_open())
00073 return MOD_ERR_NOEXIST;
00074
00075 char *tmp_output = strdup(output.c_str());
00076 int target_fd = mkstemp(tmp_output);
00077 if (target_fd == -1 || close(target_fd) == -1)
00078 {
00079 free(tmp_output);
00080 source.close();
00081 return MOD_ERR_FILE_IO;
00082 }
00083 output = tmp_output;
00084 free(tmp_output);
00085
00086 Log(LOG_DEBUG_2) << "Runtime module location: " << output;
00087
00088 std::ofstream target(output.c_str(), std::ios_base::in | std::ios_base::binary);
00089 if (!target.is_open())
00090 {
00091 source.close();
00092 return MOD_ERR_FILE_IO;
00093 }
00094
00095 int want = s.st_size;
00096 char buffer[1024];
00097 while (want > 0 && !source.fail() && !target.fail())
00098 {
00099 source.read(buffer, std::min(want, static_cast<int>(sizeof(buffer))));
00100 int read_len = source.gcount();
00101
00102 target.write(buffer, read_len);
00103 want -= read_len;
00104 }
00105
00106 source.close();
00107 target.close();
00108
00109 return !source.fail() && !target.fail() ? MOD_ERR_OK : MOD_ERR_FILE_IO;
00110 }
00111
00112
00113
00114
00115
00116
00117 template <class TYPE> static TYPE function_cast(void *symbol)
00118 {
00119 union
00120 {
00121 void *symbol;
00122 TYPE function;
00123 } cast;
00124 cast.symbol = symbol;
00125 return cast.function;
00126 }
00127
00128 ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
00129 {
00130 if (modname.empty())
00131 return MOD_ERR_PARAMS;
00132
00133 if (FindModule(modname))
00134 return MOD_ERR_EXISTS;
00135
00136 Log(LOG_DEBUG) << "trying to load [" << modname << "]";
00137
00138
00139 Anope::string pbuf = Anope::DataDir + "/runtime/" + modname + ".so.XXXXXX";
00140
00141
00142 ModuleReturn ret = moduleCopyFile(modname, pbuf);
00143 if (ret != MOD_ERR_OK)
00144 {
00145 if (ret == MOD_ERR_NOEXIST)
00146 Log(LOG_TERMINAL) << "Error while loading " << modname << " (file does not exist)";
00147 else if (ret == MOD_ERR_FILE_IO)
00148 Log(LOG_TERMINAL) << "Error while loading " << modname << " (file IO error, check file permissions and diskspace)";
00149 return ret;
00150 }
00151
00152 dlerror();
00153 void *handle = dlopen(pbuf.c_str(), RTLD_NOW);
00154 const char *err = dlerror();
00155 if (!handle && err && *err)
00156 {
00157 Log() << err;
00158 return MOD_ERR_NOLOAD;
00159 }
00160
00161 dlerror();
00162 Module *(*func)(const Anope::string &, const Anope::string &) = function_cast<Module *(*)(const Anope::string &, const Anope::string &)>(dlsym(handle, "AnopeInit"));
00163 err = dlerror();
00164 if (!func && err && *err)
00165 {
00166 Log() << "No init function found, not an Anope module";
00167 dlclose(handle);
00168 return MOD_ERR_NOLOAD;
00169 }
00170
00171 if (!func)
00172 throw CoreException("Couldn't find constructor, yet moderror wasn't set?");
00173
00174
00175 Anope::string nick;
00176 if (u)
00177 nick = u->nick;
00178
00179 Module *m;
00180
00181 try
00182 {
00183 m = func(modname, nick);
00184 }
00185 catch (const ModuleException &ex)
00186 {
00187 Log() << "Error while loading " << modname << ": " << ex.GetReason();
00188 return MOD_ERR_EXCEPTION;
00189 }
00190
00191 m->filename = pbuf;
00192 m->handle = handle;
00193
00194 ModuleVersion v = m->GetVersion();
00195 if (v.GetMajor() < Anope::VersionMajor() || (v.GetMajor() == Anope::VersionMajor() && v.GetMinor() < Anope::VersionMinor()))
00196 {
00197 Log() << "Module " << modname << " is compiled against an older version of Anope " << v.GetMajor() << "." << v.GetMinor() << ", this is " << Anope::VersionShort();
00198 DeleteModule(m);
00199 return MOD_ERR_VERSION;
00200 }
00201 else if (v.GetMajor() > Anope::VersionMajor() || (v.GetMajor() == Anope::VersionMajor() && v.GetMinor() > Anope::VersionMinor()))
00202 {
00203 Log() << "Module " << modname << " is compiled against a newer version of Anope " << v.GetMajor() << "." << v.GetMinor() << ", this is " << Anope::VersionShort();
00204 DeleteModule(m);
00205 return MOD_ERR_VERSION;
00206 }
00207 else if (v.GetPatch() < Anope::VersionPatch())
00208 {
00209 Log() << "Module " << modname << " is compiled against an older version of Anope, " << v.GetMajor() << "." << v.GetMinor() << "." << v.GetPatch() << ", this is " << Anope::VersionShort();
00210 DeleteModule(m);
00211 return MOD_ERR_VERSION;
00212 }
00213 else if (v.GetPatch() > Anope::VersionPatch())
00214 {
00215 Log() << "Module " << modname << " is compiled against a newer version of Anope, " << v.GetMajor() << "." << v.GetMinor() << "." << v.GetPatch() << ", this is " << Anope::VersionShort();
00216 DeleteModule(m);
00217 return MOD_ERR_VERSION;
00218 }
00219 else
00220 Log(LOG_DEBUG_2) << "Module " << modname << " is compiled against current version of Anope " << Anope::VersionShort();
00221
00222 Log(LOG_DEBUG) << "Module loaded.";
00223 FOREACH_MOD(I_OnModuleLoad, OnModuleLoad(u, m));
00224
00225 return MOD_ERR_OK;
00226 }
00227
00228 ModuleReturn ModuleManager::UnloadModule(Module *m, User *u)
00229 {
00230 if (!m)
00231 return MOD_ERR_PARAMS;
00232
00233 FOREACH_MOD(I_OnModuleUnload, OnModuleUnload(u, m));
00234
00235 return DeleteModule(m);
00236 }
00237
00238 Module *ModuleManager::FindModule(const Anope::string &name)
00239 {
00240 for (std::list<Module *>::const_iterator it = Modules.begin(), it_end = Modules.end(); it != it_end; ++it)
00241 {
00242 Module *m = *it;
00243
00244 if (m->name.equals_ci(name))
00245 return m;
00246 }
00247
00248 return NULL;
00249 }
00250
00251 Module *ModuleManager::FindFirstOf(ModType type)
00252 {
00253 for (std::list<Module *>::const_iterator it = Modules.begin(), it_end = Modules.end(); it != it_end; ++it)
00254 {
00255 Module *m = *it;
00256
00257 if (m->type == type)
00258 return m;
00259 }
00260
00261 return NULL;
00262 }
00263
00264 void ModuleManager::RequireVersion(int major, int minor, int patch)
00265 {
00266 if (Anope::VersionMajor() > major)
00267 return;
00268 else if (Anope::VersionMajor() == major)
00269 {
00270 if (minor == -1)
00271 return;
00272 else if (Anope::VersionMinor() > minor)
00273 return;
00274 else if (Anope::VersionMinor() == minor)
00275 {
00276 if (patch == -1)
00277 return;
00278 else if (Anope::VersionPatch() > patch)
00279 return;
00280 else if (Anope::VersionPatch() == patch)
00281 return;
00282 }
00283 }
00284
00285 throw ModuleException("This module requires version " + stringify(major) + "." + stringify(minor) + "." + stringify(patch) + " - this is " + Anope::VersionShort());
00286 }
00287
00288 ModuleReturn ModuleManager::DeleteModule(Module *m)
00289 {
00290 if (!m || !m->handle)
00291 return MOD_ERR_PARAMS;
00292
00293 void *handle = m->handle;
00294 Anope::string filename = m->filename;
00295
00296 Log(LOG_DEBUG) << "Unloading module " << m->name;
00297
00298 dlerror();
00299 void (*destroy_func)(Module *m) = function_cast<void (*)(Module *)>(dlsym(m->handle, "AnopeFini"));
00300 const char *err = dlerror();
00301 if (!destroy_func || (err && *err))
00302 {
00303 Log() << "No destroy function found for " << m->name << ", chancing delete...";
00304 delete m;
00305 }
00306 else
00307 destroy_func(m);
00308
00309 if (dlclose(handle))
00310 Log() << dlerror();
00311
00312 if (!filename.empty())
00313 unlink(filename.c_str());
00314
00315 return MOD_ERR_OK;
00316 }
00317
00318 bool ModuleManager::Attach(Implementation i, Module *mod)
00319 {
00320 if (std::find(EventHandlers[i].begin(), EventHandlers[i].end(), mod) != EventHandlers[i].end())
00321 return false;
00322
00323 EventHandlers[i].push_back(mod);
00324 return true;
00325 }
00326
00327 bool ModuleManager::Detach(Implementation i, Module *mod)
00328 {
00329 std::vector<Module *>::iterator x = std::find(EventHandlers[i].begin(), EventHandlers[i].end(), mod);
00330
00331 if (x == EventHandlers[i].end())
00332 return false;
00333
00334 EventHandlers[i].erase(x);
00335 return true;
00336 }
00337
00338 void ModuleManager::Attach(Implementation *i, Module *mod, size_t sz)
00339 {
00340 for (size_t n = 0; n < sz; ++n)
00341 Attach(i[n], mod);
00342 }
00343
00344 void ModuleManager::DetachAll(Module *mod)
00345 {
00346 for (size_t n = I_BEGIN + 1; n != I_END; ++n)
00347 Detach(static_cast<Implementation>(n), mod);
00348 }
00349
00350 bool ModuleManager::SetPriority(Module *mod, Priority s)
00351 {
00352 for (size_t n = I_BEGIN + 1; n != I_END; ++n)
00353 SetPriority(mod, static_cast<Implementation>(n), s);
00354
00355 return true;
00356 }
00357
00358 bool ModuleManager::SetPriority(Module *mod, Implementation i, Priority s, Module **modules, size_t sz)
00359 {
00367
00368
00369
00370 size_t source = 0;
00371 bool found = false;
00372 for (size_t x = 0, end = EventHandlers[i].size(); x != end; ++x)
00373 if (EventHandlers[i][x] == mod)
00374 {
00375 source = x;
00376 found = true;
00377 break;
00378 }
00379
00380
00381
00382
00383 if (!found)
00384 return false;
00385
00386 size_t swap_pos = 0;
00387 bool swap = true;
00388 switch (s)
00389 {
00390
00391 case PRIORITY_DONTCARE:
00392 swap = false;
00393 break;
00394
00395 case PRIORITY_FIRST:
00396 swap_pos = 0;
00397 break;
00398
00399 case PRIORITY_LAST:
00400 if (EventHandlers[i].empty())
00401 swap_pos = 0;
00402 else
00403 swap_pos = EventHandlers[i].size() - 1;
00404 break;
00405
00406 case PRIORITY_AFTER:
00407
00408 swap_pos = 0;
00409 swap = false;
00410 for (size_t x = 0, end = EventHandlers[i].size(); x != end; ++x)
00411 for (size_t n = 0; n < sz; ++n)
00412 if (modules[n] && EventHandlers[i][x] == modules[n] && x >= swap_pos && source <= swap_pos)
00413 {
00414 swap_pos = x;
00415 swap = true;
00416 }
00417 break;
00418
00419 case PRIORITY_BEFORE:
00420 swap_pos = EventHandlers[i].size() - 1;
00421 swap = false;
00422 for (size_t x = 0, end = EventHandlers[i].size(); x != end; ++x)
00423 for (size_t n = 0; n < sz; ++n)
00424 if (modules[n] && EventHandlers[i][x] == modules[n] && x <= swap_pos && source >= swap_pos)
00425 {
00426 swap = true;
00427 swap_pos = x;
00428 }
00429 }
00430
00431
00432 if (swap && swap_pos != source)
00433 {
00434
00435 int incrmnt = 1;
00436
00437 if (source > swap_pos)
00438 incrmnt = -1;
00439
00440 for (unsigned j = source; j != swap_pos; j += incrmnt)
00441 {
00442 if (j + incrmnt > EventHandlers[i].size() - 1 || j + incrmnt < 0)
00443 continue;
00444
00445 std::swap(EventHandlers[i][j], EventHandlers[i][j + incrmnt]);
00446 }
00447 }
00448
00449 return true;
00450 }
00451
00452 void ModuleManager::ClearCallBacks(Module *m)
00453 {
00454 while (!m->callbacks.empty())
00455 delete m->callbacks.front();
00456 }
00457
00458 void ModuleManager::UnloadAll()
00459 {
00460 std::vector<Anope::string> modules[MT_END];
00461 for (std::list<Module *>::iterator it = Modules.begin(), it_end = Modules.end(); it != it_end; ++it)
00462 if ((*it)->type != PROTOCOL && !(*it)->GetPermanent())
00463 modules[(*it)->type].push_back((*it)->name);
00464
00465 for (size_t i = MT_BEGIN + 1; i != MT_END; ++i)
00466 for (unsigned j = 0; j < modules[i].size(); ++j)
00467 {
00468 Module *m = FindModule(modules[i][j]);
00469 if (m != NULL)
00470 UnloadModule(m, NULL);
00471 }
00472 }
00473