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