Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / bucoord / ubik_db_if.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 /* Interface and supporting routines for the backup system's ubik database */
11
12 #include <afsconfig.h>
13 #include <afs/stds.h>
14
15 #include <roken.h>
16
17 #ifdef IGNORE_SOME_GCC_WARNINGS
18 # pragma GCC diagnostic warning "-Wstrict-prototypes"
19 #endif
20
21 #include <afs/cmd.h>
22 #include <afs/auth.h>
23 #include <afs/cellconfig.h>
24 #include <ubik.h>
25 #include <afs/afsint.h>
26 #include <afs/volser.h>
27 #include <afs/volser_prototypes.h>
28 #include <afs/afsutil.h>
29 #include <afs/bubasics.h>
30 #include <afs/budb_client.h>
31 #include <afs/budb.h>
32 #include <afs/com_err.h>
33
34 #include "bc.h"
35 #include "error_macros.h"
36 #include "bucoord_internal.h"
37 #include "bucoord_prototypes.h"
38
39 extern char *whoami;
40
41 /* -------------------------------------
42 * Globals
43 * -------------------------------------
44 */
45
46 struct udbHandleS udbHandle;
47
48 /* -------------------------------------
49 * interface routines (alphabetic)
50 * -------------------------------------
51 */
52
53 afs_int32 bcdb_AddVolume(struct budb_volumeEntry *veptr)
54 {
55 afs_int32 code;
56
57 code = ubik_BUDB_AddVolume(udbHandle.uh_client, 0, veptr);
58 return (code);
59 }
60
61 afs_int32 bcdb_AddVolumes(struct budb_volumeEntry *veptr, afs_int32 count)
62 {
63 struct budb_volumeList volumeList;
64 afs_int32 code;
65
66 volumeList.budb_volumeList_len = count;
67 volumeList.budb_volumeList_val = veptr;
68 code = ubik_BUDB_AddVolumes(udbHandle.uh_client, 0, &volumeList);
69 return (code);
70 }
71
72
73 afs_int32 bcdb_CreateDump(struct budb_dumpEntry *deptr)
74 {
75 afs_int32 code;
76
77 code = ubik_BUDB_CreateDump(udbHandle.uh_client, 0, deptr);
78 return (code);
79 }
80
81 afs_int32 bcdb_deleteDump(afs_int32 dumpID, afs_int32 fromTime, afs_int32 toTime,
82 budb_dumpsList *dumps)
83 {
84 afs_int32 code;
85 budb_dumpsList dumpsList, *dumpsPtr;
86
87 dumpsList.budb_dumpsList_len = 0;
88 dumpsList.budb_dumpsList_val = 0;
89 dumpsPtr = (dumps ? dumps : &dumpsList);
90
91 code =
92 ubik_BUDB_DeleteDump(udbHandle.uh_client, 0, dumpID, fromTime,
93 toTime, dumpsPtr);
94 if (dumpsList.budb_dumpsList_val)
95 free(dumpsList.budb_dumpsList_val);
96 return (code);
97 }
98
99 afs_int32 bcdb_listDumps (afs_int32 sflags, afs_int32 groupId,
100 afs_int32 fromTime, afs_int32 toTime,
101 budb_dumpsList *dumps, budb_dumpsList *flags)
102 {
103 afs_int32 code;
104 budb_dumpsList dumpsList, *dumpsPtr;
105 budb_dumpsList flagsList, *flagsPtr;
106
107 dumpsList.budb_dumpsList_len = 0;
108 dumpsList.budb_dumpsList_val = 0;
109 dumpsPtr = (dumps ? dumps : &dumpsList);
110
111 flagsList.budb_dumpsList_len = 0;
112 flagsList.budb_dumpsList_val = 0;
113 flagsPtr = (flags ? flags : &flagsList);
114
115 code =
116 ubik_BUDB_ListDumps(udbHandle.uh_client, 0, sflags, "", groupId,
117 fromTime, toTime, dumpsPtr, flagsPtr);
118
119 if (dumpsList.budb_dumpsList_val)
120 free(dumpsList.budb_dumpsList_val);
121 if (flagsList.budb_dumpsList_val)
122 free(flagsList.budb_dumpsList_val);
123 return (code);
124 }
125
126
127 afs_int32 bcdb_DeleteVDP(char *dumpSetName, char *dumpPath, afs_int32 dumpID)
128 {
129 afs_int32 code;
130
131 code =
132 ubik_BUDB_DeleteVDP(udbHandle.uh_client, 0, dumpSetName,
133 dumpPath, dumpID);
134 return (code);
135 }
136
137 /* bcdb_FindClone
138 * Returns the clone time of a volume by going up the parent chain.
139 * If no clone time is found, a clone time of 0 is returned, forcing
140 * a full dump.
141 * entry:
142 * dumpID - of the first dump to examine.
143 * volName - name of the volume for whom a clone time is required
144 * clonetime - ptr to vbl for returning result
145 * exit:
146 * 0 - clonetime set appropriately
147 * -1 - error occured in traversing chain, clone time set to 0.
148 * -2 - no clone times found, clone time set to 0
149 */
150
151 afs_int32 bcdb_FindClone(afs_int32 dumpID, char *volName, afs_int32 *clonetime)
152 {
153 afs_int32 code;
154 code =
155 ubik_BUDB_FindClone(udbHandle.uh_client, 0, dumpID, volName,
156 clonetime);
157 return (code);
158 }
159
160 /* bcdb_FindDump
161 * scan entire database for latest volume dump before adate. Optimize
162 * further by reading only the first line of the dump and if it is older
163 * than the oldest acceptable dump we've found so far, we don't bother
164 * scanning the dump file we've just opened
165 *
166 * Used by restore code when restoring a user requested volume(s)
167 * entry:
168 * volumeName - name of volume to match on
169 * beforeDate - look for dumps older than this date
170 * exit:
171 * deptr - desciptor of most recent dump
172 * notes:
173 * should be able to implement this in a single call rather than
174 * the current multiple bcdb_ call algorithm.
175 */
176
177 int
178 bcdb_FindDump(char *volumeName, afs_int32 beforeDate,
179 struct budb_dumpEntry *deptr)
180 {
181 afs_int32 code;
182 code =
183 ubik_BUDB_FindDump(udbHandle.uh_client, 0, volumeName,
184 beforeDate, deptr);
185 return (code);
186 }
187
188 /* bcdb_FindDumpByID
189 * find a dump by id. Currently insists on a single return value.
190 * entry:
191 * dumpID - id to lookup
192 * exit:
193 */
194 int
195 bcdb_FindDumpByID(afs_int32 dumpID, struct budb_dumpEntry *deptr)
196 {
197 afs_int32 code;
198 afs_int32 nextindex;
199 afs_int32 dbTime;
200 budb_dumpList dl;
201
202 /* initialize the dump list */
203 dl.budb_dumpList_len = 0;
204 dl.budb_dumpList_val = 0;
205
206 /* outline algorithm */
207 code = ubik_BUDB_GetDumps(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_DUMPID, "", /* no name */
208 dumpID, /* start */
209 0, /* end */
210 0, /* index */
211 &nextindex, &dbTime, &dl);
212
213 if ((code != 0)
214 || (dl.budb_dumpList_len != 1) /* single retn val expected */
215 ) {
216 /* printf("bcdb_FindDumpByID: code %d, nvalues %d\n",
217 code, dl.budb_dumpList_len); */
218 if (code == 0)
219 code = 1; /* multiple id's */
220 goto error;
221 }
222
223 memcpy(deptr, dl.budb_dumpList_val, sizeof(*deptr));
224
225 exit:
226 if (dl.budb_dumpList_val) {
227 /* free any allocated structures */
228 free(dl.budb_dumpList_val);
229 }
230 return (code);
231
232 error:
233 memset(deptr, 0, sizeof(*deptr));
234 goto exit;
235 }
236
237 /* bcdb_FindLastVolClone
238 * Returns the clone time, from the most recent dump of volName, when
239 * dumped in the volume set volSetName, with dump schedule dumpName.
240 * The clone time can be used to check if the volume has been correctly
241 * re-cloned, and also is used as the time from which to do the current
242 * incremental dump.
243 * entry:
244 * volSetName - name of volume set
245 * dumpName - full path of dump node
246 * volName - name of volume for whom a clone time is required
247 * clonetime - ptr to vbl for result
248 * exit:
249 * 0 - clonetime set appropriately
250 * notes:
251 * used only for warning generation. Suggest that this be omitted.
252 */
253
254 afs_int32
255 bcdb_FindLastVolClone(char *volSetName, char *dumpName, char *volName,
256 afs_int32 *clonetime)
257 {
258 /* server notes
259 * search by dumpName
260 * match on volumeset and dump path
261 * search for the volume name
262 */
263 return (0);
264 }
265
266 /* bcdb_FindLatestDump
267 * find the latest dump with volume set component avname and the
268 * specified dump pathname. Used to find a dump, relative to which an
269 * incremental dump can be done. Defines the parent <-> child relations
270 * for restores.
271 * entry:
272 * avname: volume set name
273 * dumpPath: full path of dump node
274 * exit:
275 * 0: adentry: dump entry structure filled in.
276 * -1: probably an internal error
277 * 2: no such entry
278 * Notes for 4.0:
279 * Need to store volumeset name in dump in order to implement this.
280 * Need new routine since params are two strings
281 */
282
283 int
284 bcdb_FindLatestDump(char *volSetName, char *dumpPath,
285 struct budb_dumpEntry *deptr)
286 {
287 afs_int32 code;
288 code =
289 ubik_BUDB_FindLatestDump(udbHandle.uh_client, 0, volSetName,
290 dumpPath, deptr);
291 return (code);
292 }
293
294
295 /* bcdb_FindTape
296 * find a tape
297 * entry:
298 * dumpid: dump id to which tape beint32s
299 * tapeName: name of tape
300 */
301
302 int
303 bcdb_FindTape(afs_int32 dumpid, char *tapeName,
304 struct budb_tapeEntry *teptr)
305 {
306 budb_tapeList tl;
307 afs_int32 next;
308 afs_int32 dbTime;
309 afs_int32 code = 0;
310
311 memset(teptr, 0, sizeof(*teptr));
312 tl.budb_tapeList_len = 0;
313 tl.budb_tapeList_val = 0;
314
315 code =
316 ubik_BUDB_GetTapes(udbHandle.uh_client, 0, BUDB_MAJORVERSION,
317 BUDB_OP_TAPENAME | BUDB_OP_DUMPID, tapeName, dumpid, 0, 0,
318 &next, &dbTime, &tl);
319
320 if (code)
321 ERROR(code);
322
323 if (tl.budb_tapeList_len != 1)
324 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
325
326 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
327
328 error_exit:
329 if (tl.budb_tapeList_val)
330 free(tl.budb_tapeList_val);
331 return (code);
332 }
333
334 int
335 bcdb_FindTapeSeq(afs_int32 dumpid, afs_int32 tapeSeq,
336 struct budb_tapeEntry *teptr)
337 {
338 budb_tapeList tl;
339 afs_int32 next;
340 afs_int32 dbTime;
341 afs_int32 code = 0;
342
343 memset(teptr, 0, sizeof(*teptr));
344 tl.budb_tapeList_len = 0;
345 tl.budb_tapeList_val = 0;
346
347 code =
348 ubik_BUDB_GetTapes(udbHandle.uh_client, 0, BUDB_MAJORVERSION,
349 BUDB_OP_TAPESEQ | BUDB_OP_DUMPID, "", dumpid, tapeSeq, 0,
350 &next, &dbTime, &tl);
351 if (code)
352 ERROR(code);
353
354 if (tl.budb_tapeList_len != 1)
355 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
356
357 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
358
359 error_exit:
360 if (tl.budb_tapeList_val)
361 free(tl.budb_tapeList_val);
362 return (code);
363 }
364
365 /* bcdb_FindVolumes
366 * notes:
367 * - this is part of dblookup. The existing semantics will not work since
368 * they do lookups based on dump id.
369 * - in the restore code, it uses this to extract information about
370 * the volume. Need current semantics. Could filter the output, selecting
371 * on the dumpid.
372 * - Suggest that the lookup be based on volume name only, with optional
373 * match on backup, and readonly volumes.
374 * - Further, need to check if the volume structure returns enough
375 * information
376 */
377
378 afs_int32
379 bcdb_FindVolumes(afs_int32 dumpID, char *volumeName,
380 struct budb_volumeEntry *returnArray,
381 afs_int32 last, afs_int32 *next, afs_int32 maxa,
382 afs_int32 *nEntries)
383 {
384 budb_volumeList vl;
385 afs_int32 dbTime;
386 afs_int32 code;
387
388 vl.budb_volumeList_len = maxa;
389 vl.budb_volumeList_val = returnArray;
390
391 /* outline algorithm */
392 code = ubik_BUDB_GetVolumes(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME | BUDB_OP_DUMPID, volumeName, /* name */
393 dumpID, /* start */
394 0, /* end */
395 last, /* index */
396 next, /* nextindex */
397 &dbTime, &vl);
398
399 *nEntries = vl.budb_volumeList_len;
400 return (code);
401 }
402
403 int
404 bcdb_FinishDump(struct budb_dumpEntry *deptr)
405 {
406 afs_int32 code;
407 code = ubik_BUDB_FinishDump(udbHandle.uh_client, 0, deptr);
408 return (code);
409 }
410
411 int
412 bcdb_FinishTape(struct budb_tapeEntry *teptr)
413 {
414 afs_int32 code;
415 code = ubik_BUDB_FinishTape(udbHandle.uh_client, 0, teptr);
416 return (code);
417
418 }
419
420 /* bcdb_LookupVolumes
421 */
422
423 afs_int32
424 bcdb_LookupVolume(char *volumeName, struct budb_volumeEntry *returnArray,
425 afs_int32 last, afs_int32 *next, afs_int32 maxa,
426 afs_int32 *nEntries)
427 {
428 budb_volumeList vl;
429 afs_int32 dbTime;
430 afs_int32 code;
431
432 vl.budb_volumeList_len = maxa;
433 vl.budb_volumeList_val = returnArray;
434
435 /* outline algorithm */
436 code = ubik_BUDB_GetVolumes(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME, volumeName, /* name */
437 0, /* start */
438 0, /* end */
439 last, /* index */
440 next, /* nextindex */
441 &dbTime, &vl);
442 if (code) {
443 *nEntries = 0;
444 return (code);
445 }
446 *nEntries = vl.budb_volumeList_len;
447 return (0);
448 }
449
450 int
451 bcdb_UseTape(struct budb_tapeEntry *teptr, afs_int32 *newFlag)
452 {
453 afs_int32 code;
454 code = ubik_BUDB_UseTape(udbHandle.uh_client, 0, teptr, newFlag);
455 return (code);
456 }
457
458
459 /* ---- text configuration handling routines ----
460 *
461 * notes:
462 * The caller should pass in/out a fid for an unlinked, open file to prevent
463 * tampering with the files contents;
464 */
465
466 /* bcdb_GetTextFile
467 * extract the specified textType and put it in a temporary, local
468 * file.
469 * entry:
470 * ctPtr - ptr to client structure with all the required information
471 */
472
473 int
474 bcdb_GetTextFile(udbClientTextP ctPtr)
475 {
476 afs_int32 bufferSize;
477 afs_int32 offset, nextOffset;
478 charListT charList;
479 afs_int32 code = 0;
480
481 /* Initialize charlistT_val. We try to deallocate this structure based on
482 * this */
483 memset((void *)&charList, 0, sizeof(charList));
484
485 /* check params and cleanup any previous state */
486 if (ctPtr->lockHandle == 0)
487 ERROR(BUDB_INTERNALERROR);
488
489 if (ctPtr->textStream == NULL) /* Should have an open stream */
490 ERROR(BUDB_INTERNALERROR);
491
492 /* allocate a buffer */
493 bufferSize = 1024;
494 charList.charListT_val = malloc(bufferSize);
495 if (charList.charListT_val == 0)
496 ERROR(BUDB_INTERNALERROR);
497 charList.charListT_len = bufferSize;
498
499 nextOffset = 0;
500 ctPtr->textSize = 0;
501 while (nextOffset != -1) {
502 offset = nextOffset;
503 charList.charListT_len = bufferSize;
504 code =
505 ubik_BUDB_GetText(udbHandle.uh_client, 0, ctPtr->lockHandle,
506 ctPtr->textType, bufferSize, offset, &nextOffset,
507 &charList);
508
509 if (code)
510 ERROR(code);
511
512 code =
513 fwrite(charList.charListT_val, sizeof(char),
514 charList.charListT_len, ctPtr->textStream);
515 if (ferror(ctPtr->textStream))
516 ERROR(BUDB_INTERNALERROR);
517
518 ctPtr->textSize += charList.charListT_len;
519 }
520
521 /* get text version */
522 code =
523 ubik_BUDB_GetTextVersion(udbHandle.uh_client, 0,
524 ctPtr->textType, &ctPtr->textVersion);
525 if (code)
526 ERROR(code);
527
528 normal_exit:
529 fflush(ctPtr->textStream); /* debug */
530
531 /* exit, leaving the configuration text file open */
532 if (charList.charListT_val)
533 free(charList.charListT_val);
534 return (code);
535
536 error_exit:
537 if (ctPtr->textStream != NULL) {
538 fclose(ctPtr->textStream);
539 ctPtr->textStream = NULL;
540 }
541 goto normal_exit;
542 }
543
544
545 /* bcdb_SaveTextFile
546 * save the text file in ubik database
547 * entry:
548 * textType - identifies type of configuration file
549 * filename - where to get the text from
550 */
551
552 int
553 bcdb_SaveTextFile(udbClientTextP ctPtr)
554 {
555 afs_int32 bufferSize;
556 afs_int32 offset, chunkSize, fileSize;
557 charListT charList;
558 afs_int32 code = 0;
559
560 /* allocate a buffer */
561 bufferSize = 1024;
562 charList.charListT_val = malloc(bufferSize);
563 if (charList.charListT_val == 0)
564 ERROR(BUDB_INTERNALERROR);
565 charList.charListT_len = bufferSize;
566
567 if (ctPtr->textStream == NULL)
568 ERROR(BUDB_INTERNALERROR);
569 rewind(ctPtr->textStream);
570
571 fileSize = (afs_int32) filesize(ctPtr->textStream);
572
573 afs_dprintf(("filesize is %d\n", fileSize));
574
575 rewind(ctPtr->textStream);
576
577 /* special case empty files */
578 if (fileSize == 0) {
579 charList.charListT_len = 0;
580 code =
581 ubik_BUDB_SaveText(udbHandle.uh_client, 0,
582 ctPtr->lockHandle, ctPtr->textType, 0,
583 BUDB_TEXT_COMPLETE, &charList);
584 goto error_exit;
585 }
586
587 offset = 0;
588 while (fileSize != 0) {
589 chunkSize = min(fileSize, bufferSize);
590 code =
591 fread(charList.charListT_val, sizeof(char), chunkSize,
592 ctPtr->textStream);
593
594 if (code != chunkSize)
595 printf("code = %d\n", code);
596 if (ferror(ctPtr->textStream))
597 ERROR(BUDB_INTERNALERROR);
598
599 charList.charListT_len = chunkSize;
600 code =
601 ubik_BUDB_SaveText(udbHandle.uh_client, 0,
602 ctPtr->lockHandle, ctPtr->textType, offset,
603 (chunkSize == fileSize) ? BUDB_TEXT_COMPLETE : 0,
604 &charList);
605 if (code)
606 ERROR(code);
607
608 fileSize -= chunkSize;
609 offset += chunkSize;
610 }
611
612 error_exit:
613 /* if ( ctPtr->textStream >= 0 )
614 * close(ctPtr->textStream); */
615 if (charList.charListT_val)
616 free(charList.charListT_val);
617 return (code);
618 }
619
620 int
621 bcdb_FindLastTape(afs_int32 dumpID, struct budb_dumpEntry *dumpEntry,
622 struct budb_tapeEntry *tapeEntry,
623 struct budb_volumeEntry *volEntry)
624 {
625 return (ubik_BUDB_FindLastTape(udbHandle.uh_client, 0, dumpID, dumpEntry,
626 tapeEntry, volEntry));
627 }
628
629 int
630 bcdb_MakeDumpAppended(afs_int32 appendedDumpID, afs_int32 initialDumpID,
631 afs_int32 startTapeSeq)
632 {
633 return (ubik_BUDB_MakeDumpAppended(udbHandle.uh_client, 0, appendedDumpID,
634 initialDumpID, startTapeSeq));
635 }
636
637
638 /* -------------------------------------
639 * misc. support routines
640 * -------------------------------------
641 */
642
643 afs_int32
644 filesize(FILE *stream)
645 {
646 afs_int32 offset;
647 afs_int32 size;
648
649 offset = ftell(stream);
650 fseek(stream, (afs_int32) 0, 2); /* end of file */
651 size = ftell(stream);
652 fseek(stream, offset, 0);
653 return (size);
654 }
655
656
657 /* ------------------------------------
658 * misc. support routines - general text management
659 * ------------------------------------
660 */
661
662
663 /* bc_LockText
664 * locks the text described by the ctPtr
665 * entry:
666 * ctptr - client text ptr
667 * exit:
668 * 0 - success
669 * n - fail
670 */
671
672 int
673 bc_LockText(udbClientTextP ctPtr)
674 {
675 afs_int32 code;
676 afs_int32 timeout, j = 0;
677
678 if (ctPtr->lockHandle != 0)
679 return (1); /* already locked */
680
681 timeout =
682 ((ctPtr->textSize == 0) ? 30 : ((ctPtr->textSize / 50000) + 10));
683
684 while (1) {
685 code =
686 ubik_BUDB_GetLock(udbHandle.uh_client, 0,
687 udbHandle.uh_instanceId, ctPtr->textType, timeout,
688 &ctPtr->lockHandle);
689 if ((code != BUDB_LOCKED) && (code != BUDB_SELFLOCKED)) {
690 break;
691 }
692
693 /* Mention something every 30 seconds */
694 if (++j >= 30) {
695 afs_com_err(whoami, code,
696 "; Waiting for db configuration text unlock");
697 j = 0;
698 }
699 #ifdef AFS_PTHREAD_ENV
700 sleep(1);
701 #else
702 IOMGR_Sleep(1);
703 #endif
704 }
705
706 /* cleanup */
707 if (code)
708 ctPtr->lockHandle = 0;
709 return (code);
710 }
711
712 /* bc_UnlockText
713 * unlocks the text described by the ctPtr
714 * entry:
715 * ctptr - client text ptr
716 * exit:
717 * 0 - success
718 * n - fail
719 */
720
721 int
722 bc_UnlockText(udbClientTextP ctPtr)
723 {
724 afs_int32 code = 0;
725
726 if (ctPtr->lockHandle == 0)
727 return (0);
728
729 code =
730 ubik_BUDB_FreeLock(udbHandle.uh_client, 0, ctPtr->lockHandle);
731 ctPtr->lockHandle = 0;
732
733 /* Don't try to analyse the error. Let the lock timeout */
734 return (code);
735 }
736
737 /* bc_CheckTextVersion
738 * exit:
739 * 0 - version # ok
740 * n - out of date or error
741 */
742
743 int
744 bc_CheckTextVersion(udbClientTextP ctPtr)
745 {
746 afs_int32 code;
747 afs_uint32 tversion;
748
749 if (ctPtr->textVersion == -1)
750 return (BC_VERSIONMISMATCH);
751
752 code =
753 ubik_BUDB_GetTextVersion(udbHandle.uh_client, 0,
754 ctPtr->textType, &tversion);
755 if (code)
756 return (code);
757 if (tversion != ctPtr->textVersion)
758 return (BC_VERSIONMISMATCH);
759 return (0);
760 }
761
762 /* -------------------------------------
763 * initialization routines
764 * -------------------------------------
765 */
766
767 static afsconf_secflags
768 parseSecFlags(int noAuthFlag, int localauth, const char **confdir) {
769 afsconf_secflags secFlags;
770
771 secFlags = 0;
772 if (noAuthFlag)
773 secFlags |= AFSCONF_SECOPTS_NOAUTH;
774
775 if (localauth) {
776 secFlags |= AFSCONF_SECOPTS_LOCALAUTH;
777 *confdir = AFSDIR_SERVER_ETC_DIRPATH;
778 } else {
779 *confdir = AFSDIR_CLIENT_ETC_DIRPATH;
780 }
781 return secFlags;
782 }
783
784 /* vldbClientInit
785 * Initialize a client for the vl ubik database.
786 */
787 int
788 vldbClientInit(int noAuthFlag, int localauth, char *cellName,
789 struct ubik_client **cstruct,
790 time_t *expires)
791 {
792 afs_int32 code = 0;
793 struct afsconf_dir *acdir;
794 struct rx_securityClass *sc;
795 afs_int32 i, scIndex = RX_SECIDX_NULL;
796 struct afsconf_cell info;
797 struct rx_connection *serverconns[VLDB_MAXSERVERS];
798 afsconf_secflags secFlags;
799 const char *confdir;
800
801 secFlags = parseSecFlags(noAuthFlag, localauth, &confdir);
802 secFlags |= AFSCONF_SECOPTS_FALLBACK_NULL;
803
804 /* This just preserves old behaviour of using the default cell when
805 * passed an empty string */
806 if (cellName && cellName[0] == '\0')
807 cellName = NULL;
808
809 /* Find out about the given cell */
810 acdir = afsconf_Open(confdir);
811 if (!acdir) {
812 afs_com_err(whoami, 0, "Can't open configuration directory '%s'", confdir);
813 ERROR(BC_NOCELLCONFIG);
814 }
815
816 code = afsconf_GetCellInfo(acdir, cellName, AFSCONF_VLDBSERVICE, &info);
817 if (code) {
818 afs_com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
819 cellName, confdir, AFSDIR_CELLSERVDB_FILE);
820 ERROR(BC_NOCELLCONFIG);
821 }
822
823 code = afsconf_PickClientSecObj(acdir, secFlags, &info, cellName,
824 &sc, &scIndex, expires);
825 if (code) {
826 afs_com_err(whoami, code, "(configuring connection security)");
827 ERROR(BC_NOCELLCONFIG);
828 }
829 if (scIndex == RX_SECIDX_NULL && !noAuthFlag)
830 afs_com_err(whoami, 0, "Can't get tokens - running unauthenticated");
831
832 /* tell UV module about default authentication */
833 UV_SetSecurity(sc, scIndex);
834
835 if (info.numServers > VLDB_MAXSERVERS) {
836 afs_com_err(whoami, 0,
837 "Warning: %d VLDB servers exist for cell '%s', can only remember the first %d",
838 info.numServers, cellName, VLDB_MAXSERVERS);
839 info.numServers = VLDB_MAXSERVERS;
840 }
841
842 for (i = 0; i < info.numServers; i++)
843 serverconns[i] =
844 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
845 info.hostAddr[i].sin_port, USER_SERVICE_ID, sc,
846 scIndex);
847 serverconns[i] = 0;
848
849 *cstruct = 0;
850 code = ubik_ClientInit(serverconns, cstruct);
851 if (code) {
852 afs_com_err(whoami, code, "; Can't initialize ubik connection to vldb");
853 ERROR(code);
854 }
855
856 error_exit:
857 if (acdir)
858 afsconf_Close(acdir);
859 return (code);
860 }
861
862 /* udbClientInit
863 * initialize a client for the backup systems ubik database.
864 */
865
866 afs_int32
867 udbClientInit(int noAuthFlag, int localauth, char *cellName)
868 {
869 struct afsconf_cell info;
870 struct afsconf_dir *acdir;
871 const char *confdir;
872 int i;
873 afs_int32 secFlags;
874 afs_int32 code = 0;
875
876 secFlags = parseSecFlags(noAuthFlag, localauth, &confdir);
877 secFlags |= AFSCONF_SECOPTS_FALLBACK_NULL;
878
879 if (cellName && cellName[0] == '\0')
880 cellName = NULL;
881
882 acdir = afsconf_Open(confdir);
883 if (!acdir) {
884 afs_com_err(whoami, 0, "Can't open configuration directory '%s'",
885 confdir);
886 ERROR(BC_NOCELLCONFIG);
887 }
888
889 code = afsconf_GetCellInfo(acdir, cellName, 0, &info);
890 if (code) {
891 afs_com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
892 cellName, confdir, AFSDIR_CELLSERVDB_FILE);
893 ERROR(BC_NOCELLCONFIG);
894 }
895
896 code = afsconf_PickClientSecObj(acdir, secFlags, &info, cellName,
897 &udbHandle.uh_secobj,
898 &udbHandle.uh_scIndex, NULL);
899 if (code) {
900 afs_com_err(whoami, code, "(configuring connection security)");
901 ERROR(BC_NOCELLCONFIG);
902 }
903 if (udbHandle.uh_scIndex == RX_SECIDX_NULL && !noAuthFlag)
904 afs_com_err(whoami, 0, "Can't get tokens - running unauthenticated");
905
906 /* We have to have space for the trailing NULL that terminates the server
907 * conneciton array - so we can only store MAXSERVERS-1 real elements in
908 * that array.
909 */
910 if (info.numServers >= MAXSERVERS) {
911 afs_com_err(whoami, 0,
912 "Warning: %d BDB servers exist for cell '%s', can only remember the first %d",
913 info.numServers, cellName, MAXSERVERS-1);
914 info.numServers = MAXSERVERS - 1;
915 }
916
917 /* establish connections to the servers. Check for failed connections? */
918 for (i = 0; i < info.numServers; i++) {
919 udbHandle.uh_serverConn[i] =
920 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
921 htons(AFSCONF_BUDBPORT), BUDB_SERVICE,
922 udbHandle.uh_secobj, udbHandle.uh_scIndex);
923 }
924 udbHandle.uh_serverConn[i] = 0;
925
926 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
927 if (code) {
928 afs_com_err(whoami, code,
929 "; Can't initialize ubik connection to backup database");
930 ERROR(code);
931 }
932
933 /* Try to quickly find a good site by setting deadtime low */
934 for (i = 0; i < info.numServers; i++)
935 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 1);
936 code =
937 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
938 &udbHandle.uh_instanceId);
939
940 /* Reset dead time back up to default */
941 for (i = 0; i < info.numServers; i++)
942 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 60);
943
944 /* If did not find a site on first quick pass, try again */
945 if (code == -1)
946 code =
947 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
948 &udbHandle.uh_instanceId);
949 if (code) {
950 afs_com_err(whoami, code, "; Can't access backup database");
951 ERROR(code);
952 }
953
954 error_exit:
955 if (acdir)
956 afsconf_Close(acdir);
957 return (code);
958 }
959
960 /* -------------------------------------
961 * specialized ubik support
962 * -------------------------------------
963 */
964
965 #include <rx/xdr.h>
966 #include <rx/rx.h>
967 #include <lock.h>
968
969 /* notes
970 * 1) first call with SINGLESERVER set, record the server to be used.
971 * 2) subsequent calls use that server. If a failure is encountered,
972 * the state is cleaned up and the error returned back to the caller.
973 * 3) upon completion, the user must make a dummy call with
974 * END_SINGLESERVER set, to clean up state.
975 * 4) if the vanilla ubik_Call is ever modified, the END_SINGLESERVER
976 * flag can be discarded. The first call without SINGLESERVER set
977 * can clean up the state.
978 */
979
980 struct ubikCallState {
981 afs_int32 ucs_flags; /* state flags */
982 afs_int32 ucs_selectedServer; /* which server selected */
983 };
984
985 static struct ubikCallState uServer;
986
987 /* ubik_Call_SingleServer
988 * variant of ubik_Call. This is used by the backup system to initiate
989 * a series of calls to a single ubik server. The first call sets up
990 * process state (not recorded in ubik) that requires all further calls
991 * of that group to be made to the same server process.
992 *
993 * call this instead of stub and we'll guarantee to find a host that's up.
994 * in the future, we should also put in a protocol to find the sync site
995 */
996
997 afs_int32
998 ubik_Call_SingleServer(int (*aproc) (), struct ubik_client *aclient,
999 afs_int32 aflags, char *p1, char *p2, char *p3,
1000 char *p4, char *p5, char *p6, char *p7, char *p8,
1001 char *p9, char *p10, char *p11, char *p12, char *p13,
1002 char *p14, char *p15, char *p16)
1003 {
1004 afs_int32 code;
1005 afs_int32 someCode, newHost, thisHost;
1006 afs_int32 i;
1007 afs_int32 count;
1008 int chaseCount;
1009 int pass;
1010 struct rx_connection *tc;
1011 struct rx_peer *rxp;
1012
1013 if ((aflags & (UF_SINGLESERVER | UF_END_SINGLESERVER)) != 0) {
1014 if (((aflags & UF_SINGLESERVER) != 0)
1015 && ((uServer.ucs_flags & UF_SINGLESERVER) != 0)
1016 ) {
1017
1018 /* have a selected server */
1019 tc = aclient->conns[uServer.ucs_selectedServer];
1020
1021 code =
1022 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11,
1023 p12, p13, p14, p15, p16);
1024 if (code) {
1025 /* error. Clean up single server state */
1026 memset(&uServer, 0, sizeof(uServer));
1027 }
1028 return (code);
1029 } else if ((aflags & UF_END_SINGLESERVER) != 0) {
1030 memset(&uServer, 0, sizeof(uServer));
1031 return (0);
1032 }
1033 }
1034
1035 someCode = UNOSERVERS;
1036 chaseCount = 0;
1037 pass = 0;
1038 count = 0;
1039 while (1) { /*w */
1040
1041 /* tc is the next conn to try */
1042 tc = aclient->conns[count];
1043 if (tc == 0) {
1044 if (pass == 0) {
1045 pass = 1; /* in pass 1, we look at down hosts, too */
1046 count = 0;
1047 continue;
1048 } else
1049 break; /* nothing left to try */
1050 }
1051 if (pass == 0 && (aclient->states[count] & CFLastFailed)) {
1052 count++;
1053 continue; /* this guy's down, try someone else first */
1054 }
1055
1056 code =
1057 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12,
1058 p13, p14, p15, p16);
1059
1060 /* note that getting a UNOTSYNC error code back does *not* guarantee
1061 * that there is a sync site yet elected. However, if there is a
1062 * sync site out there somewhere, and you're trying an operation that
1063 * requires a sync site, ubik will return UNOTSYNC, indicating the
1064 * operation won't work until you find a sync site
1065 */
1066 if (code == UNOTSYNC) { /*ns */
1067 /* means that this requires a sync site to work */
1068 someCode = code; /* remember an error, if this fails */
1069
1070 /* now see if we can find the sync site host */
1071 code = VOTE_GetSyncSite(tc, &newHost);
1072 if (code == 0 && newHost != 0) {
1073 newHost = htonl(newHost); /* convert back to network order */
1074
1075 /* position count at the appropriate slot in the client
1076 * structure and retry. If we can't find in slot, we'll just
1077 * continue through the whole list
1078 */
1079 for (i = 0; i < MAXSERVERS; i++) { /*f */
1080 rxp = rx_PeerOf(aclient->conns[i]);
1081 if (!(thisHost = rx_HostOf(rxp))) {
1082 count++; /* host not found, try the next dude */
1083 break;
1084 }
1085 if (thisHost == newHost) {
1086 /* avoid asking in a loop */
1087 if (chaseCount++ > 2)
1088 break;
1089 count = i; /* we were told to use this one */
1090 break;
1091 }
1092 } /*f */
1093 } else
1094 count++; /* not directed, keep looking for a sync site */
1095 continue;
1096 } /*ns */
1097 else if (code == UNOQUORUM) { /* this guy is still recovering */
1098 someCode = code;
1099 count++;
1100 continue;
1101 } else if (code < 0) { /* network errors */
1102 someCode = code;
1103 aclient->states[count] |= CFLastFailed;
1104 count++;
1105 continue;
1106 } else {
1107 /* ok, operation worked */
1108 aclient->states[count] &= ~CFLastFailed;
1109 /* either misc ubik code, or misc application code (incl success)
1110 */
1111
1112 /* if the call succeeded, setup connection state for subsequent
1113 * calls
1114 */
1115 if ((code == 0)
1116 && ((aflags & UF_SINGLESERVER) != 0)
1117 ) {
1118 /* need to save state */
1119 uServer.ucs_flags = UF_SINGLESERVER;
1120 uServer.ucs_selectedServer = count;
1121 }
1122
1123 return code;
1124 }
1125 } /*w */
1126 return someCode;
1127 }
1128
1129
1130 /* -------------------------------------
1131 * debug and test routines
1132 * -------------------------------------
1133 */
1134
1135 /* udbLocalInit
1136 * For testing only. Open a connect to the database server running on
1137 * the local host
1138 * exit:
1139 * 0 - ubik connection established in the global udbHandle structure
1140 * n - error.
1141 */
1142
1143 int
1144 udbLocalInit(void)
1145 {
1146 afs_uint32 serverList[MAXSERVERS];
1147 char hostname[256];
1148 char *args[3];
1149 int i;
1150 afs_int32 code;
1151
1152 /* get our host name */
1153 gethostname(hostname, sizeof(hostname));
1154 /* strcpy(hostname, "hops"); */
1155
1156 args[0] = "";
1157 args[1] = "-servers";
1158 args[2] = hostname;
1159
1160 code = ubik_ParseClientList(3, args, serverList);
1161 if (code) {
1162 afs_com_err(whoami, code, "; udbLocalInit: parsing ubik server list");
1163 return (-1);
1164 }
1165
1166 udbHandle.uh_scIndex = RX_SECIDX_NULL;
1167 udbHandle.uh_secobj = (struct rx_securityClass *)
1168 rxnull_NewClientSecurityObject();
1169
1170 for (i = 0; serverList[i] != 0; i++) {
1171 udbHandle.uh_serverConn[i] =
1172 rx_NewConnection(serverList[i], htons(AFSCONF_BUDBPORT),
1173 BUDB_SERVICE, udbHandle.uh_secobj,
1174 udbHandle.uh_scIndex);
1175 if (udbHandle.uh_serverConn[i] == 0) {
1176 afs_com_err(whoami, 0, "connection %d failed", i);
1177 continue;
1178 }
1179 }
1180 udbHandle.uh_serverConn[i] = 0;
1181 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1182 if (code) {
1183 afs_com_err(whoami, code, "; in ubik_ClientInit");
1184 return (code);
1185 }
1186
1187 code =
1188 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
1189 &udbHandle.uh_instanceId);
1190 if (code) {
1191 afs_com_err(whoami, code, "; Can't estblish instance Id");
1192 return (code);
1193 }
1194
1195 /* abort: */
1196 return (0);
1197 }
1198
1199 /* bc_openTextFile - This function opens a temp file to read in the
1200 * config text recd from the bu server. On Unix, an unlink() is done on
1201 * the file as soon as it is opened, so when the program exits, the file will
1202 * be removed automatically, while being invisible while in use.
1203 * On NT, however, the file must be explicitly deleted after use with an unlink()
1204 * Input:
1205 * Pointer to a udhClientTextP struct. The open stream ptr is stored in
1206 * the udbClientTextP.textStream member.
1207 * Output: The temp file name is returned in tmpFileName. This should be used
1208 * to delete the file when done with it.
1209 * Return Values:
1210 * !0: error code
1211 * 0: Success.
1212 */
1213 int
1214 bc_openTextFile(udbClientTextP ctPtr, char *tmpFileName)
1215 {
1216 int code = 0;
1217 int fd;
1218
1219 if (ctPtr->textStream != NULL) {
1220 fclose(ctPtr->textStream);
1221 ctPtr->textStream = NULL;
1222 }
1223
1224 sprintf(tmpFileName, "%s/bu_XXXXXX", gettmpdir());
1225 fd = mkstemp(tmpFileName);
1226 if (fd == -1)
1227 ERROR(BUDB_INTERNALERROR);
1228 ctPtr->textStream = fdopen(fd, "w+");
1229 if (ctPtr->textStream == NULL)
1230 ERROR(BUDB_INTERNALERROR);
1231
1232 #ifndef AFS_NT40_ENV /* This can't be done on NT */
1233 /* make the file invisible to others */
1234 code = unlink(tmpFileName);
1235 if (code)
1236 ERROR(errno);
1237 #endif
1238
1239 afs_dprintf(("file is %s\n", tmpFileName));
1240
1241 normal_exit:
1242 return code;
1243
1244 error_exit:
1245 if (ctPtr->textStream != NULL) {
1246 fclose(ctPtr->textStream);
1247 ctPtr->textStream = NULL;
1248 }
1249 goto normal_exit;
1250 }
1251
1252
1253 /* bc_closeTextFile: This function closes any actual temp files associated with
1254 * a udbClientText structure.
1255 * Input: ctPtr->textStream - stream to close
1256 * tmpFileName - temp file name to delete
1257 * RetVal:
1258 * 0 - Success
1259 * !0 - error code
1260 */
1261 int
1262 bc_closeTextFile(udbClientTextP ctPtr, char *tmpFileName)
1263 {
1264 int code = 0;
1265
1266 if (ctPtr->textStream)
1267 fclose(ctPtr->textStream);
1268
1269 if (*tmpFileName) { /* we have a valid name */
1270 code = unlink(tmpFileName);
1271 if (code < 0)
1272 code = errno;
1273 }
1274 return code;
1275 }