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