Overview
| Comment: | add ipc backbone |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
87731d4007d725922fe0a577842d9435 |
| User & Date: | lexi on 2020-12-29 14:35:10 |
| Other Links: | manifest | tags |
Context
|
2020-12-29
| ||
| 14:35 | check in missing file check-in: 5a4f99fb55 user: lexi tags: trunk | |
| 14:35 | add ipc backbone check-in: 87731d4007 user: lexi tags: trunk | |
| 00:57 | add privilege control verbs check-in: a64461061f user: lexi tags: trunk | |
Changes
Modified backend/pgsql.t from [f0f9593494] to [0f1425913d].
215 215 insert into parsav_auth (uid, name, kind, cred) values ( 216 216 $1::bigint, 217 217 (select handle from parsav_actors where id = $1::bigint), 218 218 'pw-sha256', $2::bytea 219 219 ) 220 220 ]] 221 221 }; 222 + 223 + auth_purge_type = { 224 + params = {rawstring, uint64, rawstring}, cmd = true, sql = [[ 225 + delete from parsav_auth where 226 + ((uid = 0 and name = $1::text) or uid = $2::bigint) and 227 + kind like $3::text 228 + ]] 229 + }; 222 230 223 231 post_create = { 224 232 params = {uint64, rawstring, rawstring, rawstring}, sql = [[ 225 233 insert into parsav_posts ( 226 234 author, subject, acl, body, 227 235 posted, discovered, 228 236 circles, mentions ................................................................................ 876 884 877 885 auth_create_pw = [terra( 878 886 src: &lib.store.source, 879 887 uid: uint64, 880 888 reset: bool, 881 889 pw: lib.mem.ptr(int8) 882 890 ): {} 883 - -- TODO impl reset support 884 891 var hash: uint8[lib.crypt.algsz.sha256] 885 892 if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(lib.crypt.alg.sha256.id), 886 893 [&uint8](pw.ptr), pw.ct, &hash[0]) ~= 0 then 887 894 lib.bail('cannot hash password') 888 895 end 896 + if reset then queries.auth_purge_type.exec(src, nil, uid, 'pw-%') end 889 897 queries.auth_create_pw.exec(src, uid, [lib.mem.ptr(uint8)] {ptr = &hash[0], ct = [hash.type.N]}) 890 898 end]; 899 + 900 + auth_purge_pw = [terra(src: &lib.store.source, uid: uint64, handle: rawstring): {} 901 + queries.auth_purge_type.exec(src, handle, uid, 'pw-%') 902 + end]; 903 + 904 + auth_purge_otp = [terra(src: &lib.store.source, uid: uint64, handle: rawstring): {} 905 + queries.auth_purge_type.exec(src, handle, uid, 'otp-%') 906 + end]; 907 + 908 + auth_purge_trust = [terra(src: &lib.store.source, uid: uint64, handle: rawstring): {} 909 + queries.auth_purge_type.exec(src, handle, uid, 'trust') 910 + end]; 891 911 892 912 actor_auth_register_uid = nil; -- not necessary for view-based auth 893 913 894 914 } 895 915 896 916 return b
Modified cmdparse.t from [bfedd61eec] to [49c267b075].
61 61 end 62 62 terra options:free() self.arglist:free() end 63 63 options.methods.parse = terra([self], [argc], [argv]) 64 64 [init] 65 65 var parseopts = true 66 66 var [optstack] = 0 67 67 var [subcmd] = [ opts.subcmd or 0 ] 68 - self.arglist = lib.mem.heapa(rawstring, argc) 68 + self.arglist = lib.mem.heapa(rawstring, argc + 1) 69 69 var finalargc = 0 70 70 for [idx]=1,argc do 71 71 var [arg] = argv[idx] 72 72 if optstack > 0 then optstack = optstack - 1 goto [skip] end 73 73 if arg[0] == @'-' and parseopts then 74 74 if arg[1] == @'-' then -- long option 75 75 if arg[2] == 0 then -- last option ................................................................................ 88 88 subcmd = subcmd - 1 89 89 if subcmd == 0 then parseopts = false end 90 90 end 91 91 end 92 92 ::[skip]:: 93 93 end 94 94 [verifiers] 95 + self.arglist.ptr[finalargc] = nil -- for lazy-ass argv compat 95 96 if finalargc == 0 then self.arglist:free() 96 97 else self.arglist:resize(finalargc) end 97 98 end 98 99 options.helptxt = { opts = helpstr, flags = flagstr } 99 100 end 100 101 return options 101 102 end
Modified config.lua from [0c09bec0e6] to [931922a3e1].
33 33 tgthf = u.tobool(default('parsav_arch_armhf',true)); 34 34 doc = { 35 35 online = u.tobool(default('parsav_online_documentation',true)); 36 36 offline = u.tobool(default('parsav_offline_documentation',true)); 37 37 }; 38 38 outform = default('parsav_emit_type', 'o'); 39 39 endian = default('parsav_arch_endian', 'little'); 40 - prefix = default('parsav_install_prefix', './'); 40 + prefix = default('parsav_install_prefix', '.'); 41 41 build = { 42 42 id = u.rndstr(6); 43 43 release = u.ingest('release'); 44 44 when = os.date(); 45 45 }; 46 46 feat = {}; 47 47 debug = u.tobool(default('parsav_enable_debug',true)); ................................................................................ 65 65 }):gsub("^'(.*)'$", '%1') 66 66 end 67 67 conf.os = default('parsav_host_os', default_os) 68 68 conf.tgtos = default('parsav_target_os', default_os) 69 69 conf.posix = posixes[conf.os] 70 70 conf.exe = u.tobool(default('parsav_link',not conf.tgttrip)) -- turn off for partial builds 71 71 conf.prefix_conf = default('parsav_install_prefix_cfg', conf.prefix) 72 +conf.prefix_bin = default('parsav_install_prefix_cfg', conf.prefix) 72 73 conf.prefix_static = default('parsav_install_prefix_static', nil) 73 74 conf.build.origin = coalesce( 74 75 os.getenv('parsav_builder'), 75 76 string.format('%s@%s', coalesce ( 76 77 os.getenv('USER'), 77 78 u.exec{'whoami'} 78 79 ), u.exec{'hostname'}) -- whoami and hostname are present on both windows & unix
Modified crypt.t from [9b6529621c] to [f5b057e4fa].
58 58 for i=0,sz do dest[i] = [uint8](rnd()) end 59 59 return sz 60 60 end 61 61 end 62 62 63 63 m.random = macro(function(typ, from, to) 64 64 local ty = typ:astype() 65 + from = from or 0 66 + to = to or ty:max() 65 67 return quote 66 68 var v: ty 67 69 m.spray([&uint8](&v), sizeof(ty)) 68 70 v = v % (to - from) + from -- only works with unsigned!! 69 71 in v end 70 72 end) 71 73
Modified mgtool.t from [54eca1a845] to [c954b701da].
18 18 local subcmds = { 19 19 } 20 20 21 21 local ctlcmds = { 22 22 { 'start', 'start a new instance of the server' }; 23 23 { 'stop', 'stop a running instance' }; 24 24 { 'attach', 'capture log output from a running instance' }; 25 - { 'db init <domain>', 'initialize backend databases (or a single specified database) with the necessary schema and structures for the given FQDN' }; 26 - { 'db vacuum', 'delete old remote content from the database' }; 27 - { 'db extract (<artifact>|<post>/<attachment number>)', 'extracts an attachment artifact from the database and prints it to standard out' }; 28 - { 'db excise <artifact>', 'extracts an attachment artifact from the database and prints it to standard out' }; 29 - { 'db obliterate', 'completely purge all parsav-related content and structure from the database, destroying all user content (requires confirmation)' }; 30 - { 'db insert', 'reads a file from standard in and inserts it into the attachment database, printing the resulting ID' }; 25 + { 'db', 'set up and manage the database' }; 26 + { 'user', 'manage users, privileges, and credentials'}; 31 27 { 'mkroot <handle>', 'establish a new root user with the given handle' }; 32 - { 'user <handle> auth <type> new', '(where applicable, managed auth only) create a new authentication token of the given type for a user' }; 33 - { 'user <handle> auth <type> reset', '(where applicable, managed auth only) delete all of a user\'s authentication tokens of the given type and issue a new one' }; 34 - { 'user <handle> auth (<type>|all) purge', 'delete all credentials that would allow this user to log in (where possible)' }; 35 - { 'user <handle> (grant|revoke) (<priv>|all)', 'grant or revoke a specific power to or from a user' }; 36 - { 'user <handle> emasculate', 'strip all administrative powers from a user' }; 37 - { 'user <handle> suspend [<timespec>]', '(e.g. \27[1muser jokester suspend 5d 6h 7m 3s\27[m to suspend "jokester" for five days, six hours, seven minutes, and three seconds) suspend a user'}; 38 28 { 'actor <xid> purge-all', 'remove all traces of a user from the database (except local user credentials -- use \27[1mauth all purge\27[m to prevent a user from accessing the instance)' }; 39 29 { 'actor <xid> create', 'instantiate a new actor' }; 40 30 { 'actor <xid> bestow <epithet>', 'bestow an epithet upon an actor' }; 41 - { 'conf set <setting> <value>', 'add or a change a server configuration parameter to the database' }; 42 - { 'conf get <setting>', 'report the value of a server setting' }; 43 - { 'conf reset <setting>', 'reset a server setting to its default value' }; 44 - { 'conf refresh', 'instruct an instance to refresh its configuration cache' }; 45 - { 'conf chsec', 'reset the server secret, invalidating all authentication cookies' }; 31 + { 'conf', 'manage the server configuration'}; 46 32 { 'serv dl', 'initiate an update cycle over foreign actors' }; 47 33 { 'tl', 'print the current local timeline to standard out' }; 48 34 { 'be pgsql setup-auth (managed|unmanaged)', '(PGSQL backends) select the authentication strategy to use' }; 49 35 } 50 36 51 -local ctlcmdhelp = 'commands:\n' 52 -for _, v in ipairs(ctlcmds) do 53 - ctlcmdhelp = ctlcmdhelp .. string.format ( 54 - ' \27[1m%s\27[m: %s\n', v[1]:gsub('(<%w+>)','\27[36m%1\27[;1m'), v[2] 55 - ) 37 +local cmdhelp = function(tbl) 38 + local str = '\ncommands:\n' 39 + for _, v in ipairs(tbl) do 40 + str = str .. string.format ( 41 + ' \27[1m%s\27[m: %s\n', 42 + v[1] 43 + :gsub('([%(%)|%[%]])', '\27[34m%1\27[;1m') 44 + :gsub('(<.->)','\27[36m%1\27[;1m'), 45 + v[2] 46 + ) 47 + end 48 + return str 56 49 end 57 50 58 51 local struct idelegate { 59 52 all: bool 60 53 src: &lib.store.source 61 54 srv: &lib.srv.overlord 62 55 } ................................................................................ 100 93 end 101 94 lib.dbg('assigning temporary password') 102 95 dlg:auth_create_pw(uid, reset, pstr { 103 96 ptr = [rawstring](tmppw), ct = 32 104 97 }) 105 98 end 106 99 100 +local emp = lib.ipc.global_emperor 107 101 local terra entry_mgtool(argc: int, argv: &rawstring): int 108 102 if argc < 1 then lib.bail('bad invocation!') end 109 103 110 - lib.noise_init(2) 104 + lib.noise.init(2) 111 105 [lib.init] 112 106 113 107 var srv: lib.srv.overlord 114 108 var dlg = idelegate { srv = &srv, src = nil } 115 109 116 110 var mode: ctloptions 117 111 mode:parse(argc,argv) defer mode:free() 118 112 if mode.version then version() return 0 end 119 113 if mode.help then 120 - [ lib.emit(false, 1, 'usage: ', `argv[0], ' ', ctloptions.helptxt.flags, ' <cmd> [<args>…]', ctloptions.helptxt.opts, ctlcmdhelp) ] 114 + [ lib.emit(false, 1, 'usage: ', `argv[0], ' ', ctloptions.helptxt.flags, ' <cmd> [<args>…]', ctloptions.helptxt.opts, cmdhelp(ctlcmds)) ] 121 115 return 0 122 116 end 117 + if mode.quiet then lib.noise.level = 0 end 123 118 var cnf: rawstring 124 119 if mode.backend_file ~= nil 125 120 then cnf = @mode.backend_file 126 121 else cnf = lib.proc.getenv('parsav_backend_file') 127 122 end 128 - if cnf == nil then cnf = "backend.conf" end 123 + if cnf == nil then cnf = [config.prefix_conf .. "/backend.conf"] end 129 124 if mode.all then dlg.all = true else 130 125 -- iterate through and pick the right backend 131 126 end 132 127 133 128 if mode.arglist.ct == 0 then lib.bail('no command') return 1 end 129 + 130 + if lib.str.cmp(mode.arglist(0),'start') ~= 0 then 131 + -- hack to save us some pain around forking 132 + emp = lib.ipc.emperor.mk(false) 133 + end 134 + defer emp:release() 135 + 134 136 if lib.str.cmp(mode.arglist(0),'attach') == 0 then 135 137 elseif lib.str.cmp(mode.arglist(0),'start') == 0 then 138 + mode.arglist(0) = "-"; 139 + var chargv = mode.arglist.ptr 140 + var lsr = lib.ipc.listener.mk() 141 + var chpid = lib.proc.fork() 142 + if chpid == 0 then 143 + lsr:release() 144 + --lib.proc.daemonize(1,0) 145 + lib.io.close(0) lib.io.close(1) lib.io.close(2) 146 + lib.proc.exec([config.prefix_bin .. '/parsavd'], chargv) 147 + lib.proc.execp([config.prefix_bin .. '/parsavd'], chargv) 148 + lib.ipc.notify_parent(lib.ipc.signals.state_fail_find) 149 + lib.bail('cannot find parsav program') 150 + else 151 + lib.report('starting parsav daemon') 152 + while true do 153 + var sig = lsr:block() 154 + if sig.system then lib.dbg('got system signal') end 155 + if sig.from == chpid then 156 + if sig.system and sig.sig == lib.ipc.signals.sys_child then 157 + lib.warn('parsavd failed to start') 158 + return 0 159 + elseif sig.sig == lib.ipc.signals.notify_state_change and 160 + sig.event == lib.ipc.signals.state_success then 161 + lib.report('parsavd successfully started') 162 + return 0 163 + elseif sig.sig == lib.ipc.signals.notify_state_change and 164 + sig.event == lib.ipc.signals.state_fail_find then 165 + lib.bail('parsavd could not be found') 166 + else lib.warn('got unrecognized signal, ignoring') 167 + end 168 + end 169 + end 170 + lsr:release() -- just because i feel distinctly uncomfortable leaving it out 171 + end 136 172 elseif lib.str.cmp(mode.arglist(0),'stop') == 0 then 173 + var acks = emp:mallack() 174 + emp:decree(0,nil, lib.ipc.cmd.stop, 0, &acks(0)) -- TODO targeting 175 + for i=0,acks.ct do 176 + if acks(i).success then 177 + lib.io.fmt('instance %llu successfully stepped down\n', acks(i).clid) 178 + else 179 + lib.io.fmt('instance %llu reports failure to halt\n', acks(i).clid) 180 + end 181 + end 182 + acks:free() 137 183 else 138 184 if lib.str.cmp(mode.arglist(0),'db') == 0 then 139 185 var dbmode: pbasic dbmode:parse(mode.arglist.ct, &mode.arglist(0)) 140 186 if dbmode.help then 141 - [ lib.emit(false, 1, 'usage: ', `argv[0], ' db ', dbmode.type.helptxt.flags, ' <cmd> [<args>…]', dbmode.type.helptxt.opts) ] 187 + [ lib.emit(false, 1, 'usage: ', `argv[0], ' db ', dbmode.type.helptxt.flags, ' <cmd> [<args>…]', dbmode.type.helptxt.opts, cmdhelp { 188 + { 'db init <domain>', 'initialize backend databases (or a single specified database) with the necessary schema and structures for the given FQDN' }; 189 + { 'db vacuum', 'delete old remote content from the database' }; 190 + { 'db extract (<artifact>|<post>/<attachment number>)', 'extracts an attachment artifact from the database and prints it to standard out' }; 191 + { 'db excise (<artifact>|<post>/<attachment number>)', 'removes an undesirable artifact from the database' }; 192 + { 'db obliterate [<confirmation code>]', 'completely purge all parsav-related content and structure from the database, destroying all user content (requires confirmation)' }; 193 + { 'db insert', 'reads a file from standard in and inserts it into the attachment database, printing the resulting ID' }; 194 + }) ] 142 195 return 1 143 196 end 144 197 if dbmode.arglist.ct < 1 then goto cmderr end 145 198 146 199 srv:setup(cnf) 147 200 if lib.str.cmp(dbmode.arglist(0),'init') == 0 and dbmode.arglist.ct == 2 then 148 201 lib.report('initializing new database structure for domain ', dbmode.arglist(1)) ................................................................................ 157 210 var confirmstrs = array( 158 211 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'eta', 'nu', 'kappa' 159 212 ) 160 213 var cfmstr: int8[64] cfmstr[0] = 0 161 214 var tdx = lib.osclock.time(nil) / 60 162 215 for i=0,3 do 163 216 if i ~= 0 then lib.str.cat(&cfmstr[0], '-') end 164 - lib.str.cat(&cfmstr[0], confirmstrs[(tdx + 49*i) % [confirmstrs.type.N]]) 217 + lib.str.cat(&cfmstr[0], confirmstrs[(tdx ^ (173*i)) % [confirmstrs.type.N]]) 165 218 end 166 219 167 220 if dbmode.arglist.ct == 1 then 168 221 lib.bail('you are attempting to completely obliterate all data! make sure you have selected your target correctly. if you really want to do this, pass the confirmation string ', &cfmstr[0]) 169 222 elseif dbmode.arglist.ct == 2 then 170 223 if lib.str.cmp(dbmode.arglist(1), cfmstr) == 0 then 171 224 lib.warn('completely obliterating all data!') ................................................................................ 182 235 srv:conprep(lib.store.prepmode.conf) 183 236 var cfmode: lib.cmdparse { 184 237 help = {'h','display this list'}; 185 238 no_notify = {'n', "don't instruct the server to refresh its configuration cache after making changes; useful for \"transactional\" configuration changes."}; 186 239 } 187 240 cfmode:parse(mode.arglist.ct, &mode.arglist(0)) 188 241 if cfmode.help then 189 - [ lib.emit(false, 1, 'usage: ', `argv[0], ' conf ', cfmode.type.helptxt.flags, ' <cmd> [<args>…]', cfmode.type.helptxt.opts) ] 242 + [ lib.emit(false, 1, 'usage: ', `argv[0], ' conf ', cfmode.type.helptxt.flags, ' <cmd> [<args>…]', cfmode.type.helptxt.opts, cmdhelp { 243 + { 'conf set <setting> <value>', 'add or a change a server configuration parameter to the database' }; 244 + { 'conf get <setting>', 'report the value of a server setting' }; 245 + { 'conf reset <setting>', 'reset a server setting to its default value' }; 246 + { 'conf refresh', 'instruct an instance to refresh its configuration cache' }; 247 + { 'conf chsec', 'reset the server secret, invalidating all authentication cookies' }; 248 + }) ] 190 249 return 1 191 250 end 192 251 if cfmode.arglist.ct < 1 then goto cmderr end 193 252 194 253 if cfmode.arglist.ct == 1 then 195 254 if lib.str.cmp(cfmode.arglist(0),'chsec') == 0 then 196 255 var sec: int8[65] gensec(&sec[0]) ................................................................................ 245 304 pwset(dlg, &tmppw, ruid, false) 246 305 lib.report('temporary root pw: ', {&tmppw[0], 32}) 247 306 end 248 307 else goto cmderr end 249 308 elseif lib.str.cmp(mode.arglist(0),'user') == 0 then 250 309 var umode: pbasic umode:parse(mode.arglist.ct, &mode.arglist(0)) 251 310 if umode.help then 252 - [ lib.emit(false, 1, 'usage: ', `argv[0], ' user ', umode.type.helptxt.flags, ' <handle> <cmd> [<args>…]', umode.type.helptxt.opts) ] 311 + [ lib.emit(false, 1, 'usage: ', `argv[0], ' user ', umode.type.helptxt.flags, ' <handle> <cmd> [<args>…]', umode.type.helptxt.opts, cmdhelp { 312 + { 'user <handle> auth <type> new', '(where applicable, managed auth only) create a new authentication token of the given type for a user' }; 313 + { 'user <handle> auth <type> reset', '(where applicable, managed auth only) delete all of a user\'s authentication tokens of the given type and issue a new one' }; 314 + { 'user <handle> auth (<type>|all) purge', 'delete all credentials that would allow this user to log in (where possible)' }; 315 + { 'user <handle> (grant|revoke) (<priv>|all)', 'grant or revoke a specific power to or from a user' }; 316 + { 'user <handle> emasculate', 'strip all administrative powers from a user' }; 317 + { 'user <handle> forgive', 'restore all default powers to a user' }; 318 + { 'user <handle> suspend [<timespec>]', '(e.g. \27[1muser jokester suspend 5d 6h 7m 3s\27[m to suspend "jokester" for five days, six hours, seven minutes, and three seconds) suspend a user'}; 319 + }) ] 253 320 return 1 254 321 end 255 322 if umode.arglist.ct >= 3 then 256 323 var grant = lib.str.cmp(umode.arglist(1),'grant') == 0 257 324 var handle = umode.arglist(0) 258 325 var usr = dlg:actor_fetch_xid(pstr {ptr=handle, ct=lib.str.sz(handle)}) 259 - if not usr then lib.bail('unknown handle') end 260 326 if grant or lib.str.cmp(umode.arglist(1),'revoke') == 0 then 327 + if not usr then lib.bail('unknown handle') end 261 328 var newprivs = usr.ptr.rights.powers 262 329 var map = array([lib.store.privmap]) 263 330 if umode.arglist.ct == 3 and lib.str.cmp(umode.arglist(2),'all') == 0 then 264 331 if grant 265 332 then newprivs:fill() 266 333 else newprivs:clear() 267 334 end ................................................................................ 285 352 end 286 353 287 354 usr.ptr.rights.powers = newprivs 288 355 dlg:actor_save_privs(usr.ptr) 289 356 elseif lib.str.cmp(umode.arglist(1),'auth') == 0 and umode.arglist.ct == 4 then 290 357 var reset = lib.str.cmp(umode.arglist(3),'reset') == 0 291 358 if reset or lib.str.cmp(umode.arglist(3),'new') == 0 then 359 + -- FIXME enable resetting pws for users who have 360 + -- not logged in yet 361 + if not usr then lib.bail('unknown handle') end 292 362 if lib.str.cmp(umode.arglist(2),'pw') == 0 then 293 363 var tmppw: int8[33] 294 364 pwset(dlg, &tmppw, usr.ptr.id, reset) 295 365 lib.report('new temporary password for ',usr.ptr.handle,': ', {&tmppw[0], 32}) 296 366 else lib.bail('unknown credential type') end 297 367 elseif lib.str.cmp(umode.arglist(3),'purge') == 0 then 368 + var uid: uint64 = 0 369 + if usr:ref() then uid = usr(0).id end 370 + if lib.str.cmp(umode.arglist(2),'pw') == 0 then 371 + dlg:auth_purge_pw(uid, handle) 372 + elseif lib.str.cmp(umode.arglist(2),'otp') == 0 then 373 + dlg:auth_purge_otp(uid, handle) 374 + elseif lib.str.cmp(umode.arglist(2),'trust') == 0 then 375 + dlg:auth_purge_trust(uid, handle) 376 + else lib.bail('unknown credential type') end 298 377 else goto cmderr end 299 378 else goto cmderr end 300 379 else goto cmderr end 301 380 elseif lib.str.cmp(mode.arglist(0),'actor') == 0 then 302 381 elseif lib.str.cmp(mode.arglist(0),'tl') == 0 then 303 382 elseif lib.str.cmp(mode.arglist(0),'serv') == 0 then 304 383 else goto cmderr end
Modified parsav.t from [d1470e4b10] to [1565f096a3].
124 124 local q = quote 125 125 var [val] 126 126 [exp] 127 127 in val end 128 128 return q 129 129 end); 130 130 proc = { 131 + fork = terralib.externfunction('fork', {} -> int); 132 + daemonize = terralib.externfunction('daemon', {int,int} -> {}); 131 133 exit = terralib.externfunction('exit', int -> {}); 132 134 getenv = terralib.externfunction('getenv', rawstring -> rawstring); 135 + exec = terralib.externfunction('execv', {rawstring,&rawstring} -> int); 136 + execp = terralib.externfunction('execvp', {rawstring,&rawstring} -> int); 133 137 }; 134 138 io = { 135 139 send = terralib.externfunction('write', {int, rawstring, intptr} -> ptrdiff); 136 140 recv = terralib.externfunction('read', {int, rawstring, intptr} -> ptrdiff); 141 + close = terralib.externfunction('close', {int} -> int); 137 142 say = macro(function(msg) return `lib.io.send(2, msg, [#(msg:asvalue())]) end); 138 143 fmt = terralib.externfunction('printf', 139 144 terralib.types.funcpointer({rawstring},{int},true)); 140 145 }; 141 146 str = { sz = terralib.externfunction('strlen', rawstring -> intptr) }; 142 147 copy = function(tbl) 143 148 local new = {} ................................................................................ 148 153 osclock = terralib.includec 'time.h'; 149 154 } 150 155 if config.posix then 151 156 lib.uio = terralib.includec 'sys/uio.h'; 152 157 lib.emit = lib.emitv -- use more efficient call where available 153 158 else lib.emit = lib.emit_unitary end 154 159 155 -local starttime = global(lib.osclock.time_t) 156 -local lastnoisetime = global(lib.osclock.time_t) 157 -local noise = global(uint8,1) 158 -local noise_header = function(code,txt,mod) 159 - if mod then 160 - return string.format('\27[%s;1m(%s %s)\27[m ', code,mod,txt) 161 - else 162 - return string.format('\27[%s;1m(%s)\27[m ', code,txt) 163 - end 164 -end 160 + 161 +lib.noise = { 162 + level = global(uint8,1); 163 + starttime = global(lib.osclock.time_t); 164 + lasttime = global(lib.osclock.time_t); 165 + header = function(code,txt,mod) 166 + if mod then 167 + return string.format('\27[%s;1m(%s %s)\27[m ', code,mod,txt) 168 + else 169 + return string.format('\27[%s;1m(%s)\27[m ', code,txt) 170 + end 171 + end; 172 +} 165 173 166 174 local terra timehdr() 167 175 var now = lib.osclock.time(nil) 168 - var diff = now - lastnoisetime 176 + var diff = now - lib.noise.lasttime 169 177 if diff > 30 then -- print cur time 170 - lastnoisetime = now 178 + lib.noise.lasttime = now 171 179 var curtime: int8[26] 172 180 lib.osclock.ctime_r(&now, &curtime[0]) 173 181 for i=0,26 do if curtime[i] == @'\n' then curtime[i] = 0 break end end -- :/ 174 182 [ lib.emit(false, 2, '\27[1m[', `&curtime[0], ']\27[;36m\n +00 ') ] 175 183 else -- print time since last msg 176 184 var dfs = arrayof(int8, 0x30 + diff/10, 0x30 + diff%10, 0x20, 0) 177 185 [ lib.emit(false, 2, ' \27[36m+', `&dfs[0]) ] ................................................................................ 182 190 if level >= 3 and config.debug == false then 183 191 return macro(function(...) return {} end) 184 192 end 185 193 return macro(function(...) 186 194 local fn = (...).filename 187 195 local ln = tostring((...).linenumber) 188 196 local dbgtag = string.format('\27[35m · \27[34m%s:\27[1m%s\27[m\n', fn,ln) 189 - local q = lib.emit(level < 3 and true or dbgtag, 2, noise_header(code,n), ...) 197 + local q = lib.emit(level < 3 and true or dbgtag, 2, lib.noise.header(code,n), ...) 190 198 return quote 191 199 --lib.io.fmt(['attempting to emit at ' .. fn..':'..ln.. '\n']) 192 - if noise >= level then timehdr(); [q] end end 200 + if lib.noise.level >= level then timehdr(); [q] end end 193 201 end); 194 202 end 203 +local terra final_cleanup :: {} -> {} 195 204 lib.dbg = defrep(3,'debug', '32') 196 205 lib.report = defrep(2,'info', '35') 197 206 lib.warn = defrep(1,'warn', '33') 198 207 lib.bail = macro(function(...) 199 - local q = lib.emit(true, 2, noise_header('31','fatal'), ...) 208 + local q = lib.emit(true, 2, lib.noise.header('31','fatal'), ...) 200 209 return quote 201 - timehdr(); [q] 210 + if lib.noise.level ~= 0 then 211 + timehdr(); [q] 212 + end 213 + final_cleanup() 202 214 lib.proc.exit(1) 203 215 end 204 216 end); 205 217 lib.stat = terralib.memoize(function(ty) 206 218 local n = struct { 207 219 ok: bool 208 220 union { ................................................................................ 332 344 lib.pk = lib.loadlib('mbedtls','mbedtls/pk.h') 333 345 lib.md = lib.loadlib('mbedtls','mbedtls/md.h') 334 346 lib.b64 = lib.loadlib('mbedtls','mbedtls/base64.h') 335 347 lib.net = lib.loadlib('mongoose','mongoose.h') 336 348 lib.pq = lib.loadlib('libpq','libpq-fe.h') 337 349 338 350 lib.load { 339 - 'mem', 'math', 'str', 'file', 'crypt'; 351 + 'mem', 'math', 'str', 'file', 'crypt', 'ipc'; 340 352 'http', 'html', 'session', 'tpl', 'store'; 341 353 342 354 'smackdown'; -- md-alike parser 343 355 } 344 356 345 357 local be = {} 346 358 for _, b in pairs(config.backends) do ................................................................................ 393 405 } 394 406 395 407 do 396 408 local p = string.format('parsav: %s\nbuilt on %s\n', config.build.str, config.build.when) 397 409 terra version() lib.io.send(1, p, [#p]) end 398 410 end 399 411 400 -terra lib.noise_init(default_level: uint) 401 - starttime = lib.osclock.time(nil) 402 - lastnoisetime = 0 412 +terra lib.noise.init(default_level: uint) 413 + lib.noise.starttime = lib.osclock.time(nil) 414 + lib.noise.lasttime = 0 403 415 var n = lib.proc.getenv('parsav_noise') 404 416 if n ~= nil then 405 417 if n[0] >= 0x30 and n[0] <= 0x39 and n[1] == 0 then 406 - noise = n[0] - 0x30 418 + lib.noise.level = n[0] - 0x30 407 419 return 408 420 end 409 421 end 410 - noise = default_level 422 + lib.noise.level = default_level 411 423 end 412 424 lib.load{'mgtool'} 413 425 414 426 local options = lib.cmdparse { 415 427 version = {'V', 'display information about the binary build and exit'}; 416 428 verbose = {'v', 'increase logging verbosity', inc=1}; 417 429 quiet = {'q', 'do not print to standard out'}; 418 430 help = {'h', 'display this list'}; 419 431 backend_file = {'B', 'init from specified backend file', consume=1}; 420 432 static_dir = {'S', 'directory with overrides for static content', consume=1}; 421 433 builtin_data = {'D', 'do not load static content overrides at runtime under any circumstances'}; 422 434 instance = {'i', 'set an instance name to make it easier to control multiple daemons', consume = 1}; 435 + no_ipc = {'I', 'disable IPC'}; 423 436 } 424 437 425 438 426 439 local static_setup = quote end 427 440 local mapin = quote end 428 441 local odir = symbol(rawstring) 429 442 local pathbuf = symbol(lib.str.acc) ................................................................................ 461 474 end or quote return end 462 475 ] end 463 476 464 477 var [pathbuf] defer pathbuf:free() 465 478 pathbuf:compose(odir,'/') 466 479 [mapin] 467 480 end 481 + 482 +terra final_cleanup() 483 + lib.ipc.global_emperor:release() 484 +end 468 485 469 486 local terra entry_daemon(argc: int, argv: &rawstring): int 470 487 if argc < 1 then lib.bail('bad invocation!') end 471 488 472 - lib.noise_init(1) 489 + lib.noise.init(1) 473 490 [lib.init] 474 491 475 492 -- shut mongoose the fuck up 476 493 lib.net.mg_log_set_callback([terra(msg: &opaque, sz: int, u: &opaque) end], nil) 477 494 var srv: lib.srv.overlord 478 495 479 496 do var mode: options ................................................................................ 480 497 mode:parse(argc,argv) defer mode:free() 481 498 static_init(&mode) 482 499 if mode.version then version() return 0 end 483 500 if mode.help then 484 501 [ lib.emit(true, 1, 'usage: ',`argv[0],' ', options.helptxt.flags, ' [<args>…]', options.helptxt.opts) ] 485 502 return 0 486 503 end 504 + if mode.quiet then lib.noise.level = 0 end 487 505 var cnf: rawstring 488 506 if mode.backend_file ~= nil 489 507 then cnf = @mode.backend_file 490 508 else cnf = lib.proc.getenv('parsav_backend_file') 491 509 end 492 - if cnf == nil then cnf = [config.prefix_conf .. "backend.conf"] end 510 + if cnf == nil then cnf = [config.prefix_conf .. "/backend.conf"] end 493 511 494 512 srv:setup(cnf) 513 + if argv[0][0] == @'-' and argv[0][1] == 0 then 514 + lib.ipc.notify_parent(lib.ipc.signals.state_success) 515 + argv[0] = 'parsav service daemon' 516 + end 495 517 srv:start(lib.trn(mode.instance ~= nil, @mode.instance, nil)) 496 518 end 519 + lib.ipc.global_emperor = lib.ipc.emperor.mk(true) defer lib.ipc.global_emperor:release() 497 520 498 521 lib.report('listening for requests') 499 - while true do 522 + while lib.ipc.proc_active do 500 523 srv:poll() 524 + while true do 525 + var d: lib.ipc.demand 526 + lib.ipc.global_emperor:poll(&d) 527 + var a = lib.ipc.ack {success = true} 528 + if d.cmd == lib.ipc.cmd.none then break 529 + elseif d.cmd == lib.ipc.cmd.stop then 530 + lib.ipc.proc_active = false 531 + elseif d.cmd == lib.ipc.cmd.enumerate then 532 + if srv.id ~= nil then 533 + lib.str.ncpy(&a.iname[0], srv.id, [(`a.iname).tree.type.N]) 534 + else a.iname[0] = 0 end 535 + elseif d.cmd == lib.ipc.cmd.chnoise then 536 + lib.noise.level = d.operand 537 + elseif d.cmd == lib.ipc.cmd.cfgrefresh then 538 + srv.cfg:free() 539 + srv.cfg:load() 540 + end 541 + d:ack(&lib.ipc.global_emperor, &a) 542 + end 501 543 end 502 544 srv:shutdown() 503 545 504 546 return 0 505 547 end 506 - 507 548 508 549 local bflag = function(long,short) 509 550 if short and util.has(buildopts, short) then return true end 510 551 if long and util.has(buildopts, long) then return true end 511 552 return false 512 553 end 513 554
Modified store.t from [3a79c99b1d] to [763fd9ba8a].
266 266 actor_conf_str: cnf(rawstring, lib.mem.ptr(int8)) 267 267 actor_conf_int: cnf(intptr, lib.stat(intptr)) 268 268 269 269 auth_create_pw: {&m.source, uint64, bool, lib.mem.ptr(int8)} -> {} 270 270 -- uid: uint64 271 271 -- reset: bool (delete other passwords?) 272 272 -- pw: pstring 273 + auth_purge_pw: {&m.source, uint64, rawstring} -> {} 274 + auth_purge_otp: {&m.source, uint64, rawstring} -> {} 275 + auth_purge_trust: {&m.source, uint64, rawstring} -> {} 273 276 274 277 post_save: {&m.source, &m.post} -> {} 275 278 post_create: {&m.source, &m.post} -> uint64 276 279 post_enum_author_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post)) 277 280 convo_fetch_xid: {&m.source,rawstring} -> lib.mem.ptr(m.post) 278 281 convo_fetch_uid: {&m.source,uint64} -> lib.mem.ptr(m.post) 279 282