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