summaryrefslogtreecommitdiff
path: root/man/2/styxservers
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 20:52:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 20:52:35 +0000
commit46439007cf417cbd9ac8049bb4122c890097a0fa (patch)
tree6fdb25e5f3a2b6d5657eb23b35774b631d4d97e4 /man/2/styxservers
parent37da2899f40661e3e9631e497da8dc59b971cbd0 (diff)
20060303-partial
Diffstat (limited to 'man/2/styxservers')
-rw-r--r--man/2/styxservers902
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)