ZyklonB: run plugins in a special work directory
Also small refactoring.
This commit is contained in:
parent
a275f9636c
commit
ed20322e5e
82
zyklonb.c
82
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
|
||||
|
Loading…
Reference in New Issue
Block a user