commit b6a4bb5a58c9f39bed8037cfb3c0cc22159bd6cd Author: ari melody Date: Mon May 5 17:44:20 2025 +0100 first commit 🎉 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6ce625a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +pluginhost +plugins/**/*.so +**/*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..643e15c --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +CC = clang +CFLAGS = -std=c17 -g -Wall -O2 -fPIC + +EXEC = pluginhost + +SRCS = $(shell find src -name '*.c') +OBJS = $(SRCS:.c=.o) + +PLUGINS = $(shell ls plugins) + +.PHONY: $(EXEC) + +all: $(EXEC) all_plugins + +$(EXEC): $(OBJS) + $(CC) $(CFLAGS) -o $(EXEC) $(OBJS) + +src/%.c.o: src/%.c + $(CC) $(CFLAGS) -o $@ -c $< + +all_plugins: + for plugin in $(PLUGINS); do \ + $(MAKE) -C plugins/$$plugin; \ + done + +clean: + rm -f $(EXEC) $(OBJS) + for plugin in $(PLUGINS); do \ + $(MAKE) -C plugins/$$plugin clean; \ + done diff --git a/include/ariplugin.h b/include/ariplugin.h new file mode 100644 index 0000000..4ade3e9 --- /dev/null +++ b/include/ariplugin.h @@ -0,0 +1,7 @@ +#ifndef ARIPLUGIN_H +#define ARIPLUGIN_H + +int ari_plugin_load(); +int ari_plugin_unload(); + +#endif // ARIPLUGIN_H diff --git a/plugins/aridoodle/Makefile b/plugins/aridoodle/Makefile new file mode 100644 index 0000000..9f75415 --- /dev/null +++ b/plugins/aridoodle/Makefile @@ -0,0 +1,22 @@ +CC = clang +CFLAGS = -std=c17 -g -Wall +LD = ld +LDFLAGS = -shared -g -lc + +LIBRARY = aridoodle.so + +SRCS = $(shell find . -name '*.c') +OBJS = $(SRCS:.c=.o) + +.PHONY: all + +all: $(LIBRARY) + +$(LIBRARY): $(OBJS) + $(LD) $(LDFLAGS) -o $(LIBRARY) $(OBJS) + +%.c.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +clean: + rm -f $(OBJS) $(LIBRARY) diff --git a/plugins/aridoodle/aridoodle.c b/plugins/aridoodle/aridoodle.c new file mode 100644 index 0000000..fff00ab --- /dev/null +++ b/plugins/aridoodle/aridoodle.c @@ -0,0 +1,12 @@ +#include +#include "../../include/ariplugin.h" + +int ari_plugin_load() { + printf("hello from aridoodle :aridoodle:\n"); + return 0; +} + +int ari_plugin_unload() { + printf("aridoodle says byebye!\n"); + return 0; +} diff --git a/plugins/test/Makefile b/plugins/test/Makefile new file mode 100644 index 0000000..813ad3f --- /dev/null +++ b/plugins/test/Makefile @@ -0,0 +1,22 @@ +CC = clang +CFLAGS = -std=c17 -g -Wall +LD = ld +LDFLAGS = -shared -g -lc + +LIBRARY = test.so + +SRCS = $(shell find . -name '*.c') +OBJS = $(SRCS:.c=.o) + +.PHONY: all + +all: $(LIBRARY) + +$(LIBRARY): $(OBJS) + $(LD) $(LDFLAGS) -o $(LIBRARY) $(OBJS) + +%.c.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +clean: + rm -f $(OBJS) $(LIBRARY) diff --git a/plugins/test/test.c b/plugins/test/test.c new file mode 100644 index 0000000..9a945ed --- /dev/null +++ b/plugins/test/test.c @@ -0,0 +1,12 @@ +#include +#include "../../include/ariplugin.h" + +int ari_plugin_load() { + printf("hello from test plugin!\n"); + return 0; +} + +int ari_plugin_unload() { + printf("test plugin unloaded successfully!\n"); + return 0; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..b71e50c --- /dev/null +++ b/src/main.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LIBRARY_PATH_FMT "plugins/%s/%s.so" + +typedef struct { + char name[256]; + void *handle; + + int (*func_load)(void); + int (*func_unload)(void); +} Plugin; + +int main(int argc, char *argv[]) { + // find plugins + DIR *plugins_dir = opendir("plugins"); + if (plugins_dir == NULL) { + errx(EXIT_FAILURE, "failed to read plugins directory"); + } + + struct dirent *plugin_ent; + + size_t n_plugins = 0; + while ((plugin_ent = readdir(plugins_dir)) != NULL) { + if (!strcmp(".", plugin_ent->d_name)) + continue; + if (!strcmp("..", plugin_ent->d_name)) + continue; + n_plugins++; + } + + rewinddir(plugins_dir); + Plugin plugins[n_plugins]; + size_t n_plugins_ok = 0; + + while ((plugin_ent = readdir(plugins_dir)) != NULL) { + if (!strcmp(".", plugin_ent->d_name)) + continue; + if (!strcmp("..", plugin_ent->d_name)) + continue; + + char *error; + + strcpy(plugins[n_plugins_ok].name, plugin_ent->d_name); + char *library_path = NULL; + int len = snprintf(library_path, 0, LIBRARY_PATH_FMT, plugins[n_plugins_ok].name, plugins[n_plugins_ok].name); + + library_path = malloc(len); + sprintf(library_path, LIBRARY_PATH_FMT, plugins[n_plugins_ok].name, plugins[n_plugins_ok].name); + + plugins[n_plugins_ok].handle = dlopen(library_path, RTLD_LAZY); + if (!plugins[n_plugins_ok].handle) { + errx(EXIT_FAILURE, "failed to load plugin: %s\n", dlerror()); + } + + dlerror(); // clear errors + + plugins[n_plugins_ok].func_load = dlsym(plugins[n_plugins_ok].handle, "ari_plugin_load"); + plugins[n_plugins_ok].func_unload = dlsym(plugins[n_plugins_ok].handle, "ari_plugin_unload"); + + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "failed to initialise plugin \"%s\": %s\n", plugins[n_plugins_ok].name, error); + dlclose(plugins[n_plugins_ok].handle); + continue; + } + + int code = plugins[n_plugins_ok].func_load(); + if (code != EXIT_SUCCESS) { + fprintf(stderr, "warn: plugin \"%s\" returned code %d when loaded\n", plugins[n_plugins_ok].name, code); + } + + free(library_path); + + n_plugins_ok++; + } + + printf("%ld plugins loaded.\n", n_plugins_ok); + printf("press any key to continue..."); + getc(stdin); + + for (int i = 0; i < n_plugins; i++) { + if (plugins[n_plugins_ok].handle == NULL) { + continue; + } + + int code = plugins[i].func_unload(); + if (code != EXIT_SUCCESS) { + fprintf(stderr, "warn: plugin \"%s\" returned code %d when unloaded\n", plugins[i].name, code); + } + + dlclose(plugins[i].handle); + } + + closedir(plugins_dir); + + return 0; +}