include-afsconfig-before-param-h-20010712
[openafs.git] / src / libadmin / adminutil / afs_utilAdmin.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID("$Header$");
14
15 #include <afs/stds.h>
16 #include <afs/afs_Admin.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <afs/afs_Admin.h>
20 #include "afs_AdminInternal.h"
21 #include "afs_utilAdmin.h"
22 #include <afs/pthread_glock.h>
23 #include <afs/cellconfig.h>
24 #include <afs/dirpath.h>
25 #include <afs/com_err.h>
26 #include <afs/kautils.h>
27 #include <afs/cmd.h>
28 #include <afs/vlserver.h>
29 #include <afs/pterror.h>
30 #include <afs/bnode.h>
31 #include <afs/volser.h>
32 #include <afs/afsint.h>
33 #include <rx/rx.h>
34 #include <rx/rxstat.h>
35 #ifdef AFS_NT40_ENV
36 #include <winsock2.h>
37 #else
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <netdb.h>
43 #endif
44
45 /*
46  * AIX 4.2 has PTHREAD_CREATE_UNDETACHED and not PTHREAD_CREATE_JOINABLE
47  *
48  * This fix should be done more centrally, but there's no time right now.
49  */
50 #if defined(AFS_AIX_ENV)
51 # if !defined(PTHREAD_CREATE_JOINABLE) && defined(PTHREAD_CREATE_UNDETACHED)
52 #  define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED
53 # endif
54 #endif
55
56 #define ERRCODE_RANGE 8
57 static pthread_once_t error_init_once = PTHREAD_ONCE_INIT;
58 static int error_init_done;
59
60 static void init_once(void) {
61
62     initialize_ka_error_table();
63     initialize_rxk_error_table();
64     initialize_ktc_error_table();
65     initialize_acfg_error_table();
66     initialize_cmd_error_table();
67     initialize_vl_error_table();
68     initialize_pt_error_table();
69     initialize_bz_error_table();
70     initialize_u_error_table();
71     initialize_ab_error_table();
72     initialize_af_error_table();
73     initialize_al_error_table();
74     initialize_ac_error_table();
75     initialize_ak_error_table();
76     initialize_am_error_table();
77     initialize_ap_error_table();
78     initialize_au_error_table();
79     initialize_av_error_table();
80     initialize_vols_error_table();
81     error_init_done = 1;
82 }
83
84 int ADMINAPI util_AdminErrorCodeTranslate(
85  afs_status_t errorCode,
86  int langId,
87  const char **errorTextP,
88  afs_status_p st)
89 {
90     int rc = 0;
91     afs_status_t tst = 0;
92     afs_int32 code;
93
94     if (errorTextP == NULL) {
95        tst = ADMUTILERRORTEXTPNULL;
96        goto fail_util_AdminErrorCodeTranslate;
97     }
98
99     /*
100      * Translate the error
101      */
102
103     if ( !error_init_done )
104                 pthread_once(&error_init_once, init_once);
105     code = (afs_int32) errorCode;
106     *errorTextP = error_message(code);
107     rc = 1;
108      
109 fail_util_AdminErrorCodeTranslate:
110
111     if (st != NULL) {
112         *st = tst;
113     }
114     return rc;
115 }
116
117 /*
118  * The iterator functions and data for the database server retrieval functions.
119  */
120
121 typedef struct database_server_get {
122     int total;
123     int index;
124     struct afsconf_dir *conf;
125     struct afsconf_cell cell;
126     util_databaseServerEntry_t server[CACHED_ITEMS];
127 } database_server_get_t, *database_server_get_p;
128
129 static int GetDatabaseServerRPC(
130   void *rpc_specific,
131   int slot,
132   int *last_item,
133   int *last_item_contains_data,
134   afs_status_p st)
135 {
136     int rc = 0;
137     afs_status_t tst = 0;
138     database_server_get_p serv = (database_server_get_p) rpc_specific;
139  
140     serv->server[slot].serverAddress = ntohl(serv->cell.hostAddr[serv->index].sin_addr.s_addr);
141          strcpy(serv->server[slot].serverName, serv->cell.hostName[serv->index]);
142     serv->index++;
143
144     /*
145      * See if we've processed all the entries
146      */
147  
148     if (serv->index == serv->total) {
149         *last_item = 1;
150         *last_item_contains_data = 1;
151     }
152     rc = 1;
153  
154     if (st != NULL) {
155         *st = tst;
156     }
157     return rc;
158 }
159  
160 static int GetDatabaseServerFromCache(
161   void *rpc_specific,
162   int slot,
163   void *dest,
164   afs_status_p st)
165 {
166     int rc = 0;
167     afs_status_t tst = 0;
168     database_server_get_p serv = (database_server_get_p) rpc_specific;
169  
170     memcpy(dest, (const void *) &serv->server[slot],
171            sizeof(util_databaseServerEntry_t));
172  
173     rc = 1;
174     if (st != NULL) {
175         *st = tst;
176     }
177     return rc;
178 }
179
180 static int DestroyDatabaseServer(
181     void *rpc_specific,
182     afs_status_p st)
183 {
184     int rc = 0;
185     afs_status_t tst = 0;
186     database_server_get_p serv = (database_server_get_p) rpc_specific;
187     
188     afsconf_Close(serv->conf);
189     rc = 1;
190
191     if (st != NULL) {
192         *st = tst;
193     }
194     return rc;
195 }
196
197 /*
198  * util_DatabaseServerGetBegin - begin iterating over the database
199  * server machines in a cell.
200  *
201  * PARAMETERS
202  *
203  * IN cellName - the cell where database servers reside.
204  *
205  * OUT iterationIdP - upon successful completion contains an iterator that
206  * can be passed to util_DatabaseServerGetNext.
207  *
208  * LOCKS
209  *
210  * No locks are obtained or released by this function
211  *
212  * CAUTIONS
213  *
214  * None.
215  *
216  * RETURN CODES
217  *
218  * Returns != 0 upon successful completion.
219  */
220
221 int ADMINAPI util_DatabaseServerGetBegin(
222   const char *cellName,
223   void **iterationIdP,
224   afs_status_p st)
225 {
226     int rc = 0;
227     afs_status_t tst = 0;
228     afs_admin_iterator_p iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
229     database_server_get_p serv = (database_server_get_p) calloc(1, sizeof(database_server_get_t));
230     char copyCell[MAXCELLCHARS];
231  
232     /*
233      * Validate arguments
234      */
235
236     if ((cellName == NULL) || (*cellName == 0)) {
237         tst = ADMUTILCELLNAMENULL;
238         goto fail_util_DatabaseServerGetBegin;
239     }
240
241     if (iterationIdP == NULL) {
242         goto fail_util_DatabaseServerGetBegin;
243     }
244
245     if ((iter == NULL) || (serv == NULL)) {
246         tst = ADMNOMEM;
247         goto fail_util_DatabaseServerGetBegin;
248     }
249
250     /*
251      * Fill in the serv structure
252      */
253
254     serv->conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
255     if (serv->conf == NULL) {
256         tst = ADMUTILCANTOPENCELLSERVDB;
257         goto fail_util_DatabaseServerGetBegin;
258     }
259
260     /*
261      * We must copy the cellname because afsconf_GetCellInfo
262      * actually writes over the cell name it is passed.
263      */
264     strncpy(copyCell, cellName, MAXCELLCHARS - 1);
265     tst = afsconf_GetCellInfo(serv->conf, copyCell, AFSCONF_KAUTHSERVICE,
266                               &serv->cell);
267     if (tst != 0) {
268         goto fail_util_DatabaseServerGetBegin;
269     }
270
271     serv->total = serv->cell.numServers;
272     if (IteratorInit(iter, (void *) serv, GetDatabaseServerRPC,
273                      GetDatabaseServerFromCache, NULL, DestroyDatabaseServer,
274                       &tst)) {
275         *iterationIdP = (void *) iter;
276     } else {
277         goto fail_util_DatabaseServerGetBegin;
278     }
279     rc = 1;
280
281 fail_util_DatabaseServerGetBegin:
282
283     if (rc == 0) {
284         if (iter != NULL) {
285             free(iter);
286         }
287         if (serv != NULL) {
288             free(serv);
289         }
290     }
291
292     if (st != NULL) {
293         *st = tst;
294     }
295     return rc;
296 }
297
298 /*
299  * util_DatabaseServerGetNext - get the next server address.
300  *
301  * PARAMETERS
302  *
303  * IN iterationId - an iterator returned by util_DatabaseServerGetBegin
304  *
305  * OUT serverAddressP - upon successful completion contains the next 
306  * server address in the cell.
307  *
308  * LOCKS
309  *
310  * This function locks the iterator for the duration of its processing.
311  *
312  * CAUTIONS
313  *
314  * None.
315  *
316  * RETURN CODES
317  *
318  * Returns != 0 upon successful completion.
319  */
320
321
322 int ADMINAPI util_DatabaseServerGetNext(
323   const void *iterationId,
324   util_databaseServerEntry_p serverP,
325   afs_status_p st)
326 {
327     int rc = 0;
328     afs_status_t tst = 0;
329     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
330  
331     if (iter == NULL) {
332         tst = ADMITERATORNULL;
333         goto fail_util_DatabaseServerGetNext;
334     }
335
336     if (serverP == NULL) {
337         tst = ADMUTILSERVERADDRESSPNULL;
338         goto fail_util_DatabaseServerGetNext;
339     }
340
341     rc = IteratorNext(iter, (void *) serverP, &tst);
342
343 fail_util_DatabaseServerGetNext:
344
345     if (st != NULL) {
346         *st = tst;
347     }
348     return rc;
349 }
350
351 /*
352  * util_DatabaseServerGetDone - stop using a database iterator.
353  *
354  * PARAMETERS
355  *
356  * IN iterationId - an iterator returned by util_DatabaseServerGetBegin
357  *
358  * LOCKS
359  *
360  * This function locks the iterator for the duration of its processing.
361  * And then destroys it before returning.
362  *
363  * CAUTIONS
364  *
365  * None.
366  *
367  * RETURN CODES
368  *
369  * Returns != 0 upon successful completion.
370  */
371
372 int ADMINAPI util_DatabaseServerGetDone(
373   const void *iterationId,
374   afs_status_p st)
375 {
376     int rc = 0;
377     afs_status_t tst = 0;
378     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
379  
380     /*
381      * Validate parameters
382      */
383
384     if (iter == NULL) {
385         tst = ADMITERATORNULL;
386         goto fail_util_DatabaseServerGetDone;
387     }
388
389     rc = IteratorDone(iter, &tst);
390
391 fail_util_DatabaseServerGetDone:
392
393     if (st != NULL) {
394         *st = tst;
395     }
396     return rc;
397 }
398
399 /*
400  * GetServerAddressFromName - translate a character string server name
401  * to an integer representation of an IP address.
402  *
403  * PARAMETERS
404  *
405  * IN serverName - the character string server name in either foo.com
406  * format, or 123.12.1.1 format.
407  *
408  * OUT serverAddress - an integer that is filled with the correct address
409  * in host byte order upon successful completion.
410  *
411  * LOCKS
412  * 
413  * No locks are obtained or released by this function
414  *
415  * CAUTIONS
416  *
417  * On many platforms, gethostbyname is not thread safe.  Since we are
418  * only working under NT for now I'll use it directly.  In future UNIX
419  * ports, a wrapper function should be written to call the correct function
420  * on the particular platform.
421  * 
422  * RETURN CODES
423  *
424  * Returns != 0 upon successful completion.
425  */
426
427 int ADMINAPI util_AdminServerAddressGetFromName(
428   const char *serverName,
429   int *serverAddress,
430   afs_status_p st)
431 {
432     int rc = 0;
433     afs_status_t tst = 0;
434     struct hostent *server;
435     int part1, part2, part3, part4;
436     int num_converted;
437
438     if ((serverName == NULL) || (*serverName == 0)) {
439         tst = ADMUTILSERVERNAMENULL;
440         goto fail_util_AdminServerAddressGetFromName;
441     }
442
443     if (serverAddress == NULL) {
444         tst = ADMUTILSERVERADDRESSNULL;
445         goto fail_util_AdminServerAddressGetFromName;
446     }
447
448     num_converted = sscanf(serverName, "%d.%d.%d.%d", &part1, &part2, &part3, &part4);
449     if (num_converted == 4) {
450         *serverAddress = (part1<<24) | (part2<<16) | (part3<<8) | part4;
451     } else {
452         LOCK_GLOBAL_MUTEX
453         server = gethostbyname(serverName);
454         if (server != NULL) {
455             memcpy((void *) serverAddress, (const void *) server->h_addr, sizeof(serverAddress));
456             *serverAddress = ntohl(*serverAddress);
457         } else {
458             tst = ADMUTILCANTGETSERVERNAME;
459             UNLOCK_GLOBAL_MUTEX;
460             goto fail_util_AdminServerAddressGetFromName;
461         }
462         UNLOCK_GLOBAL_MUTEX
463     }
464     rc = 1;
465
466 fail_util_AdminServerAddressGetFromName:
467
468     if (st != NULL) {
469         *st = tst;
470     }
471
472     return rc;
473 }
474
475 /*
476  * This file contains functions that can be used to create iterator
477  * functions within the api.  I have attempted to make these functions
478  * generic so that they can be used across the admin components.
479  *
480  * The functions in this file are a generalized producer/consumer
481  * implementation.  They manage access to a queue of data.  The only
482  * assumption these functions make about this data is that it is 
483  * stored in a queue which is implemented via an array.  These functions
484  * know about the index into the array, but they know nothing about
485  * the contents of the array.
486  *
487  * The data specific functions you implement will have to create some
488  * data specific storage structure that will have an array
489  * of size CACHED_ITEMS data items.  This structure will also need to
490  * store any necessary parameters/state variables you need to issue the
491  * rpc to retrieve the next item.
492  *
493  * In order to use the generic functions, you must implement four functions
494  * for each type of data you wish to retrieve.  The functions are:
495  *
496  * validate_specific_data_func - this function is handed a void pointer
497  * that points to the rpc specific data you've allocated.  The function
498  * should examine the data for validity and return an appropriate error.
499  * This function is called every time the iterator is validated.
500  *
501  * destroy_specific_data_func - this function is handed a void pointer
502  * that points to the rpc specific data you've allocated.  It should
503  * destroy any components of the specific data as required and then
504  * return.  The void pointer is free'd by the generic functions.
505  *
506  * get_cached_data_func - this function is handed a void pointer 
507  * that points to the rpc specific data you've allocated, an index
508  * into the cache of the item to be copied to the caller, and a void
509  * pointer where the cache item should be copied.
510  *
511  * make_rpc_func - this function is handed a void pointer that points
512  * to the rpc specific data you've allocated, an index into the cache
513  * of the item to be filled with the next retrieved item, and an int
514  * pointer that should be set to 1 if there are no more items to be
515  * retrieved.  The assumption made by the generic functions is that 
516  * the last_item status requires an individual rpc - the data isn't 
517  * piggybacked on the last data item.
518  */
519
520 /*
521  * IteratorDelete - delete an iterator.
522  *
523  * PARAMETERS
524  *
525  * IN interator - the iterator to delete.
526  *
527  * LOCKS
528  *
529  * No locks are held by this function.
530  *
531  * RETURN CODES
532  *
533  * Returns != 0 upon successful completion.
534  */
535
536 static int IteratorDelete(
537   afs_admin_iterator_p iter,
538   afs_status_p st)
539 {
540     int rc = 0;
541     afs_status_t tst = 0;
542
543     if(pthread_mutex_destroy(&iter->mutex)) {
544         tst = ADMMUTEXDESTROY;
545         goto fail_IteratorDelete;
546     }
547     if(pthread_cond_destroy(&iter->add_item)) {
548         tst = ADMCONDDESTROY;
549         goto fail_IteratorDelete;
550     }
551     if(pthread_cond_destroy(&iter->remove_item)) {
552         tst = ADMCONDDESTROY;
553         goto fail_IteratorDelete;
554     }
555     iter->is_valid = 0;
556     if (iter->destroy_specific != NULL) {
557         iter->destroy_specific(iter->rpc_specific, &tst);
558     }
559     free(iter->rpc_specific);
560     free(iter);
561     rc = 1;
562
563 fail_IteratorDelete:
564  
565     if (st != NULL) {
566         *st = tst;
567     }
568     return rc;
569 }
570
571 /*
572  * DataGet - the background thread that is spawned for every
573  * IteratorBegin call that is successful.  This thread tries
574  * to fetch the data from the server ahead of the
575  * IteratorNext calls.
576  *
577  * PARAMETERS
578  *
579  * IN arg - the address of the iterator structure to be used for this
580  * iteration.
581  *
582  * LOCKS
583  *
584  * The iterator mutex is used by this function to protect elements
585  * of the iterator structure.
586  *
587  * RETURN CODES
588  *
589  * Returns != 0 upon successful completion.
590  */
591  
592 static void *DataGet(void *arg)
593 {
594     afs_admin_iterator_p iter = (afs_admin_iterator_p) arg;
595     void *rc = 0;
596     afs_status_t tst = 0;
597     int mutex_locked = 0;
598     int last_item = 0;
599     int last_item_contains_data = 0;
600  
601     if (pthread_mutex_lock(&iter->mutex)) {
602         iter->st = ADMMUTEXLOCK;
603         goto fail_DataGet;
604     }
605  
606     mutex_locked = 1;
607  
608     while (1) {
609  
610         /*
611          * Check to see if there's room for this datum.  If not, wait
612          * on the consumer to free up another slot.
613          */
614  
615         while (iter->cache_slots_used == CACHED_ITEMS) {
616             if (pthread_cond_wait(&iter->remove_item, &iter->mutex)) {
617                 iter->st = ADMCONDWAIT;
618                 goto fail_DataGet;
619             }
620         }
621  
622         /*
623          * Check to see if someone called Done and terminated the request.
624          * We could have gone to sleep above when the buffer was full and
625          * instead of being awoken because another slot is open, we were
626          * awoken because the request was terminated.
627          */
628  
629         if (iter->request_terminated) {
630             goto fail_DataGet;
631         }
632  
633         if (pthread_mutex_unlock(&iter->mutex)) {
634             iter->st = ADMMUTEXUNLOCK;
635             goto fail_DataGet;
636         }
637  
638         mutex_locked = 0;
639  
640         /*
641          * Make an rpc without holding the iter mutex
642          * We reference an item in the principal cache here without
643          * holding the mutex.  This is safe because:
644          * 1. The iter structure is ref counted and won't be deleted
645          *    from underneath us.
646          * 2. cache_queue_tail is always one item ahead of the consumer
647          *    thread so we are the only thread accessing this member.
648          */
649  
650         iter->make_rpc(iter->rpc_specific, iter->cache_queue_tail,
651                        &last_item, &last_item_contains_data, &tst);
652  
653         if (pthread_mutex_lock(&iter->mutex)) {
654             iter->st = ADMMUTEXLOCK;
655             goto fail_DataGet;
656         }
657  
658         mutex_locked = 1;
659  
660         /*
661          * Check to see if someone called Done and terminated the request
662          */
663  
664         if (iter->request_terminated) {
665             goto fail_DataGet;
666         }
667  
668         /*
669          * Check the rc of the rpc, and see if there are no more items
670          * to be retrieved.
671          */
672  
673         if (tst != 0) {
674             iter->st = tst;
675             goto fail_DataGet;
676         }
677  
678         /*
679          * Check to see if this is the last item produced by the rpc.
680          * If it isn't, add the item to the cache and proceed.
681          * If it is, check to see if the last item contains valid data.
682          *     If it contains valid data, we need to add it to our cache.
683          *     If it doesn't, we mark the iterator as complete.
684          */
685
686         if ((!last_item) || ((last_item) && (last_item_contains_data))) {
687             iter->cache_queue_tail = (iter->cache_queue_tail + 1) %
688                                      CACHED_ITEMS;
689             iter->cache_slots_used++;
690         }
691         if (last_item) {
692             iter->st = ADMITERATORDONE;
693             iter->done_iterating = 1;
694             /*
695              * There's a small chance that the consumer emptied the
696              * cache queue while we were making the last rpc and has
697              * since gone to sleep waiting for more data.  In this case
698              * there will never be more data so we signal him here.
699              */
700             pthread_cond_signal(&iter->add_item);
701             goto fail_DataGet;
702         }
703  
704  
705         /*
706          * If the cache was empty and we just added another item, signal
707          * the consumer
708          */
709  
710         if (iter->cache_slots_used == 1) {
711             if (pthread_cond_signal(&iter->add_item)) {
712                 iter->st = ADMCONDSIGNAL;
713                 goto fail_DataGet;
714             }
715         }
716     }
717  
718  
719 fail_DataGet:
720  
721     /*
722      * If we are exiting with an error, signal the consumer in the event
723      * they were waiting for us to produce more data
724      */
725
726     if (tst != 0) {
727         pthread_cond_signal(&iter->add_item);
728     }
729
730     if (mutex_locked) {
731         pthread_mutex_unlock(&iter->mutex);
732     }
733  
734     return rc;
735 }
736
737 /*
738  * IsValidIterator - verify the validity of a afs_admin_iterator_t.
739  *
740  * PARAMETERS
741  *
742  * IN interator - the interator to be verified.
743  *
744  * LOCKS
745  *
746  * We assume the iter->mutex lock is already held.
747  *
748  * RETURN CODES
749  *
750  * Returns != 0 upon successful completion.
751  */
752
753 static int IsValidIterator(
754   const afs_admin_iterator_p iterator,
755   afs_status_p st)
756 {
757     int rc = 0;
758     afs_status_t tst = 0;
759
760     /*
761      * Validate input parameters
762      */
763  
764     if (iterator == NULL) {
765         tst = ADMITERATORNULL;
766         goto fail_IsValidIterator;
767     }
768  
769     if ((iterator->begin_magic != BEGIN_MAGIC) ||
770         (iterator->end_magic != END_MAGIC)) {
771         tst = ADMITERATORBADMAGICNULL;
772         goto fail_IsValidIterator;
773     }
774  
775     if (iterator->is_valid == 0) {
776         tst = ADMITERATORINVALID;
777         goto fail_IsValidIterator;
778     }
779  
780     /*
781      * Call the iterator specific validation function
782      */
783  
784     if (iterator->validate_specific != NULL) {
785         if (!iterator->validate_specific(iterator->rpc_specific, &tst)) {
786             goto fail_IsValidIterator;
787         }
788     }
789     rc = 1;
790
791 fail_IsValidIterator:
792  
793     if (st != NULL) {
794         *st = tst;
795     }
796     return rc;
797 }
798
799 /*
800  * IteratorNext - return the next datum in an interator.
801  *
802  * PARAMETERS
803  *
804  * IN interator - the iterator containing the data.
805  *
806  * IN dest - the address where the data should be copied.
807  *
808  * LOCKS
809  *
810  * Lock the iterator upon entry, and hold it during the duration of this
811  * function.
812  *
813  * RETURN CODES
814  *
815  * Returns != 0 upon successful completion.
816  */
817
818 int IteratorNext(
819   afs_admin_iterator_p iter,
820   void *dest,
821   afs_status_p st)
822 {
823     int rc = 0;
824     afs_status_t tst = 0;
825     int locked_iter = 0;
826
827     /*
828      * We have to lock the iterator before we validate it
829      */
830  
831     if (pthread_mutex_lock(&iter->mutex)) {
832         tst = ADMMUTEXLOCK;
833         goto fail_IteratorNext;
834     }
835  
836     locked_iter = 1;
837  
838     if (!IsValidIterator(iter, &tst)) {
839         goto fail_IteratorNext;
840     }
841  
842     if (iter->request_terminated == 1) {
843         tst = ADMITERATORTERMINATED;
844         goto fail_IteratorNext;
845     }
846  
847     if ((iter->st != AFS_STATUS_OK) && (iter->st != ADMITERATORDONE)) {
848         tst = iter->st;
849         goto fail_IteratorNext;
850     }
851  
852     /*
853      * Check to see if there are any queue'd items.  If not, wait here
854      * until signalled by the producer.
855      */
856  
857     while (iter->cache_slots_used == 0) {
858  
859         /*
860          * Maybe the producer experienced an rpc failure.
861          */
862  
863         if ((!iter->done_iterating) && (iter->st != 0)) {
864             tst = iter->st;
865             goto fail_IteratorNext;
866         }
867  
868         /*
869          * Maybe there are no queue'd items because the producer is done
870          */
871  
872         if (iter->done_iterating) {
873             tst = iter->st;
874             goto fail_IteratorNext;
875         }
876  
877         if (pthread_cond_wait(&iter->add_item, &iter->mutex)) {
878             tst = ADMCONDWAIT;
879             goto fail_IteratorNext;
880         }
881     }
882  
883     /*
884      * Copy the next cached item and update the cached item count
885      * and the index into the cache array
886      */
887  
888     if (!iter->get_cached_data(iter->rpc_specific, 
889                                iter->cache_queue_head,
890                                dest,
891                                &tst)) {
892         goto fail_IteratorNext;
893     }
894     
895     iter->cache_queue_head = (iter->cache_queue_head + 1) % CACHED_ITEMS;
896     iter->cache_slots_used--;
897  
898     /*
899      * If the cache was full before we removed the item above, the
900      * producer may have been waiting for us to remove an item.
901      * Signal the producer letting him know that we've opened a slot
902      * in the cache
903      */
904  
905     if (iter->cache_slots_used == (CACHED_ITEMS - 1)) {
906         if (pthread_cond_signal(&iter->remove_item)) {
907             tst = ADMCONDSIGNAL;
908             goto fail_IteratorNext;
909         }
910     }
911     rc = 1;
912
913
914 fail_IteratorNext:
915  
916     if (locked_iter == 1) {
917         pthread_mutex_unlock(&iter->mutex);
918     }
919
920     if (st != NULL) {
921         *st = tst;
922     }
923     return rc;
924 }
925
926 /*
927  * IteratorDone - mark the iterator done.
928  *
929  * PARAMETERS
930  *
931  * IN interator - the iterator to mark done.
932  *
933  * LOCKS
934  *
935  * Lock the iterator upon entry, and hold it during the duration of this
936  * function.
937  *
938  * RETURN CODES
939  *
940  * Returns != 0 upon successful completion.
941  */
942
943 int IteratorDone(
944   afs_admin_iterator_p iter,
945   afs_status_p st)
946 {
947     int rc = 0;
948     afs_status_t tst = 0;
949     int mutex_locked = 1;
950
951     if (pthread_mutex_lock(&iter->mutex)) {
952         tst = ADMMUTEXLOCK;
953         goto fail_IteratorDone;
954     }
955  
956     mutex_locked = 1;
957  
958  
959     if (!IsValidIterator(iter, &tst)) {
960         goto fail_IteratorDone;
961     }
962  
963  
964     /*
965      * Depending upon the status of the background worker thread,
966      * we can either join with him immediately (if we know he has
967      * terminated), or we need to tell him the request has been
968      * terminated and then join with him.
969      */
970
971     if (!iter->done_iterating) {
972         iter->request_terminated = 1;
973         iter->cache_slots_used = 0;
974         pthread_cond_signal(&iter->remove_item);
975     }
976
977     /*
978      * We have to unlock the mutex to allow the background thread to
979      * progress
980      */
981
982     if (pthread_mutex_unlock(&iter->mutex)) {
983         tst = ADMMUTEXUNLOCK;
984         goto fail_IteratorDone;
985     }
986
987     if (iter->make_rpc != NULL) {
988         if (pthread_join(iter->bg_worker, (void **) 0)) {
989             tst = ADMTHREADJOIN;
990             goto fail_IteratorDone;
991         }
992     }
993
994     /*
995      * We don't relock the mutex here since we are the only thread
996      * that has access to the iter now
997      */
998
999     rc = IteratorDelete(iter, &tst);
1000     mutex_locked = 0;
1001
1002 fail_IteratorDone:
1003  
1004     if (mutex_locked) {
1005         pthread_mutex_unlock(&iter->mutex);
1006     }
1007
1008     if (st != NULL) {
1009         *st = tst;
1010     }
1011     return rc;
1012 }
1013
1014 /*
1015  * IteratorInit - initialize an iterator.
1016  *
1017  * PARAMETERS
1018  *
1019  * IN interator - the iterator to initialize.
1020  *
1021  * LOCKS
1022  *
1023  * No locks are held by this function.
1024  *
1025  * RETURN CODES
1026  *
1027  * Returns != 0 upon successful completion.
1028  */
1029
1030 int IteratorInit(
1031   afs_admin_iterator_p iter,
1032   void *rpc_specific,
1033   make_rpc_func make_rpc,
1034   get_cached_data_func get_cached_data,
1035   validate_specific_data_func validate_specific_data,
1036   destroy_specific_data_func destroy_specific_data,
1037   afs_status_p st)
1038 {
1039     int rc = 0;
1040     afs_status_t tst = 0;
1041     int mutex_inited = 0;
1042     int add_item_cond_inited = 0;
1043     int remove_item_cond_inited = 0;
1044
1045     if (iter == NULL) {
1046         tst = ADMITERATORNULL;
1047         goto fail_IteratorInit;
1048     }
1049  
1050     if (rpc_specific == NULL) {
1051         tst = ADMITERATORRPCSPECIFICNULL;
1052         goto fail_IteratorInit;
1053     }
1054  
1055     /*
1056      * Initialize the iterator structure
1057      */
1058     iter->begin_magic = BEGIN_MAGIC;
1059     iter->end_magic = END_MAGIC;
1060     iter->is_valid = 1;
1061     iter->cache_slots_used = 0;
1062     iter->done_iterating = 0;
1063     iter->request_terminated = 0;
1064     iter->st = AFS_STATUS_OK;
1065     iter->cache_queue_head = 0;
1066     iter->cache_queue_tail = 0;
1067     iter->cache_slots_used = 0;
1068     iter->rpc_specific = rpc_specific;
1069     iter->make_rpc = make_rpc;
1070     iter->get_cached_data = get_cached_data;
1071     iter->validate_specific = validate_specific_data;
1072     iter->destroy_specific = destroy_specific_data;
1073
1074     if (pthread_mutex_init(&iter->mutex, (const pthread_mutexattr_t *) 0)) {
1075         tst = ADMMUTEXINIT;
1076         goto fail_IteratorInit;
1077     } else {
1078         mutex_inited = 1;
1079     }
1080
1081     if (pthread_cond_init(&iter->add_item, (const pthread_condattr_t *) 0)) {
1082         tst = ADMCONDINIT;
1083         goto fail_IteratorInit;
1084     } else {
1085         add_item_cond_inited = 1;
1086     }
1087
1088     if (pthread_cond_init(&iter->remove_item, (const pthread_condattr_t *) 0)) {
1089         tst = ADMCONDINIT;
1090         goto fail_IteratorInit;
1091     } else {
1092         remove_item_cond_inited = 1;
1093     }
1094
1095     /*
1096      * Create a worker thread that will begin to query the server
1097      * and cache responses.
1098      */
1099
1100     if (iter->make_rpc != NULL) {
1101         pthread_attr_t tattr;
1102
1103         if (pthread_attr_init(&tattr)) {
1104             tst = ADMTHREADATTRINIT;
1105             goto fail_IteratorInit;
1106         }
1107
1108         if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
1109             tst = ADMTHREADATTRSETDETACHSTATE;
1110             goto fail_IteratorInit;
1111         }
1112
1113         if (pthread_create(&iter->bg_worker, &tattr,
1114                            DataGet, (void *) iter)) {
1115             tst = ADMTHREADCREATE;
1116             goto fail_IteratorInit;
1117         }
1118     }
1119     rc = 1;
1120
1121 fail_IteratorInit:
1122  
1123     if (rc == 0) {
1124         if (mutex_inited) {
1125             pthread_mutex_destroy(&iter->mutex);
1126         }
1127         if (remove_item_cond_inited) {
1128             pthread_cond_destroy(&iter->remove_item);
1129         }
1130         if (add_item_cond_inited) {
1131             pthread_cond_destroy(&iter->add_item);
1132         }
1133     }
1134
1135     if (st != NULL) {
1136         *st = tst;
1137     }
1138     return rc;
1139 }
1140
1141 int ADMINAPI CellHandleIsValid(
1142   const void *cellHandle,
1143   afs_status_p st)
1144 {
1145     int rc = 0;
1146     afs_status_t tst = 0;
1147     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1148  
1149     /*
1150      * Validate input parameters
1151      */
1152  
1153     if (c_handle == NULL) {
1154         tst = ADMCLIENTCELLHANDLENULL;
1155         goto fail_CellHandleIsValid;
1156     }
1157  
1158     if ((c_handle->begin_magic != BEGIN_MAGIC) ||
1159         (c_handle->end_magic != END_MAGIC)) {
1160         tst = ADMCLIENTCELLHANDLEBADMAGIC;
1161         goto fail_CellHandleIsValid;
1162     }
1163  
1164     if (c_handle->is_valid == 0) {
1165         tst = ADMCLIENTCELLINVALID;
1166         goto fail_CellHandleIsValid;
1167     }
1168     rc = 1;
1169  
1170 fail_CellHandleIsValid:
1171  
1172     if (st != NULL) {
1173         *st = tst;
1174     }
1175     return rc;
1176 }
1177
1178 /*
1179  * The iterator functions and data for the rpc statistic retrieval functions
1180  */
1181
1182 typedef struct rpc_stat_get {
1183   afs_uint32 clock_sec;
1184   afs_uint32 clock_usec;
1185   afs_uint32 index;
1186   afs_uint32 total;
1187   afs_uint32 clientVersion;
1188   afs_uint32 serverVersion;
1189   struct rpcStats stat_list;
1190   afs_RPCStats_t stats[CACHED_ITEMS];
1191   afs_uint32 *pointer;
1192 } rpc_stat_get_t, *rpc_stat_get_p;
1193
1194 static void UnmarshallRPCStats(
1195     afs_uint32 serverVersion,
1196     afs_uint32 **ptrP,
1197     afs_RPCUnion_p s)
1198 {
1199     afs_uint32 *ptr;
1200     unsigned int hi, lo;
1201
1202     /*
1203      * Server must always match lower versions. We are version 1.
1204      */
1205     ptr = *ptrP;
1206     s->stats_v1.remote_peer = *(ptr++);
1207     s->stats_v1.remote_port = *(ptr++);
1208     s->stats_v1.remote_is_server = *(ptr++);
1209     s->stats_v1.interfaceId = *(ptr++);
1210     s->stats_v1.func_total = *(ptr++);
1211     s->stats_v1.func_index = *(ptr++);
1212     hi = *(ptr++);
1213     lo = *(ptr++);
1214     hset64(s->stats_v1.invocations, hi, lo);
1215     hi = *(ptr++);
1216     lo = *(ptr++);
1217     hset64(s->stats_v1.bytes_sent, hi, lo);
1218     hi = *(ptr++);
1219     lo = *(ptr++);
1220     hset64(s->stats_v1.bytes_rcvd, hi, lo);
1221     s->stats_v1.queue_time_sum.sec = *(ptr++);
1222     s->stats_v1.queue_time_sum.usec = *(ptr++);
1223     s->stats_v1.queue_time_sum_sqr.sec = *(ptr++);
1224     s->stats_v1.queue_time_sum_sqr.usec = *(ptr++);
1225     s->stats_v1.queue_time_min.sec = *(ptr++);
1226     s->stats_v1.queue_time_min.usec = *(ptr++);
1227     s->stats_v1.queue_time_max.sec = *(ptr++);
1228     s->stats_v1.queue_time_max.usec = *(ptr++);
1229     s->stats_v1.execution_time_sum.sec = *(ptr++);
1230     s->stats_v1.execution_time_sum.usec = *(ptr++);
1231     s->stats_v1.execution_time_sum_sqr.sec = *(ptr++);
1232     s->stats_v1.execution_time_sum_sqr.usec = *(ptr++);
1233     s->stats_v1.execution_time_min.sec = *(ptr++);
1234     s->stats_v1.execution_time_min.usec = *(ptr++);
1235     s->stats_v1.execution_time_max.sec = *(ptr++);
1236     s->stats_v1.execution_time_max.usec = *(ptr++);
1237     *ptrP = ptr;
1238 }
1239
1240 static int GetRPCStatsRPC(
1241   void *rpc_specific,
1242   int slot,
1243   int *last_item,
1244   int *last_item_contains_data,
1245   afs_status_p st)
1246 {
1247     int rc = 0;
1248     afs_status_t tst = 0;
1249     rpc_stat_get_p t = (rpc_stat_get_p) rpc_specific;
1250
1251     t->stats[slot].clientVersion = t->clientVersion;
1252     t->stats[slot].serverVersion = t->serverVersion;
1253     t->stats[slot].statCount = t->total;
1254
1255     /*
1256      * If the server stat version is greater than or equal to my version
1257      * number, it is required to return the values in the client's current
1258      * format
1259      */
1260
1261     UnmarshallRPCStats(t->serverVersion,
1262                        &t->pointer,
1263                        &t->stats[slot].s);
1264
1265     t->index++;
1266
1267     /*
1268      * See if we've processed all the entries
1269      */
1270
1271     if (t->index == t->total) {
1272         *last_item = 1;
1273         *last_item_contains_data = 1;
1274     }
1275     rc = 1;
1276
1277     if (st != NULL) {
1278         *st = tst;
1279     }
1280     return rc;
1281 }
1282
1283 static int GetRPCStatsFromCache(
1284   void *rpc_specific,
1285   int slot,
1286   void *dest,
1287   afs_status_p st)
1288 {
1289     int rc = 0;
1290     afs_status_t tst = 0;
1291     rpc_stat_get_p stat = (rpc_stat_get_p) rpc_specific;
1292
1293     memcpy(dest, (const void *) &stat->stats[slot],
1294            sizeof(afs_RPCStats_t));
1295
1296     rc = 1;
1297     if (st != NULL) {
1298         *st = tst;
1299     }
1300     return rc;
1301 }
1302
1303 static int DestroyRPCStats(
1304   void *rpc_specific,
1305   afs_status_p st)
1306 {
1307     int rc = 0;
1308     afs_status_t tst = 0;
1309     rpc_stat_get_p stat = (rpc_stat_get_p) rpc_specific;
1310
1311     if (stat->stat_list.rpcStats_val != NULL) {
1312         free(stat->stat_list.rpcStats_val);
1313     }
1314     rc = 1;
1315
1316     if (st != NULL) {
1317         *st = tst;
1318     }
1319     return rc;
1320 }
1321
1322 /*
1323  * util_RPCStatsGetBegin - begin retrieving rpc stats for a process
1324  *
1325  * PARAMETERS
1326  *
1327  * IN conn - an rx connection to the process to be queried
1328  *
1329  * IN rpc - the function to call to make the actual rpc
1330  *
1331  * OUT iterationIdP - an iteration id that can be passed to
1332  * util_RPCStatsGetNext to get the next rpc stat
1333  *
1334  * LOCKS
1335  *
1336  * No locks are obtained or released by this function
1337  *
1338  * RETURN CODES
1339  *
1340  * Returns != 0 upon successful completion.
1341  *
1342  */
1343
1344 int ADMINAPI util_RPCStatsGetBegin(
1345   struct rx_connection *conn,
1346   int (*rpc)(),
1347   void **iterationIdP,
1348   afs_status_p st)
1349 {
1350     int rc = 0;
1351     afs_status_t tst = 0;
1352     afs_admin_iterator_p iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1353     rpc_stat_get_p stat = (rpc_stat_get_p) malloc(sizeof(rpc_stat_get_t));
1354
1355     if (conn == NULL) {
1356         tst = ADMRXCONNNULL;
1357         goto fail_util_RPCStatsGetBegin;
1358     }
1359
1360     if (rpc == NULL) {
1361         tst = ADMRPCPTRNULL;
1362         goto fail_util_RPCStatsGetBegin;
1363     }
1364
1365     if (iterationIdP == NULL) {
1366         tst = ADMITERATIONIDPNULL;
1367         goto fail_util_RPCStatsGetBegin;
1368     }
1369
1370     if ((iter == NULL) || (stat == NULL)) {
1371         tst = ADMNOMEM;
1372         goto fail_util_RPCStatsGetBegin;
1373     }
1374
1375     stat->stat_list.rpcStats_len = 0;
1376     stat->stat_list.rpcStats_val = 0;
1377     stat->index = 0;
1378     stat->clientVersion = RX_STATS_RETRIEVAL_VERSION;
1379
1380     tst = (*rpc)(conn,
1381                stat->clientVersion,
1382                &stat->serverVersion,
1383                &stat->clock_sec,
1384                &stat->clock_usec,
1385                &stat->total,
1386                &stat->stat_list);
1387
1388     if (tst != 0) {
1389         goto fail_util_RPCStatsGetBegin;
1390     }
1391
1392     /*
1393      * If there are no statistics, just mark the iterator done and
1394      * return.
1395      */
1396
1397     if (stat->stat_list.rpcStats_len == 0) {
1398         stat->pointer = NULL;
1399         if (!IteratorInit(iter,
1400                          (void *) stat,
1401                          NULL,
1402                          NULL,
1403                          NULL,
1404                          NULL,
1405                          &tst)) {
1406             goto fail_util_RPCStatsGetBegin;
1407         }
1408         iter->done_iterating = 1;
1409         iter->st = ADMITERATORDONE;
1410     } else {
1411         stat->pointer = stat->stat_list.rpcStats_val;
1412         if (!IteratorInit(iter,
1413                          (void *) stat,
1414                          GetRPCStatsRPC,
1415                          GetRPCStatsFromCache,
1416                          NULL,
1417                          DestroyRPCStats,
1418                          &tst)) {
1419             goto fail_util_RPCStatsGetBegin;
1420         }
1421     }
1422     *iterationIdP = (void *) iter;
1423     rc = 1;
1424
1425 fail_util_RPCStatsGetBegin:
1426
1427     if (rc == 0) {
1428         if (iter != NULL) {
1429             free(iter);
1430         }
1431         if (stat != NULL) {
1432             free(stat);
1433         }
1434     }
1435
1436     if (st != NULL) {
1437         *st = tst;
1438     }
1439     return rc;
1440 }
1441
1442 /*
1443  * util_RPCStatsGetNext - retrieve the next rpc stat from the server
1444  *
1445  * PARAMETERS
1446  *
1447  * IN iterationId - an iterator previously returned by
1448  * util_RPCStatsGetBegin.
1449  *
1450  * OUT stats - upon successful completion contains the next set of stats
1451  * from the server
1452  *
1453  * LOCKS
1454  *
1455  * No locks are obtained or released by this function
1456  *
1457  * RETURN CODES
1458  *
1459  * Returns != 0 upon successful completion.
1460  *
1461  */
1462
1463 int ADMINAPI util_RPCStatsGetNext(
1464   const void *iterationId,
1465   afs_RPCStats_p stats,
1466   afs_status_p st)
1467 {
1468     int rc = 0;
1469     afs_status_t tst = 0;
1470     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1471
1472     if (iterationId == NULL) {
1473         tst = ADMITERATIONIDPNULL;
1474         goto fail_util_RPCStatsGetNext;
1475     }
1476
1477     if (stats == NULL) {
1478         tst = ADMUTILRPCSTATSNULL;
1479         goto fail_util_RPCStatsGetNext;
1480     }
1481
1482     rc = IteratorNext(iter, (void *) stats, &tst);
1483
1484 fail_util_RPCStatsGetNext:
1485
1486     if (st != NULL) {
1487         *st = tst;
1488     }
1489     return rc;
1490 }
1491
1492 /*
1493  * util_RPCStatsGetDone - finish using a stats iterator
1494  *
1495  * PARAMETERS
1496  *
1497  * IN iterationId - an iterator previously returned by
1498  * util_RPCStatsGetBegin.
1499  *
1500  * LOCKS
1501  *
1502  * No locks are obtained or released by this function
1503  *
1504  * RETURN CODES
1505  *
1506  * Returns != 0 upon successful completion.
1507  *
1508  */
1509
1510 int ADMINAPI util_RPCStatsGetDone(
1511   const void *iterationId,
1512   afs_status_p st)
1513 {
1514     int rc = 0;
1515     afs_status_t tst = 0;
1516     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1517
1518     if (iterationId == NULL) {
1519         tst = ADMITERATIONIDPNULL;
1520         goto fail_util_RPCStatsGetDone;
1521     }
1522
1523     rc = IteratorDone(iter, &tst);
1524
1525 fail_util_RPCStatsGetDone:
1526
1527     if (st != NULL) {
1528         *st = tst;
1529     }
1530     return rc;
1531 }
1532
1533 /*
1534  * util_RPCStatsStateGet - get the current state of rpc stat collection
1535  *
1536  * PARAMETERS
1537  *
1538  * IN conn - an rx connection to the process to be queried
1539  *
1540  * IN rpc - the function to call to make the actual rpc
1541  *
1542  * OUT state - the rpc stat collection state.
1543  *
1544  * LOCKS
1545  *
1546  * No locks are obtained or released by this function
1547  *
1548  * RETURN CODES
1549  *
1550  * Returns != 0 upon successful completion.
1551  *
1552  */
1553
1554 int ADMINAPI util_RPCStatsStateGet(
1555   struct rx_connection *conn,
1556   int (*rpc)(),
1557   afs_RPCStatsState_p state,
1558   afs_status_p st)
1559 {
1560     int rc = 0;
1561     afs_status_t tst = 0;
1562
1563     if (conn == NULL) {
1564         tst = ADMRXCONNNULL;
1565         goto fail_util_RPCStatsStateGet;
1566     }
1567
1568     if (rpc == NULL) {
1569         tst = ADMRPCPTRNULL;
1570         goto fail_util_RPCStatsStateGet;
1571     }
1572
1573     if (state == NULL) {
1574         tst = ADMRPCSTATENULL;
1575         goto fail_util_RPCStatsStateGet;
1576     }
1577
1578     tst = (*rpc)(conn, state);
1579
1580     if (!tst) {
1581         rc = 1;
1582     }
1583
1584 fail_util_RPCStatsStateGet:
1585
1586     if (st != NULL) {
1587         *st = tst;
1588     }
1589     return rc;
1590 }
1591
1592 /*
1593  * util_RPCStatsStateEnable - enable rpc stat collection
1594  * to enabled
1595  *
1596  * PARAMETERS
1597  *
1598  * IN conn - an rx connection to the process to be modified
1599  *
1600  * IN rpc - the function to call to make the actual rpc
1601  *
1602  * LOCKS
1603  *
1604  * No locks are obtained or released by this function
1605  *
1606  * RETURN CODES
1607  *
1608  * Returns != 0 upon successful completion.
1609  *
1610  */
1611
1612 int ADMINAPI util_RPCStatsStateEnable(
1613   struct rx_connection *conn,
1614   int (*rpc)(),
1615   afs_status_p st)
1616 {
1617     int rc = 0;
1618     afs_status_t tst = 0;
1619
1620     if (conn == NULL) {
1621         tst = ADMRXCONNNULL;
1622         goto fail_util_RPCStatsStateEnable;
1623     }
1624
1625     if (rpc == NULL) {
1626         tst = ADMRPCPTRNULL;
1627         goto fail_util_RPCStatsStateEnable;
1628     }
1629
1630     tst = (*rpc)(conn);
1631
1632     if (!tst) {
1633         rc = 1;
1634     }
1635
1636 fail_util_RPCStatsStateEnable:
1637
1638     if (st != NULL) {
1639         *st = tst;
1640     }
1641     return rc;
1642 }
1643
1644 /*
1645  * util_RPCStatsStateDisable - set the current state of rpc stat collection
1646  * to disabled
1647  *
1648  * PARAMETERS
1649  *
1650  * IN conn - an rx connection to the process to be modified
1651  *
1652  * IN rpc - the function to call to make the actual rpc
1653  *
1654  * LOCKS
1655  *
1656  * No locks are obtained or released by this function
1657  *
1658  * RETURN CODES
1659  *
1660  * Returns != 0 upon successful completion.
1661  *
1662  */
1663
1664 int ADMINAPI util_RPCStatsStateDisable(
1665   struct rx_connection *conn,
1666   int (*rpc)(),
1667   afs_status_p st)
1668 {
1669     int rc = 0;
1670     afs_status_t tst = 0;
1671
1672     if (conn == NULL) {
1673         tst = ADMRXCONNNULL;
1674         goto fail_util_RPCStatsStateDisable;
1675     }
1676
1677     if (rpc == NULL) {
1678         tst = ADMRPCPTRNULL;
1679         goto fail_util_RPCStatsStateDisable;
1680     }
1681
1682     tst = (*rpc)(conn);
1683
1684     if (!tst) {
1685         rc = 1;
1686     }
1687
1688 fail_util_RPCStatsStateDisable:
1689
1690     if (st != NULL) {
1691         *st = tst;
1692     }
1693     return rc;
1694 }
1695
1696 /*
1697  * util_RPCStatsClear - clear some or all of the fields in the rpc stat
1698  * collection at a server
1699  *
1700  * PARAMETERS
1701  *
1702  * IN conn - an rx connection to the process to be modified
1703  *
1704  * IN rpc - the function to call to make the actual rpc
1705  *
1706  * IN flag - a flag containing the fields to be cleared
1707  *
1708  *
1709  * LOCKS
1710  *
1711  * No locks are obtained or released by this function
1712  *
1713  * RETURN CODES
1714  *
1715  * Returns != 0 upon successful completion.
1716  *
1717  */
1718
1719 int ADMINAPI util_RPCStatsClear(
1720   struct rx_connection *conn,
1721   int (*rpc)(),
1722   afs_RPCStatsClearFlag_t flag,
1723   afs_status_p st)
1724 {
1725     int rc = 0;
1726     afs_status_t tst = 0;
1727
1728     if (conn == NULL) {
1729         tst = ADMRXCONNNULL;
1730         goto fail_util_RPCStatsClear;
1731     }
1732
1733     if (rpc == NULL) {
1734         tst = ADMRPCPTRNULL;
1735         goto fail_util_RPCStatsClear;
1736     }
1737
1738     tst = (*rpc)(conn, flag);
1739
1740     if (!tst) {
1741         rc = 1;
1742     }
1743
1744 fail_util_RPCStatsClear:
1745
1746     if (st != NULL) {
1747         *st = tst;
1748     }
1749     return rc;
1750 }
1751
1752 /*
1753  * util_RPCStatsVersionGet - get the current version of rpc stat collection
1754  *
1755  * PARAMETERS
1756  *
1757  * IN conn - an rx connection to the process to be modified
1758  *
1759  * OUT version - the version of rpc stat collection at the remote process
1760  *
1761  * LOCKS
1762  *
1763  * No locks are obtained or released by this function
1764  *
1765  * RETURN CODES
1766  *
1767  * Returns != 0 upon successful completion.
1768  *
1769  */
1770
1771 int ADMINAPI util_RPCStatsVersionGet(
1772   struct rx_connection *conn,
1773   afs_RPCStatsVersion_p version,
1774   afs_status_p st)
1775 {
1776     int rc = 0;
1777     afs_status_t tst = 0;
1778
1779     if (conn == NULL) {
1780         tst = ADMRXCONNNULL;
1781         goto fail_util_RPCStatsVersionGet;
1782     }
1783
1784     if (version == NULL) {
1785         tst = ADMRPCVERSIONNULL;
1786         goto fail_util_RPCStatsVersionGet;
1787     }
1788
1789     tst = RXSTATS_QueryRPCStatsVersion(conn, version);
1790
1791     if (!tst) {
1792         rc = 1;
1793     }
1794
1795 fail_util_RPCStatsVersionGet:
1796
1797     if (st != NULL) {
1798         *st = tst;
1799     }
1800     return rc;
1801 }
1802
1803 /*
1804  * The iterator for listing CM server preferences
1805  */
1806
1807 typedef struct cm_srvr_pref_get {
1808   struct rx_connection *conn;
1809   afs_int32 index;
1810   afs_CMServerPref_t srvrPrefs[CACHED_ITEMS];
1811 } cm_srvr_pref_get_t, *cm_srvr_pref_get_p;
1812
1813 static int GetServerPrefsRPC(
1814   void *rpc_specific,
1815   int slot,
1816   int *last_item,
1817   int *last_item_contains_data,
1818   afs_status_p st)
1819 {
1820     int rc = 0;
1821     afs_status_t tst = 0;
1822     cm_srvr_pref_get_p t = (cm_srvr_pref_get_p) rpc_specific;
1823
1824     /*
1825      * Get the next entry in the list of server preferences.
1826      */
1827     tst = RXAFSCB_GetServerPrefs(t->conn, t->index,
1828                                  &t->srvrPrefs[slot].ipAddr,
1829                                  &t->srvrPrefs[slot].ipRank);
1830     if (tst) {
1831         goto fail_GetServerPrefsRPC;
1832     }
1833
1834     /*
1835      * See if we've processed all the entries
1836      */
1837     if (t->srvrPrefs[slot].ipAddr == 0xffffffff) {
1838         *last_item = 1;
1839         *last_item_contains_data = 0;
1840     } else {
1841         t->index += 1;
1842     }
1843     rc = 1;
1844
1845 fail_GetServerPrefsRPC:
1846
1847     if (st != NULL) {
1848         *st = tst;
1849     }
1850     return rc;
1851 }
1852
1853 static int GetServerPrefsFromCache(
1854   void *rpc_specific,
1855   int slot,
1856   void *dest,
1857   afs_status_p st)
1858 {
1859     int rc = 0;
1860     afs_status_t tst = 0;
1861     cm_srvr_pref_get_p prefs = (cm_srvr_pref_get_p) rpc_specific;
1862
1863     memcpy(dest, (const void *) &prefs->srvrPrefs[slot],
1864            sizeof(afs_CMServerPref_t));
1865
1866     rc = 1;
1867     if (st != NULL) {
1868         *st = tst;
1869     }
1870     return rc;
1871 }
1872
1873 /*
1874  * util_CMGetServerPrefsBegin - Begin listing cache manager server preferences
1875  *
1876  * PARAMETERS
1877  *
1878  * IN conn - an rx connection to the process to be queried
1879  *
1880  * OUT iterationIdP - an iteration id that can be passed to
1881  * util_CMGetServerPrefsNext to get the next server preference
1882  *
1883  * LOCKS
1884  *
1885  * No locks are obtained or released by this function
1886  *
1887  * RETURN CODES
1888  *
1889  * Returns != 0 upon successful completion.
1890  *
1891  */
1892
1893 int ADMINAPI util_CMGetServerPrefsBegin(
1894   struct rx_connection *conn,
1895   void **iterationIdP,
1896   afs_status_p st)
1897 {
1898     int rc = 0;
1899     afs_status_t tst = 0;
1900     afs_admin_iterator_p iter;
1901     cm_srvr_pref_get_p pref;
1902
1903     if (conn == NULL) {
1904         tst = ADMRXCONNNULL;
1905         goto fail_util_CMGetServerPrefsBegin;
1906     }
1907
1908     iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1909     if (iter == NULL) {
1910         tst = ADMNOMEM;
1911         goto fail_util_CMGetServerPrefsBegin;
1912     }
1913
1914     pref = (cm_srvr_pref_get_p) malloc(sizeof(cm_srvr_pref_get_t));
1915     if (pref == NULL) {
1916         free(iter);
1917         tst = ADMNOMEM;
1918         goto fail_util_CMGetServerPrefsBegin;
1919     }
1920
1921     pref->conn = conn;
1922     pref->index = 0;
1923     if (!IteratorInit(iter, (void *) pref, GetServerPrefsRPC,
1924                       GetServerPrefsFromCache, NULL, NULL, &tst)) {
1925         free(iter);
1926         free(pref);
1927         goto fail_util_CMGetServerPrefsBegin;
1928     }
1929     *iterationIdP = (void *) iter;
1930     rc = 1;
1931
1932 fail_util_CMGetServerPrefsBegin:
1933
1934     if (st != NULL) {
1935         *st = tst;
1936     }
1937     return rc;
1938 }
1939
1940 /*
1941  * util_CMGetServerPrefsNext - Get next entry in cache manager server
1942  *                             preferences
1943  *
1944  * PARAMETERS
1945  *
1946  * IN iterationId - Iteration id created by util_CMGetServerPrefsBegin.
1947  *
1948  * OUT prefs - Next entry in cache manager server preferences.
1949  *
1950  * LOCKS
1951  *
1952  * No locks are obtained or released by this function
1953  *
1954  * RETURN CODES
1955  *
1956  * Returns != 0 upon successful completion.
1957  *
1958  */
1959
1960 int ADMINAPI util_CMGetServerPrefsNext(
1961   const void *iterationId,
1962   afs_CMServerPref_p prefs,
1963   afs_status_p st)
1964 {
1965     int rc = 0;
1966     afs_status_t tst = 0;
1967     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1968
1969     if (iterationId == NULL) {
1970         tst = ADMITERATIONIDPNULL;
1971         goto fail_util_CMGetServerPrefsNext;
1972     }
1973
1974     rc = IteratorNext(iter, (void *) prefs, &tst);
1975
1976 fail_util_CMGetServerPrefsNext:
1977
1978     if (st != NULL) {
1979         *st = tst;
1980     }
1981     return rc;
1982 }
1983
1984 /*
1985  * util_CMGetServerPrefsDone - Finish listing cache manager server
1986  *                             preferences
1987  *
1988  * PARAMETERS
1989  *
1990  * IN iterationId - Iteration id created by util_CMGetServerPrefsBegin.
1991  *
1992  * LOCKS
1993  *
1994  * No locks are obtained or released by this function
1995  *
1996  * RETURN CODES
1997  *
1998  * Returns != 0 upon successful completion.
1999  *
2000  */
2001
2002 int ADMINAPI util_CMGetServerPrefsDone(
2003   const void *iterationId,
2004   afs_status_p st)
2005 {
2006     int rc = 0;
2007     afs_status_t tst = 0;
2008     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2009
2010     if (iterationId == NULL) {
2011         tst = ADMITERATIONIDPNULL;
2012         goto fail_util_CMGetServerPrefsDone;
2013     }
2014
2015     rc = IteratorDone(iter, &tst);
2016
2017
2018 fail_util_CMGetServerPrefsDone:
2019
2020     if (st != NULL) {
2021         *st = tst;
2022     }
2023     return rc;
2024 }
2025
2026 /*
2027  * The iterator for listing CM CellServDB
2028  */
2029
2030 typedef struct cm_list_cell_get {
2031   struct rx_connection *conn;
2032   afs_int32 index;
2033   afs_CMListCell_t cell[CACHED_ITEMS];
2034 } cm_list_cell_get_t, *cm_list_cell_get_p;
2035
2036 static int ListCellsRPC(
2037   void *rpc_specific,
2038   int slot,
2039   int *last_item,
2040   int *last_item_contains_data,
2041   afs_status_p st)
2042 {
2043     int rc = 0;
2044     afs_status_t tst = 0;
2045     cm_list_cell_get_p t = (cm_list_cell_get_p) rpc_specific;
2046     char *name;
2047
2048     /*
2049      * Get the next entry in the CellServDB.
2050      */
2051     name = t->cell[slot].cellname;
2052     tst = RXAFSCB_GetCellServDB(t->conn, t->index, &name,
2053                                 t->cell[slot].serverAddr);
2054     if (tst) {
2055         goto fail_ListCellsRPC;
2056     }
2057     strcpy(t->cell[slot].cellname, name);
2058
2059     /*
2060      * See if we've processed all the entries
2061      */
2062     if (strlen(t->cell[slot].cellname) == 0) {
2063         *last_item = 1;
2064         *last_item_contains_data = 0;
2065     } else {
2066         t->index += 1;
2067     }
2068     rc = 1;
2069
2070 fail_ListCellsRPC:
2071
2072     if (st != NULL) {
2073         *st = tst;
2074     }
2075     return rc;
2076 }
2077
2078 static int ListCellsFromCache(
2079   void *rpc_specific,
2080   int slot,
2081   void *dest,
2082   afs_status_p st)
2083 {
2084     int rc = 0;
2085     afs_status_t tst = 0;
2086     cm_list_cell_get_p cell = (cm_list_cell_get_p) rpc_specific;
2087
2088     memcpy(dest, (const void *) &cell->cell[slot],
2089            sizeof(afs_CMListCell_t));
2090
2091     rc = 1;
2092     if (st != NULL) {
2093         *st = tst;
2094     }
2095     return rc;
2096 }
2097
2098 /*
2099  * util_CMListCellsBegin - Begin listing cache manager CellServDB
2100  *
2101  * PARAMETERS
2102  *
2103  * IN conn - an rx connection to the process to be queried
2104  *
2105  * OUT iterationIdP - an iteration id that can be passed to
2106  * util_CMListCellsNext to get the next cell
2107  *
2108  * LOCKS
2109  *
2110  * No locks are obtained or released by this function
2111  *
2112  * RETURN CODES
2113  *
2114  * Returns != 0 upon successful completion.
2115  *
2116  */
2117
2118 int ADMINAPI util_CMListCellsBegin(
2119   struct rx_connection *conn,
2120   void **iterationIdP,
2121   afs_status_p st)
2122 {
2123     int rc = 0;
2124     afs_status_t tst = 0;
2125     afs_admin_iterator_p iter;
2126     cm_list_cell_get_p cell;
2127
2128     if (conn == NULL) {
2129         tst = ADMRXCONNNULL;
2130         goto fail_util_CMListCellsBegin;
2131     }
2132
2133     iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
2134     if (iter == NULL) {
2135         tst = ADMNOMEM;
2136         goto fail_util_CMListCellsBegin;
2137     }
2138
2139     cell = (cm_list_cell_get_p) malloc(sizeof(cm_list_cell_get_t));
2140     if (cell == NULL) {
2141         free(iter);
2142         tst = ADMNOMEM;
2143         goto fail_util_CMListCellsBegin;
2144     }
2145
2146     cell->conn = conn;
2147     cell->index = 0;
2148     if (!IteratorInit(iter, (void *) cell, ListCellsRPC,
2149                       ListCellsFromCache, NULL, NULL, &tst)) {
2150         free(iter);
2151         free(cell);
2152         goto fail_util_CMListCellsBegin;
2153     }
2154     *iterationIdP = (void *) iter;
2155     rc = 1;
2156
2157 fail_util_CMListCellsBegin:
2158
2159     if (st != NULL) {
2160         *st = tst;
2161     }
2162     return rc;
2163 }
2164
2165 /*
2166  * util_CMListCellsNext - Get next entry in cache manager cells
2167  *
2168  * PARAMETERS
2169  *
2170  * IN iterationId - Iteration id created by util_CMGetServerPrefsBegin.
2171  *
2172  * OUT cell - Next entry in cache manager cells.
2173  *
2174  * LOCKS
2175  *
2176  * No locks are obtained or released by this function
2177  *
2178  * RETURN CODES
2179  *
2180  * Returns != 0 upon successful completion.
2181  *
2182  */
2183
2184 int ADMINAPI util_CMListCellsNext(
2185   const void *iterationId,
2186   afs_CMListCell_p cell,
2187   afs_status_p st)
2188 {
2189     int rc = 0;
2190     afs_status_t tst = 0;
2191     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2192
2193     if (iterationId == NULL) {
2194         tst = ADMITERATIONIDPNULL;
2195         goto fail_util_CMListCellsNext;
2196     }
2197
2198     rc = IteratorNext(iter, (void *) cell, &tst);
2199
2200 fail_util_CMListCellsNext:
2201
2202     if (st != NULL) {
2203         *st = tst;
2204     }
2205     return rc;
2206 }
2207
2208 /*
2209  * util_CMListCellsDone - Finish listing cache manager cells
2210  *
2211  * PARAMETERS
2212  *
2213  * IN iterationId - Iteration id created by util_CMGetServerPrefsBegin.
2214  *
2215  * LOCKS
2216  *
2217  * No locks are obtained or released by this function
2218  *
2219  * RETURN CODES
2220  *
2221  * Returns != 0 upon successful completion.
2222  *
2223  */
2224
2225 int ADMINAPI util_CMListCellsDone(
2226   const void *iterationId,
2227   afs_status_p st)
2228 {
2229     int rc = 0;
2230     afs_status_t tst = 0;
2231     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2232
2233     if (iterationId == NULL) {
2234         tst = ADMITERATIONIDPNULL;
2235         goto fail_util_CMListCellsDone;
2236     }
2237
2238     rc = IteratorDone(iter, &tst);
2239
2240
2241 fail_util_CMListCellsDone:
2242
2243     if (st != NULL) {
2244         *st = tst;
2245     }
2246     return rc;
2247 }
2248
2249 /*
2250  * util_CMLocalCell - Get the name of the cache manager's local cell.
2251  *
2252  * PARAMETERS
2253  *
2254  * IN conn - an rx connection to the process to be queried
2255  *
2256  * OUT cellName - the name of the cache manager's local cell.
2257  *
2258  * LOCKS
2259  *
2260  * No locks are obtained or released by this function
2261  *
2262  * RETURN CODES
2263  *
2264  * Returns != 0 upon successful completion.
2265  *
2266  */
2267
2268 int ADMINAPI util_CMLocalCell(
2269   struct rx_connection *conn,
2270   afs_CMCellName_p cellName,
2271   afs_status_p st)
2272 {
2273     int rc = 0;
2274     afs_status_t tst = 0;
2275     afs_CMCellName_p name;
2276
2277     if (conn == NULL) {
2278         tst = ADMRXCONNNULL;
2279         goto fail_util_CMLocalCell;
2280     }
2281
2282     if (cellName == NULL) {
2283         tst = ADMCLIENTCMCELLNAMENULL;
2284         goto fail_util_CMLocalCell;
2285     }
2286
2287     name = cellName;
2288     tst = RXAFSCB_GetLocalCell(conn, &name);
2289
2290     if (!tst) {
2291         rc = 1;
2292     }
2293
2294 fail_util_CMLocalCell:
2295
2296     if (st != NULL) {
2297         *st = tst;
2298     }
2299     return rc;
2300 }
2301
2302 static void UnmarshallCMClientConfig(
2303     afs_uint32 serverVersion,
2304     afs_uint32 *ptr,
2305     afs_ClientConfigUnion_p config)
2306 {
2307     /*
2308      * We currently only support version 1.
2309      */
2310     config->config_v1.nChunkFiles = *(ptr++);
2311     config->config_v1.nStatCaches = *(ptr++);
2312     config->config_v1.nDataCaches = *(ptr++);
2313     config->config_v1.nVolumeCaches = *(ptr++);
2314     config->config_v1.firstChunkSize = *(ptr++);
2315     config->config_v1.otherChunkSize = *(ptr++);
2316     config->config_v1.cacheSize = *(ptr++);
2317     config->config_v1.setTime = *(ptr++);
2318     config->config_v1.memCache = *(ptr++);
2319 }
2320
2321 /*
2322  * util_CMClientConfig - Get the cache manager's configuration parameters.
2323  *
2324  * PARAMETERS
2325  *
2326  * IN conn - an rx connection to the process to be queried
2327  *
2328  * OUT config - the cache manager's configuration parameters.
2329  *
2330  * LOCKS
2331  *
2332  * No locks are obtained or released by this function
2333  *
2334  * RETURN CODES
2335  *
2336  * Returns != 0 upon successful completion.
2337  *
2338  */
2339
2340 int ADMINAPI util_CMClientConfig(
2341   struct rx_connection *conn,
2342   afs_ClientConfig_p config,
2343   afs_status_p st)
2344 {
2345     int rc = 0;
2346     afs_status_t tst = 0;
2347     afs_int32 allocbytes;
2348     struct cacheConfig tconfig;
2349
2350     if (conn == NULL) {
2351         tst = ADMRXCONNNULL;
2352         goto fail_util_CMClientConfig;
2353     }
2354
2355     if (config == NULL) {
2356         tst = ADMCLIENTCMCELLNAMENULL;
2357         goto fail_util_CMClientConfig;
2358     }
2359
2360     config->clientVersion = AFS_CLIENT_RETRIEVAL_VERSION;
2361     tconfig.cacheConfig_val = NULL;
2362     tconfig.cacheConfig_len = 0;
2363     tst = RXAFSCB_GetCacheConfig(conn,
2364                                  config->clientVersion,
2365                                  &config->serverVersion,
2366                                  &allocbytes,
2367                                  &tconfig);
2368
2369     if (tst) {
2370         goto fail_util_CMClientConfig;
2371     }
2372
2373     UnmarshallCMClientConfig(config->serverVersion,
2374                              tconfig.cacheConfig_val,
2375                              &config->c);
2376     rc = 1;
2377     free(tconfig.cacheConfig_val);
2378
2379 fail_util_CMClientConfig:
2380
2381     if (st != NULL) {
2382         *st = tst;
2383     }
2384     return rc;
2385 }
2386
2387 /*
2388  * util_RXDebugVersion - Get the rxdebug version string.
2389  *
2390  * PARAMETERS
2391  *
2392  * IN handle - an rxdebug handle for the process to be queried.
2393  *
2394  * OUT version - the rxdebug version string.
2395  *
2396  * LOCKS
2397  *
2398  * No locks are obtained or released by this function
2399  *
2400  * RETURN CODES
2401  *
2402  * Returns != 0 upon successful completion.
2403  *
2404  */
2405
2406 int ADMINAPI util_RXDebugVersion(
2407   rxdebugHandle_p handle,
2408   rxdebugVersion_p version,
2409   afs_status_p st)
2410 {
2411     int rc = 0;
2412     afs_status_t tst = 0;
2413     int code;
2414
2415     if (handle == NULL) {
2416         tst = ADMRXDEBUGHANDLENULL;
2417         goto fail_util_RXDebugVersion;
2418     }
2419
2420     if (version == NULL) {
2421         tst = ADMRXDEBUGVERSIONNULL;
2422         goto fail_util_RXDebugVersion;
2423     }
2424
2425     code = rx_GetServerVersion(handle->sock,
2426                                handle->ipAddr,
2427                                handle->udpPort,
2428                                UTIL_MAX_RXDEBUG_VERSION_LEN,
2429                                version);
2430     if (code < 0) {
2431         tst = ADMCLIENTRXDEBUGTIMEOUT;
2432         goto fail_util_RXDebugVersion;
2433     }
2434
2435     rc = 1;
2436
2437 fail_util_RXDebugVersion:
2438
2439     if (st != NULL) {
2440         *st = tst;
2441     }
2442     return rc;
2443 }
2444
2445 /*
2446  * util_RXDebugSupportedStats - Get the rxdebug statistics supported by
2447  *                              the process.
2448  *
2449  * PARAMETERS
2450  *
2451  * IN handle - an rxdebug handle for the process to be queried.
2452  *
2453  * OUT supportedStats - bit mask with supported rxstats.
2454  *
2455  * LOCKS
2456  *
2457  * No locks are obtained or released by this function
2458  *
2459  * RETURN CODES
2460  *
2461  * Returns != 0 upon successful completion.
2462  *
2463  */
2464
2465 int ADMINAPI util_RXDebugSupportedStats(
2466   rxdebugHandle_p handle,
2467   afs_uint32 *supportedStats,
2468   afs_status_p st)
2469 {
2470     int rc = 0;
2471     afs_status_t tst = 0;
2472     struct rx_debugStats tstats;
2473
2474     if (handle == NULL) {
2475         tst = ADMRXDEBUGHANDLENULL;
2476         goto fail_util_RXDebugSupportedStats;
2477     }
2478
2479     if (supportedStats == NULL) {
2480         tst = ADMRXDEBUGSTATSNULL;
2481         goto fail_util_RXDebugSupportedStats;
2482     }
2483
2484     if (handle->firstFlag) {
2485         rc = util_RXDebugBasicStats(handle, &tstats, &tst);
2486         if (!rc) {
2487             goto fail_util_RXDebugSupportedStats;
2488         }
2489     }
2490
2491     *supportedStats = handle->supportedStats;
2492     rc = 1;
2493
2494 fail_util_RXDebugSupportedStats:
2495
2496     if (st != NULL) {
2497         *st = tst;
2498     }
2499     return rc;
2500 }
2501
2502
2503 /*
2504  * util_RXDebugBasicStats - Get the basic rxdebug statistics for the process.
2505  *
2506  * PARAMETERS
2507  *
2508  * IN handle - an rxdebug handle for the process to be queried.
2509  *
2510  * OUT stats - Basic rxdebug statistics for the process.
2511  *
2512  * LOCKS
2513  *
2514  * No locks are obtained or released by this function
2515  *
2516  * RETURN CODES
2517  *
2518  * Returns != 0 upon successful completion.
2519  *
2520  */
2521
2522 int ADMINAPI util_RXDebugBasicStats(
2523   rxdebugHandle_p handle,
2524   struct rx_debugStats *stats,
2525   afs_status_p st)
2526 {
2527     int rc = 0;
2528     afs_status_t tst = 0;
2529     int code;
2530
2531     if (handle == NULL) {
2532         tst = ADMRXDEBUGHANDLENULL;
2533         goto fail_util_RXDebugBasicStats;
2534     }
2535
2536     if (stats == NULL) {
2537         tst = ADMRXDEBUGSTATSNULL;
2538         goto fail_util_RXDebugBasicStats;
2539     }
2540
2541     code = rx_GetServerDebug(handle->sock,
2542                              handle->ipAddr,
2543                              handle->udpPort,
2544                              stats,
2545                              &handle->supportedStats);
2546     if (code < 0) {
2547         tst = ADMCLIENTRXDEBUGTIMEOUT;
2548         goto fail_util_RXDebugBasicStats;
2549     }
2550
2551     handle->firstFlag = 0;
2552     rc = 1;
2553
2554 fail_util_RXDebugBasicStats:
2555
2556     if (st != NULL) {
2557         *st = tst;
2558     }
2559     return rc;
2560 }
2561
2562
2563 /*
2564  * util_RXDebugRxStats - Get the detailed rxdebug statistics for the process.
2565  *
2566  * PARAMETERS
2567  *
2568  * IN handle - an rxdebug handle for the process to be queried.
2569  *
2570  * OUT stats - Detailed rxdebug statistics for the process.
2571  *
2572  * LOCKS
2573  *
2574  * No locks are obtained or released by this function
2575  *
2576  * RETURN CODES
2577  *
2578  * Returns != 0 upon successful completion.
2579  *
2580  */
2581
2582 int ADMINAPI util_RXDebugRxStats(
2583   rxdebugHandle_p handle,
2584   struct rx_stats *stats,
2585   afs_uint32 *supportedValues,
2586   afs_status_p st)
2587 {
2588     int rc = 0;
2589     int trc;
2590     afs_status_t tst = 0;
2591     int code;
2592     afs_uint32 tsupported;
2593
2594     if (handle == NULL) {
2595         tst = ADMRXDEBUGHANDLENULL;
2596         goto fail_util_RXDebugRxStats;
2597     }
2598
2599     if (supportedValues == NULL) {
2600         tst = ADMRXDEBUGSTATSNULL;
2601         goto fail_util_RXDebugRxStats;
2602     }
2603
2604     if (stats == NULL) {
2605         tst = ADMRXDEBUGSTATSNULL;
2606         goto fail_util_RXDebugRxStats;
2607     }
2608
2609     if (handle->firstFlag) {
2610         trc = util_RXDebugSupportedStats(handle, &tsupported, &tst);
2611         if(!trc) {
2612             rc = trc;
2613             goto fail_util_RXDebugRxStats;
2614         }
2615     }
2616
2617     if (!(handle->supportedStats & RX_SERVER_DEBUG_RX_STATS)) {
2618         tst = ADMCLIENTRXDEBUGNOTSUPPORTED;
2619         goto fail_util_RXDebugRxStats;
2620     }
2621
2622     code = rx_GetServerStats(handle->sock,
2623                              handle->ipAddr,
2624                              handle->udpPort,
2625                              stats,
2626                              &handle->supportedStats);
2627     if (code < 0) {
2628         tst = ADMCLIENTRXDEBUGTIMEOUT;
2629         goto fail_util_RXDebugRxStats;
2630     }
2631
2632     rc = 1;
2633
2634 fail_util_RXDebugRxStats:
2635
2636     if (st != NULL) {
2637         *st = tst;
2638     }
2639     return rc;
2640 }
2641
2642 /*
2643  * The iterator for listing RXDebug connections
2644  */
2645
2646 typedef struct rxdebug_conn_item {
2647   struct rx_debugConn conn;
2648   afs_uint32 supportedValues;
2649 } rxdebug_conn_item_t, *rxdebug_conn_item_p;
2650
2651 typedef struct rxdebug_conn_get {
2652   int allconns;
2653   rxdebugHandle_p handle;
2654   afs_int32 index;
2655   rxdebug_conn_item_t items[CACHED_ITEMS];
2656 } rxdebug_conn_get_t, *rxdebug_conn_get_p;
2657
2658 static int RXDebugConnsFromServer(
2659   void *rpc_specific,
2660   int slot,
2661   int *last_item,
2662   int *last_item_contains_data,
2663   afs_status_p st)
2664 {
2665     int rc = 0;
2666     int code;
2667     afs_status_t tst = 0;
2668     rxdebug_conn_get_p t = (rxdebug_conn_get_p) rpc_specific;
2669
2670     /*
2671      * Get the next entry the list of connections
2672      */
2673     code = rx_GetServerConnections(t->handle->sock,
2674                                    t->handle->ipAddr,
2675                                    t->handle->udpPort,
2676                                    &t->index,
2677                                    t->allconns,
2678                                    t->handle->supportedStats,
2679                                    &t->items[slot].conn,
2680                                    &t->items[slot].supportedValues);
2681     if (code < 0) {
2682         tst = ADMCLIENTRXDEBUGTIMEOUT;
2683         goto fail_ListCellsRPC;
2684     }
2685
2686     /*
2687      * See if we've processed all the entries
2688      */
2689     if (t->items[slot].conn.cid == 0xffffffff) {
2690         *last_item = 1;
2691         *last_item_contains_data = 0;
2692     }
2693     rc = 1;
2694
2695 fail_ListCellsRPC:
2696
2697     if (st != NULL) {
2698         *st = tst;
2699     }
2700     return rc;
2701 }
2702
2703 static int RXDebugConnsFromCache(
2704   void *rpc_specific,
2705   int slot,
2706   void *dest,
2707   afs_status_p st)
2708 {
2709     int rc = 0;
2710     afs_status_t tst = 0;
2711     rxdebug_conn_get_p t = (rxdebug_conn_get_p)rpc_specific;
2712
2713     memcpy(dest, (const void *)&t->items[slot],
2714            sizeof(rxdebug_conn_item_t));
2715
2716     rc = 1;
2717     if (st != NULL) {
2718         *st = tst;
2719     }
2720     return rc;
2721 }
2722
2723 /*
2724  * util_RXDebugConnectionsBegin - Begin listing rxdebug connection information
2725  *                                for a process.
2726  *
2727  * PARAMETERS
2728  *
2729  * IN handle - an rxdebug handle for the process to be queried
2730  *
2731  * IN allcons - non-zero to list all connections. If zero, only
2732  *              "interesting" connections will be listed.
2733  *
2734  * OUT iterationIdP - an iteration id that can be passed to
2735  *                    util_RXDebugConnectionsNext.
2736  *
2737  * LOCKS
2738  *
2739  * No locks are obtained or released by this function
2740  *
2741  * RETURN CODES
2742  *
2743  * Returns != 0 upon successful completion.
2744  *
2745  */
2746
2747 int ADMINAPI util_RXDebugConnectionsBegin(
2748   rxdebugHandle_p handle,
2749   int allconns,
2750   void **iterationIdP,
2751   afs_status_p st)
2752 {
2753     int rc = 0;
2754     int trc;
2755     afs_uint32 tsupported;
2756     afs_status_t tst = 0;
2757     afs_admin_iterator_p iter;
2758     rxdebug_conn_get_p t;
2759
2760     if (handle == NULL) {
2761         tst = ADMRXDEBUGHANDLENULL;
2762         goto fail_util_RXDebugConnectionsBegin;
2763     }
2764
2765     iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
2766     if (iter == NULL) {
2767         tst = ADMNOMEM;
2768         goto fail_util_RXDebugConnectionsBegin;
2769     }
2770
2771     if (handle->firstFlag) {
2772         trc = util_RXDebugSupportedStats(handle, &tsupported, &tst);
2773         if(!trc) {
2774             rc = trc;
2775             goto fail_util_RXDebugConnectionsBegin;
2776         }
2777     }
2778
2779     if (allconns &&
2780         !(handle->supportedStats & RX_SERVER_DEBUG_ALL_CONN)) {
2781         tst = ADMCLIENTRXDEBUGNOTSUPPORTED;
2782         goto fail_util_RXDebugConnectionsBegin;
2783     }
2784
2785     t = (rxdebug_conn_get_p) malloc(sizeof(rxdebug_conn_get_t));
2786     if (t == NULL) {
2787         free(iter);
2788         tst = ADMNOMEM;
2789         goto fail_util_RXDebugConnectionsBegin;
2790     }
2791
2792     t->allconns = allconns;
2793     t->handle = handle;
2794     t->index = 0;
2795     if (!IteratorInit(iter, (void *)t, RXDebugConnsFromServer,
2796                       RXDebugConnsFromCache, NULL, NULL, &tst)) {
2797         goto fail_util_RXDebugConnectionsBegin;
2798     }
2799     *iterationIdP = (void *) iter;
2800     rc = 1;
2801
2802 fail_util_RXDebugConnectionsBegin:
2803
2804     if (st != NULL) {
2805         *st = tst;
2806     }
2807     return rc;
2808 }
2809
2810
2811 /*
2812  * util_RXDebugConnectionsNext - Get rxdebug information for the next
2813  *                               connection.
2814  *
2815  * PARAMETERS
2816  *
2817  * IN iterationId - Iteration id created by util_RXDebugConnectionsNext.
2818  *
2819  * OUT conn - Rxdebug information for the next connection.
2820  *
2821  * OUT supportedValues - Bit mask of supported rxdebug values.
2822  *
2823  * LOCKS
2824  *
2825  * No locks are obtained or released by this function
2826  *
2827  * RETURN CODES
2828  *
2829  * Returns != 0 upon successful completion.
2830  *
2831  */
2832
2833 int ADMINAPI util_RXDebugConnectionsNext(
2834   const void *iterationId,
2835   struct rx_debugConn *conn,
2836   afs_uint32 *supportedValues,
2837   afs_status_p st)
2838 {
2839     int rc = 0;
2840     afs_status_t tst = 0;
2841     rxdebug_conn_item_t item;
2842     afs_admin_iterator_p iter = (afs_admin_iterator_p)iterationId;
2843
2844     if (iterationId == NULL) {
2845         tst = ADMITERATIONIDPNULL;
2846         goto fail_util_RXDebugConnectionsNext;
2847     }
2848
2849     if (conn == NULL) {
2850         tst = ADMRXDEBUGHANDLENULL;
2851         goto fail_util_RXDebugConnectionsNext;
2852     }
2853
2854     if (supportedValues == NULL) {
2855         tst = ADMRXDEBUGHANDLENULL;
2856         goto fail_util_RXDebugConnectionsNext;
2857     }
2858
2859     rc = IteratorNext(iter, (void *)&item, &tst);
2860     if (!rc) {
2861         goto fail_util_RXDebugConnectionsNext;
2862     }
2863
2864     *conn = item.conn;
2865     *supportedValues = item.supportedValues;
2866
2867 fail_util_RXDebugConnectionsNext:
2868
2869     if (st != NULL) {
2870         *st = tst;
2871     }
2872     return rc;
2873 }
2874
2875
2876 /*
2877  * util_RXDebugConnectionsDone - Finish listing rxdebug connection information.
2878  *
2879  * PARAMETERS
2880  *
2881  * IN iterationId - Iteration id created by util_RXDebugConnectionsBegin.
2882  *
2883  * LOCKS
2884  *
2885  * No locks are obtained or released by this function
2886  *
2887  * RETURN CODES
2888  *
2889  * Returns != 0 upon successful completion.
2890  *
2891  */
2892
2893 int ADMINAPI util_RXDebugConnectionsDone(
2894   const void *iterationId,
2895   afs_status_p st)
2896 {
2897     int rc = 0;
2898     afs_status_t tst = 0;
2899     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2900
2901     /*
2902      * Validate parameters
2903      */
2904
2905     if (iter == NULL) {
2906         tst = ADMITERATORNULL;
2907         goto fail_util_RXDebugConnectionsDone;
2908     }
2909
2910     rc = IteratorDone(iter, &tst);
2911
2912 fail_util_RXDebugConnectionsDone:
2913
2914     if (st != NULL) {
2915         *st = tst;
2916     }
2917     return rc;
2918
2919 }
2920
2921 /*
2922  * The iterator for listing RXDebug peer
2923  */
2924
2925 typedef struct rxdebug_peer_item {
2926   struct rx_debugPeer peer;
2927   afs_uint32 supportedValues;
2928 } rxdebug_peer_item_t, *rxdebug_peer_item_p;
2929
2930 typedef struct rxdebug_peer_get {
2931   rxdebugHandle_p handle;
2932   afs_int32 index;
2933   rxdebug_peer_item_t items[CACHED_ITEMS];
2934 } rxdebug_peer_get_t, *rxdebug_peer_get_p;
2935
2936 static int RXDebugPeersFromServer(
2937   void *rpc_specific,
2938   int slot,
2939   int *last_item,
2940   int *last_item_contains_data,
2941   afs_status_p st)
2942 {
2943     int rc = 0;
2944     int code;
2945     afs_status_t tst = 0;
2946     rxdebug_peer_get_p t = (rxdebug_peer_get_p) rpc_specific;
2947
2948     /*
2949      * Get the next entry the list of peers
2950      */
2951     code = rx_GetServerPeers(t->handle->sock,
2952                              t->handle->ipAddr,
2953                              t->handle->udpPort,
2954                              &t->index,
2955                              t->handle->supportedStats,
2956                              &t->items[slot].peer,
2957                              &t->items[slot].supportedValues);
2958     if (code < 0) {
2959         tst = ADMCLIENTRXDEBUGTIMEOUT;
2960         goto fail_ListCellsRPC;
2961     }
2962
2963     /*
2964      * See if we've processed all the entries
2965      */
2966     if (t->items[slot].peer.host == 0xffffffff) {
2967         *last_item = 1;
2968         *last_item_contains_data = 0;
2969     }
2970     rc = 1;
2971
2972 fail_ListCellsRPC:
2973
2974     if (st != NULL) {
2975         *st = tst;
2976     }
2977     return rc;
2978 }
2979
2980 static int RXDebugPeersFromCache(
2981   void *rpc_specific,
2982   int slot,
2983   void *dest,
2984   afs_status_p st)
2985 {
2986     int rc = 0;
2987     afs_status_t tst = 0;
2988     rxdebug_peer_get_p t = (rxdebug_peer_get_p)rpc_specific;
2989
2990     memcpy(dest, (const void *)&t->items[slot],
2991            sizeof(rxdebug_peer_item_t));
2992
2993     rc = 1;
2994     if (st != NULL) {
2995         *st = tst;
2996     }
2997     return rc;
2998 }
2999
3000
3001 /*
3002  * util_RXDebugPeersBegin - Begin listing rxdebug peer information for
3003  *                          a process.
3004  *
3005  * PARAMETERS
3006  *
3007  * IN handle - an rxdebug handle for the process to be queried
3008  *
3009  * OUT iterationIdP - an iteration id that can be passed to
3010  *                    util_RXDebugPeersNext.
3011  *
3012  * LOCKS
3013  *
3014  * No locks are obtained or released by this function
3015  *
3016  * RETURN CODES
3017  *
3018  * Returns != 0 upon successful completion.
3019  *
3020  */
3021
3022 int ADMINAPI util_RXDebugPeersBegin(
3023   rxdebugHandle_p handle,
3024   void **iterationIdP,
3025   afs_status_p st)
3026 {
3027     int rc = 0;
3028     int trc;
3029     afs_uint32 tsupported;
3030     afs_status_t tst = 0;
3031     afs_admin_iterator_p iter;
3032     rxdebug_peer_get_p t;
3033
3034     if (handle == NULL) {
3035         tst = ADMRXDEBUGHANDLENULL;
3036         goto fail_util_RXDebugPeersBegin;
3037     }
3038
3039     iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
3040     if (iter == NULL) {
3041         tst = ADMNOMEM;
3042         goto fail_util_RXDebugPeersBegin;
3043     }
3044
3045     if (handle->firstFlag) {
3046         trc = util_RXDebugSupportedStats(handle, &tsupported, &tst);
3047         if(!trc) {
3048             rc = trc;
3049             goto fail_util_RXDebugPeersBegin;
3050         }
3051     }
3052
3053     if(!(handle->supportedStats & RX_SERVER_DEBUG_ALL_PEER)) {
3054         tst = ADMCLIENTRXDEBUGNOTSUPPORTED;
3055         goto fail_util_RXDebugPeersBegin;
3056     }
3057
3058     t = (rxdebug_peer_get_p) malloc(sizeof(rxdebug_peer_get_t));
3059     if (t == NULL) {
3060         free(iter);
3061         tst = ADMNOMEM;
3062         goto fail_util_RXDebugPeersBegin;
3063     }
3064
3065     t->handle = handle;
3066     t->index = 0;
3067     if (!IteratorInit(iter, (void *)t, RXDebugPeersFromServer,
3068                       RXDebugPeersFromCache, NULL, NULL, &tst)) {
3069         goto fail_util_RXDebugPeersBegin;
3070     }
3071     *iterationIdP = (void *) iter;
3072     rc = 1;
3073
3074 fail_util_RXDebugPeersBegin:
3075
3076     if (st != NULL) {
3077         *st = tst;
3078     }
3079     return rc;
3080 }
3081
3082 /*
3083  * util_RXDebugPeersNext - Get rxdebug information for the next peer.
3084  *
3085  * PARAMETERS
3086  *
3087  * IN iterationId - Iteration id created by util_RXDebugPeersBegin.
3088  *
3089  * OUT peer - Rxdebug information for the next peer.
3090  *
3091  * OUT supportedValues - Bit mask of supported rxdebug values.
3092  *
3093  * LOCKS
3094  *
3095  * No locks are obtained or released by this function
3096  *
3097  * RETURN CODES
3098  *
3099  * Returns != 0 upon successful completion.
3100  *
3101  */
3102 int ADMINAPI util_RXDebugPeersNext(
3103   const void *iterationId,
3104   struct rx_debugPeer *peer,
3105   afs_uint32 *supportedValues,
3106   afs_status_p st)
3107 {
3108     int rc = 0;
3109     afs_status_t tst = 0;
3110     rxdebug_peer_item_t item;
3111     afs_admin_iterator_p iter = (afs_admin_iterator_p)iterationId;
3112
3113     if (iterationId == NULL) {
3114         tst = ADMITERATIONIDPNULL;
3115         goto fail_util_RXDebugPeersNext;
3116     }
3117
3118     if (peer == NULL) {
3119         tst = ADMRXDEBUGHANDLENULL;
3120         goto fail_util_RXDebugPeersNext;
3121     }
3122
3123     if (supportedValues == NULL) {
3124         tst = ADMRXDEBUGHANDLENULL;
3125         goto fail_util_RXDebugPeersNext;
3126     }
3127
3128     rc = IteratorNext(iter, (void *)&item, &tst);
3129     if (!rc) {
3130         goto fail_util_RXDebugPeersNext;
3131     }
3132
3133     *peer = item.peer;
3134     *supportedValues = item.supportedValues;
3135
3136 fail_util_RXDebugPeersNext:
3137
3138     if (st != NULL) {
3139         *st = tst;
3140     }
3141     return rc;
3142 }
3143
3144 /*
3145  * util_RXDebugPeersDone - Finish listing rxdebug peer information.
3146  *
3147  * PARAMETERS
3148  *
3149  * IN iterationId - Iteration id created by util_RXDebugPeersBegin.
3150  *
3151  * LOCKS
3152  *
3153  * No locks are obtained or released by this function
3154  *
3155  * RETURN CODES
3156  *
3157  * Returns != 0 upon successful completion.
3158  *
3159  */
3160
3161 int ADMINAPI util_RXDebugPeersDone(
3162   const void *iterationId,
3163   afs_status_p st)
3164 {
3165     int rc = 0;
3166     afs_status_t tst = 0;
3167     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3168
3169     /*
3170      * Validate parameters
3171      */
3172
3173     if (iter == NULL) {
3174         tst = ADMITERATORNULL;
3175         goto fail_util_RXDebugPeersDone;
3176     }
3177
3178     rc = IteratorDone(iter, &tst);
3179
3180 fail_util_RXDebugPeersDone:
3181
3182     if (st != NULL) {
3183         *st = tst;
3184     }
3185     return rc;
3186
3187 }