2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* This file implements configuration functions in the following categories:
11 * cfg_CellServDb*() - manage the cell-wide server CellServDb database.
14 #include <afsconfig.h>
15 #include <afs/param.h>
23 #include <rx/rxstat.h>
25 #include <afs/afs_Admin.h>
26 #include <afs/afs_AdminErrors.h>
27 #include <afs/afs_bosAdmin.h>
28 #include <afs/afs_clientAdmin.h>
29 #include <afs/afs_utilAdmin.h>
31 #include <afs/cellconfig.h>
32 #include <afs/bnode.h>
34 #include "cfginternal.h"
35 #include "afs_cfgAdmin.h"
38 /* Local declarations and definitions */
40 #define CSDB_OP_ADD 0 /* add a server CellServDB entry */
41 #define CSDB_OP_REM 1 /* remove a server CellServDB entry */
43 #define CSDB_WAIT 0 /* wait to begin CellServDB update operations */
44 #define CSDB_GO 1 /* begin CellServDB update operations */
45 #define CSDB_ABORT 2 /* abort CellServDB update operations */
47 #define SERVER_NAME_BLOCK_SIZE 20 /* number of server names in a block */
50 /* server name iterator */
52 int dbOnly; /* enumerate database servers only */
53 void *iterationId; /* underlying iteration handle */
54 } cfg_server_iteration_t;
57 /* CellServDB update control block */
59 /* control block invariants */
60 cfg_host_p cfg_host; /* host configuration handle */
61 int op; /* CellServDB update operation type */
62 char opHostAlias[MAXHOSTCHARS]; /* CellServDB alias for config host */
63 cfg_cellServDbUpdateCallBack_t callBack; /* CellServDB update callback */
64 void *callBackId; /* CellServDB update callback cookie */
66 /* control block synchronization objects */
67 pthread_cond_t event; /* disposition change event */
68 pthread_mutex_t mutex; /* protects disposition and workersActive */
69 int disposition; /* wait, go, or abort operation */
70 int workersActive; /* count of active worker threads */
71 } cfg_csdb_update_ctrl_t;
73 /* CellServDB update name block */
75 cfg_csdb_update_ctrl_t *ctrl; /* pointer to common control block */
76 int serverCount; /* number of entries in serverName array */
77 char serverName[SERVER_NAME_BLOCK_SIZE][AFS_MAX_SERVER_NAME_LEN];
78 } cfg_csdb_update_name_t;
80 /* name block iterator */
82 void *serverIter; /* server name iterator */
83 cfg_csdb_update_ctrl_t *ctrlBlockp; /* update control block */
84 const char *cfgHost; /* configuration host name */
85 const char *sysControlHost; /* system control host name (if any) */
86 short cfgInBlock; /* configuration host in a name block */
87 short sysInBlock; /* system control host in a name block */
88 short serverIterDone; /* server name enumeration complete */
89 } cfg_csdb_nameblock_iteration_t;
94 CellServDbUpdate(int updateOp, void *hostHandle, const char *sysControlHost,
95 cfg_cellServDbUpdateCallBack_t callBack, void *callBackId,
96 int *maxUpdates, afs_status_p st);
99 StartUpdateWorkerThread(cfg_csdb_update_name_t * nameBlockp,
102 static void *UpdateWorkerThread(void *argp);
105 CfgHostGetCellServDbAlias(cfg_host_p cfg_host, char *cfgHostAlias,
109 NameBlockGetBegin(cfg_host_p cfg_host, const char *sysControlHost,
110 cfg_csdb_update_ctrl_t * ctrlBlockp, void **iterationIdP,
114 NameBlockGetNext(void *iterationId, cfg_csdb_update_name_t * nameBlockp,
118 NameBlockGetDone(void *iterationId, afs_status_p st);
121 ServerNameGetBegin(cfg_host_p cfg_host, short dbOnly, void **iterationIdP,
125 ServerNameGetNext(void *iterationId, char *serverName, afs_status_p st);
128 ServerNameGetDone(void *iterationId, afs_status_p st);
132 /* ---------------- Exported CellServDB functions ------------------ */
136 * cfg_cellServDbUpdateCallBack_t -- prototype for status callback that is
137 * invoked by functions that update the CellServDB.
139 * Implementation provided by library user.
142 * callBackId - user-supplied context identifier; used by caller to
143 * distinguish results from different functions (or different
144 * invocations of the same function) that utilize the same callback.
146 * statusItemP - pointer to status information returned by a function
147 * via this callback; an statusItemP value of NULL indicates
148 * termination of status callbacks for a given function invocation;
149 * the termination callback will not occur until all other callbacks
150 * in the set have completed.
152 * status - if statusItemP is NULL then this argument indicates whether
153 * termination of status callbacks is due to logical completion
157 * The callback thread is not permitted to reenter the configuration
158 * library except to deallocate returned storage.
163 * cfg_CellServDbAddHost() -- Add host being configured to server
164 * CellServDB on all fileserver and database machines in cell and to
165 * host's server CellServDB.
167 * If a System Control machine has been configured, sysControlHost must
168 * specify the host name; otherwise, sysControlHost must be NULL.
171 cfg_CellServDbAddHost(void *hostHandle, /* host config handle */
172 const char *sysControlHost, /* sys control host */
173 cfg_cellServDbUpdateCallBack_t callBack, void *callBackId, int *maxUpdates, /* max servers to update */
175 { /* completion status */
176 return CellServDbUpdate(CSDB_OP_ADD, hostHandle, sysControlHost, callBack,
177 callBackId, maxUpdates, st);
182 * cfg_CellServDbRemoveHost() -- Remove host being configured from server
183 * CellServDB on all fileserver and database machines in cell and from
184 * host's server CellServDB.
186 * If a System Control machine has been configured, sysControlHost must
187 * specify the host name; otherwise, sysControlHost must be NULL.
190 cfg_CellServDbRemoveHost(void *hostHandle, /* host config handle */
191 const char *sysControlHost, /* sys control host */
192 cfg_cellServDbUpdateCallBack_t callBack, void *callBackId, int *maxUpdates, /* max servers to update */
194 { /* completion status */
195 return CellServDbUpdate(CSDB_OP_REM, hostHandle, sysControlHost, callBack,
196 callBackId, maxUpdates, st);
201 * cfg_CellServDbEnumerate() -- Enumerate database machines known to the
202 * specified database or fileserver machine. Enumeration is returned
206 cfg_CellServDbEnumerate(const char *fsDbHost, /* fileserver or database host */
207 char **cellName, /* cell name for cellDbHosts */
208 char **cellDbHosts, /* cell database hosts */
210 { /* completion status */
212 afs_status_t tst2, tst = 0;
214 /* validate parameters */
216 if (fsDbHost == NULL || *fsDbHost == '\0') {
217 tst = ADMCFGHOSTNAMENULL;
218 } else if (cellName == NULL) {
219 tst = ADMCFGCELLNAMENULL;
220 } else if (cellDbHosts == NULL) {
221 tst = ADMCFGCELLDBHOSTSNULL;
224 /* enumerate server CellServDB on specified host, along with cell name */
229 char dbhostName[MAXHOSTSPERCELL][BOS_MAX_NAME_LEN];
230 char dbhostCell[BOS_MAX_NAME_LEN];
233 if (!afsclient_NullCellOpen(&cellHandle, &tst2)) {
236 if (!bos_ServerOpen(cellHandle, fsDbHost, &bosHandle, &tst2)) {
241 if (!bos_HostGetBegin(bosHandle, &dbIter, &tst2)) {
244 for (dbhostCount = 0;; dbhostCount++) {
245 char dbhostNameTemp[BOS_MAX_NAME_LEN];
247 if (!bos_HostGetNext(dbIter, dbhostNameTemp, &tst2)) {
248 /* no more entries (or failure) */
249 if (tst2 != ADMITERATORDONE) {
253 } else if (dbhostCount >= MAXHOSTSPERCELL) {
254 /* more entries than expected */
255 tst = ADMCFGCELLSERVDBTOOMANYENTRIES;
258 strcpy(dbhostName[dbhostCount], dbhostNameTemp);
262 if (!bos_HostGetDone(dbIter, &tst2)) {
267 /* got database servers; now get cell name */
268 if (!bos_CellGet(bosHandle, dbhostCell, &tst2)) {
274 if (!bos_ServerClose(bosHandle, &tst2)) {
279 if (!afsclient_CellClose(cellHandle, &tst2)) {
285 /* return database hosts to caller */
289 for (i = 0; i < dbhostCount; i++) {
290 bufSize += strlen(dbhostName[i]) + 1;
292 bufSize++; /* end multistring */
294 *cellDbHosts = (char *)malloc(bufSize);
296 if (*cellDbHosts == NULL) {
299 char *bufp = *cellDbHosts;
301 for (i = 0; i < dbhostCount; i++) {
302 strcpy(bufp, dbhostName[i]);
303 bufp += strlen(bufp) + 1;
308 /* return cell name to caller */
310 *cellName = strdup(dbhostCell);
312 if (*cellName == NULL) {
322 /* indicate failure */
333 /* ---------------- Exported Utility functions ------------------ */
337 * cfg_CellServDbStatusDeallocate() -- Deallocate CellServDB update status
338 * record returned by library.
341 cfg_CellServDbStatusDeallocate(cfg_cellServDbStatus_t * statusItempP,
345 free((void *)statusItempP);
357 /* ---------------- Local functions ------------------ */
361 * CellServDbUpdate() -- add or remove a server CellServDB entry.
363 * Common function implementing cfg_CellServDb{Add/Remove}Host().
366 CellServDbUpdate(int updateOp, void *hostHandle, const char *sysControlHost,
367 cfg_cellServDbUpdateCallBack_t callBack, void *callBackId,
368 int *maxUpdates, afs_status_p st)
371 afs_status_t tst2, tst = 0;
372 cfg_host_p cfg_host = (cfg_host_p) hostHandle;
373 char fullSysHostName[MAXHOSTCHARS];
375 /* validate parameters */
377 if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
379 } else if (sysControlHost != NULL && *sysControlHost == '\0') {
380 tst = ADMCFGHOSTNAMENULL;
381 } else if (callBack == NULL) {
382 tst = ADMCFGCALLBACKNULL;
383 } else if (maxUpdates == NULL) {
384 tst = ADMCFGUPDATECOUNTNULL;
387 /* resolve sys ctrl host to fully qualified name (if extant) */
390 if (sysControlHost != NULL) {
391 if (!cfgutil_HostNameGetFull
392 (sysControlHost, fullSysHostName, &tst2)) {
395 sysControlHost = fullSysHostName;
400 /* Update cell-wide server CellServDb as follows:
402 * 1) If system control machine is in use then update the following:
403 * system control host + database server hosts + configuration host
405 * Updating the system control machine is theoretically sufficient,
406 * as all server hosts should be getting configuration information
407 * from there. However, we don't want to have to delay further
408 * configuration until this update occurs (which could be set for
409 * any time interval). Therefore, we compromise by manually
410 * updating the database server hosts and the host being configured.
412 * 2) If no system control machine is in use then update the following:
413 * fileserver hosts + database server hosts + configuration host
416 * We create a set of server name blocks, with one thread per name
417 * block that is responsible for updating the servers in that block.
418 * All server name blocks share a single control block that stores
419 * common data and coordinates start/abort and cleanup activities.
420 * All threads wait for the start/abort signal before performing
421 * update operations so that this function is atomic.
425 cfg_csdb_update_ctrl_t *ctrlBlockp = NULL;
429 /* create control block */
431 ctrlBlockp = (cfg_csdb_update_ctrl_t *) malloc(sizeof(*ctrlBlockp));
433 if (ctrlBlockp == NULL) {
436 ctrlBlockp->cfg_host = cfg_host;
437 ctrlBlockp->op = updateOp;
438 ctrlBlockp->callBack = callBack;
439 ctrlBlockp->callBackId = callBackId;
440 ctrlBlockp->disposition = CSDB_WAIT;
441 ctrlBlockp->workersActive = 0;
443 if (pthread_mutex_init(&ctrlBlockp->mutex, NULL)) {
445 } else if (pthread_cond_init(&ctrlBlockp->event, NULL)) {
448 /* Unfortunately the bosserver adds/removes entries from
449 * the server CellServDB based on a case-sensitive string
450 * comparison, rather than using an address comparison
451 * to handle aliasing. So we must use the name for the
452 * configuration host exactly as listed in the CellServDB.
454 * Of course the 3.5 bosserver can and should be modified to
455 * handle aliases, but we still have to deal with down-level
456 * servers in this library.
458 * To get reasonable performance, the presumption is made
459 * that all server CellServDB are identical. This way we
460 * can look up the configuration host alias once and use
461 * it everywhere. If this proves to be insufficient then
462 * this lookup will have to be done for every server to be
463 * updated which will be very costly; such individual lookups
464 * would naturally be handled by the update worker threads.
466 * A final presumption is that we can just look at the
467 * server CellServDB on the current database servers to
468 * get the configuration host alias. The only time this
469 * might get us into trouble is in a re-do scenario.
471 if (!CfgHostGetCellServDbAlias
472 (cfg_host, ctrlBlockp->opHostAlias, &tst2)) {
474 } else if (*ctrlBlockp->opHostAlias == '\0') {
475 /* no alias found; go with config host working name */
476 strcpy(ctrlBlockp->opHostAlias, cfg_host->hostName);
483 /* fill name blocks, handing each to a worker thread */
484 void *nameBlockIter = NULL;
485 short workersStarted = 0;
487 if (!NameBlockGetBegin
488 (cfg_host, sysControlHost, ctrlBlockp, &nameBlockIter,
492 cfg_csdb_update_name_t *nameBlockp = NULL;
493 short nameBlockDone = 0;
495 while (!nameBlockDone) {
496 nameBlockp = ((cfg_csdb_update_name_t *)
497 malloc(sizeof(*nameBlockp)));
499 if (nameBlockp == NULL) {
504 if (!NameBlockGetNext
505 (nameBlockIter, nameBlockp, &tst2)) {
506 /* no more entries (or failure) */
507 if (tst2 != ADMITERATORDONE) {
514 *maxUpdates += nameBlockp->serverCount;
516 if (StartUpdateWorkerThread(nameBlockp, &tst2)) {
517 /* increment worker count; lock not required
518 * until workers given start/abort signal.
520 ctrlBlockp->workersActive++;
530 if (!NameBlockGetDone(nameBlockIter, &tst2)) {
535 if (workersStarted) {
536 /* worker threads started; set disposition and signal */
537 if (pthread_mutex_lock(&ctrlBlockp->mutex)) {
541 /* tell workers to proceed with updates */
542 ctrlBlockp->disposition = CSDB_GO;
544 /* tell workers to abort */
545 ctrlBlockp->disposition = CSDB_ABORT;
548 if (pthread_mutex_unlock(&ctrlBlockp->mutex)) {
549 tst = ADMMUTEXUNLOCK;
551 if (pthread_cond_broadcast(&ctrlBlockp->event)) {
556 /* no worker threads started */
564 /* indicate failure */
575 * StartUpdateWorkerThread() -- start an update worker thread for the
576 * given server name block
578 * RETURN CODES: 1 success, 0 failure (st indicates why)
581 StartUpdateWorkerThread(cfg_csdb_update_name_t * nameBlockp, afs_status_p st)
584 afs_status_t tst = 0;
585 pthread_attr_t tattr;
588 if (pthread_attr_init(&tattr)) {
589 tst = ADMTHREADATTRINIT;
591 } else if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED)) {
592 tst = ADMTHREADATTRSETDETACHSTATE;
596 (&tid, &tattr, UpdateWorkerThread, (void *)nameBlockp)) {
597 tst = ADMTHREADCREATE;
601 /* indicate failure */
612 * UpdateWorkerThread() -- thread for updating CellServDB of servers in
613 * a single name block.
616 UpdateWorkerThread(void *argp)
618 afs_status_t sync_tst = 0;
619 cfg_csdb_update_name_t *nameBlockp = (cfg_csdb_update_name_t *) argp;
622 /* Pthread mutex and condition variable functions should never fail,
623 * but if they do make a best effort attempt to report the problem;
624 * will not be able to avoid race conditions in the face of such failures.
627 if (pthread_mutex_lock(&nameBlockp->ctrl->mutex)) {
628 sync_tst = ADMMUTEXLOCK;
631 while ((opDisposition = nameBlockp->ctrl->disposition) == CSDB_WAIT) {
632 /* wait for start/abort signal */
633 if (pthread_cond_wait
634 (&nameBlockp->ctrl->event, &nameBlockp->ctrl->mutex)) {
635 /* avoid tight loop if condition variable wait fails */
640 if (pthread_mutex_unlock(&nameBlockp->ctrl->mutex)) {
641 sync_tst = ADMMUTEXUNLOCK;
644 if (opDisposition == CSDB_GO) {
645 /* proceed with CellServDB update */
648 for (i = 0; i < nameBlockp->serverCount; i++) {
649 cfg_cellServDbStatus_t *statusp;
651 /* alloc memory for status information (including host name) */
653 while ((statusp = (cfg_cellServDbStatus_t *)
654 malloc(sizeof(*statusp) + AFS_MAX_SERVER_NAME_LEN)) ==
656 /* avoid tight loop while waiting for status storage */
660 statusp->fsDbHost = ((char *)statusp + sizeof(*statusp));
662 /* make update and set status information */
664 strcpy(statusp->fsDbHost, nameBlockp->serverName[i]);
667 /* report pthread problem */
668 statusp->status = sync_tst;
670 /* attempt update and report update status */
672 afs_status_t tst2, tst = 0;
675 (nameBlockp->ctrl->cfg_host->cellHandle,
676 nameBlockp->serverName[i], &bosHandle, &tst2)) {
680 char *opHost = nameBlockp->ctrl->opHostAlias;
682 if (nameBlockp->ctrl->op == CSDB_OP_ADD) {
683 if (!bos_HostCreate(bosHandle, opHost, &tst2)) {
687 if (!bos_HostDelete(bosHandle, opHost, &tst2)) {
688 if (tst2 != BZNOENT) {
694 if (!bos_ServerClose(bosHandle, &tst2)) {
698 statusp->status = tst;
701 /* make call back to return update status */
703 (*nameBlockp->ctrl->callBack) (nameBlockp->ctrl->callBackId,
708 /* last worker makes termination call back and deallocates control block */
710 if (pthread_mutex_lock(&nameBlockp->ctrl->mutex)) {
711 sync_tst = ADMMUTEXLOCK;
714 nameBlockp->ctrl->workersActive--;
716 if (nameBlockp->ctrl->workersActive == 0) {
717 if (opDisposition == CSDB_GO) {
718 (*nameBlockp->ctrl->callBack) (nameBlockp->ctrl->callBackId, NULL,
721 free(nameBlockp->ctrl);
724 if (pthread_mutex_unlock(&nameBlockp->ctrl->mutex)) {
725 sync_tst = ADMMUTEXUNLOCK;
728 /* all workers deallocate their own name block */
736 * CfgHostGetCellServDbAlias() -- Get alias for configuration host name
737 * as listed in the server CellServDB. If no alias is found then
738 * cfgHostAlias is set to the empty string.
740 * Note: cfgHostAlias is presumed to be a buffer of size MAXHOSTCHARS.
741 * Presumes all server CellServDB are identical.
742 * Only checks server CellServDB of database servers.
744 * RETURN CODES: 1 success, 0 failure (st indicates why)
747 CfgHostGetCellServDbAlias(cfg_host_p cfg_host, char *cfgHostAlias,
751 afs_status_t tst2, tst = 0;
754 if (!util_DatabaseServerGetBegin(cfg_host->cellName, &dbIter, &tst2)) {
757 util_databaseServerEntry_t dbhostEntry;
758 afs_status_t dbhostSt = 0;
759 short dbhostDone = 0;
760 short dbhostFound = 0;
762 while (!dbhostDone) {
763 if (!util_DatabaseServerGetNext(dbIter, &dbhostEntry, &tst2)) {
764 /* no more entries (or failure) */
765 if (tst2 != ADMITERATORDONE) {
771 if (!cfgutil_HostNameGetCellServDbAlias
772 (dbhostEntry.serverName, cfg_host->hostName, cfgHostAlias,
774 /* save failure status but keep trying */
777 } else if (*cfgHostAlias != '\0') {
784 *cfgHostAlias = '\0';
791 if (!util_DatabaseServerGetDone(dbIter, &tst2)) {
797 /* indicate failure */
808 * NameBlockGetBegin() -- initialize name block iteration
810 * RETURN CODES: 1 success, 0 failure (st indicates why)
813 NameBlockGetBegin(cfg_host_p cfg_host, const char *sysControlHost,
814 cfg_csdb_update_ctrl_t * ctrlBlockp, void **iterationIdP,
818 afs_status_t tst2, tst = 0;
819 cfg_csdb_nameblock_iteration_t *nbIterp;
821 nbIterp = (cfg_csdb_nameblock_iteration_t *) malloc(sizeof(*nbIterp));
823 if (nbIterp == NULL) {
826 short dbOnly = (sysControlHost != NULL);
828 nbIterp->ctrlBlockp = ctrlBlockp;
829 nbIterp->cfgHost = cfg_host->hostName;
830 nbIterp->sysControlHost = sysControlHost;
831 nbIterp->cfgInBlock = 0;
832 nbIterp->sysInBlock = 0;
833 nbIterp->serverIterDone = 0;
835 if (!ServerNameGetBegin
836 (cfg_host, dbOnly, &nbIterp->serverIter, &tst2)) {
841 *iterationIdP = nbIterp;
848 /* indicate failure */
859 * NameBlockGetNext() -- fill next name block
861 * RETURN CODES: 1 success, 0 failure (st indicates why)
864 NameBlockGetNext(void *iterationId, cfg_csdb_update_name_t * nameBlockp,
868 afs_status_t tst2, tst = 0;
869 cfg_csdb_nameblock_iteration_t *nbIterp;
872 nbIterp = (cfg_csdb_nameblock_iteration_t *) iterationId;
874 nameBlockp->ctrl = nbIterp->ctrlBlockp;
875 nameBlockp->serverCount = 0;
877 for (i = 0; i < SERVER_NAME_BLOCK_SIZE; i++) {
878 short nameEntered = 0;
880 if (!nbIterp->serverIterDone) {
881 if (ServerNameGetNext
882 (nbIterp->serverIter, nameBlockp->serverName[i], &tst2)) {
883 /* Got server name; check if matches cfg or sys control host.
884 * Do a simple string compare, rather than making an expensive
885 * cfgutil_HostNameIsAlias() call because it will not cause
886 * any problems to have a duplicate in the list.
890 if (!nbIterp->cfgInBlock) {
892 (nbIterp->cfgHost, nameBlockp->serverName[i])) {
893 nbIterp->cfgInBlock = 1;
897 if (!nbIterp->sysInBlock && nbIterp->sysControlHost != NULL) {
899 (nbIterp->sysControlHost,
900 nameBlockp->serverName[i])) {
901 nbIterp->sysInBlock = 1;
906 /* no more entries (or failure) */
907 if (tst2 == ADMITERATORDONE) {
908 nbIterp->serverIterDone = 1;
917 /* include config host and (possibly) sys control host */
918 if (!nbIterp->cfgInBlock) {
919 /* shouldn't be duplicate, but OK if is */
920 strcpy(nameBlockp->serverName[i], nbIterp->cfgHost);
921 nbIterp->cfgInBlock = 1;
924 } else if (!nbIterp->sysInBlock
925 && nbIterp->sysControlHost != NULL) {
926 /* shouldn't be duplicate, but OK if is */
927 strcpy(nameBlockp->serverName[i], nbIterp->sysControlHost);
928 nbIterp->sysInBlock = 1;
934 nameBlockp->serverCount++;
936 /* no more server names */
937 if (nameBlockp->serverCount == 0) {
938 tst = ADMITERATORDONE;
945 /* indicate failure */
956 * NameBlockGetDone() -- finalize name block iteration
958 * RETURN CODES: 1 success, 0 failure (st indicates why)
961 NameBlockGetDone(void *iterationId, afs_status_p st)
964 afs_status_t tst2, tst = 0;
965 cfg_csdb_nameblock_iteration_t *nbIterp;
967 nbIterp = (cfg_csdb_nameblock_iteration_t *) iterationId;
969 if (!ServerNameGetDone(nbIterp->serverIter, &tst2)) {
976 /* indicate failure */
987 * ServerNameGetBegin() -- begin database server and (optionally) fileserver
990 * RETURN CODES: 1 success, 0 failure (st indicates why)
993 ServerNameGetBegin(cfg_host_p cfg_host, short dbOnly, void **iterationIdP,
997 afs_status_t tst2, tst = 0;
998 cfg_server_iteration_t *serverIterp;
1000 serverIterp = (cfg_server_iteration_t *) malloc(sizeof(*serverIterp));
1002 if (serverIterp == NULL) {
1005 serverIterp->dbOnly = dbOnly;
1008 if (!util_DatabaseServerGetBegin
1009 (cfg_host->cellName, &serverIterp->iterationId, &tst2)) {
1013 if (!afsclient_AFSServerGetBegin
1014 (cfg_host->cellHandle, &serverIterp->iterationId, &tst2)) {
1020 *iterationIdP = serverIterp;
1027 /* indicate failure */
1038 * ServerNameGetNext() -- get next server name
1040 * RETURN CODES: 1 success, 0 failure (st indicates why)
1043 ServerNameGetNext(void *iterationId, char *serverName, afs_status_p st)
1046 afs_status_t tst2, tst = 0;
1047 cfg_server_iteration_t *serverIterp;
1049 serverIterp = (cfg_server_iteration_t *) iterationId;
1051 if (serverIterp->dbOnly) {
1052 util_databaseServerEntry_t serverEntry;
1054 if (!util_DatabaseServerGetNext
1055 (serverIterp->iterationId, &serverEntry, &tst2)) {
1058 strcpy(serverName, serverEntry.serverName);
1061 afs_serverEntry_t serverEntry;
1063 if (!afsclient_AFSServerGetNext
1064 (serverIterp->iterationId, &serverEntry, &tst2)) {
1067 strcpy(serverName, serverEntry.serverName);
1072 /* indicate failure */
1083 * ServerNameGetDone() -- terminate server enumeration
1085 * RETURN CODES: 1 success, 0 failure (st indicates why)
1088 ServerNameGetDone(void *iterationId, afs_status_p st)
1091 afs_status_t tst2, tst = 0;
1092 cfg_server_iteration_t *serverIterp;
1094 serverIterp = (cfg_server_iteration_t *) iterationId;
1096 if (serverIterp->dbOnly) {
1097 if (!util_DatabaseServerGetDone(serverIterp->iterationId, &tst2)) {
1101 if (!afsclient_AFSServerGetDone(serverIterp->iterationId, &tst2)) {
1109 /* indicate failure */