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