# # Software from the book "Inferno Programming with Limbo" # published by John Wiley & Sons, January 2003. # # p. Stanley-Marbell # implement StyxServer; include "sys.m"; include "draw.m"; include "arg.m"; include "styx.m"; include "styxlib.m"; sys : Sys; arg : Arg; styx : Styx; styxlib : Styxlib; Styxserver, Rmsg, Tmsg, Dirtab, Chan: import styxlib; mntflg := Sys->MREPL; mntpt := "/n/remote/"; numoranges : int; Qmax : con 1024; QSHIFT : con 4; Qroot, Qorange, Qnew, Qctl, Qdate, Qtime, Qline : con iota; perms := array [Qmax] of {Qnew to Qtime => 8r400, * => 8r755}; mtimes := array [Qmax] of int; atimes := array [Qmax] of int; lengths := array [Qmax] of int; StyxServer : module { init : fn(nil : ref Draw->Context, args : list of string); dirgen: fn(srv: ref Styxlib->Styxserver, c: ref Styxlib->Chan, tab: array of Styxlib->Dirtab, i: int): (int, Sys->Dir); }; init(nil : ref Draw->Context, args : list of string) { sys = load Sys Sys->PATH; styxlib = load Styxlib Styxlib->PATH; styx = load Styx Styx->PATH; arg = load Arg Arg->PATH; arg->init(args); while((c := arg->opt()) != 0) { case c { 'b' => mntflg = Sys->MBEFORE; 'a' => mntflg = Sys->MAFTER; 'r' => mntflg = Sys->MREPL; 'c' => mntflg |= Sys->MCREATE; * => { sys->print("Usage : styxserver [-rabc] \n"); exit; } } } args = arg->argv(); if (len args != 1) { sys->print("Usage : styxserver [-rabc] \n"); exit; } mntpt = hd args; styxpipe := array [2] of ref Sys->FD; sys->pipe(styxpipe); (tmsgchan, srv) := Styxserver.new(styxpipe[0]); sync := chan of int; spawn server(tmsgchan, srv, sync); <-sync; if (sys->mount(styxpipe[1], mntpt, mntflg, nil) < 0) { sys->raise(sys->sprint("fail:StyxServer mount failed : %r")); } } server(tmsgchan : chan of ref Styxlib->Tmsg, srv : ref Styxserver, sync : chan of int) { devgen := load Dirgenmod "$self"; sync <-= 0; while () { msg := <-tmsgchan; if (msg == nil) { exit; } pick m := msg { Readerror => { sys->raise(sys->sprint( "fail:Styxserver error reading Styx pipe : %r")); } Nop => srv.reply(ref Rmsg.Nop(m.tag)); Attach => srv.devattach(m); Clone => srv.devclone(m); Clunk => srv.devclunk(m); Create => srv.reply(ref Rmsg.Error(m.tag,Styxlib->Eperm)); Flush => srv.devflush(m); Open => srv.devopen(m, devgen, nil); Read => { c := srv.fidtochan(m.fid); if (c == nil) { srv.reply(ref Rmsg.Error(m.tag,Styxlib->Eperm)); break; } if (c.isdir()) { srv.devdirread(m, devgen, nil); break; } if (c.qid.path == Qnew) { if (((numoranges << QSHIFT) + Qline) < Qmax) { numoranges++; } srv.reply(ref Rmsg.Read(m.tag, m.fid, nil)); break; } srv.reply(ref Rmsg.Error(m.tag,Styxlib->Eperm)); } Remove => srv.reply(ref Rmsg.Error(m.tag,Styxlib->Eperm)); Stat => srv.devstat(m, devgen, nil); Walk => srv.devwalk(m, devgen, nil); Write => srv.reply(ref Rmsg.Error(m.tag,Styxlib->Eperm)); Wstat => srv.reply(ref Rmsg.Error(m.tag,Styxlib->Eperm)); } } } dirgen(nil : ref Styxserver, c : ref Chan, nil : array of Dirtab, entry : int) : (int, Sys->Dir) { level := c.qid.path & ((1 << QSHIFT) - 1); # Top level directory, say /n if (level == Qroot) { if (entry == 0) { return (1, packdir("orange", Qorange, Sys->CHDIR, 0)); } } # Second level directory, say, /n/orange if (level == Qorange) { if (entry == 0) { return (1, packdir("new", Qnew, 0, 0)); } else if (entry <= numoranges) { which := entry - 1; return (1, packdir(sys->sprint("%d", which), Qline|(which<CHDIR, 0)); } } # Third level directory, say, /n/orange/5 if (level == Qline) { line := (c.qid.path&~Sys->CHDIR) >> QSHIFT; case(entry) { 0 => return (1, packdir("ctl", Qctl, 0, line)); 1 => return (1, packdir("date", Qdate, 0, line)); 2 => return (1, packdir("time", Qtime, 0, line)); } } return (-1, packdir(nil, 0, 0, 0)); } packdir(name : string, Q, dirflag, line : int) : Sys->Dir { qid : Sys->Qid; qid.vers = 0; qid.path = Q; qid.path |= line << QSHIFT; qid.path |= dirflag; return Sys->Dir (name, "pip", "pip", qid, perms[Q] | (qid.path & Sys->CHDIR), atimes[Q], mtimes[Q], lengths[Q], 'O', 'O'); }