4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
..
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
..
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
local ctloptions = lib.cmdparse({
version = {'V', 'display information about the binary build and exit'};
verbose = {'v', 'increase logging verbosity', inc=1};
quiet = {'q', 'do not print to standard out'};
help = {'h', 'display this list'};
backend_file = {'B', 'init from specified backend file', consume=1};
backend = {'b', 'operate on only the selected backend'};
instance = {'i', 'specify the instance to control by name', consume=1};
all = {'A', 'affect all running instances'};
}, { subcmd = 1 })
local pbasic = lib.cmdparse {
help = {'h', 'display this list'}
}
local subcmds = {
}
local ctlcmds = {
{ 'start', 'start a new instance of the server' };
{ 'stop', 'stop a running instance' };
{ 'attach', 'capture log output from a running instance' };
{ 'db', 'set up and manage the database' };
{ 'user', 'manage users, privileges, and credentials'};
{ 'mkroot <handle>', 'establish a new root user with the given handle' };
{ '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)' };
{ 'actor <xid> create', 'instantiate a new actor' };
{ 'actor <xid> bestow <epithet>', 'bestow an epithet upon an actor' };
................................................................................
v[2]
)
end
return str
end
local struct idelegate {
all: bool
src: &lib.store.source
srv: &lib.srv.overlord
}
idelegate.metamethods.__methodmissing = macro(function(meth, self, ...)
local expr = {...}
local rt
for _,f in pairs(lib.store.backend.entries) do
local fn = f.field or f[1]
local ft = f.type or f[2]
................................................................................
if self.all
then r=self.srv:[meth]([expr])
elseif self.src ~= nil then r=self.src:[meth]([expr])
else lib.bail('no data source specified')
end
in r end
end)
local terra gensec(sdest: rawstring)
var dest = [&uint8](sdest)
lib.crypt.spray(dest,64)
for i=0,64 do dest[i] = dest[i] % (0x7e - 0x20) + 0x20 end
dest[64] = 0
end
................................................................................
else tmppw[i] = tmppw[i] + 0x30 end
end
lib.dbg('assigning temporary password')
dlg:auth_create_pw(uid, reset, pstr {
ptr = [rawstring](tmppw), ct = 32
})
end
local emp = lib.ipc.global_emperor
local terra entry_mgtool(argc: int, argv: &rawstring): int
if argc < 1 then lib.bail('bad invocation!') end
lib.noise.init(2)
[lib.init]
var srv: lib.srv.overlord
var dlg = idelegate { srv = &srv, src = nil }
var mode: ctloptions
mode:parse(argc,argv) defer mode:free()
if mode.version then version() return 0 end
if mode.help then
[ lib.emit(false, 1, 'usage: ', `argv[0], ' ', ctloptions.helptxt.flags, ' <cmd> [<args>…]', ctloptions.helptxt.opts, cmdhelp(ctlcmds)) ]
return 0
................................................................................
var cnf: rawstring
if mode.backend_file ~= nil
then cnf = @mode.backend_file
else cnf = lib.proc.getenv('parsav_backend_file')
end
if cnf == nil then cnf = [config.prefix_conf .. "/backend.conf"] end
if mode.all then dlg.all = true else
-- iterate through and pick the right backend
end
if mode.arglist.ct == 0 then lib.bail('no command') return 1 end
if lib.str.cmp(mode.arglist(0),'start') ~= 0 then
-- hack to save us some pain around forking
emp = lib.ipc.emperor.mk(false)
end
defer emp:release()
if lib.str.cmp(mode.arglist(0),'attach') == 0 then
elseif lib.str.cmp(mode.arglist(0),'start') == 0 then
mode.arglist(0) = "-";
var chargv = mode.arglist.ptr
var lsr = lib.ipc.listener.mk()
var chpid = lib.proc.fork()
if chpid == 0 then
lsr:release()
--lib.proc.daemonize(1,0)
lib.io.close(0) lib.io.close(1) lib.io.close(2)
lib.proc.exec([config.prefix_bin .. '/parsavd'], chargv)
lib.proc.execp([config.prefix_bin .. '/parsavd'], chargv)
lib.ipc.notify_parent(lib.ipc.signals.state_fail_find)
lib.bail('cannot find parsav program')
else
lib.report('starting parsav daemon')
while true do
var sig = lsr:block()
if sig.system then lib.dbg('got system signal') end
if sig.from == chpid then
if sig.system and sig.sig == lib.ipc.signals.sys_child then
................................................................................
else lib.warn('got unrecognized signal, ignoring')
end
end
end
lsr:release() -- just because i feel distinctly uncomfortable leaving it out
end
elseif lib.str.cmp(mode.arglist(0),'stop') == 0 then
var acks = emp:mallack()
emp:decree(0,nil, lib.ipc.cmd.stop, 0, &acks(0)) -- TODO targeting
for i=0,acks.ct do
if acks(i).success then
lib.io.fmt('instance %llu successfully stepped down\n', acks(i).clid)
else
lib.io.fmt('instance %llu reports failure to halt\n', acks(i).clid)
end
end
acks:free()
else
if lib.str.cmp(mode.arglist(0),'db') == 0 then
var dbmode: pbasic dbmode:parse(mode.arglist.ct, &mode.arglist(0))
if dbmode.help then
[ lib.emit(false, 1, 'usage: ', `argv[0], ' db ', dbmode.type.helptxt.flags, ' <cmd> [<args>…]', dbmode.type.helptxt.opts, cmdhelp {
{ 'db init <domain>', 'initialize backend databases (or a single specified database) with the necessary schema and structures for the given FQDN' };
{ 'db vacuum', 'delete old remote content from the database' };
|
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
|
>
>
>
>
|
>
>
>
>
>
>
|
>
|
|
>
|
|
|
|
|
<
<
|
>
>
>
>
>
>
>
>
>
|
|
>
|
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
local ctloptions = lib.cmdparse({
version = {'V', 'display information about the binary build and exit'};
verbose = {'v', 'increase logging verbosity', inc=1};
quiet = {'q', 'do not print to standard out'};
help = {'h', 'display this list'};
backend_file = {'B', 'init from specified backend file', consume=1};
backend = {'b', 'operate on only the selected backend'};
instance_id = {'i', 'specify the instance to control by name', consume=1};
instance_serial = {'I', 'specify the instance to control by serial', consume=1};
all = {'A', 'affect all running instances/backends'};
}, { subcmd = 1 })
local pbasic = lib.cmdparse {
help = {'h', 'display this list'}
}
local subcmds = {
}
local ctlcmds = {
{ 'start', 'start a new instance of the server' };
{ 'stop', 'stop a running instance' };
{ 'ls', 'list all running instances' };
{ 'attach', 'capture log output from a running instance' };
{ 'db', 'set up and manage the database' };
{ 'user', 'manage users, privileges, and credentials'};
{ 'mkroot <handle>', 'establish a new root user with the given handle' };
{ '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)' };
{ 'actor <xid> create', 'instantiate a new actor' };
{ 'actor <xid> bestow <epithet>', 'bestow an epithet upon an actor' };
................................................................................
v[2]
)
end
return str
end
local struct idelegate {
emperor: &lib.ipc.emperor
all: bool
src: &lib.store.source
srv: &lib.srv.overlord
sid: uint64
iname: rawstring
}
idelegate.metamethods.__methodmissing = macro(function(meth, self, ...)
local expr = {...}
local rt
for _,f in pairs(lib.store.backend.entries) do
local fn = f.field or f[1]
local ft = f.type or f[2]
................................................................................
if self.all
then r=self.srv:[meth]([expr])
elseif self.src ~= nil then r=self.src:[meth]([expr])
else lib.bail('no data source specified')
end
in r end
end)
terra idelegate:ipc_send(cmd: lib.ipc.cmd.t, operand: uint64)
var emp = self.emperor
var acks: lib.mem.ptr(lib.ipc.ack)
if self.sid == 0 and self.iname == nil then
if not self.all and emp:countpeers() > 1 then
lib.bail('either specify the instance to control or pass --all to control all instances')
end
acks = emp:mallack()
emp:decree(0,nil, cmd, operand, &acks(0)) -- TODO targeting
else
acks = lib.mem.heapa(lib.ipc.ack, 1)
if not emp:decree(self.sid, self.iname, cmd, operand, &acks(0)) then
acks:free()
end
end
return acks
end
local terra gensec(sdest: rawstring)
var dest = [&uint8](sdest)
lib.crypt.spray(dest,64)
for i=0,64 do dest[i] = dest[i] % (0x7e - 0x20) + 0x20 end
dest[64] = 0
end
................................................................................
else tmppw[i] = tmppw[i] + 0x30 end
end
lib.dbg('assigning temporary password')
dlg:auth_create_pw(uid, reset, pstr {
ptr = [rawstring](tmppw), ct = 32
})
end
local terra ipc_report(acks: lib.mem.ptr(lib.ipc.ack), rep: rawstring)
var decbuf: int8[21]
for i=0,acks.ct do
var num = lib.math.decstr(acks(i).clid, &decbuf[20])
if acks(i).success then
lib.report('instance #',num,' reports successful ',rep)
else
lib.report('instance #',num,' reports failed ',rep)
end
end
end
local emp = lib.ipc.global_emperor
local terra entry_mgtool(argc: int, argv: &rawstring): int
if argc < 1 then lib.bail('bad invocation!') end
lib.noise.init(2)
[lib.init]
var srv: lib.srv.overlord
var dlg = idelegate {
emperor = &emp, srv = &srv;
src = nil, sid = 0, iname = nil, all = false;
}
var mode: ctloptions
mode:parse(argc,argv) defer mode:free()
if mode.version then version() return 0 end
if mode.help then
[ lib.emit(false, 1, 'usage: ', `argv[0], ' ', ctloptions.helptxt.flags, ' <cmd> [<args>…]', ctloptions.helptxt.opts, cmdhelp(ctlcmds)) ]
return 0
................................................................................
var cnf: rawstring
if mode.backend_file ~= nil
then cnf = @mode.backend_file
else cnf = lib.proc.getenv('parsav_backend_file')
end
if cnf == nil then cnf = [config.prefix_conf .. "/backend.conf"] end
if mode.all then dlg.all = true else
-- iterate through and pick the right backend, if one is indicated
end
if mode.instance_id ~= nil and mode.instance_serial ~= nil then
lib.bail('conflicting flags passed')
end
if mode.instance_id ~= nil then
dlg.iname = @mode.instance_id
elseif mode.instance_serial ~= nil then
-- decode serial
end
if mode.arglist.ct == 0 then lib.bail('no command') return 1 end
if lib.str.cmp(mode.arglist(0),'start') ~= 0 then
-- hack to save us some pain around forking
emp = lib.ipc.emperor.mk(false)
end
defer emp:release()
if lib.str.cmp(mode.arglist(0),'attach') == 0 then
elseif lib.str.cmp(mode.arglist(0),'start') == 0 then
var smode: lib.cmdparse {
help = {'h', 'display this list'};
log = {'l', 'send server\'s logging output to a file', consume=1};
pid = {'p', 'report PID of launched process'};
instance_serial = {'s', 'report the instance serial of the launched process'};
keep_attached = {'k', 'don\'t detach from the calling terminal until a successful startup (or ever, if passed twice)', inc=1};
}
smode:parse(mode.arglist.ct,mode.arglist.ptr)
if smode.help then
[ lib.emit(false, 1, 'usage: ', `argv[0], ' start ', smode.type.helptxt.flags, ' [<instance args>…] [-- <instance flags>…]', smode.type.helptxt.opts) ]
return 1
end
var lsr = lib.ipc.listener.mk()
var chpid = lib.proc.fork()
if chpid == 0 then
lsr:release()
var chargv = lib.mem.heapa(rawstring, smode.arglist.ct + 2)
chargv(0) = '-'
for i = 1, chargv.ct - 1 do
chargv(i) = smode.arglist(i-1)
end
chargv(chargv.ct-1) = nil
if smode.keep_attached == 0 then
lib.io.close(0) lib.io.close(1) lib.io.close(2)
end
lib.proc.exec([config.prefix_bin .. '/parsavd'], chargv.ptr)
lib.proc.execp([config.prefix_bin .. '/parsavd'], chargv.ptr)
lib.ipc.notify_parent(lib.ipc.signals.state_fail_find)
lib.bail('cannot find parsav program')
-- chargv:free()
else
lib.report('starting parsav daemon')
while true do
var sig = lsr:block()
if sig.system then lib.dbg('got system signal') end
if sig.from == chpid then
if sig.system and sig.sig == lib.ipc.signals.sys_child then
................................................................................
else lib.warn('got unrecognized signal, ignoring')
end
end
end
lsr:release() -- just because i feel distinctly uncomfortable leaving it out
end
elseif lib.str.cmp(mode.arglist(0),'stop') == 0 then
if mode.arglist.ct ~= 1 then goto cmderr end
var acks = dlg:ipc_send(lib.ipc.cmd.stop, 0)
if acks:ref() then
ipc_report(acks, 'step-down')
acks:free()
end
elseif lib.str.cmp(mode.arglist(0),'ls') == 0 then
if mode.arglist.ct ~= 1 then goto cmderr end
if dlg.sid == 0 and dlg.iname == nil then dlg.all = true end
var acks = dlg:ipc_send(lib.ipc.cmd.enumerate, 0)
if acks:ref() then
for i=0,acks.ct do
var decbuf: int8[21]
var num = lib.math.decstr(acks(i).clid, &decbuf[20])
[ lib.emit(true,1, '\27[1m(', `num, ')\27[m ',`&acks(i).iname[0],' \27[1;32mactive\27[m') ]
end
acks:free()
else lib.bail('no active instances') end
else
if lib.str.cmp(mode.arglist(0),'db') == 0 then
var dbmode: pbasic dbmode:parse(mode.arglist.ct, &mode.arglist(0))
if dbmode.help then
[ lib.emit(false, 1, 'usage: ', `argv[0], ' db ', dbmode.type.helptxt.flags, ' <cmd> [<args>…]', dbmode.type.helptxt.opts, cmdhelp {
{ 'db init <domain>', 'initialize backend databases (or a single specified database) with the necessary schema and structures for the given FQDN' };
{ 'db vacuum', 'delete old remote content from the database' };
|