LINUX: afs_create infinite fetchStatus loop
[pkg-k5-afs_openafs.git] / src / bucoord / ubik_db_if.c
blob8978e4b786cf7ea197ac1f65fafa7b8d43200e05
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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 */
10 /* Interface and supporting routines for the backup system's ubik database */
12 #include <afsconfig.h>
13 #include <afs/stds.h>
15 #include <roken.h>
17 #ifdef IGNORE_SOME_GCC_WARNINGS
18 # pragma GCC diagnostic warning "-Wstrict-prototypes"
19 #endif
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>
34 #include "bc.h"
35 #include "error_macros.h"
36 #include "bucoord_internal.h"
37 #include "bucoord_prototypes.h"
39 extern char *whoami;
41 /* -------------------------------------
42 * Globals
43 * -------------------------------------
46 struct udbHandleS udbHandle;
48 /* -------------------------------------
49 * interface routines (alphabetic)
50 * -------------------------------------
53 afs_int32 bcdb_AddVolume(struct budb_volumeEntry *veptr)
55 afs_int32 code;
57 code = ubik_BUDB_AddVolume(udbHandle.uh_client, 0, veptr);
58 return (code);
61 afs_int32 bcdb_AddVolumes(struct budb_volumeEntry *veptr, afs_int32 count)
63 struct budb_volumeList volumeList;
64 afs_int32 code;
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);
73 afs_int32 bcdb_CreateDump(struct budb_dumpEntry *deptr)
75 afs_int32 code;
77 code = ubik_BUDB_CreateDump(udbHandle.uh_client, 0, deptr);
78 return (code);
81 afs_int32 bcdb_deleteDump(afs_int32 dumpID, afs_int32 fromTime, afs_int32 toTime,
82 budb_dumpsList *dumps)
84 afs_int32 code;
85 budb_dumpsList dumpsList, *dumpsPtr;
87 dumpsList.budb_dumpsList_len = 0;
88 dumpsList.budb_dumpsList_val = 0;
89 dumpsPtr = (dumps ? dumps : &dumpsList);
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);
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)
103 afs_int32 code;
104 budb_dumpsList dumpsList, *dumpsPtr;
105 budb_dumpsList flagsList, *flagsPtr;
107 dumpsList.budb_dumpsList_len = 0;
108 dumpsList.budb_dumpsList_val = 0;
109 dumpsPtr = (dumps ? dumps : &dumpsList);
111 flagsList.budb_dumpsList_len = 0;
112 flagsList.budb_dumpsList_val = 0;
113 flagsPtr = (flags ? flags : &flagsList);
115 code =
116 ubik_BUDB_ListDumps(udbHandle.uh_client, 0, sflags, "", groupId,
117 fromTime, toTime, dumpsPtr, flagsPtr);
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);
127 afs_int32 bcdb_DeleteVDP(char *dumpSetName, char *dumpPath, afs_int32 dumpID)
129 afs_int32 code;
131 code =
132 ubik_BUDB_DeleteVDP(udbHandle.uh_client, 0, dumpSetName,
133 dumpPath, dumpID);
134 return (code);
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
151 afs_int32 bcdb_FindClone(afs_int32 dumpID, char *volName, afs_int32 *clonetime)
153 afs_int32 code;
154 code =
155 ubik_BUDB_FindClone(udbHandle.uh_client, 0, dumpID, volName,
156 clonetime);
157 return (code);
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
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.
178 bcdb_FindDump(char *volumeName, afs_int32 beforeDate,
179 struct budb_dumpEntry *deptr)
181 afs_int32 code;
182 code =
183 ubik_BUDB_FindDump(udbHandle.uh_client, 0, volumeName,
184 beforeDate, deptr);
185 return (code);
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:
195 bcdb_FindDumpByID(afs_int32 dumpID, struct budb_dumpEntry *deptr)
197 afs_int32 code;
198 afs_int32 nextindex;
199 afs_int32 dbTime;
200 budb_dumpList dl;
202 /* initialize the dump list */
203 dl.budb_dumpList_len = 0;
204 dl.budb_dumpList_val = 0;
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);
213 if ((code != 0)
214 || (dl.budb_dumpList_len != 1) /* single retn val expected */
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;
223 memcpy(deptr, dl.budb_dumpList_val, sizeof(*deptr));
225 exit:
226 if (dl.budb_dumpList_val) {
227 /* free any allocated structures */
228 free(dl.budb_dumpList_val);
230 return (code);
232 error:
233 memset(deptr, 0, sizeof(*deptr));
234 goto exit;
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.
254 afs_int32
255 bcdb_FindLastVolClone(char *volSetName, char *dumpName, char *volName,
256 afs_int32 *clonetime)
258 /* server notes
259 * search by dumpName
260 * match on volumeset and dump path
261 * search for the volume name
263 return (0);
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
284 bcdb_FindLatestDump(char *volSetName, char *dumpPath,
285 struct budb_dumpEntry *deptr)
287 afs_int32 code;
288 code =
289 ubik_BUDB_FindLatestDump(udbHandle.uh_client, 0, volSetName,
290 dumpPath, deptr);
291 return (code);
295 /* bcdb_FindTape
296 * find a tape
297 * entry:
298 * dumpid: dump id to which tape beint32s
299 * tapeName: name of tape
303 bcdb_FindTape(afs_int32 dumpid, char *tapeName,
304 struct budb_tapeEntry *teptr)
306 budb_tapeList tl;
307 afs_int32 next;
308 afs_int32 dbTime;
309 afs_int32 code = 0;
311 memset(teptr, 0, sizeof(*teptr));
312 tl.budb_tapeList_len = 0;
313 tl.budb_tapeList_val = 0;
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);
320 if (code)
321 ERROR(code);
323 if (tl.budb_tapeList_len != 1)
324 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
326 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
328 error_exit:
329 if (tl.budb_tapeList_val)
330 free(tl.budb_tapeList_val);
331 return (code);
335 bcdb_FindTapeSeq(afs_int32 dumpid, afs_int32 tapeSeq,
336 struct budb_tapeEntry *teptr)
338 budb_tapeList tl;
339 afs_int32 next;
340 afs_int32 dbTime;
341 afs_int32 code = 0;
343 memset(teptr, 0, sizeof(*teptr));
344 tl.budb_tapeList_len = 0;
345 tl.budb_tapeList_val = 0;
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);
354 if (tl.budb_tapeList_len != 1)
355 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
357 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
359 error_exit:
360 if (tl.budb_tapeList_val)
361 free(tl.budb_tapeList_val);
362 return (code);
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
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)
384 budb_volumeList vl;
385 afs_int32 dbTime;
386 afs_int32 code;
388 vl.budb_volumeList_len = maxa;
389 vl.budb_volumeList_val = returnArray;
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);
399 *nEntries = vl.budb_volumeList_len;
400 return (code);
404 bcdb_FinishDump(struct budb_dumpEntry *deptr)
406 afs_int32 code;
407 code = ubik_BUDB_FinishDump(udbHandle.uh_client, 0, deptr);
408 return (code);
412 bcdb_FinishTape(struct budb_tapeEntry *teptr)
414 afs_int32 code;
415 code = ubik_BUDB_FinishTape(udbHandle.uh_client, 0, teptr);
416 return (code);
420 /* bcdb_LookupVolumes
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)
428 budb_volumeList vl;
429 afs_int32 dbTime;
430 afs_int32 code;
432 vl.budb_volumeList_len = maxa;
433 vl.budb_volumeList_val = returnArray;
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);
446 *nEntries = vl.budb_volumeList_len;
447 return (0);
451 bcdb_UseTape(struct budb_tapeEntry *teptr, afs_int32 *newFlag)
453 afs_int32 code;
454 code = ubik_BUDB_UseTape(udbHandle.uh_client, 0, teptr, newFlag);
455 return (code);
459 /* ---- text configuration handling routines ----
461 * notes:
462 * The caller should pass in/out a fid for an unlinked, open file to prevent
463 * tampering with the files contents;
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
474 bcdb_GetTextFile(udbClientTextP ctPtr)
476 afs_int32 bufferSize;
477 afs_int32 offset, nextOffset;
478 charListT charList;
479 afs_int32 code = 0;
481 /* Initialize charlistT_val. We try to deallocate this structure based on
482 * this */
483 memset((void *)&charList, 0, sizeof(charList));
485 /* check params and cleanup any previous state */
486 if (ctPtr->lockHandle == 0)
487 ERROR(BUDB_INTERNALERROR);
489 if (ctPtr->textStream == NULL) /* Should have an open stream */
490 ERROR(BUDB_INTERNALERROR);
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;
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);
509 if (code)
510 ERROR(code);
512 code =
513 fwrite(charList.charListT_val, sizeof(char),
514 charList.charListT_len, ctPtr->textStream);
515 if (ferror(ctPtr->textStream))
516 ERROR(BUDB_INTERNALERROR);
518 ctPtr->textSize += charList.charListT_len;
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);
528 normal_exit:
529 fflush(ctPtr->textStream); /* debug */
531 /* exit, leaving the configuration text file open */
532 if (charList.charListT_val)
533 free(charList.charListT_val);
534 return (code);
536 error_exit:
537 if (ctPtr->textStream != NULL) {
538 fclose(ctPtr->textStream);
539 ctPtr->textStream = NULL;
541 goto normal_exit;
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
553 bcdb_SaveTextFile(udbClientTextP ctPtr)
555 afs_int32 bufferSize;
556 afs_int32 offset, chunkSize, fileSize;
557 charListT charList;
558 afs_int32 code = 0;
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;
567 if (ctPtr->textStream == NULL)
568 ERROR(BUDB_INTERNALERROR);
569 rewind(ctPtr->textStream);
571 fileSize = (afs_int32) filesize(ctPtr->textStream);
573 afs_dprintf(("filesize is %d\n", fileSize));
575 rewind(ctPtr->textStream);
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;
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);
594 if (code != chunkSize)
595 printf("code = %d\n", code);
596 if (ferror(ctPtr->textStream))
597 ERROR(BUDB_INTERNALERROR);
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);
608 fileSize -= chunkSize;
609 offset += chunkSize;
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);
621 bcdb_FindLastTape(afs_int32 dumpID, struct budb_dumpEntry *dumpEntry,
622 struct budb_tapeEntry *tapeEntry,
623 struct budb_volumeEntry *volEntry)
625 return (ubik_BUDB_FindLastTape(udbHandle.uh_client, 0, dumpID, dumpEntry,
626 tapeEntry, volEntry));
630 bcdb_MakeDumpAppended(afs_int32 appendedDumpID, afs_int32 initialDumpID,
631 afs_int32 startTapeSeq)
633 return (ubik_BUDB_MakeDumpAppended(udbHandle.uh_client, 0, appendedDumpID,
634 initialDumpID, startTapeSeq));
638 /* -------------------------------------
639 * misc. support routines
640 * -------------------------------------
643 afs_int32
644 filesize(FILE *stream)
646 afs_int32 offset;
647 afs_int32 size;
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);
657 /* ------------------------------------
658 * misc. support routines - general text management
659 * ------------------------------------
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
673 bc_LockText(udbClientTextP ctPtr)
675 afs_int32 code;
676 afs_int32 timeout, j = 0;
678 if (ctPtr->lockHandle != 0)
679 return (1); /* already locked */
681 timeout =
682 ((ctPtr->textSize == 0) ? 30 : ((ctPtr->textSize / 50000) + 10));
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;
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;
699 #ifdef AFS_PTHREAD_ENV
700 sleep(1);
701 #else
702 IOMGR_Sleep(1);
703 #endif
706 /* cleanup */
707 if (code)
708 ctPtr->lockHandle = 0;
709 return (code);
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
722 bc_UnlockText(udbClientTextP ctPtr)
724 afs_int32 code = 0;
726 if (ctPtr->lockHandle == 0)
727 return (0);
729 code =
730 ubik_BUDB_FreeLock(udbHandle.uh_client, 0, ctPtr->lockHandle);
731 ctPtr->lockHandle = 0;
733 /* Don't try to analyse the error. Let the lock timeout */
734 return (code);
737 /* bc_CheckTextVersion
738 * exit:
739 * 0 - version # ok
740 * n - out of date or error
744 bc_CheckTextVersion(udbClientTextP ctPtr)
746 afs_int32 code;
747 afs_uint32 tversion;
749 if (ctPtr->textVersion == -1)
750 return (BC_VERSIONMISMATCH);
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);
762 /* -------------------------------------
763 * initialization routines
764 * -------------------------------------
767 static afsconf_secflags
768 parseSecFlags(int noAuthFlag, int localauth, const char **confdir) {
769 afsconf_secflags secFlags;
771 secFlags = 0;
772 if (noAuthFlag)
773 secFlags |= AFSCONF_SECOPTS_NOAUTH;
775 if (localauth) {
776 secFlags |= AFSCONF_SECOPTS_LOCALAUTH;
777 *confdir = AFSDIR_SERVER_ETC_DIRPATH;
778 } else {
779 *confdir = AFSDIR_CLIENT_ETC_DIRPATH;
781 return secFlags;
784 /* vldbClientInit
785 * Initialize a client for the vl ubik database.
788 vldbClientInit(int noAuthFlag, int localauth, char *cellName,
789 struct ubik_client **cstruct,
790 time_t *expires)
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;
801 secFlags = parseSecFlags(noAuthFlag, localauth, &confdir);
802 secFlags |= AFSCONF_SECOPTS_FALLBACK_NULL;
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;
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);
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);
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);
829 if (scIndex == RX_SECIDX_NULL && !noAuthFlag)
830 afs_com_err(whoami, 0, "Can't get tokens - running unauthenticated");
832 /* tell UV module about default authentication */
833 UV_SetSecurity(sc, scIndex);
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;
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;
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);
856 error_exit:
857 if (acdir)
858 afsconf_Close(acdir);
859 return (code);
862 /* udbClientInit
863 * initialize a client for the backup systems ubik database.
866 afs_int32
867 udbClientInit(int noAuthFlag, int localauth, char *cellName)
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;
876 secFlags = parseSecFlags(noAuthFlag, localauth, &confdir);
877 secFlags |= AFSCONF_SECOPTS_FALLBACK_NULL;
879 if (cellName && cellName[0] == '\0')
880 cellName = NULL;
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);
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);
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);
903 if (udbHandle.uh_scIndex == RX_SECIDX_NULL && !noAuthFlag)
904 afs_com_err(whoami, 0, "Can't get tokens - running unauthenticated");
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.
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;
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);
924 udbHandle.uh_serverConn[i] = 0;
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);
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);
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);
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);
954 error_exit:
955 if (acdir)
956 afsconf_Close(acdir);
957 return (code);
960 /* -------------------------------------
961 * specialized ubik support
962 * -------------------------------------
965 #include <rx/xdr.h>
966 #include <rx/rx.h>
967 #include <lock.h>
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.
980 struct ubikCallState {
981 afs_int32 ucs_flags; /* state flags */
982 afs_int32 ucs_selectedServer; /* which server selected */
985 static struct ubikCallState uServer;
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.
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
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)
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;
1013 if ((aflags & (UF_SINGLESERVER | UF_END_SINGLESERVER)) != 0) {
1014 if (((aflags & UF_SINGLESERVER) != 0)
1015 && ((uServer.ucs_flags & UF_SINGLESERVER) != 0)
1018 /* have a selected server */
1019 tc = aclient->conns[uServer.ucs_selectedServer];
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));
1028 return (code);
1029 } else if ((aflags & UF_END_SINGLESERVER) != 0) {
1030 memset(&uServer, 0, sizeof(uServer));
1031 return (0);
1035 someCode = UNOSERVERS;
1036 chaseCount = 0;
1037 pass = 0;
1038 count = 0;
1039 while (1) { /*w */
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 */
1051 if (pass == 0 && (aclient->states[count] & CFLastFailed)) {
1052 count++;
1053 continue; /* this guy's down, try someone else first */
1056 code =
1057 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12,
1058 p13, p14, p15, p16);
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
1066 if (code == UNOTSYNC) { /*ns */
1067 /* means that this requires a sync site to work */
1068 someCode = code; /* remember an error, if this fails */
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 */
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
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;
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;
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)
1112 /* if the call succeeded, setup connection state for subsequent
1113 * calls
1115 if ((code == 0)
1116 && ((aflags & UF_SINGLESERVER) != 0)
1118 /* need to save state */
1119 uServer.ucs_flags = UF_SINGLESERVER;
1120 uServer.ucs_selectedServer = count;
1123 return code;
1125 } /*w */
1126 return someCode;
1130 /* -------------------------------------
1131 * debug and test routines
1132 * -------------------------------------
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.
1144 udbLocalInit(void)
1146 afs_uint32 serverList[MAXSERVERS];
1147 char hostname[256];
1148 char *args[3];
1149 int i;
1150 afs_int32 code;
1152 /* get our host name */
1153 gethostname(hostname, sizeof(hostname));
1154 /* strcpy(hostname, "hops"); */
1156 args[0] = "";
1157 args[1] = "-servers";
1158 args[2] = hostname;
1160 code = ubik_ParseClientList(3, args, serverList);
1161 if (code) {
1162 afs_com_err(whoami, code, "; udbLocalInit: parsing ubik server list");
1163 return (-1);
1166 udbHandle.uh_scIndex = RX_SECIDX_NULL;
1167 udbHandle.uh_secobj = (struct rx_securityClass *)
1168 rxnull_NewClientSecurityObject();
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;
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);
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);
1195 /* abort: */
1196 return (0);
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.
1214 bc_openTextFile(udbClientTextP ctPtr, char *tmpFileName)
1216 int code = 0;
1217 int fd;
1219 if (ctPtr->textStream != NULL) {
1220 fclose(ctPtr->textStream);
1221 ctPtr->textStream = NULL;
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);
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
1239 afs_dprintf(("file is %s\n", tmpFileName));
1241 normal_exit:
1242 return code;
1244 error_exit:
1245 if (ctPtr->textStream != NULL) {
1246 fclose(ctPtr->textStream);
1247 ctPtr->textStream = NULL;
1249 goto normal_exit;
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
1262 bc_closeTextFile(udbClientTextP ctPtr, char *tmpFileName)
1264 int code = 0;
1266 if (ctPtr->textStream)
1267 fclose(ctPtr->textStream);
1269 if (*tmpFileName) { /* we have a valid name */
1270 code = unlink(tmpFileName);
1271 if (code < 0)
1272 code = errno;
1274 return code;