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