summaryrefslogtreecommitdiff
path: root/appl/spree/joinsession.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/spree/joinsession.b')
-rw-r--r--appl/spree/joinsession.b115
1 files changed, 115 insertions, 0 deletions
diff --git a/appl/spree/joinsession.b b/appl/spree/joinsession.b
new file mode 100644
index 00000000..b953c317
--- /dev/null
+++ b/appl/spree/joinsession.b
@@ -0,0 +1,115 @@
+implement Joinsession;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "arg.m";
+include "joinsession.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);
+}