9P(2) 9P(2)
NAME
Srv, chatty9p, dirread9p, emalloc9p, erealloc9p, estrdup9p,
listensrv, postmountsrv, postsharesrv, postsrv, readbuf,
readstr, respond, responderror, srv, srvacquire, srvforker,
srvrelease, threadlistensrv, threadpostmountsrv,
threadpostsharesrv, threadpostsrv, threadsrv,
threadsrvforker, auth9p, authattach, authread, authwrite -
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 (*start)(Srv *s);
void (*end)(Srv *s);
void* aux;
int infd;
int outfd;
void (*forker)(void (*fn)(void*), void *arg, int flags);
} Srv;
void srv(Srv *s)
int postsrv(Srv *s, char *name);
void postmountsrv(Srv *s, char *name, char *mtpt, int flag)
void postsharesrv(Srv *s, char *name, char *mtpt, char *desc)
Page 1 Plan 9 (printed 10/29/25)
9P(2) 9P(2)
void listensrv(Srv *s, char *addr)
void threadsrv(Srv *s)
int threadpostsrv(Srv *s, char *name);
void threadpostmountsrv(Srv *s, char *name, char *mtpt, int flag)
void threadpostsharesrv(Srv *s, char *name, char *mtpt, char *desc)
void threadlistensrv(Srv *s, char *addr)
void srvforker(void (*fn)(void*), void *arg, int flags)
void threadsrvforker(void (*fn)(void*), void *arg, int flags)
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 srvrelease(Srv *s)
void srvacquire(Srv *s)
void* emalloc9p(ulong n)
void* erealloc9p(void *v, ulong n)
char* estrdup9p(char *s)
extern int chatty9p;
void auth9p(Req *r);
int authattach(Req *r);
void authread(Req *r);
void authwrite(Req *r);
DESCRIPTION
The function srv and threadsrv serve 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 uncom-
pleted 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 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
Page 2 Plan 9 (printed 10/29/25)
9P(2) 9P(2)
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.
The functions srvforker and threadsrvforker handle the cre-
ation of new processes on a connection which use rfork (see
fork(2)) or procrfork (see thread(2)).
Postsrv and threadpostsrv are wrappers that create a sepa-
rate process in which to run srv. They do the following:
Initialize s->infd and s->outfd to be one end of a
freshly allocated pipe.
If name is non-nil, post the other end file descriptor
under the name /srv/name.
Initialize s->forker to either srvforker or
threadsrvforker unless already initialized to a non-nil
value.
Fork a child process via s->forker using the RFPROC,
RFNOWAIT, RFNAMEG, RFNOTEG and RFMEM flags. This iso-
lates the service loop from the callers namespace and
from notes posted to the callers note group but shares
data and bss segments.
The child process then waits for the parent to copy its
file descriptor table via rfork using RFFDG flag. This
way, the service loop will share the original file
descriptor table with previously created child pro-
cesses of the caller.
The child process then closes the other end file
descriptor and calls srv.
The parent process returns from the function with the
mountable file descriptor sfd. On error, postsrv and
threadpostsrv return a file descriptor of -1 with error
string set.
Postmountsrv and threadpostmntsrv call postsrv with name and
then if mtpt is non-nil, call amount(sfd, mtpt, flag, "");
otherwise, close the file descriptor. If any error occurs
during this process, the entire process is terminated by
calling sysfatal (see perror(2)).
Postsharesrv is similar to Postmountsrv but instead of
Page 3 Plan 9 (printed 10/29/25)
9P(2) 9P(2)
mounting the service on a directory, it is put in a share
(see shr(3)) where mtpt is the name of the share and desc is
the name of the service channel.
Listensrv and threadlistensrv create a separate process to
announce as addr. The process listens for incoming connec-
tions, 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 func-
tion 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 outgo-
ing 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 func-
tion 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 func-
tions.
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 (see
9pqueue(2)).
Page 4 Plan 9 (printed 10/29/25)
9P(2) 9P(2)
Srvrelease temporarily releases the calling process from the
server loop and if necessary spawns a new process to handle
9p requests. When released, the process can do blocking work
that would otherwise halt processing of 9p requests.
Srvacquire rejoins the calling process with the server loop
after a srvrelease.
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 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: authentication 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 neces-
sary aux state from r->fid to r->newfid when the two
are different. As long as walk sets ofcall.nqid appro-
priately, 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 ref-
erence 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.
Page 5 Plan 9 (printed 10/29/25)
9P(2) 9P(2)
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 suc-
cessful 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 updat-
ing 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 mem-
ory 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 func-
tion 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.
Page 6 Plan 9 (printed 10/29/25)
9P(2) 9P(2)
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 han-
dle 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 ini-
tialized with the stat info from the tree, and stat
itself may be nil.
Wstat
The wstat function consults r->d in changing the meta-
data 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 permissions
where appropriate.
Flush
Servers that always call respond before returning from
the service functions need not provide a flush imple-
mentation: flush is only necessary in programs that
arrange for respond to be called asynchronously. Flush
should cause the request r->oldreq to be canceled or
hurried along. If oldreq is canceled, this should be
signaled 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 func-
tions, not called in direct response to 9P requests.
Page 7 Plan 9 (printed 10/29/25)
9P(2) 9P(2)
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 out-
standing pointers to it have been closed), destroyreq
is called to allow the program to dispose of the r->aux
pointer.
Start
This gets called (from the forked service process)
prior entering the 9P service loop.
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 grace-
fully 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)).
Auth9p, authattach, authwrite, and authread are functions to
assist in the creation of authenticated file servers.
Auth9p sets afid to point to /mnt/factotum/rpc then calls
respond. It can be used as the auth service function
address. Authattach will return 0 if the session has prop-
erly authenticated or will return -1 and call respond with
an appropriate error. Authread and authwrite can be called
from the read and write service functions respectfully to
handle calls on the afid.
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.
EXAMPLES
Archfs(4), cdfs(4), nntpfs(4), snap(4), and
/sys/src/cmd/ramfs.c are good examples of simple single-
threaded file servers.
In general, the File interface is appropriate for maintain-
ing 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
Page 8 Plan 9 (printed 10/29/25)
9P(2) 9P(2)
structured (as in cdfs and nntpfs) or is maintained else-
where.
SOURCE
/sys/src/lib9p
SEE ALSO
9pfid(2), 9pfile(2), 9pqueue(2), srv(3), shr(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.
Page 9 Plan 9 (printed 10/29/25)