diff options
Diffstat (limited to 'appl/cmd/xmount.b')
| -rw-r--r-- | appl/cmd/xmount.b | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/appl/cmd/xmount.b b/appl/cmd/xmount.b new file mode 100644 index 00000000..6d86c939 --- /dev/null +++ b/appl/cmd/xmount.b @@ -0,0 +1,231 @@ +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, 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); +} |
