diff options
Diffstat (limited to 'plugins.c')
-rw-r--r-- | plugins.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/plugins.c b/plugins.c new file mode 100644 index 0000000..32a8d16 --- /dev/null +++ b/plugins.c @@ -0,0 +1,143 @@ +/* + * Copyright 2019 ~ 2021 YuutaW Minecraft, All Rights Reserved. + * Proprietary and confidential. + * Unauthorized copying of any parts of this file, via any medium is strictly prohibited. + * Written by Yuuta Liang <yuuta@yuuta.moe>, April 2021. + */ + +#include "plugins.h" +#include "common.h" +#include "plugin_registry.h" + +#include <stdlib.h> +#include <stdio.h> +#include <dlfcn.h> +#include <stdbool.h> +#include <string.h> + +static const void *plugin_dlsym(int stderr_fd, void *handle, const bool mandatory, const char *name) +{ + const void *sym = dlsym(handle, name); + if(sym == NULL) + { + if(mandatory) + { + dprintf(stderr_fd, _("Cannot load %s, aborting: %s.\n"), name, dlerror()); + } + else + { + dprintf(stderr_fd, _("Cannot load %s, ignoring: %s.\n"), name, dlerror()); + } + return NULL; + } + return sym; +} + +int plugin_unload(int stderr_fd, struct plugin *plugin) +{ + if(plugin->fc_unload != NULL) + { + struct epg_handle hdl; + plugcall_setup_handle(plugin, &hdl); + int unload_r = plugin->fc_unload(&hdl); + if(unload_r) + { + dprintf(stderr_fd, _("Cannot unload plugin: it returned an error: %d.\n"), unload_r); + return unload_r; + } + } + if(plugin->handle != NULL) + { + dlclose(plugin->handle); + plugin->handle = NULL; + } + return 0; +} + +static int plugin_load_v1(int stderr_fd, struct plugin *out) +{ + int r = 0; + const void *sym; + sym = plugin_dlsym(stderr_fd, out->handle, true, "epg_name"); + if(sym == NULL) + { + r = 64; + goto cleanup; + } + out->name = *(char**)sym; + out->fc_load = plugin_dlsym(stderr_fd, out->handle, false, "epg_load"); + out->fc_unload = plugin_dlsym(stderr_fd, out->handle, false, "epg_unload"); + out->fc_player_join = plugin_dlsym(stderr_fd, out->handle, false, "epg_player_join"); + out->fc_player_leave = plugin_dlsym(stderr_fd, out->handle, false, "epg_player_leave"); + out->fc_player_say = plugin_dlsym(stderr_fd, out->handle, false, "epg_player_say"); + out->fc_player_die = plugin_dlsym(stderr_fd, out->handle, false, "epg_player_die"); + out->fc_player_achievement = plugin_dlsym(stderr_fd, out->handle, false, "epg_player_achievement"); + out->fc_player_challenge = plugin_dlsym(stderr_fd, out->handle, false, "epg_player_challenge"); + out->fc_player_goal = plugin_dlsym(stderr_fd, out->handle, false, "epg_player_goal"); + out->fc_server_stopping = plugin_dlsym(stderr_fd, out->handle, false, "epg_server_stopping"); + out->fc_server_starting = plugin_dlsym(stderr_fd, out->handle, false, "epg_server_starting"); + out->fc_server_started = plugin_dlsym(stderr_fd, out->handle, false, "epg_server_started"); + goto cleanup; +cleanup: + return r; +} + +int plugin_load(int stderr_fd, const char *path, const int id, struct plugin *out) +{ + int r = 0; + out->id = id; + out->path = path; + out->handle = NULL; + out->name = NULL; + out->version = 0; + out->fc_load = NULL; + out->fc_unload = NULL; + out->fc_player_join = NULL; + out->fc_player_leave = NULL; + out->fc_player_say = NULL; + out->fc_player_die = NULL; + out->fc_player_achievement = NULL; + out->fc_player_challenge = NULL; + out->fc_player_goal = NULL; + out->fc_server_stopping = NULL; + out->fc_server_starting = NULL; + out->fc_server_started = NULL; + + void *handle = dlopen(path, RTLD_LAZY); + if(handle == NULL) + { + dprintf(stderr_fd, _("Cannot load %s: %s.\n"), path, dlerror()); + r = 1; + goto cleanup; + } + out->handle = handle; + const void *sym = plugin_dlsym(stderr_fd, handle, true, "epg_version"); + if(sym == NULL) + { + r = 64; + goto cleanup; + } + out->version = *(uint32_t*)sym; + switch(out->version) + { + case 1: + r = plugin_load_v1(stderr_fd, out); + if(r) goto cleanup; + break; + default: + dprintf(stderr_fd, _("Unsupported plugin %s: Incompatible with version %u.\n"), path, out->version); + break; + } + struct epg_handle hdl; + plugcall_setup_handle(out, &hdl); + r = out->fc_load(&hdl); + if(r) + { + dprintf(stderr_fd, _("Cannot load plugin: it returned an error: %d.\n"), r); + goto cleanup; + } + goto cleanup; +cleanup: + if(r) plugin_unload(stderr_fd, out); + return r; +} |