implement Mount; include "sys.m"; sys: Sys;include "draw.m";include "keyring.m";include "security.m";include "arg.m";include "sh.m";include "styxconv.m"; styxconv: Styxconv; Mount: module{ init: fn(nil: ref Draw->Context, nil: list of string);}; vflag := 0;doauth := 1; usage(){ sys->fprint(sys->fildes(2), "Usage: mount [-a|-b] [-cA] [-C cryptoalg] [-f keyfile] net!addr|file|{command} mountpoint [spec]\n"); raise "fail:usage";} fail(status, msg: string){ sys->fprint(sys->fildes(2), "mount: %s\n", msg); raise "fail:"+status;} nomod(mod: string){ fail("load", sys->sprint("can't load %s: %r", mod));} init(ctxt: ref Draw->Context, args: list of string){ sys = load Sys Sys->PATH; vflag = 0; unauth := 0; alg := "none"; keyfile: string; spec: string; arg := load Arg Arg->PATH; if(arg == nil) nomod(Arg->PATH); styxconv = load Styxconv Styxconv->PATH; if(styxconv == nil) nomod(Styxconv->PATH); arg->init(args); styxconv->init(); flags := 0; while((o := arg->opt()) != 0) case o { 'a' => flags |= Sys->MAFTER; 'b' => flags |= Sys->MBEFORE; 'c' => flags |= Sys->MCREATE; 'C' => alg = arg->arg(); if(alg == nil) usage(); 'f' => keyfile = arg->arg(); if(keyfile == nil) usage(); 'A' => doauth = 0; 'v' => vflag = 1; 'u' => unauth = 1; # temporary, undocumented option for testing * => usage(); } args = arg->argv(); arg = nil; if(len args != 2){ if(len args != 3) usage(); spec = hd tl tl args; } addr := hd args; mountpoint := hd tl args; # open stream fd := do_connect(ctxt, addr); # authenticate if necessary if (doauth) fd = do_auth(keyfile, alg, fd, addr, unauth); p := array[2] of ref Sys->FD; if(sys->pipe(p) < 0) fail("can't create pipe", sys->sprint("can't create pipe: %r")); pidch := chan of int; spawn styxconv->styxconv(p[1], fd, pidch); p[1] = nil; <- pidch; ok := sys->mount(p[0], nil, mountpoint, flags, spec); p[0] = nil; if(ok < 0) fail("mount failed", sys->sprint("mount failed: %r")); } # either make network connection or open filedo_connect(ctxt: ref Draw->Context, dest: string): ref Sys->FD{ if(dest != nil && dest[0] == '{' && dest[len dest - 1] == '}'){ doauth = 0; return popen(ctxt, dest :: nil); } (n, nil) := sys->tokenize(dest, "!"); if(n == 1){ fd := sys->open(dest, Sys->ORDWR); if(fd != nil) return fd; if(dest[0] == '/') fail("open failed", sys->sprint("can't open %s: %r", dest)); } (ok, c) := sys->dial(netmkaddr(dest, "net", "styx"), nil); if(ok < 0) fail("dial failed", sys->sprint("can't dial %s: %r", dest)); return c.dfd;} popen(ctxt: ref Draw->Context, argv: list of string): ref Sys->FD{ sh := load Sh Sh->PATH; if(sh == nil) nomod(Sh->PATH); sync := chan of int; fds := array[2] of ref Sys->FD; sys->pipe(fds); spawn runcmd(sh, ctxt, argv, fds[0], sync); <-sync; return fds[1];} runcmd(sh: Sh, ctxt: ref Draw->Context, argv: list of string, stdin: ref Sys->FD, sync: chan of int){ sys->pctl(Sys->FORKFD, nil); sys->dup(stdin.fd, 0); stdin = nil; sync <-= 0; sh->run(ctxt, argv);} # authenticate if necessarydo_auth(keyfile, alg: string, dfd: ref Sys->FD, addr: string, unauth: int): ref Sys->FD{ cert : string; kr := load Keyring Keyring->PATH; if(kr == nil) nomod(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){ if(!unauth) fail("readauthinfo failed", sys->sprint("cannot read %s: %r", cert)); sys->fprint(sys->fildes(2), "mount: can't read %s (%r): trying mount as `nobody'\n", cert); } au := load Auth Auth->PATH; if(au == nil) nomod(Auth->PATH); err := au->init(); if(err != nil) fail("auth init failed", sys->sprint("cannot init Auth: %s", err)); fd: ref Sys->FD; (fd, err) = au->client(alg, ai, dfd); if(fd == nil) fail("auth failed", sys->sprint("authentication failed: %s", err)); if(vflag) sys->print("remote username is %s\n", err); return fd;} 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, nil) := 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);}
implement Mount;
include "sys.m";
sys: Sys;
include "draw.m";
include "keyring.m";
include "security.m";
include "arg.m";
include "sh.m";
include "styxconv.m";
styxconv: Styxconv;
Mount: module
{
init: fn(nil: ref Draw->Context, nil: list of string);
};
vflag := 0;
doauth := 1;
usage()
{
sys->fprint(sys->fildes(2), "Usage: mount [-a|-b] [-cA] [-C cryptoalg] [-f keyfile] net!addr|file|{command} mountpoint [spec]\n");
raise "fail:usage";
}
fail(status, msg: string)
{
sys->fprint(sys->fildes(2), "mount: %s\n", msg);
raise "fail:"+status;
}
nomod(mod: string)
{
fail("load", sys->sprint("can't load %s: %r", mod));
}
init(ctxt: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
vflag = 0;
unauth := 0;
alg := "none";
keyfile: string;
spec: string;
arg := load Arg Arg->PATH;
if(arg == nil)
nomod(Arg->PATH);
styxconv = load Styxconv Styxconv->PATH;
if(styxconv == nil)
nomod(Styxconv->PATH);
arg->init(args);
styxconv->init();
flags := 0;
while((o := arg->opt()) != 0)
case o {
'a' =>
flags |= Sys->MAFTER;
'b' =>
flags |= Sys->MBEFORE;
'c' =>
flags |= Sys->MCREATE;
'C' =>
alg = arg->arg();
if(alg == nil)
usage();
'f' =>
keyfile = arg->arg();
if(keyfile == nil)
usage();
'A' =>
doauth = 0;
'v' =>
vflag = 1;
'u' =>
unauth = 1; # temporary, undocumented option for testing
* =>
usage();
}
args = arg->argv();
arg = nil;
if(len args != 2){
if(len args != 3)
usage();
spec = hd tl tl args;
}
addr := hd args;
mountpoint := hd tl args;
# open stream
fd := do_connect(ctxt, addr);
# authenticate if necessary
if (doauth)
fd = do_auth(keyfile, alg, fd, addr, unauth);
p := array[2] of ref Sys->FD;
if(sys->pipe(p) < 0)
fail("can't create pipe", sys->sprint("can't create pipe: %r"));
pidch := chan of int;
spawn styxconv->styxconv(p[1], fd, pidch);
p[1] = nil;
<- pidch;
ok := sys->mount(p[0], nil, mountpoint, flags, spec);
p[0] = nil;
if(ok < 0)
fail("mount failed", sys->sprint("mount failed: %r"));
}
# either make network connection or open file
do_connect(ctxt: ref Draw->Context, dest: string): ref Sys->FD
{
if(dest != nil && dest[0] == '{' && dest[len dest - 1] == '}'){
doauth = 0;
return popen(ctxt, dest :: nil);
}
(n, nil) := sys->tokenize(dest, "!");
if(n == 1){
fd := sys->open(dest, Sys->ORDWR);
if(fd != nil)
return fd;
if(dest[0] == '/')
fail("open failed", sys->sprint("can't open %s: %r", dest));
}
(ok, c) := sys->dial(netmkaddr(dest, "net", "styx"), nil);
if(ok < 0)
fail("dial failed", sys->sprint("can't dial %s: %r", dest));
return c.dfd;
}
popen(ctxt: ref Draw->Context, argv: list of string): ref Sys->FD
{
sh := load Sh Sh->PATH;
if(sh == nil)
nomod(Sh->PATH);
sync := chan of int;
fds := array[2] of ref Sys->FD;
sys->pipe(fds);
spawn runcmd(sh, ctxt, argv, fds[0], sync);
<-sync;
return fds[1];
}
runcmd(sh: Sh, ctxt: ref Draw->Context, argv: list of string, stdin: ref Sys->FD,
sync: chan of int)
{
sys->pctl(Sys->FORKFD, nil);
sys->dup(stdin.fd, 0);
stdin = nil;
sync <-= 0;
sh->run(ctxt, argv);
}
# authenticate if necessary
do_auth(keyfile, alg: string, dfd: ref Sys->FD, addr: string, unauth: int): ref Sys->FD
{
cert : string;
kr := load Keyring Keyring->PATH;
if(kr == nil)
nomod(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){
if(!unauth)
fail("readauthinfo failed", sys->sprint("cannot read %s: %r", cert));
sys->fprint(sys->fildes(2), "mount: can't read %s (%r): trying mount as `nobody'\n", cert);
}
au := load Auth Auth->PATH;
if(au == nil)
nomod(Auth->PATH);
err := au->init();
if(err != nil)
fail("auth init failed", sys->sprint("cannot init Auth: %s", err));
fd: ref Sys->FD;
(fd, err) = au->client(alg, ai, dfd);
if(fd == nil)
fail("auth failed", sys->sprint("authentication failed: %s", err));
if(vflag)
sys->print("remote username is %s\n", err);
return fd;
}
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, nil) := 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);
}