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