diff --git a/doc/man-pages/pod1/cmdebug.pod b/doc/man-pages/pod1/cmdebug.pod new file mode 100644 index 0000000000..36d981d2a1 --- /dev/null +++ b/doc/man-pages/pod1/cmdebug.pod @@ -0,0 +1,104 @@ +=head1 NAME + +cmdebug - Reports the status of a host Cache Manager + +=head1 SYNOPSIS + +B B<-servers> > [B<-port> >] + [B<-long>] [B<-refcounts>] [B<-callbacks>] [B<-addrs>] [B<-cache>] + +B B<-s> > [B<-p> >] [B<-l>] [B<-r>] [B<-c>] + [B<-a>] [B<-h>] + +=head1 DESCRIPTION + +The B command displays information about the Cache Manager and +client cache status on an AFS client machine. By default, it displays all +locked cache entries, but other information can be requested via various +options. + +=head1 OPTIONS + +=over 4 + +=item B<-servers> > + +Names the client machine for which to display Cache Manager status. +Provide the machine's IP address in dotted decimal format, its fully +qualified host name (for example, B), or the shortest +abbreviated form of its host name that distinguishes it from other +machines. Successful use of an abbreviated form depends on the +availability of a name resolution service (such as the Domain Name Service +or a local host table) at the time the command is issued. + +=item B<-port> > + +Identifies the port on which to contact the Cache Manager. By default, +the standard port 7001 is used, so this option is very rarely needed. + +=item B<-long> + +Reports on all lock statuses and all cache entries, rather than only +locked cache entries. Do not use this option with B<-refcounts>, +B<-callbacks>, B<-addrs>, or B<-cache>. + +=item B<-refcounts> + +Reports only those cache entries with non-zero reference counts. Do not +use this option with B<-long>, B<-callbacks>, B<-addrs>, or B<-cache>. + +=item B<-callbacks> + +Reports only those cache entries with callbacks. Do not use this option +with B<-long>, B<-refcounts>, B<-addrs>, or B<-cache>. + +=item B<-addrs> + +Rather than showing any cache entries, displays the interfaces the Cache +Manager answers on, including their netmasks and MTUs. This is useful for +analyzing clients that are multihomed and identifying problems with +netmasks or MTU settings. Do not use this option with B<-long>, +B<-refcounts>, B<-callbacks>, or B<-cache>. + +=item B<-cache> + +Rather than showing any cache entries, displays the cache configuration +for the client machine. The information displayed is essentially the +information that can be configured via parameters to B. Do not use +this option with B<-long>, B<-refcounts>, B<-callbacks>, or B<-addrs>. + +=item B<-help> + +Prints the online help for this command. All other valid options are +ignored. + +=back + +=head1 EXAMPLES + +Displays all of the locked cache entries on C: + + % cmdebug client1 + +Displays the cache configuration for C: + + % cmdebug client1.abc.com -cache + +Displays all cache entries for C: + + % cmdebug client2.abc.com -long + +=head1 PRIVILEGE REQUIRED + +None + +=head1 SEE ALSO + +L + +=head1 COPYRIGHT + +Copyright 2005 Russ Allbery + +This documentation is covered by the IBM Public License Version 1.0. This +man page was written by Russ Allbery for OpenAFS. diff --git a/doc/man-pages/pod1/rxgen.pod b/doc/man-pages/pod1/rxgen.pod new file mode 100644 index 0000000000..d012f0ee32 --- /dev/null +++ b/doc/man-pages/pod1/rxgen.pod @@ -0,0 +1,1463 @@ +=head1 NAME + +rxgen - Stub generator for the Rx remote procedure call package + +=head1 SYNOPSIS + +B [B<-h> | B<-c> | B<-C> | B<-S> | B<-r>] [B<-dkpR>] + [B<-I> I] [B<-P> I] [B<-o> I] [I] + +B B<-s> I [B<-o> I] [I] + +B B<-l> [B<-o> I] [I] + +B B<-m> [B<-o> I] [I] + +=head1 DESCRIPTION + +B is a tool that generates C code to implement the Rx RPC protocol; +it takes as input a description of an application interface similar to C +and produces a number of server and/or client stub routines to be linked +with RPC-based programs. These stubs allow programs to invoke remote +procedures through local procedure calls. B is an extension of +Sun's B (version 3.9) and retains full B functionality (at +least as of that version). Please refer to rpcgen(1) for more details on +the Sun's RPC specific flags, and to the RPC programming guide regarding +the RPC language along with useful examples. + +=head1 OPTIONS + +B operates in several different modes. The generated output files +can be produced individually (using one of B<-h>, B<-c>, B<-C>, or B<-S>) +or collectively. All output files are created when the default is used +(i.e., no options), or the output is limited to the server stubs (B<-C> +and B<-S>) when the B<-r> flag is used. The following describes the types +of generated output files (for simplicity, I refers to the main +output filename): + +=over 4 + +=item B<-h> + +Generate C data definitions (a header file) from standard RPCL definitions +(default extension: I.h). + +=item B<-c> + +Compile the XDR routines required to serialize the protocol described by +RPCL. Generate XDR routines for all declarations (default extension: +I.xdr.c). + +=item B<-C> + +Generate all the client-side stub routines (default extension: +I.cs.c). Calling a routine in this file will cause the +arguments to be packed up and sent via Rx (or R). + +=item B<-S> + +Generate all the server-side stub routines (default extension: +I.ss.c). Arguments are unpacked, and the corresponding server +routine is called. + +=item B<-r> + +Generate the two default extension files produced by the B<-C> and B<-S> +options. + +=back + +The following options can be used on any combination of B calls: + +=over 4 + +=item B<-R> + +Generate code for the older \R protocol, as opposed to Rx, which is the +default. + +=item B<-k> + +Must be specified when the generated code is intended to be used by the +kernel; special "includes" and other specifics are produced when the +target output is for the kernel. + +=item B<-p> + +Package combination flag: when multiple packages are included within a +single specification file, a single Execute Request routine will be used +for all of them as a result of this flag. The default is to generate +individual Execute Request stubs for each package. + +=item B<-I> I + +Similar to the B<-I> flag in the C compiler (B). This flag is passed +to the pre-processor (B) so that directory I is searched before +the standard lookup list for #include files. As expected, multiple B<-I> +flags can be used simultaneously. + +=item B<-P> I + +The I string following this switch is prepended to all generated +output files; useful when multiple runs want to produce different versions +of the same interface (say, kernel and non-kernel versions). + +=item B<-d> + +Debugging mode; only needed when B is to be debugged (say, via +B). + +=item B<-o> I + +Specify the name of the output file. If none is specified, the standard +output is used (B<-c>, B<-h>, B<-C>, and B<-S> modes only). Note that if +an output file is specified in a multi-output file option (such as the +default, or with option B<-r>), then the I replaces the name +generated by default (which is based on the configuration's main file +name). + +=back + +The B<-s>, B<-l>, and B<-m> options are present only for B +support. See rpcgen(1) for information on their use. + +=head1 B SYNTAX SUMMARY + + Specification file: + + | + | + | + | + | + + + : + + "package" + + : + + "prefix" + + : + + "startingopcode" + + : + + "splitprefix" ";" + + : + + "IN =" "|" + "OUT =" "|" + + + : + + ["proc"] [] [] + ["split" | "multi"] + ["=" ] ";" + + : + + "(" ")" + + : + + + ["<" ">" | "[" "]"] | NULL + + : + + "," | NULL + + : + + "IN" | "OUT" | "INOUT" | NULL + + : + + | NULL + + : + : + : + : + : + : + : + : + : + + + + : + : + + Sun's RPCL language syntax (see rpcgen(1)) + +=head1 B COMMANDS + +=head2 Comments and Preprocessing + +The input interface may contain preprocessor directives which are passed +through the C preprocessor (i.e. C). Since the preprocessor runs on +all input files before they are actually interpreted by B, all +B directives (#include, #ifdefs, #defines, etc.) are legal and +welcomed within an B input file. Of course, none of these +preprocessor directives will be included in any of the generated files. +To facilitate distinctions between the different types of output files, +B defines certain special B symbols for use by the B +programmer. These are RPC_HDR (defined when compiling into header, +I.h, files), RPC_XDR (defined when compiling into xdr, +I.xdr.c, files), RPC_CLIENT (defined when compiling into client +stubs, I.cs.c, files), and RPC_SERVER (defined when compiling +into server stubs, I.ss.c, files). + +In addition, B does a little preprocessing of its own. Any line +beginning with C<%> is passed directly into the output file, uninterpreted +by B. For a more heavy en masse dumping of uninterpreted code, it +would be adviced to include all such code in an C<#include> file and pass +it in preceded by C<%>. The input interface may also contain any C-style +comments which are, of course, ignored. Interpretation is token-based, +thus special line-orientation of separate statements is not necessary. +B also provides a quite rich and helpful set of error reports, +identifying them by exact line location and error type. Also, B +will automatically generate #include lines for standard include files, +such as F and F, along with the generated header file +from this interface. + +=head2 Prefixing stub procedures + +The I statement tells B the name of the interface package. +It is used for prefixing the naming of all generated stub routines and the +execute request procedure. For example: + + package AFS_ + +causes the execute request procedure to be named AFS_ExecuteRequest +(Warning: in the older version an additional C<_> was appended after the +package name to the ExecuteRequest name; thus make sure you don't have an +ExecuteRequest interface routine) and a given stub routine, say Fetch, to +be actually named AFS_Fetch. Multiple package statements (current maximum +size is 10) per configuration are permitted and are useful when multiple +sets of interfaces are implemented (see the example at the end). Note +that in such cases, use of the B<-p> flag results in the generation of +just one ExecuteRequest procedure which recognizes the multiple interfaces +and whose name is prefixed by the first package statement. In the default +case, independent ExecuteRequest procedures will be created for each +packaged group of remote procedure calls. + +The I statement supplies a name to prepend to all calls to remote +procedure names in the ExecuteRequest stub routine. It is useful when the +server makes RPC calls to other servers (say, for debugging purposes). +For example: + + prefix S + +causes the name C to be prepended to the name of all routines called +from the server stubs. The server can then call the original name and get +the client stubs. + +=head2 B procedure declaration + +The I statement is the most common (and meaningful) in the B +interface. Its syntax description is: + + [proc] [] [] (, ..., ) + [split | multi] [= ] ; + +where: + +=over 2 + +=item * + +C is an optional prefix of the procedure statement. This is just a +stylistic item and not a required procedure delimiter. + +=item * + + is the name of the procedure. Note that even the name of the +procedure is optional. This only makes sense when the name of the given +procedure is identical to the name of the last I statement (i.e., +C and the declaration of the C procedure). + +=item * + +, if present, causes the ExecuteRequest procedure to call +that stub instead of the automatically generated stub when a call with +that opcode is decoded. + +=item * + + is a constant or symbol that is the opcode for that procedure. +One might use the preprocessor features (i.e., #define), the I +RPC-language feature, or the old good constants as opcodes. Some further +evaluation/processing of opcodes is done. Particularly, checks for +duplicate and non-existent opcodes are performed, along with checks for +"holes" (i.e., gaps in consecutive opcodes) in the opcode sequences. For +example, we use the fact that when "holes" in opcodes exist, the +ExecuteRequest procedure uses the I statement rather than the faster +(and smaller, codewise) indexed array method. + +Also, B defines (i.e., appends to the header file) three valuable +macros for each package group: LOWEST_OPCODE, +HIGHEST_OPCODE, and NUMBER_OPCODES. These may +be useful to the B programmer. Also, notice that the I +statement is an optional feature, and can be omitted. In such cases, +automatic opcode numbers are generated sequentially, starting from 0. + +One can change the initial opcode number by using the I +(for lack of a better name) B command. Its syntax is: + + startingopcode + +where must be reasonable! Note that one can not mix +procedures, some with opcodes and some without, nor allow opcodes after +the specification of the I statement. B will +complain in all such cases. + +=item * + +The I entry represents a given parameter of the procedure. Its +syntax is: + + [IN | INOUT | OUT | ] + [|<>|[max]|[]] + +If the type is an indirect type (i.e., is followed by *), it is assumed +that the pointer should be followed one level and the data pointed to is +to be transmitted. This should normally be used for all structures/arrays +and out parameters. A noticeable exception is when explicit +array/structure maximum size is given; since no array-of-pointer +declarations are allowed one should use typedefs to achieve the similar +effect. The parameters could be input parameters (preceded by IN), output +parameters (preceded by OUT), or input/output parameters (preceded by +INOUT). If not specified, then the direction of the previous parameter in +the procedure is used. (Note: the first parameter must be preceded by the +directional primitive!) + +=item * + +C is a hack to handle stub routines that do things such as file +transfers or any other operation that has to exchange information (e.g., +length of a file) before the call returns its output parameters. Because +of the particular handshake that is involved when doing remote file +transfer, we currently break all such calls into two client-side stub +routines. The first (with the default prefix of C) is used to pass +all IN and INOUT parameters to the server side. The second (with the +default prefix of C) is used to get back the INOUT and OUT parameters +from the server. Between the two calls, the user is supposed to do the +appropriate calls for the file transfer. For example, the following +procedure declaration in package AFS_ + + Fetch (IN a, b,INOUT c, OUT d) split = FETCHOPCODE; + +will roughly generate the two independent client stub routines: + + BeginAFS_Fetch (IN a, b, c) + +and + + EndAFS_Fetch(OUT c, d) + +The I statement is used to change the default prefix names +used by the two client-side stub generated routines when dealing with file +transfer-related procedure calls. For example: + + splitprefix IN=Before_ OUT=After_ + +will cause the naming of the two client stubs for a file transfer-related +routine, say Fetch(), to be Before_AFS_Fetch() and After_AFS_Fetch(), +respectively. + +=item * + +The C option is nearly identical to the C feature described +above. The only significant visible difference is that along with the two +client stubs, the standard client stub is also generated. Since the +intention is to handle the multi-Rx calls, we need the whole standard +procedure stub in the cases where no multi-Rx call of the procedure is +performed. A side effect of the C option is the generation of a +special macro (i.e., C<< multi_ >> which passes back as +arguments the C and C stubs in the header output file. This +macro is used directly by the Rx code when a multi-Rx call of this +procedure is performed. + +=back + +=head2 OBSOLETE B FEATURES + +Although the following rxgen commands are still in effect, they will soon +be removed since there are better alternatives. DO NOT USE THEM! + +The I statement is a temporary hack used to handle certain +inefficiencies of standard xdr routines to handle some user-customized +declarations. In particular, this applies to a string pointer specified +as part of a declaration. For example, + + special struct BBS SeqBody; + +tells B that the entry C in the user-defined BBS xdr +routine is a string (note that more than one string can be "special" per +structure -- multiple ones are separated by commas); it will thus allocate +and de-allocate space properly in the server-generated stubs that contain +this structure as an IN or INOUT parameter. + +A better alternative to I is the I statement, which +is simply the C token followed by the regular declaration of a +struct based on the RPCL rules. In this case, the declaration will be +included in the generated header file (B<-h> option) but no xdr routine +will be generated for this structure -- the user will supply this. All +pointer entries in this structure will be remembered so when the structure +is used as an IN or INOUT in the server stub, no core leaks will occur. +For example, consider + + customized struct CBS { + long Seqlen; + char *SeqBody; + } + +The C routine would be provided by the user where during the +DECODE xdr opcode, appropriate space for the C string is +allocated. Similarly, that space is freed during the FREE xdr opcode. + +Note: Old style "Array parameter specifications" are not supported any +more. + +=head1 EXAMPLES + +In case there are some requirements not available by the current RPC +language, one can customize some XDR routines by leaving those data types +undefined. For every data type that is undefined, it will be assumed that +a routine exists with the name C prepended to it. A selected set of +B features is presented below, but for a more comprehensive one +(unions, complex examples, etc) please refer to the I and I. + +=head2 Typedefs + +The RPC typedef statement is identical to the C typedef (i.e. C<< typedef + >>). By default, most user declarations (i.e. structs, +unions, etc) are automatically typedef'ed by B. Since it makes +parsing simpler, its usage is recommended by B scripts. + +=head2 Strings + +The C C string convention is kind of ambiguous, since it is +usually intended to mean a null-terminated string of characters, but it +could also represent a pointer to a single character, a pointer to an +array of characters, etc. In the RPC language, a null-terminated string +is unambiguously called a "string". Examples, + + string bigname<>; + string name; + typedef string volname; + +Notice that the maximum size of string can be arbitrary (like C +above) or, preferably, or specified in angle brackets (i.e. C and +C above). In practice, one should always use only bounded +strings in interfaces. A sample calling proc using the declarations above +would be: + + GetEntryByName (IN volname name, + OUT struct vldbentry *entry) = VL_GETENTRYBYNAME; + +or, of course, + + GetEntryByName (IN string volname, + OUT struct vldbentry *entry) = VL_GETENTRYBYNAME; + +It is very important for the user to understand when the string parameters +should be allocated and/or freed by the his/her client and/or server +programs. A short analysis on string parameters handling follows (note +that a similar method is used for the handling of variable length arrays +as it will be shown later on): + +=over 2 + +=item * + +In the client side: IN and INOUT string parameters are the programmer's +responsibility and should be allocated (static or via malloc) before +calling the rpc and freed (if malloc was used) after the rpc's return in +the user's client program; of course, for INOUT parameters, the returned +string can't be bigger than the malloced input string. + +OUT string parameters are automatically malloced (based on the length of +the returned string and not the maxsize) by the B client stubs (in +I.cs.c) and must be freed by the client program; admittedly, +this could be somewhat confusing since the user needs to free something +that he/she didn't allocate.} + +=item * + +In the server side: IN and INOUT string parameters are automatically +malloced (based on the size of incoming strings) by the rxgen server stubs +(in I.ss.c) before they are passed to the user's server +procedure; that space is automatically freed just before the rxgen server +stub returns; therefore the user need not do anything special for IN and +INOUT string parameters. + +OUT string parameters must be malloced by the user's server procedure +(i.e. null pointer is passed to it by the rxgen server stub) and it is +automatically freed at the end of the B server stub. Like in the +client side, the OUT parameters are somewhat unorthodox (i.e. the server +routine must malloc a string without ever freeing it itself; this is done +by the B server stub). + +Note that for INOUT and OUT string parameters, in both the client and +server sides their arguments must be char of pointers (i.e. char **). + +=head2 Pointers + +Pointer declarations in RPC are also exactly as they are in C +(i.e. C). Of course, one can't send +pointers over the network, but one can use XDR pointers for sending +recursive data types such as lists and trees (an example of a linked list +will be demonstrated shortly). + +=head2 Arrays + +Fixed arrays are just like standard C array declarations (i.e. C) without any side effect problems in +B. Since variable-length arrays have no explicit syntax in C, the +angle-brackets are used for it and the array declarations are actually +compiled into "struct"s. For example, declarations such as: + + const MAXBULKSIZE = 10000; + const MAXENTRIES = 100; + opaque bulk; /* At most 10000 items */ + int hosts<>; /* any number of items */ + typedef vldbentry blkentries<100>; /* Preferable array decl */ + +are compiled into the following structs: + + struct { + u_int bulk_len; /* no of items */ + char *bulk_val; /* pointer to array */ + } bulk; + +for the C array, and similarly for the C<< blkentries<100> >> array, + + struct { + u_int blkentries_len; /* no of items in array */ + vldbentry *blkentries_val; /* pointer to array */ + } blkentries; + +Therefore the user should be aware of the "magically" generated structure +entries such as the number of items in the array (_len) and +the pointer to the array (_val) since some of the entries will +have to be filled in from the client/server programs. A sample proc would +be: + + typedef vldbentry blkentries; + proc GetBlk (OUT blkentries *vlentries) = VL_GETBLK; + +or, more directly, + + GetBlk(OUT vldbentry vlentries) = VL_GETBLK; + +Note that although the latest method is preferable since one does not have +to first use the typedef statement (and admittedly, programmers prefer +avoiding typedefs), one should realize that B does the structure +expansion and the xdr creation implicitly; therefore the user should be +aware of the C and C fields as before +(see following examples). + +=head3 Array example I (least desirable) + +Procedure declaration in the interface configuration: + + proc ListAttributes (IN vldblistbyattributes *attributes, + INOUT blkentries *vldbentries) = VL_LISTATTRIBUTES; + +Sample CLIENT code: + + blkentries entries, *pnt; + entries.blkentries_len = 10; /* max # returned entries */ + entries.blkentries_val = (vldbentry *)malloc(LEN); + /* It must be set */ + + code = VL_ListAttributes(&attributes, &entries); + if (!code) { + pnt = entries.blkentries_val; + for (i=0; i < entries.blkentries_len; i++, pnt++) + display_vldbentry(pnt); + /* Make sure you free the allocated space */ + free((char *)entries.blkentries_val); + } + +Sample SERVER code: + + VL_ListAttributes(attributes, entries) + { + vldbentry *singleentry = entries->blkentries_val; + entries->blkentries_len = 0; + + while (copy_to_vldbentry(&vlentry, singleentry)) + singleentry++, vldbentries->entries_len++; + } + +Although this method for variable-size arrays works fine, there are some +major drawbacks. The array parameter (i.e. vldbentries above) must be +declared as INOUT since we need to pass the max length of the expected +returned array; more importantly, a big (depending on the value of +C<_len>) chunk of junk code is going to be transferred to the server as +result of the IN(out) side-effect of the array. It's an easy and +convenient method if the returned array size can be predicted from the +start and when the size is quite high. This method is included as an +example of erroneous use (and abuse) of B and should not be used. + +=head3 Array example II (Desirable method) + +Procedure declaration in the interface configuration (using Example I +above): + + proc ListAttributes (IN vldblistbyattributes *attributes, + OUT blkentries *vldbentries) = VL_LISTATTRIBUTES; + +Sample CLIENT code: + + blkentries entries, *pnt; + + code = VL_ListAttributes(&attributes, &entries); + if (!code) { + pnt = entries.blkentries_val; + for (i=0; i < entries.blkentries_len; i++, pnt++) + display_vldbentry(pnt); + /* Make sure you free the allocated space (by rxgen) */ + free((char *)entries.blkentries_val); + } + +Sample SERVER code: + + VL_ListAttributes(attributes, entries) + { + vldbentry *singleentry; + entries->blkentries_len = 0; + singleentry = entries->blkentries_val + = (vldbentry *)malloc(MAXENTRIES * sizeof(vldbentry)); + + while (copy_to_vldbentry(&vlentry, singleentry)) + singleentry++, vldbentries->entries_len++; + } + +This is the best (and simplest) way of using variable-size arrays as an +output parameter. It is the responsibility of the server-side stub to +malloc() the adequate space which is automatically freed by the B +stub; the client side should free the space allocated by the +B-calling stub. + +=head3 Array example III (Linked Lists) + +Considering the following 3 declarations (could have applied some +optimizations) in the configuration file: + + typedef struct single_vldbentry *vldblist; + struct single_vldbentry { + vldbentry vlentry; + vldblist next_vldb; + }; + + struct vldb_list { + vldblist node; + }; + +and the rxgen procedure declaration: + + LinkedList (IN vldblistbyattributes *attributes, + OUT vldb_list *linkedentries) = VL_LINKEDLIST; + +Sample CLIENT code: + + vldb_list linkedvldbs; + vldblist vllist, vllist1; + + bzero(&linkedvldbs, sizeof(vldb_list)); + code = VL_LinkedList(&attributes, &nentries, &linkedvldbs); + if (!code) { + printf("We got %d vldb entries\n", nentries); + for (vllist = linkedvldbs.node; vllist; vllist = vllist1) { + vllist1 = vllist->next_vldb; + display_entry(&vllist->vlentry); + free((char *)vllist); + } + } + +Sample SERVER code: + + VL_LinkedList(rxcall, attributes, nentries, linkedvldbs); + { + vldblist vllist, *vllistptr = &linkedvldbs->node; + while (...) { + vllist = *vllistptr + = (single_vldbentry *)malloc (sizeof (single_vldbentry)); + copy_to_vldbentry(&tentry, &vllist->vlentry); + nentries++; + vllistptr = &vllist->next_vldb; + }; + *vllistptr = NULL; + } + +Using a linked list offers many advantages: Nothing is passed to the +server (the parameter is OUT), no additional overhead is involved, and the +caller doesn't have to explicitly prepare for an arbitrary return size. A +drawback is that the caller has the responsibility of malloc() (on the +server) and free (on the client) of each entry (to avoid unwanted +core-leaks). Another drawback is that since it's a recursive call, the C +stack will grow linearly with respect to the number of nodes in the list +(so it's wise to increase the Rx LWP stack if huge amounts of data are +expected back -- default stack size is 4K). The advantages should +outweight the disadvantages here. + +It's important to pay attention to the comments of the three array +examples above particularly when they're references to when the user +should allocate/free space for the variable length arrays. The mechanism +is very similar to the handling of strings thus you might need to review +the strings section above; note that the linked lists are handled somewhat +differently... + +=head2 Miscellaneous examples + +Below is an abbreviated version of a random interface file which shows +some of the common cases. + + /* Declaration of all structures used by the R.xg script interface */ + + struct AFSFid { + unsigned long Volume; + unsigned long Vnode; + unsigned long Unique; + }; + + typedef long ViceDataType; + + /* Note that TEST would be equivalent to "HEADER" only during the + processing of the header, *.h, file */ + + #ifdef RPC_HDR + #define TEST "HEADER" + #else + #define TEST "REST" + #endif + + /* This is the standard *.xg specification file */ + + package AFS_ + splitprefix IN=BEFORE_ OUT=AFTER_; + Prefix Test + + proc Remove(IN struct AFSFid *Did, IN string volname<64>, + OUT struct AFSStatus *Status) = AFS_REMOVE; + + DisconnectFS AUX_disconnectFS() = AFS_DISCONNECTFS; + + proc GetVolumeInfo(IN string Vid, + OUT struct VolumeInfo *Info) = AFS_GETVOLUMEINFO; + + /* You could have more than an interface per configuration */ + + package VOTE_ + + /* Using the "multi" feature; thus VOTE_Beacon can be called as an + multi-Rx call or as a regular call */ + + Beacon (IN long state, long voteStart, + net_version *version, net_tid *tid) + multi = VOTE_BEACON; + + package DISK_ + + /* Using the "split" feature */ + + SendFile (IN long file, long offset, + long length, net_version *version) + split = DISK_SENDFILE; + +=head2 Output of an actual interface configuration + +We'll demonstrate some of the actual output generated by B by +following an abbreviated actual interface configuration. + +=head3 Configuration file + +Contents of the interface configuration file (F): + + package VL_ + #include "vl_opcodes.h" /* The opcodes are included here */ + %#include "vl_opcodes.h" /* directly to other places */ + + /* Current limitations on parameters that affect other packages + (i.e. volume) */ + + const MAXNAMELEN = 65; + const MAXNSERVERS = 8; + const MAXTYPES = 3; + + /* External (visible) representation of an individual vldb entry */ + + struct vldbentry { + char name[MAXNAMELEN]; + long volumeType; + long nServers; + long serverNumber[MAXNSERVERS]; + long serverPartition[MAXNSERVERS]; + long serverFlags[MAXNSERVERS]; + u_long volumeId[MAXTYPES]; + long flags; + }; + + typedef struct single_vldbentry *vldblist; + struct single_vldbentry { + vldbentry VldbEntry; + vldblist next_vldb; + }; + + struct vldb_list { + vldblist node; + }; + + /* vldb interface calls */ + + CreateEntry (IN long Volid, + vldbentry *newentry) = VLCREATEENTRY; + + GetEntryByName (IN string volumename, + OUT vldbentry *entry) = VLGETENTRYBYNAME; + + GetNewVolumeId (IN long bumpcount, + OUT long *newvolumid) = VLGETNEWVOLUMEID; + + ReplaceEntry (IN long Volid, + long voltype, + vldbentry *newentry, + long ReleaseType) multi = VLREPLACEENTRY; + + ListAttributes (IN VldbListByAttributes *attributes, + OUT long *nentries, + OUT vldbentry bulkentries) + = VLLISTATTRIBUTES; + + LinkedList (IN VldbListByAttributes *attributes, + OUT long *nentries, + OUT vldb_list *linkedentries) = VLLINKEDLIST; + +We'll concentrate only on the Rx generated code since the R generated code +(B<-R> option) will soon be obsolete. For a detailed description on the +Rx-related calls inside the generated stubs (i.e., rx_NewCall(), +rx_EndCall()), along with details on what happens inside certain calls +(like xdrrx_create()) please refer to the Rx documentation. Typing C will result in the creation of four files: F, +F, F and F. A closer look at +these files follows. + +=head3 Header file (F) + + /* Machine generated file -- Do NOT edit */ + + #include "vl_opcodes.h" /* directly to other places */ + #define MAXNAMELEN 65 + #define MAXNSERVERS 8 + #define MAXTYPES 3 + + struct vldbentry { + char name[MAXNAMELEN]; + long volumeType; + long nServers; + long serverNumber[MAXNSERVERS]; + long serverPartition[MAXNSERVERS]; + long serverFlags[MAXNSERVERS]; + u_long volumeId[MAXTYPES]; + long flags; + }; + typedef struct vldbentry vldbentry; + bool_t xdr_vldbentry(); + + typedef struct single_vldbentry *vldblist; + bool_t xdr_vldblist(); + + struct single_vldbentry { + vldbentry VldbEntry; + vldblist next_vldb; + }; + typedef struct single_vldbentry single_vldbentry; + bool_t xdr_single_vldbentry(); + + struct vldb_list { + vldblist node; + }; + typedef struct vldb_list vldb_list; + bool_t xdr_vldb_list(); + + #include + #define multi_VL_ReplaceEntry(Volid, voltype, newentry, ReleaseType) \ + multi_Body(StartVL_ReplaceEntry(multi_call, Volid, voltype, + newentry, ReleaseType), EndVL_ReplaceEntry(multi_call)) + + typedef struct bulkentries { + u_int bulkentries_len; + vldbentry *bulkentries_val; + } bulkentries; + bool_t xdr_bulkentries(); + + /* Opcode-related useful stats for package: VL_ */ + #define VL_LOWEST_OPCODE 501 + #define VL_HIGHEST_OPCODE 506 + #define VL_NUMBER_OPCODES 6 + +Notice that all structures are automatically typedef'ed and all Cs +are converted to C<#define>s. Some data structures, such as bulkentries, +are taken from procedure params (from ListAttributes proc). Thus, this +should be kept in mind when creating stubs piecemeal with B (i.e., +using the B<-c>, B<-h>, B<-C>, or B<-S> flags). Also, one of the side +effects of the C option (in C proc) is the generation +of the C above. + +=head3 XDR routines for structures (vldbint.xdr.c) + + /* Machine generated file -- Do NOT edit */ + + #include + #include "vldbint.h" + + #include "vl_opcodes.h" /* directly to other places */ + + bool_t + xdr_vldbentry(xdrs, objp) + XDR *xdrs; + vldbentry *objp; + { + if (!xdr_vector(xdrs, (char *)objp->name, MAXNAMELEN, + sizeof(char), xdr_char)) + return (FALSE); + if (!xdr_long(xdrs, &objp->volumeType)) + return (FALSE); + if (!xdr_long(xdrs, &objp->nServers)) + return (FALSE); + if (!xdr_vector(xdrs, (char *)objp->serverNumber, MAXNSERVERS, + sizeof(long), xdr_long)) + return (FALSE); + if (!xdr_vector(xdrs, (char *)objp->serverPartition, + MAXNSERVERS, sizeof(long), xdr_long)) + return (FALSE); + if (!xdr_vector(xdrs, (char *)objp->serverFlags, MAXNSERVERS, + sizeof(long), xdr_long)) + return (FALSE); + if (!xdr_vector(xdrs, (char *)objp->volumeId, MAXTYPES, + sizeof(u_long), xdr_u_long)) + return (FALSE); + if (!xdr_long(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); + } + + bool_t + xdr_vldblist(xdrs, objp) + XDR *xdrs; + vldblist *objp; + { + if (!xdr_pointer(xdrs, (char **)objp, + sizeof(struct single_vldbentry), + xdr_single_vldbentry)) + return (FALSE); + return (TRUE); + } + + bool_t + xdr_single_vldbentry(xdrs, objp) + XDR *xdrs; + single_vldbentry *objp; + { + if (!xdr_vldbentry(xdrs, &objp->VldbEntry)) + return (FALSE); + if (!xdr_vldblist(xdrs, &objp->next_vldb)) + return (FALSE); + return (TRUE); + } + + bool_t + xdr_vldb_list(xdrs, objp) + XDR *xdrs; + vldb_list *objp; + { + if (!xdr_vldblist(xdrs, &objp->node)) + return (FALSE); + return (TRUE); + } + + bool_t + xdr_bulkentries(xdrs, objp) + XDR *xdrs; + bulkentries *objp; + { + if (!xdr_array(xdrs, (char **)&objp->bulkentries_val, + (u_int *)&objp->bulkentries_len, MAXVLDBLEN, + sizeof(vldbentry), xdr_vldbentry)) + return (FALSE); + return (TRUE); + } + +Note that the xdr_bulkentries() is automatically generated as a side +effect of a procedure parameter declaration. Thus, if identical multiple +type parameter declarations are used, then multiply-defined xdr_* stubs +will be created! We felt this was a better alternative to having the +B programmer deal with types such as bulkentries_1, +bulkentries_2... + +=head3 Client-Side stub routines (vldbint.cs.c) + + /* Machine generated file -- Do NOT edit */ + + #include + #include + #include + #include "vldbint.h" + + #include "vl_opcodes.h" /* directly to other places */ + + int VL_CreateEntry(z_conn, Volid, newentry) + register struct rx_connection *z_conn; + long Volid; + vldbentry * newentry; + { + struct rx_call *z_call = rx_NewCall(z_conn); + static int z_op = 501; + int z_result; + XDR z_xdrs; + + xdrrx_create(&z_xdrs, z_call, XDR_ENCODE); + + /* Marshal the arguments */ + if ((!xdr_int(&z_xdrs, &z_op)) + || (!xdr_long(&z_xdrs, &Volid)) + || (!xdr_vldbentry(&z_xdrs, newentry))) { + z_result = RXGEN_CC_MARSHAL; + goto fail; + } + + z_result = RXGEN_SUCCESS; + fail: + return rx_EndCall(z_call, z_result); + } + + int VL_GetEntryByName(z_conn, volumename, entry) + register struct rx_connection *z_conn; + char * volumename; + vldbentry * entry; + { + struct rx_call *z_call = rx_NewCall(z_conn); + static int z_op = 504; + int z_result; + XDR z_xdrs; + + xdrrx_create(&z_xdrs, z_call, XDR_ENCODE); + + /* Marshal the arguments */ + if ((!xdr_int(&z_xdrs, &z_op)) + || (!xdr_string(&z_xdrs, &volumename, 65))) { + z_result = RXGEN_CC_MARSHAL; + goto fail; + } + + /* Un-marshal the reply arguments */ + z_xdrs.x_op = XDR_DECODE; + if ((!xdr_vldbentry(&z_xdrs, entry))) { + z_result = RXGEN_CC_UNMARSHAL; + goto fail; + } + + z_result = RXGEN_SUCCESS; + fail: + return rx_EndCall(z_call, z_result); + } + + int VL_GetNewVolumeId(z_conn, bumpcount, newvolumid) + register struct rx_connection *z_conn; + long bumpcount; + long * newvolumid; + { + struct rx_call *z_call = rx_NewCall(z_conn); + static int z_op = 505; + int z_result; + XDR z_xdrs; + + xdrrx_create(&z_xdrs, z_call, XDR_ENCODE); + + /* Marshal the arguments */ + if ((!xdr_int(&z_xdrs, &z_op)) + || (!xdr_long(&z_xdrs, &bumpcount))) { + z_result = RXGEN_CC_MARSHAL; + goto fail; + } + + /* Un-marshal the reply arguments */ + z_xdrs.x_op = XDR_DECODE; + if ((!xdr_long(&z_xdrs, newvolumid))) { + z_result = RXGEN_CC_UNMARSHAL; + goto fail; + } + + z_result = RXGEN_SUCCESS; + fail: + return rx_EndCall(z_call, z_result); + } + + int VL_ReplaceEntry(z_conn, Volid, voltype, newentry, ReleaseType) + register struct rx_connection *z_conn; + long Volid, voltype, ReleaseType; + vldbentry * newentry; + { + struct rx_call *z_call = rx_NewCall(z_conn); + static int z_op = 506; + int z_result; + XDR z_xdrs; + + xdrrx_create(&z_xdrs, z_call, XDR_ENCODE); + + /* Marshal the arguments */ + if ((!xdr_int(&z_xdrs, &z_op)) + || (!xdr_long(&z_xdrs, &Volid)) + || (!xdr_long(&z_xdrs, &voltype)) + || (!xdr_vldbentry(&z_xdrs, newentry)) + || (!xdr_long(&z_xdrs, &ReleaseType))) { + z_result = RXGEN_CC_MARSHAL; + goto fail; + } + + z_result = RXGEN_SUCCESS; + fail: + return rx_EndCall(z_call, z_result); + } + + int StartVL_ReplaceEntry(z_call, Volid, voltype, newentry, ReleaseType) + register struct rx_call *z_call; + long Volid, voltype, ReleaseType; + vldbentry * newentry; + { + static int z_op = 506; + int z_result; + XDR z_xdrs; + + xdrrx_create(&z_xdrs, z_call, XDR_ENCODE); + + /* Marshal the arguments */ + if ((!xdr_int(&z_xdrs, &z_op)) + || (!xdr_long(&z_xdrs, &Volid)) + || (!xdr_long(&z_xdrs, &voltype)) + || (!xdr_vldbentry(&z_xdrs, newentry)) + || (!xdr_long(&z_xdrs, &ReleaseType))) { + z_result = RXGEN_CC_MARSHAL; + goto fail; + } + + z_result = RXGEN_SUCCESS; + fail: + return z_result; + } + + int EndVL_ReplaceEntry(z_call) + register struct rx_call *z_call; + { + int z_result; + XDR z_xdrs; + + z_result = RXGEN_SUCCESS; + fail: + return z_result; + } + + int VL_ListAttributes(z_conn, attributes, nentries, bulkentries_1) + register struct rx_connection *z_conn; + VldbListByAttributes * attributes; + long * nentries; + bulkentries * bulkentries_1; + { + struct rx_call *z_call = rx_NewCall(z_conn); + static int z_op = 511; + int z_result; + XDR z_xdrs; + + xdrrx_create(&z_xdrs, z_call, XDR_ENCODE); + + /* Marshal the arguments */ + if ((!xdr_int(&z_xdrs, &z_op)) + || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) { + z_result = RXGEN_CC_MARSHAL; + goto fail; + } + + /* Un-marshal the reply arguments */ + z_xdrs.x_op = XDR_DECODE; + if ((!xdr_long(&z_xdrs, nentries)) + || (!xdr_bulkentries(&z_xdrs, bulkentries_1))) { + z_result = RXGEN_CC_UNMARSHAL; + goto fail; + } + + z_result = RXGEN_SUCCESS; + fail: + return rx_EndCall(z_call, z_result); + } + + int VL_LinkedList(z_conn, attributes, nentries, linkedentries) + register struct rx_connection *z_conn; + VldbListByAttributes * attributes; + long * nentries; + vldb_list * linkedentries; + { + struct rx_call *z_call = rx_NewCall(z_conn); + static int z_op = 512; + int z_result; + XDR z_xdrs; + + xdrrx_create(&z_xdrs, z_call, XDR_ENCODE); + + /* Marshal the arguments */ + if ((!xdr_int(&z_xdrs, &z_op)) + || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) { + z_result = RXGEN_CC_MARSHAL; + goto fail; + } + + /* Un-marshal the reply arguments */ + z_xdrs.x_op = XDR_DECODE; + if ((!xdr_long(&z_xdrs, nentries)) + || (!xdr_vldb_list(&z_xdrs, linkedentries))) { + z_result = RXGEN_CC_UNMARSHAL; + goto fail; + } + + z_result = RXGEN_SUCCESS; + fail: + return rx_EndCall(z_call, z_result); + } + +Notice the side effect of the C feature (three different modules +for C proc). + +=head3 Server-Side stub routines (vldbint.ss.c) + + /* Machine generated file -- Do NOT edit */ + + #include + #include + #include + #include "vldbint.h" + + #include "vl_opcodes.h" /* directly to other places */ + + long _VL_CreateEntry(z_call, z_xdrs) + struct rx_call *z_call; + XDR *z_xdrs; + { + long z_result; + long Volid; + vldbentry newentry; + + if ((!xdr_long(z_xdrs, &Volid)) + || (!xdr_vldbentry(z_xdrs, &newentry))) { + z_result = RXGEN_SS_UNMARSHAL; + goto fail; + } + + z_result = VL_CreateEntry(z_call, Volid, &newentry); + fail: + return z_result; + } + + long _VL_GetEntryByName(z_call, z_xdrs) + struct rx_call *z_call; + XDR *z_xdrs; + { + long z_result; + char *volumename = (char *)0; + vldbentry entry; + + if ((!xdr_string(z_xdrs, &volumename, 65))) { + z_result = RXGEN_SS_UNMARSHAL; + goto fail; + } + + z_result = VL_GetEntryByName(z_call, &volumename, &entry); + z_xdrs->x_op = XDR_ENCODE; + if ((!xdr_vldbentry(z_xdrs, &entry))) + z_result = RXGEN_SS_MARSHAL; + fail: + z_xdrs->x_op = XDR_FREE; + if (!xdr_string(z_xdrs, &volumename, 65)) goto fail1; + return z_result; + fail1: + return RXGEN_SS_XDRFREE; + } + + long _VL_GetNewVolumeId(z_call, z_xdrs) + struct rx_call *z_call; + XDR *z_xdrs; + { + long z_result; + long bumpcount; + long newvolumid; + + if ((!xdr_long(z_xdrs, &bumpcount))) { + z_result = RXGEN_SS_UNMARSHAL; + goto fail; + } + + z_result = VL_GetNewVolumeId(z_call, bumpcount, &newvolumid); + z_xdrs->x_op = XDR_ENCODE; + if ((!xdr_long(z_xdrs, &newvolumid))) + z_result = RXGEN_SS_MARSHAL; + fail: + return z_result; + } + + long _VL_ReplaceEntry(z_call, z_xdrs) + struct rx_call *z_call; + XDR *z_xdrs; + { + long z_result; + long Volid, voltype, ReleaseType; + vldbentry newentry; + + if ((!xdr_long(z_xdrs, &Volid)) + || (!xdr_long(z_xdrs, &voltype)) + || (!xdr_vldbentry(z_xdrs, &newentry)) + || (!xdr_long(z_xdrs, &ReleaseType))) { + z_result = RXGEN_SS_UNMARSHAL; + goto fail; + } + + z_result = VL_ReplaceEntry(z_call, Volid, voltype, &newentry, + ReleaseType); + fail: + return z_result; + } + + long _VL_ListAttributes(z_call, z_xdrs) + struct rx_call *z_call; + XDR *z_xdrs; + { + long z_result; + VldbListByAttributes attributes; + long nentries; + bulkentries bulkentries_1; + + if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) { + z_result = RXGEN_SS_UNMARSHAL; + goto fail; + } + + z_result = VL_ListAttributes(z_call, &attributes, &nentries, + &bulkentries_1); + z_xdrs->x_op = XDR_ENCODE; + if ((!xdr_long(z_xdrs, &nentries)) + || (!xdr_bulkentries(z_xdrs, &bulkentries_1))) + z_result = RXGEN_SS_MARSHAL; + fail: + z_xdrs->x_op = XDR_FREE; + if (!xdr_bulkentries(z_xdrs, &bulkentries_1)) goto fail1; + return z_result; + fail1: + return RXGEN_SS_XDRFREE; + } + + long _VL_LinkedList(z_call, z_xdrs) + struct rx_call *z_call; + XDR *z_xdrs; + { + long z_result; + VldbListByAttributes attributes; + long nentries; + vldb_list linkedentries; + + if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) { + z_result = RXGEN_SS_UNMARSHAL; + goto fail; + } + + z_result = VL_LinkedList(z_call, &attributes, &nentries, + &linkedentries); + z_xdrs->x_op = XDR_ENCODE; + if ((!xdr_long(z_xdrs, &nentries)) + || (!xdr_vldb_list(z_xdrs, &linkedentries))) + z_result = RXGEN_SS_MARSHAL; + fail: + return z_result; + } + + long _VL_CreateEntry(); + long _VL_GetEntryByName(); + long _VL_GetNewVolumeId(); + long _VL_ReplaceEntry(); + long _VL_ListAttributes(); + long _VL_LinkedList(); + + static long (*StubProcsArray0[])() = {_VL_CreateEntry, + _VL_GetEntryByName, _VL_GetNewVolumeId, _VL_ReplaceEntry, + _VL_ListAttributes, _VL_LinkedList}; + + VL_ExecuteRequest(z_call) + register struct rx_call *z_call; + { + int op; + XDR z_xdrs; + long z_result; + + xdrrx_create(&z_xdrs, z_call, XDR_DECODE); + if (!xdr_int(&z_xdrs, &op)) + z_result = RXGEN_DECODE; + else if (op < VL_LOWEST_OPCODE || op > VL_HIGHEST_OPCODE) + z_result = RXGEN_OPCODE; + else + z_result = (*StubProcsArray0[op - VL_LOWEST_OPCODE]) + (z_call, &z_xdrs); + return z_result; + } + +If there were gaps in the procedures' opcode sequence the code for +VL_ExecuteRequest() routine would be have been drastically different (it +would have been a case statement for each procedure). + +=head1 NOTES + +B is implemented from Sun's B utility. All of the standard +B's functionality is fully maintained. Note that some active +B options that don't apply to B's purpose aren't referenced +here (i.e., B<-s>, B<-l>, B<-m> options) and the interested reader should +refer to rpcgen(1) for details. + +When the C<%#include > feature is used make sure that you +don't have any B language features (i.e. %#defines) since you'll +get syntax errors during compilations.. + +Since this is an ongoing project many of the above may change/disappear +without a major warning. + +=head1 SEE ALSO + +I: Summary description of rxgen's grammar. + +I: Sun's RPC protocol compiler. B was +implemented as an extension to that compiler. + +I: Detailed examples in +using XDR. + +I: Summary of Sun's Remote Procedure Call Language. + +I: An extended Remote Procedure Call Protocol. + +I: An earlier version of a similar stub generator used for the R RPC +protocol. + +=head1 COPYRIGHT + +IBM Corporation 2000. All Rights Reserved. + +This documentation is covered by the IBM Public License Version 1.0. It +was converted from the original TeX B manual to POD by Russ +Allbery.