ref: aee91c4ed0277e343a62cd124ee7175f54ffefb3
dir: /appl/cmd/ctlfs.b/
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); } } }