diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 20:52:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 20:52:35 +0000 |
| commit | 46439007cf417cbd9ac8049bb4122c890097a0fa (patch) | |
| tree | 6fdb25e5f3a2b6d5657eb23b35774b631d4d97e4 /man/2/styxservers | |
| parent | 37da2899f40661e3e9631e497da8dc59b971cbd0 (diff) | |
20060303-partial
Diffstat (limited to 'man/2/styxservers')
| -rw-r--r-- | man/2/styxservers | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/man/2/styxservers b/man/2/styxservers new file mode 100644 index 00000000..fca2748a --- /dev/null +++ b/man/2/styxservers @@ -0,0 +1,902 @@ +.TH STYXSERVERS 2 +.SH NAME +styxservers \- +Styx server implementation assistance +.SH SYNOPSIS +.EX +include "sys.m"; +include "styx.m"; +Tmsg, Rmsg: import Styx; +include "styxservers.m"; +styxservers := load Styxservers Styxservers->PATH; +Styxserver, Fid, Navigator: import styxservers; + +Styxserver: adt { + fd: ref Sys->FD; # file server end of connection + t: ref Navigator; # name space navigator for this server + msize: int; # negotiated Styx message size + + new: fn(fd: ref Sys->FD, t: ref Navigator, rootpath: big) + :(chan of ref Tmsg, ref Styxserver); + reply: fn(srv: self ref Styxserver, m: ref Rmsg): int; + + # protocol operations + attach: fn(srv: self ref Styxserver, m: ref Tmsg.Attach): ref Fid; + clunk: fn(srv: self ref Styxserver, m: ref Tmsg.Clunk): ref Fid; + walk: fn(srv: self ref Styxserver, m: ref Tmsg.Walk): ref Fid; + open: fn(srv: self ref Styxserver, m: ref Tmsg.Open): ref Fid; + read: fn(srv: self ref Styxserver, m: ref Tmsg.Read): ref Fid; + remove: fn(srv: self ref Styxserver, m: ref Tmsg.Remove): ref Fid; + stat: fn(srv: self ref Styxserver, m: ref Tmsg.Stat); + default: fn(srv: self ref Styxserver, gm: ref Tmsg); + + # check validity + cancreate: fn(srv: self ref Styxserver, m: ref Tmsg.Create) + :(ref Fid, int, ref Sys->Dir, string); + canopen: fn(srv: self ref Styxserver, m: ref Tmsg.Open) + :(ref Fid, int, ref Sys->Dir, string); + canread: fn(srv: self ref Styxserver, m: ref Tmsg.Read) + :(ref Fid, string); + canwrite: fn(srv: self ref Styxserver, m: ref Tmsg.Write) + :(ref Fid, string); + + # fid management + getfid: fn(srv: self ref Styxserver, fid: int): ref Fid; + newfid: fn(srv: self ref Styxserver, fid: int): ref Fid; + delfid: fn(srv: self ref Styxserver, c: ref Fid); + allfids: fn(srv: self ref Styxserver): list of ref Fid; + + iounit: fn(srv: self ref Styxserver): int; +}; + +Fid: adt { + fid: int; # client's fid + path: big; # file's 64-bit unique path + qtype: int; # file's qid type (eg, Sys->QTDIR if directory) + isopen: int; # non-zero if file is open + mode: int; # if open, the open mode + uname: string; # user name from original attach + param: string; # attach aname from original attach + data: array of byte; # application data + + clone: fn(f: self ref Fid, nf: ref Fid): ref Fid; + open: fn(f: self ref Fid, mode: int, qid: Sys->Qid); + walk: fn(f: self ref Fid, qid: Sys->Qid); +}; + +Navop: adt { + reply: chan of (ref Sys->Dir, string); # channel for reply + path: big; # file or directory path + pick { + Stat => + Walk => + name: string; + Readdir => + offset: int; # index (origin 0) of first entry to return + count: int; # number of directory entries requested + } +}; + +Navigator: adt { + new: fn(c: chan of ref Navop): ref Navigator; + stat: fn(t: self ref Navigator, path: big): (ref Sys->Dir, string); + walk: fn(t: self ref Navigator, parent: big, name: string) + : (ref Sys->Dir, string); + readdir:fn(t: self ref Navigator, path: big, + offset, count: int): array of ref Sys->Dir; +}; + +init: fn(styx: Styx); +traceset: fn(on: int); + +readbytes: fn(m: ref Styx->Tmsg.Read, d: array of byte): + ref Styx->Rmsg.Read; +readstr: fn(m: ref Styx->Tmsg.Read, s: string): + ref Styx->Rmsg.Read; +openok: fn(uname: string, omode, + perm: int, funame, fgname: string): int; +openmode: fn(o: int): int; +.EE +.SH DESCRIPTION +When writing a Styx file server, there are some +commonly performed tasks that are +fiddly or tedious to implement each time. +.B Styxservers +provides a framework to automate some of these +routine tasks. +In particular, it helps manage the fid space, +implements common default processing for protocol messages, +and assists walking around the +directory hierarchy and reading of directories. Other +tasks, such as defining the structure of the +name space, and reading and writing files in it, are +left to the file server program itself. +Familiarity with Section 5 of the manual which defines the protocol +(see +.IR intro (5)), +and with the representation of Styx messages in Limbo +(see +.IR styx (2)), +is a prerequisite for use of this module. +.PP +.B Styxservers +does not define or store any of the directory hierarchy itself; +instead it queries an external process for information +when necessary, through a value of type +.BR Navigator , +which encapsulates communication with that process. +That process must be started up +independently of each +.BR Styxserver ; +a channel to such a process should be provided +when starting a new +.BR Styxserver . +The channel carries messages of type +.BR Navop . +.IR Styxservers-nametree (2) +provides a ready-made +implementation of such a process that is sufficient for many applications. +.PP +.B Styxserver +keeps tabs on the fids that are currently in use, and remembers +some associated information, such as the Qid path +of the file, whether it has been opened, etc. +It does this using values of type +.BR Fid . +.PP +Once the +.B Styxservers +module has been loaded, +the +.B init +function must be called before anything else, +to initialise its internal state. The +.I styx +argument should be an implementation of +the +.IR styx (2) +module, which will be used to translate messages. +Individual +.B Styxserver +instances do not share state, and are therefore +independently thread-safe. +.SS Fid representation +.B Styxservers +represents each active fid as a +.B Fid +value, +which has the following public members: +.TF param +.TP +.B fid +The integer +.I fid +value provided by the client to refer to an active instance of a file in the file server, +as described in +.IR intro (5). +.TP +.B path +The 64-bit qid path that uniquely identifies the file on the file server, +as described in +.IR intro (5). +It is set by +.IB f .walk +and +.IB f .open +(see below). +.TP +.B qtype +The file's qid type; it is +.B Sys->QTDIR +if and only if the fid refers to a directory. +The value is set by +.IB f .walk +and +.IB f .open +(see below). +.TP +.B isopen +Non-zero if and only if the fid has been opened by an +.IR open (5) +message. +It is initially zero, and set by +.IB f .open +(see below). +.TP +.B mode +Valid only if the fid has been opened. +It has one of the values +.BR Sys->OREAD , +.BR Sys->OWRITE , +.BR Sys->ORDWR , +possibly ORed with +.BR Sys->ORCLOSE , +corresponding to the mode with which the file was opened. +It is set by +.IB f .open +(see below). +.TP +.B uname +The name of the user that created the fid. +.TP +.B param +Set by +.B Styxservers +to the +.B aname +of the initial +.IR attach (5) +message, +and subsequently inherited by each new fid created by +.IR walk (5), +but not otherwise used by +.B Styxservers +itself, and may be changed by the application. +.TP +.B data +Unused by +.BR Styxservers ; +for application use. +It might be used, for instance, to implement a file that gives different +data to different clients. +.TP +.IB f .clone( nf ) +Copy the current state of all members of +.I f +except +.IB f .fid\f1,\fP +into +.IR nf , +and return +.IR nf . +Used by +.BR Styxserver.walk , +and is needed by an application only if it replaces that function. +.TP +.IB f .walk( qid ) +Make +.I f +refer to the file with the given +.IR qid : +set +.IB f .path +and +.IB f .qtype +from +.IB qid .path +and +.IB qid .qtype . +Used by +.IB Styxserver.walk +and is needed by an application only if it replaces that function. +.TP +.IB f .open( mode,\ qid ) +Mark +.I f +as `open', +set +.IR f .mode +to +.IR mode , +and set +.B path +and +.B qtype +to the path and type of +.IR qid . +Used by the +implementations of +.B open +and +.B create +messages. +The default implementation of +.IR open (5) +in +.B Styxserver +obtains the value of +.I mode +from +.B Styxserver.canopen +(below), +and +obtains the value of +.I qid +by querying the application's navigator. +.SS Styxserver and file server state +Each +.B Styxserver +value holds the state for a single file server, including its active fids, +the link to the external name space process, and other internal data. +Most of the state is manipulated through the member functions described below. +The exceptions are two read-only values: +the +.B Navigator +reference +.IB srv .t +which can be used to access that navigator; and +the file descriptor +.IB srv .fd +that is the file server's end of the connection to the Styx client. +Both values are initially provided by the file serving application, +but can be accessed through the +.B Styxserver +value for convenience. +The file descriptor value is normally used only through +.BR Styxserver.reply , +but will be needed directly if the caller needs the file descriptor value +as a parameter to +.IR sys-pctl (2) +when insulating the serving process's file descriptors from the surrounding environment. +.PP +The first set of functions in +.B Styxserver +provides common and default actions: +.TP +.B Styxserver.new(\fIfd\fP,\ \fIt\fP,\ \fIrootpath\fP) +Create a new +.BR Styxserver . +It returns a tuple, say +.RI ( c ", " srv ), +and spawns a new process, which uses +.IR styx (2) +to read and parse Styx messages read +from +.IR fd , +and send them down +.IR c ; +.I t +should be a +.B Navigator +adt which the +.B Styxserver +can use to answer queries +on the name space (see ``Navigating file trees'', below). +.I Rootpath +gives the Qid path of the root of the served name space. +.TP +.IB srv .reply(\fIm\fP) +Send a reply (R-message) to a client. The various utility methods, +listed below, call this function to make their response. +.TP +.IB srv .attach(\fIm\fP) +Respond to an +.IR attach (5) +message +.IR m , +creating a new fid in the process, and returning it. +Returns +.B nil +if +.IB m .fid +is a duplicate of an existing fid. +The value of the attach parameter +.IB m .aname +is copied into the new fid's +.B param +field, as is the attaching user name, +.IB m .uname . +.TP +.IB srv .clunk(\fIm\fP) +Respond to a +.IR clunk (5) +message +.IR m , +and return the old +.BR Fid . +Note that this does nothing about remove-on-close +files; that should be programmed explicitly if needed. +.TP +.IB srv .walk(\fIm\fP) +Respond to a +.IR walk (5) +message +.IR m , +querying +.IB srv . t +for information on existing files. +.TP +.IB srv .open(\fIm\fP) +Respond to an +.IR open (5) +message +.IR m . +This will allow a file to be opened if its permissions allow the +specified mode of access. +.TP +.IB srv .read(\fIm\fP) +Respond to a +.IR read (5) +message +.IR m . +If a directory is being read, the appropriate reply +is made; for files, an error is given. +.TP +.IB srv .remove(\fIm\fP) +Respond to a +.IR remove (5) +message +.IR m +with an error, clunking the fid as it does so, +and returning the old +.BR Fid . +.TP +.IB srv .stat(\fIm\fP) +Respond to a +.IR stat (5) +message +.IR m . +.TP +.IB srv .default(\fIgm\fP) +Respond to an arbitrary T-message, +.IR gm , +as appropriate (eg, by calling +.IB srv .walk +for a +.IR walk (5) +message). +It responds appropriately to +.IR version (5), +and replies to +.B Tauth +(see +.IR attach (5)) +stating that authentication is not required. +Other messages without an associated +.B Styxserver +function are generally responded to +with a ``permission denied'' error. +.PP +All the functions above check the validity of the fids, modes, counts and offsets +in the messages, and automatically reply to the client with a suitable +.IR error (5) +message on error. +.PP +The following further +.B Styxserver +operations are useful +in applications that override all or part of the default handling +(in particular, +to process read and write requests): +.TP +.IB srv .canopen( m ) +Check whether it is legal to open a file as requested by message +.IR m : +the fid is valid but not already open, the corresponding file exists and its +permissions allow access in the requested mode, and if +.B Sys->ORCLOSE +is requested, the parent directory is writable (to allow the file to be removed when closed). +.B Canopen +returns a tuple, say +.RI ( f ,\ mode ,\ d,\ err\ \fP). +If the open request was invalid, +.I f +will be nil, and the string +.I err +will diagnose the error (for return to the client in an +.B Rmsg.Error +message). +If the request was valid: +.I f +contains the +.B Fid +representing the file to be opened; +.I mode +is the access mode derived from +.IB m .mode , +.BR Sys->OREAD , +.BR Sys->OWRITE , +.BR Sys->ORDWR , +ORed with +.BR Sys->ORCLOSE ; +.I d +is a +.B Dir +value giving the file's attributes, obtained from the navigator; +and +.I err +is nil. +Once the application has done what it must to open the file, +it must call +.IB f .open +to mark it open. +.TP +.IB srv .cancreate( m ) +Checks whether the +creation of the file requested by +message +.I m +is legal: +the fid is valid but not open, refers to a directory, +the permissions returned by +.IR srv .t.stat +show that directory is writable by the requesting user, +the name does not already exist in that directory, +and the mode with which the new file would be opened is valid. +.B Cancreate +returns a tuple, say +.RI ( f ,\ mode,\ d,\ err\ \fP). +If the creation request was invalid, +.I f +will be nil, and the string +.I err +will diagnose the error, for use in an error reply to the client. +If the request was valid: +.I f +contains the +.B Fid +representing the parent directory; +.I mode +is the open mode as defined for +.B canopen +above; +.I d +is a +.B Dir +value containing some initial attributes for the new file or directory; +and +.I err +is nil. +The initial attributes set in +.I d +are: +.IB d .name +(the name of the file to be created); +.IB d .uid +and +.IB d .muid +(the user that did the initial attach); +.IB d .gid , +.IB d .dtype , +.IB d .dev +(taken from the parent directory's attributes); +and +.IB d .mode +holds the file mode that should be attributed to the new +file (taking into account the parent mode, as +described in +.IR open (5)). +The caller must supply +.IB d .qid +once the file has successfully been created, +and +.IB d .atime +and +.IB d .mtime ; +it must also call +.IB f .open +to mark +.I f +open and set its path to the file's path. +If the file cannot be created successfully, the application should reply with +an +.IR error (5) +message and leave +.I f +untouched. +The +.B Fid +.I f +will then continue to refer to the original directory, and remain unopened. +.TP +.IB srv .canread( m ) +Checks whether +.IR read (5) +message +.I m +refers to a valid fid that has been opened for reading, +and that the count and file offset are non-negative. +.B Canread +returns a tuple, say +.RI ( f ,\ err ); +if the attempted access is illegal, +.I f +will be nil, and +.I err +contains a description of the error, +otherwise +.I f +contains the +.B Fid +corresponding to the file in question. +It is typically called by an application's implementation of +.B Tmsg.Read +to obtain the +.B Fid +corresponding to the fid in the message, and check the access. +.TP +.IB srv .canwrite( m ) +Checks whether +message +.I m +refers to a valid fid that has been opened for writing, +and that the file offset is non-negative. +.B Canwrite +returns a tuple, say +.RI ( f ,\ err ); +if the attempted access is illegal, +.I f +will be nil, and +.I err +contains a description of the error, +otherwise +.I f +contains the +.B Fid +corresponding to the file in question. +It is typically called by an application's implementation of +.B Tmsg.Write +to obtain the +.B Fid +corresponding to the fid in the message, and check the access. +.TP +.IB srv .iounit() +Return an appropriate value for use as the +.I iounit +element in +.B Rmsg.Open +and +.B Rmsg.Create +replies, +as defined in +.IR open (5), +based on the message size negotiated by the initial +.IR version (5) +message. +.PP +The remaining functions are normally used only by servers that need to +override default actions. +They maintain and access the mapping between a client's fid values presented in +.B Tmsg +messages and the +.B Fid +values that represent the corresponding files internally. +.TP +.IB srv .newfid(\fIfid\fP) +Create a new +.B Fid +associated with number +.I fid +and return it. +Return nil if the +.I fid +is already in use (implies a client error if the server correctly clunks fids). +.TP +.IB srv .getfid(\fIfid\fP) +Get the +.B Fid +data associated with numeric id +.IR fid ; +return nil if there is none such (a malicious or erroneous client +can cause this). +.TP +.IB srv .delfid(\fIfid\fP) +Delete +.I fid +from the table of fids in the +.BR Styxserver . +(There is no error return.) +.TP +.IB srv .allfids() +Return a list of all current fids (ie, the files currently active on the client). +.PP +.B Newfid +is required when processing +.IR auth (5), +.IR attach (5) +and +.IR walk (5) +messages to create new fids. +.B Delfid +is used to clunk fids when processing +.IR clunk (5), +.IR remove (5), +and in a failed +.IR walk (5) +when it specified a new fid. +All other messages should refer only to already existing fids, and the associated +.B Fid +data is fetched by +.BR getfid . +.SS Navigating file trees +When a +.B Styxserver +instance needs to know about the namespace, +it queries an external process through a channel +by sending a +.B Navop +request; +each such request carries with it a +.B reply +channel through which the +reply should be made. +The reply tuple has a reference to a +.B Sys->Dir +value that is non-nil on success, and a diagnostic string +that is non-nil on error. +.PP +Files in the tree are referred to +by their Qid +.BR path . +The requests are: +.TF Walk +.TP +.BR Stat +.br +Find a file in the hierarchy by its +.BR path , +and reply with the corresponding +.B Dir +data if found (or a diagnostic on error). +.TP +.BR Walk +.br +Look for file +.B name +in the directory with the given +.BR path . +.TP +.BR Readdir +.br +Get information on selected files in the directory with the given +.BR path . +In this case, the reply channel is used to send +a sequence of values, one for each entry in the directory, finishing with a tuple value +.BR (nil,nil) . +The entries to return are those selected by an +.B offset +that is the index (origin 0) of the first directory entry to return, +and a +.B count +of a number of entries to return starting with that index. +Note that both values are expressed in units of directory entries, not as byte counts. +.PP +.B Styxserver +provides a +.B Navigator +adt to enable convenient access to this functionality; calls +into the +.B Navigator +adt are bundled up into requests on the channel, and the +reply returned. +The functions provided are: +.TP 10 +.BI Navigator.new( c ) +Create a new +.BR Navigator , +sending requests down +.IR c . +.TP +.IB t .stat(\fIpath\fP) +Find the file with the given +.IR path . +Return a tuple +.RI ( d ,\ err ), +where +.I d +holds directory information for the file +if found; otherwise +.I err +contains an error message. +.TP +.IB t .walk(\fIparent\fP,\ \fIname\fP) +Find the file with name +.I name +inside parent directory +.IR parent . +Return a tuple as for +.BR stat . +.TP +.IB t .readdir(\fIpath\fP,\ \fIoffset\fP,\ \fIcount\fP) +Return directory data read from directory +.IR path , +starting at entry +.I offset +for +.I count +entries. +.SS Other functions +The following functions provide some commonly used functionality: +.TP 10 +.BI readbytes( m ,\ d ) +Assuming that the file in question contains data +.IR d , +.B readbytes +returns an appropriate reply to +.IR read (5) +message +.IR m , +taking account of +.IB m .offset +and +.IB m.count +when extracting data from +.IR d . +.TP 10 +.BI readstr( m ,\ s ) +Assuming that the file in question contains string +.IR s , +.B readstr +returns an appropriate reply to +.IR read (5) +message +.IR m , +taking account of +.IB m .offset +and +.IB m.count +when extracting data from the UTF-8 representation of +.IR s . +.TP +.BI openok (\fIuname\fP,\ \fIomode\fP,\ \fIperm\fP,\ \fIfuid\fP,\ \fIfgid\fP) +Does standard permission checking, assuming user +.I uname +is trying to open a file with access mode +.IR omode , +where the file is owned by +.IR fuid , +has group +.IR fgid , +and permissions +.IR perm . +Returns true (non-zero) if permission would be granted, and false (zero) otherwise. +.TP +.BI openmode( o ) +Checks to see whether the open mode +.I o +is well-formed; if it is not, +.B openmode +returns -1; if it is, it returns the mode +with OTRUNC and ORCLOSE flags removed. +.TP +.BI traceset( on ) +If +.I on +is true (non-zero), +will trace Styx requests and replies, on standard error. +This option must be set before creating a +.BR Styxserver , +to ensure that it preserves its standard error descriptor. +.SS Constants +.B Styxservers +defines a number of constants applicable to the writing +of Styx servers, including: +.TP +.BR Einuse\fP,\fP\ Ebadfid\fP,\fP\ Eopen\fP,\fP\ Enotfound\fP,\fP\ Enotdir\fP,\fP\ Eperm\fP,\fP\ Ebadarg\fP,\fP\ Eexists +These provide standard strings for commonly used error conditions, +to be used in +.B Rmsg.Error +replies. +.SS Authentication +If authentication is required beyond that provided at the link level +(for instance by +.IR security-auth (2)), +the server application must handle +.B Tauth +itself, +remember the value of +.I afid +in that message, and generate an +.B Rauth +reply with a suitable Qid referring to a file with +.B Qid.qtype +of +.BR QTAUTH . +Following successful authentication by read and write on that file, +it must associate that status with the +.IR afid . +Then, on a subsequent +.B Tattach +message, before calling +.I srv .attach +it must check that the +.BR Tattach 's +.I afid +value corresponds to one previously authenticated, and +reply with an appropriate error if not. +.SH SOURCE +.B /appl/lib/styxservers.b +.SH SEE ALSO +.IR styxservers-nametree (2), +.IR sys-stat (2), +.IR intro (5) |
