Page MenuHomeFreeBSD

D26756.id78154.diff
No OneTemporary

D26756.id78154.diff

Index: lib/flua/libjail/jail.3lua
===================================================================
--- lib/flua/libjail/jail.3lua
+++ lib/flua/libjail/jail.3lua
@@ -23,12 +23,13 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 17, 2020
+.Dd October 12, 2020
.Dt JAIL 3lua
.Os
.Sh NAME
.Nm getid ,
.Nm getname ,
+.Nm list ,
.Nm allparams ,
.Nm getparams ,
.Nm setparams ,
@@ -47,6 +48,7 @@
.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 jid, err = jail.setparams(jid|name, params, flags )
.It Dv jail.CREATE
@@ -76,6 +78,21 @@
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 .
@@ -190,6 +207,32 @@
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 ,
Index: lib/flua/libjail/lua_jail.c
===================================================================
--- lib/flua/libjail/lua_jail.c
+++ lib/flua/libjail/lua_jail.c
@@ -2,6 +2,7 @@
* 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
@@ -34,6 +35,7 @@
#include <sys/jail.h>
#include <errno.h>
#include <jail.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -41,8 +43,210 @@
#include <lauxlib.h>
#include <lualib.h>
+#define JAIL_METATABLE "jail iterator metatable"
+
int luaopen_jail(lua_State *);
+typedef bool (*getparam_filter)(const char *, void *);
+
+static int 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 paramter 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);
+ luaL_argcheck(L, nargs <= 1, 1, "too many arguments");
+ 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)
{
@@ -100,12 +304,73 @@
return (1);
}
+static int
+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);
+ return (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);
+ return (luaL_error(L, "jailparam_init: %s",
+ jail_errmsg));
+ }
+ }
+ *params_countp -= skipped;
+ return (0);
+}
+
+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, skipped;
+ size_t params_count;
+ struct getparams_filter_args gpa;
int flags, jid, type;
type = lua_type(L, 1);
@@ -155,40 +420,8 @@
/*
* Set the remaining param names being requested.
*/
-
- skipped = 0;
- for (size_t i = 1; i < params_count; ++i) {
- const char *param_name;
-
- lua_rawgeti(L, -1, i);
- param_name = lua_tostring(L, -1);
- if (param_name == NULL) {
- jailparam_free(params, i - skipped);
- free(params);
- return (luaL_argerror(L, 2,
- "param names must be strings"));
- }
- lua_pop(L, 1);
- /* Skip name or jid, whichever was given. */
- if (type == LUA_TSTRING) {
- if (strcmp(param_name, "name") == 0) {
- ++skipped;
- continue;
- }
- } else /* type == LUA_TNUMBER */ {
- if (strcmp(param_name, "jid") == 0) {
- ++skipped;
- continue;
- }
- }
- if (jailparam_init(&params[i - skipped], param_name) == -1) {
- jailparam_free(params, i - skipped);
- free(params);
- return (luaL_error(L, "jailparam_init: %s",
- jail_errmsg));
- }
- }
- params_count -= skipped;
+ gpa.filter_type = type;
+ getparam_table(L, 2, params, 0, &params_count, l_getparams_filter, &gpa);
/*
* Get the values and convert to a table.
@@ -368,6 +601,8 @@
* or nil, error (string) on error
*/
{"setparams", l_setparams},
+ /** Get a list of jails. */
+ {"list", l_list},
{NULL, NULL}
};
@@ -387,5 +622,7 @@
lua_pushinteger(L, JAIL_DYING);
lua_setfield(L, -2, "DYING");
+ register_jail_metatable(L);
+
return (1);
}

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 8, 5:35 PM (10 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28479389
Default Alt Text
D26756.id78154.diff (11 KB)

Event Timeline