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