ZyklonB: run plugins in a special work directory
Also small refactoring.
This commit is contained in:
		
							
								
								
									
										82
									
								
								zyklonb.c
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								zyklonb.c
									
									
									
									
									
								
							@@ -1021,16 +1021,12 @@ is_valid_plugin_name (const char *name)
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static struct plugin *
 | 
				
			||||||
plugin_load (struct bot_context *ctx, const char *name, struct error **e)
 | 
					plugin_launch (struct bot_context *ctx, const char *name, struct error **e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *plugin_dir = str_map_find (&ctx->config, "plugin_dir");
 | 
						const char *plugin_dir = str_map_find (&ctx->config, "plugin_dir");
 | 
				
			||||||
	if (!plugin_dir)
 | 
						if (!plugin_dir)
 | 
				
			||||||
		FAIL ("plugin directory not set");
 | 
							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];
 | 
						int stdin_pipe[2];
 | 
				
			||||||
	if (pipe (stdin_pipe) == -1)
 | 
						if (pipe (stdin_pipe) == -1)
 | 
				
			||||||
@@ -1043,6 +1039,14 @@ plugin_load (struct bot_context *ctx, const char *name, struct error **e)
 | 
				
			|||||||
		goto fail_1;
 | 
							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 (stdin_pipe[1]);
 | 
				
			||||||
	set_cloexec (stdout_pipe[0]);
 | 
						set_cloexec (stdout_pipe[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1056,36 +1060,40 @@ plugin_load (struct bot_context *ctx, const char *name, struct error **e)
 | 
				
			|||||||
	if (pid == 0)
 | 
						if (pid == 0)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Redirect the child's stdin and stdout to the pipes
 | 
							// Redirect the child's stdin and stdout to the pipes
 | 
				
			||||||
		hard_assert (dup2 (stdin_pipe[0],  STDIN_FILENO)  != -1);
 | 
							if (dup2 (stdin_pipe[0], STDIN_FILENO) == -1
 | 
				
			||||||
		hard_assert (dup2 (stdout_pipe[1], STDOUT_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 (stdin_pipe[0]);
 | 
				
			||||||
		xclose (stdout_pipe[1]);
 | 
							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
 | 
							// Restore some of the signal handling
 | 
				
			||||||
		signal (SIGPIPE, SIG_DFL);
 | 
							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);
 | 
							execve (argv[0], argv, environ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// We will collect the failure later via SIGCHLD
 | 
							// We will collect the failure later via SIGCHLD
 | 
				
			||||||
		print_error ("%s: %s: %s",
 | 
							print_error ("%s: %s: %s", "failed to load the plugin",
 | 
				
			||||||
			"failed to load the plugin", "exec", strerror (errno));
 | 
								"exec", strerror (errno));
 | 
				
			||||||
		_exit (EXIT_FAILURE);
 | 
							_exit (EXIT_FAILURE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						str_free (&work_dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	xclose (stdin_pipe[0]);
 | 
						xclose (stdin_pipe[0]);
 | 
				
			||||||
	xclose (stdout_pipe[1]);
 | 
						xclose (stdout_pipe[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_blocking (stdout_pipe[0], false);
 | 
					 | 
				
			||||||
	set_blocking (stdin_pipe[1], false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct plugin *plugin = xmalloc (sizeof *plugin);
 | 
						struct plugin *plugin = xmalloc (sizeof *plugin);
 | 
				
			||||||
	plugin_init (plugin);
 | 
						plugin_init (plugin);
 | 
				
			||||||
	plugin->ctx = ctx;
 | 
						plugin->ctx = ctx;
 | 
				
			||||||
@@ -1093,6 +1101,32 @@ plugin_load (struct bot_context *ctx, const char *name, struct error **e)
 | 
				
			|||||||
	plugin->name = xstrdup (name);
 | 
						plugin->name = xstrdup (name);
 | 
				
			||||||
	plugin->read_fd = stdout_pipe[0];
 | 
						plugin->read_fd = stdout_pipe[0];
 | 
				
			||||||
	plugin->write_fd = stdin_pipe[1];
 | 
						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);
 | 
						poller_fd_init (&plugin->read_event, &ctx->poller, plugin->read_fd);
 | 
				
			||||||
	plugin->read_event.dispatcher = (poller_fd_fn) on_plugin_readable;
 | 
						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);
 | 
						poller_fd_set (&plugin->read_event, POLLIN);
 | 
				
			||||||
	return true;
 | 
						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
 | 
					static bool
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user