summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorforsyth <forsyth@vitanuova.com>2009-12-04 20:41:24 +0000
committerforsyth <forsyth@vitanuova.com>2009-12-04 20:41:24 +0000
commit54041ca415f1fdfa1c3dcd82d524223cfa890940 (patch)
tree61b7d29f9df1ade1b3cb5ad859f53fecead5e356
parent1d6f6b43a0f31b37b3302fc0d627c904c381f3d1 (diff)
20091204
-rw-r--r--CHANGES6
-rw-r--r--appl/charon/build.b2
-rw-r--r--appl/charon/chutils.b13
-rw-r--r--appl/charon/chutils.m1
-rw-r--r--appl/charon/date.b2
-rw-r--r--appl/charon/gui.b6
-rw-r--r--appl/charon/img.b6
-rw-r--r--appl/charon/jscript.b2
-rw-r--r--appl/charon/layout.b14
-rw-r--r--appl/cmd/mount.b8
-rw-r--r--appl/lib/styxconv/mkfile6
-rw-r--r--appl/lib/styxconv/new2old.b640
-rw-r--r--appl/lib/styxconv/nsys.m51
-rw-r--r--appl/lib/styxconv/old2new.b480
-rw-r--r--appl/lib/styxconv/ostyx.b87
-rw-r--r--appl/lib/styxconv/ostyx.m4
-rw-r--r--dis/charon.disbin27991 -> 27980 bytes
-rw-r--r--dis/charon/build.disbin38663 -> 38649 bytes
-rw-r--r--dis/charon/chutils.disbin29634 -> 29555 bytes
-rw-r--r--dis/charon/date.disbin674 -> 658 bytes
-rw-r--r--dis/charon/file.disbin1344 -> 1344 bytes
-rw-r--r--dis/charon/ftp.disbin3907 -> 3907 bytes
-rw-r--r--dis/charon/gui.disbin9827 -> 9766 bytes
-rw-r--r--dis/charon/http.disbin12056 -> 12056 bytes
-rw-r--r--dis/charon/img.disbin62156 -> 62112 bytes
-rw-r--r--dis/charon/jscript.disbin50995 -> 50983 bytes
-rw-r--r--dis/charon/layout.disbin67654 -> 67536 bytes
-rw-r--r--dis/charon/lex.disbin13338 -> 13338 bytes
-rw-r--r--dis/lib/styxconv/new2old.disbin0 -> 7646 bytes
-rw-r--r--dis/lib/styxconv/old2new.disbin0 -> 5698 bytes
-rw-r--r--dis/lib/styxconv/ostyx.disbin13434 -> 13741 bytes
-rw-r--r--dis/mount.disbin5776 -> 5767 bytes
-rw-r--r--include/version.h2
-rw-r--r--man/2/styxconv56
-rw-r--r--module/styxconv.m7
-rw-r--r--os/pc/fns.h4
-rw-r--r--os/pc/mmu.c6
37 files changed, 1310 insertions, 93 deletions
diff --git a/CHANGES b/CHANGES
index 231e7c8a..15960391 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,9 @@
+20091127
+ problems fixed in styxconv(2), which can now convert both ways [rog]
+20091119
+ emu/port/devfs-posix.c missing waserror in dirread (obscure but possible failure)
+20091007
+ remove intermediate exception-raising function from charon implementation
20091004
restore "keyring" to lib section of emu/Plan9/emu
20090930
diff --git a/appl/charon/build.b b/appl/charon/build.b
index c9b4ab01..b0eef1de 100644
--- a/appl/charon/build.b
+++ b/appl/charon/build.b
@@ -1620,7 +1620,7 @@ lexstring(s: string) : array of ref Token
lastps(psl: list of ref Pstate) : ref Pstate
{
if(psl == nil)
- CU->raisex("EXInternal: empty pstate stack");
+ raise "EXInternal: empty pstate stack";
while(tl psl != nil)
psl = tl psl;
return hd psl;
diff --git a/appl/charon/chutils.b b/appl/charon/chutils.b
index 40da2f5f..8d8bdf33 100644
--- a/appl/charon/chutils.b
+++ b/appl/charon/chutils.b
@@ -1227,14 +1227,14 @@ ResourceState.cur() : ResourceState
if(mfd == nil)
mfd = sys->open("/dev/memory", sys->OREAD);
if (mfd == nil)
- raisex(sys->sprint("can't open /dev/memory: %r"));
+ raise sys->sprint("can't open /dev/memory: %r");
sys->seek(mfd, big 0, Sys->SEEKSTART);
buf := array[400] of byte;
n := sys->read(mfd, buf, len buf);
if (n <= 0)
- raisex(sys->sprint("can't read /dev/memory: %r"));
+ raise sys->sprint("can't read /dev/memory: %r");
(nil, l) := sys->tokenize(string buf[0:n], "\n");
# p->cursize, p->maxsize, p->hw, p->nalloc, p->nfree, p->nbrk, poolmax(p), p->name)
@@ -1763,7 +1763,7 @@ makestrinttab(a: array of string) : array of T->StringInt
ans[i].key = a[i];
ans[i].val = i;
if(i > 0 && a[i] < a[i-1])
- raisex("EXInternal: table out of alphabetical order");
+ raise "EXInternal: table out of alphabetical order";
}
return ans;
}
@@ -1866,15 +1866,10 @@ min(a,b: int) : int
return b;
}
-raisex(e: string)
-{
- raise e;
-}
-
assert(i: int)
{
if(!i) {
- raisex("EXInternal: assertion failed");
+ raise "EXInternal: assertion failed";
# sys->print("assertion failed\n");
# s := hmeth[-1];
}
diff --git a/appl/charon/chutils.m b/appl/charon/chutils.m
index 8d7d3a8c..15c3308f 100644
--- a/appl/charon/chutils.m
+++ b/appl/charon/chutils.m
@@ -360,7 +360,6 @@ CharonUtils: module
color: fn(s: string, dflt: int) : int;
max: fn(a, b : int) : int;
min: fn(a, b : int) : int;
- raisex: fn(e: string);
assert: fn(i: int);
stripscript: fn(s: string) : string; # strip HTML comments from Script
getconv: fn(chset : string) : Btos;
diff --git a/appl/charon/date.b b/appl/charon/date.b
index b247d578..c801772e 100644
--- a/appl/charon/date.b
+++ b/appl/charon/date.b
@@ -23,7 +23,7 @@ init(cu: CharonUtils)
CU = cu;
daytime = load Daytime Daytime->PATH;
if (daytime==nil)
- CU->raisex(sys->sprint("EXInternal: can't load Daytime: %r"));
+ raise sys->sprint("EXInternal: can't load Daytime: %r");
}
# print dates in the format
diff --git a/appl/charon/gui.b b/appl/charon/gui.b
index d433bf82..0b4b7f1c 100644
--- a/appl/charon/gui.b
+++ b/appl/charon/gui.b
@@ -98,7 +98,7 @@ init(ctxt: ref Draw->Context, cu: CharonUtils): ref Draw->Context
tk = load Tk Tk->PATH;
tkclient = load Tkclient Tkclient->PATH;
if(tkclient == nil)
- CU->raisex(sys->sprint("EXInternal: can't load module Tkclient: %r"));
+ raise sys->sprint("EXInternal: can't load module Tkclient: %r");
tkclient->init();
wmctl: chan of string;
@@ -386,11 +386,11 @@ makewins()
realwin = screen.newwindow(r, D->Refnone, D->White);
realwin.origin(ZP, r.min);
if(realwin == nil)
- CU->raisex(sys->sprint("EXFatal: can't initialize windows: %r"));
+ raise sys->sprint("EXFatal: can't initialize windows: %r");
mainwin = display.newimage(realwin.r, realwin.chans, 0, D->White);
if(mainwin == nil)
- CU->raisex(sys->sprint("EXFatal: can't initialize windows: %r"));
+ raise sys->sprint("EXFatal: can't initialize windows: %r");
}
hidewins()
diff --git a/appl/charon/img.b b/appl/charon/img.b
index fd8b625d..299ddeeb 100644
--- a/appl/charon/img.b
+++ b/appl/charon/img.b
@@ -161,7 +161,7 @@ imgerror(is: ref ImageSource, msg: string)
is.err = msg;
if(dbg)
sys->print("Image error: %s\n", msg);
- CU->raisex("exImageerror:");
+ raise "exImageerror:";
}
# Get next char or raise exception if cannot
@@ -179,7 +179,7 @@ getc(is: ref ImageSource) : int
ungetc(is: ref ImageSource)
{
if(is.i == 0)
- CU->raisex("EXInternal: ungetc past beginning of buffer");
+ raise "EXInternal: ungetc past beginning of buffer";
is.i--;
}
@@ -190,7 +190,7 @@ ungetc2(is: ref ImageSource, nil: byte)
{
if(is.i < 2) {
if(is.i != 1)
- CU->raisex("EXInternal: ungetc2 past beginning of buffer");
+ raise "EXInternal: ungetc2 past beginning of buffer";
is.i = 0;
}
else
diff --git a/appl/charon/jscript.b b/appl/charon/jscript.b
index 0742da31..315baf78 100644
--- a/appl/charon/jscript.b
+++ b/appl/charon/jscript.b
@@ -2107,7 +2107,7 @@ specindex(class: string) : int
if(objspecs[i].name == class)
break;
if(i == len objspecs)
- CU->raisex("EXInternal: couldn't find host object class " + class);
+ raise "EXInternal: couldn't find host object class " + class;
return i;
}
diff --git a/appl/charon/layout.b b/appl/charon/layout.b
index ee5c9064..a4ad1c8f 100644
--- a/appl/charon/layout.b
+++ b/appl/charon/layout.b
@@ -516,7 +516,7 @@ createvscroll(f: ref Frame)
f.vscr.r = f.vscr.r.addpt(Point(f.cr.max.x-breadth, f.cr.min.y));
f.cr.max.x -= breadth;
if(f.cr.dx() <= 2*f.marginw)
- CU->raisex("EXInternal: frame too small for layout");
+ raise "EXInternal: frame too small for layout";
f.vscr.draw(1);
}
@@ -531,7 +531,7 @@ createhscroll(f: ref Frame)
f.hscr.r = f.hscr.r.addpt(Point(x,f.cr.max.y-breadth));
f.cr.max.y -= breadth;
if(f.cr.dy() <= 2*f.marginh)
- CU->raisex("EXInternal: frame too small for layout");
+ raise "EXInternal: frame too small for layout";
f.hscr.draw(1);
}
@@ -985,7 +985,7 @@ fixlinegeom(f: ref Frame, lay: ref Lay, l: ref Line)
# line is complete, next line will start with it (or it is nil)
rest := it;
if(lastit == nil)
- CU->raisex("EXInternal: no items on line");
+ raise "EXInternal: no items on line";
lastit.next = nil;
l.width = w;
@@ -1087,7 +1087,7 @@ getfont(num: int) : ref Font
f = Font.open(display, fonts[num].name);
if(f == nil) {
if(num == DefFnt)
- CU->raisex(sys->sprint("exLayout: can't open default font %s: %r", fonts[num].name));
+ raise sys->sprint("exLayout: can't open default font %s: %r", fonts[num].name);
else {
if(int (CU->config).dbg['w'])
sys->print("warning: substituting default for font %s\n",
@@ -2389,7 +2389,7 @@ markchanges(loc: ref Loc)
}
LEtablecell =>
if(lastf == nil)
- CU->raisex("EXInternal: markchanges no lastf");
+ raise "EXInternal: markchanges no lastf";
c := loc.le[i].tcell;
clay := lastf.sublays[c.layid];
if(clay != nil)
@@ -2424,7 +2424,7 @@ colorimage(rgb: int) : ref Image
# im := display.color(pix);
im := display.rgb((rgb>>16)&255, (rgb>>8)&255, rgb&255);
if(im == nil)
- CU->raisex(sys->sprint("exLayout: can't allocate color #%8.8ux: %r", rgb));
+ raise sys->sprint("exLayout: can't allocate color #%8.8ux: %r", rgb);
x = ref Colornode(rgb, im, xhd);
colorhashtab[hv] = x;
}
@@ -3309,7 +3309,7 @@ Control.scrollset(c: self ref Control, v1, v2, vmax, nsteps, draw: int)
if(l <= 0)
l = 1;
if(l < 0)
- CU->raisex("EXInternal: negative scrollbar trough");
+ raise "EXInternal: negative scrollbar trough";
sc.top = l*v1/vmax;
sc.bot = l*(vmax-v2)/vmax;
if (nsteps == 0)
diff --git a/appl/cmd/mount.b b/appl/cmd/mount.b
index 9eb6e3a9..514db41a 100644
--- a/appl/cmd/mount.b
+++ b/appl/cmd/mount.b
@@ -215,17 +215,15 @@ runcmd(sh: Sh, ctxt: ref Draw->Context, argv: list of string, stdin: ref Sys->FD
cvstyx(fd: ref Sys->FD): (ref Sys->FD, string)
{
- styxconv := load Styxconv Styxconv->PATH;
+ styxconv := load Styxconv Styxconv->PATHNEW2OLD;
if(styxconv == nil)
- return (nil, sys->sprint("cannot load %s: %r", Styxconv->PATH));
+ return (nil, sys->sprint("cannot load %s: %r", Styxconv->PATHNEW2OLD));
styxconv->init();
p := array[2] of ref Sys->FD;
if(sys->pipe(p) < 0)
return (nil, sys->sprint("can't create pipe: %r"));
- pidc := chan of int;
- spawn styxconv->styxconv(p[1], fd, pidc);
+ spawn styxconv->styxconv(p[1], fd);
p[1] = nil;
- <-pidc;
return (p[0], nil);
}
diff --git a/appl/lib/styxconv/mkfile b/appl/lib/styxconv/mkfile
index fe4ad61e..02b28bc0 100644
--- a/appl/lib/styxconv/mkfile
+++ b/appl/lib/styxconv/mkfile
@@ -2,11 +2,13 @@
TARG=\
ostyx.dis\
- styxconv.dis\
-
+ new2old.dis\
+ old2new.dis\
+
MODULES=\
ostyx.m\
osys.m\
+ nsys.m\
SYSMODULES=\
bufio.m\
diff --git a/appl/lib/styxconv/new2old.b b/appl/lib/styxconv/new2old.b
new file mode 100644
index 00000000..36c1e91b
--- /dev/null
+++ b/appl/lib/styxconv/new2old.b
@@ -0,0 +1,640 @@
+implement Styxconv;
+
+include "sys.m";
+ sys: Sys;
+include "osys.m";
+include "nsys.m";
+include "draw.m";
+include "styx.m";
+ nstyx: Styx;
+ Tmsg, Rmsg: import nstyx;
+include "ostyx.m";
+ ostyx: OStyx;
+ OTmsg, ORmsg: import ostyx;
+include "styxconv.m";
+
+# todo: map fids > ffff into 16 bits
+
+DEBUG: con 1;
+
+Fid: adt
+{
+ fid: int;
+ isdir: int;
+ n: int; # size of last new client dirread request.
+ soff: int; # dir offset on old server.
+ coff: int; # dir offset on new client.
+ next: cyclic ref Fid;
+};
+
+Req: adt {
+ tag: int;
+ oldtag: int; # if it's a flush.
+ rp: ref Reqproc;
+ next: cyclic ref Req;
+ flushes: list of ref Rmsg.Flush; # flushes awaiting req finish.
+};
+
+Reqproc: adt {
+ newtmsg: chan of ref Tmsg; # convproc -> reqproc, once per req.
+ newrmsg: chan of ref Rmsg; # reqproc -> convproc, once per req
+
+ oldtmsg: chan of ref OTmsg; # reqproc -> convproc
+ oldrmsg: chan of ref ORmsg; # convproc -> reqproc
+
+ flushable: int;
+
+ new: fn(): ref Reqproc;
+ rpc: fn(rp: self ref Reqproc, otm: ref OTmsg): ref ORmsg;
+};
+
+tags: ref Req;
+avail: chan of ref Reqproc;
+fids: ref Fid;
+nprocs := 0;
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ if(sys == nil)
+ nomod("Sys", Sys->PATH);
+ nstyx = load Styx Styx->PATH;
+ if(nstyx == nil)
+ nomod("Styx", Styx->PATH);
+ ostyx = load OStyx OStyx->PATH;
+ if(ostyx == nil)
+ nomod("OStyx", OStyx->PATH);
+
+ ostyx->init();
+ nstyx->init();
+ avail = chan of ref Reqproc;
+}
+
+styxconv(newclient: ref Sys->FD, oldsrv: ref Sys->FD)
+{
+ newtmsg := chan of ref Tmsg;
+ oldrmsg := chan of ref ORmsg;
+
+ killpids := chan[2] of int;
+ spawn readnewtmsgs(killpids, newclient, newtmsg);
+ spawn readoldrmsgs(killpids, oldsrv, oldrmsg);
+
+converting:
+ for(;;)alt{
+ ntm := <-newtmsg =>
+ if(DEBUG)
+ sys->fprint(sys->fildes(2), "-> %s\n", ntm.text());
+ if(ntm == nil)
+ break converting;
+ ns2os(ntm, newclient, oldsrv);
+ orm := <-oldrmsg =>
+ if(DEBUG)
+ sys->fprint(sys->fildes(2), " <- %s\n", ostyx->rmsg2s(orm));
+ if(orm == nil)
+ break converting;
+ t := looktag(orm.tag);
+ if(t == nil){
+ warning("reply by old-server to non-existent tag");
+ break;
+ }
+ pick rm := orm {
+ Flush =>
+ ot := looktag(t.oldtag);
+ # if it's an Rflush of a request-in-progress,
+ # we send it to the reqproc, which
+ # can then clean up as it likes.
+ if(ot != nil){
+ if(ot.rp != nil){
+ if(ot.rp.flushable){
+ ot.rp.oldrmsg <-= rm;
+ # reqproc is bound to finish after a flush
+ reqreply(ot, newclient, oldsrv);
+ }else {
+ # hold flush reply for later
+ ot.flushes = ref Rmsg.Flush(rm.tag) :: ot.flushes;
+ }
+ break;
+ }
+ deletetag(t.oldtag);
+ }
+ NRsend(newclient, ref Rmsg.Flush(rm.tag));
+ deletetag(rm.tag);
+ * =>
+ if(t.rp != nil){
+ t.rp.oldrmsg <-= orm;
+ reqreply(t, newclient, oldsrv);
+ }else{
+ os2ns(orm, newclient);
+ deletetag(orm.tag);
+ }
+ }
+ }
+ # kill off active reqprocs
+ for(; tags != nil; tags = tags.next){
+ if(tags.rp != nil){
+ tags.rp.oldrmsg <-= nil;
+ nprocs--;
+ }
+ }
+ # kill off idle reqprocs
+ while(nprocs > 0){
+ rp := <-avail;
+ rp.newtmsg <-= nil;
+ nprocs--;
+ }
+ # kill off message readers
+ kill(<-killpids);
+ kill(<-killpids);
+}
+
+# process one response from the request proc.
+# request proc can respond by sending a new tmsg to the old server
+# or by sending an rmsg to the new client, in which case
+# it implicitly signals that it has finished processing the request.
+# the actual reply might be an Rflush, signifying that
+# the request has been aborted.
+reqreply(t: ref Req, newclient: ref Sys->FD, oldsrv: ref Sys->FD)
+{
+ rp := t.rp;
+ alt{
+ nrm := <-rp.newrmsg =>
+ # request is done when process sends rmsg
+ pick rm := nrm {
+ Flush =>
+ deletetag(t.tag);
+ }
+ deletetag(nrm.tag);
+ NRsend(newclient, nrm);
+ for(; t.flushes != nil; t.flushes = tl t.flushes)
+ NRsend(newclient, hd t.flushes);
+
+ otm := <-rp.oldtmsg =>
+ OTsend(oldsrv, otm);
+ }
+}
+
+
+# T messages: forward on, reply immediately, or start processing.
+ns2os(tm0: ref Tmsg, newclient, oldsrv: ref Sys->FD)
+{
+ otm: ref OTmsg;
+
+ t := ref Req(tm0.tag, -1, nil, nil, nil);
+ pick tm := tm0{
+ Readerror =>
+ exit;
+ Version =>
+ (s, v) := nstyx->compatible(tm, nstyx->MAXRPC, nil);
+ NRsend(newclient, ref Rmsg.Version(tm.tag, s, v));
+ return;
+ Auth =>
+ NRsend(newclient, ref Rmsg.Error(tm.tag, "authorization not required"));
+ return;
+ Walk =>
+ storetag(t);
+ t.rp = Reqproc.new();
+ t.rp.newtmsg <-= tm;
+ reqreply(t, newclient, oldsrv);
+ return;
+ Attach =>
+ otm = ref OTmsg.Attach(tm.tag, tm.fid, tm.uname, tm.aname);
+ Flush =>
+ t.oldtag = tm.oldtag;
+ otm = ref OTmsg.Flush(tm.tag, tm.oldtag);
+ Open =>
+ otm = ref OTmsg.Open(tm.tag, tm.fid, tm.mode);
+ Create =>
+ otm = ref OTmsg.Create(tm.tag, tm.fid, tm.perm, tm.mode, tm.name);
+ Read =>
+ fp := findfid(tm.fid);
+ count := tm.count;
+ offset := tm.offset;
+ if(fp != nil && fp.isdir){
+ fp.n = count;
+ count = (count/OStyx->DIRLEN)*OStyx->DIRLEN;
+ if(int offset != fp.coff){
+ NRsend(newclient, ref Rmsg.Error(tm.tag, "unexpected offset in dirread"));
+ return;
+ }
+ offset = big fp.soff;
+ }
+ otm = ref OTmsg.Read(tm.tag, tm.fid, count, offset);
+ Write =>
+ otm = ref OTmsg.Write(tm.tag, tm.fid, tm.offset, tm.data);
+ Clunk =>
+ otm = ref OTmsg.Clunk(tm.tag, tm.fid);
+ Remove =>
+ otm = ref OTmsg.Remove(tm.tag, tm.fid);
+ Stat =>
+ otm = ref OTmsg.Stat(tm.tag, tm.fid);
+ Wstat =>
+ otm = ref OTmsg.Wstat(tm.tag, tm.fid, nd2od(tm.stat));
+ * =>
+ fatal("bad T message");
+ }
+ storetag(t);
+ OTsend(oldsrv, otm);
+}
+
+# R messages: old to new
+os2ns(orm0: ref ORmsg, newclient: ref Sys->FD)
+{
+ rm: ref Rmsg;
+
+ rm = nil;
+ pick orm := orm0 {
+ Error =>
+ rm = ref Rmsg.Error(orm.tag, orm.err);
+ Flush =>
+ rm = ref Rmsg.Flush(orm.tag);
+ Clone =>
+ rm = ref Rmsg.Walk(orm.tag, nil);
+ Walk =>
+ fatal("walk rmsgs should be dealt with be walkreqproc");
+ Open =>
+ setfid(orm.fid, orm.qid);
+ rm = ref Rmsg.Open(orm.tag, oq2nq(orm.qid), 0);
+ Create =>
+ setfid(orm.fid, orm.qid);
+ rm = ref Rmsg.Create(orm.tag, oq2nq(orm.qid), 0);
+ Read =>
+ fp := findfid(orm.fid);
+ data := orm.data;
+ if(fp != nil && fp.isdir)
+ data = ods2nds(data, fp.n);
+ fp.coff += len data;
+ fp.soff += len orm.data;
+ rm = ref Rmsg.Read(orm.tag, data);
+ Write =>
+ rm = ref Rmsg.Write(orm.tag, orm.count);
+ Clunk =>
+ rm = ref Rmsg.Clunk(orm.tag);
+ deletefid(orm.fid);
+ Remove =>
+ rm = ref Rmsg.Remove(orm.tag);
+ deletefid(orm.fid);
+ Stat =>
+ rm = ref Rmsg.Stat(orm.tag, od2nd(orm.stat));
+ Wstat =>
+ rm = ref Rmsg.Wstat(orm.tag);
+ Attach =>
+ newfid(orm.fid, orm.qid.path & OSys->CHDIR);
+ rm = ref Rmsg.Attach(orm.tag, oq2nq(orm.qid));
+ * =>
+ fatal("bad R message");
+ }
+ NRsend(newclient, rm);
+}
+
+Reqproc.rpc(rp: self ref Reqproc, otm: ref OTmsg): ref ORmsg
+{
+ rp.oldtmsg <-= otm;
+ m := <-rp.oldrmsg;
+ if(m == nil)
+ exit;
+ return m;
+}
+
+Reqproc.new(): ref Reqproc
+{
+ alt{
+ rp := <-avail =>
+ return rp;
+ * =>
+ rp := ref Reqproc(
+ chan of ref Tmsg,
+ chan of ref Rmsg,
+ chan of ref OTmsg,
+ chan of ref ORmsg,
+ 1);
+ spawn reqproc(rp);
+ nprocs++;
+ return rp;
+ }
+}
+
+reqproc(rp: ref Reqproc)
+{
+ for(;;){
+ tm := <-rp.newtmsg;
+ if(tm == nil)
+ return;
+ rm: ref Rmsg;
+ pick m := tm {
+ Walk =>
+ rm = walkreq(m, rp);
+ * =>
+ fatal("non-walk req passed to reqproc");
+ }
+ rp.flushable = 1;
+ rp.newrmsg <-= rm;
+ avail <-= rp;
+ }
+}
+
+# note that although this is in a separate process,
+# whenever it's not in Reqproc.rpc, the styxconv
+# process is blocked, so although state is shared,
+# there are no race conditions.
+walkreq(tm: ref Tmsg.Walk, rp: ref Reqproc): ref Rmsg
+{
+ cloned := 0;
+ n := len tm.names;
+ if(tm.newfid != tm.fid){
+ cloned = 1;
+ pick rm := rp.rpc(ref OTmsg.Clone(tm.tag, tm.fid, tm.newfid)) {
+ Clone =>
+ ;
+ Error =>
+ return ref Rmsg.Error(tm.tag, rm.err);
+ Flush =>
+ return ref Rmsg.Flush(rm.tag);
+ * =>
+ fatal("unexpected reply to OTmsg.Clone");
+ }
+ cloned = 1;
+ }
+ qids := array[n] of NSys->Qid;
+ finalqid: OSys->Qid;
+
+ # make sure we don't get flushed in an unwindable state.
+ rp.flushable = n == 1 || cloned;
+ for(i := 0; i < n; i++){
+ pick rm := rp.rpc(ref OTmsg.Walk(tm.tag, tm.newfid, tm.names[i])) {
+ Walk =>
+ qids[i] = oq2nq(rm.qid);
+ finalqid = rm.qid;
+ Flush =>
+ if(cloned){
+ rp.flushable = 0;
+ rp.rpc(ref OTmsg.Clunk(tm.tag, tm.newfid));
+ }
+ return ref Rmsg.Flush(rm.tag);
+ Error =>
+ if(cloned){
+ rp.flushable = 0;
+ rp.rpc(ref OTmsg.Clunk(tm.tag, tm.newfid));
+ }
+ if(i == 0)
+ return ref Rmsg.Error(tm.tag, rm.err);
+ return ref Rmsg.Walk(tm.tag, qids[0:i]);
+ }
+ }
+ if(cloned)
+ clonefid(tm.fid, tm.newfid);
+ if(n > 0)
+ setfid(tm.newfid, finalqid);
+ return ref Rmsg.Walk(tm.tag, qids);
+}
+
+storetag(t: ref Req)
+{
+ t.next = tags;
+ tags = t;
+}
+
+looktag(tag: int): ref Req
+{
+ for(t := tags; t != nil; t = t.next)
+ if(t.tag == tag)
+ return t;
+ return nil;
+}
+
+deletetag(tag: int)
+{
+ prev: ref Req;
+ t := tags;
+ while(t != nil){
+ if(t.tag == tag){
+ next := t.next;
+ t.next = nil;
+ if(prev != nil)
+ prev.next = next;
+ else
+ tags = next;
+ t = next;
+ }else{
+ prev = t;
+ t = t.next;
+ }
+ }
+}
+
+newfid(fid: int, isdir: int): ref Fid
+{
+ f := ref Fid;
+ f.fid = fid;
+ f.isdir = isdir;
+ f.n = f.soff = f.coff = 0;
+ f.next = fids;
+ fids = f;
+ return f;
+}
+
+clonefid(ofid: int, fid: int): ref Fid
+{
+ if((f := findfid(ofid)) != nil){
+ nf := newfid(fid, f.isdir);
+ return nf;
+ }
+ warning("clone of non-existent fid");
+ return newfid(fid, 0);
+}
+
+deletefid(fid: int)
+{
+ lf: ref Fid;
+
+ for(f := fids; f != nil; f = f.next){
+ if(f.fid == fid){
+ if(lf == nil)
+ fids = f.next;
+ else
+ lf.next = f.next;
+ return;
+ }
+ lf = f;
+ }
+}
+
+findfid(fid: int): ref Fid
+{
+ for(f := fids; f != nil; f = f.next)
+ if(f.fid == fid)
+ return f;
+ return nil;
+}
+
+setfid(fid: int, qid: OSys->Qid)
+{
+ f := findfid(fid);
+ if(f == nil){
+ warning(sys->sprint("cannot find fid %d", fid));
+ }else{
+ f.isdir = qid.path & OSys->CHDIR;
+ }
+}
+
+om2nm(om: int): int
+{
+ # DMDIR == CHDIR
+ return om;
+}
+
+nm2om(m: int): int
+{
+ # DMDIR == CHDIR
+ return m&~(NSys->DMAPPEND|NSys->DMEXCL|NSys->DMAUTH);
+}
+
+oq2nq(oq: OSys->Qid): NSys->Qid
+{
+ q: NSys->Qid;
+
+ isdir := oq.path&OSys->CHDIR;
+ q.path = big (oq.path&~OSys->CHDIR);
+ q.vers = oq.vers;
+ q.qtype = 0;
+ if(isdir)
+ q.qtype |= NSys->QTDIR;
+ return q;
+}
+
+nq2oq(q: NSys->Qid): OSys->Qid
+{
+ oq: OSys->Qid;
+
+ isdir := q.qtype&NSys->QTDIR;
+ oq.path = int q.path;
+ oq.vers = q.vers;
+ if(isdir)
+ oq.path |= OSys->CHDIR;
+ return oq;
+}
+
+od2nd(od: OSys->Dir): NSys->Dir
+{
+ d: NSys->Dir;
+
+ d.name = od.name;
+ d.uid = od.uid;
+ d.gid = od.gid;
+ d.muid = od.uid;
+ d.qid = oq2nq(od.qid);
+ d.mode = om2nm(od.mode);
+ d.atime = od.atime;
+ d.mtime = od.mtime;
+ d.length = big od.length;
+ d.dtype = od.dtype;
+ d.dev = od.dev;
+ return d;
+}
+
+nd2od(d: NSys->Dir): OSys->Dir
+{
+ od: OSys->Dir;
+
+ od.name = d.name;
+ od.uid = d.uid;
+ od.gid = d.gid;
+ od.qid = nq2oq(d.qid);
+ od.mode = nm2om(d.mode);
+ od.atime = d.atime;
+ od.mtime = d.mtime;
+ od.length = int d.length;
+ od.dtype = d.dtype;
+ od.dev = d.dev;
+ return od;
+}
+
+ods2nds(ob: array of byte, max: int): array of byte
+{
+ od: OSys->Dir;
+
+ m := len ob;
+ if(m % OStyx->DIRLEN != 0)
+ fatal(sys->sprint("bad dir len %d", m));
+ m /= OStyx->DIRLEN;
+ n := 0;
+ p := ob;
+ for(i := 0; i < m; i++){
+ (p, od) = ostyx->convM2D(p);
+ d := od2nd(od);
+ nn := nstyx->packdirsize(d);
+ if(n+nn > max) # might just happen with long file names
+ break;
+ n += nn;
+ }
+ m = i;
+ b := array[n] of byte;
+ n = 0;
+ p = ob;
+ for(i = 0; i < m; i++){
+ (p, od) = ostyx->convM2D(p);
+ d := od2nd(od);
+ q := nstyx->packdir(d);
+ nn := len q;
+ b[n: ] = q[0: nn];
+ n += nn;
+ }
+ return b;
+}
+
+OTsend(fd: ref Sys->FD, otm: ref OTmsg): int
+{
+ if(DEBUG)
+ sys->fprint(sys->fildes(2), " -> %s\n", ostyx->tmsg2s(otm));
+ s := array[OStyx->MAXRPC] of byte;
+ n := ostyx->tmsg2d(otm, s);
+ if(n < 0)
+ return -1;
+ return sys->write(fd, s, n);
+}
+
+NRsend(fd: ref Sys->FD, rm: ref Rmsg): int
+{
+ if(DEBUG)
+ sys->fprint(sys->fildes(2), "<- %s\n", rm.text());
+ s := rm.pack();
+ if(s == nil)
+ return -1;
+ return sys->write(fd, s, len s);
+}
+
+readnewtmsgs(pidc: chan of int, newclient: ref Sys->FD, newtmsg: chan of ref Tmsg)
+{
+ pidc <-= sys->pctl(0, nil);
+ for(;;){
+ newtmsg <-= Tmsg.read(newclient, nstyx->MAXRPC);
+ }
+}
+
+readoldrmsgs(pidc: chan of int, oldsrv: ref Sys->FD, oldrmsg: chan of ref ORmsg)
+{
+ pidc <-= sys->pctl(0, nil);
+ for(;;){
+ oldrmsg <-= ORmsg.read(oldsrv);
+ }
+}
+
+warning(err: string)
+{
+ sys->fprint(sys->fildes(2), "warning: %s\n", err);
+}
+
+fatal(err: string)
+{
+ sys->fprint(sys->fildes(2), "%s\n", err);
+ exit;
+}
+
+nomod(mod: string, path: string)
+{
+ fatal(sys->sprint("can't load %s(%s): %r", mod, path));
+}
+
+kill(pid: int)
+{
+ sys->fprint(sys->open("#p/"+string pid+"/ctl", Sys->OWRITE), "kill");
+}
diff --git a/appl/lib/styxconv/nsys.m b/appl/lib/styxconv/nsys.m
new file mode 100644
index 00000000..5fe267ec
--- /dev/null
+++ b/appl/lib/styxconv/nsys.m
@@ -0,0 +1,51 @@
+NSys: module
+{
+ # Unique file identifier for file objects
+ Qid: adt
+ {
+ path: big;
+ vers: int;
+ qtype: int;
+ };
+
+ QTDIR: con 16r80;
+ QTAPPEND: con 16r40;
+ QTEXCL: con 16r20;
+ QTAUTH: con 16r08;
+ QTTMP: con 16r04;
+ QTFILE: con 0;
+
+ # Return from stat and directory read
+ Dir: adt
+ {
+ name: string;
+ uid: string;
+ gid: string;
+ muid: string;
+ qid: Qid;
+ mode: int;
+ atime: int;
+ mtime: int;
+ length: big;
+ dtype: int;
+ dev: int;
+ };
+
+ # Maximum read which will be completed atomically;
+ # also the optimum block size
+ #
+ ATOMICIO: con 8192;
+
+ OREAD: con 0;
+ OWRITE: con 1;
+ ORDWR: con 2;
+ OTRUNC: con 16;
+ ORCLOSE: con 64;
+ OEXCL: con 16r1000;
+
+ DMDIR: con int 1<<31;
+ DMAPPEND: con int 1<<30;
+ DMEXCL: con int 1<<29;
+ DMAUTH: con int 1<<27;
+ DMTMP: con int 1<<26;
+};
diff --git a/appl/lib/styxconv/old2new.b b/appl/lib/styxconv/old2new.b
new file mode 100644
index 00000000..a9ced502
--- /dev/null
+++ b/appl/lib/styxconv/old2new.b
@@ -0,0 +1,480 @@
+implement Styxconv;
+
+include "sys.m";
+ sys: Sys;
+include "osys.m";
+include "nsys.m";
+include "draw.m";
+include "styx.m";
+ nstyx: Styx;
+ Tmsg, Rmsg: import nstyx;
+include "ostyx.m";
+ ostyx: OStyx;
+ OTmsg, ORmsg: import ostyx;
+include "styxconv.m";
+
+DEBUG: con 0;
+
+# convert from old styx client to new styx server.
+# more straightforward than the other way around
+# because there's an almost exactly 1-1 mapping
+# between message types. (the exception is Tversion,
+# but we do that synchronously anyway).
+
+# todo: map qids > ffffffff into 32 bits.
+
+Msize: con nstyx->IOHDRSZ + OSys->ATOMICIO;
+Fid: adt
+{
+ fid: int;
+ isdir: int;
+ n: int; # size of last new client dirread request.
+ soff: int; # dir offset on new server.
+ coff: int; # dir offset on old client.
+ next: cyclic ref Fid;
+ extras: array of byte; # packed old styx dir structures
+};
+
+Req: adt {
+ tag: int;
+ fid: int;
+ oldtag: int; # if it's a flush.
+ newfid: int; # if it's a clone
+ next: cyclic ref Req;
+};
+
+tags: ref Req;
+fids: ref Fid;
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ if(sys == nil)
+ nomod("Sys", Sys->PATH);
+ nstyx = load Styx Styx->PATH;
+ if(nstyx == nil)
+ nomod("Styx", Styx->PATH);
+ ostyx = load OStyx OStyx->PATH;
+ if(ostyx == nil)
+ nomod("OStyx", OStyx->PATH);
+
+ ostyx->init();
+ nstyx->init();
+}
+
+styxconv(oldclient, newsrv: ref Sys->FD)
+{
+ oldtmsg := chan of ref OTmsg;
+ newrmsg := chan of ref Rmsg;
+
+ killpids := chan[2] of int;
+ spawn readoldtmsgs(killpids, oldclient, oldtmsg);
+ spawn readnewrmsgs(killpids, newsrv, newrmsg);
+ # XXX difficulty: what happens if the server isn't responding
+ # and the client hangs up? we won't know about it.
+ # but we don't want to know about normal t-messages
+ # piling up either, so we don't want to alt on oldtmsg too.
+ NTsend(newsrv, ref Tmsg.Version(nstyx->NOTAG, Msize, "9P2000"));
+ pick nrm := <-newrmsg {
+ Version =>
+ if(DEBUG)
+ sys->fprint(sys->fildes(2), " <- %s\n", nrm.text());
+ if(nrm.msize < Msize)
+ fatal("message size too small");
+ Error =>
+ fatal("versioning failed: " + nrm.ename);
+ * =>
+ fatal("bad response to Tversion: " + nrm.text());
+ }
+
+converting:
+ for(;;)alt{
+ otm := <-oldtmsg =>
+ if(DEBUG)
+ sys->fprint(sys->fildes(2), "-> %s\n", ostyx->tmsg2s(otm));
+ if(otm == nil || tagof(otm) == tagof(OTmsg.Readerror))
+ break converting;
+ oc2ns(otm, oldclient, newsrv);
+ nrm := <-newrmsg =>
+ if(DEBUG)
+ sys->fprint(sys->fildes(2), " <- %s\n", nrm.text());
+ if(nrm == nil || tagof(nrm) == tagof(Rmsg.Readerror))
+ break converting;
+ t := looktag(nrm.tag);
+ if(t == nil){
+ warning("reply by new-server to non-existent tag");
+ break;
+ }
+ ns2oc(t, nrm, oldclient);
+ deletetag(nrm.tag);
+ }
+
+ kill(<-killpids);
+ kill(<-killpids);
+}
+
+# T messages: forward on or reply immediately
+oc2ns(tm0: ref OTmsg, oldclient, newsrv: ref Sys->FD)
+{
+ ntm: ref Tmsg;
+
+ t := ref Req(tm0.tag, -1, -1, -1, nil);
+ pick tm := tm0{
+ Nop =>
+ ORsend(oldclient, ref ORmsg.Nop(tm.tag));
+ return;
+ Attach =>
+ t.fid = tm.fid;
+ ntm = ref Tmsg.Attach(tm.tag, tm.fid, nstyx->NOFID, tm.uname, tm.aname);
+ Clone =>
+ t.fid = tm.fid;
+ t.newfid = tm.newfid;
+ ntm = ref Tmsg.Walk(tm.tag, tm.fid, tm.newfid, nil);
+ Walk =>
+ t.fid = tm.fid;
+ ntm = ref Tmsg.Walk(tm.tag, tm.fid, tm.fid, array[] of {tm.name});
+ Flush =>
+ t.oldtag = tm.oldtag;
+ ntm = ref Tmsg.Flush(tm.tag, tm.oldtag);
+ Open =>
+ t.fid = tm.fid;
+ ntm = ref Tmsg.Open(tm.tag, tm.fid, tm.mode);
+ Create =>
+ t.fid = tm.fid;
+ ntm = ref Tmsg.Create(tm.tag, tm.fid, tm.name, tm.perm, tm.mode);
+ Read =>
+ t.fid = tm.fid;
+ fp := findfid(tm.fid);
+ count := tm.count;
+ offset := tm.offset;
+ if(fp.isdir){
+ count = (count/OStyx->DIRLEN)*OStyx->DIRLEN;
+ # if we got some extra entries last time,
+ # then send 'em back this time.
+ extras := fp.extras;
+ if(len extras > 0){
+ if(count > len extras)
+ count = len extras;
+ ORsend(oldclient, ref ORmsg.Read(tm.tag, t.fid, fp.extras[0:count]));
+ fp.extras = extras[count:];
+ fp.coff += count;
+ return;
+ }
+ fp.n = count;
+ if(int offset != fp.coff){
+ ORsend(oldclient, ref ORmsg.Error(tm.tag, "unexpected offset in dirread"));
+ return;
+ }
+ offset = big fp.soff;
+ }
+ ntm = ref Tmsg.Read(tm.tag, tm.fid, offset, count);
+ Write =>
+ t.fid = tm.fid;
+ ntm = ref Tmsg.Write(tm.tag, tm.fid, tm.offset, tm.data);
+ Clunk =>
+ t.fid = tm.fid;
+ ntm = ref Tmsg.Clunk(tm.tag, tm.fid);
+ Remove =>
+ t.fid = tm.fid;
+ ntm = ref Tmsg.Remove(tm.tag, tm.fid);
+ Stat =>
+ t.fid = tm.fid;
+ ntm = ref Tmsg.Stat(tm.tag, tm.fid);
+ Wstat =>
+ t.fid = tm.fid;
+ ntm = ref Tmsg.Wstat(tm.tag, tm.fid, od2nd(tm.stat));
+ * =>
+ fatal("bad T message");
+ }
+ storetag(t);
+ NTsend(newsrv, ntm);
+}
+
+# R messages: new to old
+ns2oc(t: ref Req, nrm0: ref Rmsg, oldclient: ref Sys->FD)
+{
+ rm: ref ORmsg;
+ pick nrm := nrm0{
+ Error =>
+ rm = ref ORmsg.Error(nrm.tag, nrm.ename);
+ Flush =>
+ rm = ref ORmsg.Flush(nrm.tag);
+ deletetag(t.oldtag);
+ Walk =>
+ if(len nrm.qids == 0){
+ clonefid(t.fid, t.newfid);
+ rm = ref ORmsg.Clone(nrm.tag, t.fid);
+ }else{
+ q := nrm.qids[0];
+ setfid(t.fid, q);
+ rm = ref ORmsg.Walk(nrm.tag, t.fid, nq2oq(q));
+ }
+ Open =>
+ setfid(t.fid, nrm.qid);
+ rm = ref ORmsg.Open(nrm.tag, t.fid, nq2oq(nrm.qid));
+ Create =>
+ setfid(t.fid, nrm.qid);
+ rm = ref ORmsg.Create(nrm.tag, t.fid, nq2oq(nrm.qid));
+ Read =>
+ fp := findfid(t.fid);
+ data := nrm.data;
+ if(fp != nil && fp.isdir){
+ data = nds2ods(data);
+ if(len data > fp.n){
+ fp.extras = data[fp.n:];
+ data = data[0:fp.n];
+ }
+ fp.coff += len data;
+ fp.soff += len nrm.data;
+ }
+ rm = ref ORmsg.Read(nrm.tag, t.fid, data);
+ Write =>
+ rm = ref ORmsg.Write(nrm.tag, t.fid, nrm.count);
+ Clunk =>
+ deletefid(t.fid);
+ rm = ref ORmsg.Clunk(nrm.tag, t.fid);
+ Remove =>
+ deletefid(t.fid);
+ rm = ref ORmsg.Remove(nrm.tag, t.fid);
+ Stat =>
+ rm = ref ORmsg.Stat(nrm.tag, t.fid, nd2od(nrm.stat));
+ Wstat =>
+ rm = ref ORmsg.Wstat(nrm.tag, t.fid);
+ Attach =>
+ newfid(t.fid, nrm.qid.qtype & NSys->QTDIR);
+ rm = ref ORmsg.Attach(nrm.tag, t.fid, nq2oq(nrm.qid));
+ * =>
+ fatal("bad R message");
+ }
+ ORsend(oldclient, rm);
+}
+
+storetag(t: ref Req)
+{
+ t.next = tags;
+ tags = t;
+}
+
+looktag(tag: int): ref Req
+{
+ for(t := tags; t != nil; t = t.next)
+ if(t.tag == tag)
+ return t;
+ return nil;
+}
+
+deletetag(tag: int)
+{
+ prev: ref Req;
+ t := tags;
+ while(t != nil){
+ if(t.tag == tag){
+ next := t.next;
+ t.next = nil;
+ if(prev != nil)
+ prev.next = next;
+ else
+ tags = next;
+ t = next;
+ }else{
+ prev = t;
+ t = t.next;
+ }
+ }
+}
+
+newfid(fid: int, isdir: int): ref Fid
+{
+ f := ref Fid;
+ f.fid = fid;
+ f.isdir = isdir;
+ f.n = f.soff = f.coff = 0;
+ f.next = fids;
+ fids = f;
+ return f;
+}
+
+clonefid(ofid: int, fid: int): ref Fid
+{
+ if((f := findfid(ofid)) != nil)
+ return newfid(fid, f.isdir);
+ warning("clone of non-existent fid");
+ return newfid(fid, 0);
+}
+
+deletefid(fid: int)
+{
+ lf: ref Fid;
+
+ for(f := fids; f != nil; f = f.next){
+ if(f.fid == fid){
+ if(lf == nil)
+ fids = f.next;
+ else
+ lf.next = f.next;
+ return;
+ }
+ lf = f;
+ }
+}
+
+findfid(fid: int): ref Fid
+{
+ for(f := fids; f != nil && f.fid != fid; f = f.next)
+ ;
+ return f;
+}
+
+setfid(fid: int, qid: NSys->Qid)
+{
+ if((f := findfid(fid)) != nil)
+ f.isdir = qid.qtype & NSys->QTDIR;
+}
+
+om2nm(om: int): int
+{
+ # DMDIR == CHDIR
+ return om;
+}
+
+nm2om(m: int): int
+{
+ # DMDIR == CHDIR
+ return m&~(NSys->DMAPPEND|NSys->DMEXCL|NSys->DMAUTH);
+}
+
+oq2nq(oq: OSys->Qid): NSys->Qid
+{
+ q: NSys->Qid;
+
+ isdir := oq.path&OSys->CHDIR;
+ q.path = big (oq.path&~OSys->CHDIR);
+ q.vers = oq.vers;
+ q.qtype = 0;
+ if(isdir)
+ q.qtype |= NSys->QTDIR;
+ return q;
+}
+
+nq2oq(q: NSys->Qid): OSys->Qid
+{
+ oq: OSys->Qid;
+
+ isdir := q.qtype&NSys->QTDIR;
+ oq.path = int q.path;
+ oq.vers = q.vers;
+ if(isdir)
+ oq.path |= OSys->CHDIR;
+ return oq;
+}
+
+od2nd(od: OSys->Dir): NSys->Dir
+{
+ d: NSys->Dir;
+
+ d.name = od.name;
+ d.uid = od.uid;
+ d.gid = od.gid;
+ d.muid = od.uid;
+ d.qid = oq2nq(od.qid);
+ d.mode = om2nm(od.mode);
+ d.atime = od.atime;
+ d.mtime = od.mtime;
+ d.length = big od.length;
+ d.dtype = od.dtype;
+ d.dev = od.dev;
+ return d;
+}
+
+nd2od(d: NSys->Dir): OSys->Dir
+{
+ od: OSys->Dir;
+
+ od.name = d.name;
+ od.uid = d.uid;
+ od.gid = d.gid;
+ od.qid = nq2oq(d.qid);
+ od.mode = nm2om(d.mode);
+ od.atime = d.atime;
+ od.mtime = d.mtime;
+ od.length = int d.length;
+ od.dtype = d.dtype;
+ od.dev = d.dev;
+ return od;
+}
+
+nds2ods(ob: array of byte): array of byte
+{
+ i := 0;
+ n := 0;
+ ds: list of NSys->Dir;
+ while(i < len ob){
+ (size, d) := nstyx->unpackdir(ob[i:]);
+ if(size == 0)
+ break;
+ ds = d :: ds;
+ i += size;
+ n++;
+ }
+ b := array[OStyx->DIRLEN * n] of byte;
+ for(i = (n - 1) * OStyx->DIRLEN; i >= 0; i -= OStyx->DIRLEN){
+ ostyx->convD2M(b[i:], nd2od(hd ds));
+ ds = tl ds;
+ }
+ return b;
+}
+
+NTsend(fd: ref Sys->FD, ntm: ref Tmsg)
+{
+ if(DEBUG)
+ sys->fprint(sys->fildes(2), " -> %s\n", ntm.text());
+ s := ntm.pack();
+ sys->write(fd, s, len s);
+}
+
+ORsend(fd: ref Sys->FD, orm: ref ORmsg)
+{
+ if(DEBUG)
+ sys->fprint(sys->fildes(2), "<- %s\n", ostyx->rmsg2s(orm));
+ s := array[OStyx->MAXRPC] of byte;
+ n := ostyx->rmsg2d(orm, s);
+ if(n > 0)
+ sys->write(fd, s, n);
+}
+
+readoldtmsgs(pidc: chan of int, oldclient: ref Sys->FD, oldtmsg: chan of ref OTmsg)
+{
+ pidc <-= sys->pctl(0, nil);
+ for(;;){
+ oldtmsg <-= OTmsg.read(oldclient);
+ }
+}
+
+readnewrmsgs(pidc: chan of int, newsrv: ref Sys->FD, newrmsg: chan of ref Rmsg)
+{
+ pidc <-= sys->pctl(0, nil);
+ for(;;){
+ newrmsg <-= Rmsg.read(newsrv, Msize);
+ }
+}
+
+warning(err: string)
+{
+ sys->fprint(sys->fildes(2), "warning: %s\n", err);
+}
+
+fatal(err: string)
+{
+ sys->fprint(sys->fildes(2), "%s\n", err);
+ exit;
+}
+
+nomod(mod: string, path: string)
+{
+ fatal(sys->sprint("can't load %s(%s): %r", mod, path));
+}
+
+kill(pid: int)
+{
+ sys->fprint(sys->open("#p/"+string pid+"/ctl", Sys->OWRITE), "kill");
+}
diff --git a/appl/lib/styxconv/ostyx.b b/appl/lib/styxconv/ostyx.b
index ce8e0d9e..b575a0cb 100644
--- a/appl/lib/styxconv/ostyx.b
+++ b/appl/lib/styxconv/ostyx.b
@@ -13,43 +13,81 @@ DEBUG: con 0;
CHANHASHSIZE: con 32;
+init()
+{
+ sys = load Sys Sys->PATH;
+ gsofar = 0;
+ gdata = array[MAXRPC] of {* => byte 0};
+}
+
+# note that this implementation fails if we're reading OTmsgs and ORmsgs
+# concurrently. luckily we don't need to in styxconv.
gsofar: int;
gdata: array of byte;
-ORmsg.read(fd: ref Sys->FD, msize: int): ref ORmsg
+ORmsg.read(fd: ref Sys->FD): ref ORmsg
{
- if(sys == nil)
- sys = load Sys Sys->PATH;
- if(gdata == nil){
- gsofar = 0;
- gdata = array[msize] of byte;
- }
+ mlen := 0;
+ m: ref ORmsg;
for (;;){
- n := sys->read(fd, gdata[gsofar:], len gdata - gsofar);
- if(n <= 0){
- m: ref ORmsg = nil;
-
- if(n < 0)
- m = ref ORmsg.Error(-1, sys->sprint("%r"));
+ if(gsofar > 0)
+ (mlen, m) = d2rmsg(gdata[0 : gsofar]);
+ if(mlen == 0){
+ if(gsofar == len gdata){
+ ndata := array[MAXRPC] of byte;
+ ndata[0:] = gdata;
+ gdata = ndata;
+ }
+ n := sys->read(fd, gdata[gsofar:], len gdata - gsofar);
+ if(n <= 0)
+ return nil;
+ gsofar += n;
+ }else if(mlen > 0){
+ if(tagof(m) == tagof(OTmsg.Write)) {
+ ndata := array[MAXRPC] of byte;
+ ndata[0:] = gdata[mlen : gsofar];
+ gdata = ndata;
+ }else
+ gdata[0:] = gdata[mlen : gsofar];
+ gsofar -= mlen;
return m;
- }
- gsofar += n;
- (cn, m) := d2rmsg(gdata[0: gsofar]);
- if(cn == -1)
+ }else
gsofar = 0;
- else if(cn > 0){
- if(tagof(m) == tagof(ORmsg.Read)) {
- ndata := array[msize] of byte;
- ndata[0: ] = gdata[cn: gsofar];
+ }
+}
+
+OTmsg.read(fd: ref Sys->FD): ref OTmsg
+{
+ mlen := 0;
+ m: ref OTmsg;
+ for (;;){
+ if(gsofar > 0)
+ (mlen, m) = d2tmsg(gdata[0 : gsofar]);
+ if(mlen == 0){
+ if(gsofar == len gdata){
+ ndata := array[MAXRPC] of byte;
+ ndata[0:] = gdata;
+ gdata = ndata;
+ }
+ n := sys->read(fd, gdata[gsofar:], len gdata - gsofar);
+ if(n <= 0)
+ return nil;
+ gsofar += n;
+ }else if(mlen > 0){
+ if(tagof(m) == tagof(OTmsg.Write)) {
+ ndata := array[MAXRPC] of byte;
+ ndata[0:] = gdata[mlen : gsofar];
gdata = ndata;
}else
- gdata[0: ] = gdata[cn: gsofar];
- gsofar -= cn;
+ gdata[0:] = gdata[mlen : gsofar];
+ gsofar -= mlen;
return m;
- }
+ }else
+ gsofar = 0;
}
}
+
Styxserver.new(fd: ref Sys->FD): (chan of ref OTmsg, ref Styxserver)
{
if (sys == nil)
@@ -572,7 +610,6 @@ pstring(a: array of byte, s: string, n: int): array of byte
# convert from Dir to bytes
convD2M(d: array of byte, f: OSys->Dir): array of byte
{
- n := len d;
d = pstring(d, f.name, OSys->NAMELEN);
d = pstring(d, f.uid, OSys->NAMELEN);
d = pstring(d, f.gid, OSys->NAMELEN);
diff --git a/appl/lib/styxconv/ostyx.m b/appl/lib/styxconv/ostyx.m
index de99d65a..82d94d15 100644
--- a/appl/lib/styxconv/ostyx.m
+++ b/appl/lib/styxconv/ostyx.m
@@ -24,6 +24,7 @@ OStyx: module
devclone: fn(srv: self ref Styxserver, m: ref OTmsg.Clone): ref Chan;
};
+ init: fn();
d2tmsg: fn(d: array of byte): (int, ref OTmsg);
d2rmsg: fn(d: array of byte): (int, ref ORmsg);
tmsg2d: fn(gm: ref OTmsg, d: array of byte): int;
@@ -69,6 +70,7 @@ OStyx: module
fid: int;
uname, aname: string;
}
+ read: fn(fd: ref Sys->FD): ref OTmsg;
};
ORmsg: adt {
@@ -99,7 +101,7 @@ OStyx: module
stat: OSys->Dir;
}
- read: fn(fd: ref Sys->FD, msize: int): ref ORmsg;
+ read: fn(fd: ref Sys->FD): ref ORmsg;
};
MAXRPC: con 128 + OSys->ATOMICIO;
diff --git a/dis/charon.dis b/dis/charon.dis
index f87c7aac..34054b67 100644
--- a/dis/charon.dis
+++ b/dis/charon.dis
Binary files differ
diff --git a/dis/charon/build.dis b/dis/charon/build.dis
index 658df708..43daa9f0 100644
--- a/dis/charon/build.dis
+++ b/dis/charon/build.dis
Binary files differ
diff --git a/dis/charon/chutils.dis b/dis/charon/chutils.dis
index c2c52e12..bd4c9cbb 100644
--- a/dis/charon/chutils.dis
+++ b/dis/charon/chutils.dis
Binary files differ
diff --git a/dis/charon/date.dis b/dis/charon/date.dis
index faa821df..3efd693e 100644
--- a/dis/charon/date.dis
+++ b/dis/charon/date.dis
Binary files differ
diff --git a/dis/charon/file.dis b/dis/charon/file.dis
index ae21e915..0f329d9a 100644
--- a/dis/charon/file.dis
+++ b/dis/charon/file.dis
Binary files differ
diff --git a/dis/charon/ftp.dis b/dis/charon/ftp.dis
index 1be3f503..1b2752d5 100644
--- a/dis/charon/ftp.dis
+++ b/dis/charon/ftp.dis
Binary files differ
diff --git a/dis/charon/gui.dis b/dis/charon/gui.dis
index ff44d1a0..503b19a1 100644
--- a/dis/charon/gui.dis
+++ b/dis/charon/gui.dis
Binary files differ
diff --git a/dis/charon/http.dis b/dis/charon/http.dis
index 28acaba0..0f09c160 100644
--- a/dis/charon/http.dis
+++ b/dis/charon/http.dis
Binary files differ
diff --git a/dis/charon/img.dis b/dis/charon/img.dis
index dfb65e7f..18e7f594 100644
--- a/dis/charon/img.dis
+++ b/dis/charon/img.dis
Binary files differ
diff --git a/dis/charon/jscript.dis b/dis/charon/jscript.dis
index 20f9696f..98a95c49 100644
--- a/dis/charon/jscript.dis
+++ b/dis/charon/jscript.dis
Binary files differ
diff --git a/dis/charon/layout.dis b/dis/charon/layout.dis
index 72b8fafa..cecb0fa7 100644
--- a/dis/charon/layout.dis
+++ b/dis/charon/layout.dis
Binary files differ
diff --git a/dis/charon/lex.dis b/dis/charon/lex.dis
index a7c38467..9c382756 100644
--- a/dis/charon/lex.dis
+++ b/dis/charon/lex.dis
Binary files differ
diff --git a/dis/lib/styxconv/new2old.dis b/dis/lib/styxconv/new2old.dis
new file mode 100644
index 00000000..35938c13
--- /dev/null
+++ b/dis/lib/styxconv/new2old.dis
Binary files differ
diff --git a/dis/lib/styxconv/old2new.dis b/dis/lib/styxconv/old2new.dis
new file mode 100644
index 00000000..c3cd1378
--- /dev/null
+++ b/dis/lib/styxconv/old2new.dis
Binary files differ
diff --git a/dis/lib/styxconv/ostyx.dis b/dis/lib/styxconv/ostyx.dis
index 61c961d9..c52aed56 100644
--- a/dis/lib/styxconv/ostyx.dis
+++ b/dis/lib/styxconv/ostyx.dis
Binary files differ
diff --git a/dis/mount.dis b/dis/mount.dis
index 21837f16..35463f5f 100644
--- a/dis/mount.dis
+++ b/dis/mount.dis
Binary files differ
diff --git a/include/version.h b/include/version.h
index ffe114f4..b83da283 100644
--- a/include/version.h
+++ b/include/version.h
@@ -1 +1 @@
-#define VERSION "Fourth Edition (20091119)"
+#define VERSION "Fourth Edition (20091127)"
diff --git a/man/2/styxconv b/man/2/styxconv
index f18c48a6..9180ad96 100644
--- a/man/2/styxconv
+++ b/man/2/styxconv
@@ -4,10 +4,11 @@ styxconv \- convert between old and new Styx
.SH SYNOPSIS
.EX
include "styxconv.m";
-styxconv := load Styxconv Styxconv->PATH;
+styxconv := load Styxconv Styxconv->PATHNEW2OLD;
+styxconv := load Styxconv Styxconv->PATHOLD2NEW;
init: fn();
-styxconv: fn(to: ref Sys->FD, from: ref Sys->FD, pid: chan of int);
+styxconv: fn(client: ref Sys->FD, server: ref Sys->FD);
.EE
.SH DESCRIPTION
.B Styxconv
@@ -22,49 +23,46 @@ must be called before any other function in the module.
.PP
The function
.B styxconv
-takes two file descriptors.
-.I From
-must be a connection to a file server that serves the original, older
-version of Styx.
-.I To
-is a connection, perhaps a pipe, to something that requires the current protocol;
-.B Sys->mount
-for instance
-(see
-.IR sys-bind (2)).
+takes two file descriptors:
+.I client
+should be a connection to a styx client requiring
+one version of the protocol;
+.I server
+should be a connection to a styx server serving
+the other version of the protocol.
+There are two conversion modules:
+.B PATHNEW2OLD
+converts from a new client to an old server;
+.B PATHOLD2NEW
+converts from an old client to a new server.
+.PP
.B Styxconv
-is spawned by the caller, to create a process that copies messages between
-.I from
+should be spawned by the caller, and copies messages between
+.I client
and
-.IR to ,
-converting as required as it goes.
-Its process ID is the only message sent on
-channel
-.IR pidc ;
-it must be received by
-.BR styxconv 's
-caller.
+.IR server ,
+converting as required.
See the example below.
.SH EXAMPLE
Apply
.B styxconv
to file descriptor
-.I fd
-connected to an old Styx server:
+.IR fd ,
+connected to an old Styx server, and return
+a file descriptor suitable for mounting with
+.IR mount (2).
.IP
.EX
cvstyx(fd: ref Sys->FD): ref Sys->FD
{
- styxconv := load Styxconv Styxconv->PATH;
+ styxconv := load Styxconv Styxconv->NEW2OLDPATH;
if(styxconv == nil)
return nil;
p := array[2] of ref Sys->FD;
if(sys->pipe(p) < 0)
return nil;
styxconv->init();
- pidc := chan of int;
- spawn styxconv->styxconv(p[1], fd, pidc);
- <-pidc;
+ spawn styxconv->styxconv(p[1], fd);
return p[0];
}
.EE
@@ -75,3 +73,5 @@ cvstyx(fd: ref Sys->FD): ref Sys->FD
.IR sys-bind (2),
.IR sys-pipe (2),
.IR intro (5)
+.SH BUGS
+There is no provision for 9p2000 authentication.
diff --git a/module/styxconv.m b/module/styxconv.m
index 2752d3c6..81f1e210 100644
--- a/module/styxconv.m
+++ b/module/styxconv.m
@@ -1,9 +1,10 @@
Styxconv: module
{
- PATH: con "/dis/lib/styxconv/styxconv.dis";
-
+ PATHOLD2NEW: con "/dis/lib/styxconv/old2new.dis";
+ PATHNEW2OLD: con "/dis/lib/styxconv/new2old.dis";
+
# call first
init: fn();
# spawn and synchronize
- styxconv: fn(in: ref Sys->FD, out: ref Sys->FD, sync: chan of int);
+ styxconv: fn(client: ref Sys->FD, server: ref Sys->FD);
};
diff --git a/os/pc/fns.h b/os/pc/fns.h
index de8cfbe1..10a5f098 100644
--- a/os/pc/fns.h
+++ b/os/pc/fns.h
@@ -133,12 +133,12 @@ ulong rdtsc32(void);
void screeninit(void);
int screenprint(char*, ...); /* debugging */
void (*screenputs)(char*, int);
-#define segflush(a,n)
+int segflush(void*, ulong);
void syncclock(void);
uvlong tscticks(uvlong*);
void trapenable(int, void (*)(Ureg*, void*), void*, char*);
void trapinit(void);
-ulong _tas(ulong*);
+int _tas(int*);
ulong umbmalloc(ulong, int, int);
void umbfree(ulong, int);
ulong umbrwmalloc(ulong, int, int);
diff --git a/os/pc/mmu.c b/os/pc/mmu.c
index 6a9e8089..da86517d 100644
--- a/os/pc/mmu.c
+++ b/os/pc/mmu.c
@@ -335,3 +335,9 @@ vunmap(void *va, int size)
if(va != nil)
upafree(PADDR(va), size);
}
+
+int
+segflush(void*, ulong)
+{
+ return 0;
+}