diff --git a/libexec/flua/linit_flua.c b/libexec/flua/linit_flua.c index 5cae7531b7da..8eaa4af1ffca 100644 --- a/libexec/flua/linit_flua.c +++ b/libexec/flua/linit_flua.c @@ -1,79 +1,80 @@ /* ** $Id: linit.c,v 1.39.1.1 2017/04/19 17:20:42 roberto Exp $ ** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ #define linit_c #define LUA_LIB /* ** If you embed Lua in your program and need to open the standard ** libraries, call luaL_openlibs in your program. If you need a ** different set of libraries, copy this file to your project and edit ** it to suit your needs. ** ** You can also *preload* libraries, so that a later 'require' can ** open the library, which is already linked to the application. ** For that, do the following code: ** ** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); ** lua_pushcfunction(L, luaopen_modname); ** lua_setfield(L, -2, modname); ** lua_pop(L, 1); // remove PRELOAD table */ #include "lprefix.h" #include #include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "lfs.h" #include "lposix.h" #include "lfbsd.h" /* ** these libs are loaded by lua.c and are readily available to any Lua ** program */ static const luaL_Reg loadedlibs[] = { {"_G", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_DBLIBNAME, luaopen_debug}, #if defined(LUA_COMPAT_BITLIB) {LUA_BITLIBNAME, luaopen_bit32}, #endif /* FreeBSD Extensions */ {"lfs", luaopen_lfs}, + {"posix.fnmatch", luaopen_posix_fnmatch}, {"posix.libgen", luaopen_posix_libgen}, {"posix.stdlib", luaopen_posix_stdlib}, {"posix.sys.stat", luaopen_posix_sys_stat}, {"posix.sys.utsname", luaopen_posix_sys_utsname}, {"posix.sys.wait", luaopen_posix_sys_wait}, {"posix.unistd", luaopen_posix_unistd}, {"fbsd", luaopen_fbsd}, {NULL, NULL} }; LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; /* "require" functions from 'loadedlibs' and set results to global table */ for (lib = loadedlibs; lib->func; lib++) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ } } diff --git a/libexec/flua/modules/lposix.c b/libexec/flua/modules/lposix.c index 77e152754b8c..0f3ea7722d4d 100644 --- a/libexec/flua/modules/lposix.c +++ b/libexec/flua/modules/lposix.c @@ -1,554 +1,595 @@ /*- * Copyright (c) 2019, 2023 Kyle Evans * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include +#include #include #include #include #include #include #include #include #include "lauxlib.h" #include "lposix.h" /* * Minimal implementation of luaposix needed for internal FreeBSD bits. */ static int lua__exit(lua_State *L) { int code, narg; narg = lua_gettop(L); luaL_argcheck(L, narg == 1, 1, "_exit takes exactly one argument"); code = luaL_checkinteger(L, 1); _exit(code); } static int lua_basename(lua_State *L) { char *inpath, *outpath; int narg; narg = lua_gettop(L); luaL_argcheck(L, narg > 0, 1, "at least one argument required"); inpath = strdup(luaL_checkstring(L, 1)); if (inpath == NULL) { lua_pushnil(L); lua_pushstring(L, strerror(ENOMEM)); lua_pushinteger(L, ENOMEM); return (3); } outpath = basename(inpath); lua_pushstring(L, outpath); free(inpath); return (1); } static int lua_chmod(lua_State *L) { int n; const char *path; mode_t mode; n = lua_gettop(L); luaL_argcheck(L, n == 2, n > 2 ? 3 : n, "chmod takes exactly two arguments"); path = luaL_checkstring(L, 1); mode = (mode_t)luaL_checkinteger(L, 2); if (chmod(path, mode) == -1) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); lua_pushinteger(L, errno); return (3); } lua_pushinteger(L, 0); return (1); } static int lua_chown(lua_State *L) { int n; const char *path; uid_t owner = (uid_t) -1; gid_t group = (gid_t) -1; n = lua_gettop(L); luaL_argcheck(L, n > 1, n, "chown takes at least two arguments"); path = luaL_checkstring(L, 1); if (lua_isinteger(L, 2)) owner = (uid_t) lua_tointeger(L, 2); else if (lua_isstring(L, 2)) { struct passwd *p = getpwnam(lua_tostring(L, 2)); if (p != NULL) owner = p->pw_uid; else return (luaL_argerror(L, 2, lua_pushfstring(L, "unknown user %s", lua_tostring(L, 2)))); } else if (!lua_isnoneornil(L, 2)) { const char *type = luaL_typename(L, 2); return (luaL_argerror(L, 2, lua_pushfstring(L, "integer or string expected, got %s", type))); } if (lua_isinteger(L, 3)) group = (gid_t) lua_tointeger(L, 3); else if (lua_isstring(L, 3)) { struct group *g = getgrnam(lua_tostring(L, 3)); if (g != NULL) group = g->gr_gid; else return (luaL_argerror(L, 3, lua_pushfstring(L, "unknown group %s", lua_tostring(L, 3)))); } else if (!lua_isnoneornil(L, 3)) { const char *type = luaL_typename(L, 3); return (luaL_argerror(L, 3, lua_pushfstring(L, "integer or string expected, got %s", type))); } if (chown(path, owner, group) == -1) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); lua_pushinteger(L, errno); return (3); } lua_pushinteger(L, 0); return (1); } static int lua_pclose(lua_State *L) { int error, fd, n; n = lua_gettop(L); luaL_argcheck(L, n == 1, 1, "close takes exactly one argument (fd)"); fd = luaL_checkinteger(L, 1); if (fd < 0) { error = EBADF; goto err; } if (close(fd) == 0) { lua_pushinteger(L, 0); return (1); } error = errno; err: lua_pushnil(L); lua_pushstring(L, strerror(error)); lua_pushinteger(L, error); return (3); } +static int +lua_fnmatch(lua_State *L) +{ + const char *pattern, *string; + int flags, n; + + n = lua_gettop(L); + luaL_argcheck(L, n == 2 || n == 3, 4, "need 2 or 3 arguments"); + + pattern = luaL_checkstring(L, 1); + string = luaL_checkstring(L, 2); + flags = luaL_optinteger(L, 3, 0); + lua_pushinteger(L, fnmatch(pattern, string, flags)); + + return (1); +} + static int lua_uname(lua_State *L) { struct utsname name; int error, n; n = lua_gettop(L); luaL_argcheck(L, n == 0, 1, "too many arguments"); error = uname(&name); if (error != 0) { error = errno; lua_pushnil(L); lua_pushstring(L, strerror(error)); lua_pushinteger(L, error); return (3); } lua_newtable(L); #define setkv(f) do { \ lua_pushstring(L, name.f); \ lua_setfield(L, -2, #f); \ } while (0) setkv(sysname); setkv(nodename); setkv(release); setkv(version); setkv(machine); #undef setkv return (1); } static int lua_dirname(lua_State *L) { char *inpath, *outpath; int narg; narg = lua_gettop(L); luaL_argcheck(L, narg > 0, 1, "dirname takes at least one argument (path)"); inpath = strdup(luaL_checkstring(L, 1)); if (inpath == NULL) { lua_pushnil(L); lua_pushstring(L, strerror(ENOMEM)); lua_pushinteger(L, ENOMEM); return (3); } outpath = dirname(inpath); lua_pushstring(L, outpath); free(inpath); return (1); } static int lua_fork(lua_State *L) { pid_t pid; int narg; narg = lua_gettop(L); luaL_argcheck(L, narg == 0, 1, "too many arguments"); pid = fork(); if (pid < 0) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); lua_pushinteger(L, errno); return (3); } lua_pushinteger(L, pid); return (1); } static int lua_getpid(lua_State *L) { int narg; narg = lua_gettop(L); luaL_argcheck(L, narg == 0, 1, "too many arguments"); lua_pushinteger(L, getpid()); return (1); } static int lua_pipe(lua_State *L) { int error, fd[2], narg; narg = lua_gettop(L); luaL_argcheck(L, narg == 0, 1, "too many arguments"); error = pipe(fd); if (error != 0) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); lua_pushinteger(L, errno); return (1); } lua_pushinteger(L, fd[0]); lua_pushinteger(L, fd[1]); return (2); } static int lua_read(lua_State *L) { char *buf; ssize_t ret; size_t sz; int error, fd, narg; narg = lua_gettop(L); luaL_argcheck(L, narg == 2, 1, "read takes exactly two arguments (fd, size)"); fd = luaL_checkinteger(L, 1); sz = luaL_checkinteger(L, 2); if (fd < 0) { error = EBADF; goto err; } buf = malloc(sz); if (buf == NULL) goto err; /* * For 0-byte reads, we'll still push the empty string and let the * caller deal with EOF to match lposix semantics. */ ret = read(fd, buf, sz); if (ret >= 0) lua_pushlstring(L, buf, ret); else if (ret < 0) error = errno; /* Save to avoid clobber by free() */ free(buf); if (error != 0) goto err; /* Just the string pushed. */ return (1); err: lua_pushnil(L); lua_pushstring(L, strerror(error)); lua_pushinteger(L, error); return (3); } static int lua_realpath(lua_State *L) { const char *inpath; char *outpath; int narg; narg = lua_gettop(L); luaL_argcheck(L, narg > 0, 1, "at least one argument required"); inpath = luaL_checkstring(L, 1); outpath = realpath(inpath, NULL); if (outpath == NULL) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); lua_pushinteger(L, errno); return (3); } lua_pushstring(L, outpath); free(outpath); return (1); } static int lua_wait(lua_State *L) { pid_t pid; int options, status; int narg; narg = lua_gettop(L); pid = -1; status = options = 0; if (narg >= 1 && !lua_isnil(L, 1)) pid = luaL_checkinteger(L, 1); if (narg >= 2 && !lua_isnil(L, 2)) options = luaL_checkinteger(L, 2); pid = waitpid(pid, &status, options); if (pid < 0) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); lua_pushinteger(L, errno); return (3); } lua_pushinteger(L, pid); if (pid == 0) { lua_pushliteral(L, "running"); return (2); } if (WIFCONTINUED(status)) { lua_pushliteral(L, "continued"); return (2); } else if(WIFSTOPPED(status)) { lua_pushliteral(L, "stopped"); lua_pushinteger(L, WSTOPSIG(status)); return (3); } else if (WIFEXITED(status)) { lua_pushliteral(L, "exited"); lua_pushinteger(L, WEXITSTATUS(status)); return (3); } else if (WIFSIGNALED(status)) { lua_pushliteral(L, "killed"); lua_pushinteger(L, WTERMSIG(status)); return (3); } return (1); } static int lua_write(lua_State *L) { const char *buf; size_t bufsz, sz; ssize_t ret; off_t offset; int error, fd, narg; narg = lua_gettop(L); luaL_argcheck(L, narg >= 2, 1, "write takes at least two arguments (fd, buf, sz, off)"); luaL_argcheck(L, narg <= 4, 5, "write takes no more than four arguments (fd, buf, sz, off)"); fd = luaL_checkinteger(L, 1); if (fd < 0) { error = EBADF; goto err; } buf = luaL_checkstring(L, 2); bufsz = sz = lua_rawlen(L, 2); if (narg >= 3 && !lua_isnil(L, 3)) sz = luaL_checkinteger(L, 3); offset = 0; if (narg >= 4 && !lua_isnil(L, 4)) offset = luaL_checkinteger(L, 4); if ((size_t)offset > bufsz || offset + sz > bufsz) { lua_pushnil(L); lua_pushfstring(L, "write: invalid access offset %zu, size %zu in a buffer size %zu", offset, sz, bufsz); lua_pushinteger(L, EINVAL); return (3); } ret = write(fd, buf + offset, sz); if (ret < 0) { error = errno; goto err; } lua_pushinteger(L, ret); return (1); err: lua_pushnil(L); lua_pushstring(L, strerror(error)); lua_pushinteger(L, error); return (3); } #define REG_DEF(n, func) { #n, func } #define REG_SIMPLE(n) REG_DEF(n, lua_ ## n) static const struct luaL_Reg libgenlib[] = { REG_SIMPLE(basename), REG_SIMPLE(dirname), { NULL, NULL }, }; static const struct luaL_Reg stdliblib[] = { REG_SIMPLE(realpath), { NULL, NULL }, }; +static const struct luaL_Reg fnmatchlib[] = { + REG_SIMPLE(fnmatch), + { NULL, NULL }, +}; + static const struct luaL_Reg sys_statlib[] = { REG_SIMPLE(chmod), { NULL, NULL }, }; static const struct luaL_Reg sys_utsnamelib[] = { REG_SIMPLE(uname), { NULL, NULL }, }; static const struct luaL_Reg sys_waitlib[] = { REG_SIMPLE(wait), {NULL, NULL}, }; static const struct luaL_Reg unistdlib[] = { REG_SIMPLE(_exit), REG_SIMPLE(chown), REG_DEF(close, lua_pclose), REG_SIMPLE(fork), REG_SIMPLE(getpid), REG_SIMPLE(pipe), REG_SIMPLE(read), REG_SIMPLE(write), { NULL, NULL }, }; #undef REG_SIMPLE #undef REG_DEF int luaopen_posix_libgen(lua_State *L) { luaL_newlib(L, libgenlib); return (1); } int luaopen_posix_stdlib(lua_State *L) { luaL_newlib(L, stdliblib); return (1); } +int +luaopen_posix_fnmatch(lua_State *L) +{ + luaL_newlib(L, fnmatchlib); + +#define setkv(f) do { \ + lua_pushinteger(L, f); \ + lua_setfield(L, -2, #f); \ +} while (0) + setkv(FNM_PATHNAME); + setkv(FNM_NOESCAPE); + setkv(FNM_NOMATCH); + setkv(FNM_PERIOD); +#undef setkv + + return 1; +} + int luaopen_posix_sys_stat(lua_State *L) { luaL_newlib(L, sys_statlib); return (1); } int luaopen_posix_sys_wait(lua_State *L) { luaL_newlib(L, sys_waitlib); #define lua_pushflag(L, flag) do { \ lua_pushinteger(L, flag); \ lua_setfield(L, -2, #flag); \ } while(0) /* Only these two exported by lposix */ lua_pushflag(L, WNOHANG); lua_pushflag(L, WUNTRACED); lua_pushflag(L, WCONTINUED); lua_pushflag(L, WSTOPPED); #ifdef WTRAPPED lua_pushflag(L, WTRAPPED); #endif lua_pushflag(L, WEXITED); lua_pushflag(L, WNOWAIT); #undef lua_pushflag return (1); } int luaopen_posix_sys_utsname(lua_State *L) { luaL_newlib(L, sys_utsnamelib); return 1; } int luaopen_posix_unistd(lua_State *L) { luaL_newlib(L, unistdlib); return (1); } diff --git a/libexec/flua/modules/lposix.h b/libexec/flua/modules/lposix.h index 9d2c97b0d2dc..da7079056826 100644 --- a/libexec/flua/modules/lposix.h +++ b/libexec/flua/modules/lposix.h @@ -1,15 +1,16 @@ /*- * * This file is in the public domain. */ #pragma once #include +int luaopen_posix_fnmatch(lua_State *L); int luaopen_posix_libgen(lua_State *L); int luaopen_posix_stdlib(lua_State *L); int luaopen_posix_sys_stat(lua_State *L); int luaopen_posix_sys_utsname(lua_State *L); int luaopen_posix_sys_wait(lua_State *L); int luaopen_posix_unistd(lua_State *L);