Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / libadmin / cfg / cfgdb.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 /* This file implements configuration functions in the following categories:
11 * cfg_CellServDb*() - manage the cell-wide server CellServDb database.
12 */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <afs/stds.h>
17
18 #include <roken.h>
19
20 #include <pthread.h>
21
22 #include <rx/rx.h>
23 #include <rx/rxstat.h>
24
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>
30
31 #include <afs/cellconfig.h>
32 #include <afs/bnode.h>
33
34 #include "cfginternal.h"
35 #include "afs_cfgAdmin.h"
36
37
38 /* Local declarations and definitions */
39
40 #define CSDB_OP_ADD 0 /* add a server CellServDB entry */
41 #define CSDB_OP_REM 1 /* remove a server CellServDB entry */
42
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 */
46
47 #define SERVER_NAME_BLOCK_SIZE 20 /* number of server names in a block */
48
49
50 /* server name iterator */
51 typedef struct {
52 int dbOnly; /* enumerate database servers only */
53 void *iterationId; /* underlying iteration handle */
54 } cfg_server_iteration_t;
55
56
57 /* CellServDB update control block */
58 typedef struct {
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 */
65
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;
72
73 /* CellServDB update name block */
74 typedef struct {
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;
79
80 /* name block iterator */
81 typedef struct {
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;
90
91
92
93 static int
94 CellServDbUpdate(int updateOp, void *hostHandle, const char *sysControlHost,
95 cfg_cellServDbUpdateCallBack_t callBack, void *callBackId,
96 int *maxUpdates, afs_status_p st);
97
98 static int
99 StartUpdateWorkerThread(cfg_csdb_update_name_t * nameBlockp,
100 afs_status_p st);
101
102 static void *UpdateWorkerThread(void *argp);
103
104 static int
105 CfgHostGetCellServDbAlias(cfg_host_p cfg_host, char *cfgHostAlias,
106 afs_status_p st);
107
108 static int
109 NameBlockGetBegin(cfg_host_p cfg_host, const char *sysControlHost,
110 cfg_csdb_update_ctrl_t * ctrlBlockp, void **iterationIdP,
111 afs_status_p st);
112
113 static int
114 NameBlockGetNext(void *iterationId, cfg_csdb_update_name_t * nameBlockp,
115 afs_status_p st);
116
117 static int
118 NameBlockGetDone(void *iterationId, afs_status_p st);
119
120 static int
121 ServerNameGetBegin(cfg_host_p cfg_host, short dbOnly, void **iterationIdP,
122 afs_status_p st);
123
124 static int
125 ServerNameGetNext(void *iterationId, char *serverName, afs_status_p st);
126
127 static int
128 ServerNameGetDone(void *iterationId, afs_status_p st);
129
130
131
132 /* ---------------- Exported CellServDB functions ------------------ */
133
134
135 /*
136 * cfg_cellServDbUpdateCallBack_t -- prototype for status callback that is
137 * invoked by functions that update the CellServDB.
138 *
139 * Implementation provided by library user.
140 *
141 * ARGUMENTS:
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.
145 *
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.
151 *
152 * status - if statusItemP is NULL then this argument indicates whether
153 * termination of status callbacks is due to logical completion
154 * or an error.
155 *
156 * RESTRICTIONS:
157 * The callback thread is not permitted to reenter the configuration
158 * library except to deallocate returned storage.
159 */
160
161
162 /*
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.
166 *
167 * If a System Control machine has been configured, sysControlHost must
168 * specify the host name; otherwise, sysControlHost must be NULL.
169 */
170 int ADMINAPI
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 */
174 afs_status_p st)
175 { /* completion status */
176 return CellServDbUpdate(CSDB_OP_ADD, hostHandle, sysControlHost, callBack,
177 callBackId, maxUpdates, st);
178 }
179
180
181 /*
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.
185 *
186 * If a System Control machine has been configured, sysControlHost must
187 * specify the host name; otherwise, sysControlHost must be NULL.
188 */
189 int ADMINAPI
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 */
193 afs_status_p st)
194 { /* completion status */
195 return CellServDbUpdate(CSDB_OP_REM, hostHandle, sysControlHost, callBack,
196 callBackId, maxUpdates, st);
197 }
198
199
200 /*
201 * cfg_CellServDbEnumerate() -- Enumerate database machines known to the
202 * specified database or fileserver machine. Enumeration is returned
203 * as a multistring.
204 */
205 int ADMINAPI
206 cfg_CellServDbEnumerate(const char *fsDbHost, /* fileserver or database host */
207 char **cellName, /* cell name for cellDbHosts */
208 char **cellDbHosts, /* cell database hosts */
209 afs_status_p st)
210 { /* completion status */
211 int rc = 1;
212 afs_status_t tst2, tst = 0;
213
214 /* validate parameters */
215
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;
222 }
223
224 /* enumerate server CellServDB on specified host, along with cell name */
225
226 if (tst == 0) {
227 void *cellHandle;
228 void *bosHandle;
229 char dbhostName[MAXHOSTSPERCELL][BOS_MAX_NAME_LEN];
230 char dbhostCell[BOS_MAX_NAME_LEN];
231 int dbhostCount = 0;
232
233 if (!afsclient_NullCellOpen(&cellHandle, &tst2)) {
234 tst = tst2;
235 } else {
236 if (!bos_ServerOpen(cellHandle, fsDbHost, &bosHandle, &tst2)) {
237 tst = tst2;
238 } else {
239 void *dbIter;
240
241 if (!bos_HostGetBegin(bosHandle, &dbIter, &tst2)) {
242 tst = tst2;
243 } else {
244 for (dbhostCount = 0;; dbhostCount++) {
245 char dbhostNameTemp[BOS_MAX_NAME_LEN];
246
247 if (!bos_HostGetNext(dbIter, dbhostNameTemp, &tst2)) {
248 /* no more entries (or failure) */
249 if (tst2 != ADMITERATORDONE) {
250 tst = tst2;
251 }
252 break;
253 } else if (dbhostCount >= MAXHOSTSPERCELL) {
254 /* more entries than expected */
255 tst = ADMCFGCELLSERVDBTOOMANYENTRIES;
256 break;
257 } else {
258 strcpy(dbhostName[dbhostCount], dbhostNameTemp);
259 }
260 }
261
262 if (!bos_HostGetDone(dbIter, &tst2)) {
263 tst = tst2;
264 }
265
266 if (tst == 0) {
267 /* got database servers; now get cell name */
268 if (!bos_CellGet(bosHandle, dbhostCell, &tst2)) {
269 tst = tst2;
270 }
271 }
272 }
273
274 if (!bos_ServerClose(bosHandle, &tst2)) {
275 tst = tst2;
276 }
277 }
278
279 if (!afsclient_CellClose(cellHandle, &tst2)) {
280 tst = tst2;
281 }
282 }
283
284 if (tst == 0) {
285 /* return database hosts to caller */
286 int i;
287 size_t bufSize = 0;
288
289 for (i = 0; i < dbhostCount; i++) {
290 bufSize += strlen(dbhostName[i]) + 1;
291 }
292 bufSize++; /* end multistring */
293
294 *cellDbHosts = malloc(bufSize);
295
296 if (*cellDbHosts == NULL) {
297 tst = ADMNOMEM;
298 } else {
299 char *bufp = *cellDbHosts;
300
301 for (i = 0; i < dbhostCount; i++) {
302 strcpy(bufp, dbhostName[i]);
303 bufp += strlen(bufp) + 1;
304 }
305 *bufp = '\0';
306 }
307
308 /* return cell name to caller */
309 if (tst == 0) {
310 *cellName = strdup(dbhostCell);
311
312 if (*cellName == NULL) {
313 free(*cellDbHosts);
314 *cellDbHosts = NULL;
315 tst = ADMNOMEM;
316 }
317 }
318 }
319 }
320
321 if (tst != 0) {
322 /* indicate failure */
323 rc = 0;
324 }
325 if (st != NULL) {
326 *st = tst;
327 }
328 return rc;
329 }
330
331
332
333 /* ---------------- Exported Utility functions ------------------ */
334
335
336 /*
337 * cfg_CellServDbStatusDeallocate() -- Deallocate CellServDB update status
338 * record returned by library.
339 */
340 int ADMINAPI
341 cfg_CellServDbStatusDeallocate(cfg_cellServDbStatus_t * statusItempP,
342 afs_status_p st)
343 {
344 if ( statusItempP )
345 free(statusItempP);
346
347 if (st != NULL) {
348 *st = 0;
349 }
350 return 1;
351 }
352
353
354
355
356
357 /* ---------------- Local functions ------------------ */
358
359
360 /*
361 * CellServDbUpdate() -- add or remove a server CellServDB entry.
362 *
363 * Common function implementing cfg_CellServDb{Add/Remove}Host().
364 */
365 static int
366 CellServDbUpdate(int updateOp, void *hostHandle, const char *sysControlHost,
367 cfg_cellServDbUpdateCallBack_t callBack, void *callBackId,
368 int *maxUpdates, afs_status_p st)
369 {
370 int rc = 1;
371 afs_status_t tst2, tst = 0;
372 cfg_host_p cfg_host = (cfg_host_p) hostHandle;
373 char fullSysHostName[MAXHOSTCHARS];
374
375 /* validate parameters */
376
377 if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
378 tst = 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;
385 }
386
387 /* resolve sys ctrl host to fully qualified name (if extant) */
388
389 if (tst == 0) {
390 if (sysControlHost != NULL) {
391 if (!cfgutil_HostNameGetFull
392 (sysControlHost, fullSysHostName, &tst2)) {
393 tst = tst2;
394 } else {
395 sysControlHost = fullSysHostName;
396 }
397 }
398 }
399
400 /* Update cell-wide server CellServDb as follows:
401 *
402 * 1) If system control machine is in use then update the following:
403 * system control host + database server hosts + configuration host
404 *
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.
411 *
412 * 2) If no system control machine is in use then update the following:
413 * fileserver hosts + database server hosts + configuration host
414 *
415 * General algorithm:
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.
422 */
423
424 if (tst == 0) {
425 cfg_csdb_update_ctrl_t *ctrlBlockp = NULL;
426
427 *maxUpdates = 0;
428
429 /* create control block */
430
431 ctrlBlockp = malloc(sizeof(*ctrlBlockp));
432
433 if (ctrlBlockp == NULL) {
434 tst = ADMNOMEM;
435 } else {
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;
442
443 if (pthread_mutex_init(&ctrlBlockp->mutex, NULL)) {
444 tst = ADMMUTEXINIT;
445 } else if (pthread_cond_init(&ctrlBlockp->event, NULL)) {
446 tst = ADMCONDINIT;
447 } else {
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.
453 *
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.
457 *
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.
465 *
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.
470 */
471 if (!CfgHostGetCellServDbAlias
472 (cfg_host, ctrlBlockp->opHostAlias, &tst2)) {
473 tst = tst2;
474 } else if (*ctrlBlockp->opHostAlias == '\0') {
475 /* no alias found; go with config host working name */
476 strcpy(ctrlBlockp->opHostAlias, cfg_host->hostName);
477 }
478 }
479
480 if (tst != 0) {
481 free(ctrlBlockp);
482 } else {
483 /* fill name blocks, handing each to a worker thread */
484 void *nameBlockIter = NULL;
485 short workersStarted = 0;
486
487 if (!NameBlockGetBegin
488 (cfg_host, sysControlHost, ctrlBlockp, &nameBlockIter,
489 &tst2)) {
490 tst = tst2;
491 } else {
492 cfg_csdb_update_name_t *nameBlockp = NULL;
493 short nameBlockDone = 0;
494
495 while (!nameBlockDone) {
496 nameBlockp = malloc(sizeof(*nameBlockp));
497
498 if (nameBlockp == NULL) {
499 tst = ADMNOMEM;
500 nameBlockDone = 1;
501
502 } else
503 if (!NameBlockGetNext
504 (nameBlockIter, nameBlockp, &tst2)) {
505 /* no more entries (or failure) */
506 if (tst2 != ADMITERATORDONE) {
507 tst = tst2;
508 }
509 free(nameBlockp);
510 nameBlockDone = 1;
511
512 } else {
513 *maxUpdates += nameBlockp->serverCount;
514
515 if (StartUpdateWorkerThread(nameBlockp, &tst2)) {
516 /* increment worker count; lock not required
517 * until workers given start/abort signal.
518 */
519 ctrlBlockp->workersActive++;
520 workersStarted = 1;
521 } else {
522 tst = tst2;
523 free(nameBlockp);
524 nameBlockDone = 1;
525 }
526 }
527 }
528
529 if (!NameBlockGetDone(nameBlockIter, &tst2)) {
530 tst = tst2;
531 }
532 }
533
534 if (workersStarted) {
535 /* worker threads started; set disposition and signal */
536 if (pthread_mutex_lock(&ctrlBlockp->mutex)) {
537 tst = ADMMUTEXLOCK;
538 } else {
539 if (tst == 0) {
540 /* tell workers to proceed with updates */
541 ctrlBlockp->disposition = CSDB_GO;
542 } else {
543 /* tell workers to abort */
544 ctrlBlockp->disposition = CSDB_ABORT;
545 }
546
547 if (pthread_mutex_unlock(&ctrlBlockp->mutex)) {
548 tst = ADMMUTEXUNLOCK;
549 }
550 if (pthread_cond_broadcast(&ctrlBlockp->event)) {
551 tst = ADMCONDSIGNAL;
552 }
553 }
554 } else {
555 /* no worker threads started */
556 free(ctrlBlockp);
557 }
558 }
559 }
560 }
561
562 if (tst != 0) {
563 /* indicate failure */
564 rc = 0;
565 }
566 if (st != NULL) {
567 *st = tst;
568 }
569 return rc;
570 }
571
572
573 /*
574 * StartUpdateWorkerThread() -- start an update worker thread for the
575 * given server name block
576 *
577 * RETURN CODES: 1 success, 0 failure (st indicates why)
578 */
579 static int
580 StartUpdateWorkerThread(cfg_csdb_update_name_t * nameBlockp, afs_status_p st)
581 {
582 int rc = 1;
583 afs_status_t tst = 0;
584 pthread_attr_t tattr;
585 pthread_t tid;
586
587 if (pthread_attr_init(&tattr)) {
588 tst = ADMTHREADATTRINIT;
589
590 } else if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED)) {
591 tst = ADMTHREADATTRSETDETACHSTATE;
592
593 } else
594 if (pthread_create
595 (&tid, &tattr, UpdateWorkerThread, (void *)nameBlockp)) {
596 tst = ADMTHREADCREATE;
597 }
598
599 if (tst != 0) {
600 /* indicate failure */
601 rc = 0;
602 }
603 if (st != NULL) {
604 *st = tst;
605 }
606 return rc;
607 }
608
609
610 /*
611 * UpdateWorkerThread() -- thread for updating CellServDB of servers in
612 * a single name block.
613 */
614 static void *
615 UpdateWorkerThread(void *argp)
616 {
617 afs_status_t sync_tst = 0;
618 cfg_csdb_update_name_t *nameBlockp = (cfg_csdb_update_name_t *) argp;
619 int opDisposition;
620
621 /* Pthread mutex and condition variable functions should never fail,
622 * but if they do make a best effort attempt to report the problem;
623 * will not be able to avoid race conditions in the face of such failures.
624 */
625
626 if (pthread_mutex_lock(&nameBlockp->ctrl->mutex)) {
627 sync_tst = ADMMUTEXLOCK;
628 }
629
630 while ((opDisposition = nameBlockp->ctrl->disposition) == CSDB_WAIT) {
631 /* wait for start/abort signal */
632 if (pthread_cond_wait
633 (&nameBlockp->ctrl->event, &nameBlockp->ctrl->mutex)) {
634 /* avoid tight loop if condition variable wait fails */
635 cfgutil_Sleep(1);
636 }
637 }
638
639 if (pthread_mutex_unlock(&nameBlockp->ctrl->mutex)) {
640 sync_tst = ADMMUTEXUNLOCK;
641 }
642
643 if (opDisposition == CSDB_GO) {
644 /* proceed with CellServDB update */
645 int i;
646
647 for (i = 0; i < nameBlockp->serverCount; i++) {
648 cfg_cellServDbStatus_t *statusp;
649
650 /* alloc memory for status information (including host name) */
651
652 while ((statusp =
653 malloc(sizeof(*statusp) + AFS_MAX_SERVER_NAME_LEN)) ==
654 NULL) {
655 /* avoid tight loop while waiting for status storage */
656 cfgutil_Sleep(1);
657 }
658
659 statusp->fsDbHost = ((char *)statusp + sizeof(*statusp));
660
661 /* make update and set status information */
662
663 strcpy(statusp->fsDbHost, nameBlockp->serverName[i]);
664
665 if (sync_tst != 0) {
666 /* report pthread problem */
667 statusp->status = sync_tst;
668 } else {
669 /* attempt update and report update status */
670 void *bosHandle;
671 afs_status_t tst2, tst = 0;
672
673 if (!bos_ServerOpen
674 (nameBlockp->ctrl->cfg_host->cellHandle,
675 nameBlockp->serverName[i], &bosHandle, &tst2)) {
676 tst = tst2;
677
678 } else {
679 char *opHost = nameBlockp->ctrl->opHostAlias;
680
681 if (nameBlockp->ctrl->op == CSDB_OP_ADD) {
682 if (!bos_HostCreate(bosHandle, opHost, &tst2)) {
683 tst = tst2;
684 }
685 } else {
686 if (!bos_HostDelete(bosHandle, opHost, &tst2)) {
687 if (tst2 != BZNOENT) {
688 tst = tst2;
689 }
690 }
691 }
692
693 if (!bos_ServerClose(bosHandle, &tst2)) {
694 tst = tst2;
695 }
696 }
697 statusp->status = tst;
698 }
699
700 /* make call back to return update status */
701
702 (*nameBlockp->ctrl->callBack) (nameBlockp->ctrl->callBackId,
703 statusp, 0);
704 }
705 }
706
707 /* last worker makes termination call back and deallocates control block */
708
709 if (pthread_mutex_lock(&nameBlockp->ctrl->mutex)) {
710 sync_tst = ADMMUTEXLOCK;
711 }
712
713 nameBlockp->ctrl->workersActive--;
714
715 if (nameBlockp->ctrl->workersActive == 0) {
716 if (opDisposition == CSDB_GO) {
717 (*nameBlockp->ctrl->callBack) (nameBlockp->ctrl->callBackId, NULL,
718 sync_tst);
719 }
720 free(nameBlockp->ctrl);
721 }
722
723 if (pthread_mutex_unlock(&nameBlockp->ctrl->mutex)) {
724 sync_tst = ADMMUTEXUNLOCK;
725 }
726
727 /* all workers deallocate their own name block */
728 free(nameBlockp);
729
730 return NULL;
731 }
732
733
734 /*
735 * CfgHostGetCellServDbAlias() -- Get alias for configuration host name
736 * as listed in the server CellServDB. If no alias is found then
737 * cfgHostAlias is set to the empty string.
738 *
739 * Note: cfgHostAlias is presumed to be a buffer of size MAXHOSTCHARS.
740 * Presumes all server CellServDB are identical.
741 * Only checks server CellServDB of database servers.
742 *
743 * RETURN CODES: 1 success, 0 failure (st indicates why)
744 */
745 static int
746 CfgHostGetCellServDbAlias(cfg_host_p cfg_host, char *cfgHostAlias,
747 afs_status_p st)
748 {
749 int rc = 1;
750 afs_status_t tst2, tst = 0;
751 void *dbIter;
752
753 if (!util_DatabaseServerGetBegin(cfg_host->cellName, &dbIter, &tst2)) {
754 tst = tst2;
755 } else {
756 util_databaseServerEntry_t dbhostEntry;
757 afs_status_t dbhostSt = 0;
758 short dbhostDone = 0;
759 short dbhostFound = 0;
760
761 while (!dbhostDone) {
762 if (!util_DatabaseServerGetNext(dbIter, &dbhostEntry, &tst2)) {
763 /* no more entries (or failure) */
764 if (tst2 != ADMITERATORDONE) {
765 tst = tst2;
766 }
767 dbhostDone = 1;
768
769 } else
770 if (!cfgutil_HostNameGetCellServDbAlias
771 (dbhostEntry.serverName, cfg_host->hostName, cfgHostAlias,
772 &tst2)) {
773 /* save failure status but keep trying */
774 dbhostSt = tst2;
775
776 } else if (*cfgHostAlias != '\0') {
777 dbhostFound = 1;
778 dbhostDone = 1;
779 }
780 }
781
782 if (!dbhostFound) {
783 *cfgHostAlias = '\0';
784
785 if (tst == 0) {
786 tst = dbhostSt;
787 }
788 }
789
790 if (!util_DatabaseServerGetDone(dbIter, &tst2)) {
791 tst = tst2;
792 }
793 }
794
795 if (tst != 0) {
796 /* indicate failure */
797 rc = 0;
798 }
799 if (st != NULL) {
800 *st = tst;
801 }
802 return rc;
803 }
804
805
806 /*
807 * NameBlockGetBegin() -- initialize name block iteration
808 *
809 * RETURN CODES: 1 success, 0 failure (st indicates why)
810 */
811 static int
812 NameBlockGetBegin(cfg_host_p cfg_host, const char *sysControlHost,
813 cfg_csdb_update_ctrl_t * ctrlBlockp, void **iterationIdP,
814 afs_status_p st)
815 {
816 int rc = 1;
817 afs_status_t tst2, tst = 0;
818 cfg_csdb_nameblock_iteration_t *nbIterp;
819
820 nbIterp = malloc(sizeof(*nbIterp));
821
822 if (nbIterp == NULL) {
823 tst = ADMNOMEM;
824 } else {
825 short dbOnly = (sysControlHost != NULL);
826
827 nbIterp->ctrlBlockp = ctrlBlockp;
828 nbIterp->cfgHost = cfg_host->hostName;
829 nbIterp->sysControlHost = sysControlHost;
830 nbIterp->cfgInBlock = 0;
831 nbIterp->sysInBlock = 0;
832 nbIterp->serverIterDone = 0;
833
834 if (!ServerNameGetBegin
835 (cfg_host, dbOnly, &nbIterp->serverIter, &tst2)) {
836 tst = tst2;
837 }
838
839 if (tst == 0) {
840 *iterationIdP = nbIterp;
841 } else {
842 free(nbIterp);
843 }
844 }
845
846 if (tst != 0) {
847 /* indicate failure */
848 rc = 0;
849 }
850 if (st != NULL) {
851 *st = tst;
852 }
853 return rc;
854 }
855
856
857 /*
858 * NameBlockGetNext() -- fill next name block
859 *
860 * RETURN CODES: 1 success, 0 failure (st indicates why)
861 */
862 static int
863 NameBlockGetNext(void *iterationId, cfg_csdb_update_name_t * nameBlockp,
864 afs_status_p st)
865 {
866 int rc = 1;
867 afs_status_t tst2, tst = 0;
868 cfg_csdb_nameblock_iteration_t *nbIterp;
869 int i;
870
871 nbIterp = (cfg_csdb_nameblock_iteration_t *) iterationId;
872
873 nameBlockp->ctrl = nbIterp->ctrlBlockp;
874 nameBlockp->serverCount = 0;
875
876 for (i = 0; i < SERVER_NAME_BLOCK_SIZE; i++) {
877 short nameEntered = 0;
878
879 if (!nbIterp->serverIterDone) {
880 if (ServerNameGetNext
881 (nbIterp->serverIter, nameBlockp->serverName[i], &tst2)) {
882 /* Got server name; check if matches cfg or sys control host.
883 * Do a simple string compare, rather than making an expensive
884 * cfgutil_HostNameIsAlias() call because it will not cause
885 * any problems to have a duplicate in the list.
886 */
887 nameEntered = 1;
888
889 if (!nbIterp->cfgInBlock) {
890 if (!strcasecmp
891 (nbIterp->cfgHost, nameBlockp->serverName[i])) {
892 nbIterp->cfgInBlock = 1;
893 }
894 }
895
896 if (!nbIterp->sysInBlock && nbIterp->sysControlHost != NULL) {
897 if (!strcasecmp
898 (nbIterp->sysControlHost,
899 nameBlockp->serverName[i])) {
900 nbIterp->sysInBlock = 1;
901 }
902 }
903
904 } else {
905 /* no more entries (or failure) */
906 if (tst2 == ADMITERATORDONE) {
907 nbIterp->serverIterDone = 1;
908 } else {
909 tst = tst2;
910 break;
911 }
912 }
913 }
914
915 if (!nameEntered) {
916 /* include config host and (possibly) sys control host */
917 if (!nbIterp->cfgInBlock) {
918 /* shouldn't be duplicate, but OK if is */
919 strcpy(nameBlockp->serverName[i], nbIterp->cfgHost);
920 nbIterp->cfgInBlock = 1;
921 nameEntered = 1;
922
923 } else if (!nbIterp->sysInBlock
924 && nbIterp->sysControlHost != NULL) {
925 /* shouldn't be duplicate, but OK if is */
926 strcpy(nameBlockp->serverName[i], nbIterp->sysControlHost);
927 nbIterp->sysInBlock = 1;
928 nameEntered = 1;
929 }
930 }
931
932 if (nameEntered) {
933 nameBlockp->serverCount++;
934 } else {
935 /* no more server names */
936 if (nameBlockp->serverCount == 0) {
937 tst = ADMITERATORDONE;
938 }
939 break;
940 }
941 }
942
943 if (tst != 0) {
944 /* indicate failure */
945 rc = 0;
946 }
947 if (st != NULL) {
948 *st = tst;
949 }
950 return rc;
951 }
952
953
954 /*
955 * NameBlockGetDone() -- finalize name block iteration
956 *
957 * RETURN CODES: 1 success, 0 failure (st indicates why)
958 */
959 static int
960 NameBlockGetDone(void *iterationId, afs_status_p st)
961 {
962 int rc = 1;
963 afs_status_t tst2, tst = 0;
964 cfg_csdb_nameblock_iteration_t *nbIterp;
965
966 nbIterp = (cfg_csdb_nameblock_iteration_t *) iterationId;
967
968 if (!ServerNameGetDone(nbIterp->serverIter, &tst2)) {
969 tst = tst2;
970 }
971
972 free(nbIterp);
973
974 if (tst != 0) {
975 /* indicate failure */
976 rc = 0;
977 }
978 if (st != NULL) {
979 *st = tst;
980 }
981 return rc;
982 }
983
984
985 /*
986 * ServerNameGetBegin() -- begin database server and (optionally) fileserver
987 * name enumeration
988 *
989 * RETURN CODES: 1 success, 0 failure (st indicates why)
990 */
991 static int
992 ServerNameGetBegin(cfg_host_p cfg_host, short dbOnly, void **iterationIdP,
993 afs_status_p st)
994 {
995 int rc = 1;
996 afs_status_t tst2, tst = 0;
997 cfg_server_iteration_t *serverIterp;
998
999 serverIterp = malloc(sizeof(*serverIterp));
1000
1001 if (serverIterp == NULL) {
1002 tst = ADMNOMEM;
1003 } else {
1004 serverIterp->dbOnly = dbOnly;
1005
1006 if (dbOnly) {
1007 if (!util_DatabaseServerGetBegin
1008 (cfg_host->cellName, &serverIterp->iterationId, &tst2)) {
1009 tst = tst2;
1010 }
1011 } else {
1012 if (!afsclient_AFSServerGetBegin
1013 (cfg_host->cellHandle, &serverIterp->iterationId, &tst2)) {
1014 tst = tst2;
1015 }
1016 }
1017
1018 if (tst == 0) {
1019 *iterationIdP = serverIterp;
1020 } else {
1021 free(serverIterp);
1022 }
1023 }
1024
1025 if (tst != 0) {
1026 /* indicate failure */
1027 rc = 0;
1028 }
1029 if (st != NULL) {
1030 *st = tst;
1031 }
1032 return rc;
1033 }
1034
1035
1036 /*
1037 * ServerNameGetNext() -- get next server name
1038 *
1039 * RETURN CODES: 1 success, 0 failure (st indicates why)
1040 */
1041 static int
1042 ServerNameGetNext(void *iterationId, char *serverName, afs_status_p st)
1043 {
1044 int rc = 1;
1045 afs_status_t tst2, tst = 0;
1046 cfg_server_iteration_t *serverIterp;
1047
1048 serverIterp = (cfg_server_iteration_t *) iterationId;
1049
1050 if (serverIterp->dbOnly) {
1051 util_databaseServerEntry_t serverEntry;
1052
1053 if (!util_DatabaseServerGetNext
1054 (serverIterp->iterationId, &serverEntry, &tst2)) {
1055 tst = tst2;
1056 } else {
1057 strcpy(serverName, serverEntry.serverName);
1058 }
1059 } else {
1060 afs_serverEntry_t serverEntry;
1061
1062 if (!afsclient_AFSServerGetNext
1063 (serverIterp->iterationId, &serverEntry, &tst2)) {
1064 tst = tst2;
1065 } else {
1066 strcpy(serverName, serverEntry.serverName);
1067 }
1068 }
1069
1070 if (tst != 0) {
1071 /* indicate failure */
1072 rc = 0;
1073 }
1074 if (st != NULL) {
1075 *st = tst;
1076 }
1077 return rc;
1078 }
1079
1080
1081 /*
1082 * ServerNameGetDone() -- terminate server enumeration
1083 *
1084 * RETURN CODES: 1 success, 0 failure (st indicates why)
1085 */
1086 static int
1087 ServerNameGetDone(void *iterationId, afs_status_p st)
1088 {
1089 int rc = 1;
1090 afs_status_t tst2, tst = 0;
1091 cfg_server_iteration_t *serverIterp;
1092
1093 serverIterp = (cfg_server_iteration_t *) iterationId;
1094
1095 if (serverIterp->dbOnly) {
1096 if (!util_DatabaseServerGetDone(serverIterp->iterationId, &tst2)) {
1097 tst = tst2;
1098 }
1099 } else {
1100 if (!afsclient_AFSServerGetDone(serverIterp->iterationId, &tst2)) {
1101 tst = tst2;
1102 }
1103 }
1104
1105 free(serverIterp);
1106
1107 if (tst != 0) {
1108 /* indicate failure */
1109 rc = 0;
1110 }
1111 if (st != NULL) {
1112 *st = tst;
1113 }
1114 return rc;
1115 }