/* * CellServDbUpdate() -- add or remove a server CellServDB entry. * * Common function implementing cfg_CellServDb{Add/Remove}Host(). */ static int CellServDbUpdate(int updateOp, void *hostHandle, const char *sysControlHost, cfg_cellServDbUpdateCallBack_t callBack, void *callBackId, int *maxUpdates, afs_status_p st) { int rc = 1; afs_status_t tst2, tst = 0; cfg_host_p cfg_host = (cfg_host_p) hostHandle; char fullSysHostName[MAXHOSTCHARS]; /* validate parameters */ if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) { tst = tst2; } else if (sysControlHost != NULL && *sysControlHost == '\0') { tst = ADMCFGHOSTNAMENULL; } else if (callBack == NULL) { tst = ADMCFGCALLBACKNULL; } else if (maxUpdates == NULL) { tst = ADMCFGUPDATECOUNTNULL; } /* resolve sys ctrl host to fully qualified name (if extant) */ if (tst == 0) { if (sysControlHost != NULL) { if (!cfgutil_HostNameGetFull (sysControlHost, fullSysHostName, &tst2)) { tst = tst2; } else { sysControlHost = fullSysHostName; } } } /* Update cell-wide server CellServDb as follows: * * 1) If system control machine is in use then update the following: * system control host + database server hosts + configuration host * * Updating the system control machine is theoretically sufficient, * as all server hosts should be getting configuration information * from there. However, we don't want to have to delay further * configuration until this update occurs (which could be set for * any time interval). Therefore, we compromise by manually * updating the database server hosts and the host being configured. * * 2) If no system control machine is in use then update the following: * fileserver hosts + database server hosts + configuration host * * General algorithm: * We create a set of server name blocks, with one thread per name * block that is responsible for updating the servers in that block. * All server name blocks share a single control block that stores * common data and coordinates start/abort and cleanup activities. * All threads wait for the start/abort signal before performing * update operations so that this function is atomic. */ if (tst == 0) { cfg_csdb_update_ctrl_t *ctrlBlockp = NULL; *maxUpdates = 0; /* create control block */ ctrlBlockp = (cfg_csdb_update_ctrl_t *) malloc(sizeof(*ctrlBlockp)); if (ctrlBlockp == NULL) { tst = ADMNOMEM; } else { ctrlBlockp->cfg_host = cfg_host; ctrlBlockp->op = updateOp; ctrlBlockp->callBack = callBack; ctrlBlockp->callBackId = callBackId; ctrlBlockp->disposition = CSDB_WAIT; ctrlBlockp->workersActive = 0; if (pthread_mutex_init(&ctrlBlockp->mutex, NULL)) { tst = ADMMUTEXINIT; } else if (pthread_cond_init(&ctrlBlockp->event, NULL)) { tst = ADMCONDINIT; } else { /* Unfortunately the bosserver adds/removes entries from * the server CellServDB based on a case-sensitive string * comparison, rather than using an address comparison * to handle aliasing. So we must use the name for the * configuration host exactly as listed in the CellServDB. * * Of course the 3.5 bosserver can and should be modified to * handle aliases, but we still have to deal with down-level * servers in this library. * * To get reasonable performance, the presumption is made * that all server CellServDB are identical. This way we * can look up the configuration host alias once and use * it everywhere. If this proves to be insufficient then * this lookup will have to be done for every server to be * updated which will be very costly; such individual lookups * would naturally be handled by the update worker threads. * * A final presumption is that we can just look at the * server CellServDB on the current database servers to * get the configuration host alias. The only time this * might get us into trouble is in a re-do scenario. */ if (!CfgHostGetCellServDbAlias (cfg_host, ctrlBlockp->opHostAlias, &tst2)) { tst = tst2; } else if (*ctrlBlockp->opHostAlias == '\0') { /* no alias found; go with config host working name */ strcpy(ctrlBlockp->opHostAlias, cfg_host->hostName); } } if (tst != 0) { free(ctrlBlockp); } else { /* fill name blocks, handing each to a worker thread */ void *nameBlockIter = NULL; short workersStarted = 0; if (!NameBlockGetBegin (cfg_host, sysControlHost, ctrlBlockp, &nameBlockIter, &tst2)) { tst = tst2; } else { cfg_csdb_update_name_t *nameBlockp = NULL; short nameBlockDone = 0; while (!nameBlockDone) { nameBlockp = ((cfg_csdb_update_name_t *) malloc(sizeof(*nameBlockp))); if (nameBlockp == NULL) { tst = ADMNOMEM; nameBlockDone = 1; } else if (!NameBlockGetNext (nameBlockIter, nameBlockp, &tst2)) { /* no more entries (or failure) */ if (tst2 != ADMITERATORDONE) { tst = tst2; } free(nameBlockp); nameBlockDone = 1; } else { *maxUpdates += nameBlockp->serverCount; if (StartUpdateWorkerThread(nameBlockp, &tst2)) { /* increment worker count; lock not required * until workers given start/abort signal. */ ctrlBlockp->workersActive++; workersStarted = 1; } else { tst = tst2; free(nameBlockp); nameBlockDone = 1; } } } if (!NameBlockGetDone(nameBlockIter, &tst2)) { tst = tst2; } } if (workersStarted) { /* worker threads started; set disposition and signal */ if (pthread_mutex_lock(&ctrlBlockp->mutex)) { tst = ADMMUTEXLOCK; } else { if (tst == 0) { /* tell workers to proceed with updates */ ctrlBlockp->disposition = CSDB_GO; } else { /* tell workers to abort */ ctrlBlockp->disposition = CSDB_ABORT; } if (pthread_mutex_unlock(&ctrlBlockp->mutex)) { tst = ADMMUTEXUNLOCK; } if (pthread_cond_broadcast(&ctrlBlockp->event)) { tst = ADMCONDSIGNAL; } } } else { /* no worker threads started */ free(ctrlBlockp); } } } } if (tst != 0) { /* indicate failure */ rc = 0; } if (st != NULL) { *st = tst; } return rc; }
/* * ClientCellServDbUpdate() -- add or remove a client CellServDB entry. * * Common function implementing cfg_ClientCellServDb{Add/Remove}(). */ static int ClientCellServDbUpdate(int updateOp, void *hostHandle, const char *cellName, const char *dbentry, afs_status_p st) { int rc = 1; afs_status_t tst2, tst = 0; cfg_host_p cfg_host = (cfg_host_p) hostHandle; char dbentryFull[MAXHOSTCHARS]; /* validate parameters and resolve dbentry to fully qualified name */ if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) { tst = tst2; } else if (cellName == NULL || *cellName == '\0') { tst = ADMCFGCELLNAMENULL; } else if (strlen(cellName) > (MAXCELLCHARS - 1)) { tst = ADMCFGCELLNAMETOOLONG; } else if (dbentry == NULL || *dbentry == '\0') { tst = ADMCFGHOSTNAMENULL; } else if (strlen(dbentry) > (MAXHOSTCHARS - 1)) { tst = ADMCFGHOSTNAMETOOLONG; } else if (!cfgutil_HostNameGetFull(dbentry, dbentryFull, &tst2)) { tst = tst2; } /* remote configuration not yet supported in this function */ if (tst == 0) { if (!cfg_host->is_local) { tst = ADMCFGNOTSUPPORTED; } } /* modify local client CellServDB entry for specified cell */ #ifdef AFS_NT40_ENV if (tst == 0) { CELLSERVDB clientDb; if (!CSDB_ReadFile(&clientDb, AFSDIR_CLIENT_CELLSERVDB_FILEPATH)) { tst = ADMCFGCLIENTCELLSERVDBNOTREAD; } else { CELLDBLINE *cellLinep = CSDB_FindCell(&clientDb, cellName); CELLDBLINE *serverLinep = NULL; int serverLineCount = 0; if (cellLinep != NULL) { /* found cellName, now find server to add/remove */ CELLDBLINE *workingLinep; for (workingLinep = cellLinep->pNext; workingLinep != NULL; workingLinep = workingLinep->pNext) { CELLDBLINEINFO lineInfo; if (!CSDB_CrackLine(&lineInfo, workingLinep->szLine)) { /* not a server (or cell) line; perhaps a comment */ continue; } else if (lineInfo.szCell[0] != '\0') { /* hit a new cell line */ break; } else { /* found a server line; check if is host of interest */ short isValid; int dbentryAddr = ntohl(lineInfo.ipServer); serverLineCount++; if (!cfgutil_HostAddressIsValid (dbentryFull, dbentryAddr, &isValid, &tst2)) { tst = tst2; break; } else if (isValid) { /* found server of interest */ serverLinep = workingLinep; break; } } } } if (tst == 0) { if (updateOp == CSDB_OP_ADD && serverLinep == NULL) { if (cellLinep == NULL) { cellLinep = CSDB_AddCell(&clientDb, cellName, NULL, NULL); } if (cellLinep == NULL) { tst = ADMNOMEM; } else if (serverLineCount >= MAXHOSTSPERCELL) { tst = ADMCFGCLIENTCELLSERVDBNOSPACE; } else { const char *dbentryAddrStr; if (!cfgutil_HostNameGetAddressString (dbentryFull, &dbentryAddrStr, &tst2)) { tst = tst2; } else { serverLinep = CSDB_AddCellServer(&clientDb, cellLinep, dbentryAddrStr, dbentryFull); if (serverLinep == NULL) { tst = ADMNOMEM; } } } } else if (updateOp == CSDB_OP_REM && serverLinep != NULL) { (void)CSDB_RemoveLine(&clientDb, serverLinep); } if (tst == 0) { if (!CSDB_WriteFile(&clientDb)) { tst = ADMCFGCLIENTCELLSERVDBNOTWRITTEN; } } } CSDB_FreeFile(&clientDb); } } #else if (tst == 0) { /* function not yet implemented for Unix */ tst = ADMCFGNOTSUPPORTED; } #endif /* AFS_NT40_ENV */ if (tst != 0) { /* indicate failure */ rc = 0; } if (st != NULL) { *st = tst; } return rc; }
/* * cfg_HostOpen() -- Obtain host configuration handle. */ int ADMINAPI cfg_HostOpen(void *cellHandle, /* cell handle */ const char *hostName, /* name of host to configure */ void **hostHandleP, /* host config handle */ afs_status_p st) { /* completion status */ int rc = 1; afs_status_t tst2, tst = 0; cfg_host_p cfg_host; char fullHostName[MAXHOSTCHARS]; /* validate parameters and resolve host name to fully qualified name */ if (!CellHandleIsValid(cellHandle, &tst2)) { tst = tst2; } else if (hostName == NULL || *hostName == '\0') { tst = ADMCFGHOSTNAMENULL; } else if (strlen(hostName) > (MAXHOSTCHARS - 1)) { tst = ADMCFGHOSTNAMETOOLONG; } else if (hostHandleP == NULL) { tst = ADMCFGHOSTHANDLEPNULL; } else if (!cfgutil_HostNameGetFull(hostName, fullHostName, &tst2)) { tst = tst2; } /* remote configuration not yet supported; hostName must be local host */ if (tst == 0) { short isLocal; if (!cfgutil_HostNameIsLocal(hostName, &isLocal, &tst2)) { tst = tst2; } else if (!isLocal) { tst = ADMCFGNOTSUPPORTED; } } /* allocate a host configuration handle */ if (tst == 0) { char *localHostName; if ((cfg_host = (cfg_host_p) malloc(sizeof(cfg_host_t))) == NULL) { tst = ADMNOMEM; } else if ((localHostName = (char *)malloc(strlen(fullHostName) + 1)) == NULL) { free(cfg_host); tst = ADMNOMEM; } else { /* initialize handle */ cfg_host->begin_magic = BEGIN_MAGIC; cfg_host->is_valid = 1; cfg_host->hostName = localHostName; cfg_host->is_local = 1; /* not yet supporting remote config */ cfg_host->cellHandle = cellHandle; cfg_host->bosHandle = NULL; cfg_host->end_magic = END_MAGIC; strcpy(localHostName, fullHostName); if (!afsclient_CellNameGet (cfg_host->cellHandle, &cfg_host->cellName, &tst2)) { tst = tst2; } else if (pthread_mutex_init(&cfg_host->mutex, NULL)) { tst = ADMMUTEXINIT; } if (tst != 0) { /* cell name lookup or mutex initialization failed */ free(localHostName); free(cfg_host); } } } if (tst == 0) { /* success; return host config handle to user */ *hostHandleP = cfg_host; } else { /* indicate failure */ rc = 0; } if (st != NULL) { *st = tst; } return rc; }