diff --git a/first/ackbuilder.lua b/first/ackbuilder.lua new file mode 100644 index 000000000..963173405 --- /dev/null +++ b/first/ackbuilder.lua @@ -0,0 +1,254 @@ +local M = {} + +function M.subenv(p) + local e = p[1] + setmetable(p, {__index = e}) + return p +end + +local function check_filename(fn) + if type(fn) == "table" then + for _, f in ipairs(fn) do + check_filename(f) + end + else + if fn:find("%s") then + error("Filename '"+fn+"' contains spaces. This will make the build system sad.") + end + end +end + +function M.basename(fn) + if type(fn) == "table" then + local nfn = {} + for _, f in ipairs(fn) do + nfn[#nfn+1] = M.basename(f) + end + return nfn + else + local _, _, base = fn:find("([^/]*)$") + return base + end +end + +function M.flatten(t) + if t == nil then + return {} + end + + local tt = {} + for _, subt in ipairs(t) do + if type(subt) == "table" then + for _, subt in ipairs(M.flatten(subt)) do + tt[#tt+1] = subt + end + else + tt[#tt+1] = subt + end + end + return tt +end + +local function append(...) + local ts = {} + for _, t in ipairs({...}) do + for _, v in ipairs(t) do + ts[#ts+1] = v + end + end + return ts +end + +local function settotable(s) + local t = {} + for k in pairs(s) do + t[#t+1] = k + end + return t +end + +local function asstring(t) + return table.concat(M.flatten(t), " ") +end + +local function emit(...) + for _, s in ipairs({...}) do + io.stdout:write(s) + end +end + +function M.rawtarget(p) + local description = p.description or error("no description supplied") + local ins = M.flatten(p.ins) + local outs = M.flatten(p.outs) + + local cmd = p.command + if type(cmd) ~= "table" then + cmd = {cmd} + end + + for _, s in ipairs(ins) do + check_filename(s) + end + for _, s in ipairs(outs) do + check_filename(s) + end + + emit(outs[1], ":") + for _, s in ipairs(ins) do + emit(" ", s) + end + emit("\n") + + emit("\t@echo ", p.description, "\n") + + emit("\t$(hide) ", table.concat(cmd, " && "), "\n") + + for i = 2, #outs do + emit(outs[i], ": ", outs[1], "\n") + end + + emit("\n") +end + +function M.export(p) + local e = p[1] + local dest = p.dest or error("no export destination provided") + local deps = p.deps or error("nothing to export") + + local fdeps = M.flatten(deps) + + if #fdeps ~= 1 then + error("you can only export one thing at a time") + end + + return M.rawtarget {e, + ins=deps, + outs={dest}, + command="cp "..fdeps[1].." "..dest, + description="EXPORT "..dest + } +end + +function M.hermetic(p) + local e = p[1] + local ins = M.flatten(p.ins) + local deps = M.flatten(p.deps) + local baseouts = p.baseouts or error("you must specify some baseouts") + local description = p.description + + local absouts = {} + local path = e.PATH .. "/" .. p.baseouts[1] .. ".env" + + for _, s in ipairs(M.flatten(p.baseouts)) do + absouts[#absouts+1] = path .. "/" .. s + end + + local dirset = {} + for _, s in ipairs(absouts) do + local d = s:gsub("^(.*/).*$", "%1") + if d then + dirset[d] = true + end + end + + local newcmd = { + "rm -rf "..path, + "mkdir -p "..asstring(settotable(dirset)), + "ln -srf "..asstring(append(ins, deps)).." "..path, + "cd "..path + } + for _, s in ipairs(p.command) do + newcmd[#newcmd+1] = "(" .. s .. ")" + end + + M.rawtarget {e, + ins={ins, unpack(deps)}, + outs=absouts, + command=newcmd, + description=description + } + + return absouts +end + +function M.cfile(p) + local e = p[1] + local src = p.src + local deps = p.deps or {} + + local outfile = p.src:gsub("%.c$", ".o") + local basesrc = M.basename(p.src) + + return M.hermetic {e, + ins={src}, + deps=deps, + baseouts={outfile}, + command={e.CC.." "..e.CFLAGS.." -c -o "..outfile.." "..basesrc}, + description="CC "..src + } +end + +function M.cprogram(p) + local e = p[1] + local name = p.name or error("cprogram must have a name specified") + local deps = p.deps or {} + local libs = p.libraries or {} + local headers = p.headers or {} + + if p.srcs then + local mainlib = M.clibrary {e, + name=name..".a", + deps=deps, + srcs=p.srcs, + headers=headers + } + + deps = append(deps, {mainlib}) + end + + local libflags = {} + for _, s in ipairs(libs) do + libflags[#libflags+1] = "-l"..s + end + + return M.hermetic {e, + ins=deps, + baseouts={name}, + command={e.CC.." "..e.CFLAGS.." -o "..name.." "..asstring(M.basename(deps)).." "..asstring(libflags)}, + description="CLINK "..name + } +end + +function M.clibrary(p) + local e = p[1] + local name = p.name or error("clibrary must have a name specified") + local deps = M.flatten(p.deps) + local srcs = M.flatten(p.srcs) + local headers = M.flatten(p.headers) + + local baseouts = {name} + + local objs = deps + for _, f in ipairs(srcs) do + objs[#objs+1] = M.cfile {e, + src=f, + deps=headers + } + end + + return M.hermetic {e, + ins=append(objs, headers), + baseouts=baseouts, + command={ + e.AR.." q "..name.." "..asstring(M.basename(objs)), + e.RANLIB.." "..name, + }, + description="CLIBRARY "..name + } +end + +emit("hide = @\n") + +return M + diff --git a/first/bouncer b/first/bouncer new file mode 100755 index 000000000..f7408a012 --- /dev/null +++ b/first/bouncer @@ -0,0 +1,32 @@ +#!/bin/sh +set -e +set -x + +logfile=/tmp/bouncer.$$ +trap "rm -f $logfile" EXIT + +if [ S"$1" = S"" ]; then + >&2 echo "bouncer: syntax error: BOUNCER_WHITELIST=... bouncer " + exit 1 +fi + +strace -eopen,chdir -o $logfile -f "$@" + +awk -f- -F '[ "()]+' $logfile <<"EOF" + +BEGIN { + split(ENVIRON["BOUNCER_WHITELIST"], whitelist_array, " +"); + for (i in whitelist_array) + whitelist[whitelist_array[i]] = 1; +} + +$2 == "chdir" { + print "pid ", $1, " chdir: ", $3; +} + +($2 == "open") && ($5 !~ /O_CREAT/) && ($7 != -1) { + print "pid ", $1, " open: ", $3, $7; +} + +EOF +