mirror of
https://github.com/Harshit-Dhanwalkar/AsciiCam.git
synced 2026-06-21 10:58:05 +02:00
171 lines
4 KiB
C
171 lines
4 KiB
C
#include "plugins.h"
|
|
|
|
#include <dlfcn.h>
|
|
#include <fcntl.h>
|
|
#include <libgen.h> // dirname()
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/inotify.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
static int copy_file(const char *src, const char *dst) {
|
|
int fd_src = open(src, O_RDONLY);
|
|
if (fd_src < 0) {
|
|
perror("[plugin] open src");
|
|
return -1;
|
|
}
|
|
|
|
int fd_dst = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0755);
|
|
if (fd_dst < 0) {
|
|
perror("[plugin] open dst");
|
|
close(fd_src);
|
|
return -1;
|
|
}
|
|
|
|
char buf[65536];
|
|
ssize_t n;
|
|
while ((n = read(fd_src, buf, sizeof(buf))) > 0) {
|
|
if (write(fd_dst, buf, (size_t)n) != n) {
|
|
perror("[plugin] write");
|
|
close(fd_src);
|
|
close(fd_dst);
|
|
unlink(dst);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
close(fd_src);
|
|
close(fd_dst);
|
|
return 0;
|
|
}
|
|
|
|
int plugin_load(plugin_loader_t *pl, const char *path) {
|
|
// Close old handle
|
|
if (pl->dl_handle) {
|
|
dlclose(pl->dl_handle);
|
|
pl->dl_handle = NULL;
|
|
pl->plugin = NULL;
|
|
}
|
|
|
|
// Delete the previous temp copy
|
|
if (pl->tmp_path[0] != '\0') {
|
|
unlink(pl->tmp_path);
|
|
pl->tmp_path[0] = '\0';
|
|
}
|
|
|
|
snprintf(pl->tmp_path, sizeof(pl->tmp_path), "%s.%ld.tmp", path,
|
|
(long)time(NULL));
|
|
|
|
if (copy_file(path, pl->tmp_path) < 0) {
|
|
fprintf(stderr, "[plugin] could not copy %s -> %s\n", path, pl->tmp_path);
|
|
pl->tmp_path[0] = '\0';
|
|
return -1;
|
|
}
|
|
|
|
pl->dl_handle = dlopen(pl->tmp_path, RTLD_NOW | RTLD_LOCAL);
|
|
if (!pl->dl_handle) {
|
|
fprintf(stderr, "[plugin] dlopen: %s\n", dlerror());
|
|
unlink(pl->tmp_path);
|
|
pl->tmp_path[0] = '\0';
|
|
return -1;
|
|
}
|
|
|
|
void *sym = dlsym(pl->dl_handle, "plugin_get");
|
|
if (!sym) {
|
|
fprintf(stderr, "[plugin] dlsym: %s\n", dlerror());
|
|
dlclose(pl->dl_handle);
|
|
pl->dl_handle = NULL;
|
|
return -1;
|
|
}
|
|
|
|
filter_plugin_t *(*get_plugin)(void) = dlsym(pl->dl_handle, "plugin_get");
|
|
if (!get_plugin) {
|
|
fprintf(stderr, "[plugin] dlsym: %s\n", dlerror());
|
|
dlclose(pl->dl_handle);
|
|
pl->dl_handle = NULL;
|
|
unlink(pl->tmp_path);
|
|
pl->tmp_path[0] = '\0';
|
|
return -1;
|
|
}
|
|
|
|
pl->plugin = get_plugin();
|
|
fprintf(stderr, "[plugin] loaded: %s\n", pl->plugin->name);
|
|
return 0;
|
|
}
|
|
|
|
void plugin_watch_init(plugin_loader_t *pl, const char *path) {
|
|
strncpy(pl->path, path, sizeof(pl->path) - 1);
|
|
|
|
char dir_copy[256];
|
|
strncpy(dir_copy, path, sizeof(dir_copy) - 1);
|
|
const char *dir = dirname(dir_copy);
|
|
|
|
pl->inotify_fd = inotify_init1(IN_NONBLOCK);
|
|
if (pl->inotify_fd < 0) {
|
|
perror("[plugin] inotify_init1");
|
|
return;
|
|
}
|
|
|
|
pl->inotify_wd =
|
|
inotify_add_watch(pl->inotify_fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO);
|
|
|
|
if (pl->inotify_wd < 0)
|
|
perror("[plugin] inotify_add_watch");
|
|
}
|
|
|
|
void plugin_check_reload(plugin_loader_t *pl) {
|
|
if (pl->inotify_fd < 0)
|
|
return;
|
|
|
|
// Read all available events from the non-blocking queue
|
|
char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event))));
|
|
// char buf[sizeof(struct inotify_event) + 256];
|
|
ssize_t n = read(pl->inotify_fd, buf, sizeof(buf));
|
|
if (n <= 0)
|
|
return; // No new filesystem modifications detected
|
|
|
|
char path_copy[256];
|
|
strncpy(path_copy, pl->path, sizeof(path_copy) - 1);
|
|
const char *soname = basename(path_copy);
|
|
|
|
int relevant = 0;
|
|
const char *p = buf;
|
|
while (p < buf + n) {
|
|
const struct inotify_event *ev = (const struct inotify_event *)p;
|
|
if (ev->len > 0 && strcmp(ev->name, soname) == 0) {
|
|
relevant = 1;
|
|
break;
|
|
}
|
|
p += sizeof(*ev) + ev->len;
|
|
}
|
|
|
|
if (!relevant)
|
|
return;
|
|
|
|
usleep(150000); // 150ms delay for linker
|
|
|
|
if (plugin_load(pl, pl->path) == 0) {
|
|
fprintf(stderr, "\n[plugin] Hot-swapped: %s\n", pl->plugin->name);
|
|
} else {
|
|
fprintf(stderr, "\n[plugin] Hot-swap failed. Retaining active filter.\n");
|
|
}
|
|
}
|
|
|
|
void plugin_cleanup(plugin_loader_t *pl) {
|
|
if (pl->dl_handle) {
|
|
dlclose(pl->dl_handle);
|
|
pl->dl_handle = NULL;
|
|
}
|
|
|
|
// Remove tmp copy
|
|
if (pl->tmp_path[0] != '\0') {
|
|
unlink(pl->tmp_path);
|
|
pl->tmp_path[0] = '\0';
|
|
}
|
|
|
|
if (pl->inotify_fd >= 0) {
|
|
close(pl->inotify_fd);
|
|
pl->inotify_fd = -1;
|
|
}
|
|
}
|