.TH 9P 2 .SH NAME Srv, dirread9p, emalloc9p, erealloc9p, estrdup9p, listensrv, postfd, postmountsrv, postsharesrv, readbuf, readstr, respond, responderror, srvacquire, srvrelease, threadlistensrv, threadpostmountsrv, threadpostsharesrv, srv \- 9P file service .SH SYNOPSIS .ft L .nf #include #include #include #include #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 void srv(Srv *s) void postmountsrv(Srv *s, char *name, char *mtpt, int flag) void postsharesrv(Srv *s, char *name, char *mtpt, char *desc) void threadpostmountsrv(Srv *s, char *name, char *mtpt, int flag) void threadpostsharesrv(Srv *s, char *name, char *mtpt, char *desc) 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) .fi .PP .nf .ft L .ta \w'\fLvoid* 'u void srvrelease(Srv *s) void srvacquire(Srv *s) .fi .PP .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 9pfid (2). .PP The behavior of .I srv depends on whether there is a file tree (see .IR 9pfile (2)) 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 .I rfork (see .IR fork (2)) or .I procrfork (see .IR thread (2)), 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 .I sysfatal (see .IR perror (2)). .PP .I Postsharesrv is similar to .I Postmountsrv but instead of mounting the service on a directory, it is put in a share (see .IR shr (3)) where .IB mtpt is the name of the share and .IB desc is the name of the service channel. .PP .I Listensrv and .I threadlistensrv create a separate process to announce as .IR addr . The process listens for incoming connections, creating a new process to serve each. Using these functions results in .I 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. .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 .I Responderror calls .I respond with the system error string (see .IR errstr (2)). .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 (see .IR 9pqueue (2)). .PP .I Srvrelease temporarily releases the calling process from the server loop and if neccesary spawns a new process to handle 9p requests. When released, the process can do blocking work that would otherwise halt processing of 9p requests. .I Srvacquire rejoins the calling process with the server loop after a srvrelease. .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 endsrv and then abort. .TP .I Auth If authentication is desired, the .I auth function should record that .IB r -> afid is the new authentication fid and set .IB r -> 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 (2)). .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. .IP 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 (5). When using file trees, .I srv will take care to check that the request satisfies the permissions outlined in .IR stat (5). 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 This gets called (from the forked service process) prior entering the 9P service loop. .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 (2)). .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 .IR Archfs (4), .IR cdfs (4), .IR nntpfs (4), .IR snap (4), and .B /sys/src/lib9p/ramfs.c are good examples of simple single-threaded file servers. .IR Webfs (4) and .I sshnet (see .IR ssh (1)) are good examples of multithreaded file servers. .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 /sys/src/lib9p .SH SEE ALSO .IR 9pfid (2), .IR 9pfile (2), .IR 9pqueue (2), .IR srv (3), .IR shr (3), .IR intro (5) .SH 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.