summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zyklonb.c82
1 files changed, 54 insertions, 28 deletions
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