From nobody Wed Jul 09 05:12:55 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4bcR2011HHz616rX; Wed, 09 Jul 2025 05:12:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4bcR1z4fRwz3LhR; Wed, 09 Jul 2025 05:12:55 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1752037975; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Cu+KDEtxfrEKyWM0gvbmOErnacktkTnzy+hxfdY8x0E=; b=rIDLZ5DfgLE2sEbzU5riksl48r3alPcGvgeoUOHoS4Bnhx7ehprExHb22obs+yQ+exxI04 SXd9Ds0mp2268b3BhH03wHZgMcN5KyCQzzpRIUHOZCzgI05ZUx3CNaKsvrmpDxWqQFsAvs UAQ2kdFeL8P7pBNgC20/JPW4OzV/8YerjusjEHZHThIqlMtb1sxDo3lhJ5nFqgX7MVlQr3 Dm9LdHqrANDcK+cO/zft5oGEgW7reZjhfx0h8joLEOmPxILnZobEL4RkEsC7/sM0xMAMq7 VVe+SDKCYmgmWTKBY3L+BOZMZgKlBWWIkrsa3Gx28jI/gNSbzWTBJ5vk05UMdQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1752037975; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Cu+KDEtxfrEKyWM0gvbmOErnacktkTnzy+hxfdY8x0E=; b=AyJRwlknxueKgImIyCtkoDY1YG89V57YNYCFE1KaCycyJuztKygKHdqxULuQESAKlMDcyP Ouq7K/ymtQJuyquZZpv3dPQ+tE4beJkU52H9hAbjUl0WBRbL0oAbuI/vhwCALs+o8vuRVe WPyPSkUZVwMWUwJjoBoBCOqt4ZeyWrSG/kLCszUX+fOWUqquomcqHaZp3bHk2ID+VypM1G 5W2u5jAvgStGNy5MePce+yPDWTC8jVmZ92+SaF9fk0ScMbOmVdw3OvbN8LNAOrr6cIRNx2 4IPVMAxM+59qsT60qp0o//uOpaMOXq9p76aDzVzT0i+mbMXYp1keCOW55wQ7Nw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1752037975; a=rsa-sha256; cv=none; b=wCLdzYKIp+v0T0SBe3esX2NqeRzQ/p5wrE2Vmi0DumgHsVloBrvZfrggVP+i9mL7USK+x1 Q/I01vial6vjzSKtrrAwZnNBGPz1lA28BXQqjBMk+/mw+g1heQpRBMO3RnqzmglVkN7DXX NLRYEqfF7t58Nn4RPtNt7ymcbzN6DcI498b5sdvU60IywM+X48zFA4r+DNVAIxrnvHfgC1 vGONNFrG6eZ/633MyZ7bD9EpdyVB8s5A3YojtHDJ7WTkkQpP2Nq++rqwcv8omNRUCQuf58 4pkI77gM7d+L4dBRAg71uyloeOf0CQ0gjRwXf0bvL3tdVmqd9PSB/EyeOMZ7yQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4bcR1z3dTMz17gC; Wed, 09 Jul 2025 05:12:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 5695Ctdc030527; Wed, 9 Jul 2025 05:12:55 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 5695CtTH030524; Wed, 9 Jul 2025 05:12:55 GMT (envelope-from git) Date: Wed, 9 Jul 2025 05:12:55 GMT Message-Id: <202507090512.5695CtTH030524@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kyle Evans Subject: git: 3f0e1092097e - main - flua: fbsd: allow stdout to be captured for exec() processes List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 3f0e1092097ed63b83a02518395e370c3cac01be Auto-Submitted: auto-generated The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=3f0e1092097ed63b83a02518395e370c3cac01be commit 3f0e1092097ed63b83a02518395e370c3cac01be Author: Kyle Evans AuthorDate: 2025-07-09 05:12:32 +0000 Commit: Kyle Evans CommitDate: 2025-07-09 05:12:32 +0000 flua: fbsd: allow stdout to be captured for exec() processes This allows us to do things like: ``` local fp = assert(fbsd.exec({"ls", "-l"}, true)) local fpout = assert(fp:stdout()) while true do local line = fpout:read("l") if not line then break end print("Read: " .. line) end fp:close() ``` The makeman lua rewrite will use it to capture `make showconfig` output for processing. Reviewed by: bapt Differential Revision: https://reviews.freebsd.org/D50539 --- libexec/flua/modules/lfbsd.c | 95 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 13 deletions(-) diff --git a/libexec/flua/modules/lfbsd.c b/libexec/flua/modules/lfbsd.c index a361fa25601b..ef660ba9fd77 100644 --- a/libexec/flua/modules/lfbsd.c +++ b/libexec/flua/modules/lfbsd.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,7 @@ struct fbsd_process { int pid; int stdin_fileno; + int stdout_fileno; }; extern char **environ; @@ -70,6 +72,16 @@ luaL_checkarraystrings(lua_State *L, int arg) return ret; } +static void +close_pipes(int pipes[2]) +{ + + if (pipes[0] != -1) + close(pipes[0]); + if (pipes[1] != -1) + close(pipes[1]); +} + static int lua_exec(lua_State *L) { @@ -77,31 +89,57 @@ lua_exec(lua_State *L) int r; posix_spawn_file_actions_t action; int stdin_pipe[2] = {-1, -1}; + int stdout_pipe[2] = {-1, -1}; pid_t pid; const char **argv; int n = lua_gettop(L); - luaL_argcheck(L, n == 1, n > 1 ? 2 : n, - "fbsd.exec takes exactly one argument"); + bool capture_stdout; + luaL_argcheck(L, n > 0 && n <= 2, n >= 2 ? 2 : n, + "fbsd.exec takes exactly one or two arguments"); + capture_stdout = lua_toboolean(L, 2); if (pipe(stdin_pipe) < 0) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); lua_pushinteger(L, errno); return (3); } + if (capture_stdout && pipe(stdout_pipe) < 0) { + close_pipes(stdin_pipe); + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); + lua_pushinteger(L, errno); + return (3); + } proc = lua_newuserdata(L, sizeof(*proc)); proc->stdin_fileno = stdin_pipe[1]; - + proc->stdout_fileno = stdout_pipe[1]; posix_spawn_file_actions_init(&action); posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO); posix_spawn_file_actions_addclose(&action, stdin_pipe[1]); + if (stdin_pipe[0] != STDIN_FILENO) + posix_spawn_file_actions_addclose(&action, stdin_pipe[0]); + + /* + * Setup stdout to be captured if requested. Otherwise, we just let it + * go to our own stdout. + */ + if (stdout_pipe[0] != -1) { + posix_spawn_file_actions_adddup2(&action, stdout_pipe[0], + STDOUT_FILENO); + posix_spawn_file_actions_addclose(&action, stdout_pipe[1]); + if (stdout_pipe[0] != STDOUT_FILENO) { + posix_spawn_file_actions_addclose(&action, + stdout_pipe[0]); + } + } argv = luaL_checkarraystrings(L, 1); if (0 != (r = posix_spawnp(&pid, argv[0], &action, NULL, (char*const*)argv, environ))) { - close(stdin_pipe[0]); - close(stdin_pipe[1]); + close_pipes(stdin_pipe); + close_pipes(stdout_pipe); posix_spawn_file_actions_destroy(&action); lua_pop(L, 2); /* Pop off the process handle and args. */ @@ -114,12 +152,14 @@ lua_exec(lua_State *L) lua_pop(L, 1); close(stdin_pipe[0]); + if (stdout_pipe[0] != -1) + close(stdout_pipe[0]); posix_spawn_file_actions_destroy(&action); proc->pid = pid; luaL_setmetatable(L, FBSD_PROCESSHANDLE); - return 1; + return (1); } static int @@ -144,24 +184,34 @@ lua_process_close(lua_State *L) return (2); } - if (proc->stdin_fileno >= 0) + if (proc->stdin_fileno >= 0) { close(proc->stdin_fileno); - proc->stdin_fileno = -1; + proc->stdin_fileno = -1; + } + + if (proc->stdout_fileno >= 0) { + close(proc->stdout_fileno); + proc->stdout_fileno = -1; + } lua_pushboolean(L, 1); - return 1; + return (1); } static int -lua_process_stdin(lua_State *L) +lua_process_makestdio(lua_State *L, int fd, const char *mode) { - struct fbsd_process *proc; luaL_Stream *p; FILE *fp; int r; - proc = luaL_checkudata(L, 1, FBSD_PROCESSHANDLE); - fp = fdopen(proc->stdin_fileno, "w"); + if (fd == -1) { + lua_pushnil(L); + lua_pushstring(L, "Stream not captured"); + return (2); + } + + fp = fdopen(fd, mode); if (fp == NULL) { r = errno; @@ -178,10 +228,29 @@ lua_process_stdin(lua_State *L) return (1); } +static int +lua_process_stdin(lua_State *L) +{ + struct fbsd_process *proc; + + proc = luaL_checkudata(L, 1, FBSD_PROCESSHANDLE); + return (lua_process_makestdio(L, proc->stdin_fileno, "w")); +} + +static int +lua_process_stdout(lua_State *L) +{ + struct fbsd_process *proc; + + proc = luaL_checkudata(L, 1, FBSD_PROCESSHANDLE); + return (lua_process_makestdio(L, proc->stdout_fileno, "r")); +} + #define PROCESS_SIMPLE(n) { #n, lua_process_ ## n } static const struct luaL_Reg fbsd_process[] = { PROCESS_SIMPLE(close), PROCESS_SIMPLE(stdin), + PROCESS_SIMPLE(stdout), { NULL, NULL }, };