git: 6a2c624b35a0 - main - flua: fbsd: return a process handle to operate on when we exec()

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Wed, 09 Jul 2025 05:12:54 UTC
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=6a2c624b35a0c760b00b9a34c10b7ea0c240c677

commit 6a2c624b35a0c760b00b9a34c10b7ea0c240c677
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-07-09 05:12:31 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2025-07-09 05:12:31 +0000

    flua: fbsd: return a process handle to operate on when we exec()
    
    This gives us some way to be able to write to stdin if we want to, or
    as a future improvement, will allow us to extract stdout from the
    process.  The handle is setup to close and waitpid() on close/gc so that
    existing users wouldn't necessarily leak for the lifetime of the script
    if they weren't adopted to the new model.
    
    Reviewed by:    bapt
    Differential Revision:  https://reviews.freebsd.org/D50538
---
 libexec/flua/modules/lfbsd.c | 94 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 86 insertions(+), 8 deletions(-)

diff --git a/libexec/flua/modules/lfbsd.c b/libexec/flua/modules/lfbsd.c
index 6279474f8388..a361fa25601b 100644
--- a/libexec/flua/modules/lfbsd.c
+++ b/libexec/flua/modules/lfbsd.c
@@ -2,6 +2,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright 2023 Baptiste Daroussin <bapt@FreeBSD.org>
+ * Copyright (C) 2025 Kyle Evans <kevans@FreeBSD.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted providing that the following conditions~
@@ -38,6 +39,13 @@
 #include "lauxlib.h"
 #include "lfbsd.h"
 
+#define	FBSD_PROCESSHANDLE	"fbsd_process_t*"
+
+struct fbsd_process {
+	int	pid;
+	int	stdin_fileno;
+};
+
 extern char **environ;
 
 static const char**
@@ -65,7 +73,8 @@ luaL_checkarraystrings(lua_State *L, int arg)
 static int
 lua_exec(lua_State *L)
 {
-	int r, pstat;
+	struct fbsd_process *proc;
+	int r;
 	posix_spawn_file_actions_t action;
 	int stdin_pipe[2] = {-1, -1};
 	pid_t pid;
@@ -81,6 +90,9 @@ lua_exec(lua_State *L)
 		return (3);
 	}
 
+	proc = lua_newuserdata(L, sizeof(*proc));
+	proc->stdin_fileno = stdin_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]);
@@ -91,6 +103,7 @@ lua_exec(lua_State *L)
 		close(stdin_pipe[0]);
 		close(stdin_pipe[1]);
 		posix_spawn_file_actions_destroy(&action);
+		lua_pop(L, 2);	/* Pop off the process handle and args. */
 
 		lua_pushnil(L);
 		lua_pushstring(L, strerror(r));
@@ -98,12 +111,26 @@ lua_exec(lua_State *L)
 		return (3);
 	}
 
+	lua_pop(L, 1);
+
 	close(stdin_pipe[0]);
 	posix_spawn_file_actions_destroy(&action);
 
-	while (waitpid(pid, &pstat, 0) == -1) {
-		if (errno != EINTR) {
-			close(stdin_pipe[1]);
+	proc->pid = pid;
+	luaL_setmetatable(L, FBSD_PROCESSHANDLE);
+
+	return 1;
+}
+
+static int
+lua_process_close(lua_State *L)
+{
+	struct fbsd_process *proc;
+	int pstat, r;
+
+	proc = luaL_checkudata(L, 1, FBSD_PROCESSHANDLE);
+	while (waitpid(proc->pid, &pstat, 0) == -1) {
+		if ((r = errno) != EINTR) {
 			lua_pushnil(L);
 			lua_pushstring(L, strerror(r));
 			lua_pushinteger(L, r);
@@ -111,18 +138,60 @@ lua_exec(lua_State *L)
 		}
 	}
 
-	if (WEXITSTATUS(pstat) != 0) {
+	if (!WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) {
 		lua_pushnil(L);
 		lua_pushstring(L, "Abnormal termination");
+		return (2);
+	}
+
+	if (proc->stdin_fileno >= 0)
+		close(proc->stdin_fileno);
+	proc->stdin_fileno = -1;
+
+	lua_pushboolean(L, 1);
+	return 1;
+}
+
+static int
+lua_process_stdin(lua_State *L)
+{
+	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 (fp == NULL) {
+		r = errno;
+
+		lua_pushnil(L);
+		lua_pushstring(L, strerror(r));
 		lua_pushinteger(L, r);
 		return (3);
 	}
 
-	close(stdin_pipe[1]);
-	lua_pushinteger(L, pid);
-	return 1;
+	p = lua_newuserdata(L, sizeof(*p));
+	p->closef = &lua_process_close;
+	p->f = fp;
+	luaL_setmetatable(L, LUA_FILEHANDLE);
+	return (1);
 }
 
+#define PROCESS_SIMPLE(n)	{ #n, lua_process_ ## n }
+static const struct luaL_Reg fbsd_process[] = {
+	PROCESS_SIMPLE(close),
+	PROCESS_SIMPLE(stdin),
+	{ NULL, NULL },
+};
+
+static const struct luaL_Reg fbsd_process_meta[] = {
+	{ "__index", NULL },
+	{ "__gc", lua_process_close },
+	{ "__close", lua_process_close },
+	{ NULL, NULL },
+};
+
 #define REG_SIMPLE(n)	{ #n, lua_ ## n }
 static const struct luaL_Reg fbsd_lib[] = {
 	REG_SIMPLE(exec),
@@ -134,5 +203,14 @@ int
 luaopen_fbsd(lua_State *L)
 {
 	luaL_newlib(L, fbsd_lib);
+
+	luaL_newmetatable(L, FBSD_PROCESSHANDLE);
+	luaL_setfuncs(L, fbsd_process_meta, 0);
+
+	luaL_newlibtable(L, fbsd_process);
+	luaL_setfuncs(L, fbsd_process, 0);
+	lua_setfield(L, -2, "__index");
+	lua_pop(L, 1);
+
 	return (1);
 }