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>
15 #ifdef IGNORE_SOME_GCC_WARNINGS
16 # pragma GCC diagnostic warning "-Wstrict-prototypes"
19 #include <sys/types.h>
23 #elif defined(AFS_SUN5_ENV)
26 #include <sys/param.h> /* for hostnames etc */
29 #include <afs/cellconfig.h>
31 #include <afs/volser.h>
32 #include <afs/afsutil.h>
33 #include <afs/bubasics.h>
34 #include <afs/budb_client.h>
36 #include <afs/com_err.h>
40 #include "error_macros.h"
41 #include "bucoord_internal.h"
42 #include "bucoord_prototypes.h"
46 /* -------------------------------------
48 * -------------------------------------
51 struct udbHandleS udbHandle;
53 /* -------------------------------------
54 * interface routines (alphabetic)
55 * -------------------------------------
58 afs_int32 bcdb_AddVolume(register struct budb_volumeEntry *veptr)
62 code = ubik_BUDB_AddVolume(udbHandle.uh_client, 0, veptr);
66 afs_int32 bcdb_AddVolumes(register struct budb_volumeEntry *veptr, afs_int32 count)
68 struct budb_volumeList volumeList;
71 volumeList.budb_volumeList_len = count;
72 volumeList.budb_volumeList_val = veptr;
73 code = ubik_BUDB_AddVolumes(udbHandle.uh_client, 0, &volumeList);
78 afs_int32 bcdb_CreateDump(register struct budb_dumpEntry *deptr)
82 code = ubik_BUDB_CreateDump(udbHandle.uh_client, 0, deptr);
86 afs_int32 bcdb_deleteDump(afs_int32 dumpID, afs_int32 fromTime, afs_int32 toTime,
87 budb_dumpsList *dumps)
90 budb_dumpsList dumpsList, *dumpsPtr;
92 dumpsList.budb_dumpsList_len = 0;
93 dumpsList.budb_dumpsList_val = 0;
94 dumpsPtr = (dumps ? dumps : &dumpsList);
97 ubik_BUDB_DeleteDump(udbHandle.uh_client, 0, dumpID, fromTime,
99 if (dumpsList.budb_dumpsList_val)
100 free(dumpsList.budb_dumpsList_val);
104 afs_int32 bcdb_listDumps (afs_int32 sflags, afs_int32 groupId,
105 afs_int32 fromTime, afs_int32 toTime,
106 budb_dumpsList *dumps, budb_dumpsList *flags)
109 budb_dumpsList dumpsList, *dumpsPtr;
110 budb_dumpsList flagsList, *flagsPtr;
112 dumpsList.budb_dumpsList_len = 0;
113 dumpsList.budb_dumpsList_val = 0;
114 dumpsPtr = (dumps ? dumps : &dumpsList);
116 flagsList.budb_dumpsList_len = 0;
117 flagsList.budb_dumpsList_val = 0;
118 flagsPtr = (flags ? flags : &flagsList);
121 ubik_BUDB_ListDumps(udbHandle.uh_client, 0, sflags, "", groupId,
122 fromTime, toTime, dumpsPtr, flagsPtr);
124 if (dumpsList.budb_dumpsList_val)
125 free(dumpsList.budb_dumpsList_val);
126 if (flagsList.budb_dumpsList_val)
127 free(flagsList.budb_dumpsList_val);
132 afs_int32 bcdb_DeleteVDP(char *dumpSetName, char *dumpPath, afs_int32 dumpID)
137 ubik_BUDB_DeleteVDP(udbHandle.uh_client, 0, dumpSetName,
143 * Returns the clone time of a volume by going up the parent chain.
144 * If no clone time is found, a clone time of 0 is returned, forcing
147 * dumpID - of the first dump to examine.
148 * volName - name of the volume for whom a clone time is required
149 * clonetime - ptr to vbl for returning result
151 * 0 - clonetime set appropriately
152 * -1 - error occured in traversing chain, clone time set to 0.
153 * -2 - no clone times found, clone time set to 0
156 afs_int32 bcdb_FindClone(afs_int32 dumpID, char *volName, afs_int32 *clonetime)
160 ubik_BUDB_FindClone(udbHandle.uh_client, 0, dumpID, volName,
166 * scan entire database for latest volume dump before adate. Optimize
167 * further by reading only the first line of the dump and if it is older
168 * than the oldest acceptable dump we've found so far, we don't bother
169 * scanning the dump file we've just opened
171 * Used by restore code when restoring a user requested volume(s)
173 * volumeName - name of volume to match on
174 * beforeDate - look for dumps older than this date
176 * deptr - desciptor of most recent dump
178 * should be able to implement this in a single call rather than
179 * the current multiple bcdb_ call algorithm.
183 bcdb_FindDump(char *volumeName, afs_int32 beforeDate,
184 struct budb_dumpEntry *deptr)
188 ubik_BUDB_FindDump(udbHandle.uh_client, 0, volumeName,
194 * find a dump by id. Currently insists on a single return value.
196 * dumpID - id to lookup
200 bcdb_FindDumpByID(afs_int32 dumpID, struct budb_dumpEntry *deptr)
202 register afs_int32 code;
207 /* initialize the dump list */
208 dl.budb_dumpList_len = 0;
209 dl.budb_dumpList_val = 0;
211 /* outline algorithm */
212 code = ubik_BUDB_GetDumps(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_DUMPID, "", /* no name */
216 &nextindex, &dbTime, &dl);
219 || (dl.budb_dumpList_len != 1) /* single retn val expected */
221 /* printf("bcdb_FindDumpByID: code %d, nvalues %d\n",
222 code, dl.budb_dumpList_len); */
224 code = 1; /* multiple id's */
228 memcpy(deptr, dl.budb_dumpList_val, sizeof(*deptr));
231 if (dl.budb_dumpList_val) {
232 /* free any allocated structures */
233 free(dl.budb_dumpList_val);
238 memset(deptr, 0, sizeof(*deptr));
242 /* bcdb_FindLastVolClone
243 * Returns the clone time, from the most recent dump of volName, when
244 * dumped in the volume set volSetName, with dump schedule dumpName.
245 * The clone time can be used to check if the volume has been correctly
246 * re-cloned, and also is used as the time from which to do the current
249 * volSetName - name of volume set
250 * dumpName - full path of dump node
251 * volName - name of volume for whom a clone time is required
252 * clonetime - ptr to vbl for result
254 * 0 - clonetime set appropriately
256 * used only for warning generation. Suggest that this be omitted.
260 bcdb_FindLastVolClone(char *volSetName, char *dumpName, char *volName,
261 afs_int32 *clonetime)
265 * match on volumeset and dump path
266 * search for the volume name
271 /* bcdb_FindLatestDump
272 * find the latest dump with volume set component avname and the
273 * specified dump pathname. Used to find a dump, relative to which an
274 * incremental dump can be done. Defines the parent <-> child relations
277 * avname: volume set name
278 * dumpPath: full path of dump node
280 * 0: adentry: dump entry structure filled in.
281 * -1: probably an internal error
284 * Need to store volumeset name in dump in order to implement this.
285 * Need new routine since params are two strings
289 bcdb_FindLatestDump(char *volSetName, char *dumpPath,
290 struct budb_dumpEntry *deptr)
294 ubik_BUDB_FindLatestDump(udbHandle.uh_client, 0, volSetName,
303 * dumpid: dump id to which tape beint32s
304 * tapeName: name of tape
308 bcdb_FindTape(afs_int32 dumpid, char *tapeName,
309 struct budb_tapeEntry *teptr)
316 memset(teptr, 0, sizeof(*teptr));
317 tl.budb_tapeList_len = 0;
318 tl.budb_tapeList_val = 0;
321 ubik_BUDB_GetTapes(udbHandle.uh_client, 0, BUDB_MAJORVERSION,
322 BUDB_OP_TAPENAME | BUDB_OP_DUMPID, tapeName, dumpid, 0, 0,
323 &next, &dbTime, &tl);
328 if (tl.budb_tapeList_len != 1)
329 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
331 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
334 if (tl.budb_tapeList_val)
335 free(tl.budb_tapeList_val);
340 bcdb_FindTapeSeq(afs_int32 dumpid, afs_int32 tapeSeq,
341 struct budb_tapeEntry *teptr)
348 memset(teptr, 0, sizeof(*teptr));
349 tl.budb_tapeList_len = 0;
350 tl.budb_tapeList_val = 0;
353 ubik_BUDB_GetTapes(udbHandle.uh_client, 0, BUDB_MAJORVERSION,
354 BUDB_OP_TAPESEQ | BUDB_OP_DUMPID, "", dumpid, tapeSeq, 0,
355 &next, &dbTime, &tl);
359 if (tl.budb_tapeList_len != 1)
360 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
362 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
365 if (tl.budb_tapeList_val)
366 free(tl.budb_tapeList_val);
372 * - this is part of dblookup. The existing semantics will not work since
373 * they do lookups based on dump id.
374 * - in the restore code, it uses this to extract information about
375 * the volume. Need current semantics. Could filter the output, selecting
377 * - Suggest that the lookup be based on volume name only, with optional
378 * match on backup, and readonly volumes.
379 * - Further, need to check if the volume structure returns enough
384 bcdb_FindVolumes(afs_int32 dumpID, char *volumeName,
385 struct budb_volumeEntry *returnArray,
386 afs_int32 last, afs_int32 *next, afs_int32 maxa,
393 vl.budb_volumeList_len = maxa;
394 vl.budb_volumeList_val = returnArray;
396 /* outline algorithm */
397 code = ubik_BUDB_GetVolumes(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME | BUDB_OP_DUMPID, volumeName, /* name */
401 next, /* nextindex */
404 *nEntries = vl.budb_volumeList_len;
409 bcdb_FinishDump(register struct budb_dumpEntry *deptr)
412 code = ubik_BUDB_FinishDump(udbHandle.uh_client, 0, deptr);
417 bcdb_FinishTape(register struct budb_tapeEntry *teptr)
420 code = ubik_BUDB_FinishTape(udbHandle.uh_client, 0, teptr);
425 /* bcdb_LookupVolumes
429 bcdb_LookupVolume(char *volumeName, struct budb_volumeEntry *returnArray,
430 afs_int32 last, afs_int32 *next, afs_int32 maxa,
437 vl.budb_volumeList_len = maxa;
438 vl.budb_volumeList_val = returnArray;
440 /* outline algorithm */
441 code = ubik_BUDB_GetVolumes(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME, volumeName, /* name */
445 next, /* nextindex */
451 *nEntries = vl.budb_volumeList_len;
456 bcdb_UseTape(struct budb_tapeEntry *teptr, afs_int32 *newFlag)
459 code = ubik_BUDB_UseTape(udbHandle.uh_client, 0, teptr, newFlag);
464 /* ---- text configuration handling routines ----
467 * The caller should pass in/out a fid for an unlinked, open file to prevent
468 * tampering with the files contents;
472 * extract the specified textType and put it in a temporary, local
475 * ctPtr - ptr to client structure with all the required information
479 bcdb_GetTextFile(register udbClientTextP ctPtr)
481 afs_int32 bufferSize;
482 afs_int32 offset, nextOffset;
486 /* Initialize charlistT_val. We try to deallocate this structure based on
488 memset((void *)&charList, 0, sizeof(charList));
490 /* check params and cleanup any previous state */
491 if (ctPtr->lockHandle == 0)
492 ERROR(BUDB_INTERNALERROR);
494 if (ctPtr->textStream == NULL) /* Should have an open stream */
495 ERROR(BUDB_INTERNALERROR);
497 /* allocate a buffer */
499 charList.charListT_val = (char *)malloc(bufferSize);
500 if (charList.charListT_val == 0)
501 ERROR(BUDB_INTERNALERROR);
502 charList.charListT_len = bufferSize;
507 while (nextOffset != -1) {
509 charList.charListT_len = bufferSize;
511 ubik_BUDB_GetText(udbHandle.uh_client, 0, ctPtr->lockHandle,
512 ctPtr->textType, bufferSize, offset, &nextOffset,
519 fwrite(charList.charListT_val, sizeof(char),
520 charList.charListT_len, ctPtr->textStream);
521 if (ferror(ctPtr->textStream))
522 ERROR(BUDB_INTERNALERROR);
524 ctPtr->textSize += charList.charListT_len;
527 /* get text version */
529 ubik_BUDB_GetTextVersion(udbHandle.uh_client, 0,
530 ctPtr->textType, &ctPtr->textVersion);
535 fflush(ctPtr->textStream); /* debug */
537 /* exit, leaving the configuration text file open */
538 if (charList.charListT_val)
539 free(charList.charListT_val);
543 if (ctPtr->textStream != NULL) {
544 fclose(ctPtr->textStream);
545 ctPtr->textStream = NULL;
552 * save the text file in ubik database
554 * textType - identifies type of configuration file
555 * filename - where to get the text from
559 bcdb_SaveTextFile(udbClientTextP ctPtr)
561 afs_int32 bufferSize;
562 afs_int32 offset, chunkSize, fileSize;
566 /* allocate a buffer */
568 charList.charListT_val = (char *)malloc(bufferSize);
569 if (charList.charListT_val == 0)
570 ERROR(BUDB_INTERNALERROR);
571 charList.charListT_len = bufferSize;
573 if (ctPtr->textStream == NULL)
574 ERROR(BUDB_INTERNALERROR);
575 rewind(ctPtr->textStream);
577 fileSize = (afs_int32) filesize(ctPtr->textStream);
579 afs_dprintf(("filesize is %d\n", fileSize));
581 rewind(ctPtr->textStream);
583 /* special case empty files */
585 charList.charListT_len = 0;
587 ubik_BUDB_SaveText(udbHandle.uh_client, 0,
588 ctPtr->lockHandle, ctPtr->textType, 0,
589 BUDB_TEXT_COMPLETE, &charList);
594 while (fileSize != 0) {
595 chunkSize = MIN(fileSize, bufferSize);
597 fread(charList.charListT_val, sizeof(char), chunkSize,
600 if (code != chunkSize)
601 printf("code = %d\n", code);
602 if (ferror(ctPtr->textStream))
603 ERROR(BUDB_INTERNALERROR);
605 charList.charListT_len = chunkSize;
607 ubik_BUDB_SaveText(udbHandle.uh_client, 0,
608 ctPtr->lockHandle, ctPtr->textType, offset,
609 (chunkSize == fileSize) ? BUDB_TEXT_COMPLETE : 0,
614 fileSize -= chunkSize;
619 /* if ( ctPtr->textStream >= 0 )
620 * close(ctPtr->textStream); */
621 if (charList.charListT_val)
622 free(charList.charListT_val);
627 bcdb_FindLastTape(afs_int32 dumpID, struct budb_dumpEntry *dumpEntry,
628 struct budb_tapeEntry *tapeEntry,
629 struct budb_volumeEntry *volEntry)
631 return (ubik_BUDB_FindLastTape(udbHandle.uh_client, 0, dumpID, dumpEntry,
632 tapeEntry, volEntry));
636 bcdb_MakeDumpAppended(afs_int32 appendedDumpID, afs_int32 initialDumpID,
637 afs_int32 startTapeSeq)
639 return (ubik_BUDB_MakeDumpAppended(udbHandle.uh_client, 0, appendedDumpID,
640 initialDumpID, startTapeSeq));
644 /* -------------------------------------
645 * misc. support routines
646 * -------------------------------------
650 filesize(FILE *stream)
655 offset = ftell(stream);
656 fseek(stream, (afs_int32) 0, 2); /* end of file */
657 size = ftell(stream);
658 fseek(stream, offset, 0);
663 /* ------------------------------------
664 * misc. support routines - general text management
665 * ------------------------------------
670 * locks the text described by the ctPtr
672 * ctptr - client text ptr
679 bc_LockText(udbClientTextP ctPtr)
682 afs_int32 timeout, j = 0;
684 if (ctPtr->lockHandle != 0)
685 return (1); /* already locked */
688 ((ctPtr->textSize == 0) ? 30 : ((ctPtr->textSize / 50000) + 10));
692 ubik_BUDB_GetLock(udbHandle.uh_client, 0,
693 udbHandle.uh_instanceId, ctPtr->textType, timeout,
695 if ((code != BUDB_LOCKED) && (code != BUDB_SELFLOCKED)) {
699 /* Mention something every 30 seconds */
701 afs_com_err(whoami, code,
702 "; Waiting for db configuration text unlock");
705 #ifdef AFS_PTHREAD_ENV
714 ctPtr->lockHandle = 0;
719 * unlocks the text described by the ctPtr
721 * ctptr - client text ptr
728 bc_UnlockText(udbClientTextP ctPtr)
732 if (ctPtr->lockHandle == 0)
736 ubik_BUDB_FreeLock(udbHandle.uh_client, 0, ctPtr->lockHandle);
737 ctPtr->lockHandle = 0;
739 /* Don't try to analyse the error. Let the lock timeout */
743 /* bc_CheckTextVersion
746 * n - out of date or error
750 bc_CheckTextVersion(udbClientTextP ctPtr)
755 if (ctPtr->textVersion == -1)
756 return (BC_VERSIONMISMATCH);
759 ubik_BUDB_GetTextVersion(udbHandle.uh_client, 0,
760 ctPtr->textType, &tversion);
763 if (tversion != ctPtr->textVersion)
764 return (BC_VERSIONMISMATCH);
768 /* -------------------------------------
769 * initialization routines
770 * -------------------------------------
774 * Initialize a client for the vl ubik database.
777 vldbClientInit(int noAuthFlag, int localauth, char *cellName,
778 struct ubik_client **cstruct,
779 struct ktc_token *ttoken)
782 struct afsconf_dir *acdir;
783 struct rx_securityClass *sc;
784 afs_int32 i, scIndex = 0; /* Index of Rx security object - noauth */
785 struct afsconf_cell info;
786 struct ktc_principal sname;
787 struct rx_connection *serverconns[VLDB_MAXSERVERS];
790 /* Find out about the given cell */
792 afsconf_Open((localauth ? AFSDIR_SERVER_ETC_DIRPATH :
793 AFSDIR_CLIENT_ETC_DIRPATH));
795 afs_com_err(whoami, 0, "Can't open configuration directory '%s'",
796 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
797 AFSDIR_CLIENT_ETC_DIRPATH));
798 ERROR(BC_NOCELLCONFIG);
804 code = afsconf_GetLocalCell(acdir, cname, sizeof(cname));
806 afs_com_err(whoami, code,
807 "; Can't get the local cell name - check %s/%s",
808 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
809 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_THISCELL_FILE);
812 strcpy(cellName, cname);
815 code = afsconf_GetCellInfo(acdir, cellName, AFSCONF_VLDBSERVICE, &info);
817 afs_com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
819 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
820 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_CELLSERVDB_FILE);
821 ERROR(BC_NOCELLCONFIG);
825 * Grab tickets if we care about authentication.
829 code = afsconf_GetLatestKey(acdir, 0, 0);
831 afs_com_err(whoami, code, "; Can't get key from local key file");
834 code = afsconf_ClientAuth(acdir, &sc, &scIndex);
836 afs_com_err(whoami, code, "; Calling ClientAuth");
840 ttoken->endTime = NEVERDATE;
844 strcpy(sname.cell, info.name);
845 sname.instance[0] = 0;
846 strcpy(sname.name, "afs");
849 ktc_GetToken(&sname, ttoken, sizeof(struct ktc_token), NULL);
851 afs_com_err(whoami, code, 0,
852 "; Can't get AFS tokens - running unauthenticated");
854 if ((ttoken->kvno < 0) || (ttoken->kvno > 256))
855 afs_com_err(whoami, 0,
856 "Funny kvno (%d) in ticket, proceeding",
865 sc = rxnull_NewClientSecurityObject();
868 sc = (struct rx_securityClass *)
869 rxkad_NewClientSecurityObject(rxkad_clear,
871 ttoken->kvno, ttoken->ticketLen,
875 afs_com_err(whoami, 0, "Unsupported authentication type %d", scIndex);
882 afs_com_err(whoami, 0,
883 "Can't create a security object with security index %d",
888 /* tell UV module about default authentication */
889 UV_SetSecurity(sc, scIndex);
891 if (info.numServers > VLDB_MAXSERVERS) {
892 afs_com_err(whoami, 0,
893 "Warning: %d VLDB servers exist for cell '%s', can only remember the first %d",
894 info.numServers, cellName, VLDB_MAXSERVERS);
895 info.numServers = VLDB_MAXSERVERS;
898 for (i = 0; i < info.numServers; i++)
900 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
901 info.hostAddr[i].sin_port, USER_SERVICE_ID, sc,
906 code = ubik_ClientInit(serverconns, cstruct);
908 afs_com_err(whoami, code, "; Can't initialize ubik connection to vldb");
914 afsconf_Close(acdir);
919 * initialize a client for the backup systems ubik database.
923 udbClientInit(int noAuthFlag, int localauth, char *cellName)
925 struct ktc_principal principal;
926 struct ktc_token token;
927 struct afsconf_cell info;
928 struct afsconf_dir *acdir;
933 afsconf_Open((localauth ? AFSDIR_SERVER_ETC_DIRPATH :
934 AFSDIR_CLIENT_ETC_DIRPATH));
936 afs_com_err(whoami, 0, "Can't open configuration directory '%s'",
937 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
938 AFSDIR_CLIENT_ETC_DIRPATH));
939 ERROR(BC_NOCELLCONFIG);
945 code = afsconf_GetLocalCell(acdir, cname, sizeof(cname));
947 afs_com_err(whoami, code,
948 "; Can't get the local cell name - check %s/%s",
949 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
950 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_THISCELL_FILE);
953 strcpy(cellName, cname);
956 code = afsconf_GetCellInfo(acdir, cellName, 0, &info);
958 afs_com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
960 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
961 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_CELLSERVDB_FILE);
962 ERROR(BC_NOCELLCONFIG);
965 udbHandle.uh_scIndex = RX_SCINDEX_NULL;
968 code = afsconf_GetLatestKey(acdir, 0, 0);
970 afs_com_err(whoami, code, "; Can't get key from local key file");
974 afsconf_ClientAuth(acdir, &udbHandle.uh_secobj,
975 &udbHandle.uh_scIndex);
977 afs_com_err(whoami, code, "; Calling ClientAuth");
983 /* setup principal */
984 strcpy(principal.cell, info.name);
985 principal.instance[0] = 0;
986 strcpy(principal.name, "afs");
989 code = ktc_GetToken(&principal, &token, sizeof(token), NULL);
991 afs_com_err(whoami, code,
992 "; Can't get tokens - running unauthenticated");
994 if ((token.kvno < 0) || (token.kvno > 256))
995 afs_com_err(whoami, 0,
996 "Unexpected kvno (%d) in ticket - proceeding",
998 udbHandle.uh_scIndex = RX_SCINDEX_KAD; /* Kerberos */
1002 switch (udbHandle.uh_scIndex) {
1004 udbHandle.uh_secobj = rxnull_NewClientSecurityObject();
1008 udbHandle.uh_secobj = (struct rx_securityClass *)
1009 rxkad_NewClientSecurityObject(rxkad_clear, &token.sessionKey,
1010 token.kvno, token.ticketLen,
1015 afs_com_err(whoami, 0, "Unsupported authentication type %d",
1016 udbHandle.uh_scIndex);
1022 if (!udbHandle.uh_secobj) {
1023 afs_com_err(whoami, 0,
1024 "Can't create a security object with security index %d",
1025 udbHandle.uh_secobj);
1029 if (info.numServers > MAXSERVERS) {
1030 afs_com_err(whoami, 0,
1031 "Warning: %d BDB servers exist for cell '%s', can only remember the first %d",
1032 info.numServers, cellName, MAXSERVERS);
1033 info.numServers = MAXSERVERS;
1036 /* establish connections to the servers. Check for failed connections? */
1037 for (i = 0; i < info.numServers; i++) {
1038 udbHandle.uh_serverConn[i] =
1039 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
1040 htons(AFSCONF_BUDBPORT), BUDB_SERVICE,
1041 udbHandle.uh_secobj, udbHandle.uh_scIndex);
1043 udbHandle.uh_serverConn[i] = 0;
1045 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1047 afs_com_err(whoami, code,
1048 "; Can't initialize ubik connection to backup database");
1052 /* Try to quickly find a good site by setting deadtime low */
1053 for (i = 0; i < info.numServers; i++)
1054 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 1);
1056 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
1057 &udbHandle.uh_instanceId);
1059 /* Reset dead time back up to default */
1060 for (i = 0; i < info.numServers; i++)
1061 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 60);
1063 /* If did not find a site on first quick pass, try again */
1066 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
1067 &udbHandle.uh_instanceId);
1069 afs_com_err(whoami, code, "; Can't access backup database");
1075 afsconf_Close(acdir);
1079 /* -------------------------------------
1080 * specialized ubik support
1081 * -------------------------------------
1089 * 1) first call with SINGLESERVER set, record the server to be used.
1090 * 2) subsequent calls use that server. If a failure is encountered,
1091 * the state is cleaned up and the error returned back to the caller.
1092 * 3) upon completion, the user must make a dummy call with
1093 * END_SINGLESERVER set, to clean up state.
1094 * 4) if the vanilla ubik_Call is ever modified, the END_SINGLESERVER
1095 * flag can be discarded. The first call without SINGLESERVER set
1096 * can clean up the state.
1099 struct ubikCallState {
1100 afs_int32 ucs_flags; /* state flags */
1101 afs_int32 ucs_selectedServer; /* which server selected */
1104 static struct ubikCallState uServer;
1106 /* ubik_Call_SingleServer
1107 * variant of ubik_Call. This is used by the backup system to initiate
1108 * a series of calls to a single ubik server. The first call sets up
1109 * process state (not recorded in ubik) that requires all further calls
1110 * of that group to be made to the same server process.
1112 * call this instead of stub and we'll guarantee to find a host that's up.
1113 * in the future, we should also put in a protocol to find the sync site
1117 ubik_Call_SingleServer(int (*aproc) (), struct ubik_client *aclient,
1118 afs_int32 aflags, char *p1, char *p2, char *p3,
1119 char *p4, char *p5, char *p6, char *p7, char *p8,
1120 char *p9, char *p10, char *p11, char *p12, char *p13,
1121 char *p14, char *p15, char *p16)
1123 register afs_int32 code;
1124 afs_int32 someCode, newHost, thisHost;
1125 register afs_int32 i;
1126 register afs_int32 count;
1129 struct rx_connection *tc;
1130 struct rx_peer *rxp;
1132 if ((aflags & (UF_SINGLESERVER | UF_END_SINGLESERVER)) != 0) {
1133 if (((aflags & UF_SINGLESERVER) != 0)
1134 && ((uServer.ucs_flags & UF_SINGLESERVER) != 0)
1137 /* have a selected server */
1138 tc = aclient->conns[uServer.ucs_selectedServer];
1141 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11,
1142 p12, p13, p14, p15, p16);
1144 /* error. Clean up single server state */
1145 memset(&uServer, 0, sizeof(uServer));
1148 } else if ((aflags & UF_END_SINGLESERVER) != 0) {
1149 memset(&uServer, 0, sizeof(uServer));
1154 someCode = UNOSERVERS;
1160 /* tc is the next conn to try */
1161 tc = aclient->conns[count];
1164 pass = 1; /* in pass 1, we look at down hosts, too */
1168 break; /* nothing left to try */
1170 if (pass == 0 && (aclient->states[count] & CFLastFailed)) {
1172 continue; /* this guy's down, try someone else first */
1176 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12,
1177 p13, p14, p15, p16);
1179 /* note that getting a UNOTSYNC error code back does *not* guarantee
1180 * that there is a sync site yet elected. However, if there is a
1181 * sync site out there somewhere, and you're trying an operation that
1182 * requires a sync site, ubik will return UNOTSYNC, indicating the
1183 * operation won't work until you find a sync site
1185 if (code == UNOTSYNC) { /*ns */
1186 /* means that this requires a sync site to work */
1187 someCode = code; /* remember an error, if this fails */
1189 /* now see if we can find the sync site host */
1190 code = VOTE_GetSyncSite(tc, &newHost);
1191 if (code == 0 && newHost != 0) {
1192 newHost = htonl(newHost); /* convert back to network order */
1194 /* position count at the appropriate slot in the client
1195 * structure and retry. If we can't find in slot, we'll just
1196 * continue through the whole list
1198 for (i = 0; i < MAXSERVERS; i++) { /*f */
1199 rxp = rx_PeerOf(aclient->conns[i]);
1200 if (!(thisHost = rx_HostOf(rxp))) {
1201 count++; /* host not found, try the next dude */
1204 if (thisHost == newHost) {
1205 /* avoid asking in a loop */
1206 if (chaseCount++ > 2)
1208 count = i; /* we were told to use this one */
1213 count++; /* not directed, keep looking for a sync site */
1216 else if (code == UNOQUORUM) { /* this guy is still recovering */
1220 } else if (code < 0) { /* network errors */
1222 aclient->states[count] |= CFLastFailed;
1226 /* ok, operation worked */
1227 aclient->states[count] &= ~CFLastFailed;
1228 /* either misc ubik code, or misc application code (incl success)
1231 /* if the call succeeded, setup connection state for subsequent
1235 && ((aflags & UF_SINGLESERVER) != 0)
1237 /* need to save state */
1238 uServer.ucs_flags = UF_SINGLESERVER;
1239 uServer.ucs_selectedServer = count;
1249 /* -------------------------------------
1250 * debug and test routines
1251 * -------------------------------------
1255 * For testing only. Open a connect to the database server running on
1258 * 0 - ubik connection established in the global udbHandle structure
1265 afs_int32 serverList[MAXSERVERS];
1271 /* get our host name */
1272 gethostname(hostname, sizeof(hostname));
1273 /* strcpy(hostname, "hops"); */
1276 args[1] = "-servers";
1279 code = ubik_ParseClientList(3, args, serverList);
1281 afs_com_err(whoami, code, "; udbLocalInit: parsing ubik server list");
1285 udbHandle.uh_scIndex = RX_SCINDEX_NULL;
1286 udbHandle.uh_secobj = (struct rx_securityClass *)
1287 rxnull_NewClientSecurityObject();
1289 for (i = 0; serverList[i] != 0; i++) {
1290 udbHandle.uh_serverConn[i] =
1291 rx_NewConnection(serverList[i], htons(AFSCONF_BUDBPORT),
1292 BUDB_SERVICE, udbHandle.uh_secobj,
1293 udbHandle.uh_scIndex);
1294 if (udbHandle.uh_serverConn[i] == 0) {
1295 afs_com_err(whoami, 0, "connection %d failed", i);
1299 udbHandle.uh_serverConn[i] = 0;
1300 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1302 afs_com_err(whoami, code, "; in ubik_ClientInit");
1307 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
1308 &udbHandle.uh_instanceId);
1310 afs_com_err(whoami, code, "; Can't estblish instance Id");
1318 /* bc_openTextFile - This function opens a temp file to read in the
1319 * config text recd from the bu server. On Unix, an unlink() is done on
1320 * the file as soon as it is opened, so when the program exits, the file will
1321 * be removed automatically, while being invisible while in use.
1322 * On NT, however, the file must be explicitly deleted after use with an unlink()
1324 * Pointer to a udhClientTextP struct. The open stream ptr is stored in
1325 * the udbClientTextP.textStream member.
1326 * Output: The temp file name is returned in tmpFileName. This should be used
1327 * to delete the file when done with it.
1333 bc_openTextFile(udbClientTextP ctPtr, char *tmpFileName)
1337 if (ctPtr->textStream != NULL)
1338 fclose(ctPtr->textStream);
1340 sprintf(tmpFileName, "%s/bu_XXXXXX", gettmpdir());
1341 #ifdef AFS_LINUX20_ENV
1342 mkstemp(tmpFileName);
1344 mktemp(tmpFileName);
1346 ctPtr->textStream = fopen(tmpFileName, "w+");
1347 if (ctPtr->textStream == NULL)
1348 ERROR(BUDB_INTERNALERROR);
1350 #ifndef AFS_NT40_ENV /* This can't be done on NT */
1351 /* make the file invisible to others */
1352 code = unlink(tmpFileName);
1357 afs_dprintf(("file is %s\n", tmpFileName));
1363 if (ctPtr->textStream != NULL) {
1364 fclose(ctPtr->textStream);
1365 ctPtr->textStream = NULL;
1371 /* bc_closeTextFile: This function closes any actual temp files associated with
1372 * a udbClientText structure.
1373 * Input: ctPtr->textStream - stream to close
1374 * tmpFileName - temp file name to delete
1380 bc_closeTextFile(udbClientTextP ctPtr, char *tmpFileName)
1384 if (ctPtr->textStream)
1385 fclose(ctPtr->textStream);
1387 if (*tmpFileName) { /* we have a valid name */
1388 code = unlink(tmpFileName);