Page MenuHomeFreeBSD

D46553.diff
No OneTemporary

D46553.diff

diff --git a/libexec/flua/modules/lposix.c b/libexec/flua/modules/lposix.c
--- a/libexec/flua/modules/lposix.c
+++ b/libexec/flua/modules/lposix.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,6 +33,9 @@
#include <errno.h>
#include <grp.h>
#include <pwd.h>
+#include <spawn.h>
+#include <stdbool.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -39,6 +43,22 @@
#include "lauxlib.h"
#include "lposix.h"
+/* udata keys */
+#define FREEBSD_SYS_FD_KEY "freebsd_sys_fd"
+#define POSIX_SPAWN_FILE_ACTIONS_KEY "freebsd_posix_spawn_file_actions"
+#define POSIX_SPAWNATTR_KEY "freebsd_posix_spawnattr"
+
+#define PUSH_ERROR(L, error) do { \
+ lua_pushnil(L); \
+ lua_pushstring(L, strerror(error)); \
+ lua_pushinteger(L, error); \
+} while (0)
+
+#define PUSH_ERRNO(L) do { \
+ int saved_error = errno; \
+ PUSH_ERROR(L, saved_error); \
+} while (0)
+
/*
* Minimal implementation of luaposix needed for internal FreeBSD bits.
*/
@@ -121,6 +141,425 @@
return (1);
}
+static int
+lua_close_(lua_State *L)
+{
+ int error, *fdp;
+
+ fdp = luaL_checkudata(L, 1, FREEBSD_SYS_FD_KEY);
+ error = close(*fdp);
+ if (error != 0) {
+ PUSH_ERRNO(L);
+ return (3);
+ }
+ /* Prevent __gc from touching this fd. */
+ *fdp = -1;
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static int
+lua_pipe(lua_State *L)
+{
+ int error, fds[2];
+ int *fdp;
+
+ error = pipe(fds);
+ if (error == -1) {
+ PUSH_ERRNO(L);
+ return (3);
+ }
+
+ fdp = lua_newuserdata(L, sizeof(int));
+ *fdp = fds[0];
+ luaL_getmetatable(L, FREEBSD_SYS_FD_KEY);
+ lua_setmetatable(L, -2);
+ fdp = lua_newuserdata(L, sizeof(int));
+ *fdp = fds[1];
+ luaL_getmetatable(L, FREEBSD_SYS_FD_KEY);
+ lua_setmetatable(L, -2);
+
+ return (2);
+}
+
+static int
+lua_posix_spawn_impl(lua_State *L, bool path)
+{
+ extern char **environ;
+ posix_spawn_file_actions_t file_actions, *file_actionsp;
+ posix_spawnattr_t attr, *attrp;
+ const char *file;
+ const char **argv;
+ const char **envp;
+ char *const *_argv;
+ char *const *_envp;
+ int argi, argc, envc, ret, ret1;
+ pid_t pid;
+
+ argi = 1;
+ file = luaL_checkstring(L, argi++);
+
+ /*
+ * File actions and spawn attributes are optional. They must be
+ * followed by a table.
+ */
+ attrp = NULL;
+ file_actionsp = NULL;
+ if (lua_isuserdata(L, argi)) {
+ lua_getmetatable(L, argi);
+ luaL_getmetatable(L, POSIX_SPAWN_FILE_ACTIONS_KEY);
+ if (lua_rawequal(L, -1, -2)) {
+ file_actionsp = luaL_checkudata(L, argi,
+ POSIX_SPAWN_FILE_ACTIONS_KEY);
+ argi++;
+ }
+ lua_pop(L, 2);
+ }
+ if (lua_isuserdata(L, argi)) {
+ void *val;
+
+ val = luaL_checkudata(L, argi, POSIX_SPAWNATTR_KEY);
+ if (val != NULL) {
+ attrp = val;
+ argi++;
+ }
+ }
+ luaL_checktype(L, argi, LUA_TTABLE);
+
+ /*
+ * If the caller didn't provide a file actions or spawn attributes, set
+ * up a no-op default.
+ */
+ if (file_actionsp == NULL) {
+ ret = posix_spawn_file_actions_init(&file_actions);
+ if (ret != 0) {
+ PUSH_ERROR(L, ret);
+ return (3);
+ }
+ file_actionsp = &file_actions;
+ }
+ if (attrp == NULL) {
+ ret = posix_spawnattr_init(&attr);
+ if (ret != 0) {
+ PUSH_ERROR(L, ret);
+ return (3);
+ }
+ attrp = &attr;
+ }
+
+ argc = lua_rawlen(L, argi);
+ argv = calloc(argc + 1, sizeof(char *));
+ if (argv == NULL) {
+ PUSH_ERROR(L, ret);
+ return (3);
+ }
+ for (int i = 0; i < argc; i++) {
+ lua_rawgeti(L, argi, i + 1);
+ argv[i] = lua_tostring(L, -1);
+ lua_pop(L, 1);
+ }
+ argi++;
+
+ /*
+ * POSIX doesn't appear to specify what happens if the envp is NULL.
+ * FreeBSD treats it as meaning that the environment is to be inherited,
+ * which seems sensible. Follow that behaviour if the caller didn't
+ * specify a final parameter.
+ */
+ if (lua_gettop(L) >= argi && lua_type(L, argi) != LUA_TNIL) {
+ luaL_checktype(L, argi, LUA_TTABLE);
+ envc = lua_rawlen(L, argi);
+ envp = calloc(envc + 1, sizeof(char *));
+ if (envp == NULL) {
+ PUSH_ERRNO(L);
+ return (3);
+ }
+ for (int i = 0; i < envc; i++) {
+ lua_rawgeti(L, argi, i + 1);
+ envp[i] = lua_tostring(L, -1);
+ lua_pop(L, 1);
+ }
+ argi++;
+ } else {
+ envp = __DECONST(const char **, environ);
+ }
+
+ _argv = __DECONST(char * const *, argv);
+ _envp = __DECONST(char * const *, envp);
+ ret = path ?
+ posix_spawnp(&pid, file, file_actionsp, attrp, _argv, _envp) :
+ posix_spawn(&pid, file, file_actionsp, attrp, _argv, _envp);
+
+ if (file_actionsp == &file_actions) {
+ ret1 = posix_spawn_file_actions_destroy(file_actionsp);
+ assert(ret1 == 0);
+ }
+ if (attrp == &attr) {
+ ret1 = posix_spawnattr_destroy(attrp);
+ assert(ret1 == 0);
+ }
+
+ free(argv);
+ if (envp != __DECONST(const char **, environ))
+ free(envp);
+
+ if (ret != 0) {
+ PUSH_ERROR(L, ret);
+ return (3);
+ }
+
+ lua_pushinteger(L, pid);
+ return (1);
+}
+
+static int
+lua_posix_spawn(lua_State *L)
+{
+ return (lua_posix_spawn_impl(L, false));
+}
+
+static int
+lua_posix_spawnp(lua_State *L)
+{
+ return (lua_posix_spawn_impl(L, true));
+}
+
+static int
+lua_posix_spawn_file_actions_init(lua_State *L)
+{
+ posix_spawn_file_actions_t *file_actions;
+ int error;
+
+ file_actions = lua_newuserdata(L, sizeof(posix_spawn_file_actions_t));
+ error = posix_spawn_file_actions_init(file_actions);
+ if (error != 0) {
+ PUSH_ERROR(L, error);
+ return (3);
+ }
+
+ luaL_getmetatable(L, POSIX_SPAWN_FILE_ACTIONS_KEY);
+ lua_setmetatable(L, -2);
+
+ return (1);
+}
+
+static int
+lua_posix_spawn_file_actions_addopen(lua_State *L)
+{
+ posix_spawn_file_actions_t *file_actions;
+ const char *path;
+ int error, *fdp, oflags;
+ mode_t mode;
+
+ file_actions = luaL_checkudata(L, 1, POSIX_SPAWN_FILE_ACTIONS_KEY);
+ fdp = luaL_checkudata(L, 2, FREEBSD_SYS_FD_KEY);
+ path = luaL_checkstring(L, 3);
+ oflags = luaL_checkinteger(L, 4);
+ mode = luaL_optinteger(L, 5, 0);
+
+ error = posix_spawn_file_actions_addopen(file_actions, *fdp, path,
+ oflags, mode);
+ if (error != 0) {
+ PUSH_ERROR(L, error);
+ return (3);
+ }
+
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static int
+lua_posix_spawn_file_actions_adddup2(lua_State *L)
+{
+ posix_spawn_file_actions_t *file_actions;
+ int error, *oldfdp, newfd;
+
+ file_actions = luaL_checkudata(L, 1, POSIX_SPAWN_FILE_ACTIONS_KEY);
+ oldfdp = luaL_checkudata(L, 2, FREEBSD_SYS_FD_KEY);
+ newfd = luaL_checkinteger(L, 3);
+
+ error = posix_spawn_file_actions_adddup2(file_actions, *oldfdp, newfd);
+ if (error != 0) {
+ PUSH_ERROR(L, error);
+ return (3);
+ }
+
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static int
+lua_posix_spawn_file_actions_addclose(lua_State *L)
+{
+ posix_spawn_file_actions_t *file_actions;
+ int error, *fdp;
+
+ file_actions = luaL_checkudata(L, 1, POSIX_SPAWN_FILE_ACTIONS_KEY);
+ fdp = luaL_checkudata(L, 2, FREEBSD_SYS_FD_KEY);
+
+ error = posix_spawn_file_actions_addclose(file_actions, *fdp);
+ if (error != 0) {
+ PUSH_ERROR(L, error);
+ return (3);
+ }
+
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static int
+lua_posix_spawn_file_actions_addclosefrom_np(lua_State *L)
+{
+ posix_spawn_file_actions_t *file_actions;
+ int error, from;
+
+ file_actions = luaL_checkudata(L, 1, POSIX_SPAWN_FILE_ACTIONS_KEY);
+ from = luaL_checkinteger(L, 2);
+
+ error = posix_spawn_file_actions_addclosefrom_np(file_actions, from);
+ if (error != 0) {
+ PUSH_ERROR(L, error);
+ return (3);
+ }
+
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static int
+lua_posix_spawn_file_actions_addchdir_np(lua_State *L)
+{
+ posix_spawn_file_actions_t *file_actions;
+ const char *path;
+ int error;
+
+ file_actions = luaL_checkudata(L, 1, POSIX_SPAWN_FILE_ACTIONS_KEY);
+ path = luaL_checkstring(L, 2);
+
+ error = posix_spawn_file_actions_addchdir_np(file_actions, path);
+ if (error != 0) {
+ PUSH_ERROR(L, error);
+ return (3);
+ }
+
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static int
+lua_posix_spawn_file_actions_addfchdir_np(lua_State *L)
+{
+ posix_spawn_file_actions_t *file_actions;
+ int error, *fdp;
+
+ file_actions = luaL_checkudata(L, 1, POSIX_SPAWN_FILE_ACTIONS_KEY);
+ fdp = luaL_checkudata(L, 2, FREEBSD_SYS_FD_KEY);
+
+ error = posix_spawn_file_actions_addfchdir_np(file_actions, *fdp);
+ if (error != 0) {
+ PUSH_ERROR(L, error);
+ return (3);
+ }
+
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static int
+lua_posix_spawnattr_init(lua_State *L)
+{
+ posix_spawnattr_t *attr;
+ int error;
+
+ attr = lua_newuserdata(L, sizeof(posix_spawnattr_t));
+
+ error = posix_spawnattr_init(attr);
+ if (error != 0) {
+ PUSH_ERROR(L, error);
+ return (3);
+ }
+
+ luaL_getmetatable(L, POSIX_SPAWNATTR_KEY);
+ lua_setmetatable(L, -2);
+ return (1);
+}
+
+static int
+lua_posix_spawnattr_getflags(lua_State *L)
+{
+ posix_spawnattr_t *attr;
+ short flags;
+ int error;
+
+ attr = luaL_checkudata(L, 1, POSIX_SPAWNATTR_KEY);
+
+ error = posix_spawnattr_getflags(attr, &flags);
+ if (error != 0) {
+ PUSH_ERROR(L, error);
+ return (3);
+ }
+
+ lua_pushinteger(L, flags);
+ return (1);
+}
+
+static int
+lua_posix_spawnattr_setflags(lua_State *L)
+{
+ posix_spawnattr_t *attr;
+ lua_Integer lflags;
+ short flags;
+ int error;
+
+ attr = luaL_checkudata(L, 1, POSIX_SPAWNATTR_KEY);
+ lflags = luaL_checkinteger(L, 2);
+ if (lflags > SHRT_MAX || lflags < SHRT_MIN) {
+ return (luaL_error(L, "flags too large: %jx",
+ (uintmax_t)lflags));
+ }
+ flags = (short)lflags;
+
+ error = posix_spawnattr_setflags(attr, flags);
+ assert(error == 0);
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static int
+lua_posix_spawnattr_getpgroup(lua_State *L)
+{
+ posix_spawnattr_t *attr;
+ pid_t pgroup;
+ int error;
+
+ attr = luaL_checkudata(L, 1, POSIX_SPAWNATTR_KEY);
+
+ error = posix_spawnattr_getpgroup(attr, &pgroup);
+ assert(error == 0);
+ lua_pushinteger(L, pgroup);
+ return (1);
+}
+
+static int
+lua_posix_spawnattr_setpgroup(lua_State *L)
+{
+ posix_spawnattr_t *attr;
+ lua_Integer lpgrp;
+ pid_t pgrp;
+ int error;
+
+ attr = luaL_checkudata(L, 1, POSIX_SPAWNATTR_KEY);
+ lpgrp = luaL_checkinteger(L, 2);
+ if (lpgrp > INT_MAX || lpgrp < INT_MIN)
+ return (luaL_error(L, "pgrp too large: %jd", (intmax_t)lpgrp));
+ pgrp = (pid_t)lpgrp;
+
+ error = posix_spawnattr_setpgroup(attr, pgrp);
+ assert(error == 0);
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
static int
lua_getpid(lua_State *L)
{
@@ -166,6 +605,90 @@
}
#define REG_SIMPLE(n) { #n, lua_ ## n }
+static const struct luaL_Reg spawnlib[] = {
+ REG_SIMPLE(posix_spawn),
+ REG_SIMPLE(posix_spawnp),
+ REG_SIMPLE(posix_spawn_file_actions_init),
+ REG_SIMPLE(posix_spawn_file_actions_addopen),
+ REG_SIMPLE(posix_spawn_file_actions_adddup2),
+ REG_SIMPLE(posix_spawn_file_actions_addclose),
+
+ /*
+ * XXX-MJ should these be excluded from the posix module and instead
+ * included in a hypothetical freebsd.c.spawn module? Does the _np
+ * suffix have any formal significance in posix?
+ */
+ REG_SIMPLE(posix_spawn_file_actions_addclosefrom_np),
+ REG_SIMPLE(posix_spawn_file_actions_addchdir_np),
+ REG_SIMPLE(posix_spawn_file_actions_addfchdir_np),
+
+ REG_SIMPLE(posix_spawnattr_init),
+ REG_SIMPLE(posix_spawnattr_getflags),
+ REG_SIMPLE(posix_spawnattr_setflags),
+ REG_SIMPLE(posix_spawnattr_getpgroup),
+ REG_SIMPLE(posix_spawnattr_setpgroup),
+#ifdef notyet
+ REG_SIMPLE(posix_spawnattr_getsigdefault),
+ REG_SIMPLE(posix_spawnattr_setsigdefault),
+ REG_SIMPLE(posix_spawnattr_getsigmask),
+ REG_SIMPLE(posix_spawnattr_setsigmask),
+ REG_SIMPLE(posix_spawnattr_getschedparam),
+ REG_SIMPLE(posix_spawnattr_setschedparam),
+ REG_SIMPLE(posix_spawnattr_getschedpolicy),
+ REG_SIMPLE(posix_spawnattr_setschedpolicy),
+#endif
+ { NULL, NULL },
+};
+
+static int
+lua_posix_spawn_file_actions_destroy(lua_State *L)
+{
+ posix_spawn_file_actions_t *file_actions;
+
+ file_actions = luaL_checkudata(L, 1, POSIX_SPAWN_FILE_ACTIONS_KEY);
+ posix_spawn_file_actions_destroy(file_actions);
+ return (0);
+}
+
+static const struct luaL_Reg posix_spawn_file_actions_mt[] = {
+ { "__gc", lua_posix_spawn_file_actions_destroy },
+ { NULL, NULL }
+};
+
+static int
+lua_freebsd_sys_fd_gc(lua_State *L)
+{
+ int error, *fdp;
+
+ fdp = luaL_checkudata(L, 1, FREEBSD_SYS_FD_KEY);
+ if (*fdp != -1) {
+ error = close(*fdp);
+ assert(error == 0);
+ *fdp = -1;
+ }
+ return (0);
+}
+
+static const struct luaL_Reg lua_freebsd_sys_fd[] = {
+ { "__gc", lua_freebsd_sys_fd_gc },
+ { NULL, NULL },
+};
+
+static int
+lua_posix_spawnattr_destroy(lua_State *L)
+{
+ posix_spawnattr_t *attr;
+
+ attr = luaL_checkudata(L, 1, POSIX_SPAWNATTR_KEY);
+ posix_spawnattr_destroy(attr);
+ return (0);
+}
+
+static const struct luaL_Reg posix_spawnattr_mt[] = {
+ { "__gc", lua_posix_spawnattr_destroy },
+ { NULL, NULL }
+};
+
static const struct luaL_Reg sys_statlib[] = {
REG_SIMPLE(chmod),
{ NULL, NULL },
@@ -177,31 +700,67 @@
};
static const struct luaL_Reg unistdlib[] = {
- REG_SIMPLE(getpid),
REG_SIMPLE(chown),
+ { "close", lua_close_ }, /* XXX-MJ name collision */
+ REG_SIMPLE(getpid),
+ REG_SIMPLE(pipe),
{ NULL, NULL },
};
#undef REG_SIMPLE
+int
+luaopen_posix_spawn(lua_State *L)
+{
+ int ret;
+
+ ret = luaL_newmetatable(L, POSIX_SPAWN_FILE_ACTIONS_KEY);
+ assert(ret == 1);
+ luaL_setfuncs(L, posix_spawn_file_actions_mt, 0);
+ ret = luaL_newmetatable(L, POSIX_SPAWNATTR_KEY);
+ assert(ret == 1);
+ luaL_setfuncs(L, posix_spawnattr_mt, 0);
+
+ /* XXX-MJ this is generic and doesn't belong here */
+ ret = luaL_newmetatable(L, FREEBSD_SYS_FD_KEY);
+ assert(ret == 1);
+ luaL_setfuncs(L, lua_freebsd_sys_fd, 0);
+
+ luaL_newlib(L, spawnlib);
+#define ADDFLAG(c) \
+ lua_pushinteger(L, c); \
+ lua_setfield(L, -2, #c)
+ ADDFLAG(POSIX_SPAWN_RESETIDS);
+ ADDFLAG(POSIX_SPAWN_SETPGROUP);
+ ADDFLAG(POSIX_SPAWN_SETSIGDEF);
+ ADDFLAG(POSIX_SPAWN_SETSIGMASK);
+ ADDFLAG(POSIX_SPAWN_SETSCHEDPARAM);
+ ADDFLAG(POSIX_SPAWN_SETSCHEDULER);
+#ifdef POSIX_SPAWN_DISABLE_ASLR_NP
+ ADDFLAG(POSIX_SPAWN_DISABLE_ASLR_NP);
+#endif
+#undef ADDFLAG
+ return (1);
+}
+
int
luaopen_posix_sys_stat(lua_State *L)
{
luaL_newlib(L, sys_statlib);
- return 1;
+ return (1);
}
int
luaopen_posix_sys_utsname(lua_State *L)
{
luaL_newlib(L, sys_utsnamelib);
- return 1;
+ return (1);
}
int
luaopen_posix_unistd(lua_State *L)
{
luaL_newlib(L, unistdlib);
- return 1;
+ return (1);
}
/*
@@ -216,6 +775,7 @@
{
/* Somewhat duplicated from linit_flua.c */
static const luaL_Reg posixlibs[] = {
+ { "posix.spawn", luaopen_posix_spawn },
{ "posix.sys.stat", luaopen_posix_sys_stat },
{ "posix.sys.utsname", luaopen_posix_sys_utsname },
{ "posix.unistd", luaopen_posix_unistd },

File Metadata

Mime Type
text/plain
Expires
Fri, Sep 27, 12:57 PM (13 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
11420855
Default Alt Text
D46553.diff (14 KB)

Event Timeline