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>
18 #include <sys/types.h>
22 #elif defined(AFS_SUN5_ENV)
25 #include <sys/param.h> /* for hostnames etc */
28 #include <afs/cellconfig.h>
30 #include <afs/volser.h>
31 #include <afs/afsutil.h>
32 #include <afs/bubasics.h>
33 #include <afs/budb_client.h>
35 #include <afs/com_err.h>
39 #include "error_macros.h"
42 afs_int32 bcdb_AddVolume(register struct budb_volumeEntry *);
43 afs_int32 bcdb_AddVolumes(register struct budb_volumeEntry *, afs_int32 );
44 afs_int32 bcdb_CreateDump(register struct budb_dumpEntry *) ;
45 afs_int32 bcdb_deleteDump(afs_int32, afs_int32, afs_int32, budb_dumpsList *);
46 /*note the pinter to the function comes from ubik/ubikclient ubik_Call function.*/
47 afs_int32 bcdb_listDumps (int (), afs_int32,afs_int32,afs_int32, budb_dumpsList *,
49 afs_int32 bcdb_DeleteVDP(char *, char *, afs_int32 );
50 afs_int32 bcdb_FindClone(afs_int32, char *, afs_int32 *);
54 /* -------------------------------------
56 * -------------------------------------
59 struct udbHandleS udbHandle;
61 /* -------------------------------------
62 * interface routines (alphabetic)
63 * -------------------------------------
66 afs_int32 bcdb_AddVolume(register struct budb_volumeEntry *veptr)
70 code = ubik_Call(BUDB_AddVolume, udbHandle.uh_client, 0, veptr);
74 afs_int32 bcdb_AddVolumes(register struct budb_volumeEntry *veptr, afs_int32 count)
76 struct budb_volumeList volumeList;
79 volumeList.budb_volumeList_len = count;
80 volumeList.budb_volumeList_val = veptr;
81 code = ubik_Call(BUDB_AddVolumes, udbHandle.uh_client, 0, &volumeList);
86 afs_int32 bcdb_CreateDump(register struct budb_dumpEntry *deptr)
90 code = ubik_Call(BUDB_CreateDump, udbHandle.uh_client, 0, deptr);
94 afs_int32 bcdb_deleteDump(afs_int32 dumpID, afs_int32 fromTime, afs_int32 toTime,
95 budb_dumpsList *dumps)
98 budb_dumpsList dumpsList, *dumpsPtr;
100 dumpsList.budb_dumpsList_len = 0;
101 dumpsList.budb_dumpsList_val = 0;
102 dumpsPtr = (dumps ? dumps : &dumpsList);
105 ubik_Call(BUDB_DeleteDump, udbHandle.uh_client, 0, dumpID, fromTime,
107 if (dumpsList.budb_dumpsList_val)
108 free(dumpsList.budb_dumpsList_val);
112 afs_int32 bcdb_listDumps (int (*sflags) (), afs_int32 groupId,afs_int32 fromTime, afs_int32 toTime,budb_dumpsList *dumps, budb_dumpsList *flags)
114 afs_int32 code, sflag = 0;
115 budb_dumpsList dumpsList, *dumpsPtr;
116 budb_dumpsList flagsList, *flagsPtr;
118 dumpsList.budb_dumpsList_len = 0;
119 dumpsList.budb_dumpsList_val = 0;
120 dumpsPtr = (dumps ? dumps : &dumpsList);
122 flagsList.budb_dumpsList_len = 0;
123 flagsList.budb_dumpsList_val = 0;
124 flagsPtr = (flags ? flags : &flagsList);
127 ubik_Call(BUDB_ListDumps, udbHandle.uh_client, 0, sflags, "", groupId,
128 fromTime, toTime, dumpsPtr, flagsPtr);
130 if (dumpsList.budb_dumpsList_val)
131 free(dumpsList.budb_dumpsList_val);
132 if (flagsList.budb_dumpsList_val)
133 free(flagsList.budb_dumpsList_val);
138 afs_int32 bcdb_DeleteVDP(char *dumpSetName, char *dumpPath, afs_int32 dumpID)
143 ubik_Call(BUDB_DeleteVDP, udbHandle.uh_client, 0, dumpSetName,
149 * Returns the clone time of a volume by going up the parent chain.
150 * If no clone time is found, a clone time of 0 is returned, forcing
153 * dumpID - of the first dump to examine.
154 * volName - name of the volume for whom a clone time is required
155 * clonetime - ptr to vbl for returning result
157 * 0 - clonetime set appropriately
158 * -1 - error occured in traversing chain, clone time set to 0.
159 * -2 - no clone times found, clone time set to 0
162 afs_int32 bcdb_FindClone(afs_int32 dumpID, char *volName, afs_int32 *clonetime)
166 ubik_Call(BUDB_FindClone, udbHandle.uh_client, 0, dumpID, volName,
172 * scan entire database for latest volume dump before adate. Optimize
173 * further by reading only the first line of the dump and if it is older
174 * than the oldest acceptable dump we've found so far, we don't bother
175 * scanning the dump file we've just opened
177 * Used by restore code when restoring a user requested volume(s)
179 * volumeName - name of volume to match on
180 * beforeDate - look for dumps older than this date
182 * deptr - desciptor of most recent dump
184 * should be able to implement this in a single call rather than
185 * the current multiple bcdb_ call algorithm.
188 bcdb_FindDump(volumeName, beforeDate, deptr)
190 afs_int32 beforeDate;
191 struct budb_dumpEntry *deptr;
195 ubik_Call(BUDB_FindDump, udbHandle.uh_client, 0, volumeName,
201 * find a dump by id. Currently insists on a single return value.
203 * dumpID - id to lookup
206 bcdb_FindDumpByID(dumpID, deptr)
208 register struct budb_dumpEntry *deptr;
210 register afs_int32 code;
215 /* initialize the dump list */
216 dl.budb_dumpList_len = 0;
217 dl.budb_dumpList_val = 0;
219 /* outline algorithm */
220 code = ubik_Call(BUDB_GetDumps, udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_DUMPID, "", /* no name */
224 &nextindex, &dbTime, &dl);
227 || (dl.budb_dumpList_len != 1) /* single retn val expected */
229 /* printf("bcdb_FindDumpByID: code %d, nvalues %d\n",
230 code, dl.budb_dumpList_len); */
232 code = 1; /* multiple id's */
236 memcpy(deptr, dl.budb_dumpList_val, sizeof(*deptr));
239 if (dl.budb_dumpList_val) {
240 /* free any allocated structures */
241 free(dl.budb_dumpList_val);
246 memset(deptr, 0, sizeof(*deptr));
250 /* bcdb_FindLastVolClone
251 * Returns the clone time, from the most recent dump of volName, when
252 * dumped in the volume set volSetName, with dump schedule dumpName.
253 * The clone time can be used to check if the volume has been correctly
254 * re-cloned, and also is used as the time from which to do the current
257 * volSetName - name of volume set
258 * dumpName - full path of dump node
259 * volName - name of volume for whom a clone time is required
260 * clonetime - ptr to vbl for result
262 * 0 - clonetime set appropriately
264 * used only for warning generation. Suggest that this be omitted.
268 bcdb_FindLastVolClone(volSetName, dumpName, volName, clonetime)
272 afs_int32 *clonetime;
276 * match on volumeset and dump path
277 * search for the volume name
282 /* bcdb_FindLatestDump
283 * find the latest dump with volume set component avname and the
284 * specified dump pathname. Used to find a dump, relative to which an
285 * incremental dump can be done. Defines the parent <-> child relations
288 * avname: volume set name
289 * dumpPath: full path of dump node
291 * 0: adentry: dump entry structure filled in.
292 * -1: probably an internal error
295 * Need to store volumeset name in dump in order to implement this.
296 * Need new routine since params are two strings
299 bcdb_FindLatestDump(volSetName, dumpPath, deptr)
302 struct budb_dumpEntry *deptr;
306 ubik_Call(BUDB_FindLatestDump, udbHandle.uh_client, 0, volSetName,
315 * dumpid: dump id to which tape beint32s
316 * tapeName: name of tape
319 bcdb_FindTape(dumpid, tapeName, teptr)
322 struct budb_tapeEntry *teptr;
329 memset(teptr, 0, sizeof(*teptr));
330 tl.budb_tapeList_len = 0;
331 tl.budb_tapeList_val = 0;
334 ubik_Call(BUDB_GetTapes, udbHandle.uh_client, 0, BUDB_MAJORVERSION,
335 BUDB_OP_TAPENAME | BUDB_OP_DUMPID, tapeName, dumpid, 0, 0,
336 &next, &dbTime, &tl);
341 if (tl.budb_tapeList_len != 1)
342 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
344 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
347 if (tl.budb_tapeList_val)
348 free(tl.budb_tapeList_val);
352 bcdb_FindTapeSeq(dumpid, tapeSeq, teptr)
355 struct budb_tapeEntry *teptr;
362 memset(teptr, 0, sizeof(*teptr));
363 tl.budb_tapeList_len = 0;
364 tl.budb_tapeList_val = 0;
367 ubik_Call(BUDB_GetTapes, udbHandle.uh_client, 0, BUDB_MAJORVERSION,
368 BUDB_OP_TAPESEQ | BUDB_OP_DUMPID, "", dumpid, tapeSeq, 0,
369 &next, &dbTime, &tl);
373 if (tl.budb_tapeList_len != 1)
374 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
376 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
379 if (tl.budb_tapeList_val)
380 free(tl.budb_tapeList_val);
386 * - this is part of dblookup. The existing semantics will not work since
387 * they do lookups based on dump id.
388 * - in the restore code, it uses this to extract information about
389 * the volume. Need current semantics. Could filter the output, selecting
391 * - Suggest that the lookup be based on volume name only, with optional
392 * match on backup, and readonly volumes.
393 * - Further, need to check if the volume structure returns enough
398 bcdb_FindVolumes(dumpID, volumeName, returnArray, last, next, maxa, nEntries)
401 struct budb_volumeEntry *returnArray;
411 vl.budb_volumeList_len = maxa;
412 vl.budb_volumeList_val = returnArray;
414 /* outline algorithm */
415 code = ubik_Call(BUDB_GetVolumes, udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME | BUDB_OP_DUMPID, volumeName, /* name */
419 next, /* nextindex */
422 *nEntries = vl.budb_volumeList_len;
427 bcdb_FinishDump(deptr)
428 register struct budb_dumpEntry *deptr;
431 code = ubik_Call(BUDB_FinishDump, udbHandle.uh_client, 0, deptr);
435 bcdb_FinishTape(teptr)
436 register struct budb_tapeEntry *teptr;
439 code = ubik_Call(BUDB_FinishTape, udbHandle.uh_client, 0, teptr);
444 /* bcdb_LookupVolumes
448 bcdb_LookupVolume(volumeName, returnArray, last, next, maxa, nEntries)
450 struct budb_volumeEntry *returnArray;
460 vl.budb_volumeList_len = maxa;
461 vl.budb_volumeList_val = returnArray;
463 /* outline algorithm */
464 code = ubik_Call(BUDB_GetVolumes, udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME, volumeName, /* name */
468 next, /* nextindex */
474 *nEntries = vl.budb_volumeList_len;
479 bcdb_UseTape(teptr, newFlag)
480 register struct budb_tapeEntry *teptr;
484 code = ubik_Call(BUDB_UseTape, udbHandle.uh_client, 0, teptr, newFlag);
489 /* ---- text configuration handling routines ----
492 * The caller should pass in/out a fid for an unlinked, open file to prevent
493 * tampering with the files contents;
497 * extract the specified textType and put it in a temporary, local
500 * ctPtr - ptr to client structure with all the required information
503 bcdb_GetTextFile(register udbClientTextP ctPtr)
505 afs_int32 bufferSize;
506 afs_int32 offset, nextOffset;
510 /* Initialize charlistT_val. We try to deallocate this structure based on
512 memset((void *)&charList, 0, sizeof(charList));
514 /* check params and cleanup any previous state */
515 if (ctPtr->lockHandle == 0)
516 ERROR(BUDB_INTERNALERROR);
518 if (ctPtr->textStream == NULL) /* Should have an open stream */
519 ERROR(BUDB_INTERNALERROR);
521 /* allocate a buffer */
523 charList.charListT_val = (char *)malloc(bufferSize);
524 if (charList.charListT_val == 0)
525 ERROR(BUDB_INTERNALERROR);
526 charList.charListT_len = bufferSize;
531 while (nextOffset != -1) {
533 charList.charListT_len = bufferSize;
535 ubik_Call(BUDB_GetText, udbHandle.uh_client, 0, ctPtr->lockHandle,
536 ctPtr->textType, bufferSize, offset, &nextOffset,
543 fwrite(charList.charListT_val, sizeof(char),
544 charList.charListT_len, ctPtr->textStream);
545 if (ferror(ctPtr->textStream))
546 ERROR(BUDB_INTERNALERROR);
548 ctPtr->textSize += charList.charListT_len;
551 /* get text version */
553 ubik_Call(BUDB_GetTextVersion, udbHandle.uh_client, 0,
554 ctPtr->textType, &ctPtr->textVersion);
559 fflush(ctPtr->textStream); /* debug */
561 /* exit, leaving the configuration text file open */
562 if (charList.charListT_val)
563 free(charList.charListT_val);
567 if (ctPtr->textStream != NULL) {
568 fclose(ctPtr->textStream);
569 ctPtr->textStream = NULL;
576 * save the text file in ubik database
578 * textType - identifies type of configuration file
579 * filename - where to get the text from
582 bcdb_SaveTextFile(ctPtr)
583 udbClientTextP ctPtr;
585 afs_int32 bufferSize;
586 afs_int32 offset, chunkSize, fileSize;
589 afs_int32 filesize();
591 /* allocate a buffer */
593 charList.charListT_val = (char *)malloc(bufferSize);
594 if (charList.charListT_val == 0)
595 ERROR(BUDB_INTERNALERROR);
596 charList.charListT_len = bufferSize;
598 if (ctPtr->textStream == NULL)
599 ERROR(BUDB_INTERNALERROR);
600 rewind(ctPtr->textStream);
602 fileSize = (afs_int32) filesize(ctPtr->textStream);
604 dprintf(("filesize is %d\n", fileSize));
606 rewind(ctPtr->textStream);
608 /* special case empty files */
610 charList.charListT_len = 0;
612 ubik_Call(BUDB_SaveText, udbHandle.uh_client, 0,
613 ctPtr->lockHandle, ctPtr->textType, 0,
614 BUDB_TEXT_COMPLETE, &charList);
619 while (fileSize != 0) {
620 chunkSize = MIN(fileSize, bufferSize);
622 fread(charList.charListT_val, sizeof(char), chunkSize,
625 if (code != chunkSize)
626 printf("code = %d\n", code);
627 if (ferror(ctPtr->textStream))
628 ERROR(BUDB_INTERNALERROR);
630 charList.charListT_len = chunkSize;
632 ubik_Call(BUDB_SaveText, udbHandle.uh_client, 0,
633 ctPtr->lockHandle, ctPtr->textType, offset,
634 (chunkSize == fileSize) ? BUDB_TEXT_COMPLETE : 0,
639 fileSize -= chunkSize;
644 /* if ( ctPtr->textStream >= 0 )
645 * close(ctPtr->textStream); */
646 if (charList.charListT_val)
647 free(charList.charListT_val);
651 bcdb_FindLastTape(dumpID, dumpEntry, tapeEntry, volEntry)
653 struct budb_dumpEntry *dumpEntry;
654 struct budb_tapeEntry *tapeEntry;
655 struct budb_volumeEntry *volEntry;
658 (BUDB_FindLastTape, udbHandle.uh_client, 0, dumpID, dumpEntry,
659 tapeEntry, volEntry));
662 bcdb_MakeDumpAppended(appendedDumpID, initialDumpID, startTapeSeq)
663 afs_int32 appendedDumpID;
664 afs_int32 initialDumpID;
665 afs_int32 startTapeSeq;
668 (BUDB_MakeDumpAppended, udbHandle.uh_client, 0, appendedDumpID,
669 initialDumpID, startTapeSeq));
673 /* -------------------------------------
674 * misc. support routines
675 * -------------------------------------
685 offset = ftell(stream);
686 fseek(stream, (afs_int32) 0, 2); /* end of file */
687 size = ftell(stream);
688 fseek(stream, offset, 0);
693 /* ------------------------------------
694 * misc. support routines - general text management
695 * ------------------------------------
700 * locks the text described by the ctPtr
702 * ctptr - client text ptr
709 register udbClientTextP ctPtr;
712 afs_int32 timeout, j = 0;
714 if (ctPtr->lockHandle != 0)
715 return (1); /* already locked */
718 ((ctPtr->textSize == 0) ? 30 : ((ctPtr->textSize / 50000) + 10));
722 ubik_Call(BUDB_GetLock, udbHandle.uh_client, 0,
723 udbHandle.uh_instanceId, ctPtr->textType, timeout,
725 if ((code != BUDB_LOCKED) && (code != BUDB_SELFLOCKED)) {
729 /* Mention something every 30 seconds */
731 afs_com_err(whoami, code,
732 "; Waiting for db configuration text unlock");
735 #ifdef AFS_PTHREAD_ENV
744 ctPtr->lockHandle = 0;
749 * unlocks the text described by the ctPtr
751 * ctptr - client text ptr
758 register udbClientTextP ctPtr;
762 if (ctPtr->lockHandle == 0)
766 ubik_Call(BUDB_FreeLock, udbHandle.uh_client, 0, ctPtr->lockHandle);
767 ctPtr->lockHandle = 0;
769 /* Don't try to analyse the error. Let the lock timeout */
773 /* bc_CheckTextVersion
776 * n - out of date or error
779 bc_CheckTextVersion(ctPtr)
780 register udbClientTextP ctPtr;
785 if (ctPtr->textVersion == -1)
786 return (BC_VERSIONMISMATCH);
789 ubik_Call(BUDB_GetTextVersion, udbHandle.uh_client, 0,
790 ctPtr->textType, &tversion);
793 if (tversion != ctPtr->textVersion)
794 return (BC_VERSIONMISMATCH);
798 /* -------------------------------------
799 * initialization routines
800 * -------------------------------------
804 * Initialize a client for the vl ubik database.
806 vldbClientInit(noAuthFlag, localauth, cellName, cstruct, ttoken)
810 struct ubik_client **cstruct;
811 struct ktc_token *ttoken;
814 struct afsconf_dir *acdir;
815 struct rc_securityClass *sc;
816 afs_int32 i, scIndex = 0; /* Index of Rx security object - noauth */
817 struct afsconf_cell info;
818 struct ktc_principal sname;
819 struct rx_connection *serverconns[VLDB_MAXSERVERS];
822 /* Find out about the given cell */
824 afsconf_Open((localauth ? AFSDIR_SERVER_ETC_DIRPATH :
825 AFSDIR_CLIENT_ETC_DIRPATH));
827 afs_com_err(whoami, 0, "Can't open configuration directory '%s'",
828 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
829 AFSDIR_CLIENT_ETC_DIRPATH));
830 ERROR(BC_NOCELLCONFIG);
836 code = afsconf_GetLocalCell(acdir, cname, sizeof(cname));
838 afs_com_err(whoami, code,
839 "; Can't get the local cell name - check %s/%s",
840 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
841 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_THISCELL_FILE);
844 strcpy(cellName, cname);
847 code = afsconf_GetCellInfo(acdir, cellName, AFSCONF_VLDBSERVICE, &info);
849 afs_com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
851 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
852 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_CELLSERVDB_FILE);
853 ERROR(BC_NOCELLCONFIG);
857 * Grab tickets if we care about authentication.
861 code = afsconf_GetLatestKey(acdir, 0, 0);
863 afs_com_err(whoami, code, "; Can't get key from local key file");
866 code = afsconf_ClientAuth(acdir, &sc, &scIndex);
868 afs_com_err(whoami, code, "; Calling ClientAuth");
872 ttoken->endTime = NEVERDATE;
876 strcpy(sname.cell, info.name);
877 sname.instance[0] = 0;
878 strcpy(sname.name, "afs");
881 ktc_GetToken(&sname, ttoken, sizeof(struct ktc_token), NULL);
883 afs_com_err(whoami, code, 0,
884 "; Can't get AFS tokens - running unauthenticated");
886 if ((ttoken->kvno < 0) || (ttoken->kvno > 255))
887 afs_com_err(whoami, 0,
888 "Funny kvno (%d) in ticket, proceeding",
897 sc = rxnull_NewClientSecurityObject();
900 sc = (struct rx_securityClass *)
901 rxkad_NewClientSecurityObject(rxkad_clear,
903 ttoken->kvno, ttoken->ticketLen,
907 afs_com_err(whoami, 0, "Unsupported authentication type %d", scIndex);
914 afs_com_err(whoami, 0,
915 "Can't create a security object with security index %d",
920 /* tell UV module about default authentication */
921 UV_SetSecurity(sc, scIndex);
923 if (info.numServers > VLDB_MAXSERVERS) {
924 afs_com_err(whoami, 0,
925 "Warning: %d VLDB servers exist for cell '%s', can only remember the first %d",
926 info.numServers, cellName, VLDB_MAXSERVERS);
927 info.numServers = VLDB_MAXSERVERS;
930 for (i = 0; i < info.numServers; i++)
932 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
933 info.hostAddr[i].sin_port, USER_SERVICE_ID, sc,
938 code = ubik_ClientInit(serverconns, cstruct);
940 afs_com_err(whoami, code, "; Can't initialize ubik connection to vldb");
946 afsconf_Close(acdir);
951 * initialize a client for the backup systems ubik database.
955 udbClientInit(noAuthFlag, localauth, cellName)
960 struct ktc_principal principal;
961 struct ktc_token token;
962 struct afsconf_cell info;
963 struct afsconf_dir *acdir;
968 afsconf_Open((localauth ? AFSDIR_SERVER_ETC_DIRPATH :
969 AFSDIR_CLIENT_ETC_DIRPATH));
971 afs_com_err(whoami, 0, "Can't open configuration directory '%s'",
972 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
973 AFSDIR_CLIENT_ETC_DIRPATH));
974 ERROR(BC_NOCELLCONFIG);
980 code = afsconf_GetLocalCell(acdir, cname, sizeof(cname));
982 afs_com_err(whoami, code,
983 "; Can't get the local cell name - check %s/%s",
984 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
985 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_THISCELL_FILE);
988 strcpy(cellName, cname);
991 code = afsconf_GetCellInfo(acdir, cellName, 0, &info);
993 afs_com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
995 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
996 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_CELLSERVDB_FILE);
997 ERROR(BC_NOCELLCONFIG);
1000 udbHandle.uh_scIndex = RX_SCINDEX_NULL;
1003 code = afsconf_GetLatestKey(acdir, 0, 0);
1005 afs_com_err(whoami, code, "; Can't get key from local key file");
1009 afsconf_ClientAuth(acdir, &udbHandle.uh_secobj,
1010 &udbHandle.uh_scIndex);
1012 afs_com_err(whoami, code, "; Calling ClientAuth");
1018 /* setup principal */
1019 strcpy(principal.cell, info.name);
1020 principal.instance[0] = 0;
1021 strcpy(principal.name, "afs");
1024 code = ktc_GetToken(&principal, &token, sizeof(token), NULL);
1026 afs_com_err(whoami, code,
1027 "; Can't get tokens - running unauthenticated");
1029 if ((token.kvno < 0) || (token.kvno > 255))
1030 afs_com_err(whoami, 0,
1031 "Unexpected kvno (%d) in ticket - proceeding",
1033 udbHandle.uh_scIndex = RX_SCINDEX_KAD; /* Kerberos */
1037 switch (udbHandle.uh_scIndex) {
1039 udbHandle.uh_secobj = rxnull_NewClientSecurityObject();
1043 udbHandle.uh_secobj = (struct rx_securityClass *)
1044 rxkad_NewClientSecurityObject(rxkad_clear, &token.sessionKey,
1045 token.kvno, token.ticketLen,
1050 afs_com_err(whoami, 0, "Unsupported authentication type %d",
1051 udbHandle.uh_scIndex);
1057 if (!udbHandle.uh_secobj) {
1058 afs_com_err(whoami, 0,
1059 "Can't create a security object with security index %d",
1060 udbHandle.uh_secobj);
1064 if (info.numServers > MAXSERVERS) {
1065 afs_com_err(whoami, 0,
1066 "Warning: %d BDB servers exist for cell '%s', can only remember the first %d",
1067 info.numServers, cellName, MAXSERVERS);
1068 info.numServers = MAXSERVERS;
1071 /* establish connections to the servers. Check for failed connections? */
1072 for (i = 0; i < info.numServers; i++) {
1073 udbHandle.uh_serverConn[i] =
1074 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
1075 htons(AFSCONF_BUDBPORT), BUDB_SERVICE,
1076 udbHandle.uh_secobj, udbHandle.uh_scIndex);
1078 udbHandle.uh_serverConn[i] = 0;
1080 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1082 afs_com_err(whoami, code,
1083 "; Can't initialize ubik connection to backup database");
1087 /* Try to quickly find a good site by setting deadtime low */
1088 for (i = 0; i < info.numServers; i++)
1089 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 1);
1091 ubik_Call(BUDB_GetInstanceId, udbHandle.uh_client, 0,
1092 &udbHandle.uh_instanceId);
1094 /* Reset dead time back up to default */
1095 for (i = 0; i < info.numServers; i++)
1096 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 60);
1098 /* If did not find a site on first quick pass, try again */
1101 ubik_Call(BUDB_GetInstanceId, udbHandle.uh_client, 0,
1102 &udbHandle.uh_instanceId);
1104 afs_com_err(whoami, code, "; Can't access backup database");
1110 afsconf_Close(acdir);
1114 /* -------------------------------------
1115 * specialized ubik support
1116 * -------------------------------------
1124 * 1) first call with SINGLESERVER set, record the server to be used.
1125 * 2) subsequent calls use that server. If a failure is encountered,
1126 * the state is cleaned up and the error returned back to the caller.
1127 * 3) upon completion, the user must make a dummy call with
1128 * END_SINGLESERVER set, to clean up state.
1129 * 4) if the vanilla ubik_Call is ever modified, the END_SINGLESERVER
1130 * flag can be discarded. The first call without SINGLESERVER set
1131 * can clean up the state.
1134 struct ubikCallState {
1135 afs_int32 ucs_flags; /* state flags */
1136 afs_int32 ucs_selectedServer; /* which server selected */
1139 static struct ubikCallState uServer;
1141 /* ubik_Call_SingleServer
1142 * variant of ubik_Call. This is used by the backup system to initiate
1143 * a series of calls to a single ubik server. The first call sets up
1144 * process state (not recorded in ubik) that requires all further calls
1145 * of that group to be made to the same server process.
1147 * call this instead of stub and we'll guarantee to find a host that's up.
1148 * in the future, we should also put in a protocol to find the sync site
1152 ubik_Call_SingleServer(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8,
1153 p9, p10, p11, p12, p13, p14, p15, p16)
1154 register struct ubik_client *aclient;
1157 char *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13,
1160 register afs_int32 code;
1161 afs_int32 someCode, newHost, thisHost;
1162 register afs_int32 i;
1163 register afs_int32 count;
1166 struct rx_connection *tc;
1167 struct rx_peer *rxp;
1169 if ((aflags & (UF_SINGLESERVER | UF_END_SINGLESERVER)) != 0) {
1170 if (((aflags & UF_SINGLESERVER) != 0)
1171 && ((uServer.ucs_flags & UF_SINGLESERVER) != 0)
1174 /* have a selected server */
1175 tc = aclient->conns[uServer.ucs_selectedServer];
1178 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11,
1179 p12, p13, p14, p15, p16);
1181 /* error. Clean up single server state */
1182 memset(&uServer, 0, sizeof(uServer));
1185 } else if ((aflags & UF_END_SINGLESERVER) != 0) {
1186 memset(&uServer, 0, sizeof(uServer));
1191 someCode = UNOSERVERS;
1197 /* tc is the next conn to try */
1198 tc = aclient->conns[count];
1201 pass = 1; /* in pass 1, we look at down hosts, too */
1205 break; /* nothing left to try */
1207 if (pass == 0 && (aclient->states[count] & CFLastFailed)) {
1209 continue; /* this guy's down, try someone else first */
1213 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12,
1214 p13, p14, p15, p16);
1216 /* note that getting a UNOTSYNC error code back does *not* guarantee
1217 * that there is a sync site yet elected. However, if there is a
1218 * sync site out there somewhere, and you're trying an operation that
1219 * requires a sync site, ubik will return UNOTSYNC, indicating the
1220 * operation won't work until you find a sync site
1222 if (code == UNOTSYNC) { /*ns */
1223 /* means that this requires a sync site to work */
1224 someCode = code; /* remember an error, if this fails */
1226 /* now see if we can find the sync site host */
1227 code = VOTE_GetSyncSite(tc, &newHost);
1228 if (code == 0 && newHost != 0) {
1229 newHost = htonl(newHost); /* convert back to network order */
1231 /* position count at the appropriate slot in the client
1232 * structure and retry. If we can't find in slot, we'll just
1233 * continue through the whole list
1235 for (i = 0; i < MAXSERVERS; i++) { /*f */
1236 rxp = rx_PeerOf(aclient->conns[i]);
1237 if (!(thisHost = rx_HostOf(rxp))) {
1238 count++; /* host not found, try the next dude */
1241 if (thisHost == newHost) {
1242 /* avoid asking in a loop */
1243 if (chaseCount++ > 2)
1245 count = i; /* we were told to use this one */
1250 count++; /* not directed, keep looking for a sync site */
1253 else if (code == UNOQUORUM) { /* this guy is still recovering */
1257 } else if (code < 0) { /* network errors */
1259 aclient->states[count] |= CFLastFailed;
1263 /* ok, operation worked */
1264 aclient->states[count] &= ~CFLastFailed;
1265 /* either misc ubik code, or misc application code (incl success)
1268 /* if the call succeeded, setup connection state for subsequent
1272 && ((aflags & UF_SINGLESERVER) != 0)
1274 /* need to save state */
1275 uServer.ucs_flags = UF_SINGLESERVER;
1276 uServer.ucs_selectedServer = count;
1286 /* -------------------------------------
1287 * debug and test routines
1288 * -------------------------------------
1292 * For testing only. Open a connect to the database server running on
1295 * 0 - ubik connection established in the global udbHandle structure
1301 afs_int32 serverList[MAXSERVERS];
1307 /* get our host name */
1308 gethostname(hostname, sizeof(hostname));
1309 /* strcpy(hostname, "hops"); */
1312 args[1] = "-servers";
1315 code = ubik_ParseClientList(3, args, serverList);
1317 afs_com_err(whoami, code, "; udbLocalInit: parsing ubik server list");
1321 udbHandle.uh_scIndex = RX_SCINDEX_NULL;
1322 udbHandle.uh_secobj = (struct rx_securityClass *)
1323 rxnull_NewClientSecurityObject();
1325 for (i = 0; serverList[i] != 0; i++) {
1326 udbHandle.uh_serverConn[i] =
1327 rx_NewConnection(serverList[i], htons(AFSCONF_BUDBPORT),
1328 BUDB_SERVICE, udbHandle.uh_secobj,
1329 udbHandle.uh_scIndex);
1330 if (udbHandle.uh_serverConn[i] == 0) {
1331 afs_com_err(whoami, 0, "connection %d failed", i);
1335 udbHandle.uh_serverConn[i] = 0;
1336 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1338 afs_com_err(whoami, code, "; in ubik_ClientInit");
1343 ubik_Call(BUDB_GetInstanceId, udbHandle.uh_client, 0,
1344 &udbHandle.uh_instanceId);
1346 afs_com_err(whoami, code, "; Can't estblish instance Id");
1354 /* bc_openTextFile - This function opens a temp file to read in the
1355 * config text recd from the bu server. On Unix, an unlink() is done on
1356 * the file as soon as it is opened, so when the program exits, the file will
1357 * be removed automatically, while being invisible while in use.
1358 * On NT, however, the file must be explicitly deleted after use with an unlink()
1360 * Pointer to a udhClientTextP struct. The open stream ptr is stored in
1361 * the udbClientTextP.textStream member.
1362 * Output: The temp file name is returned in tmpFileName. This should be used
1363 * to delete the file when done with it.
1369 bc_openTextFile(udbClientTextP ctPtr, char *tmpFileName)
1373 if (ctPtr->textStream != NULL)
1374 fclose(ctPtr->textStream);
1376 sprintf(tmpFileName, "%s/bu_XXXXXX", gettmpdir());
1377 #ifdef AFS_LINUX20_ENV
1378 mkstemp(tmpFileName);
1380 mktemp(tmpFileName);
1382 ctPtr->textStream = fopen(tmpFileName, "w+");
1383 if (ctPtr->textStream == NULL)
1384 ERROR(BUDB_INTERNALERROR);
1386 #ifndef AFS_NT40_ENV /* This can't be done on NT */
1387 /* make the file invisible to others */
1388 code = unlink(tmpFileName);
1393 dprintf(("file is %s\n", tmpFileName));
1399 if (ctPtr->textStream != NULL) {
1400 fclose(ctPtr->textStream);
1401 ctPtr->textStream = NULL;
1407 /* bc_closeTextFile: This function closes any actual temp files associated with
1408 * a udbClientText structure.
1409 * Input: ctPtr->textStream - stream to close
1410 * tmpFileName - temp file name to delete
1416 bc_closeTextFile(udbClientTextP ctPtr, char *tmpFileName)
1420 if (ctPtr->textStream)
1421 fclose(ctPtr->textStream);
1423 if (*tmpFileName) { /* we have a valid name */
1424 code = unlink(tmpFileName);