9P(2) 9P(2)
NAME
Fid, File, Req, Srv, Tree, allocmap, allocfid, allocfidpool,
allocreq, allocreqpool, caninsertkey, closefid, deletekey,
fcreate, freefid, freemap, freereq, fremove, fwalk, mktree,
fdirread, insertkey, lookupfid, lookupkey, lookupreq, srv,
postmountsrv, readbuf, readstr, respond, threadpostmountsrv,
_lib9p_emalloc, _lib9p_erealloc, _lib9p_estrdup - 9P file
server functions
SYNOPSIS
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
typedef struct Fid
{
ulong fid;
char omode;/* -1 if not open */
char uid[NAMELEN];
Qid qid;
File *file;
Ref ref;
void *aux;
...
} Fid;
typedef struct Req
{
ulong tag;
Ref ref;
void *aux;
...
} Req;
typedef struct File
{
Dir;
File*parent;
Refref;
void*aux;
...
} File;
typedef struct Tree
{
File*root;
void(*rmaux)(File *file);
Page 1 Plan 9 (printed 3/7/26)
9P(2) 9P(2)
...
} Tree;
Tree* mktree(char *uid, char *gid, ulong perm)
File* fcreate(File *dir, char *name, char *uid, char *gid, ulong perm)
int fremove(File *file)
void fclose(File *file)
File* fwalk(File *file, char *name)
char* fdirread(File *dir, char *buf, long *n, vlong off)
typedef struct Srv {
Tree *tree;
void (*session)(Req *req, char *id, char *dom, char *chal);
void (*attach)(Req *req, Fid *fid, char *spec, Qid *qid);
void (*clone) (Req *req, Fid *old, Fid *new);
void (*walk) (Req *req, Fid *fid, char *name, Qid *qid);
void (*open) (Req *req, Fid *fid, int omode, Qid *qid);
void (*create)(Req *req, Fid *fid, char *name, int omode,
ulong perm, Qid *qid);
void (*remove)(Req *req, Fid *fid);
void (*read) (Req *req, Fid *fid, void *buf,
long *count, vlong offset);
void (*write) (Req *req, Fid *fid, void *buf,
long *count, vlong offset);
void (*stat) (Req *req, Fid *fid, Dir *d);
void (*wstat) (Req *req, Fid *fid, Dir *d);
void (*flush) (Req *req, Req *oldreq);
void (*clunkaux)(Fid *fid);
} Srv;
void srv(Srv *s, int fd)
void postmountsrv(Srv *s, char *srvname, char *mtpt, int flag)
void threadpostmountsrv(Srv *s, char *srvname, char *mtpt, int flag)
void respond(Req *req, char *error)
void readstr(vlong offset, void *dst, long *ndst, char *src)
void readbuf(vlong offset, void *dst, long *ndst, void *src, long nsrc)
void* _lib9p_emalloc(ulong sz)
void* _lib9p_erealloc(void *ptr, ulong newsz)
char* _lib9p_estrdup(char *str)
Intmap* allocmap(void (*inc)(void*))
void freemap(Intmap *map)
void* lookupkey(Intmap *map, ulong key)
void* insertkey(Intmap *map, ulong key, void *val)
int caninsertkey(Intmap *map, ulong key, void *val)
void* deletekey(Intmap *map, ulong key)
Fidpool* allocfidpool(void)
void freefidpool(Fidpool *p)
Fid* allocfid(Fidpool *p, ulong f)
void freefid(Fid *f)
Page 2 Plan 9 (printed 3/7/26)
9P(2) 9P(2)
void closefid(Fid *f)
Fid* lookupfid(Fidpool *p, ulong f)
Reqpool* allocreqpool(void)
void freereqpool(Reqpool *p)
Req* allocreq(Reqpool *p, ulong tag)
void freereq(Req *r)
void closereq(Req *r)
Req* lookupreq(Reqpool *p, ulong tag)
DESCRIPTION
These routines provide a library for writing 9P file
servers.
Fid data structures are allocated one-to-one with active
fids in the served 9P connection. They are analogous to
Chan structures in the Plan 9 kernel. The fid element is
the integer fid used in the 9P connection. Omode is the
mode under which the fid was opened, or -1 if this fid has
not been opened yet. Note that in addition to the values
OREAD, OWRITE, and ORDWR, omode can contain the various
flags permissible in an open call. To ignore the flags, use
omode&OMASK. Omode should not be changed by the client.
Uid contains the name of the user who has authenticated in
order to obtain this fid. Qid is set to the last qid
returned by an attach, walk, or open function (q.v.). The
file element is explained below. The aux element belongs to
the client, and may be used to store a per-Fid data pointer.
Req data structures are allocated one-to-one with outstand-
ing 9P requests. They contain the tag of the request as
well as an aux element that may be used by the client to
store a per-Req data pointer (often useful for multithreaded
servers).
The File and Tree structures provide an in-memory file hier-
archy that can be used to handle stat, walk, and open
requests. If being used, the library will keep the Fid's
file element pointing at the appropriate File structure as
it is walked over the tree. As with the other structures,
the aux element may be used by the client to store a
per-File data pointer.
The Fid, File, and Req structures are garbage collected by
reference counting, so that (for example) clunking a fid
will not free it while another request using that fid is
still pending.
When creating a new reference by copying a pointer, the
count should be incremented with incref. When a Fid is col-
lected, the clunkaux function of the Srv structure
(described below) is called to collect the pointer stored in
Page 3 Plan 9 (printed 3/7/26)
9P(2) 9P(2)
aux. Similarly, when a File is collected, the rmaux func-
tion in the Tree structure is called to claim the aux
pointer. No such function is called when collecting a Req
structure: the aux pointer should be removed before calling
respond (described below). To destroy a reference to a Fid,
File, or Req, call closefid, fclose, or closereq, respec-
tively.
Mktree creates a new file tree whose root has owner uid,
group gid, and permissions perm. It returns a reference to
that file. Fcreate creates and returns a reference to a new
file called name in the directory dir. The file is owned by
user uid, group gid, and has permissions perm. If a file of
the same name already exists in the directory, fcreate
returns zero. Otherwise it returns a pointer to the newly
created File structure. Fremove removes file from its
directory. If file is itself a directory that is not empty
or is the root, it is not removed, and fremove returns -1.
Otherwise fremove returns zero. If removing the file from
its directory causes the reference count to go to zero, the
file is collected and rmaux is called. Fwalk returns a new
reference to the File named name in the directory dir. If
no such file exists, it returns zero. It does not decrement
dir's reference count. Fdirread fills buf with at most n
bytes of entries from the directory dir beginning at offset
offset. Note that the use of file trees is not required; it
is provided as a convenience.
To start a file server, one must fill in a Srv structure
with pointers to the functions satisfying 9P requests. As
explained below, in almost all cases, using a nil function
pointer results in sensible default behavior. If the tree
pointer is non-zero, that file tree is used as described
below. Calling srv with such a structure and a file
descriptor causes it to serve 9P on that file descriptor.
It does not return until the 9P conversation terminates. In
contrast, postmountsrv forks off a 9P server and returns.
Before returning, if srvname is not zero, the service is
posted in /srv/srvname (see srv(3)). If mtpt is not zero,
the service is mounted at mtpt with mount flag flag.
Threadpostmountsrv is similar but intended for use in pro-
grams that use the thread(2) library for process creation.
The functions registered in the Srv structure must conform
to the following requirements. The first argument of each
function is a pointer to a Req that provides context to the
library for responding to the request. If a function is
provided, it must arrange for respond to be called when the
request is satisfied. The first argument to respond should
be the Req pointer; the second is an error string. If the
request was satisfied successfully, the error string should
be a nil pointer. Note that it is permissible for a
Page 4 Plan 9 (printed 3/7/26)
9P(2) 9P(2)
function to return without calling respond, as long as it
has arranged for respond to be called at some point in the
future, perhaps by another proc sharing its address space,
but see the discussion of flush below. Once respond has
been called, the function's pointer arguments must not be
dereferenced, as they may point at freed memory.
If the library 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), it will reply with
an error without consulting any of the registered functions.
The session function should fill id, dom, and chal with the
authentication id and domain of the server, and a challenge,
as described in attach(5). Before calling session, the
library zeros these fields. Leaving any or all of them zero
is permissible. Session may be nil, indicating no authenti-
cation information.
The attach function should check authentication information
if desired, and fill in qid with the qid of the file system
root. Attach may be nil only if file trees are being used,
in which case the qid will be filled in from the tree, and
no authentication will be done.
When a fid is cloned, the library simply copies the aux
pointer from the old Fid to create the new one. If further
processing is desired, a non-nil clone function will be
called after this copying has been done. A typical use of
this function might be to increment a reference count in the
structure pointed at by aux.
If file trees are being used, the 9P server will react to a
walk message by attempting to walk the Fid's file. If this
fails, a ``file not found'' error is sent back. Otherwise
the Fid's file and qid elements are updated. If file trees
are in use, the walk function is never called. If file
trees are not in use, a walk function must be provided.
Clwalk messages are translated by the library into a clone
followed (when successful) by a walk; the library's client
need not worry about them.
If file trees are being used, the file metadata will be con-
sulted on open, create, and remove to see if the requester
has the appropriate permissions. If not, an error will be
sent back without calling a registered function.
If file trees are not in use or the user has the appropriate
permissions, open is called with the fid being opened, the
open mode, and a pointer to a qid to be filled in. The qid
defaults to the one stored in the fid structure. If file
Page 5 Plan 9 (printed 3/7/26)
9P(2) 9P(2)
trees are not in use, an open function must be provided.
The create function is passed the fid for the current direc-
tory, as well as the name, mode, and permissions for the
file to be created. It must fill in the qid on success, and
must allocate the new File with fcreate when file trees are
in use. Note that the create function must allow for the
possibility of fcreate returning nil. If create is nil, a
``creation disallowed'' error will be sent instead.
The remove function is called on a request to remove the
file associated with a Fid. If using file trees, remove
must call fremove itself. If remove is nil, a ``remove dis-
allowed'' error will be sent instead. The library correctly
detects 9P requests on removed files (via other fid refer-
ences), and returns appropriate errors.
The read function must be provided; it fills buf with at
most *n bytes of data from offset offset of the file. It
also sets *n to the number of bytes being returned. If
using file trees, the library will handle reads of directo-
ries: read will only be called for requests on files.
Readstr and readbuf are useful for satisfying read requests
on a string or buffer.
The write function is similar, but need not be provided: a
``write disallowed'' message will be sent if write is nil.
Otherwise, write should attempt to write the *n bytes of buf
to offset offset of the file, leaving in *n the number of
bytes actually written.
The stat function should fill in dir with the stat info for
fid. If using file trees, dir will be initialized with the
stat info from the tree, and stat itself may be nil.
The wstat function takes a fid and a new Dir structure for
it, as well as a bitmask specifying which fields to update.
Other fields in the Dir structure should be ignored. If
using file trees and wstat is successful, the corresponding
file's Dir structure will be updated. It is permissible for
wstat to be nil, in which case all wstats will fail with the
error message ``wstat disallowed''.
The flush function is called to cancel the outstanding
request oldreq. In single-threaded servers, it is safe to
not supply such a function. In multithreaded servers, the
client must guarantee that once respond has been called for
req, respond will not be called for oldreq.
The actual 9P service loop provided by srv (and indirectly
by postmountsrv and threadpostmountsrv) is a single thread
of execution. If it is expected that some requests might
Page 6 Plan 9 (printed 3/7/26)
9P(2) 9P(2)
block, arranging for alternate processes is suggested.
Implementation
The rest of the text of this manual page describes the
structures used to implement the library. This is useful
for some applications, but most users need not concern them-
selves with it.
The library uses internally the functions _lib9p_emalloc,
_lib9p_erealloc, and _lib9p_estrdup, which are like malloc,
realloc, and strdup, but call abort(2) rather than returning
zero on error. If alternate behavior is desired, one can
link against replacements for all three.
An Intmap is a arbitrary mapping from integers to pointers.
Allocmap creates a new one, and freemap destroys it. New
entries are added to the map by calling insertkey, which
will return the previous value associated with the given id,
or zero if there was no previous value. Before inserting
the value, the inc function used when creating the map is
called with the new value; typically this increments a ref-
erence count to reflect the creation of the new reference
held by the map. Caninsertkey is similar, but only inserts
the entry if no entry for id already exists. It returns 1
if the entry was inserted, and 0 otherwise. Lookupkey
returns the pointer associated with id, or zero if there is
no such pointer. As with the insertion routines, inc is
called on the pointer before it is returned. The reference
count must be incremented by these routines rather than
their callers to avoid the entry being deleted between func-
tion return and reference increment. Deletekey removes the
entry for id from the map, returning the associated pointer,
if any.
Intmaps are used to implement Fidpools and Reqpools, which
are allocation pools for Fids and Reqs. Allocfidpool cre-
ates a new fid pool, and freefidpool destroys one. Allocfid
returns a reference to a new Fid structure with identifier
f. If a structure with that identifier has already been
allocated, allocfid returns zero. Closefid destroys a ref-
erence to a Fid but leaves it allocated. Freefid deallo-
cates a Fid and destroys the passed reference. When the
reference count goes to zero, clunkaux will be called on
that particular Fid structure. Lookupfid returns a refer-
ence to the Fid structure identified with f, or zero if
there is no such structure.
Allocreqpool, freereqpool, allocreq, closereq, freereq, and
lookupreq behave similarly, manipulating request pools.
EXAMPLES
The file servers archfs(4), cdfs(4), snap(4), and aux/olefs
Page 7 Plan 9 (printed 3/7/26)
9P(2) 9P(2)
(see doc2txt(1)) are examples of simple single-threaded file
servers written using this library. Unlike the others, cdfs
does not use the File interface but instead creates its
directory entries on the fly.
SOURCE
/sys/src/lib9p
SEE ALSO
srv(3), intro(5)
BUGS
The library is new and not particularly well exercised; send
bug reports to rsc@plan9.bell-labs.com.
Page 8 Plan 9 (printed 3/7/26)