ref: 063c3f398e949895bb9795539e83a2e0be364376
dir: /appl/spree/join.b/
implement Join;
include "sys.m";
sys: Sys;
include "draw.m";
include "sh.m";
include "arg.m";
include "join.m";
usage()
{
sys->fprint(stderr(), "usage: joinsession [-d mntdir] [-j joinrequest] name\n");
raise "fail:usage";
}
CLIENTDIR: con "/dis/spree/clients";
init(ctxt: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
arg := load Arg Arg->PATH;
arg->init(argv);
mnt := "/n/remote";
joinmsg := "join";
while ((opt := arg->opt()) != 0) {
case opt {
'd' =>
if ((mnt = arg->arg()) == nil)
usage();
'j' =>
joinmsg = arg->arg();
* =>
usage();
}
}
argv = arg->argv();
if (len argv != 1)
usage();
arg = nil;
e := join(ctxt, mnt, hd argv, joinmsg);
if (e != nil) {
sys->fprint(stderr(), "startclient: %s\n", e);
raise "fail:error";
}
}
join(ctxt: ref Draw->Context, mnt: string, dir: string, joinmsg: string): string
{
if (sys == nil)
sys = load Sys Sys->PATH;
fd := sys->open(mnt + "/" + dir + "/ctl", Sys->ORDWR);
if (fd == nil)
return sys->sprint("cannot open %s: %r", mnt + "/" + dir + "/ctl");
if (joinmsg != nil)
if (sys->fprint(fd, "%s", joinmsg) == -1)
return sys->sprint("cannot join: %r");
buf := array[Sys->ATOMICIO] of byte;
while ((n := sys->read(fd, buf, len buf)) > 0) {
(nil, lines) := sys->tokenize(string buf[0:n], "\n");
for (; lines != nil; lines = tl lines) {
(nil, toks) := sys->tokenize(hd lines, " ");
if (len toks > 1 && hd toks == "clienttype") {
sync := chan of string;
spawn startclient(ctxt, hd tl toks :: mnt :: dir :: tl tl toks, fd, sync);
fd = nil;
return <-sync;
}
sys->fprint(stderr(), "startclient: unknown lobby message %s\n", hd lines);
}
}
return "premature EOF";
}
startclient(ctxt: ref Draw->Context, argv: list of string, fd: ref Sys->FD, sync: chan of string)
{
sys->pctl(Sys->FORKNS|Sys->FORKFD|Sys->NEWPGRP, nil);
sys->dup(fd.fd, 0);
fd = nil;
sys->pctl(Sys->NEWFD, 0 :: 1 :: 2 :: nil);
# XXX security: weed out slashes
path := CLIENTDIR + "/" + hd argv + ".dis";
mod := load Command path;
if (mod == nil) {
sync <-= sys->sprint("cannot load %s: %r\n", path);
return;
}
spawn clientmod(mod, ctxt, argv);
sync <-= nil;
}
clientmod(mod: Command, ctxt: ref Draw->Context, argv: list of string)
{
wfd := sys->open("/prog/" + string sys->pctl(0, nil) + "/wait", Sys->OREAD);
spawn mod->init(ctxt, argv);
buf := array[Sys->ATOMICIO] of byte;
n := sys->read(wfd, buf, len buf);
sys->print("client process (%s) exited: %s\n", concat(argv), string buf[0:n]);
}
concat(l: list of string): string
{
if (l == nil)
return nil;
s := hd l;
for (l = tl l; l != nil; l = tl l)
s += " " + hd l;
return s;
}
stderr(): ref Sys->FD
{
return sys->fildes(2);
}