dddb/appl/cmd/ctlfs.b

223 lines
4.6 KiB
Brainfuck

include "dial.m";
dial: Dial;
include "security.m";
auth: Auth;
include "styx.m";
styx: Styx;
Tmsg, Rmsg: import Styx;
include "styxservers.m";
styxservers: Styxservers;
Styxserver, Fid, Navigator,
Navop, Enotfound, Enotdir: import styxservers;
# FS file index
Qroot, Qctl, Qstats, Qmax: con iota;
tab := array[] of {
(Qroot, ".", Sys->DMDIR|8r555),
(Qctl, "ctl", 8r222),
(Qstats, "stats", 8r111),
};
# create ctlfs and the appropriate listeners
init_ctlfs(cfg: Config, keyfile: string, algs: list of string)
{
dial = load Dial Dial->PATH;
auth = load Auth Auth->PATH;
styx = load Styx Styx->PATH;
if(dial == nil)
error("ctlfs: dial module not found");
if(auth == nil)
error("ctlfs: auth module not found");
if(styx == nil)
error("ctlfs: styx module not found");
auth->init();
styx->init();
styxservers->init(styx);
styxservers->traceset(chatty);
# authinfo init
if(debug)
sys->fprint(stderr, "ctlfs: reading authinfo");
authinfo: ref Keyring->Authinfo;
if (doauth) {
if (keyfile == nil)
keyfile = "/usr/" + user() + "/keyring/default";
authinfo = keyring->readauthinfo(keyfile);
if (authinfo == nil)
error(sys->sprint("ctlfs: cannot read %s: %r", keyfile));
}
# announcing
if(debug)
sys->fprint(stderr, "ctlfs: announcing dddbctl");
addr := dial->netmkaddr(cfg.addr, "tcp", "dddbctl");
c := dial->announce(addr);
if(c == nil)
error(sys->sprint("ctlfs: cannot listen on %s\n", addr));
# bootstrapping
if(debug)
sys->fprint
sys->unmount(nil, "/mnt/keys");
navch := chan of ref Navop;
spawn ctlfs_navigator(navch);
nav := Navigator.new(navch);
(tc, srv) := Styxserver.new(fildes(0), nav, big Qroot);
# listener entrypoint
listener(c, authinfo, algs);
}
# dddbctl listener loop
ctlfs_listener(c: ref Dial->Connection, authinfo: ref Keyring->Authinfo, algs: list of string)
{
for (;;) {
nc := dial->listen(c);
if (nc == nil)
error(sys->sprint("listen failed: %r"));
if (debug)
sys->fprint(stderr, "ctlfs: got connection from %s\n",
readfile(nc.dir + "/remote"));
dfd := dial->accept(nc);
if (dfd != nil) {
if(nc.cfd != nil)
sys->fprint(nc.cfd, "keepalive");
hostname: string;
if(passhostnames){
hostname = readfile(nc.dir + "/remote");
if(hostname != nil)
hostname = hostname[0:len hostname - 1];
}
spawn ctlfs_authenticator(dfd, authinfo, algs, hostname);
}
}
}
# authenticate a connection and set the user id.
ctlfs_authenticator(dfd: ref Sys->FD, authinfo: ref Keyring->Authinfo,
algs: list of string, hostname: string)
{
# authenticate and change user id appropriately
(fd, err) := auth->server(algs, authinfo, dfd, 1);
if (fd == nil) {
if (debug)
sys->fprint(stderr(), "ctlfs: authentication failed: %s\n", err);
return;
}
if (debug)
sys->fprint(stderr(), "ctlfs: client authenticated as %s\n", err);
spawn exportproc(sync, mfd, err, hostname, fd);
}
ctlfs_loop()
{
# Primary server loop
loop:
while((tmsg := <-tc) != nil) {
# Switch on operations being performed on a given Fid
pick msg := tmsg {
Open =>
srv.default(msg);
Read =>
fid := srv.getfid(msg.fid);
if(fid.qtype & Sys->QTDIR) {
# This is a directory read
srv.default(msg);
continue loop;
}
case int fid.path {
Qlog =>
# A read on our log file, tell them what they've already said ?
s := "";
for(l := log; l != nil; l = tl l)
s = hd l + s;
srv.reply(styxservers->readstr(msg, s));
* =>
srv.default(msg);
}
Write =>
fid := srv.getfid(msg.fid);
case int fid.path {
Qctl =>
# Don't care about offset
cmd := string msg.data;
reply: ref Rmsg = ref Rmsg.Write(msg.tag, len msg.data);
case cmd {
* =>
# Ignore empty writes
if(cmd != nil)
log = cmd :: log;
else
reply = ref Rmsg.Error(msg.tag, "empty write!");
}
srv.reply(reply);
* =>
srv.default(msg);
}
* =>
srv.default(msg);
}
}
exit;
}
# Navigator function for moving around under /
ctlfs_navigator(c: chan of ref Navop) {
loop:
for(;;) {
navop := <-c;
pick op := navop {
Stat =>
op.reply <-= (dir(int op.path), nil);
Walk =>
if(op.name == "..") {
op.reply <-= (dir(Qroot), nil);
continue loop;
}
case int op.path&16rff {
Qroot =>
for(i := 1; i < Qmax; i++)
if(tab[i].t1 == op.name) {
op.reply <-= (dir(i), nil);
continue loop;
}
op.reply <-= (nil, Enotfound);
* =>
op.reply <-= (nil, Enotdir);
}
Readdir =>
for(i := 0; i < op.count && i + op.offset < (len tab) - 1; i++)
op.reply <-= (dir(Qroot+1+i+op.offset), nil);
op.reply <-= (nil, nil);
}
}
}