Commit | Line | Data |
---|---|---|
805e021f CE |
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 | } |