Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Properly implement a message channel for scripts
Baptiste Daroussin committed 6 years ago
commit 767fbd77ee64e22a31a4d5903c1e36dcd8533a70
parent 2fab660
2 files changed +82 -3
modified libpkg/lua_scripts.c
@@ -34,6 +34,7 @@
#include <sys/wait.h>

#include <errno.h>
+
#include <poll.h>
#include <utstring.h>
#include <lauxlib.h>
#include <lualib.h>
@@ -84,9 +85,11 @@ static int
lua_print_msg(lua_State *L)
{
	const char* str = luaL_checkstring(L, 1);
+
	lua_getglobal(L, "msgfd");
+
	int fd = lua_tointeger(L, -1);
+

+
	dprintf(fd, "%s\n", str);

-
	pkg_emit_message(str);
-
	pkg_emit_message("\n");
	return (0);
}

@@ -126,6 +129,11 @@ pkg_lua_script_run(struct pkg * const pkg, pkg_lua_script type)
	struct procctl_reaper_status info;
	struct procctl_reaper_kill killemall;
#endif
+
	struct pollfd pfd;
+
	int cur_pipe[2];
+
	char *line = NULL;
+
	FILE *f;
+
	ssize_t linecap = 0;

	if (pkg->lua_scripts[type] == NULL)
		return (EPKG_OK);
