223 lines
4.6 KiB
Brainfuck
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);
|
|
}
|
|
}
|
|
}
|