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