2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* Interface and supporting routines for the backup system's ubik database */
12 #include <afsconfig.h>
17 #ifdef IGNORE_SOME_GCC_WARNINGS
18 # pragma GCC diagnostic warning "-Wstrict-prototypes"
23 #include <afs/cellconfig.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>
32 #include <afs/com_err.h>
35 #include "error_macros.h"
36 #include "bucoord_internal.h"
37 #include "bucoord_prototypes.h"
41 /* -------------------------------------
43 * -------------------------------------
46 struct udbHandleS udbHandle
;
48 /* -------------------------------------
49 * interface routines (alphabetic)
50 * -------------------------------------
53 afs_int32
bcdb_AddVolume(struct budb_volumeEntry
*veptr
)
57 code
= ubik_BUDB_AddVolume(udbHandle
.uh_client
, 0, veptr
);
61 afs_int32
bcdb_AddVolumes(struct budb_volumeEntry
*veptr
, afs_int32 count
)
63 struct budb_volumeList volumeList
;
66 volumeList
.budb_volumeList_len
= count
;
67 volumeList
.budb_volumeList_val
= veptr
;
68 code
= ubik_BUDB_AddVolumes(udbHandle
.uh_client
, 0, &volumeList
);
73 afs_int32
bcdb_CreateDump(struct budb_dumpEntry
*deptr
)
77 code
= ubik_BUDB_CreateDump(udbHandle
.uh_client
, 0, deptr
);
81 afs_int32
bcdb_deleteDump(afs_int32 dumpID
, afs_int32 fromTime
, afs_int32 toTime
,
82 budb_dumpsList
*dumps
)
85 budb_dumpsList dumpsList
, *dumpsPtr
;
87 dumpsList
.budb_dumpsList_len
= 0;
88 dumpsList
.budb_dumpsList_val
= 0;
89 dumpsPtr
= (dumps
? dumps
: &dumpsList
);
92 ubik_BUDB_DeleteDump(udbHandle
.uh_client
, 0, dumpID
, fromTime
,
94 if (dumpsList
.budb_dumpsList_val
)
95 free(dumpsList
.budb_dumpsList_val
);
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
)
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
);
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
);
127 afs_int32
bcdb_DeleteVDP(char *dumpSetName
, char *dumpPath
, afs_int32 dumpID
)
132 ubik_BUDB_DeleteVDP(udbHandle
.uh_client
, 0, dumpSetName
,
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
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
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
)
155 ubik_BUDB_FindClone(udbHandle
.uh_client
, 0, dumpID
, volName
,
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)
168 * volumeName - name of volume to match on
169 * beforeDate - look for dumps older than this date
171 * deptr - desciptor of most recent dump
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
)
183 ubik_BUDB_FindDump(udbHandle
.uh_client
, 0, volumeName
,
189 * find a dump by id. Currently insists on a single return value.
191 * dumpID - id to lookup
195 bcdb_FindDumpByID(afs_int32 dumpID
, struct budb_dumpEntry
*deptr
)
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 */
211 &nextindex
, &dbTime
, &dl
);
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); */
219 code
= 1; /* multiple id's */
223 memcpy(deptr
, dl
.budb_dumpList_val
, sizeof(*deptr
));
226 if (dl
.budb_dumpList_val
) {
227 /* free any allocated structures */
228 free(dl
.budb_dumpList_val
);
233 memset(deptr
, 0, sizeof(*deptr
));
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
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
249 * 0 - clonetime set appropriately
251 * used only for warning generation. Suggest that this be omitted.
255 bcdb_FindLastVolClone(char *volSetName
, char *dumpName
, char *volName
,
256 afs_int32
*clonetime
)
260 * match on volumeset and dump path
261 * search for the volume name
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
272 * avname: volume set name
273 * dumpPath: full path of dump node
275 * 0: adentry: dump entry structure filled in.
276 * -1: probably an internal error
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
)
289 ubik_BUDB_FindLatestDump(udbHandle
.uh_client
, 0, volSetName
,
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
)
311 memset(teptr
, 0, sizeof(*teptr
));
312 tl
.budb_tapeList_len
= 0;
313 tl
.budb_tapeList_val
= 0;
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
);
323 if (tl
.budb_tapeList_len
!= 1)
324 ERROR(BC_NOTUNIQUE
); /* expecting a single descriptor */
326 memcpy(teptr
, tl
.budb_tapeList_val
, sizeof(*teptr
));
329 if (tl
.budb_tapeList_val
)
330 free(tl
.budb_tapeList_val
);
335 bcdb_FindTapeSeq(afs_int32 dumpid
, afs_int32 tapeSeq
,
336 struct budb_tapeEntry
*teptr
)
343 memset(teptr
, 0, sizeof(*teptr
));
344 tl
.budb_tapeList_len
= 0;
345 tl
.budb_tapeList_val
= 0;
348 ubik_BUDB_GetTapes(udbHandle
.uh_client
, 0, BUDB_MAJORVERSION
,
349 BUDB_OP_TAPESEQ
| BUDB_OP_DUMPID
, "", dumpid
, tapeSeq
, 0,
350 &next
, &dbTime
, &tl
);
354 if (tl
.budb_tapeList_len
!= 1)
355 ERROR(BC_NOTUNIQUE
); /* expecting a single descriptor */
357 memcpy(teptr
, tl
.budb_tapeList_val
, sizeof(*teptr
));
360 if (tl
.budb_tapeList_val
)
361 free(tl
.budb_tapeList_val
);
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
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
379 bcdb_FindVolumes(afs_int32 dumpID
, char *volumeName
,
380 struct budb_volumeEntry
*returnArray
,
381 afs_int32 last
, afs_int32
*next
, afs_int32 maxa
,
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 */
396 next
, /* nextindex */
399 *nEntries
= vl
.budb_volumeList_len
;
404 bcdb_FinishDump(struct budb_dumpEntry
*deptr
)
407 code
= ubik_BUDB_FinishDump(udbHandle
.uh_client
, 0, deptr
);
412 bcdb_FinishTape(struct budb_tapeEntry
*teptr
)
415 code
= ubik_BUDB_FinishTape(udbHandle
.uh_client
, 0, teptr
);
420 /* bcdb_LookupVolumes
424 bcdb_LookupVolume(char *volumeName
, struct budb_volumeEntry
*returnArray
,
425 afs_int32 last
, afs_int32
*next
, afs_int32 maxa
,
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 */
440 next
, /* nextindex */
446 *nEntries
= vl
.budb_volumeList_len
;
451 bcdb_UseTape(struct budb_tapeEntry
*teptr
, afs_int32
*newFlag
)
454 code
= ubik_BUDB_UseTape(udbHandle
.uh_client
, 0, teptr
, newFlag
);
459 /* ---- text configuration handling routines ----
462 * The caller should pass in/out a fid for an unlinked, open file to prevent
463 * tampering with the files contents;
467 * extract the specified textType and put it in a temporary, local
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
;
481 /* Initialize charlistT_val. We try to deallocate this structure based on
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 */
494 charList
.charListT_val
= malloc(bufferSize
);
495 if (charList
.charListT_val
== 0)
496 ERROR(BUDB_INTERNALERROR
);
497 charList
.charListT_len
= bufferSize
;
501 while (nextOffset
!= -1) {
503 charList
.charListT_len
= bufferSize
;
505 ubik_BUDB_GetText(udbHandle
.uh_client
, 0, ctPtr
->lockHandle
,
506 ctPtr
->textType
, bufferSize
, offset
, &nextOffset
,
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 */
523 ubik_BUDB_GetTextVersion(udbHandle
.uh_client
, 0,
524 ctPtr
->textType
, &ctPtr
->textVersion
);
529 fflush(ctPtr
->textStream
); /* debug */
531 /* exit, leaving the configuration text file open */
532 if (charList
.charListT_val
)
533 free(charList
.charListT_val
);
537 if (ctPtr
->textStream
!= NULL
) {
538 fclose(ctPtr
->textStream
);
539 ctPtr
->textStream
= NULL
;
546 * save the text file in ubik database
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
;
560 /* allocate a buffer */
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 */
579 charList
.charListT_len
= 0;
581 ubik_BUDB_SaveText(udbHandle
.uh_client
, 0,
582 ctPtr
->lockHandle
, ctPtr
->textType
, 0,
583 BUDB_TEXT_COMPLETE
, &charList
);
588 while (fileSize
!= 0) {
589 chunkSize
= min(fileSize
, bufferSize
);
591 fread(charList
.charListT_val
, sizeof(char), chunkSize
,
594 if (code
!= chunkSize
)
595 printf("code = %d\n", code
);
596 if (ferror(ctPtr
->textStream
))
597 ERROR(BUDB_INTERNALERROR
);
599 charList
.charListT_len
= chunkSize
;
601 ubik_BUDB_SaveText(udbHandle
.uh_client
, 0,
602 ctPtr
->lockHandle
, ctPtr
->textType
, offset
,
603 (chunkSize
== fileSize
) ? BUDB_TEXT_COMPLETE
: 0,
608 fileSize
-= chunkSize
;
613 /* if ( ctPtr->textStream >= 0 )
614 * close(ctPtr->textStream); */
615 if (charList
.charListT_val
)
616 free(charList
.charListT_val
);
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 * -------------------------------------
644 filesize(FILE *stream
)
649 offset
= ftell(stream
);
650 fseek(stream
, (afs_int32
) 0, 2); /* end of file */
651 size
= ftell(stream
);
652 fseek(stream
, offset
, 0);
657 /* ------------------------------------
658 * misc. support routines - general text management
659 * ------------------------------------
664 * locks the text described by the ctPtr
666 * ctptr - client text ptr
673 bc_LockText(udbClientTextP ctPtr
)
676 afs_int32 timeout
, j
= 0;
678 if (ctPtr
->lockHandle
!= 0)
679 return (1); /* already locked */
682 ((ctPtr
->textSize
== 0) ? 30 : ((ctPtr
->textSize
/ 50000) + 10));
686 ubik_BUDB_GetLock(udbHandle
.uh_client
, 0,
687 udbHandle
.uh_instanceId
, ctPtr
->textType
, timeout
,
689 if ((code
!= BUDB_LOCKED
) && (code
!= BUDB_SELFLOCKED
)) {
693 /* Mention something every 30 seconds */
695 afs_com_err(whoami
, code
,
696 "; Waiting for db configuration text unlock");
699 #ifdef AFS_PTHREAD_ENV
708 ctPtr
->lockHandle
= 0;
713 * unlocks the text described by the ctPtr
715 * ctptr - client text ptr
722 bc_UnlockText(udbClientTextP ctPtr
)
726 if (ctPtr
->lockHandle
== 0)
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 */
737 /* bc_CheckTextVersion
740 * n - out of date or error
744 bc_CheckTextVersion(udbClientTextP ctPtr
)
749 if (ctPtr
->textVersion
== -1)
750 return (BC_VERSIONMISMATCH
);
753 ubik_BUDB_GetTextVersion(udbHandle
.uh_client
, 0,
754 ctPtr
->textType
, &tversion
);
757 if (tversion
!= ctPtr
->textVersion
)
758 return (BC_VERSIONMISMATCH
);
762 /* -------------------------------------
763 * initialization routines
764 * -------------------------------------
767 static afsconf_secflags
768 parseSecFlags(int noAuthFlag
, int localauth
, const char **confdir
) {
769 afsconf_secflags secFlags
;
773 secFlags
|= AFSCONF_SECOPTS_NOAUTH
;
776 secFlags
|= AFSCONF_SECOPTS_LOCALAUTH
;
777 *confdir
= AFSDIR_SERVER_ETC_DIRPATH
;
779 *confdir
= AFSDIR_CLIENT_ETC_DIRPATH
;
785 * Initialize a client for the vl ubik database.
788 vldbClientInit(int noAuthFlag
, int localauth
, char *cellName
,
789 struct ubik_client
**cstruct
,
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
;
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')
809 /* Find out about the given cell */
810 acdir
= afsconf_Open(confdir
);
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
);
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
);
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
++)
844 rx_NewConnection(info
.hostAddr
[i
].sin_addr
.s_addr
,
845 info
.hostAddr
[i
].sin_port
, USER_SERVICE_ID
, sc
,
850 code
= ubik_ClientInit(serverconns
, cstruct
);
852 afs_com_err(whoami
, code
, "; Can't initialize ubik connection to vldb");
858 afsconf_Close(acdir
);
863 * initialize a client for the backup systems ubik database.
867 udbClientInit(int noAuthFlag
, int localauth
, char *cellName
)
869 struct afsconf_cell info
;
870 struct afsconf_dir
*acdir
;
876 secFlags
= parseSecFlags(noAuthFlag
, localauth
, &confdir
);
877 secFlags
|= AFSCONF_SECOPTS_FALLBACK_NULL
;
879 if (cellName
&& cellName
[0] == '\0')
882 acdir
= afsconf_Open(confdir
);
884 afs_com_err(whoami
, 0, "Can't open configuration directory '%s'",
886 ERROR(BC_NOCELLCONFIG
);
889 code
= afsconf_GetCellInfo(acdir
, cellName
, 0, &info
);
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
);
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
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
);
928 afs_com_err(whoami
, code
,
929 "; Can't initialize ubik connection to backup database");
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);
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 */
947 ubik_BUDB_GetInstanceId(udbHandle
.uh_client
, 0,
948 &udbHandle
.uh_instanceId
);
950 afs_com_err(whoami
, code
, "; Can't access backup database");
956 afsconf_Close(acdir
);
960 /* -------------------------------------
961 * specialized ubik support
962 * -------------------------------------
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
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
)
1005 afs_int32 someCode
, newHost
, thisHost
;
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
];
1022 (*aproc
) (tc
, p1
, p2
, p3
, p4
, p5
, p6
, p7
, p8
, p9
, p10
, p11
,
1023 p12
, p13
, p14
, p15
, p16
);
1025 /* error. Clean up single server state */
1026 memset(&uServer
, 0, sizeof(uServer
));
1029 } else if ((aflags
& UF_END_SINGLESERVER
) != 0) {
1030 memset(&uServer
, 0, sizeof(uServer
));
1035 someCode
= UNOSERVERS
;
1041 /* tc is the next conn to try */
1042 tc
= aclient
->conns
[count
];
1045 pass
= 1; /* in pass 1, we look at down hosts, too */
1049 break; /* nothing left to try */
1051 if (pass
== 0 && (aclient
->states
[count
] & CFLastFailed
)) {
1053 continue; /* this guy's down, try someone else first */
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 */
1085 if (thisHost
== newHost
) {
1086 /* avoid asking in a loop */
1087 if (chaseCount
++ > 2)
1089 count
= i
; /* we were told to use this one */
1094 count
++; /* not directed, keep looking for a sync site */
1097 else if (code
== UNOQUORUM
) { /* this guy is still recovering */
1101 } else if (code
< 0) { /* network errors */
1103 aclient
->states
[count
] |= CFLastFailed
;
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
1116 && ((aflags
& UF_SINGLESERVER
) != 0)
1118 /* need to save state */
1119 uServer
.ucs_flags
= UF_SINGLESERVER
;
1120 uServer
.ucs_selectedServer
= count
;
1130 /* -------------------------------------
1131 * debug and test routines
1132 * -------------------------------------
1136 * For testing only. Open a connect to the database server running on
1139 * 0 - ubik connection established in the global udbHandle structure
1146 afs_uint32 serverList
[MAXSERVERS
];
1152 /* get our host name */
1153 gethostname(hostname
, sizeof(hostname
));
1154 /* strcpy(hostname, "hops"); */
1157 args
[1] = "-servers";
1160 code
= ubik_ParseClientList(3, args
, serverList
);
1162 afs_com_err(whoami
, code
, "; udbLocalInit: parsing ubik server list");
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
);
1180 udbHandle
.uh_serverConn
[i
] = 0;
1181 code
= ubik_ClientInit(udbHandle
.uh_serverConn
, &udbHandle
.uh_client
);
1183 afs_com_err(whoami
, code
, "; in ubik_ClientInit");
1188 ubik_BUDB_GetInstanceId(udbHandle
.uh_client
, 0,
1189 &udbHandle
.uh_instanceId
);
1191 afs_com_err(whoami
, code
, "; Can't estblish instance Id");
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()
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.
1214 bc_openTextFile(udbClientTextP ctPtr
, char *tmpFileName
)
1219 if (ctPtr
->textStream
!= NULL
) {
1220 fclose(ctPtr
->textStream
);
1221 ctPtr
->textStream
= NULL
;
1224 sprintf(tmpFileName
, "%s/bu_XXXXXX", gettmpdir());
1225 fd
= mkstemp(tmpFileName
);
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
);
1239 afs_dprintf(("file is %s\n", tmpFileName
));
1245 if (ctPtr
->textStream
!= NULL
) {
1246 fclose(ctPtr
->textStream
);
1247 ctPtr
->textStream
= NULL
;
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
1262 bc_closeTextFile(udbClientTextP ctPtr
, char *tmpFileName
)
1266 if (ctPtr
->textStream
)
1267 fclose(ctPtr
->textStream
);
1269 if (*tmpFileName
) { /* we have a valid name */
1270 code
= unlink(tmpFileName
);