|
|
| |
9P(3) |
FreeBSD Library Functions Manual |
9P(3) |
Srv, dirread9p, emalloc9p, erealloc9p, estrdup9p, postfd, postmountsrv, readbuf,
readstr, respond, srv, threadpostmountsrv, walkandclone - 9P file service
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
typedef struct Srv {
Tree* tree;
void (*attach)(Req *r);
void (*auth)(Req *r);
void (*open)(Req *r);
void (*create)(Req *r);
void (*read)(Req *r);
void (*write)(Req *r);
void (*remove)(Req *r);
void (*flush)(Req *r);
void (*stat)(Req *r);
void (*wstat)(Req *r);
void (*walk)(Req *r);
char* (*walk1)(Fid *fid, char *name, Qid *qid);
char* (*clone)(Fid *oldfid, Fid *newfid);
void (*destroyfid)(Fid *fid);
void (*destroyreq)(Req *r);
void (*start)(Srv *s);
void (*end)(Srv *s);
void* aux;
int infd;
int outfd;
int srvfd;
int nopipe;
} Srv;
int srv(Srv *s)
void postmountsrv(Srv *s, char *name, char *mtpt, int flag)
void threadpostmountsrv(Srv *s, char *name, char *mtpt, int flag)
int postfd(char *srvname, int fd)
void respond(Req *r, char *error)
ulong readstr(Req *r, char *src)
ulong readbuf(Req *r, void *src, ulong nsrc)
typedef int Dirgen(int n, Dir *dir, void *aux)
void dirread9p(Req *r, Dirgen *gen, void *aux)
void walkandclone(Req *r, char *(*walk1)(Fid *old, char *name, void *v),
char *(*clone)(Fid *old, Fid *new, void *v), void *v)
void* emalloc9p(ulong n)
void* erealloc9p(void *v, ulong n)
char* estrdup9p(char *s)
extern int chatty9p;
The function srv serves a 9P session by reading requests from
s->infd, dispatching them to the function pointers kept in
Srv, and writing the responses to s->outfd. (Typically,
postmountsrv or threadpostmountsrv initializes the infd
and outfd structure members. See the description below.)
Req and Fid structures are allocated one-to-one with
uncompleted requests and active fids, and are described in
The behavior of srv depends on whether there is a file tree
(see associated with the server, that is, whether the tree element is
nonzero. The differences are made explicit in the discussion of the service
loop below. The aux element is the client's, to do with as it
pleases.
Srv does not return until the 9P conversation is finished.
Since it is usually run in a separate process so that the caller can exit,
the service loop has little chance to return gracefully on out of memory
errors. It calls emalloc9p, erealloc9p, and estrdup9p
to obtain its memory. The default implementations of these functions act as
malloc, realloc, and strdup but abort the program if
they run out of memory. If alternate behavior is desired, clients can link
against alternate implementations of these functions.
Postmountsrv and threadpostmountsrv are wrappers
that create a separate process in which to run srv. They do the
following:
- If s->nopipe is zero (the common case), initialize
s->infd and s->outfd to be
one end of a freshly allocated pipe, with s->srvfd
initialized as the other end.
- If name is non-nil, call
postfd(s->srvfd, name)
to post s->srvfd as
/srv/name.
- Fork a child process via or procrfork (see using the RFFDG,
RFNAMEG, and RFMEM flags. The child process calls
close(s->srvfd) and then
srv(s); it will exit once srv
returns.
- If mtpt is non-nil, call
amount(s->srvfd, mtpt,
flag, ""); otherwise, close
s->srvfd.
- The parent returns to the caller.
If any error occurs during this process, the entire process is
terminated by calling
The functions in a Srv structure named after 9P transactions are called
to satisfy requests as they arrive. If a function is provided, it must
arrange for respond to be called when the request is satisfied. The
only parameter of each service function is a Req* parameter (say
r). The incoming request parameters are stored in
r->ifcall; r->fid and
r->newfid are pointers to Fid structures
corresponding to the numeric fids in r->ifcall;
similarly, r->oldreq is the Req structure
corresponding to r->ifcall.oldtag. The outgoing
response data should be stored in r->ofcall.
The one exception to this rule is that stat should fill in
r->d rather than
r->ofcall.stat: the library will convert the
structure into the machine-independent wire representation. Similarly,
wstat may consult r->d rather than decoding
r->ifcall.stat itself. When a request
has been handled, respond should be called with r and an error
string. If the request was satisfied successfully, the error string should be
a nil pointer. Note that it is permissible for a function to return without
itself calling respond, as long as it has arranged for respond
to be called at some point in the future by another proc sharing its address
space, but see the discussion of flush below. Once respond has
been called, the Req* as well as any pointers it once contained must be
considered freed and not referenced.
If the service loop detects an error in a request (e.g., an
attempt to reuse an extant fid, an open of an already open fid, a read from
a fid opened for write, etc.) it will reply with an error without consulting
the service functions.
The service loop provided by srv (and indirectly by
postmountsrv and threadpostmountsrv) is single-threaded. If it
is expected that some requests might block, arranging for alternate
processes to handle them is suggested.
The constraints on the service functions are as follows. These
constraints are checked while the server executes. If a service function
fails to do something it ought to have, srv will call end and
then abort.
- Auth
- If authentication is desired, the auth function should record that
afid is the new authentication fid and set afid->qid and
ofcall.qid. Auth may be nil, in which case it will be
treated as having responded with the error ``argv0: authentication not
required,'' where argv0 is the program name variable as set by
ARGBEGIN (see
- Attach
- The attach function should check the authentication state of
afid if desired, and set
r->fid->qid and ofcall.qid
to the qid of the file system root. Attach may be nil only if file
trees are in use; in this case, the qid will be filled from the root of
the tree, and no authentication will be done.
- Walk
- If file trees are in use, walk is handled internally, and
srv->walk is never called.
- If file trees are not in use, walk should consult
r->ifcall.wname and
r->ifcall.nwname, filling in
ofcall.qid and
ofcall.nqid, and also copying any necessary
aux state from r->fid to
r->newfid when the two are different. As long as
walk sets ofcall.nqid appropriately, it can
respond with a nil error string even when 9P demands an error
(e.g., in the case of a short walk); the library detects error
conditions and handles them appropriately.
- Because implementing the full walk message is intricate and prone to
error, the helper routine walkandclone will handle the request
given pointers to two functions walk1 and (optionally) clone
. Clone, if non-nil, is called to signal the creation of
newfid from oldfid. Typically a clone routine will
copy or increment a reference count in oldfid's aux element.
Walk1 should walk fid to name, initializing
fid->qid to the new path's qid. Both should return
nil on success or an error message on error. Walkandclone will call
respond after handling the request.
- Walk1, Clone
- If the client provides functions srv->walk1 and
(optionally) srv->clone, the 9P service
loop will call walkandclone with these functions to handle the
request. Unlike the walk1 above, srv->walk1
must fill in both fid->qid and *qid
with the new qid on a successful walk.
- Open
- If file trees are in use, the file metadata will be consulted on open,
create, remove, and wstat to see if the requester has the appropriate
permissions. If not, an error will be sent back without consulting a
service function.
If not using file trees or the user has the appropriate
permissions, open is called with
r->ofcall.qid already initialized to
the one stored in the Fid structure (that is, the one returned in the
previous walk). If the qid changes, both should be updated.
- Create
- The create function must fill in both
r->fid->qid and
r->ofcall.qid on success. When using
file trees, create should allocate a new File with
createfile; note that createfile may return nil (because,
say, the file already exists). If the create function is nil,
srv behaves as though it were a function that always responded with
the error ``create prohibited''.
- Remove
- Remove should mark the file as removed, whether by calling
removefile when using file trees, or by updating an internal data
structure. In general it is not a good idea to clean up the aux
information associated with the corresponding File at this time, to
avoid memory errors if other fids have references to that file. Instead,
it is suggested that remove simply mark the file as removed (so
that further operations on it know to fail) and wait until the file tree's
destroy function is called to reclaim the aux pointer. If not using
file trees, it is prudent to take the analogous measures. If remove
is not provided, all remove requests will draw ``remove prohibited''
errors.
- Read
- The read function must be provided; it fills
r->ofcall.data with at most
r->ifcall.count bytes of data from
offset r->ifcall.offset of the file.
It also sets r->ofcall.count to the
number of bytes being returned. If using file trees, srv will
handle reads of directories internally, only calling read for
requests on files. Readstr and readbuf are useful for
satisfying read requests on a string or buffer. Consulting the request in
r->ifcall, they fill
r->ofcall.data and set
r->ofcall.count; they do not
call respond. Similarly, dirread9p can be used to
handle directory reads in servers not using file trees. The passed
gen function will be called as necessary to fill dir with
information for the nth entry in the directory. The string pointers
placed in dir should be fresh copies made with estrdup9p;
they will be freed by dirread9p after each successful call to
gen. Gen should return zero if it successfully filled
dir, minus one on end of directory.
- Write
- The write function is similar but need not be provided. If it is
not, all writes will draw ``write prohibited'' errors. Otherwise,
write should attempt to write the
r->ifcall.count bytes of
r->ifcall.data to offset
r->ifcall.offset of the file,
setting r->ofcall.count to the
number of bytes actually written. Most programs consider it an error to
write less than the requested amount.
- Stat
- Stat should fill r->d with the stat
information for r->fid. If using file
trees, r->d will have been initialized with the
stat info from the tree, and stat itself may be nil.
- Wstat
- The wstat consults r->d in changing the
metadata for r->fid as described in
stat(9p). When using file trees, srv will take care to check
that the request satisfies the permissions outlined in stat(9p).
Otherwise wstat should take care to enforce permissions where
appropriate.
- Flush
- Servers that always call respond before returning from the service
functions need not provide a flush implementation: flush is
only necessary in programs that arrange for respond to be called
asynchronously. Flush should cause the request
r->oldreq to be cancelled or hurried along. If
oldreq is cancelled, this should be signalled by calling
respond on oldreq with error string `interrupted'.
Flush must respond to r with a nil error string.
Flush may respond to r before forcing a response to
r->oldreq. In this case, the library will
delay sending the Rflush message until the response to
r->oldreq has been sent.
Destroyfid, destroyreq, start, and end
are auxiliary functions, not called in direct response to 9P requests.
- Destroyfid
- When a Fid's reference count drops to zero (i.e., it has
been clunked and there are no outstanding requests referring to it),
destroyfid is called to allow the program to dispose of the
fid->aux pointer.
- Destroyreq
- Similarly, when a Req's reference count drops to zero (i.e.,
it has been handled via respond and other outstanding pointers to
it have been closed), destroyreq is called to allow the program to
dispose of the r->aux pointer.
- Start
- Before the 9P service loop begins, the service proc calls start so
that the server can run any initialization that must be done from inside
the service proc.
- End
- Once the 9P service loop has finished (end of file been reached on the
service pipe or a bad message has been read), end is called (if
provided) to allow any final cleanup. For example, it was used by the Palm
Pilot synchronization file system (never finished) to gracefully terminate
the serial conversation once the file system had been unmounted. After
calling end, the service loop (which runs in a separate process
from its caller) terminates using _exits (see
If the chatty9p flag is at least one, a transcript of the
9P session is printed on standard error. If the chatty9p flag is
greater than one, additional unspecified debugging output is generated. By
convention, servers written using this library accept the -D option
to increment chatty9p.
/src/lib9p/ramfs.c is an example of a simple single-threaded file server.
On Plan 9, see archfs, cdfs, nntpfs, webfs, and
sshnet for more examples.
In general, the File interface is appropriate for
maintaining arbitrary file trees (as in ramfs). The File
interface is best avoided when the tree structure is easily generated as
necessary; this is true when the tree is highly structured (as in
cdfs and nntpfs) or is maintained elsewhere.
Visit the GSP FreeBSD Man Page Interface. Output converted with ManDoc. |