@@ -140,6 +148,10 @@ pkg_lua_script_run(struct pkg * const pkg, pkg_lua_script type)
#endif

	LL_FOREACH(pkg->lua_scripts[type], lscript) {
+
		if (get_socketpair(cur_pipe) == -1) {
+
			pkg_emit_errno("pkg_run_script", "socketpair");
+
			goto cleanup;
+
		}
		pid_t pid = fork();
		if (pid > 0) {
			static const luaL_Reg pkg_lib[] = {
@@ -147,9 +159,12 @@ pkg_lua_script_run(struct pkg * const pkg, pkg_lua_script type)
				{ "prefixed_path", lua_prefix_path },
				{ NULL, NULL },
			};
+
			close(cur_pipe[0]);
			lua_State *L = luaL_newstate();
			luaL_openlibs( L );
			lua_atpanic(L, (lua_CFunction)stack_dump );
+
			lua_pushinteger(L, cur_pipe[1]);
+
			lua_setglobal(L, "msgfd");
			lua_pushlightuserdata(L, pkg);
			lua_setglobal(L, "package");
			lua_pushliteral(L, "PREFIX");
@@ -175,6 +190,26 @@ pkg_lua_script_run(struct pkg * const pkg, pkg_lua_script type)
			goto cleanup;
		}

+
		close(cur_pipe[1]);
+
		memset(&pfd, 0, sizeof(pfd));
+
		pfd.fd = cur_pipe[0];
+
		pfd.events = POLLIN | POLLERR | POLLHUP;
+
		f = fdopen(pfd.fd, "r");
+
		for (;;) {
+
			if (poll(&pfd, 1, -1) == -1) {
+
				if (errno == EINTR)
+
					continue;
+
				else
+
					goto cleanup;
+
			}
+
			if (pfd.revents & (POLLERR|POLLHUP))
+
				break;
+
			if (getline(&line, &linecap, f) > 0) {
+
				pkg_emit_message(line);
+
			}
+
		}
+
		fclose(f);
+

		while (waitpid(pid, &pstat, 0) == -1) {
			if (errno != EINTR) {
				ret = EPKG_FATAL;
@@ -208,6 +243,7 @@ cleanup:
	}
	procctl(P_PID, mypid, PROC_REAP_RELEASE, NULL);
#endif
+
	free(line);

	return (ret);
}
modified libpkg/scripts.c
@@ -37,6 +37,7 @@
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
+
#include <poll.h>
#include <spawn.h>
#include <stdlib.h>
#include <limits.h>
@@ -58,7 +59,7 @@ pkg_script_run(struct pkg * const pkg, pkg_script type)
	pid_t pid;
	const char *script_cmd_p;
	const char *argv[4];
-
	char **ep;
+
	char **ep, *buf;
	int ret = EPKG_OK;
	int fd = -1;
	int stdin_pipe[2] = {-1, -1};
@@ -68,12 +69,17 @@ pkg_script_run(struct pkg * const pkg, pkg_script type)
	ssize_t bytes_written;
	size_t script_cmd_len;
	long argmax;
+
	int cur_pipe[2];
#ifdef PROC_REAP_KILL
	bool do_reap;
	pid_t mypid;
	struct procctl_reaper_status info;
	struct procctl_reaper_kill killemall;
#endif
+
	struct pollfd pfd;
+
	ssize_t linecap = 0;
+
	char *line = NULL;
+
	FILE *f;

	struct {
		const char * const arg;
@@ -142,10 +148,21 @@ pkg_script_run(struct pkg * const pkg, pkg_script type)

			pkg_debug(3, "Scripts: executing\n--- BEGIN ---\n%s\nScripts: --- END ---", utstring_body(script_cmd));
			posix_spawn_file_actions_init(&action);
+
			if (get_socketpair(cur_pipe) == -1) {
+
				pkg_emit_errno("pkg_run_script", "socketpair");
+
				goto cleanup;
+
			}
+

+
			asprintf(&buf, "%d", cur_pipe[1]);
+
			setenv("PKG_MSGFD", buf, 1);
+
			free(buf);
+

			if (utstring_len(script_cmd) > argmax) {
				if (pipe(stdin_pipe) < 0) {
					ret = EPKG_FATAL;
					posix_spawn_file_actions_destroy(&action);
+
					close(cur_pipe[0]);
+
					close(cur_pipe[1]);
					goto cleanup;
				}

@@ -164,6 +181,8 @@ pkg_script_run(struct pkg * const pkg, pkg_script type)
					pkg_errno("Cannot open %s", "/dev/null");
					ret = EPKG_FATAL;
					posix_spawn_file_actions_destroy(&action);
+
					close(cur_pipe[0]);
+
					close(cur_pipe[1]);
					goto cleanup;
				}
				posix_spawn_file_actions_adddup2(&action,
@@ -183,6 +202,8 @@ pkg_script_run(struct pkg * const pkg, pkg_script type)
				errno = error;
				pkg_errno("Cannot runscript %s", map[i].arg);
				posix_spawn_file_actions_destroy(&action);
+
				close(cur_pipe[0]);
+
				close(cur_pipe[1]);
				goto cleanup;
			}
			posix_spawn_file_actions_destroy(&action);
@@ -208,6 +229,27 @@ pkg_script_run(struct pkg * const pkg, pkg_script type)

			unsetenv("PKG_PREFIX");

+
			close(cur_pipe[1]);
+
			memset(&pfd, 0, sizeof(pfd));
+
			pfd.fd = cur_pipe[0];
+
			pfd.events = POLLIN | POLLERR | POLLHUP;
+

+
			f = fdopen(pfd.fd, "r");
+
			for (;;) {
+
				if (poll(&pfd, 1, -1) == -1) {
+
					if (errno == EINTR)
+
						continue;
+
					else
+
						goto cleanup;
+
				}
+
				if (pfd.revents & (POLLERR|POLLHUP))
+
					break;
+
				if (getline(&line, &linecap, f) > 0) {
+
					pkg_emit_message(line);
+
				}
+
			}
+
			fclose(f);
+

			while (waitpid(pid, &pstat, 0) == -1) {
				if (errno != EINTR)
					goto cleanup;
@@ -226,6 +268,7 @@ pkg_script_run(struct pkg * const pkg, pkg_script type)

cleanup:

+
	free(line);
	utstring_free(script_cmd);
	if (stdin_pipe[0] != -1)
		close(stdin_pipe[0]);