ZyklonB: run plugins in a special work directory

Also small refactoring.
This commit is contained in:
Přemysl Eric Janouch 2016-02-20 00:10:15 +01:00
parent a275f9636c
commit ed20322e5e
1 changed files with 54 additions and 28 deletions

View File

@ -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