aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2025-11-23 01:12:43 -0600
committerLibravatar bigfoot547 <[email protected]>2025-11-23 01:12:43 -0600
commitbc6575839f8f826b6e3537f5f88970f4444a06c5 (patch)
treea1f9973beda654b77690bcf5672335e179f0a7c3 /src
parentignore this commit (diff)
more work on plugins
Diffstat (limited to 'src')
-rw-r--r--src/main.c11
-rw-r--r--src/plugins.c157
2 files changed, 156 insertions, 12 deletions
diff --git a/src/main.c b/src/main.c
index 50baf66..36eeaf7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,6 +4,7 @@
#include <stdarg.h>
#include "pipeline.h"
+#include "plugins.h"
PIPELINE_STAGE static int identity_stage_handle(const ptx_pipeline_ctx_t *ctx, const void *data, size_t sz)
{
@@ -119,5 +120,15 @@ int main(void) {
ptx_pipeline_free(pl);
+ ptx_plugin_manager_t *mgr = ptx_plugin_manager_new();
+ if (!mgr) {
+ fputs("Failed to allocate plugin manager\n", stderr);
+ return 1;
+ }
+
+ ptx_plugin_manager_load_dir(mgr, "plugins");
+
+ ptx_plugin_manager_free(mgr);
+
return 0;
}
diff --git a/src/plugins.c b/src/plugins.c
index f2f8d14..b96aade 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -3,19 +3,35 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
-
+#include <assert.h>
+#include <dlfcn.h>
#include <sys/types.h>
#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
struct ptx__plugin_manager_tag
{
- size_t sz_plugins;
- ptx_plugin_t *plugins;
+ ptx_plugin_t *pl_head, *pl_tail;
};
struct ptx__plugin_handle_tag
{
- char *path;
+ /* what plugin manager is this plugin known to? */
+ ptx_plugin_manager_t *manager;
+
+ /* handle to library */
+ void *modp;
+ const struct ptx_plugin_desc *desc;
+
+ /* plugin list entries */
+ ptx_plugin_t *prev;
+ ptx_plugin_t *next;
+
+ int path_fd;
+ /* plugin filename */
+ char fname[1];
};
ptx_plugin_manager_t *ptx_plugin_manager_new(void)
@@ -24,40 +40,157 @@ ptx_plugin_manager_t *ptx_plugin_manager_new(void)
if (!mgr) return NULL;
/* do init */
- mgr->sz_plugins = 0;
- mgr->plugins = NULL;
+ mgr->pl_head = mgr->pl_tail = NULL;
return mgr;
}
+/* inform the plugin that it is about to be unloaded. It should clean up its resources. */
+static void deinit_plugin(ptx_plugin_t *plugin);
+
+/* unload/cleanup/free the plugin. */
+static void free_plugin(ptx_plugin_t *plugin);
+
void ptx_plugin_manager_free(ptx_plugin_manager_t *mgr)
{
if (!mgr) return;
/* do cleanup */
+ for (ptx_plugin_t *plugin = mgr->pl_head, *next; plugin; plugin = next) {
+ next = plugin->next;
+ deinit_plugin(plugin);
+ free_plugin(plugin);
+ }
free(mgr);
return;
}
-int ptx_plugin_manager_load_dir(ptx_plugin_manager_t *mgr, const char *dirnam)
+static ptx_plugin_t *load_plugin(ptx_plugin_manager_t *manager, const char *plugin_file, const char *plugin_fname)
+{
+ /* define and initialize all variables to be cleaned up here! */
+ size_t fnamelen = strlen(plugin_fname);
+
+ ptx_plugin_t *plugin = NULL;
+ void *mod_dl = NULL;
+ const struct ptx_plugin_desc *pl_desc;
+
+ plugin = calloc(1, sizeof(ptx_plugin_t) + fnamelen);
+ if (!plugin) {
+ fprintf(stderr, "(plugin) malloc (loading %s): %s\n", plugin_file, strerror(errno));
+ /* FIXME: maybe abort() for these sorts of issues? */
+ goto cleanup;
+ }
+
+ plugin->manager = manager;
+ memcpy(plugin->fname, plugin_fname, fnamelen); /* NUL-termination achieved thanks to calloc */
+
+ mod_dl = dlopen(plugin_file, RTLD_NOW | RTLD_LOCAL);
+ if (!mod_dl) {
+ fprintf(stderr, "(plugin) dlopen: failed to load %s: %s\n", plugin_fname, dlerror());
+ goto cleanup;
+ }
+
+ plugin->modp = mod_dl;
+
+ pl_desc = dlsym(mod_dl, PTX_STR(PTX__INTERNAL_PLUGIN_DESC_SYM));
+ if (!pl_desc) {
+ fprintf(stderr, "(plugin) dlsym(descriptor): failed to load %s: %s\n", plugin_fname, dlerror());
+ goto cleanup;
+ }
+
+ plugin->desc = pl_desc;
+
+ return plugin;
+
+cleanup:
+ if (mod_dl) dlclose(mod_dl);
+ free(plugin);
+
+ return NULL;
+}
+
+#define PATHBUF_LEN (32)
+int ptx_plugin_manager_load_dir(ptx_plugin_manager_t *mgr, const char *dirname)
{
struct dirent *ent;
- DIR *dir = opendir(dirnam);
+ char pl_pathbuf[PATHBUF_LEN] = { 0 };
+ struct stat st;
+
+ DIR *dir = opendir(dirname);
if (!dir) {
- fprintf(stderr, "Failed to load plugins from %s (opendir): %s\n", dirnam, strerror(errno));
+ fprintf(stderr, "Failed to load plugins from %s (opendir): %s\n", dirname, strerror(errno));
return -1;
}
+ int pl_dir_fd = dirfd(dir);
+ assert(pl_dir_fd >= 0);
+
while ((errno = 0, ent = readdir(dir))) {
-
+ int pl_fd = openat(pl_dir_fd, ent->d_name, O_PATH);
+ if (pl_fd < 0) {
+ fprintf(stderr, "(plugin) openat: failed to open %s/%s: %s\n", dirname, ent->d_name, strerror(errno));
+ continue;
+ }
+
+ if (fstat(pl_fd, &st) < 0) {
+ fprintf(stderr, "(plugin) fstat: failed to stat %s/%s: %s\n", dirname, ent->d_name, strerror(errno));
+ goto cleanup_iter;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ goto cleanup_iter; /* not a file. skip silently */
+ }
+
+ int rlen = snprintf(pl_pathbuf, PATHBUF_LEN, "/proc/self/fd/%d", pl_fd);
+ assert(rlen < PATHBUF_LEN);
+ assert(pl_pathbuf[PATHBUF_LEN-1] == '\0');
+
+ ptx_plugin_t *plugin = load_plugin(mgr, pl_pathbuf, ent->d_name);
+ if (!plugin) goto cleanup_iter; /* error has been reported by load_plugin already. */
+
+ plugin->path_fd = pl_fd;
+
+ if (mgr->pl_head) {
+ assert(mgr->pl_tail);
+
+ mgr->pl_tail->next = plugin;
+ plugin->prev = mgr->pl_tail;
+ plugin->next = NULL;
+ mgr->pl_tail = plugin;
+ } else {
+ assert(!mgr->pl_tail);
+ plugin->prev = plugin->next = NULL;
+ mgr->pl_head = mgr->pl_tail = plugin;
+ }
+
+ continue;
+
+cleanup_iter:
+ close(pl_fd);
}
- if (errno != 0) {
- fprintf(stderr, "Error reading entries from %s (readdir): %s\n", dirnam, strerror(errno));
+ int errno_save = errno;
+ closedir(dir);
+
+ if (errno_save != 0) {
+ fprintf(stderr, "Error reading entries from %s (readdir): %s\n", dirname, strerror(errno));
return -1;
}
return 0;
}
+
+static void deinit_plugin(ptx_plugin_t *plugin)
+{
+ /* TODO */
+ UNUSED(plugin);
+}
+
+static void free_plugin(ptx_plugin_t *plugin)
+{
+ dlclose(plugin->modp);
+ close(plugin->path_fd);
+ free(plugin);
+}