implement Newwin;
# serve /n/rwin/new, allowing new shell windows to be created
# by remote agents. assumes mntgen on /n.
# write kind of window to be created into /n/rwin/new (sh or rio); read name of directory
# containing cons/consctl, etc
include "sys.m";
sys: Sys;
include "draw.m";
include "sh.m";
sh: Sh;
Newwin: module {
init: fn(nil: ref Draw->Context, nil: list of string);
};
init(ctxt: ref Draw->Context, nil: list of string)
{
sys = load Sys Sys->PATH;
sh = load Sh Sh->PATH;
sys->pipe(p := array[2] of ref Sys->FD);
spawn srv(ctxt, p[0], sync := chan of int);
p[0] = nil;
<-sync;
if(sys->mount(p[1], nil, "/n/rwin", Sys->MREPL, nil) == -1)
raise "fail:cannot mount";
}
srv(ctxt: ref Draw->Context, fd: ref Sys->FD, sync: chan of int)
{
sys->pctl(Sys->FORKNS | Sys->FORKFD, nil);
sync <-= 0;
spawn export(fd, "/n/rwin");
sys->bind("#s", "/n/rwin", Sys->MBEFORE);
sh->run(nil, "mount" :: "-a" :: "{mntgen}" :: "/n/rwin" :: nil);
fio := sys->file2chan("/n/rwin", "new");
if(fio == nil){
sys->print("cannot make /chan/newwin: %r");
return;
}
spawn srv0(ctxt, fio);
}
export(fd: ref Sys->FD, d: string)
{
sys->export(fd, d, Sys->EXPWAIT);
}
srv0(ctxt: ref Draw->Context, fio: ref Sys->FileIO)
{
pending: list of (int, array of byte);
loop:
for(;;)alt{
(nil, data, fid, wc) := <-fio.write =>
if(wc == nil)
break;
if(len data > 0 && data[len data - 1] == byte '\n')
data = data[0:len data - 1];
for(p := pending; p != nil; p = tl p)
if((hd p).t0 == fid){
wc <-= (-1, "request already pending");
continue loop;
}
(d, e) := newwin(ctxt, string data);
if(d == nil)
wc <-= (-1, sys->sprint("cannot start shell: %s", e));
else{
pending = (fid, array of byte d) :: pending;
wc <-= (len data, nil);
}
(offset, nb, fid, rc) := <-fio.read =>
p: list of (int, array of byte);
if(rc == nil){
for(; pending != nil; pending = tl pending)
if((hd pending).t0 != fid)
p = hd pending :: p;
pending = p;
break;
}
d: array of byte;
for(; pending != nil; pending = tl pending){
if((hd pending).t0 == fid)
d = (hd pending).t1;
else
p = hd pending :: p;
}
if(offset >= len d)
rc <-= (nil, nil);
else{
rc <-= (d, nil);
if(offset + nb < len d)
pending = (fid, d) :: pending;
}
}
}
n := 0;
newwin(ctxt: ref Draw->Context, kind: string): (string, string)
{
d := sys->sprint("%d", n++);
case kind {
"sh" =>
e := sh->run(ctxt, "/dis/wm/remotesh" :: "-s" :: "/n/rwin/"+d :: nil);
if(e != nil)
return (nil, e);
"rio" =>
e := sh->run(ctxt, "9win" :: "-s" :: "/n/rwin/"+d :: nil);
if(e != nil)
return (nil, e);
sys->bind("/dev", "/n/rwin/"+d, Sys->MAFTER);
* =>
return (nil, "known kind of window");
}
return (d, nil);
}
|