aboutsummaryrefslogtreecommitdiffhomepage
path: root/plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugin.c')
-rw-r--r--plugin.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/plugin.c b/plugin.c
new file mode 100644
index 0000000..561e131
--- /dev/null
+++ b/plugin.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include "plugin.h"
+
+size_t plugins = 0;
+void** plugin_handle = NULL;
+
+static int plugin_attach(char* path, char* file){
+ plugin_init init = NULL;
+ void* handle = NULL;
+
+ char* lib = calloc(strlen(path) + strlen(file) + 1, sizeof(char));
+ if(!lib){
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 1;
+ }
+
+ snprintf(lib, strlen(path) + strlen(file) + 1, "%s%s", path, file);
+
+ handle = dlopen(lib, RTLD_NOW);
+ if(!handle){
+ fprintf(stderr, "Failed to load plugin %s: %s\n", lib, dlerror());
+ free(lib);
+ return 0;
+ }
+
+ init = dlsym(handle, "init");
+ if(init){
+ if(init()){
+ fprintf(stderr, "Plugin %s failed to initialize\n", lib);
+ dlclose(handle);
+ free(lib);
+ return 1;
+ }
+ }
+ else{
+ return 0;
+ }
+
+ plugin_handle = realloc(plugin_handle, (plugins + 1) * sizeof(void*));
+ if(!plugin_handle){
+ fprintf(stderr, "Failed to allocate memory\n");
+ dlclose(handle);
+ free(lib);
+ return 1;
+ }
+
+ plugin_handle[plugins] = handle;
+ plugins++;
+
+ return 0;
+}
+
+int plugins_load(char* path){
+ int rv = -1;
+
+ struct dirent* entry;
+ struct stat file_stat;
+ DIR* directory = opendir(path);
+ if(!directory){
+ fprintf(stderr, "Failed to open plugin search path %s: %s\n", path, strerror(errno));
+ return 1;
+ }
+
+ for(entry = readdir(directory); entry; entry = readdir(directory)){
+ if(fstatat(dirfd(directory), entry->d_name, &file_stat, 0) < 0){
+ fprintf(stderr, "Failed to stat %s: %s\n", entry->d_name, strerror(errno));
+ continue;
+ }
+
+ if(!S_ISREG(file_stat.st_mode)){
+ continue;
+ }
+
+ if(!(file_stat.st_mode & S_IXUSR)){
+ continue;
+ }
+
+ if(plugin_attach(path, entry->d_name)){
+ goto load_done;
+ }
+ }
+ rv = 0;
+
+load_done:
+ if(closedir(directory) < 0){
+ fprintf(stderr, "Failed to close plugin directory %s: %s\n", path, strerror(errno));
+ return -1;
+ }
+ return rv;
+}
+
+int plugins_close(){
+ size_t u;
+ for(u = 0; u < plugins; u++){
+ if(dlclose(plugin_handle[u])){
+ fprintf(stderr, "Failed to unload plugin: %s\n", dlerror());
+ }
+ }
+
+ free(plugin_handle);
+ plugins = 0;
+ return 0;
+}