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>
30 #include <afs/afs_Admin.h>
31 #include <afs/afs_AdminErrors.h>
32 #include <afs/afs_bosAdmin.h>
33 #include <afs/afs_clientAdmin.h>
34 #include <afs/afs_utilAdmin.h>
36 #include <afs/cellconfig.h>
37 #include <afs/bnode.h>
39 #include "cfginternal.h"
40 #include "afs_cfgAdmin.h"
43 /* Local declarations and definitions */
45 #define CSDB_OP_ADD 0 /* add a server CellServDB entry */
46 #define CSDB_OP_REM 1 /* remove a server CellServDB entry */
48 #define CSDB_WAIT 0 /* wait to begin CellServDB update operations */
49 #define CSDB_GO 1 /* begin CellServDB update operations */
50 #define CSDB_ABORT 2 /* abort CellServDB update operations */
52 #define SERVER_NAME_BLOCK_SIZE 20 /* number of server names in a block */
55 /* server name iterator */
57 int dbOnly; /* enumerate database servers only */
58 void *iterationId; /* underlying iteration handle */
59 } cfg_server_iteration_t;
62 /* CellServDB update control block */
64 /* control block invariants */
65 cfg_host_p cfg_host; /* host configuration handle */
66 int op; /* CellServDB update operation type */
67 char opHostAlias[MAXHOSTCHARS]; /* CellServDB alias for config host */
68 cfg_cellServDbUpdateCallBack_t callBack; /* CellServDB update callback */
69 void *callBackId; /* CellServDB update callback cookie */
71 /* control block synchronization objects */
72 pthread_cond_t event; /* disposition change event */
73 pthread_mutex_t mutex; /* protects disposition and workersActive */
74 int disposition; /* wait, go, or abort operation */
75 int workersActive; /* count of active worker threads */
76 } cfg_csdb_update_ctrl_t;
78 /* CellServDB update name block */
80 cfg_csdb_update_ctrl_t *ctrl; /* pointer to common control block */
81 int serverCount; /* number of entries in serverName array */
82 char serverName[SERVER_NAME_BLOCK_SIZE][AFS_MAX_SERVER_NAME_LEN];
83 } cfg_csdb_update_name_t;
85 /* name block iterator */
87 void *serverIter; /* server name iterator */
88 cfg_csdb_update_ctrl_t *ctrlBlockp; /* update control block */
89 const char *cfgHost; /* configuration host name */
90 const char *sysControlHost; /* system control host name (if any) */
91 short cfgInBlock; /* configuration host in a name block */
92 short sysInBlock; /* system control host in a name block */
93 short serverIterDone; /* server name enumeration complete */
94 } cfg_csdb_nameblock_iteration_t;
99 CellServDbUpdate(int updateOp, void *hostHandle, const char *sysControlHost,
100 cfg_cellServDbUpdateCallBack_t callBack, void *callBackId,
101 int *maxUpdates, afs_status_p st);
104 StartUpdateWorkerThread(cfg_csdb_update_name_t * nameBlockp,
107 static void *UpdateWorkerThread(void *argp);
110 CfgHostGetCellServDbAlias(cfg_host_p cfg_host, char *cfgHostAlias,
114 NameBlockGetBegin(cfg_host_p cfg_host, const char *sysControlHost,
115 cfg_csdb_update_ctrl_t * ctrlBlockp, void **iterationIdP,
119 NameBlockGetNext(void *iterationId, cfg_csdb_update_name_t * nameBlockp,
123 NameBlockGetDone(void *iterationId, afs_status_p st);
126 ServerNameGetBegin(cfg_host_p cfg_host, short dbOnly, void **iterationIdP,
130 ServerNameGetNext(void *iterationId, char *serverName, afs_status_p st);
133 ServerNameGetDone(void *iterationId, afs_status_p st);
137 /* ---------------- Exported CellServDB functions ------------------ */
141 * cfg_cellServDbUpdateCallBack_t -- prototype for status callback that is
142 * invoked by functions that update the CellServDB.
144 * Implementation provided by library user.
147 * callBackId - user-supplied context identifier; used by caller to
148 * distinguish results from different functions (or different
149 * invocations of the same function) that utilize the same callback.
151 * statusItemP - pointer to status information returned by a function
152 * via this callback; an statusItemP value of NULL indicates
153 * termination of status callbacks for a given function invocation;
154 * the termination callback will not occur until all other callbacks
155 * in the set have completed.
157 * status - if statusItemP is NULL then this argument indicates whether
158 * termination of status callbacks is due to logical completion
162 * The callback thread is not permitted to reenter the configuration
163 * library except to deallocate returned storage.
168 * cfg_CellServDbAddHost() -- Add host being configured to server
169 * CellServDB on all fileserver and database machines in cell and to
170 * host's server CellServDB.
172 * If a System Control machine has been configured, sysControlHost must
173 * specify the host name; otherwise, sysControlHost must be NULL.
176 cfg_CellServDbAddHost(void *hostHandle, /* host config handle */
177 const char *sysControlHost, /* sys control host */
178 cfg_cellServDbUpdateCallBack_t callBack, void *callBackId, int *maxUpdates, /* max servers to update */
180 { /* completion status */
181 return CellServDbUpdate(CSDB_OP_ADD, hostHandle, sysControlHost, callBack,
182 callBackId, maxUpdates, st);
187 * cfg_CellServDbRemoveHost() -- Remove host being configured from server
188 * CellServDB on all fileserver and database machines in cell and from
189 * host's server CellServDB.
191 * If a System Control machine has been configured, sysControlHost must
192 * specify the host name; otherwise, sysControlHost must be NULL.
195 cfg_CellServDbRemoveHost(void *hostHandle, /* host config handle */
196 const char *sysControlHost, /* sys control host */
197 cfg_cellServDbUpdateCallBack_t callBack, void *callBackId, int *maxUpdates, /* max servers to update */
199 { /* completion status */
200 return CellServDbUpdate(CSDB_OP_REM, hostHandle, sysControlHost, callBack,
201 callBackId, maxUpdates, st);
206 * cfg_CellServDbEnumerate() -- Enumerate database machines known to the
207 * specified database or fileserver machine. Enumeration is returned
211 cfg_CellServDbEnumerate(const char *fsDbHost, /* fileserver or database host */
212 char **cellName, /* cell name for cellDbHosts */
213 char **cellDbHosts, /* cell database hosts */
215 { /* completion status */
217 afs_status_t tst2, tst = 0;
219 /* validate parameters */
221 if (fsDbHost == NULL || *fsDbHost == '\0') {
222 tst = ADMCFGHOSTNAMENULL;
223 } else if (cellName == NULL) {
224 tst = ADMCFGCELLNAMENULL;
225 } else if (cellDbHosts == NULL) {
226 tst = ADMCFGCELLDBHOSTSNULL;
229 /* enumerate server CellServDB on specified host, along with cell name */
234 char dbhostName[MAXHOSTSPERCELL][BOS_MAX_NAME_LEN];
235 char dbhostCell[BOS_MAX_NAME_LEN];
238 if (!afsclient_NullCellOpen(&cellHandle, &tst2)) {
241 if (!bos_ServerOpen(cellHandle, fsDbHost, &bosHandle, &tst2)) {
246 if (!bos_HostGetBegin(bosHandle, &dbIter, &tst2)) {
249 for (dbhostCount = 0;; dbhostCount++) {
250 char dbhostNameTemp[BOS_MAX_NAME_LEN];
252 if (!bos_HostGetNext(dbIter, dbhostNameTemp, &tst2)) {
253 /* no more entries (or failure) */
254 if (tst2 != ADMITERATORDONE) {
258 } else if (dbhostCount >= MAXHOSTSPERCELL) {
259 /* more entries than expected */
260 tst = ADMCFGCELLSERVDBTOOMANYENTRIES;
263 strcpy(dbhostName[dbhostCount], dbhostNameTemp);
267 if (!bos_HostGetDone(dbIter, &tst2)) {
272 /* got database servers; now get cell name */
273 if (!bos_CellGet(bosHandle, dbhostCell, &tst2)) {
279 if (!bos_ServerClose(bosHandle, &tst2)) {
284 if (!afsclient_CellClose(cellHandle, &tst2)) {
290 /* return database hosts to caller */
294 for (i = 0; i < dbhostCount; i++) {
295 bufSize += strlen(dbhostName[i]) + 1;
297 bufSize++; /* end multistring */
299 *cellDbHosts = (char *)malloc(bufSize);
301 if (*cellDbHosts == NULL) {
304 char *bufp = *cellDbHosts;
306 for (i = 0; i < dbhostCount; i++) {
307 strcpy(bufp, dbhostName[i]);
308 bufp += strlen(bufp) + 1;
313 /* return cell name to caller */
315 *cellName = (char *)malloc(strlen(dbhostCell) + 1);
317 if (*cellName == NULL) {
321 strcpy(*cellName, dbhostCell);
328 /* indicate failure */
339 /* ---------------- Exported Utility functions ------------------ */
343 * cfg_CellServDbStatusDeallocate() -- Deallocate CellServDB update status
344 * record returned by library.
347 cfg_CellServDbStatusDeallocate(cfg_cellServDbStatus_t * statusItempP,
350 free((void *)statusItempP);
362 /* ---------------- Local functions ------------------ */
366 * CellServDbUpdate() -- add or remove a server CellServDB entry.
368 * Common function implementing cfg_CellServDb{Add/Remove}Host().
371 CellServDbUpdate(int updateOp, void *hostHandle, const char *sysControlHost,
372 cfg_cellServDbUpdateCallBack_t callBack, void *callBackId,
373 int *maxUpdates, afs_status_p st)
376 afs_status_t tst2, tst = 0;
377 cfg_host_p cfg_host = (cfg_host_p) hostHandle;
378 char fullSysHostName[MAXHOSTCHARS];
380 /* validate parameters */
382 if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
384 } else if (sysControlHost != NULL && *sysControlHost == '\0') {
385 tst = ADMCFGHOSTNAMENULL;
386 } else if (callBack == NULL) {
387 tst = ADMCFGCALLBACKNULL;
388 } else if (maxUpdates == NULL) {
389 tst = ADMCFGUPDATECOUNTNULL;
392 /* resolve sys ctrl host to fully qualified name (if extant) */
395 if (sysControlHost != NULL) {
396 if (!cfgutil_HostNameGetFull
397 (sysControlHost, fullSysHostName, &tst2)) {
400 sysControlHost = fullSysHostName;
405 /* Update cell-wide server CellServDb as follows:
407 * 1) If system control machine is in use then update the following:
408 * system control host + database server hosts + configuration host
410 * Updating the system control machine is theoretically sufficient,
411 * as all server hosts should be getting configuration information
412 * from there. However, we don't want to have to delay further
413 * configuration until this update occurs (which could be set for
414 * any time interval). Therefore, we compromise by manually
415 * updating the database server hosts and the host being configured.
417 * 2) If no system control machine is in use then update the following:
418 * fileserver hosts + database server hosts + configuration host
421 * We create a set of server name blocks, with one thread per name
422 * block that is responsible for updating the servers in that block.
423 * All server name blocks share a single control block that stores
424 * common data and coordinates start/abort and cleanup activities.
425 * All threads wait for the start/abort signal before performing
426 * update operations so that this function is atomic.
430 cfg_csdb_update_ctrl_t *ctrlBlockp;
434 /* create control block */
436 ctrlBlockp = (cfg_csdb_update_ctrl_t *) malloc(sizeof(*ctrlBlockp));
438 if (ctrlBlockp == NULL) {
441 ctrlBlockp->cfg_host = cfg_host;
442 ctrlBlockp->op = updateOp;
443 ctrlBlockp->callBack = callBack;
444 ctrlBlockp->callBackId = callBackId;
445 ctrlBlockp->disposition = CSDB_WAIT;
446 ctrlBlockp->workersActive = 0;
448 if (pthread_mutex_init(&ctrlBlockp->mutex, NULL)) {
450 } else if (pthread_cond_init(&ctrlBlockp->event, NULL)) {
453 /* Unfortunately the bosserver adds/removes entries from
454 * the server CellServDB based on a case-sensitive string
455 * comparison, rather than using an address comparison
456 * to handle aliasing. So we must use the name for the
457 * configuration host exactly as listed in the CellServDB.
459 * Of course the 3.5 bosserver can and should be modified to
460 * handle aliases, but we still have to deal with down-level
461 * servers in this library.
463 * To get reasonable performance, the presumption is made
464 * that all server CellServDB are identical. This way we
465 * can look up the configuration host alias once and use
466 * it everywhere. If this proves to be insufficient then
467 * this lookup will have to be done for every server to be
468 * updated which will be very costly; such individual lookups
469 * would naturally be handled by the update worker threads.
471 * A final presumption is that we can just look at the
472 * server CellServDB on the current database servers to
473 * get the configuration host alias. The only time this
474 * might get us into trouble is in a re-do scenario.
476 if (!CfgHostGetCellServDbAlias
477 (cfg_host, ctrlBlockp->opHostAlias, &tst2)) {
479 } else if (*ctrlBlockp->opHostAlias == '\0') {
480 /* no alias found; go with config host working name */
481 strcpy(ctrlBlockp->opHostAlias, cfg_host->hostName);
488 /* fill name blocks, handing each to a worker thread */
490 short workersStarted = 0;
492 if (!NameBlockGetBegin
493 (cfg_host, sysControlHost, ctrlBlockp, &nameBlockIter,
497 cfg_csdb_update_name_t *nameBlockp;
498 short nameBlockDone = 0;
500 while (!nameBlockDone) {
501 nameBlockp = ((cfg_csdb_update_name_t *)
502 malloc(sizeof(*nameBlockp)));
504 if (nameBlockp == NULL) {
509 if (!NameBlockGetNext
510 (nameBlockIter, nameBlockp, &tst2)) {
511 /* no more entries (or failure) */
512 if (tst2 != ADMITERATORDONE) {
519 *maxUpdates += nameBlockp->serverCount;
521 if (StartUpdateWorkerThread(nameBlockp, &tst2)) {
522 /* increment worker count; lock not required
523 * until workers given start/abort signal.
525 ctrlBlockp->workersActive++;
535 if (!NameBlockGetDone(nameBlockIter, &tst2)) {
540 if (workersStarted) {
541 /* worker threads started; set disposition and signal */
542 if (pthread_mutex_lock(&ctrlBlockp->mutex)) {
546 /* tell workers to proceed with updates */
547 ctrlBlockp->disposition = CSDB_GO;
549 /* tell workers to abort */
550 ctrlBlockp->disposition = CSDB_ABORT;
553 if (pthread_mutex_unlock(&ctrlBlockp->mutex)) {
554 tst = ADMMUTEXUNLOCK;
556 if (pthread_cond_broadcast(&ctrlBlockp->event)) {
561 /* no worker threads started */
569 /* indicate failure */
580 * StartUpdateWorkerThread() -- start an update worker thread for the
581 * given server name block
583 * RETURN CODES: 1 success, 0 failure (st indicates why)
586 StartUpdateWorkerThread(cfg_csdb_update_name_t * nameBlockp, afs_status_p st)
589 afs_status_t tst = 0;
590 pthread_attr_t tattr;
593 if (pthread_attr_init(&tattr)) {
594 tst = ADMTHREADATTRINIT;
596 } else if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED)) {
597 tst = ADMTHREADATTRSETDETACHSTATE;
601 (&tid, &tattr, UpdateWorkerThread, (void *)nameBlockp)) {
602 tst = ADMTHREADCREATE;
606 /* indicate failure */
617 * UpdateWorkerThread() -- thread for updating CellServDB of servers in
618 * a single name block.
621 UpdateWorkerThread(void *argp)
623 afs_status_t sync_tst = 0;
624 cfg_csdb_update_name_t *nameBlockp = (cfg_csdb_update_name_t *) argp;
627 /* Pthread mutex and condition variable functions should never fail,
628 * but if they do make a best effort attempt to report the problem;
629 * will not be able to avoid race conditions in the face of such failures.
632 if (pthread_mutex_lock(&nameBlockp->ctrl->mutex)) {
633 sync_tst = ADMMUTEXLOCK;
636 while ((opDisposition = nameBlockp->ctrl->disposition) == CSDB_WAIT) {
637 /* wait for start/abort signal */
638 if (pthread_cond_wait
639 (&nameBlockp->ctrl->event, &nameBlockp->ctrl->mutex)) {
640 /* avoid tight loop if condition variable wait fails */
645 if (pthread_mutex_unlock(&nameBlockp->ctrl->mutex)) {
646 sync_tst = ADMMUTEXUNLOCK;
649 if (opDisposition == CSDB_GO) {
650 /* proceed with CellServDB update */
653 for (i = 0; i < nameBlockp->serverCount; i++) {
654 cfg_cellServDbStatus_t *statusp;
656 /* alloc memory for status information (including host name) */
658 while ((statusp = (cfg_cellServDbStatus_t *)
659 malloc(sizeof(*statusp) + AFS_MAX_SERVER_NAME_LEN)) ==
661 /* avoid tight loop while waiting for status storage */
665 statusp->fsDbHost = ((char *)statusp + sizeof(*statusp));
667 /* make update and set status information */
669 strcpy(statusp->fsDbHost, nameBlockp->serverName[i]);
672 /* report pthread problem */
673 statusp->status = sync_tst;
675 /* attempt update and report update status */
677 afs_status_t tst2, tst = 0;
680 (nameBlockp->ctrl->cfg_host->cellHandle,
681 nameBlockp->serverName[i], &bosHandle, &tst2)) {
685 char *opHost = nameBlockp->ctrl->opHostAlias;
687 if (nameBlockp->ctrl->op == CSDB_OP_ADD) {
688 if (!bos_HostCreate(bosHandle, opHost, &tst2)) {
692 if (!bos_HostDelete(bosHandle, opHost, &tst2)) {
693 if (tst2 != BZNOENT) {
699 if (!bos_ServerClose(bosHandle, &tst2)) {
703 statusp->status = tst;
706 /* make call back to return update status */
708 (*nameBlockp->ctrl->callBack) (nameBlockp->ctrl->callBackId,
713 /* last worker makes termination call back and deallocates control block */
715 if (pthread_mutex_lock(&nameBlockp->ctrl->mutex)) {
716 sync_tst = ADMMUTEXLOCK;
719 nameBlockp->ctrl->workersActive--;
721 if (nameBlockp->ctrl->workersActive == 0) {
722 if (opDisposition == CSDB_GO) {
723 (*nameBlockp->ctrl->callBack) (nameBlockp->ctrl->callBackId, NULL,
726 free(nameBlockp->ctrl);
729 if (pthread_mutex_unlock(&nameBlockp->ctrl->mutex)) {
730 sync_tst = ADMMUTEXUNLOCK;
733 /* all workers deallocate their own name block */
741 * CfgHostGetCellServDbAlias() -- Get alias for configuration host name
742 * as listed in the server CellServDB. If no alias is found then
743 * cfgHostAlias is set to the empty string.
745 * Note: cfgHostAlias is presumed to be a buffer of size MAXHOSTCHARS.
746 * Presumes all server CellServDB are identical.
747 * Only checks server CellServDB of database servers.
749 * RETURN CODES: 1 success, 0 failure (st indicates why)
752 CfgHostGetCellServDbAlias(cfg_host_p cfg_host, char *cfgHostAlias,
756 afs_status_t tst2, tst = 0;
759 if (!util_DatabaseServerGetBegin(cfg_host->cellName, &dbIter, &tst2)) {
762 util_databaseServerEntry_t dbhostEntry;
763 afs_status_t dbhostSt = 0;
764 short dbhostDone = 0;
765 short dbhostFound = 0;
767 while (!dbhostDone) {
768 if (!util_DatabaseServerGetNext(dbIter, &dbhostEntry, &tst2)) {
769 /* no more entries (or failure) */
770 if (tst2 != ADMITERATORDONE) {
776 if (!cfgutil_HostNameGetCellServDbAlias
777 (dbhostEntry.serverName, cfg_host->hostName, cfgHostAlias,
779 /* save failure status but keep trying */
782 } else if (*cfgHostAlias != '\0') {
789 *cfgHostAlias = '\0';
796 if (!util_DatabaseServerGetDone(dbIter, &tst2)) {
802 /* indicate failure */
813 * NameBlockGetBegin() -- initialize name block iteration
815 * RETURN CODES: 1 success, 0 failure (st indicates why)
818 NameBlockGetBegin(cfg_host_p cfg_host, const char *sysControlHost,
819 cfg_csdb_update_ctrl_t * ctrlBlockp, void **iterationIdP,
823 afs_status_t tst2, tst = 0;
824 cfg_csdb_nameblock_iteration_t *nbIterp;
826 nbIterp = (cfg_csdb_nameblock_iteration_t *) malloc(sizeof(*nbIterp));
828 if (nbIterp == NULL) {
831 short dbOnly = (sysControlHost != NULL);
833 nbIterp->ctrlBlockp = ctrlBlockp;
834 nbIterp->cfgHost = cfg_host->hostName;
835 nbIterp->sysControlHost = sysControlHost;
836 nbIterp->cfgInBlock = 0;
837 nbIterp->sysInBlock = 0;
838 nbIterp->serverIterDone = 0;
840 if (!ServerNameGetBegin
841 (cfg_host, dbOnly, &nbIterp->serverIter, &tst2)) {
846 *iterationIdP = nbIterp;
853 /* indicate failure */
864 * NameBlockGetNext() -- fill next name block
866 * RETURN CODES: 1 success, 0 failure (st indicates why)
869 NameBlockGetNext(void *iterationId, cfg_csdb_update_name_t * nameBlockp,
873 afs_status_t tst2, tst = 0;
874 cfg_csdb_nameblock_iteration_t *nbIterp;
877 nbIterp = (cfg_csdb_nameblock_iteration_t *) iterationId;
879 nameBlockp->ctrl = nbIterp->ctrlBlockp;
880 nameBlockp->serverCount = 0;
882 for (i = 0; i < SERVER_NAME_BLOCK_SIZE; i++) {
883 short nameEntered = 0;
885 if (!nbIterp->serverIterDone) {
886 if (ServerNameGetNext
887 (nbIterp->serverIter, nameBlockp->serverName[i], &tst2)) {
888 /* Got server name; check if matches cfg or sys control host.
889 * Do a simple string compare, rather than making an expensive
890 * cfgutil_HostNameIsAlias() call because it will not cause
891 * any problems to have a duplicate in the list.
895 if (!nbIterp->cfgInBlock) {
897 (nbIterp->cfgHost, nameBlockp->serverName[i])) {
898 nbIterp->cfgInBlock = 1;
902 if (!nbIterp->sysInBlock && nbIterp->sysControlHost != NULL) {
904 (nbIterp->sysControlHost,
905 nameBlockp->serverName[i])) {
906 nbIterp->sysInBlock = 1;
911 /* no more entries (or failure) */
912 if (tst2 == ADMITERATORDONE) {
913 nbIterp->serverIterDone = 1;
922 /* include config host and (possibly) sys control host */
923 if (!nbIterp->cfgInBlock) {
924 /* shouldn't be duplicate, but OK if is */
925 strcpy(nameBlockp->serverName[i], nbIterp->cfgHost);
926 nbIterp->cfgInBlock = 1;
929 } else if (!nbIterp->sysInBlock
930 && nbIterp->sysControlHost != NULL) {
931 /* shouldn't be duplicate, but OK if is */
932 strcpy(nameBlockp->serverName[i], nbIterp->sysControlHost);
933 nbIterp->sysInBlock = 1;
939 nameBlockp->serverCount++;
941 /* no more server names */
942 if (nameBlockp->serverCount == 0) {
943 tst = ADMITERATORDONE;
950 /* indicate failure */
961 * NameBlockGetDone() -- finalize name block iteration
963 * RETURN CODES: 1 success, 0 failure (st indicates why)
966 NameBlockGetDone(void *iterationId, afs_status_p st)
969 afs_status_t tst2, tst = 0;
970 cfg_csdb_nameblock_iteration_t *nbIterp;
972 nbIterp = (cfg_csdb_nameblock_iteration_t *) iterationId;
974 if (!ServerNameGetDone(nbIterp->serverIter, &tst2)) {
981 /* indicate failure */
992 * ServerNameGetBegin() -- begin database server and (optionally) fileserver
995 * RETURN CODES: 1 success, 0 failure (st indicates why)
998 ServerNameGetBegin(cfg_host_p cfg_host, short dbOnly, void **iterationIdP,
1002 afs_status_t tst2, tst = 0;
1003 cfg_server_iteration_t *serverIterp;
1005 serverIterp = (cfg_server_iteration_t *) malloc(sizeof(*serverIterp));
1007 if (serverIterp == NULL) {
1010 serverIterp->dbOnly = dbOnly;
1013 if (!util_DatabaseServerGetBegin
1014 (cfg_host->cellName, &serverIterp->iterationId, &tst2)) {
1018 if (!afsclient_AFSServerGetBegin
1019 (cfg_host->cellHandle, &serverIterp->iterationId, &tst2)) {
1025 *iterationIdP = serverIterp;
1032 /* indicate failure */
1043 * ServerNameGetNext() -- get next server name
1045 * RETURN CODES: 1 success, 0 failure (st indicates why)
1048 ServerNameGetNext(void *iterationId, char *serverName, afs_status_p st)
1051 afs_status_t tst2, tst = 0;
1052 cfg_server_iteration_t *serverIterp;
1054 serverIterp = (cfg_server_iteration_t *) iterationId;
1056 if (serverIterp->dbOnly) {
1057 util_databaseServerEntry_t serverEntry;
1059 if (!util_DatabaseServerGetNext
1060 (serverIterp->iterationId, &serverEntry, &tst2)) {
1063 strcpy(serverName, serverEntry.serverName);
1066 afs_serverEntry_t serverEntry;
1068 if (!afsclient_AFSServerGetNext
1069 (serverIterp->iterationId, &serverEntry, &tst2)) {
1072 strcpy(serverName, serverEntry.serverName);
1077 /* indicate failure */
1088 * ServerNameGetDone() -- terminate server enumeration
1090 * RETURN CODES: 1 success, 0 failure (st indicates why)
1093 ServerNameGetDone(void *iterationId, afs_status_p st)
1096 afs_status_t tst2, tst = 0;
1097 cfg_server_iteration_t *serverIterp;
1099 serverIterp = (cfg_server_iteration_t *) iterationId;
1101 if (serverIterp->dbOnly) {
1102 if (!util_DatabaseServerGetDone(serverIterp->iterationId, &tst2)) {
1106 if (!afsclient_AFSServerGetDone(serverIterp->iterationId, &tst2)) {
1114 /* indicate failure */