1if not modules then modules = { } end modules ['l-sandbox'] = {
2 version = 1.001,
3 comment = "companion to luat-lib.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11
12
13
14
15
16local global = _G
17local next = next
18local unpack = unpack or table.unpack
19local type = type
20local tprint = texio and texio.write_nl or print
21local tostring = tostring
22local format = string.format
23local concat = table.concat
24local sort = table.sort
25local gmatch = string.gmatch
26local gsub = string.gsub
27local requiem = require
28
29sandbox = { }
30local sandboxed = false
31local overloads = { }
32local skiploads = { }
33local initializers = { }
34local finalizers = { }
35local originals = { }
36local comments = { }
37local trace = false
38local logger = false
39local blocked = { }
40
41
42
43local function report(...)
44 tprint("sandbox ! " .. format(...))
45end
46
47sandbox.report = report
48
49function sandbox.setreporter(r)
50 report = r
51 sandbox.report = r
52end
53
54function sandbox.settrace(v)
55 trace = v
56end
57
58function sandbox.setlogger(l)
59 logger = type(l) == "function" and l or false
60end
61
62local function register(func,overload,comment)
63 if type(func) == "function" then
64 if type(overload) == "string" then
65 comment = overload
66 overload = nil
67 end
68 local function f(...)
69 if sandboxed then
70 local overload = overloads[f]
71 if overload then
72 if logger then
73 local result = { overload(func,...) }
74 logger {
75 comment = comments[f] or tostring(f),
76 arguments = { ... },
77 result = result[1] and true or false,
78 }
79 return unpack(result)
80 else
81 return overload(func,...)
82 end
83 else
84
85 end
86 else
87 return func(...)
88 end
89 end
90 if comment then
91 comments[f] = comment
92 if trace then
93 report("registering function: %s",comment)
94 end
95 end
96 overloads[f] = overload or false
97 originals[f] = func
98 return f
99 end
100end
101
102local function redefine(func,comment)
103 if type(func) == "function" then
104 skiploads[func] = comment or comments[func] or "unknown"
105 if overloads[func] == false then
106 overloads[func] = nil
107 end
108 end
109end
110
111sandbox.register = register
112sandbox.redefine = redefine
113
114function sandbox.original(func)
115 return originals and originals[func] or func
116end
117
118function sandbox.overload(func,overload,comment)
119 comment = comment or comments[func] or "?"
120 if type(func) ~= "function" then
121 if trace then
122 report("overloading unknown function: %s",comment)
123 end
124 elseif type(overload) ~= "function" then
125 if trace then
126 report("overloading function with bad overload: %s",comment)
127 end
128 elseif overloads[func] == nil then
129 if trace then
130 report("function is not registered: %s",comment)
131 end
132 elseif skiploads[func] then
133 if trace then
134 report("function is not skipped: %s",comment)
135 end
136 else
137 if trace then
138 report("overloading function: %s",comment)
139 end
140 overloads[func] = overload
141 end
142 return func
143end
144
145local function whatever(specification,what,target)
146 if type(specification) ~= "table" then
147 report("%s needs a specification",what)
148 elseif type(specification.category) ~= "string" or type(specification.action) ~= "function" then
149 report("%s needs a category and action",what)
150 elseif not sandboxed then
151 target[#target+1] = specification
152 elseif trace then
153 report("already enabled, discarding %s",what)
154 end
155end
156
157function sandbox.initializer(specification)
158 whatever(specification,"initializer",initializers)
159end
160
161function sandbox.finalizer(specification)
162 whatever(specification,"finalizer",finalizers)
163end
164
165function require(name)
166 local n = gsub(name,"^.*[\\/]","")
167 local n = gsub(n,"[%.].*$","")
168 local b = blocked[n]
169 if b == false then
170 return nil
171 elseif b then
172 if trace then
173 report("using blocked: %s",n)
174 end
175 return b
176 else
177 if trace then
178 report("requiring: %s",name)
179 end
180 return requiem(name)
181 end
182end
183
184function blockrequire(name,lib)
185 if trace then
186 report("preventing reload of: %s",name)
187 end
188 blocked[name] = lib or _G[name] or false
189end
190
191function sandbox.enable()
192 if not sandboxed then
193 debug = {
194 traceback = debug.traceback,
195 }
196 for i=1,#initializers do
197 initializers[i].action()
198 end
199 for i=1,#finalizers do
200 finalizers[i].action()
201 end
202 local nnot = 0
203 local nyes = 0
204 local cnot = { }
205 local cyes = { }
206 local skip = { }
207 for k, v in next, overloads do
208 local c = comments[k]
209 if v then
210 if c then
211 cyes[#cyes+1] = c
212 else
213 nyes = nyes + 1
214 end
215 else
216 if c then
217 cnot[#cnot+1] = c
218 else
219 nnot = nnot + 1
220 end
221 end
222 end
223 for k, v in next, skiploads do
224 skip[#skip+1] = v
225 end
226 if #cyes > 0 then
227 sort(cyes)
228 report("overloaded known: %s",concat(cyes," | "))
229 end
230 if nyes > 0 then
231 report("overloaded unknown: %s",nyes)
232 end
233 if #cnot > 0 then
234 sort(cnot)
235 report("not overloaded known: %s",concat(cnot," | "))
236 end
237 if nnot > 0 then
238 report("not overloaded unknown: %s",nnot)
239 end
240 if #skip > 0 then
241 sort(skip)
242 report("not overloaded redefined: %s",concat(skip," | "))
243 end
244
245 initializers = nil
246 finalizers = nil
247 originals = nil
248 sandboxed = true
249 end
250end
251
252blockrequire("lfs",lfs)
253blockrequire("io",io)
254blockrequire("os",os)
255blockrequire("ffi",ffi)
256
257
258
259
260
261
262
263
264local function supported(library)
265 local l = _G[library]
266
267
268
269
270
271 return l
272end
273
274
275
276
277
278
279
280
281
282loadfile = register(loadfile,"loadfile")
283
284if supported("lua") then
285 lua.openfile = register(lua.openfile,"lua.openfile")
286end
287
288if supported("io") then
289 io.open = register(io.open, "io.open")
290 io.popen = register(io.popen, "io.popen")
291 io.lines = register(io.lines, "io.lines")
292 io.output = register(io.output,"io.output")
293 io.input = register(io.input, "io.input")
294end
295
296if supported("os") then
297 os.execute = register(os.execute,"os.execute")
298 os.spawn = register(os.spawn, "os.spawn")
299 os.exec = register(os.exec, "os.exec")
300 os.rename = register(os.rename, "os.rename")
301 os.remove = register(os.remove, "os.remove")
302end
303
304if supported("lfs") then
305 lfs.chdir = register(lfs.chdir, "lfs.chdir")
306 lfs.mkdir = register(lfs.mkdir, "lfs.mkdir")
307 lfs.rmdir = register(lfs.rmdir, "lfs.rmdir")
308 lfs.isfile = register(lfs.isfile, "lfs.isfile")
309 lfs.isdir = register(lfs.isdir, "lfs.isdir")
310 lfs.attributes = register(lfs.attributes, "lfs.attributes")
311 lfs.dir = register(lfs.dir, "lfs.dir")
312 lfs.lock_dir = register(lfs.lock_dir, "lfs.lock_dir")
313 lfs.touch = register(lfs.touch, "lfs.touch")
314 lfs.link = register(lfs.link, "lfs.link")
315 lfs.setmode = register(lfs.setmode, "lfs.setmode")
316 lfs.readlink = register(lfs.readlink, "lfs.readlink")
317 lfs.shortname = register(lfs.shortname, "lfs.shortname")
318 lfs.symlinkattributes = register(lfs.symlinkattributes,"lfs.symlinkattributes")
319end
320
321 |