ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/collab/connect.b/
implement Connect;
include "sys.m";
sys: Sys;
include "draw.m";
include "keyring.m";
include "security.m";
include "arg.m";
Connect: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
remotedir := "/n/remote";
# localdir := "/n/ftree/collab"; # deprecated?
localdir := "/n/remote/collab";
COLLABPORT: con "9999"; # TO DO: needs symbolic name in services
usage()
{
sys->fprint(sys->fildes(2), "Usage: connect [-v] [-C cryptoalg] [-k keyring] [net!addr [localdir]]\n");
raise "fail:usage";
}
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
vflag := 0;
alg := "none";
keyfile := "";
netaddr := "$collab";
arg := load Arg Arg->PATH;
if(arg != nil){
arg->init(args);
while((c := arg->opt()) != 0)
case c {
'C' =>
alg = arg->arg();
'k' =>
keyfile = arg->arg();
'v' =>
vflag++;
* =>
usage();
}
}
args = arg->argv();
arg = nil;
if(args != nil){
netaddr = hd args;
args = tl args;
if(args != nil)
localdir = hd args;
}
if(vflag)
sys->print("connect: dial %s\n", netaddr);
(fd, user) := authdial(netaddr, keyfile, alg);
if(vflag)
sys->print("remote username is %s\n", user);
if(sys->mount(fd, nil, remotedir, Sys->MREPL, nil) < 0)
error(sys->sprint("can't mount %s on %s: %r", netaddr, remotedir));
fd = nil;
connectdir := remotedir+"/collab";
if (sys->bind(connectdir, localdir, Sys->MCREATE|Sys->MREPL) < 0){
error(sys->sprint("cannot bind %s onto %s: %r\n", connectdir, localdir));
raise "fail:error";
}
# if something such as ftree is running and watching for changes, tell it about this one
fd = sys->open("/chan/nsupdate", Sys->OWRITE);
if(fd != nil)
sys->fprint(fd, "/n/ftree/collab");
if(vflag)
sys->print("collab connected\n");
}
authdial(addr, keyfile, alg: string): (ref Sys->FD, string)
{
cert : string;
kr := load Keyring Keyring->PATH;
if(kr == nil)
error(sys->sprint("cannot load %s: %r", Keyring->PATH));
kd := "/usr/" + user() + "/keyring/";
if (keyfile == nil) {
cert = kd + netmkaddr(addr, "tcp", "");
(ok, nil) := sys->stat(cert);
if (ok < 0)
cert = kd + "default";
}
else if (len keyfile > 0 && keyfile[0] != '/')
cert = kd + keyfile;
else
cert = keyfile;
ai := kr->readauthinfo(cert);
if (ai == nil)
error(sys->sprint("cannot read authentication data from %s: %r", cert));
au := load Auth Auth->PATH;
if(au == nil)
error(sys->sprint("cannot load %s: %r", Auth->PATH));
err := au->init();
if(err != nil)
error(sys->sprint("cannot init Auth: %s", err));
(ok, c) := sys->dial(netmkaddr(addr, "tcp", COLLABPORT), nil);
if(ok < 0)
error(sys->sprint("can't dial %s: %r", addr));
(fd, id_or_err) := au->client(alg, ai, c.dfd);
if(fd == nil)
error(sys->sprint("authentication failed: %s", id_or_err));
return (fd, id_or_err);
}
user(): string
{
fd := sys->open("/dev/user", sys->OREAD);
if(fd == nil)
return "";
buf := array[Sys->NAMEMAX] of byte;
n := sys->read(fd, buf, len buf);
if(n < 0)
return "";
return string buf[0:n];
}
netmkaddr(addr, net, svc: string): string
{
if(net == nil)
net = "net";
(n, l) := sys->tokenize(addr, "!");
if(n <= 1){
if(svc== nil)
return sys->sprint("%s!%s", net, addr);
return sys->sprint("%s!%s!%s", net, addr, svc);
}
if(svc == nil || n > 2)
return addr;
return sys->sprint("%s!%s", addr, svc);
}
error(m: string)
{
sys->fprint(sys->fildes(2), "connect: %s\n", m);
raise "fail:error";
}