9P(2)9P(2)NAME
Srv, dirread9p, emalloc9p, erealloc9p, estrdup9p, listensrv, postfd,
postmountsrv, readbuf, readstr, respond, responderror, threadlistensrv,
threadpostmountsrv, srv - 9P file service
SYNOPSIS
#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 (*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)
void listensrv(Srv *s, char *addr)
void threadlistensrv(Srv *s, char *addr)
int postfd(char *srvname, int fd)
void respond(Req *r, char *error)
void responderror(Req*)
void readstr(Req *r, char *src)
void readbuf(Req *r, void *src, long 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;
DESCRIPTION
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 9pfid(2).
The behavior of srv depends on whether there is a file tree (see
9pfile(2)) associated with the server, that is, whether the tree ele‐
ment 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 ser‐
vice 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 rfork (see fork(2)) or procrfork (see
thread(2)), 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, ""); oth‐
erwise, close s->srvfd.
The parent returns to the caller.
If any error occurs during this process, the entire process is termi‐
nated by calling sysfatal (see perror(2)).
Listensrv and threadlistensrv create a separate process to announce as
addr. The process listens for incoming connections, creating a new
process to serve each. Using these functions results in srv and the
service functions being run in multiple processes simultaneously. The
library locks its own data structures as necessary; the client may need
to lock data it shares between the multiple connections.
Service functions
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 corre‐
sponding 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 con‐
vert 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.
Responderror calls respond with the system error string (see
errstr(2)).
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 con‐
straints are checked while the server executes. If a service function
fails to do something it ought to have, srv will call endsrv and then
abort.
Auth If authentication is desired, the auth function should record
that r->afid is the new authentication fid and set r->afid->qid
and ofcall.qid. Auth may be nil, in which case it will be
treated as having responded with the error ``argv0: authentica‐
tion not required,'' where argv0 is the program name variable as
set by ARGBEGIN (see arg(2)).
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 permis‐
sions, 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 cre‐
ate 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 pru‐
dent 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.off‐
set 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. Oth‐
erwise, write should attempt to write the r->ifcall.count bytes
of r->ifcall.data to offset r->ifcall.offset of the file, set‐
ting 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(5). When using file trees, srv will take care
to check that the request satisfies the permissions outlined in
stat(5). Otherwise wstat should take care to enforce permis‐
sions where appropriate.
Flush Servers that always call respond before returning from the ser‐
vice 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, 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.
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 ser‐
vice loop (which runs in a separate process from its caller)
terminates using _exits (see exits(2)).
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.
EXAMPLESArchfs(4), cdfs(4), nntpfs(4), snap(4), and /sys/src/lib9p/ramfs.c are
good examples of simple single-threaded file servers. Webfs(4) and
sshnet (see ssh(1)) are good examples of multithreaded file servers.
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.
SOURCE
/sys/src/lib9p
SEE ALSO9pfid(2), 9pfile(2), srv(3), intro(5)BUGS
The switch to 9P2000 was taken as an opportunity to tidy much of the
interface; we promise to avoid such gratuitous change in the future.
9P(2)