123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786 |
- .TH 9P 2
- .SH NAME
- Srv,
- dirread9p,
- emalloc9p,
- erealloc9p,
- estrdup9p,
- postfd,
- postmountsrv,
- readbuf,
- readstr,
- respond,
- responderror,
- threadpostmountsrv,
- srv \- 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 (*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)
- 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* 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 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.
- .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
- Single-threaded servers, which always call
- .I respond
- before returning from the service functions,
- need not provide a
- .I flush
- implementation:
- .I flush
- is only necessary in multithreaded programs,
- which 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 ,
- 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 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 srv (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.
|