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