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);}
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);
}