summaryrefslogtreecommitdiff
path: root/tex/context/base/l-sandbox.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/l-sandbox.lua')
-rw-r--r--tex/context/base/l-sandbox.lua271
1 files changed, 271 insertions, 0 deletions
diff --git a/tex/context/base/l-sandbox.lua b/tex/context/base/l-sandbox.lua
new file mode 100644
index 000000000..f7901379c
--- /dev/null
+++ b/tex/context/base/l-sandbox.lua
@@ -0,0 +1,271 @@
+if not modules then modules = { } end modules ['l-sandbox'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- We use string instead of function variables, so 'io.open' instead of io.open. That
+-- way we can still intercept repetetive overloads. One complication is that when we use
+-- sandboxed function sin helpers in the sanbox checkers, we can get a recursion loop
+-- so for that vreason we need to keep originals around till we enable the sandbox.
+
+-- if sandbox then return end
+
+local global = _G
+local next = next
+local unpack = unpack or table.unpack
+local type = type
+local tprint = texio.write_nl or print
+local tostring = tostring
+local format = string.format -- no formatters yet
+local concat = table.concat
+local sort = table.sort
+local gmatch = string.gmatch
+
+sandbox = { }
+local sandboxed = false
+local overloads = { }
+local skiploads = { }
+local initializers = { }
+local finalizers = { }
+local originals = { }
+local comments = { }
+local trace = false
+local logger = false
+
+-- this comes real early, so that we can still alias
+
+local function report(...)
+ tprint("sandbox ! " .. format(...)) -- poor mans tracer
+end
+
+sandbox.report = report
+
+function sandbox.setreporter(r)
+ report = r
+ sandbox.report = r
+end
+
+function sandbox.settrace(v)
+ trace = v
+end
+
+function sandbox.setlogger(l)
+ logger = type(l) == "function" and l or false
+end
+
+local function register(func,overload,comment)
+ if type(func) == "function" then
+ if type(overload) == "string" then
+ comment = overload
+ overload = nil
+ end
+ local function f(...)
+ if sandboxed then
+ local overload = overloads[f]
+ if overload then
+ if logger then
+ local result = { overload(func,...) }
+ logger {
+ comment = comments[f] or tostring(f),
+ arguments = { ... },
+ result = result[1] and true or false,
+ }
+ return unpack(result)
+ else
+ return overload(func,...)
+ end
+ else
+ -- ignored, maybe message
+ end
+ else
+ return func(...)
+ end
+ end
+ if comment then
+ comments[f] = comment
+ if trace then
+ report("registering function: %s",comment)
+ end
+ end
+ overloads[f] = overload or false
+ originals[f] = func
+ return f
+ end
+end
+
+local function redefine(func,comment)
+ if type(func) == "function" then
+ skiploads[func] = comment or comments[func] or "unknown"
+ if overloads[func] == false then
+ overloads[func] = nil -- not initialized anyway
+ end
+ end
+end
+
+sandbox.register = register
+sandbox.redefine = redefine
+
+function sandbox.original(func)
+ return originals and originals[func] or func
+end
+
+function sandbox.overload(func,overload,comment)
+ comment = comment or comments[func] or "?"
+ if type(func) ~= "function" then
+ if trace then
+ report("overloading unknown function: %s",comment)
+ end
+ elseif type(overload) ~= "function" then
+ if trace then
+ report("overloading function with bad overload: %s",comment)
+ end
+ elseif overloads[func] == nil then
+ if trace then
+ report("function is not registered: %s",comment)
+ end
+ elseif skiploads[func] then
+ if trace then
+ report("function is not skipped: %s",comment)
+ end
+ else
+ if trace then
+ report("overloading function: %s",comment)
+ end
+ overloads[func] = overload
+ end
+ return func
+end
+
+function sandbox.initializer(f)
+ if not sandboxed then
+ initializers[#initializers+1] = f
+ elseif trace then
+ report("already enabled, discarding initializer")
+ end
+end
+
+function sandbox.finalizer(f)
+ if not sandboxed then
+ finalizers[#finalizers+1] = f
+ elseif trace then
+ report("already enabled, discarding finalizer")
+ end
+end
+
+function sandbox.enable()
+ if not sandboxed then
+ for i=1,#initializers do
+ initializers[i]()
+ end
+ for i=1,#finalizers do
+ finalizers[i]()
+ end
+ local nnot = 0
+ local nyes = 0
+ local cnot = { }
+ local cyes = { }
+ local skip = { }
+ for k, v in next, overloads do
+ local c = comments[k]
+ if v then
+ if c then
+ cyes[#cyes+1] = c
+ else -- if not skiploads[k] then
+ nyes = nyes + 1
+ end
+ else
+ if c then
+ cnot[#cnot+1] = c
+ else -- if not skiploads[k] then
+ nnot = nnot + 1
+ end
+ end
+ end
+ for k, v in next, skiploads do
+ skip[#skip+1] = v
+ end
+ if #cyes > 0 then
+ sort(cyes)
+ report(" overloaded known : %s",concat(cyes," | "))
+ end
+ if nyes > 0 then
+ report(" overloaded unknown : %s",nyes)
+ end
+ if #cnot > 0 then
+ sort(cnot)
+ report("not overloaded known : %s",concat(cnot," | "))
+ end
+ if nnot > 0 then
+ report("not overloaded unknown : %s",nnot)
+ end
+ if #skip > 0 then
+ sort(skip)
+ report("not overloaded redefined : %s",concat(skip," | "))
+ end
+ initializers = nil
+ finalizers = nil
+ originals = nil
+ sandboxed = true
+ end
+end
+
+-- we sandbox some of the built-in functions now:
+
+-- todo: require
+-- todo: load
+
+local function supported(library)
+ local l = _G[library]
+ -- if l then
+ -- for k, v in next, l do
+ -- report("%s.%s",library,k)
+ -- end
+ -- end
+ return l
+end
+
+-- io.tmpfile : we don't know where that one ends up but probably is user temp space
+-- os.tmpname : no need to deal with this: outputs rubish anyway (\s9v0. \s9v0.1 \s9v0.2 etc)
+-- os.tmpdir : not needed either (luatex.vob000 luatex.vob000 etc)
+
+-- os.setenv : maybe
+-- require : maybe (normally taken from tree)
+-- http etc : maybe (all schemes that go outside)
+
+loadfile = register(loadfile,"loadfile")
+
+if supported("io") then
+ io.open = register(io.open, "io.open")
+ io.popen = register(io.popen, "io.popen") -- needs checking
+ io.lines = register(io.lines, "io.lines")
+ io.output = register(io.output, "io.output")
+ io.input = register(io.input, "io.input")
+end
+
+if supported("os") then
+ os.execute = register(os.execute, "os.execute")
+ os.spawn = register(os.spawn, "os.spawn")
+ os.exec = register(os.exec, "os.exec")
+ os.rename = register(os.rename, "os.rename")
+ os.remove = register(os.remove, "os.remove")
+end
+
+if supported("lfs") then
+ lfs.chdir = register(lfs.chdir, "lfs.chdir")
+ lfs.mkdir = register(lfs.mkdir, "lfs.mkdir")
+ lfs.rmdir = register(lfs.rmdir, "lfs.rmdir")
+ lfs.isfile = register(lfs.isfile, "lfs.isfile")
+ lfs.isdir = register(lfs.isdir, "lfs.isdir")
+ lfs.attributes = register(lfs.attributes, "lfs.attributes")
+ lfs.dir = register(lfs.dir, "lfs.dir")
+ lfs.lock_dir = register(lfs.lock_dir, "lfs.lock_dir")
+ lfs.touch = register(lfs.touch, "lfs.touch")
+ lfs.link = register(lfs.link, "lfs.link")
+ lfs.setmode = register(lfs.setmode, "lfs.setmode")
+ lfs.readlink = register(lfs.readlink, "lfs.readlink")
+ lfs.shortname = register(lfs.shortname, "lfs.shortname")
+ lfs.symlinkattributes = register(lfs.symlinkattributes,"lfs.symlinkattributes")
+end