ADDED common.lua Index: common.lua ================================================================== --- common.lua +++ common.lua @@ -0,0 +1,91 @@ +local map = function(lst,fn) + local new = {} for k,v in pairs(lst) do + local nv, nk = fn(v,k) + new[nk or k] = nv + end + return new +end + +local chomp = function(str) + while string.sub(str,#str) == '\n' do + str = string.sub(str,1,#str - 1) + end + return str +end + +local exec = function(args, val) + local cmd = table.concat(map(args, function(a) + return string.format('%q', a) + end), ' ') + if val then return os.execute(cmd) else + local fd = io.popen(cmd,'r') + local t = fd:read('*a') + return chomp(t), fd:close() + end +end + +local function dump(v,pfx) + pfx = pfx or '' + local np = pfx .. ' ' + if type(v) == 'string' then + return string.format('%q', v) + elseif type(v) == 'table' then + local str = '' + for k,v in pairs(v) do + str = str .. string.format('%s[%s] = %s\n', np, dump(k,np), dump(v,np)) + end + return '{\n' .. str .. pfx .. '}\n' + else + return string.format('%s', v) + end +end +local ping = function(path) + local f = io.open(path) + if f then f:close() return true end + return false +end +local tobool = function(s) + if s == true then return true + elseif s == false then return false end + s = ({ + yes = true, ['true'] = true, on = true, ['1'] = true; + no = false, ['false'] = false, off = false, ['0'] = false; + })[string.lower(s)] + if not s then return false end + return true +end +return { + exec = exec; + dump = dump; + ping = ping; + chomp = chomp; + map = map; + tobool = tobool; + append = function(a,b) + for _, v in pairs(b) do a[#a+1] = v end + end; + has = function(haystack,needle,eq) + eq = eq or function(a,b) return a == b end + for k,v in pairs(haystack) do + if eq(needle,v) then return k end + end + end; + parseargs = function(a) + local raw = false + local opts, args = {}, {} + for i,v in ipairs(a) do + if v == '--' then + raw = true + else + if (not raw) and string.sub(v,1,2) == '--' then -- longopt + opts[#opts+1] = string.sub(v,3) + elseif (not raw) and string.sub(v,1,1) == '-' then -- shortopts + for c in string.gmatch(string.sub(v,2), '.') do + opts[#opts+1] = c + end + else args[#args+1]=v end + end + end + return opts, args + end; +} ADDED config.lua Index: config.lua ================================================================== --- config.lua +++ config.lua @@ -0,0 +1,147 @@ +local u = dofile('common.lua') +local default = function(var,def) + local v = os.getenv(var) + if v then return v else return def end +end +local posixes = { + linux = true; osx = true; + android = true; haiku = true; +} +local conf = { + pkg = {}; + os = default('parsav_target_os', 'linux'); + dist = default('parsav_dist', os.getenv('NIX_PATH') and 'nixos'); + tgttrip = default('parsav_arch_triple'); -- target triple, used in xcomp + tgtcpu = default('parsav_arch_cpu'); -- target cpu, used in xcomp + tgthf = u.tobool(default('parsav_arch_armhf',true)); +} +conf.posix = posixes[conf.os] +conf.exe = u.tobool(default('parsav_link',not conf.tgttrip)); -- turn off for partial builds + +local fallback = dofile('pkgdata.lua') +local libfind do local mkf = function(p) + return function(l) return string.format(p,l) end + end + local unx = function(p) + return function(l) + if string.sub(l,1,3) == 'lib' + then return string.format('%s.%s',l,p) + else return string.format('lib%s.%s',l,p) + end + end + end + + libfind = { + linux = { + static = unx 'a'; + dynamic = unx 'so'; + }; + osx = { dynamic = mkf '%s.dylib'; }; + win = { dynamic = mkf '%s.dll'; }; + } +end +local pkg = function(name) + local fbo = fallback[name] and fallback[name].osvars + and fallback[name].osvars[conf.os .. '_' .. conf.dist] + local fbv = fallback[name] and fallback[name].vars + local pkgenv = function(e) + return os.getenv(string.format('parsav_pkg_%s_%s',name,e)) + end + name = pkgenv('override') or name + local nul = function() end + local pkc, pkv = nul, nul + local cnfvar = function(v,e) + local eval = function(e) + if type(e) == 'function' + then return e(conf) + else return e + end + end + return pkgenv(v) or pkv(e or v) or (fbo and eval(fbo[v])) or (fbv and eval(fbv[v])) + end + if conf.posix then + pkc = function(...) return u.exec { 'pkg-config'; name; ... } end + local pkcv = function(...) return u.exec({ 'pkg-config'; name; ... }, true) end + if pkcv('--exists') == 0 then + pkv = function(v) + return pkc('--variable', v) + end + else pkc = nul end + else + print '(warn) configuring on non-POSIX OS, all relevant paths must be specified manually in environment variables or build will fail!' + end + local locdep = u.ping('./lib/' .. name) + local prefix + if locdep then + prefix = './lib/' .. name + end + prefix = prefix or cnfvar('prefix') + local libdir = cnfvar('libdir') + if not libdir then + if locdep + then libdir = prefix .. (cnfvar('builddir') or cnfvar('libbuilddir')) or '' + else libdir = prefix .. '/lib' + end + end + local incdir = cnfvar('incdir','includedir') or (prefix .. '/include') + local libstr = pkc '--libs-only-l' -- (--static is not reliable) + local libs = fallback[name] and fallback[name].libs or {} + local linkstatic = locdep + if (not locdep) and libstr then + libs = {} + for m in string.gmatch(libstr, '-l(%g+)') do + libs[#libs + 1] = m + end + else + if #libs == 0 then libs = { name } end + end + + conf.pkg[name] = { + prefix = prefix; + libdir = libdir; + incdir = incdir; + dylibs = {}, statlibs = {}; + } + local me = conf.pkg[name] + + local lf = libfind[conf.os] + if lf.dynamic then me.dylibs = u.map(libs, lf.dynamic) end + if lf.static then me.statlibs = u.map(libs, lf.static) end + + if linkstatic then + local ldf = {} + for _,v in pairs(me.statlibs) do + local fl = libdir .. '/' .. v + if u.ping(fl) then ldf[#ldf+1] = fl end + end + me.linkargs = ldf + else + local arg = name + if string.sub(arg,1,3) == 'lib' then arg = string.sub(arg,4) end + local linkline = libstr or string.format('-l%s', arg) + me.linkargs = { + string.format('-L%s', me.libdir); + } + for m in string.gmatch(linkline, '(%g+)') do + me.linkargs[#me.linkargs+1] = m + end + + -- siiiiigh + for _,l in pairs(libs) do + local sw = string.format('-l%s', l) + local found = false + for _,a in pairs(me.linkargs) do + if a == sw then found = true break end + end + if not found then + me.linkargs[#me.linkargs+1] = sw + end + end + end +end + +pkg('mbedtls') +pkg('libhttp') +pkg('json-c') + +return conf ADDED makefile Index: makefile ================================================================== --- makefile +++ makefile @@ -0,0 +1,65 @@ +dl = git +dbg-flags = $(if $(dbg),-g) + +parsav: parsav.t config.lua pkgdata.lua + terra $(dbg-flags) $< +parsav.o: parsav.t config.lua pkgdata.lua + env parsav_link=no terra $(dbg-flags) $< + +clean: + rm parsav parsav.o + +dep: dep.mbedtls dep.libhttp dep.json-c +dep.mbedtls: lib/mbedtls/library/libmbedtls.a \ + lib/mbedtls/library/libmbedcrypto.a \ + lib/mbedtls/library/libmbedx509.a +dep.libhttp: lib/libhttp/lib/libhttp.a +dep.json-c: lib/libhttp/json-c.a + +lib: + mkdir $@ +# parsav is designed to be fronted by a real web +# server like nginx if SSL is to be used +# caveat: libhttp is a mess. the docs are completely +# full of shit. there is no lua support as far as i +# can tell. +lib/libhttp/lib/libhttp.a: lib/libhttp + $(MAKE) -C $< lib/libhttp.a \ + RM='rm -f' \ + CC="$(CC) -Wno-unused-result" \ + DFLAGS="-DNO_SSL -DNO_FILES -DNO_CGI -DUSE_STACK_SIZE=102400 -DUSE_IPV6" + +lib/json-c/Makefile: lib/json-c lib/json-c/CMakeLists.txt + cd lib/json-c && cmake . +lib/json-c/libjson-c.a: lib/json-c/Makefile + $(MAKE) -C lib/json-c +lib/mbedtls/library/%.a: lib/mbedtls + $(MAKE) -C lib/mbedtls/library $*.a + +ifeq ($(dl), git) +lib/libhttp: lib + cd lib && git clone https://github.com/lammertb/libhttp.git +lib/mbedtls: lib + cd lib && git clone https://github.com/ARMmbed/mbedtls.git +lib/json-c: lib + cd lib && git clone https://github.com/json-c/json-c.git +else +lib/%: lib/%.tar.gz + cd lib && tar zxf $*.tar.gz + mv lib/$$(tar tf $< | head -n1) $@ + +ifeq ($(dl), wget) + dlfile = wget "$(1)" -O "$(2)" +endif + +ifeq ($(dl), curl) + dlfile = curl "$(1)" -o "$(2)" +endif + +lib/libhttp.tar.gz: lib + $(call dlfile,https://api.github.com/repos/lammertb/libhttp/tarball/master,$@) +lib/mbedtls.tar.gz: lib + $(call dlfile,https://api.github.com/repos/ARMmbed/mbedtls/tarball/master,$@) +lib/json-c.tar.gz: lib + $(call dlfile,https://api.github.com/repos/json-c/json-c/tarball/master,$@) +endif ADDED parsav.md Index: parsav.md ================================================================== --- parsav.md +++ parsav.md @@ -0,0 +1,20 @@ +# parsav + +**parsav** is a lightweight fediverse server + +## dependencies + +* libhttp +* json-c +* mbedtls +* postgresql-libs + +## building + +first, either install any missing dependencies as shared libraries, or build them as static libraries as described below: + +* libhttp: run `$ make lib/libhttp/lib/libhttp.a` +* json-c (deps: `cmake`): run `$ make lib/json-c/libjson-c.a` +* mbedtls: run `$ make lib/mbedtls/lib/mbed{crypto,tls,x509}.a` + +you can install static libraries for all dependencies with `$ make dep`, but this is recommended only if you have none of the above ADDED parsav.t Index: parsav.t ================================================================== --- parsav.t +++ parsav.t @@ -0,0 +1,62 @@ +-- vim: ft=terra + +local util = dofile('common.lua') +local buildopts, buildargs = util.parseargs{...} + +local config = dofile('config.lua') + +local lib = { + loadlib = function(name,hdr) + local p = config.pkg[name] + -- for _,v in pairs(p.dylibs) do + -- terralib.linklibrary(p.libdir .. '/' .. v) + -- end + return terralib.includec(p.incdir .. '/' .. hdr) + end; + randomize = terralib.externfunction('getrandom', {&opaque, intptr, uint} -> ptrdiff); +} +lib.rsa = lib.loadlib('mbedtls','mbedtls/rsa.h') +lib.pk = lib.loadlib('mbedtls','mbedtls/pk.h') + +local callbacks = { + randomize = terra(ctx: &opaque, dest: &uint8, sz: intptr): int + return lib.randomize(dest, sz, 0) + end; +} + +terra entry(): int + var pk: lib.pk.mbedtls_pk_context + lib.pk.mbedtls_pk_init(&pk) + lib.pk.mbedtls_pk_setup(&pk, lib.pk.mbedtls_pk_info_from_type(lib.pk.MBEDTLS_PK_RSA)) + var rsa = [&lib.rsa.mbedtls_rsa_context](pk.pk_ctx) + lib.rsa.mbedtls_rsa_gen_key(rsa, callbacks.randomize, nil, 2048, 65537) + return 0 +end + +local bflag = function(long,short) + if short and util.has(buildopts, short) then return true end + if long and util.has(buildopts, long) then return true end + return false +end + +if bflag('dump-config','C') then + print(util.dump(config)) + os.exit(0) +end + +local emit = print +if bflag('quiet','q') then emit = function() end end + +local out = config.exe and 'parsav' or 'parsav.o' +local linkargs = {} +for _,p in pairs(config.pkg) do util.append(linkargs, p.linkargs) end +emit('linking with args',util.dump(linkargs)) +terralib.saveobj(out, { + main = entry + }, + linkargs, + config.tgttrip and terralib.newtarget { + Triple = config.tgttrip; + CPU = config.tgtcpu; + FloatABIHard = config.tgthf; + } or nil) ADDED pkgdata.lua Index: pkgdata.lua ================================================================== --- pkgdata.lua +++ pkgdata.lua @@ -0,0 +1,14 @@ +local util = dofile('common.lua') +local sthunk = function(...) local a = {...} return function() return util.exec(a) end end +return { + mbedtls = { + libs = {'mbedtls', 'mbedcrypto', 'mbedx509'}; + osvars = { + linux_nixos = { -- lacks a *.pc on nixos systems + prefix = sthunk('nix', 'path-info', 'nixos.mbedtls'); + } + }; + vars = { builddir = '/library' }; + }; + libhttp = { vars = { builddir = '/lib' }; }; +}