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