diff --git a/zyklonb.c b/zyklonb.c index c74af84..4ab27bc 100644 --- a/zyklonb.c +++ b/zyklonb.c @@ -1021,16 +1021,12 @@ is_valid_plugin_name (const char *name) return true; } -static bool -plugin_load (struct bot_context *ctx, const char *name, struct error **e) +static struct plugin * +plugin_launch (struct bot_context *ctx, const char *name, struct error **e) { const char *plugin_dir = str_map_find (&ctx->config, "plugin_dir"); if (!plugin_dir) FAIL ("plugin directory not set"); - if (!is_valid_plugin_name (name)) - FAIL ("invalid plugin name"); - if (str_map_find (&ctx->plugins_by_name, name)) - FAIL ("the plugin has already been loaded"); int stdin_pipe[2]; if (pipe (stdin_pipe) == -1) @@ -1043,6 +1039,14 @@ plugin_load (struct bot_context *ctx, const char *name, struct error **e) goto fail_1; } + struct str work_dir; + str_init (&work_dir); + get_xdg_home_dir (&work_dir, "XDG_DATA_HOME", ".local/share"); + str_append_printf (&work_dir, "/%s", PROGRAM_NAME); + + if (!mkdir_with_parents (work_dir.str, e)) + goto fail_2; + set_cloexec (stdin_pipe[1]); set_cloexec (stdout_pipe[0]); @@ -1056,36 +1060,40 @@ plugin_load (struct bot_context *ctx, const char *name, struct error **e) if (pid == 0) { // Redirect the child's stdin and stdout to the pipes - hard_assert (dup2 (stdin_pipe[0], STDIN_FILENO) != -1); - hard_assert (dup2 (stdout_pipe[1], STDOUT_FILENO) != -1); + if (dup2 (stdin_pipe[0], STDIN_FILENO) == -1 + || dup2 (stdout_pipe[1], STDOUT_FILENO) == -1) + { + print_error ("%s: %s: %s", "failed to load the plugin", + "dup2", strerror (errno)); + _exit (EXIT_FAILURE); + } + if (chdir (work_dir.str)) + { + print_error ("%s: %s: %s", "failed to load the plugin", + "chdir", strerror (errno)); + _exit (EXIT_FAILURE); + } xclose (stdin_pipe[0]); xclose (stdout_pipe[1]); - struct str pathname; - str_init (&pathname); - str_append (&pathname, plugin_dir); - str_append_c (&pathname, '/'); - str_append (&pathname, name); - // Restore some of the signal handling signal (SIGPIPE, SIG_DFL); - char *const argv[] = { pathname.str, NULL }; + char *argv[] = { xstrdup_printf ("%s/%s", plugin_dir, name), NULL }; execve (argv[0], argv, environ); // We will collect the failure later via SIGCHLD - print_error ("%s: %s: %s", - "failed to load the plugin", "exec", strerror (errno)); + print_error ("%s: %s: %s", "failed to load the plugin", + "exec", strerror (errno)); _exit (EXIT_FAILURE); } + str_free (&work_dir); + xclose (stdin_pipe[0]); xclose (stdout_pipe[1]); - set_blocking (stdout_pipe[0], false); - set_blocking (stdin_pipe[1], false); - struct plugin *plugin = xmalloc (sizeof *plugin); plugin_init (plugin); plugin->ctx = ctx; @@ -1093,6 +1101,32 @@ plugin_load (struct bot_context *ctx, const char *name, struct error **e) plugin->name = xstrdup (name); plugin->read_fd = stdout_pipe[0]; plugin->write_fd = stdin_pipe[1]; + return plugin; + +fail_2: + str_free (&work_dir); + xclose (stdout_pipe[0]); + xclose (stdout_pipe[1]); +fail_1: + xclose (stdin_pipe[0]); + xclose (stdin_pipe[1]); + return NULL; +} + +static bool +plugin_load (struct bot_context *ctx, const char *name, struct error **e) +{ + if (!is_valid_plugin_name (name)) + FAIL ("invalid plugin name"); + if (str_map_find (&ctx->plugins_by_name, name)) + FAIL ("the plugin has already been loaded"); + + struct plugin *plugin; + if (!(plugin = plugin_launch (ctx, name, e))) + return false; + + set_blocking (plugin->read_fd, false); + set_blocking (plugin->write_fd, false); poller_fd_init (&plugin->read_event, &ctx->poller, plugin->read_fd); plugin->read_event.dispatcher = (poller_fd_fn) on_plugin_readable; @@ -1107,14 +1141,6 @@ plugin_load (struct bot_context *ctx, const char *name, struct error **e) poller_fd_set (&plugin->read_event, POLLIN); return true; - -fail_2: - xclose (stdout_pipe[0]); - xclose (stdout_pipe[1]); -fail_1: - xclose (stdin_pipe[0]); - xclose (stdin_pipe[1]); - return false; } static bool