From 09b76106003704754f50c91aee9a28d7bac88b69 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Sat, 6 Jun 2015 12:16:09 +0700 Subject: [PATCH] Add a bunch of explanatory comments. --- mods/calandria/server.lua | 3 +++ mods/orb/fs.lua | 39 +++++++++++++++++++++++++++++++++------ mods/orb/init.lua | 3 ++- mods/orb/process.lua | 9 +++++++++ mods/orb/shell.lua | 9 +++++++++ mods/orb/utils.lua | 2 ++ 6 files changed, 58 insertions(+), 7 deletions(-) diff --git a/mods/calandria/server.lua b/mods/calandria/server.lua index 024722f..42661b4 100644 --- a/mods/calandria/server.lua +++ b/mods/calandria/server.lua @@ -103,6 +103,9 @@ calandria.server = { } pcall(calandria.server.load) + +-- TODO: check to see if these have been loaded already: +-- if(not minetest.registered_items["mod:item"]) then ... minetest.register_on_shutdown(calandria.server.save) minetest.register_node("calandria:server", { diff --git a/mods/orb/fs.lua b/mods/orb/fs.lua index 2553ed4..8c87fe4 100644 --- a/mods/orb/fs.lua +++ b/mods/orb/fs.lua @@ -1,5 +1,7 @@ -- fake lil filesystem orb.fs = { + + -- This gives us a raw filesystem that's just a table with permissions data empty = function() return {_user = "root", _group = "all", proc = { _user = "root", _group = "all" @@ -21,6 +23,8 @@ orb.fs = { return parent[base] end, + -- Actually returns both the dirname and the basename. + -- for instance, "/path/to/file" returns "/path/to" and "file" dirname = function(path) local t = orb.utils.split(path, "/") local basename = t[#t] @@ -29,8 +33,11 @@ orb.fs = { return "/" .. table.concat(t, "/"), basename end, - -- read/write/append here are wrappers that help you work with function - -- files, which is how pipes and other special devices are implemented. + -- read/write/append here are wrappers that help you work with + -- function files, which is how pipes and other special devices are + -- implemented. When dealing with regular files, you can just grab + -- them straight out of the filesystem as strings to read or drop strings + -- into the directory to write. read = function(f, path) local contents = f[path] if(type(contents) == "string") then @@ -64,8 +71,8 @@ orb.fs = { f[home]._user = user f[home]._group = user orb.fs.mkdir(f, "/proc/" .. user) - f["/proc/" .. user]._user = user - f["/proc/" .. user]._group = user + f.proc[user]._user = user + f.proc[user]._group = user end, add_to_group = function(f, user, group) @@ -81,6 +88,7 @@ orb.fs = { group_dir[user] = user end, + -- This is for copying stuff from the host OS into the virtualized OS. copy_to_fs = function(f, fs_path, real_path) local dir, base = orb.fs.dirname(fs_path) local path = orb.mod_dir .. "/resources/" .. real_path @@ -113,6 +121,7 @@ orb.fs = { end end, + -- Load up an empty filesystem. seed = function(f, users) for _,d in pairs({"/etc", "/home", "/tmp", "/bin", "/digi"}) do orb.fs.mkdir(f, d) @@ -166,6 +175,7 @@ orb.fs = { reloaders = (orb.fs and orb.fs.reloaders) or {}, + -- Reload all of orb's own code, and reset the /bin directory. reloader = function(f) return function() dofile(orb.mod_dir .. "/init.lua") @@ -184,6 +194,21 @@ orb.fs = { end end, + -- Proxying a raw filesystem has two purposes: one is to enforce filesystem + -- permissions rules (this is done using a metatable) and one is to allow + -- access using full filenames. For instance, these are equivalent: + -- + -- f.home.technomancy.bin["myls"] + -- f["/home/technomancy/bin/myls"] + -- + -- Raw filesystems require the first style, but the latter works with + -- proxied filesystems. + -- + -- Be aware that f["/home"] will return another proxied subfilesystem + -- that looks like a filesystem but is actually just sliced off at + -- a subdirectory. This is a bit of a problem since calculating permissions + -- requires access to the "/etc/groups" directory, which is why this + -- function takes a raw_root argument as well. proxy = function(raw, user, raw_root) local descend = function(f, path, user) local target = f @@ -198,7 +223,7 @@ orb.fs = { return target end - local unreadable = function(_k,v) + local unreadable = function(_k, v) return {_user = v._user, _group = v._group} end @@ -223,6 +248,8 @@ orb.fs = { target[base] = content end, + -- Unfortunately Lua 5.1 has no way to specify an iterator from the + -- metatable, so this only works with orb.utils.mtpairs. =( __iterator = function(_f) assert(orb.fs.readable(raw_root, raw, user), "Not readable") local f = {} @@ -244,7 +271,7 @@ orb.fs = { } setmetatable(f, mt) - -- only need this for fs roots + -- Only need this for fs roots. if(raw == raw_root) then orb.fs.reloaders[f] = orb.fs.reloader(raw_root) end diff --git a/mods/orb/init.lua b/mods/orb/init.lua index e1e93d9..80c9c77 100644 --- a/mods/orb/init.lua +++ b/mods/orb/init.lua @@ -13,8 +13,9 @@ dofile(orb.mod_dir .. "/shell.lua") dofile(orb.mod_dir .. "/process.lua") -- pp = dofile(orb.mod_dir .. "/PrettyPrint.lua") --- interactively: +-- for interactive use, but also as a sample of how the API works: if(arg) then + -- start with an empty filesystem f = orb.fs.empty() f0 = orb.fs.seed(orb.fs.proxy(f, "root", f), {"technomancy", "buddyberg", "zacherson"}) diff --git a/mods/orb/process.lua b/mods/orb/process.lua index 2b56306..b1e4aa1 100644 --- a/mods/orb/process.lua +++ b/mods/orb/process.lua @@ -1,4 +1,7 @@ orb.process = { + -- Create a coroutine for a command to run inside and place it into the + -- process table. The process table is stored in the filesystem under + -- f.proc[user] spawn = function(f, env, command) local co = coroutine.create(function() orb.shell.exec(f, env, "smash") end) @@ -11,10 +14,14 @@ orb.process = { return co, id end, + -- The process ID is taken from lua's own tostring called on a coroutine. id_for = function(p) return tostring(p):match(": 0x(.+)") end, + -- Loop through all the coroutines in the process table and give them all + -- a chance to run till they yield. No attempt at fairness or time limits + -- yet. scheduler = function(f) for u,procs in pairs(f.proc) do if(type(procs) == "table") then @@ -31,6 +38,8 @@ orb.process = { end end, + -- When restoring an fs from serialization, we have to repopulate special + -- nodes in the fs that were not serializable. restore_digi = function(f) for k,v in orb.utils.mtpairs(f.digi) do local channel_dir = "/digi/" .. k diff --git a/mods/orb/shell.lua b/mods/orb/shell.lua index 648669d..d9f4c17 100644 --- a/mods/orb/shell.lua +++ b/mods/orb/shell.lua @@ -12,6 +12,9 @@ orb.shell = { } end, + -- This function does too much: it turns a command string into a tokenized + -- list of arguments, but it also searches the argument list for stdio + -- redirects and sets up the environment's read/write appropriately. parse = function(f, env, command) local args = {} local tokens = orb.utils.split(command, " +") @@ -56,6 +59,9 @@ orb.shell = { return executable_name, args end, + -- Execute a command directly in the current coroutine. This is a low-level + -- call; usually you want orb.process.spawn which creates it as a proper + -- process. exec = function(f, env, command) local env = orb.utils.shallow_copy(env) local executable_name, args = orb.shell.parse(f, env, command) @@ -72,10 +78,13 @@ orb.shell = { error(executable_name .. " not found.") end, + -- Like exec, but protected in a pcall. pexec = function(f, env, command) return pcall(function() orb.shell.exec(f, env, command) end) end, + -- Set up the sandbox in which code runs. Need to avoid exposing anything + -- that could allow security leaks. sandbox = function(f, env) local read = function(...) return env.read(...) end local write = function(...) return env.write(...) end diff --git a/mods/orb/utils.lua b/mods/orb/utils.lua index 0724c6a..c9b3cf5 100644 --- a/mods/orb/utils.lua +++ b/mods/orb/utils.lua @@ -1,5 +1,7 @@ -- utils +-- mostly functions which are inexplicable omissions from the lua standard lib + orb.utils = { split = function(str,div) if(div=='') then return {str} end