mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-06-16 02:15:48 +00:00
329 lines
7.5 KiB
C
329 lines
7.5 KiB
C
#include "uwsgi.h"
|
|
|
|
extern struct uwsgi_server uwsgi;
|
|
|
|
#ifdef UWSGI_ELF
|
|
static void uwsgi_plugin_parse_section(char *filename) {
|
|
size_t s_len = 0;
|
|
char *buf = uwsgi_elf_section(filename, "uwsgi", &s_len);
|
|
if (buf) {
|
|
char *ctx = NULL;
|
|
char *p = strtok_r(buf, "\n", &ctx);
|
|
while (p) {
|
|
char *equal = strchr(p, '=');
|
|
if (equal) {
|
|
*equal = 0;
|
|
if (!strcmp(p, "requires")) {
|
|
if (!plugin_already_loaded(equal+1)) {
|
|
uwsgi_load_plugin(-1, equal + 1, NULL);
|
|
}
|
|
}
|
|
}
|
|
p = strtok_r(NULL, "\n", &ctx);
|
|
}
|
|
free(buf);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
struct uwsgi_plugin *uwsgi_plugin_get(const char *plugin) {
|
|
int i;
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
if (uwsgi.p[i]->name) {
|
|
if (!strcmp(plugin, uwsgi.p[i]->name)) {
|
|
#ifdef UWSGI_DEBUG
|
|
uwsgi_log("%s plugin already available\n", plugin);
|
|
#endif
|
|
return uwsgi.p[i];
|
|
}
|
|
}
|
|
if (uwsgi.p[i]->alias) {
|
|
if (!strcmp(plugin, uwsgi.p[i]->alias)) {
|
|
#ifdef UWSGI_DEBUG
|
|
uwsgi_log("%s plugin already available\n", plugin);
|
|
#endif
|
|
return uwsgi.p[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
|
|
|
if (uwsgi.gp[i]->name) {
|
|
if (!strcmp(plugin, uwsgi.gp[i]->name)) {
|
|
#ifdef UWSGI_DEBUG
|
|
uwsgi_log("%s plugin already available\n", plugin);
|
|
#endif
|
|
return uwsgi.p[i];
|
|
}
|
|
}
|
|
if (uwsgi.gp[i]->alias) {
|
|
if (!strcmp(plugin, uwsgi.gp[i]->alias)) {
|
|
#ifdef UWSGI_DEBUG
|
|
uwsgi_log("%s plugin already available\n", plugin);
|
|
#endif
|
|
return uwsgi.p[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int plugin_already_loaded(const char *plugin) {
|
|
struct uwsgi_plugin *up = uwsgi_plugin_get(plugin);
|
|
if (up) return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
|
|
|
void *plugin_handle = NULL;
|
|
char *plugin_abs_path = NULL;
|
|
char *plugin_filename = NULL;
|
|
|
|
int need_free = 0;
|
|
char *plugin_name = uwsgi_strip(uwsgi_str(plugin));
|
|
char *plugin_symbol_name_start = plugin_name;
|
|
|
|
struct uwsgi_plugin *up;
|
|
char linkpath_buf[1024], linkpath[1024];
|
|
int linkpath_size;
|
|
|
|
char *colon = strchr(plugin_name, ':');
|
|
if (colon) {
|
|
colon[0] = 0;
|
|
modifier = atoi(plugin_name);
|
|
plugin_name = colon + 1;
|
|
colon[0] = ':';
|
|
}
|
|
|
|
char *init_func = strchr(plugin_name, '|');
|
|
if (init_func) {
|
|
init_func[0] = 0;
|
|
init_func++;
|
|
}
|
|
|
|
if (!uwsgi_endswith(plugin_name, "_plugin.so")) {
|
|
plugin_name = uwsgi_concat2(plugin_name, "_plugin.so");
|
|
need_free = 1;
|
|
}
|
|
|
|
plugin_symbol_name_start = plugin_name;
|
|
|
|
// step 1: check for absolute plugin (stop if it fails)
|
|
if (strchr(plugin_name, '/')) {
|
|
#ifdef UWSGI_ELF
|
|
uwsgi_plugin_parse_section(plugin_name);
|
|
#endif
|
|
plugin_handle = dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL);
|
|
if (!plugin_handle) {
|
|
if (!has_option)
|
|
uwsgi_log("%s\n", dlerror());
|
|
goto end;
|
|
}
|
|
plugin_symbol_name_start = uwsgi_get_last_char(plugin_name, '/');
|
|
plugin_symbol_name_start++;
|
|
plugin_abs_path = plugin_name;
|
|
goto success;
|
|
}
|
|
|
|
// step dir, check for user-supplied plugins directory
|
|
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
|
|
while (pdir) {
|
|
plugin_filename = uwsgi_concat3(pdir->value, "/", plugin_name);
|
|
#ifdef UWSGI_ELF
|
|
uwsgi_plugin_parse_section(plugin_filename);
|
|
#endif
|
|
plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);
|
|
if (plugin_handle) {
|
|
plugin_abs_path = plugin_filename;
|
|
//free(plugin_filename);
|
|
goto success;
|
|
}
|
|
free(plugin_filename);
|
|
plugin_filename = NULL;
|
|
pdir = pdir->next;
|
|
}
|
|
|
|
// last step: search in compile-time plugin_dir
|
|
if (!plugin_handle) {
|
|
plugin_filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", plugin_name);
|
|
#ifdef UWSGI_ELF
|
|
uwsgi_plugin_parse_section(plugin_filename);
|
|
#endif
|
|
plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);
|
|
plugin_abs_path = plugin_filename;
|
|
//free(plugin_filename);
|
|
}
|
|
|
|
success:
|
|
if (!plugin_handle) {
|
|
if (!has_option)
|
|
uwsgi_log("!!! UNABLE to load uWSGI plugin: %s !!!\n", dlerror());
|
|
}
|
|
else {
|
|
if (init_func) {
|
|
void (*plugin_init_func)() = dlsym(plugin_handle, init_func);
|
|
if (plugin_init_func) {
|
|
plugin_init_func();
|
|
}
|
|
}
|
|
char *plugin_entry_symbol = uwsgi_concat2n(plugin_symbol_name_start, strlen(plugin_symbol_name_start) - 3, "", 0);
|
|
up = dlsym(plugin_handle, plugin_entry_symbol);
|
|
if (!up) {
|
|
// is it a link ?
|
|
memset(linkpath_buf, 0, 1024);
|
|
memset(linkpath, 0, 1024);
|
|
if ((linkpath_size = readlink(plugin_abs_path, linkpath_buf, 1023)) > 0) {
|
|
do {
|
|
linkpath_buf[linkpath_size] = '\0';
|
|
strncpy(linkpath, linkpath_buf, linkpath_size + 1);
|
|
} while ((linkpath_size = readlink(linkpath, linkpath_buf, 1023)) > 0);
|
|
#ifdef UWSGI_DEBUG
|
|
uwsgi_log("%s\n", linkpath);
|
|
#endif
|
|
free(plugin_entry_symbol);
|
|
char *slash = uwsgi_get_last_char(linkpath, '/');
|
|
if (!slash) {
|
|
slash = linkpath;
|
|
}
|
|
else {
|
|
slash++;
|
|
}
|
|
plugin_entry_symbol = uwsgi_concat2n(slash, strlen(slash) - 3, "", 0);
|
|
up = dlsym(plugin_handle, plugin_entry_symbol);
|
|
}
|
|
}
|
|
if (up) {
|
|
if (!up->name) {
|
|
uwsgi_log("the loaded plugin (%s) has no .name attribute\n", plugin_name);
|
|
if (dlclose(plugin_handle)) {
|
|
uwsgi_error("dlclose()");
|
|
}
|
|
if (need_free)
|
|
free(plugin_name);
|
|
if (plugin_filename)
|
|
free(plugin_filename);
|
|
free(plugin_entry_symbol);
|
|
return NULL;
|
|
}
|
|
if (plugin_already_loaded(up->name)) {
|
|
if (dlclose(plugin_handle)) {
|
|
uwsgi_error("dlclose()");
|
|
}
|
|
if (need_free)
|
|
free(plugin_name);
|
|
if (plugin_filename)
|
|
free(plugin_filename);
|
|
free(plugin_entry_symbol);
|
|
return NULL;
|
|
}
|
|
if (has_option) {
|
|
struct uwsgi_option *op = up->options;
|
|
int found = 0;
|
|
while (op && op->name) {
|
|
if (!strcmp(has_option, op->name)) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
op++;
|
|
}
|
|
if (!found) {
|
|
if (dlclose(plugin_handle)) {
|
|
uwsgi_error("dlclose()");
|
|
}
|
|
if (need_free)
|
|
free(plugin_name);
|
|
if (plugin_filename)
|
|
free(plugin_filename);
|
|
free(plugin_entry_symbol);
|
|
return NULL;
|
|
}
|
|
|
|
}
|
|
if (modifier != -1) {
|
|
fill_plugin_table(modifier, up);
|
|
up->modifier1 = modifier;
|
|
}
|
|
else {
|
|
fill_plugin_table(up->modifier1, up);
|
|
}
|
|
if (need_free)
|
|
free(plugin_name);
|
|
if (plugin_filename)
|
|
free(plugin_filename);
|
|
free(plugin_entry_symbol);
|
|
|
|
if (up->on_load)
|
|
up->on_load();
|
|
return plugin_handle;
|
|
}
|
|
if (!has_option)
|
|
uwsgi_log("%s\n", dlerror());
|
|
}
|
|
|
|
end:
|
|
if (need_free)
|
|
free(plugin_name);
|
|
if (plugin_filename)
|
|
free(plugin_filename);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int uwsgi_try_autoload(char *option) {
|
|
DIR *d;
|
|
struct dirent *dp;
|
|
// step dir, check for user-supplied plugins directory
|
|
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
|
|
while (pdir) {
|
|
d = opendir(pdir->value);
|
|
if (d) {
|
|
while ((dp = readdir(d)) != NULL) {
|
|
if (uwsgi_endswith(dp->d_name, "_plugin.so")) {
|
|
char *filename = uwsgi_concat3(pdir->value, "/", dp->d_name);
|
|
if (uwsgi_load_plugin(-1, filename, option)) {
|
|
uwsgi_log("option \"%s\" found in plugin %s\n", option, filename);
|
|
free(filename);
|
|
closedir(d);
|
|
// add new options
|
|
build_options();
|
|
return 1;
|
|
}
|
|
free(filename);
|
|
}
|
|
}
|
|
closedir(d);
|
|
}
|
|
pdir = pdir->next;
|
|
}
|
|
|
|
// last step: search in compile-time plugin_dir
|
|
d = opendir(UWSGI_PLUGIN_DIR);
|
|
if (!d)
|
|
return 0;
|
|
|
|
while ((dp = readdir(d)) != NULL) {
|
|
if (uwsgi_endswith(dp->d_name, "_plugin.so")) {
|
|
char *filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", dp->d_name);
|
|
if (uwsgi_load_plugin(-1, filename, option)) {
|
|
uwsgi_log("option \"%s\" found in plugin %s\n", option, filename);
|
|
free(filename);
|
|
closedir(d);
|
|
// add new options
|
|
build_options();
|
|
return 1;
|
|
}
|
|
free(filename);
|
|
}
|
|
}
|
|
|
|
closedir(d);
|
|
|
|
return 0;
|
|
|
|
}
|