aboutsummaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2024-09-09 15:17:27 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2024-09-12 07:03:44 +0000
commit7899f917b1c0ea178f1d2be0cfb452086d079d23 (patch)
tree82f36a60bad849ea06999c0eeb006f920ede71a9 /libexec
parentd82cb5c608ae9aaced4cb459ca511e62c64dbf74 (diff)
Diffstat (limited to 'libexec')
-rw-r--r--libexec/flua/Makefile5
-rw-r--r--libexec/flua/Makefile.inc5
-rw-r--r--libexec/flua/libfreebsd/Makefile3
-rw-r--r--libexec/flua/libfreebsd/Makefile.inc1
-rw-r--r--libexec/flua/libfreebsd/sys/Makefile4
-rw-r--r--libexec/flua/libfreebsd/sys/Makefile.inc1
-rw-r--r--libexec/flua/libfreebsd/sys/linker/Makefile7
-rw-r--r--libexec/flua/libfreebsd/sys/linker/freebsd.sys.linker.3lua67
-rw-r--r--libexec/flua/libfreebsd/sys/linker/linker.c104
-rw-r--r--libexec/flua/libhash/Makefile9
-rw-r--r--libexec/flua/libhash/hash.3lua54
-rw-r--r--libexec/flua/libhash/lhash.c177
-rw-r--r--libexec/flua/libhash/lhash.h11
-rw-r--r--libexec/flua/libjail/Makefile9
-rw-r--r--libexec/flua/libjail/jail.3lua277
-rw-r--r--libexec/flua/libjail/lua_jail.c710
-rw-r--r--libexec/flua/libucl/Makefile14
17 files changed, 1458 insertions, 0 deletions
diff --git a/libexec/flua/Makefile b/libexec/flua/Makefile
index c8206b94769d..08ea9c002d61 100644
--- a/libexec/flua/Makefile
+++ b/libexec/flua/Makefile
@@ -1,5 +1,10 @@
.include <src.lua.mk>
+SUBDIR+= libfreebsd
+SUBDIR+= libhash
+SUBDIR+= libjail
+SUBDIR+= libucl
+
LUASRC?= ${SRCTOP}/contrib/lua/src
.PATH: ${LUASRC}
diff --git a/libexec/flua/Makefile.inc b/libexec/flua/Makefile.inc
new file mode 100644
index 000000000000..34505d54d7df
--- /dev/null
+++ b/libexec/flua/Makefile.inc
@@ -0,0 +1,5 @@
+SHLIBDIR?= ${LIBDIR}/flua
+
+CFLAGS+= \
+ -I${SRCTOP}/contrib/lua/src \
+ -I${SRCTOP}/lib/liblua
diff --git a/libexec/flua/libfreebsd/Makefile b/libexec/flua/libfreebsd/Makefile
new file mode 100644
index 000000000000..6ed0451055ff
--- /dev/null
+++ b/libexec/flua/libfreebsd/Makefile
@@ -0,0 +1,3 @@
+SUBDIR+= sys
+
+.include <bsd.subdir.mk>
diff --git a/libexec/flua/libfreebsd/Makefile.inc b/libexec/flua/libfreebsd/Makefile.inc
new file mode 100644
index 000000000000..01b5f23410c8
--- /dev/null
+++ b/libexec/flua/libfreebsd/Makefile.inc
@@ -0,0 +1 @@
+.include "../Makefile.inc"
diff --git a/libexec/flua/libfreebsd/sys/Makefile b/libexec/flua/libfreebsd/sys/Makefile
new file mode 100644
index 000000000000..9f38294536f2
--- /dev/null
+++ b/libexec/flua/libfreebsd/sys/Makefile
@@ -0,0 +1,4 @@
+SUBDIR+= linker
+
+.include <bsd.subdir.mk>
+
diff --git a/libexec/flua/libfreebsd/sys/Makefile.inc b/libexec/flua/libfreebsd/sys/Makefile.inc
new file mode 100644
index 000000000000..01b5f23410c8
--- /dev/null
+++ b/libexec/flua/libfreebsd/sys/Makefile.inc
@@ -0,0 +1 @@
+.include "../Makefile.inc"
diff --git a/libexec/flua/libfreebsd/sys/linker/Makefile b/libexec/flua/libfreebsd/sys/linker/Makefile
new file mode 100644
index 000000000000..1adf547b503c
--- /dev/null
+++ b/libexec/flua/libfreebsd/sys/linker/Makefile
@@ -0,0 +1,7 @@
+SHLIB_NAME= linker.so
+
+SRCS+= linker.c
+
+MAN= freebsd.sys.linker.3lua
+
+.include <bsd.lib.mk>
diff --git a/libexec/flua/libfreebsd/sys/linker/freebsd.sys.linker.3lua b/libexec/flua/libfreebsd/sys/linker/freebsd.sys.linker.3lua
new file mode 100644
index 000000000000..0ab8f185388a
--- /dev/null
+++ b/libexec/flua/libfreebsd/sys/linker/freebsd.sys.linker.3lua
@@ -0,0 +1,67 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2024, Baptiste Daroussin <bapt@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd September 6, 2024
+.Dt FREEBSD.SYS.LINKER 3lua
+.Os
+.Sh NAME
+.Nm freebsd.sys.linker
+.Nd Lua binding to
+.Fx 's
+Linker functions
+.Sh SYNOPSIS
+.Bd -literal
+local linker = require('freebsd.sys.linker')
+.Ed
+.Pp
+.Bl -tag -width XXXX -compact
+.It Dv fileid, err, errno = linker.kldload(name)
+.It Dv ok, err, errno = linker.kldunload(fileid|name)
+.El
+.Sh DESCRIPTION
+The
+.Nm
+module is a binding to the
+.Fx 's
+linker functions.
+List of functions:
+.Bl -tag -width XXXX
+.It Dv fileid, err = freebsd.sys.linker.kldload(name)
+Load the kernel module named
+.Fa name
+and return the identifier
+.Pq fileid
+as an interger.
+.It Dv ok, err, errno = freebsd.sys.linker.kldunload(fileid|name)
+Unload the kernel module identifier either by
+.Fa name
+as a string, or
+.Fa fileid
+as an integer.
+.El
+.Sh SEE ALSO
+.Xr kldload 2 ,
+.Xr kldunload 2
diff --git a/libexec/flua/libfreebsd/sys/linker/linker.c b/libexec/flua/libfreebsd/sys/linker/linker.c
new file mode 100644
index 000000000000..a2dc3b487525
--- /dev/null
+++ b/libexec/flua/libfreebsd/sys/linker/linker.c
@@ -0,0 +1,104 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024, Baptiste Daroussin <bapt@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+#include <sys/linker.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+int luaopen_freebsd_sys_linker(lua_State *L);
+
+static int
+lua_kldload(lua_State *L)
+{
+ const char *name;
+ int ret;
+
+ name = luaL_checkstring(L, 1);
+ ret = kldload(name);
+ if (ret == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ lua_pushinteger(L, errno);
+ return (3);
+ }
+ lua_pushinteger(L, ret);
+ return (1);
+}
+
+static int
+lua_kldunload(lua_State *L)
+{
+ const char *name;
+ int ret, fileid;
+
+ if (lua_isinteger(L, 1)) {
+ fileid = lua_tointeger(L, 1);
+ } else {
+ name = luaL_checkstring(L, 1);
+ fileid = kldfind(name);
+ }
+ if (fileid == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ lua_pushinteger(L, errno);
+ return (3);
+ }
+ ret = kldunload(fileid);
+ lua_pushinteger(L, ret);
+ if (ret == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ lua_pushinteger(L, errno);
+ return (3);
+ }
+ lua_pushinteger(L, 0);
+ return (1);
+}
+
+#define REG_SIMPLE(n) { #n, lua_ ## n }
+static const struct luaL_Reg freebsd_sys_linker[] = {
+ REG_SIMPLE(kldload),
+ REG_SIMPLE(kldunload),
+ { NULL, NULL },
+};
+#undef REG_SIMPLE
+
+int
+luaopen_freebsd_sys_linker(lua_State *L)
+{
+ luaL_newlib(L, freebsd_sys_linker);
+
+ return (1);
+}
diff --git a/libexec/flua/libhash/Makefile b/libexec/flua/libhash/Makefile
new file mode 100644
index 000000000000..b7c8d7ee9948
--- /dev/null
+++ b/libexec/flua/libhash/Makefile
@@ -0,0 +1,9 @@
+SHLIB_NAME= hash.so
+
+SRCS+= lhash.c
+
+LIBADD+= md
+
+MAN= hash.3lua
+
+.include <bsd.lib.mk>
diff --git a/libexec/flua/libhash/hash.3lua b/libexec/flua/libhash/hash.3lua
new file mode 100644
index 000000000000..1662e87f7c68
--- /dev/null
+++ b/libexec/flua/libhash/hash.3lua
@@ -0,0 +1,54 @@
+.\"
+.\" Copyright (c) 2024 Netflix, Inc.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd February 6, 2024
+.Dt HASH 3lua
+.Os
+.Sh NAME
+.Nm new ,
+.Nm update ,
+.Nm digest ,
+.Nm hexdigest
+.Nd Lua Cryptographic hash module.
+.Sh DESCRIPTION
+The built-in cryptographic hashing Lua bindings for the are available via the
+.Ic hash
+table.
+.Ss Supported Hashing Schemes
+The following hashing schemes are supported by the hash module.
+.Bl -bullet -compact
+.It
+sha256
+.El
+.Ss APIs Supported
+.Bl -tag -width asdf -compact
+.It Fn new data
+Compute a digest based on the
+.Va data .
+.It Fn update Va data
+Using the current digest, process
+.Va data
+to compute a new digest as if all prior data had been concatenated together.
+.It Fn digest
+Return the hashed digest as a binary array.
+This resets the context.
+.It Fn hexdigest
+Take
+.Fn digest
+and convert it to an upper case hex string.
+This resets the context.
+.It Va digest_size
+Return the size of the digest, in bytes.
+.It Va block_size
+Return the block size used in bytes.
+.El
+.Sh EXAMPLES
+.Sh SEE ALSO
+.Xr sha256 3
+.Sh AUTHORS
+The
+.Nm
+man page was written by
+.An Warner Losh Aq Mt imp@FreeBSD.org .
diff --git a/libexec/flua/libhash/lhash.c b/libexec/flua/libhash/lhash.c
new file mode 100644
index 000000000000..4587961fe8a0
--- /dev/null
+++ b/libexec/flua/libhash/lhash.c
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (c) 2024 Netflix, Inc
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <lua.h>
+#include "lauxlib.h"
+#include "lhash.h"
+
+#include <sha256.h>
+#include <string.h>
+
+#define SHA256_META "SHA256 meta table"
+#define SHA256_DIGEST_LEN 32
+
+/*
+ * Note C++ comments indicate the before -- after state of the stack, in with a
+ * similar convention to forth's ( ) comments. Lua indexes are from 1 and can be
+ * read left to right (leftmost is 1). Negative are relative to the end (-1 is
+ * rightmost). A '.' indicates a return value left on the stack (all values to
+ * its right). Trivial functions don't do this.
+ */
+
+/*
+ * Updates the digest with the new data passed in. Takes 1 argument, which
+ * is converted to a string.
+ */
+static int
+lua_sha256_update(lua_State *L)
+{
+ size_t len;
+ const unsigned char *data;
+ SHA256_CTX *ctx;
+
+ ctx = luaL_checkudata(L, 1, SHA256_META);
+ data = luaL_checklstring(L, 2, &len);
+ SHA256_Update(ctx, data, len);
+
+ lua_settop(L, 1);
+
+ return (1);
+}
+
+/*
+ * Finalizes the digest value and returns it as a 32-byte binary string. The ctx
+ * is zeroed.
+ */
+static int
+lua_sha256_digest(lua_State *L)
+{
+ SHA256_CTX *ctx;
+ unsigned char digest[SHA256_DIGEST_LEN];
+
+ ctx = luaL_checkudata(L, 1, SHA256_META);
+ SHA256_Final(digest, ctx);
+ lua_pushlstring(L, digest, sizeof(digest));
+
+ return (1);
+}
+
+/*
+ * Finalizes the digest value and returns it as a 64-byte ascii string of hex
+ * numbers. The ctx is zeroed.
+ */
+static int
+lua_sha256_hexdigest(lua_State *L)
+{
+ SHA256_CTX *ctx;
+ char buf[SHA256_DIGEST_LEN * 2 + 1];
+ unsigned char digest[SHA256_DIGEST_LEN];
+ static const char hex[]="0123456789abcdef";
+ int i;
+
+ ctx = luaL_checkudata(L, 1, SHA256_META);
+ SHA256_Final(digest, ctx);
+ for (i = 0; i < SHA256_DIGEST_LEN; i++) {
+ buf[i+i] = hex[digest[i] >> 4];
+ buf[i+i+1] = hex[digest[i] & 0x0f];
+ }
+ buf[i+i] = '\0';
+
+ lua_pushstring(L, buf);
+
+ return (1);
+}
+
+/*
+ * Zeros out the ctx before garbage collection. Normally this is done in
+ * obj:digest or obj:hexdigest, but if not, it will be wiped here. Lua
+ * manages freeing the ctx memory.
+ */
+static int
+lua_sha256_done(lua_State *L)
+{
+ SHA256_CTX *ctx;
+
+ ctx = luaL_checkudata(L, 1, SHA256_META);
+ memset(ctx, 0, sizeof(*ctx));
+
+ return (0);
+}
+
+/*
+ * Create object obj which accumulates the state of the sha256 digest
+ * for its contents and any subsequent obj:update call. It takes zero
+ * or 1 arguments.
+ */
+static int
+lua_sha256(lua_State *L)
+{
+ SHA256_CTX *ctx;
+ int top;
+
+ /* We take 0 or 1 args */
+ top = lua_gettop(L); // data -- data
+ if (top > 1) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ ctx = lua_newuserdata(L, sizeof(*ctx)); // data -- data ctx
+ SHA256_Init(ctx);
+ if (top == 1) {
+ size_t len;
+ const unsigned char *data;
+
+ data = luaL_checklstring(L, 1, &len);
+ SHA256_Update(ctx, data, len);
+ }
+ luaL_setmetatable(L, SHA256_META); // data ctx -- data ctx
+
+ return (1); // data . ctx
+}
+
+/*
+ * Setup the metatable to manage our userdata that we create in lua_sha256. We
+ * request a finalization call with __gc so we can zero out the ctx buffer so
+ * that we don't leak secrets if obj:digest or obj:hexdigest aren't called.
+ */
+static void
+register_metatable_sha256(lua_State *L)
+{
+ luaL_newmetatable(L, SHA256_META); // -- meta
+
+ lua_newtable(L); // meta -- meta tbl
+ lua_pushcfunction(L, lua_sha256_update); // meta tbl -- meta tbl fn
+ lua_setfield(L, -2, "update"); // meta tbl fn -- meta tbl
+ lua_pushcfunction(L, lua_sha256_digest); // meta tbl -- meta tbl fn
+ lua_setfield(L, -2, "digest"); // meta tbl fn -- meta tbl
+ lua_pushcfunction(L, lua_sha256_hexdigest); // meta tbl -- meta tbl fn
+ lua_setfield(L, -2, "hexdigest"); // meta tbl fn -- meta tbl
+
+ /* Associate tbl with metatable */
+ lua_setfield(L, -2, "__index"); // meta tbl -- meta
+ lua_pushcfunction(L, lua_sha256_done); // meta -- meta fn
+ lua_setfield(L, -2, "__gc"); // meta fn -- meta
+
+ lua_pop(L, 1); // meta --
+}
+
+#define REG_SIMPLE(n) { #n, lua_ ## n }
+static const struct luaL_Reg hashlib[] = {
+ REG_SIMPLE(sha256),
+ { NULL, NULL },
+};
+#undef REG_SIMPLE
+
+int
+luaopen_hash(lua_State *L)
+{
+ register_metatable_sha256(L);
+
+ luaL_newlib(L, hashlib);
+
+ return 1;
+}
diff --git a/libexec/flua/libhash/lhash.h b/libexec/flua/libhash/lhash.h
new file mode 100644
index 000000000000..c1e9788a55a3
--- /dev/null
+++ b/libexec/flua/libhash/lhash.h
@@ -0,0 +1,11 @@
+/*-
+ * Copyright (c) 2024 Netflix, Inc
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <lua.h>
+
+int luaopen_hash(lua_State *L);
diff --git a/libexec/flua/libjail/Makefile b/libexec/flua/libjail/Makefile
new file mode 100644
index 000000000000..20cd9f5f1429
--- /dev/null
+++ b/libexec/flua/libjail/Makefile
@@ -0,0 +1,9 @@
+SHLIB_NAME= jail.so
+
+SRCS+= lua_jail.c
+
+LIBADD+= jail
+
+MAN= jail.3lua
+
+.include <bsd.lib.mk>
diff --git a/libexec/flua/libjail/jail.3lua b/libexec/flua/libjail/jail.3lua
new file mode 100644
index 000000000000..59cbd2dc228c
--- /dev/null
+++ b/libexec/flua/libjail/jail.3lua
@@ -0,0 +1,277 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2020, Ryan Moeller <freqlabs@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd October 24, 2020
+.Dt JAIL 3lua
+.Os
+.Sh NAME
+.Nm attach ,
+.Nm getid ,
+.Nm getname ,
+.Nm list ,
+.Nm allparams ,
+.Nm getparams ,
+.Nm remove ,
+.Nm setparams ,
+.Nm CREATE ,
+.Nm UPDATE ,
+.Nm ATTACH ,
+.Nm DYING
+.Nd Lua binding to
+.Xr jail 3
+.Sh SYNOPSIS
+.Bd -literal
+local jail = require('jail')
+.Ed
+.Pp
+.Bl -tag -width XXXX -compact
+.It Dv ok, err = jail.attach(jid|name)
+.It Dv jid, err = jail.getid(name)
+.It Dv name, err = jail.getname(jid)
+.It Dv params, err = jail.allparams()
+.It Dv iter, jail_obj = jail.list([params])
+.It Dv jid, res = jail.getparams(jid|name, params [, flags ] )
+.It Dv ok, err = jail.remove(jid|name)
+.It Dv jid, err = jail.setparams(jid|name, params, flags )
+.It Dv jail.CREATE
+.It Dv jail.UPDATE
+.It Dv jail.ATTACH
+.It Dv jail.DYING
+.El
+.Sh DESCRIPTION
+The
+.Nm jail
+module is a binding to the
+.Xr jail 3
+library.
+It provides a string-oriented interface for the
+.Xr jail_get 2
+and
+.Xr jail_set 2
+system calls.
+.Bl -tag -width XXXX
+.It Dv ok, err = jail.attach(jid|name)
+Attach to the given jail, identified by an integer
+.Fa jid
+or the
+.Fa name .
+.It Dv jid, err = jail.getid(name)
+Get the jail identifier
+.Pq jid
+as an integer.
+.Fa name
+is the name of a jail or a jid in the form of a string.
+.It Dv name, err = jail.getname(jid)
+Get the name of a jail as a string for the given
+.Fa jid
+.Pq an integer .
+.It Dv iter, jail_obj = jail.list([params])
+Returns an iterator over running jails on the system.
+.Dv params
+is a list of parameters to fetch for each jail as we iterate.
+.Dv jid
+and
+.Dv name
+will always be returned, and may be omitted from
+.Dv params .
+Additionally,
+.Dv params
+may be omitted or an empty table, but not nil.
+.Pp
+See
+.Sx EXAMPLES .
+.It Dv params, err = jail.allparams()
+Get a list of all supported parameter names
+.Pq as strings .
+See
+.Xr jail 8
+for descriptions of the core jail parameters.
+.It Dv jid, res = jail.getparams(jid|name, params [, flags ] )
+Get a table of the requested parameters for the given jail.
+.Nm jid|name
+can either be the jid as an integer or the jid or name as a string.
+.Nm params
+is a list of parameter names.
+.Nm flags
+is an optional integer representing the flag bits to apply for the operation.
+See the list of flags below.
+Only the
+.Dv DYING
+flag is valid to set.
+.It Dv ok, err = jail.remove(jid|name)
+Remove the given jail, identified by an integer
+.Fa jid
+or the
+.Fa name .
+.It Dv jid, err = jail.setparams(jid|name, params [, flags ] )
+Set parameters for a given jail.
+This is used to create, update, attach to, or destroy a jail.
+.Nm jid|name
+can either be the jid as an integer or the jid or name as a string.
+.Nm params
+is a table of parameters to apply to the jail, where each key in the table
+is a parameter name as a string and each value is a string that will be
+converted to the internal value type by
+.Xr jailparam_import 3 .
+.Nm flags
+is an optional integer representing the flag bits to apply for the operation.
+See the list of flags below.
+.El
+.Pp
+The
+.Nm flags
+arguments are an integer bitwise-or combination of one or more of the following
+flags:
+.Bl -tag -width XXXX
+.It Dv jail.CREATE
+Used with
+.Fn setparams
+to create a new jail.
+The jail must not already exist, unless combined with
+.Dv UPDATE .
+.It Dv jail.UPDATE
+Used with
+.Fn setparams
+to modify an existing jail.
+The jail must already exist, unless combined with
+.Dv CREATE .
+.It Dv jail.ATTACH
+Used with
+.Fn setparams
+in combination with
+.Dv CREATE
+or
+.Dv UPDATE
+to attach the current process to a jail.
+.It Dv jail.DYING
+Allow operating on a jail that is in the process of being removed.
+.El
+.Sh RETURN VALUES
+The
+.Fn getid
+and
+.Fn setparams
+functions return a jail identifier integer on success, or
+.Dv nil
+and an error message string if an error occurred.
+.Pp
+The
+.Fn getname
+function returns a jail name string on success, or
+.Dv nil
+and an error message string if an error occurred.
+.Pp
+The
+.Fn allparams
+function returns a list of parameter name strings on success, or
+.Dv nil
+and an error message string if an error occurred.
+.Pp
+The
+.Fn getparams
+function returns a jail identifier integer and a table of jail parameters
+with parameter name strings as keys and strings for values on success, or
+.Dv nil
+and an error message string if an error occurred.
+.Pp
+The
+.Fn list
+function returns an iterator over the list of running jails.
+.Pp
+The
+.Fn attach
+and
+.Fn remove
+functions return true on success, or
+.Dv nil
+and an error message string if an error occurred.
+.Sh EXAMPLES
+Set the hostname of jail
+.Dq foo
+to
+.Dq foo.bar :
+.Bd -literal -offset indent
+local jail = require('jail')
+
+jid, err = jail.setparams("foo", {["host.hostname"]="foo.bar"},
+ jail.UPDATE)
+if not jid then
+ error(err)
+end
+.Ed
+.Pp
+Retrieve the hostname of jail
+.Dq foo :
+.Bd -literal -offset indent
+local jail = require('jail')
+
+jid, res = jail.getparams("foo", {"host.hostname"})
+if not jid then
+ error(res)
+end
+print(res["host.hostname"])
+.Ed
+.Pp
+Iterate over jails on the system:
+.Bd -literal -offset indent
+local jail = require('jail')
+
+-- Recommended: just loop over it
+for jparams in jail.list() do
+ print(jparams["jid"] .. " = " .. jparams["name"])
+end
+
+-- Request path and hostname, too
+for jparams in jail.list({"path", "host.hostname"}) do
+ print(jparams["host.hostname"] .. " mounted at " .. jparams["path"])
+end
+
+-- Raw iteration protocol
+local iter, jail_obj = jail.list()
+
+-- Request the first params
+local jparams = jail_obj:next()
+while jparams do
+ print(jparams["jid"] .. " = " .. jparams["name"])
+ -- Subsequent calls may return nil
+ jparams = jail_obj:next()
+end
+.Ed
+.Sh SEE ALSO
+.Xr jail 2 ,
+.Xr jail 3 ,
+.Xr jail 8
+.Sh HISTORY
+The
+.Nm jail
+Lua module for flua first appeared in
+.Fx 13.0 .
+.Sh AUTHORS
+.An Ryan Moeller ,
+with inspiration from
+.Nx
+gpio(3lua), by
+.An Mark Balmer .
diff --git a/libexec/flua/libjail/lua_jail.c b/libexec/flua/libjail/lua_jail.c
new file mode 100644
index 000000000000..f364b090b3f9
--- /dev/null
+++ b/libexec/flua/libjail/lua_jail.c
@@ -0,0 +1,710 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020, Ryan Moeller <freqlabs@FreeBSD.org>
+ * Copyright (c) 2020, Kyle Evans <kevans@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/jail.h>
+#include <errno.h>
+#include <jail.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#define JAIL_METATABLE "jail iterator metatable"
+
+/*
+ * Taken from RhodiumToad's lspawn implementation, let static analyzers make
+ * better decisions about the behavior after we raise an error.
+ */
+#if defined(LUA_VERSION_NUM) && defined(LUA_API)
+LUA_API int (lua_error) (lua_State *L) __dead2;
+#endif
+#if defined(LUA_ERRFILE) && defined(LUALIB_API)
+LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg) __dead2;
+LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname) __dead2;
+LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...) __dead2;
+#endif
+
+int luaopen_jail(lua_State *);
+
+typedef bool (*getparam_filter)(const char *, void *);
+
+static void getparam_table(lua_State *L, int paramindex,
+ struct jailparam *params, size_t paramoff, size_t *params_countp,
+ getparam_filter keyfilt, void *udata);
+
+struct l_jail_iter {
+ struct jailparam *params;
+ size_t params_count;
+ int jid;
+};
+
+static bool
+l_jail_filter(const char *param_name, void *data __unused)
+{
+
+ /*
+ * Allowing lastjid will mess up our iteration over all jails on the
+ * system, as this is a special parameter that indicates where the search
+ * starts from. We'll always add jid and name, so just silently remove
+ * these.
+ */
+ return (strcmp(param_name, "lastjid") != 0 &&
+ strcmp(param_name, "jid") != 0 &&
+ strcmp(param_name, "name") != 0);
+}
+
+static int
+l_jail_iter_next(lua_State *L)
+{
+ struct l_jail_iter *iter, **iterp;
+ struct jailparam *jp;
+ int serrno;
+
+ iterp = (struct l_jail_iter **)luaL_checkudata(L, 1, JAIL_METATABLE);
+ iter = *iterp;
+ luaL_argcheck(L, iter != NULL, 1, "closed jail iterator");
+
+ jp = iter->params;
+ /* Populate lastjid; we must keep it in params[0] for our sake. */
+ if (jailparam_import_raw(&jp[0], &iter->jid, sizeof(iter->jid))) {
+ jailparam_free(jp, iter->params_count);
+ free(jp);
+ free(iter);
+ *iterp = NULL;
+ return (luaL_error(L, "jailparam_import_raw: %s", jail_errmsg));
+ }
+
+ /* The list of requested params was populated back in l_list(). */
+ iter->jid = jailparam_get(jp, iter->params_count, 0);
+ if (iter->jid == -1) {
+ /*
+ * We probably got an ENOENT to signify the end of the jail
+ * listing, but just in case we didn't; stash it off and start
+ * cleaning up. We'll handle non-ENOENT errors later.
+ */
+ serrno = errno;
+ jailparam_free(jp, iter->params_count);
+ free(iter->params);
+ free(iter);
+ *iterp = NULL;
+ if (serrno != ENOENT)
+ return (luaL_error(L, "jailparam_get: %s",
+ strerror(serrno)));
+ return (0);
+ }
+
+ /*
+ * Finally, we'll fill in the return table with whatever parameters the
+ * user requested, in addition to the ones we forced with exception to
+ * lastjid.
+ */
+ lua_newtable(L);
+ for (size_t i = 0; i < iter->params_count; ++i) {
+ char *value;
+
+ jp = &iter->params[i];
+ if (strcmp(jp->jp_name, "lastjid") == 0)
+ continue;
+ value = jailparam_export(jp);
+ lua_pushstring(L, value);
+ lua_setfield(L, -2, jp->jp_name);
+ free(value);
+ }
+
+ return (1);
+}
+
+static int
+l_jail_iter_close(lua_State *L)
+{
+ struct l_jail_iter *iter, **iterp;
+
+ /*
+ * Since we're using this as the __gc method as well, there's a good
+ * chance that it's already been cleaned up by iterating to the end of
+ * the list.
+ */
+ iterp = (struct l_jail_iter **)lua_touserdata(L, 1);
+ iter = *iterp;
+ if (iter == NULL)
+ return (0);
+
+ jailparam_free(iter->params, iter->params_count);
+ free(iter->params);
+ free(iter);
+ *iterp = NULL;
+ return (0);
+}
+
+static int
+l_list(lua_State *L)
+{
+ struct l_jail_iter *iter;
+ int nargs;
+
+ nargs = lua_gettop(L);
+ if (nargs >= 1)
+ luaL_checktype(L, 1, LUA_TTABLE);
+
+ iter = malloc(sizeof(*iter));
+ if (iter == NULL)
+ return (luaL_error(L, "malloc: %s", strerror(errno)));
+
+ /*
+ * lastjid, jid, name + length of the table. This may be too much if
+ * we have duplicated one of those fixed parameters.
+ */
+ iter->params_count = 3 + (nargs != 0 ? lua_rawlen(L, 1) : 0);
+ iter->params = malloc(iter->params_count * sizeof(*iter->params));
+ if (iter->params == NULL) {
+ free(iter);
+ return (luaL_error(L, "malloc params: %s", strerror(errno)));
+ }
+
+ /* The :next() method will populate lastjid before jail_getparam(). */
+ if (jailparam_init(&iter->params[0], "lastjid") == -1) {
+ free(iter->params);
+ free(iter);
+ return (luaL_error(L, "jailparam_init: %s", jail_errmsg));
+ }
+ /* These two will get populated by jail_getparam(). */
+ if (jailparam_init(&iter->params[1], "jid") == -1) {
+ jailparam_free(iter->params, 1);
+ free(iter->params);
+ free(iter);
+ return (luaL_error(L, "jailparam_init: %s",
+ jail_errmsg));
+ }
+ if (jailparam_init(&iter->params[2], "name") == -1) {
+ jailparam_free(iter->params, 2);
+ free(iter->params);
+ free(iter);
+ return (luaL_error(L, "jailparam_init: %s",
+ jail_errmsg));
+ }
+
+ /*
+ * We only need to process additional arguments if we were given any.
+ * That is, we don't descend into getparam_table if we're passed nothing
+ * or an empty table.
+ */
+ iter->jid = 0;
+ if (iter->params_count != 3)
+ getparam_table(L, 1, iter->params, 2, &iter->params_count,
+ l_jail_filter, NULL);
+
+ /*
+ * Part of the iterator magic. We give it an iterator function with a
+ * metatable defining next() and close() that can be used for manual
+ * iteration. iter->jid is how we track which jail we last iterated, to
+ * be supplied as "lastjid".
+ */
+ lua_pushcfunction(L, l_jail_iter_next);
+ *(struct l_jail_iter **)lua_newuserdata(L,
+ sizeof(struct l_jail_iter **)) = iter;
+ luaL_getmetatable(L, JAIL_METATABLE);
+ lua_setmetatable(L, -2);
+ return (2);
+}
+
+static void
+register_jail_metatable(lua_State *L)
+{
+ luaL_newmetatable(L, JAIL_METATABLE);
+ lua_newtable(L);
+ lua_pushcfunction(L, l_jail_iter_next);
+ lua_setfield(L, -2, "next");
+ lua_pushcfunction(L, l_jail_iter_close);
+ lua_setfield(L, -2, "close");
+
+ lua_setfield(L, -2, "__index");
+
+ lua_pushcfunction(L, l_jail_iter_close);
+ lua_setfield(L, -2, "__gc");
+
+ lua_pop(L, 1);
+}
+
+static int
+l_getid(lua_State *L)
+{
+ const char *name;
+ int jid;
+
+ name = luaL_checkstring(L, 1);
+ jid = jail_getid(name);
+ if (jid == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, jail_errmsg);
+ return (2);
+ }
+ lua_pushinteger(L, jid);
+ return (1);
+}
+
+static int
+l_getname(lua_State *L)
+{
+ char *name;
+ int jid;
+
+ jid = luaL_checkinteger(L, 1);
+ name = jail_getname(jid);
+ if (name == NULL) {
+ lua_pushnil(L);
+ lua_pushstring(L, jail_errmsg);
+ return (2);
+ }
+ lua_pushstring(L, name);
+ free(name);
+ return (1);
+}
+
+static int
+l_allparams(lua_State *L)
+{
+ struct jailparam *params;
+ int params_count;
+
+ params_count = jailparam_all(&params);
+ if (params_count == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, jail_errmsg);
+ return (2);
+ }
+ lua_newtable(L);
+ for (int i = 0; i < params_count; ++i) {
+ lua_pushstring(L, params[i].jp_name);
+ lua_rawseti(L, -2, i + 1);
+ }
+ jailparam_free(params, params_count);
+ free(params);
+ return (1);
+}
+
+static void
+getparam_table(lua_State *L, int paramindex, struct jailparam *params,
+ size_t params_off, size_t *params_countp, getparam_filter keyfilt,
+ void *udata)
+{
+ size_t params_count;
+ int skipped;
+
+ params_count = *params_countp;
+ skipped = 0;
+ for (size_t i = 1 + params_off; i < params_count; ++i) {
+ const char *param_name;
+
+ lua_rawgeti(L, -1, i - params_off);
+ param_name = lua_tostring(L, -1);
+ if (param_name == NULL) {
+ jailparam_free(params, i - skipped);
+ free(params);
+ luaL_argerror(L, paramindex,
+ "param names must be strings");
+ }
+ lua_pop(L, 1);
+ if (keyfilt != NULL && !keyfilt(param_name, udata)) {
+ ++skipped;
+ continue;
+ }
+ if (jailparam_init(&params[i - skipped], param_name) == -1) {
+ jailparam_free(params, i - skipped);
+ free(params);
+ luaL_error(L, "jailparam_init: %s", jail_errmsg);
+ }
+ }
+ *params_countp -= skipped;
+}
+
+struct getparams_filter_args {
+ int filter_type;
+};
+
+static bool
+l_getparams_filter(const char *param_name, void *udata)
+{
+ struct getparams_filter_args *gpa;
+
+ gpa = udata;
+
+ /* Skip name or jid, whichever was given. */
+ if (gpa->filter_type == LUA_TSTRING) {
+ if (strcmp(param_name, "name") == 0)
+ return (false);
+ } else /* type == LUA_TNUMBER */ {
+ if (strcmp(param_name, "jid") == 0)
+ return (false);
+ }
+
+ return (true);
+}
+
+static int
+l_getparams(lua_State *L)
+{
+ const char *name;
+ struct jailparam *params;
+ size_t params_count;
+ struct getparams_filter_args gpa;
+ int flags, jid, type;
+
+ type = lua_type(L, 1);
+ luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
+ "expected a jail name (string) or id (integer)");
+ luaL_checktype(L, 2, LUA_TTABLE);
+ params_count = 1 + lua_rawlen(L, 2);
+ flags = luaL_optinteger(L, 3, 0);
+
+ params = malloc(params_count * sizeof(struct jailparam));
+ if (params == NULL)
+ return (luaL_error(L, "malloc: %s", strerror(errno)));
+
+ /*
+ * Set the jail name or id param as determined by the first arg.
+ */
+
+ if (type == LUA_TSTRING) {
+ if (jailparam_init(&params[0], "name") == -1) {
+ free(params);
+ return (luaL_error(L, "jailparam_init: %s",
+ jail_errmsg));
+ }
+ name = lua_tostring(L, 1);
+ if (jailparam_import(&params[0], name) == -1) {
+ jailparam_free(params, 1);
+ free(params);
+ return (luaL_error(L, "jailparam_import: %s",
+ jail_errmsg));
+ }
+ } else /* type == LUA_TNUMBER */ {
+ if (jailparam_init(&params[0], "jid") == -1) {
+ free(params);
+ return (luaL_error(L, "jailparam_init: %s",
+ jail_errmsg));
+ }
+ jid = lua_tointeger(L, 1);
+ if (jailparam_import_raw(&params[0], &jid, sizeof(jid)) == -1) {
+ jailparam_free(params, 1);
+ free(params);
+ return (luaL_error(L, "jailparam_import_raw: %s",
+ jail_errmsg));
+ }
+ }
+
+ /*
+ * Set the remaining param names being requested.
+ */
+ gpa.filter_type = type;
+ getparam_table(L, 2, params, 0, &params_count, l_getparams_filter, &gpa);
+
+ /*
+ * Get the values and convert to a table.
+ */
+
+ jid = jailparam_get(params, params_count, flags);
+ if (jid == -1) {
+ jailparam_free(params, params_count);
+ free(params);
+ lua_pushnil(L);
+ lua_pushstring(L, jail_errmsg);
+ return (2);
+ }
+ lua_pushinteger(L, jid);
+
+ lua_newtable(L);
+ for (size_t i = 0; i < params_count; ++i) {
+ char *value;
+
+ value = jailparam_export(&params[i]);
+ lua_pushstring(L, value);
+ free(value);
+ lua_setfield(L, -2, params[i].jp_name);
+ }
+
+ jailparam_free(params, params_count);
+ free(params);
+
+ return (2);
+}
+
+static int
+l_setparams(lua_State *L)
+{
+ const char *name;
+ struct jailparam *params;
+ size_t params_count;
+ int flags, jid, type;
+
+ type = lua_type(L, 1);
+ luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
+ "expected a jail name (string) or id (integer)");
+ luaL_checktype(L, 2, LUA_TTABLE);
+
+ lua_pushnil(L);
+ for (params_count = 1; lua_next(L, 2) != 0; ++params_count)
+ lua_pop(L, 1);
+
+ flags = luaL_optinteger(L, 3, 0);
+
+ params = malloc(params_count * sizeof(struct jailparam));
+ if (params == NULL)
+ return (luaL_error(L, "malloc: %s", strerror(errno)));
+
+ /*
+ * Set the jail name or id param as determined by the first arg.
+ */
+
+ if (type == LUA_TSTRING) {
+ if (jailparam_init(&params[0], "name") == -1) {
+ free(params);
+ return (luaL_error(L, "jailparam_init: %s",
+ jail_errmsg));
+ }
+ name = lua_tostring(L, 1);
+ if (jailparam_import(&params[0], name) == -1) {
+ jailparam_free(params, 1);
+ free(params);
+ return (luaL_error(L, "jailparam_import: %s",
+ jail_errmsg));
+ }
+ } else /* type == LUA_TNUMBER */ {
+ if (jailparam_init(&params[0], "jid") == -1) {
+ free(params);
+ return (luaL_error(L, "jailparam_init: %s",
+ jail_errmsg));
+ }
+ jid = lua_tointeger(L, 1);
+ if (jailparam_import_raw(&params[0], &jid, sizeof(jid)) == -1) {
+ jailparam_free(params, 1);
+ free(params);
+ return (luaL_error(L, "jailparam_import_raw: %s",
+ jail_errmsg));
+ }
+ }
+
+ /*
+ * Set the rest of the provided params.
+ */
+
+ lua_pushnil(L);
+ for (size_t i = 1; i < params_count && lua_next(L, 2) != 0; ++i) {
+ const char *value;
+
+ name = lua_tostring(L, -2);
+ if (name == NULL) {
+ jailparam_free(params, i);
+ free(params);
+ return (luaL_argerror(L, 2,
+ "param names must be strings"));
+ }
+ if (jailparam_init(&params[i], name) == -1) {
+ jailparam_free(params, i);
+ free(params);
+ return (luaL_error(L, "jailparam_init: %s",
+ jail_errmsg));
+ }
+
+ value = lua_tostring(L, -1);
+ if (value == NULL) {
+ jailparam_free(params, i + 1);
+ free(params);
+ return (luaL_argerror(L, 2,
+ "param values must be strings"));
+ }
+ if (jailparam_import(&params[i], value) == -1) {
+ jailparam_free(params, i + 1);
+ free(params);
+ return (luaL_error(L, "jailparam_import: %s",
+ jail_errmsg));
+ }
+
+ lua_pop(L, 1);
+ }
+
+ /*
+ * Attempt to set the params.
+ */
+
+ jid = jailparam_set(params, params_count, flags);
+ if (jid == -1) {
+ jailparam_free(params, params_count);
+ free(params);
+ lua_pushnil(L);
+ lua_pushstring(L, jail_errmsg);
+ return (2);
+ }
+ lua_pushinteger(L, jid);
+
+ jailparam_free(params, params_count);
+ free(params);
+ return (1);
+}
+
+static int
+l_attach(lua_State *L)
+{
+ int jid, type;
+
+ type = lua_type(L, 1);
+ luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
+ "expected a jail name (string) or id (integer)");
+
+ if (lua_isstring(L, 1)) {
+ /* Resolve it to a jid. */
+ jid = jail_getid(lua_tostring(L, 1));
+ if (jid == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, jail_errmsg);
+ return (2);
+ }
+ } else {
+ jid = lua_tointeger(L, 1);
+ }
+
+ if (jail_attach(jid) == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ return (2);
+ }
+
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static int
+l_remove(lua_State *L)
+{
+ int jid, type;
+
+ type = lua_type(L, 1);
+ luaL_argcheck(L, type == LUA_TSTRING || type == LUA_TNUMBER, 1,
+ "expected a jail name (string) or id (integer)");
+
+ if (lua_isstring(L, 1)) {
+ /* Resolve it to a jid. */
+ jid = jail_getid(lua_tostring(L, 1));
+ if (jid == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, jail_errmsg);
+ return (2);
+ }
+ } else {
+ jid = lua_tointeger(L, 1);
+ }
+
+ if (jail_remove(jid) == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ return (2);
+ }
+
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static const struct luaL_Reg l_jail[] = {
+ /** Get id of a jail by name.
+ * @param name jail name (string)
+ * @return jail id (integer)
+ * or nil, error (string) on error
+ */
+ {"getid", l_getid},
+ /** Get name of a jail by id.
+ * @param jid jail id (integer)
+ * @return jail name (string)
+ * or nil, error (string) on error
+ */
+ {"getname", l_getname},
+ /** Get a list of all known jail parameters.
+ * @return list of jail parameter names (table of strings)
+ * or nil, error (string) on error
+ */
+ {"allparams", l_allparams},
+ /** Get the listed params for a given jail.
+ * @param jail jail name (string) or id (integer)
+ * @param params list of parameter names (table of strings)
+ * @param flags optional flags (integer)
+ * @return jid (integer), params (table of [string] = string)
+ * or nil, error (string) on error
+ */
+ {"getparams", l_getparams},
+ /** Set params for a given jail.
+ * @param jail jail name (string) or id (integer)
+ * @param params params and values (table of [string] = string)
+ * @param flags optional flags (integer)
+ * @return jid (integer)
+ * or nil, error (string) on error
+ */
+ {"setparams", l_setparams},
+ /** Get a list of jail parameters for running jails on the system.
+ * @param params optional list of parameter names (table of
+ * strings)
+ * @return iterator (function), jail_obj (object) with next and
+ * close methods
+ */
+ {"list", l_list},
+ /** Attach to a running jail.
+ * @param jail jail name (string) or id (integer)
+ * @return true (boolean)
+ * or nil, error (string) on error
+ */
+ {"attach", l_attach},
+ /** Remove a running jail.
+ * @param jail jail name (string) or id (integer)
+ * @return true (boolean)
+ * or nil, error (string) on error
+ */
+ {"remove", l_remove},
+ {NULL, NULL}
+};
+
+int
+luaopen_jail(lua_State *L)
+{
+ lua_newtable(L);
+
+ luaL_setfuncs(L, l_jail, 0);
+
+ lua_pushinteger(L, JAIL_CREATE);
+ lua_setfield(L, -2, "CREATE");
+ lua_pushinteger(L, JAIL_UPDATE);
+ lua_setfield(L, -2, "UPDATE");
+ lua_pushinteger(L, JAIL_ATTACH);
+ lua_setfield(L, -2, "ATTACH");
+ lua_pushinteger(L, JAIL_DYING);
+ lua_setfield(L, -2, "DYING");
+
+ register_jail_metatable(L);
+
+ return (1);
+}
diff --git a/libexec/flua/libucl/Makefile b/libexec/flua/libucl/Makefile
new file mode 100644
index 000000000000..a88c8bda6bfc
--- /dev/null
+++ b/libexec/flua/libucl/Makefile
@@ -0,0 +1,14 @@
+SHLIB_NAME= ucl.so
+
+WARNS= 2
+
+UCLSRC?= ${SRCTOP}/contrib/libucl
+.PATH: ${UCLSRC}/lua
+SRCS+= lua_ucl.c
+CFLAGS+= \
+ -I${UCLSRC}/include \
+ -I${UCLSRC}/src \
+ -I${UCLSRC}/uthash
+LIBADD+= ucl
+
+.include <bsd.lib.mk>