/** * Tries to find plugin with specified name (file name without suffix and path) * in standard plugin path. * If plugin is found, tries to load it, and if file is not valid plugin, error * will be reported. * Also check dependencies, and tries to load plugins that this depends on. * If anything fails, plugin won't be loaded, and error will be reported. * @param name Plugin name * @return Plugin load status */ PluginLoadStatus plugins_load(char *name) { PluginLoadStatus result = PLUG_FILE_NOT_FOUND; // Scan all configured plugin directories size_t count = config_getvalue_count(loadedPlugins->config, "pluginsdir"); for (size_t i = 0; i < count; i++) { DirList dl = dirs_load(config_getvalue_array_string( loadedPlugins->config, "pluginsdir", i, "./plugins/")); for (int f = 0; f < dl->filesCount; f++) { char *basename = dirs_basename(dl->files[f]->name); if (dl->files[f]->mode & S_IXUSR && dl->files[f]->mode & S_IFREG && strncmp(basename, name, strlen(name)) == 0) { result = plugins_loadplugin(dl->files[f]->path); } free(basename); if (result != PLUG_FILE_NOT_FOUND && result != PLUG_PATH_NOT_FOUND) { break; } } dirs_freelist(dl); if (result != PLUG_FILE_NOT_FOUND && result != PLUG_PATH_NOT_FOUND) { break; } } return result; } // plugins_load
static const char *exportdescription(const struct exportmode *mode, char *buffer, size_t buffersize) { char *result = buffer; enum indexcompression ic; static const char* compression_names[ic_count] = { "uncompressed" ,"gzipped" #ifdef HAVE_LIBBZ2 ,"bzip2ed" #endif }; bool needcomma = false, needellipsis = false; assert (buffersize > 50); *buffer++ = ' '; buffersize--; *buffer++ = '('; buffersize--; for (ic = ic_first ; ic < ic_count ; ic++) { if ((mode->compressions & IC_FLAG(ic)) != 0) { size_t l = strlen(compression_names[ic]); assert (buffersize > l+3); if (needcomma) { *buffer++ = ','; buffersize--; } memcpy(buffer, compression_names[ic], l); buffer += l; buffersize -= l; needcomma = true; } } /* should be long enough for the previous things in all cases */ assert (buffersize > 10); if (mode->hooks.count > 0) { int i; if (needcomma) { *buffer++ = ','; buffersize--; } strcpy(buffer, "script: "); buffer += 8; buffersize -= 8; needcomma = false; for (i = 0 ; i < mode->hooks.count ; i++) { const char *hook = dirs_basename(mode->hooks.values[i]); size_t l = strlen(hook); if (buffersize < 6) { needellipsis = true; break; } if (needcomma) { *buffer++ = ','; buffersize--; } if (l > buffersize - 5) { memcpy(buffer, hook, buffersize-5); buffer += (buffersize-5); buffersize -= (buffersize-5); needellipsis = true; break; } else { memcpy(buffer, hook, l); buffer += l; buffersize -= l; assert (buffersize >= 2); } needcomma = true; } } if (needellipsis) { /* moveing backward here is easier than checking above */ if (buffersize < 5) { buffer -= (5 - buffersize); buffersize = 5; } *buffer++ = '.'; buffersize--; *buffer++ = '.'; buffersize--; *buffer++ = '.'; buffersize--; } assert (buffersize >= 2); *buffer++ = ')'; buffersize--; *buffer = '\0'; return result; }
/** * Load plugin in exactly given filename. It checks plugin's dependencies, * and tries to load them too. * @param path Path to plugin * @return Plugin load status */ PluginLoadStatus plugins_loadplugin(char *path) { PluginLoadStatus result = PLUG_OK; char *pathdup = path; if (file_exists(pathdup)) { char *basename = dirs_basename(pathdup); if (plugins_isloaded(basename)) { free(basename); printError("plugins", "Plugin %s is already loaded.", pathdup); return PLUG_ALREADY_LOADED; } printError("plugins", "Loading plugin %s", pathdup); Plugin plugin = malloc(sizeof(struct sPlugin)); // Add plugin to linked list, for circular dependency check plugin->prev = loadedPlugins->last; plugin->next = NULL; if (loadedPlugins->last != NULL) { loadedPlugins->last->next = plugin; } else { loadedPlugins->first = plugin; } loadedPlugins->last = plugin; plugin->handle = dlopen(pathdup, RTLD_LAZY | RTLD_GLOBAL); if (plugin->handle != NULL) { plugin->name = basename; plugin->path = strdup(path); plugin->info = malloc(sizeof(PluginInfo)); plugin->info->name = NULL; plugin->info->author = NULL; plugin->info->version = NULL; plugin->info->customData = NULL; plugin->info->irc = loadedPlugins->irc; plugin->info->config = loadedPlugins->config; plugin->info->events = loadedPlugins->events; plugin->info->socketpool = loadedPlugins->socketpool; plugin->deps = NULL; plugin->init = (PluginInitPrototype *)dlsym( plugin->handle, "PluginInit"); plugin->done = (PluginDonePrototype *)dlsym( plugin->handle, "PluginDone"); plugin->beforeDepsUnload = (PluginDonePrototype *)dlsym( plugin->handle, "PluginBeforeUnload"); if (plugin->init != NULL && plugin->done != NULL) { // Scan plugin dependencies. PluginLoadStatus depsLoad = PLUG_OK; // PluginDeps function is optional. PluginDepsPrototype *plugindeps = (PluginDepsPrototype *)dlsym(plugin->handle, "PluginDeps"); if (plugindeps != NULL) { plugindeps(&plugin->deps); if (plugin->deps != NULL) { TOKENS tok = tokenizer_tokenize(plugin->deps, ','); for (size_t i = 0; i < tok->count; i++) { if (!plugins_isloaded(tokenizer_gettok(tok, i))) { depsLoad = plugins_load( tokenizer_gettok(tok, i)); if (depsLoad != PLUG_OK) { break; } } } tokenizer_free(tok); } } if (depsLoad == PLUG_OK) { // And finally, when everything is OK, call init function. plugin->init(plugin->info); result = PLUG_OK; } else { printError("plugins", "Plugin %s will not be loaded, " "because of dependency error.", path); result = PLUG_DEPENDENCY; } } else { // If no init and done functions were found. plugins_unloadplugin(plugin); printError("plugins", "%s is not valid plugin.", pathdup); result = PLUG_INVALID; } // Unload plugin if it's loading failed. if (result != PLUG_OK) { plugin->done = NULL; plugins_unloadplugin(plugin); } // End of plug->handle != NULL } else { // Remove plugin from linked list loadedPlugins->last = loadedPlugins->last->prev; loadedPlugins->last->next = NULL; printError("plugins", "Plugin loading error: %s", dlerror()); result = PLUG_DL_ERROR; } } else { printError("plugins", "Plugin file not found."); result = PLUG_FILE_NOT_FOUND; } return result; } // plugins_loadplugin
static inline retvalue morgue_name(const char *filekey, char **name_p, int *fd_p) { const char *name = dirs_basename(filekey); char *firsttry = calc_dirconcat(global.morguedir, name); int fd, en, number; retvalue r; if (FAILEDTOALLOC(firsttry)) return RET_ERROR_OOM; fd = open(firsttry, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY, 0666); if (fd >= 0) { assert (fd > 2); *name_p = firsttry; *fd_p = fd; return RET_OK; } en = errno; if (en == ENOENT) { r = dirs_make_recursive(global.morguedir); if (RET_WAS_ERROR(r)) { free(firsttry); return r; } /* try again */ fd = open(firsttry, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY, 0666); if (fd >= 0) { assert (fd > 2); *name_p = firsttry; *fd_p = fd; return RET_OK; } en = errno; } if (en != EEXIST) { fprintf(stderr, "error %d creating morgue-file %s: %s\n", en, firsttry, strerror(en)); free(firsttry); return RET_ERRNO(en); } /* file exists, try names with -number appended: */ for (number = 1 ; number < 1000 ; number++) { char *try = mprintf("%s-%d", firsttry, number); if (FAILEDTOALLOC(try)) { free(firsttry); return RET_ERROR_OOM; } fd = open(try, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY, 0666); if (fd >= 0) { assert (fd > 2); free(firsttry); *name_p = try; *fd_p = fd; return RET_OK; } free(try); } free(firsttry); fprintf(stderr, "Could not create a new file '%s' in morguedir '%s'!\n", name, global.morguedir); return RET_ERROR; }