From 03ed0973531708d855da1129f54ee6b3f933b0af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?= Date: Wed, 28 Oct 2020 14:02:03 +0100 Subject: [PATCH] ZyklonB: use XDG paths by default Install plugins to /usr/share rather than /usr/lib since they're arch-independent. Many precedents can be found for scripted plugins in /usr/share and fewer for /usr/lib. Look for plugins in all XDG data directories and repurpose the "plugin_dir" setting to override this behaviour. This adds some complexity to the bot but unifies the project. It might make sense to remove the "plugin_dir" setting. --- CMakeLists.txt | 5 ++--- config.h.in | 2 +- zyklonb.c | 38 ++++++++++++++++++++++++++++++-------- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ee87ab..7da0cd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,8 +132,6 @@ set (HAVE_EDITLINE "${WANT_LIBEDIT}") set (HAVE_LUA "${WITH_LUA}") include (GNUInstallDirs) -# ZyklonB is currently an odd duck but degesch follows normal XDG rules -set (zyklonb_plugin_dir ${CMAKE_INSTALL_LIBDIR}/zyklonb/plugins) configure_file (${PROJECT_SOURCE_DIR}/config.h.in ${PROJECT_BINARY_DIR}/config.h) include_directories (${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR}) @@ -187,8 +185,9 @@ add_custom_target (clang-tidy # Installation install (TARGETS zyklonb degesch kike DESTINATION ${CMAKE_INSTALL_BINDIR}) install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) +# XXX: our defaults for XDG_DATA_DIRS expect /usr/local/shore or /usr/share install (DIRECTORY plugins/zyklonb/ - DESTINATION ${zyklonb_plugin_dir} USE_SOURCE_PERMISSIONS) + DESTINATION ${CMAKE_INSTALL_DATADIR}/zyklonb/plugins USE_SOURCE_PERMISSIONS) install (DIRECTORY plugins/degesch/ DESTINATION ${CMAKE_INSTALL_DATADIR}/degesch/plugins) diff --git a/config.h.in b/config.h.in index e5a98d0..176dde5 100644 --- a/config.h.in +++ b/config.h.in @@ -2,7 +2,7 @@ #define CONFIG_H #define PROGRAM_VERSION "${project_version}" -#define ZYKLONB_PLUGIN_DIR "${CMAKE_INSTALL_PREFIX}/${zyklonb_plugin_dir}" +#define LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}" #cmakedefine HAVE_READLINE #cmakedefine HAVE_EDITLINE diff --git a/zyklonb.c b/zyklonb.c index 0d27758..c8fddeb 100644 --- a/zyklonb.c +++ b/zyklonb.c @@ -1,7 +1,7 @@ /* * zyklonb.c: the experimental IRC bot * - * Copyright (c) 2014 - 2016, Přemysl Eric Janouch + * Copyright (c) 2014 - 2020, Přemysl Eric Janouch * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. @@ -18,7 +18,6 @@ #include "config.h" #define PROGRAM_NAME "ZyklonB" -#define PLUGIN_DIR ZYKLONB_PLUGIN_DIR #include "common.c" @@ -49,7 +48,7 @@ static struct simple_config_item g_config_table[] = { "prefix", ":", "The prefix for bot commands" }, { "admin", NULL, "Host mask for administrators" }, { "plugins", NULL, "The plugins to load on startup" }, - { "plugin_dir", PLUGIN_DIR, "Where to search for plugins" }, + { "plugin_dir", NULL, "Plugin search path override" }, { "recover", "on", "Whether to re-launch on crash" }, { NULL, NULL, NULL } @@ -1015,21 +1014,41 @@ is_valid_plugin_name (const char *name) return true; } +static char * +plugin_resolve_relative_filename (const char *filename) +{ + struct strv paths = strv_make (); + get_xdg_data_dirs (&paths); + strv_append (&paths, LIBDIR); // Legacy, we do not compile any plugins + char *result = resolve_relative_filename_generic + (&paths, PROGRAM_NAME "/plugins/", filename); + strv_free (&paths); + return result; +} + static struct plugin * plugin_launch (struct bot_context *ctx, const char *name, struct error **e) { + char *path = NULL; const char *plugin_dir = str_map_find (&ctx->config, "plugin_dir"); - if (!plugin_dir) + if (plugin_dir) { - error_set (e, "plugin directory not set"); - return NULL; + // resolve_relative_filename_generic() won't accept relative paths, + // so just keep the old behaviour and expect the file to exist. + // We could use resolve_filename() on "plugin_dir" with paths=getcwd(). + path = xstrdup_printf ("%s/%s", plugin_dir, name); + } + else if (!(path = plugin_resolve_relative_filename (name))) + { + error_set (e, "plugin not found"); + goto fail_0; } int stdin_pipe[2]; if (pipe (stdin_pipe) == -1) { error_set (e, "%s: %s", "pipe", strerror (errno)); - return NULL; + goto fail_0; } int stdout_pipe[2]; @@ -1079,7 +1098,7 @@ plugin_launch (struct bot_context *ctx, const char *name, struct error **e) // Restore some of the signal handling signal (SIGPIPE, SIG_DFL); - char *argv[] = { xstrdup_printf ("%s/%s", plugin_dir, name), NULL }; + char *argv[] = { path, NULL }; execve (argv[0], argv, environ); // We will collect the failure later via SIGCHLD @@ -1089,6 +1108,7 @@ plugin_launch (struct bot_context *ctx, const char *name, struct error **e) } str_free (&work_dir); + free (path); xclose (stdin_pipe[0]); xclose (stdout_pipe[1]); @@ -1108,6 +1128,8 @@ fail_2: fail_1: xclose (stdin_pipe[0]); xclose (stdin_pipe[1]); +fail_0: + free (path); return NULL; }