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