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