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>
13 #include <afs/param.h>
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>
39 #include "error_macros.h"
43 /* -------------------------------------
45 * -------------------------------------
48 struct udbHandleS udbHandle;
50 /* -------------------------------------
51 * interface routines (alphabetic)
52 * -------------------------------------
56 register struct budb_volumeEntry *veptr;
60 code = ubik_Call(BUDB_AddVolume, udbHandle.uh_client, 0, veptr);
64 bcdb_AddVolumes(veptr, count)
65 register struct budb_volumeEntry *veptr;
68 struct budb_volumeList volumeList;
71 volumeList.budb_volumeList_len = count;
72 volumeList.budb_volumeList_val = veptr;
73 code = ubik_Call(BUDB_AddVolumes, udbHandle.uh_client, 0, &volumeList);
78 bcdb_CreateDump(deptr)
79 register struct budb_dumpEntry *deptr;
83 code = ubik_Call(BUDB_CreateDump, udbHandle.uh_client, 0, deptr);
87 bcdb_deleteDump(dumpID, fromTime, toTime, dumps)
91 budb_dumpsList *dumps;
94 budb_dumpsList dumpsList, *dumpsPtr;
96 dumpsList.budb_dumpsList_len = 0;
97 dumpsList.budb_dumpsList_val = 0;
98 dumpsPtr = (dumps ? dumps : &dumpsList);
101 ubik_Call(BUDB_DeleteDump, udbHandle.uh_client, 0, dumpID, fromTime,
103 if (dumpsList.budb_dumpsList_val)
104 free(dumpsList.budb_dumpsList_val);
108 bcdb_listDumps(sflags, groupId, fromTime, toTime, dumps, flags)
112 budb_dumpsList *dumps;
113 budb_dumpsList *flags;
115 afs_int32 code, sflag = 0;
116 budb_dumpsList dumpsList, *dumpsPtr;
117 budb_dumpsList flagsList, *flagsPtr;
119 dumpsList.budb_dumpsList_len = 0;
120 dumpsList.budb_dumpsList_val = 0;
121 dumpsPtr = (dumps ? dumps : &dumpsList);
123 flagsList.budb_dumpsList_len = 0;
124 flagsList.budb_dumpsList_val = 0;
125 flagsPtr = (flags ? flags : &flagsList);
128 ubik_Call(BUDB_ListDumps, udbHandle.uh_client, 0, sflags, "", groupId,
129 fromTime, toTime, dumpsPtr, flagsPtr);
131 if (dumpsList.budb_dumpsList_val)
132 free(dumpsList.budb_dumpsList_val);
133 if (flagsList.budb_dumpsList_val)
134 free(flagsList.budb_dumpsList_val);
139 bcdb_DeleteVDP(dumpSetName, dumpPath, dumpID)
147 ubik_Call(BUDB_DeleteVDP, udbHandle.uh_client, 0, dumpSetName,
153 * Returns the clone time of a volume by going up the parent chain.
154 * If no clone time is found, a clone time of 0 is returned, forcing
157 * dumpID - of the first dump to examine.
158 * volName - name of the volume for whom a clone time is required
159 * clonetime - ptr to vbl for returning result
161 * 0 - clonetime set appropriately
162 * -1 - error occured in traversing chain, clone time set to 0.
163 * -2 - no clone times found, clone time set to 0
167 bcdb_FindClone(dumpID, volName, clonetime)
170 afs_int32 *clonetime;
174 ubik_Call(BUDB_FindClone, udbHandle.uh_client, 0, dumpID, volName,
180 * scan entire database for latest volume dump before adate. Optimize
181 * further by reading only the first line of the dump and if it is older
182 * than the oldest acceptable dump we've found so far, we don't bother
183 * scanning the dump file we've just opened
185 * Used by restore code when restoring a user requested volume(s)
187 * volumeName - name of volume to match on
188 * beforeDate - look for dumps older than this date
190 * deptr - desciptor of most recent dump
192 * should be able to implement this in a single call rather than
193 * the current multiple bcdb_ call algorithm.
196 bcdb_FindDump(volumeName, beforeDate, deptr)
198 afs_int32 beforeDate;
199 struct budb_dumpEntry *deptr;
203 ubik_Call(BUDB_FindDump, udbHandle.uh_client, 0, volumeName,
209 * find a dump by id. Currently insists on a single return value.
211 * dumpID - id to lookup
214 bcdb_FindDumpByID(dumpID, deptr)
216 register struct budb_dumpEntry *deptr;
218 register afs_int32 code;
223 /* initialize the dump list */
224 dl.budb_dumpList_len = 0;
225 dl.budb_dumpList_val = 0;
227 /* outline algorithm */
228 code = ubik_Call(BUDB_GetDumps, udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_DUMPID, "", /* no name */
232 &nextindex, &dbTime, &dl);
235 || (dl.budb_dumpList_len != 1) /* single retn val expected */
237 /* printf("bcdb_FindDumpByID: code %d, nvalues %d\n",
238 code, dl.budb_dumpList_len); */
240 code = 1; /* multiple id's */
244 memcpy(deptr, dl.budb_dumpList_val, sizeof(*deptr));
247 if (dl.budb_dumpList_val) {
248 /* free any allocated structures */
249 free(dl.budb_dumpList_val);
254 memset(deptr, 0, sizeof(*deptr));
258 /* bcdb_FindLastVolClone
259 * Returns the clone time, from the most recent dump of volName, when
260 * dumped in the volume set volSetName, with dump schedule dumpName.
261 * The clone time can be used to check if the volume has been correctly
262 * re-cloned, and also is used as the time from which to do the current
265 * volSetName - name of volume set
266 * dumpName - full path of dump node
267 * volName - name of volume for whom a clone time is required
268 * clonetime - ptr to vbl for result
270 * 0 - clonetime set appropriately
272 * used only for warning generation. Suggest that this be omitted.
276 bcdb_FindLastVolClone(volSetName, dumpName, volName, clonetime)
280 afs_int32 *clonetime;
284 * match on volumeset and dump path
285 * search for the volume name
290 /* bcdb_FindLatestDump
291 * find the latest dump with volume set component avname and the
292 * specified dump pathname. Used to find a dump, relative to which an
293 * incremental dump can be done. Defines the parent <-> child relations
296 * avname: volume set name
297 * dumpPath: full path of dump node
299 * 0: adentry: dump entry structure filled in.
300 * -1: probably an internal error
303 * Need to store volumeset name in dump in order to implement this.
304 * Need new routine since params are two strings
307 bcdb_FindLatestDump(volSetName, dumpPath, deptr)
310 struct budb_dumpEntry *deptr;
314 ubik_Call(BUDB_FindLatestDump, udbHandle.uh_client, 0, volSetName,
323 * dumpid: dump id to which tape beint32s
324 * tapeName: name of tape
327 bcdb_FindTape(dumpid, tapeName, teptr)
330 struct budb_tapeEntry *teptr;
337 memset(teptr, 0, sizeof(*teptr));
338 tl.budb_tapeList_len = 0;
339 tl.budb_tapeList_val = 0;
342 ubik_Call(BUDB_GetTapes, udbHandle.uh_client, 0, BUDB_MAJORVERSION,
343 BUDB_OP_TAPENAME | BUDB_OP_DUMPID, tapeName, dumpid, 0, 0,
344 &next, &dbTime, &tl);
349 if (tl.budb_tapeList_len != 1)
350 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
352 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
355 if (tl.budb_tapeList_val)
356 free(tl.budb_tapeList_val);
360 bcdb_FindTapeSeq(dumpid, tapeSeq, teptr)
363 struct budb_tapeEntry *teptr;
370 memset(teptr, 0, sizeof(*teptr));
371 tl.budb_tapeList_len = 0;
372 tl.budb_tapeList_val = 0;
375 ubik_Call(BUDB_GetTapes, udbHandle.uh_client, 0, BUDB_MAJORVERSION,
376 BUDB_OP_TAPESEQ | BUDB_OP_DUMPID, "", dumpid, tapeSeq, 0,
377 &next, &dbTime, &tl);
381 if (tl.budb_tapeList_len != 1)
382 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
384 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
387 if (tl.budb_tapeList_val)
388 free(tl.budb_tapeList_val);
394 * - this is part of dblookup. The existing semantics will not work since
395 * they do lookups based on dump id.
396 * - in the restore code, it uses this to extract information about
397 * the volume. Need current semantics. Could filter the output, selecting
399 * - Suggest that the lookup be based on volume name only, with optional
400 * match on backup, and readonly volumes.
401 * - Further, need to check if the volume structure returns enough
406 bcdb_FindVolumes(dumpID, volumeName, returnArray, last, next, maxa, nEntries)
409 struct budb_volumeEntry *returnArray;
419 vl.budb_volumeList_len = maxa;
420 vl.budb_volumeList_val = returnArray;
422 /* outline algorithm */
423 code = ubik_Call(BUDB_GetVolumes, udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME | BUDB_OP_DUMPID, volumeName, /* name */
427 next, /* nextindex */
430 *nEntries = vl.budb_volumeList_len;
435 bcdb_FinishDump(deptr)
436 register struct budb_dumpEntry *deptr;
439 code = ubik_Call(BUDB_FinishDump, udbHandle.uh_client, 0, deptr);
443 bcdb_FinishTape(teptr)
444 register struct budb_tapeEntry *teptr;
447 code = ubik_Call(BUDB_FinishTape, udbHandle.uh_client, 0, teptr);
452 /* bcdb_LookupVolumes
456 bcdb_LookupVolume(volumeName, returnArray, last, next, maxa, nEntries)
458 struct budb_volumeEntry *returnArray;
468 vl.budb_volumeList_len = maxa;
469 vl.budb_volumeList_val = returnArray;
471 /* outline algorithm */
472 code = ubik_Call(BUDB_GetVolumes, udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME, volumeName, /* name */
476 next, /* nextindex */
482 *nEntries = vl.budb_volumeList_len;
487 bcdb_UseTape(teptr, newFlag)
488 register struct budb_tapeEntry *teptr;
492 code = ubik_Call(BUDB_UseTape, udbHandle.uh_client, 0, teptr, newFlag);
497 /* ---- text configuration handling routines ----
500 * The caller should pass in/out a fid for an unlinked, open file to prevent
501 * tampering with the files contents;
505 * extract the specified textType and put it in a temporary, local
508 * ctPtr - ptr to client structure with all the required information
511 bcdb_GetTextFile(register udbClientTextP ctPtr)
513 afs_int32 bufferSize;
514 afs_int32 offset, nextOffset, chunkSize;
518 /* Initialize charlistT_val. We try to deallocate this structure based on
520 memset((void *)&charList, 0, sizeof(charList));
522 /* check params and cleanup any previous state */
523 if (ctPtr->lockHandle == 0)
524 ERROR(BUDB_INTERNALERROR);
526 if (ctPtr->textStream == NULL) /* Should have an open stream */
527 ERROR(BUDB_INTERNALERROR);
529 /* allocate a buffer */
531 charList.charListT_val = (char *)malloc(bufferSize);
532 if (charList.charListT_val == 0)
533 ERROR(BUDB_INTERNALERROR);
534 charList.charListT_len = bufferSize;
539 while (nextOffset != -1) {
541 charList.charListT_len = bufferSize;
543 ubik_Call(BUDB_GetText, udbHandle.uh_client, 0, ctPtr->lockHandle,
544 ctPtr->textType, bufferSize, offset, &nextOffset,
551 fwrite(charList.charListT_val, sizeof(char),
552 charList.charListT_len, ctPtr->textStream);
553 if (ferror(ctPtr->textStream))
554 ERROR(BUDB_INTERNALERROR);
556 ctPtr->textSize += charList.charListT_len;
559 /* get text version */
561 ubik_Call(BUDB_GetTextVersion, udbHandle.uh_client, 0,
562 ctPtr->textType, &ctPtr->textVersion);
567 fflush(ctPtr->textStream); /* debug */
569 /* exit, leaving the configuration text file open */
570 if (charList.charListT_val)
571 free(charList.charListT_val);
575 if (ctPtr->textStream != NULL) {
576 fclose(ctPtr->textStream);
577 ctPtr->textStream = NULL;
584 * save the text file in ubik database
586 * textType - identifies type of configuration file
587 * filename - where to get the text from
590 bcdb_SaveTextFile(ctPtr)
591 udbClientTextP ctPtr;
593 afs_int32 bufferSize;
594 afs_int32 offset, chunkSize, fileSize;
597 afs_int32 filesize();
599 /* allocate a buffer */
601 charList.charListT_val = (char *)malloc(bufferSize);
602 if (charList.charListT_val == 0)
603 ERROR(BUDB_INTERNALERROR);
604 charList.charListT_len = bufferSize;
606 if (ctPtr->textStream == NULL)
607 ERROR(BUDB_INTERNALERROR);
608 rewind(ctPtr->textStream);
610 fileSize = (afs_int32) filesize(ctPtr->textStream);
612 dprintf(("filesize is %d\n", fileSize));
614 rewind(ctPtr->textStream);
616 /* special case empty files */
618 charList.charListT_len = 0;
620 ubik_Call(BUDB_SaveText, udbHandle.uh_client, 0,
621 ctPtr->lockHandle, ctPtr->textType, 0,
622 BUDB_TEXT_COMPLETE, &charList);
627 while (fileSize != 0) {
628 chunkSize = MIN(fileSize, bufferSize);
630 fread(charList.charListT_val, sizeof(char), chunkSize,
633 if (code != chunkSize)
634 printf("code = %d\n", code);
635 if (ferror(ctPtr->textStream))
636 ERROR(BUDB_INTERNALERROR);
638 charList.charListT_len = chunkSize;
640 ubik_Call(BUDB_SaveText, udbHandle.uh_client, 0,
641 ctPtr->lockHandle, ctPtr->textType, offset,
642 (chunkSize == fileSize) ? BUDB_TEXT_COMPLETE : 0,
647 fileSize -= chunkSize;
652 /* if ( ctPtr->textStream >= 0 )
653 * close(ctPtr->textStream); */
654 if (charList.charListT_val)
655 free(charList.charListT_val);
659 bcdb_FindLastTape(dumpID, dumpEntry, tapeEntry, volEntry)
661 struct budb_dumpEntry *dumpEntry;
662 struct budb_tapeEntry *tapeEntry;
663 struct budb_volumeEntry *volEntry;
666 (BUDB_FindLastTape, udbHandle.uh_client, 0, dumpID, dumpEntry,
667 tapeEntry, volEntry));
670 bcdb_MakeDumpAppended(appendedDumpID, initialDumpID, startTapeSeq)
671 afs_int32 appendedDumpID;
672 afs_int32 initialDumpID;
673 afs_int32 startTapeSeq;
676 (BUDB_MakeDumpAppended, udbHandle.uh_client, 0, appendedDumpID,
677 initialDumpID, startTapeSeq));
681 /* -------------------------------------
682 * misc. support routines
683 * -------------------------------------
693 offset = ftell(stream);
694 fseek(stream, (afs_int32) 0, 2); /* end of file */
695 size = ftell(stream);
696 fseek(stream, offset, 0);
701 /* ------------------------------------
702 * misc. support routines - general text management
703 * ------------------------------------
708 * locks the text described by the ctPtr
710 * ctptr - client text ptr
717 register udbClientTextP ctPtr;
720 afs_int32 timeout, j = 0;
722 if (ctPtr->lockHandle != 0)
723 return (1); /* already locked */
726 ((ctPtr->textSize == 0) ? 30 : ((ctPtr->textSize / 50000) + 10));
730 ubik_Call(BUDB_GetLock, udbHandle.uh_client, 0,
731 udbHandle.uh_instanceId, ctPtr->textType, timeout,
733 if ((code != BUDB_LOCKED) && (code != BUDB_SELFLOCKED)) {
737 /* Mention something every 30 seconds */
739 com_err(whoami, code,
740 "; Waiting for db configuration text unlock");
743 #ifdef AFS_PTHREAD_ENV
752 ctPtr->lockHandle = 0;
757 * unlocks the text described by the ctPtr
759 * ctptr - client text ptr
766 register udbClientTextP ctPtr;
770 if (ctPtr->lockHandle == 0)
774 ubik_Call(BUDB_FreeLock, udbHandle.uh_client, 0, ctPtr->lockHandle);
775 ctPtr->lockHandle = 0;
777 /* Don't try to analyse the error. Let the lock timeout */
781 /* bc_CheckTextVersion
784 * n - out of date or error
787 bc_CheckTextVersion(ctPtr)
788 register udbClientTextP ctPtr;
793 if (ctPtr->textVersion == -1)
794 return (BC_VERSIONMISMATCH);
797 ubik_Call(BUDB_GetTextVersion, udbHandle.uh_client, 0,
798 ctPtr->textType, &tversion);
801 if (tversion != ctPtr->textVersion)
802 return (BC_VERSIONMISMATCH);
806 /* -------------------------------------
807 * initialization routines
808 * -------------------------------------
812 * Initialize a client for the vl ubik database.
814 vldbClientInit(noAuthFlag, localauth, cellName, cstruct, ttoken)
818 struct ubik_client **cstruct;
819 struct ktc_token *ttoken;
822 struct afsconf_dir *acdir;
823 struct rc_securityClass *sc;
824 afs_int32 i, scIndex = 0; /* Index of Rx security object - noauth */
825 struct afsconf_cell info;
826 struct ktc_principal sname;
827 struct rx_connection *serverconns[VLDB_MAXSERVERS];
830 /* Find out about the given cell */
832 afsconf_Open((localauth ? AFSDIR_SERVER_ETC_DIRPATH :
833 AFSDIR_CLIENT_ETC_DIRPATH));
835 com_err(whoami, 0, "Can't open configuration directory '%s'",
836 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
837 AFSDIR_CLIENT_ETC_DIRPATH));
838 ERROR(BC_NOCELLCONFIG);
844 code = afsconf_GetLocalCell(acdir, cname, sizeof(cname));
846 com_err(whoami, code,
847 "; Can't get the local cell name - check %s/%s",
848 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
849 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_THISCELL_FILE);
852 strcpy(cellName, cname);
855 code = afsconf_GetCellInfo(acdir, cellName, AFSCONF_VLDBSERVICE, &info);
857 com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
859 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
860 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_CELLSERVDB_FILE);
861 ERROR(BC_NOCELLCONFIG);
865 * Grab tickets if we care about authentication.
869 code = afsconf_GetLatestKey(acdir, 0, 0);
871 com_err(whoami, code, "; Can't get key from local key file");
874 code = afsconf_ClientAuth(acdir, &sc, &scIndex);
876 com_err(whoami, code, "; Calling ClientAuth");
880 ttoken->endTime = NEVERDATE;
884 strcpy(sname.cell, info.name);
885 sname.instance[0] = 0;
886 strcpy(sname.name, "afs");
889 ktc_GetToken(&sname, ttoken, sizeof(struct ktc_token), NULL);
891 com_err(whoami, code, 0,
892 "; Can't get AFS tokens - running unauthenticated");
894 if ((ttoken->kvno < 0) || (ttoken->kvno > 255))
896 "Funny kvno (%d) in ticket, proceeding",
905 sc = rxnull_NewClientSecurityObject();
908 sc = (struct rx_securityClass *)
909 rxkad_NewClientSecurityObject(rxkad_clear,
911 ttoken->kvno, ttoken->ticketLen,
915 com_err(whoami, 0, "Unsupported authentication type %d", scIndex);
923 "Can't create a security object with security index %d",
928 /* tell UV module about default authentication */
929 UV_SetSecurity(sc, scIndex);
931 if (info.numServers > VLDB_MAXSERVERS) {
933 "Warning: %d VLDB servers exist for cell '%s', can only remember the first %d",
934 info.numServers, cellName, VLDB_MAXSERVERS);
935 info.numServers = VLDB_MAXSERVERS;
938 for (i = 0; i < info.numServers; i++)
940 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
941 info.hostAddr[i].sin_port, USER_SERVICE_ID, sc,
946 code = ubik_ClientInit(serverconns, cstruct);
948 com_err(whoami, code, "; Can't initialize ubik connection to vldb");
954 afsconf_Close(acdir);
959 * initialize a client for the backup systems ubik database.
963 udbClientInit(noAuthFlag, localauth, cellName)
968 afs_int32 serverList[MAXSERVERS];
970 struct ktc_principal principal;
971 struct ktc_token token;
972 struct afsconf_cell info;
973 struct afsconf_dir *acdir;
978 afsconf_Open((localauth ? AFSDIR_SERVER_ETC_DIRPATH :
979 AFSDIR_CLIENT_ETC_DIRPATH));
981 com_err(whoami, 0, "Can't open configuration directory '%s'",
982 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
983 AFSDIR_CLIENT_ETC_DIRPATH));
984 ERROR(BC_NOCELLCONFIG);
990 code = afsconf_GetLocalCell(acdir, cname, sizeof(cname));
992 com_err(whoami, code,
993 "; Can't get the local cell name - check %s/%s",
994 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
995 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_THISCELL_FILE);
998 strcpy(cellName, cname);
1001 code = afsconf_GetCellInfo(acdir, cellName, 0, &info);
1003 com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
1005 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
1006 AFSDIR_CLIENT_ETC_DIRPATH), AFSDIR_CELLSERVDB_FILE);
1007 ERROR(BC_NOCELLCONFIG);
1010 udbHandle.uh_scIndex = RX_SCINDEX_NULL;
1013 code = afsconf_GetLatestKey(acdir, 0, 0);
1015 com_err(whoami, code, "; Can't get key from local key file");
1019 afsconf_ClientAuth(acdir, &udbHandle.uh_secobj,
1020 &udbHandle.uh_scIndex);
1022 com_err(whoami, code, "; Calling ClientAuth");
1028 /* setup principal */
1029 strcpy(principal.cell, info.name);
1030 principal.instance[0] = 0;
1031 strcpy(principal.name, "afs");
1034 code = ktc_GetToken(&principal, &token, sizeof(token), NULL);
1036 com_err(whoami, code,
1037 "; Can't get tokens - running unauthenticated");
1039 if ((token.kvno < 0) || (token.kvno > 255))
1041 "Unexpected kvno (%d) in ticket - proceeding",
1043 udbHandle.uh_scIndex = RX_SCINDEX_KAD; /* Kerberos */
1047 switch (udbHandle.uh_scIndex) {
1049 udbHandle.uh_secobj = rxnull_NewClientSecurityObject();
1053 udbHandle.uh_secobj = (struct rx_securityClass *)
1054 rxkad_NewClientSecurityObject(rxkad_clear, &token.sessionKey,
1055 token.kvno, token.ticketLen,
1060 com_err(whoami, 0, "Unsupported authentication type %d",
1061 udbHandle.uh_scIndex);
1067 if (!udbHandle.uh_secobj) {
1069 "Can't create a security object with security index %d",
1070 udbHandle.uh_secobj);
1074 if (info.numServers > MAXSERVERS) {
1076 "Warning: %d BDB servers exist for cell '%s', can only remember the first %d",
1077 info.numServers, cellName, MAXSERVERS);
1078 info.numServers = MAXSERVERS;
1081 /* establish connections to the servers. Check for failed connections? */
1082 for (i = 0; i < info.numServers; i++) {
1083 udbHandle.uh_serverConn[i] =
1084 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
1085 htons(AFSCONF_BUDBPORT), BUDB_SERVICE,
1086 udbHandle.uh_secobj, udbHandle.uh_scIndex);
1088 udbHandle.uh_serverConn[i] = 0;
1090 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1092 com_err(whoami, code,
1093 "; Can't initialize ubik connection to backup database");
1097 /* Try to quickly find a good site by setting deadtime low */
1098 for (i = 0; i < info.numServers; i++)
1099 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 1);
1101 ubik_Call(BUDB_GetInstanceId, udbHandle.uh_client, 0,
1102 &udbHandle.uh_instanceId);
1104 /* Reset dead time back up to default */
1105 for (i = 0; i < info.numServers; i++)
1106 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 60);
1108 /* If did not find a site on first quick pass, try again */
1111 ubik_Call(BUDB_GetInstanceId, udbHandle.uh_client, 0,
1112 &udbHandle.uh_instanceId);
1114 com_err(whoami, code, "; Can't access backup database");
1120 afsconf_Close(acdir);
1124 /* -------------------------------------
1125 * specialized ubik support
1126 * -------------------------------------
1134 * 1) first call with SINGLESERVER set, record the server to be used.
1135 * 2) subsequent calls use that server. If a failure is encountered,
1136 * the state is cleaned up and the error returned back to the caller.
1137 * 3) upon completion, the user must make a dummy call with
1138 * END_SINGLESERVER set, to clean up state.
1139 * 4) if the vanilla ubik_Call is ever modified, the END_SINGLESERVER
1140 * flag can be discarded. The first call without SINGLESERVER set
1141 * can clean up the state.
1144 struct ubikCallState {
1145 afs_int32 ucs_flags; /* state flags */
1146 afs_int32 ucs_selectedServer; /* which server selected */
1149 static struct ubikCallState uServer;
1151 /* ubik_Call_SingleServer
1152 * variant of ubik_Call. This is used by the backup system to initiate
1153 * a series of calls to a single ubik server. The first call sets up
1154 * process state (not recorded in ubik) that requires all further calls
1155 * of that group to be made to the same server process.
1157 * call this instead of stub and we'll guarantee to find a host that's up.
1158 * in the future, we should also put in a protocol to find the sync site
1162 ubik_Call_SingleServer(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8,
1163 p9, p10, p11, p12, p13, p14, p15, p16)
1164 register struct ubik_client *aclient;
1167 char *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13,
1170 register afs_int32 code;
1171 afs_int32 someCode, newHost, thisHost;
1172 register afs_int32 i;
1173 register afs_int32 count;
1176 struct rx_connection *tc;
1177 struct rx_peer *rxp;
1179 if ((aflags & (UF_SINGLESERVER | UF_END_SINGLESERVER)) != 0) {
1180 if (((aflags & UF_SINGLESERVER) != 0)
1181 && ((uServer.ucs_flags & UF_SINGLESERVER) != 0)
1184 /* have a selected server */
1185 tc = aclient->conns[uServer.ucs_selectedServer];
1188 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11,
1189 p12, p13, p14, p15, p16);
1191 /* error. Clean up single server state */
1192 memset(&uServer, 0, sizeof(uServer));
1195 } else if ((aflags & UF_END_SINGLESERVER) != 0) {
1196 memset(&uServer, 0, sizeof(uServer));
1201 someCode = UNOSERVERS;
1207 /* tc is the next conn to try */
1208 tc = aclient->conns[count];
1211 pass = 1; /* in pass 1, we look at down hosts, too */
1215 break; /* nothing left to try */
1217 if (pass == 0 && (aclient->states[count] & CFLastFailed)) {
1219 continue; /* this guy's down, try someone else first */
1223 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12,
1224 p13, p14, p15, p16);
1226 /* note that getting a UNOTSYNC error code back does *not* guarantee
1227 * that there is a sync site yet elected. However, if there is a
1228 * sync site out there somewhere, and you're trying an operation that
1229 * requires a sync site, ubik will return UNOTSYNC, indicating the
1230 * operation won't work until you find a sync site
1232 if (code == UNOTSYNC) { /*ns */
1233 /* means that this requires a sync site to work */
1234 someCode = code; /* remember an error, if this fails */
1236 /* now see if we can find the sync site host */
1237 code = VOTE_GetSyncSite(tc, &newHost);
1238 if (code == 0 && newHost != 0) {
1239 newHost = htonl(newHost); /* convert back to network order */
1241 /* position count at the appropriate slot in the client
1242 * structure and retry. If we can't find in slot, we'll just
1243 * continue through the whole list
1245 for (i = 0; i < MAXSERVERS; i++) { /*f */
1246 rxp = rx_PeerOf(aclient->conns[i]);
1247 if (!(thisHost = rx_HostOf(rxp))) {
1248 count++; /* host not found, try the next dude */
1251 if (thisHost == newHost) {
1252 /* avoid asking in a loop */
1253 if (chaseCount++ > 2)
1255 count = i; /* we were told to use this one */
1260 count++; /* not directed, keep looking for a sync site */
1263 else if (code == UNOQUORUM) { /* this guy is still recovering */
1267 } else if (code < 0) { /* network errors */
1269 aclient->states[count] |= CFLastFailed;
1273 /* ok, operation worked */
1274 aclient->states[count] &= ~CFLastFailed;
1275 /* either misc ubik code, or misc application code (incl success)
1278 /* if the call succeeded, setup connection state for subsequent
1282 && (aflags & UF_SINGLESERVER != 0)
1284 /* need to save state */
1285 uServer.ucs_flags = UF_SINGLESERVER;
1286 uServer.ucs_selectedServer = count;
1296 /* -------------------------------------
1297 * debug and test routines
1298 * -------------------------------------
1302 * For testing only. Open a connect to the database server running on
1305 * 0 - ubik connection established in the global udbHandle structure
1311 afs_int32 serverList[MAXSERVERS];
1317 /* get our host name */
1318 gethostname(hostname, sizeof(hostname));
1319 /* strcpy(hostname, "hops"); */
1322 args[1] = "-servers";
1325 code = ubik_ParseClientList(3, args, serverList);
1327 com_err(whoami, code, "; udbLocalInit: parsing ubik server list");
1331 udbHandle.uh_scIndex = RX_SCINDEX_NULL;
1332 udbHandle.uh_secobj = (struct rx_securityClass *)
1333 rxnull_NewClientSecurityObject();
1335 for (i = 0; serverList[i] != 0; i++) {
1336 udbHandle.uh_serverConn[i] =
1337 rx_NewConnection(serverList[i], htons(AFSCONF_BUDBPORT),
1338 BUDB_SERVICE, udbHandle.uh_secobj,
1339 udbHandle.uh_scIndex);
1340 if (udbHandle.uh_serverConn[i] == 0) {
1341 com_err(whoami, 0, "connection %d failed", i);
1345 udbHandle.uh_serverConn[i] = 0;
1346 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1348 com_err(whoami, code, "; in ubik_ClientInit");
1353 ubik_Call(BUDB_GetInstanceId, udbHandle.uh_client, 0,
1354 &udbHandle.uh_instanceId);
1356 com_err(whoami, code, "; Can't estblish instance Id");
1364 /* bc_openTextFile - This function opens a temp file to read in the
1365 * config text recd from the bu server. On Unix, an unlink() is done on
1366 * the file as soon as it is opened, so when the program exits, the file will
1367 * be removed automatically, while being invisible while in use.
1368 * On NT, however, the file must be explicitly deleted after use with an unlink()
1370 * Pointer to a udhClientTextP struct. The open stream ptr is stored in
1371 * the udbClientTextP.textStream member.
1372 * Output: The temp file name is returned in tmpFileName. This should be used
1373 * to delete the file when done with it.
1379 bc_openTextFile(udbClientTextP ctPtr, char *tmpFileName)
1383 if (ctPtr->textStream != NULL)
1384 fclose(ctPtr->textStream);
1386 sprintf(tmpFileName, "%s/bu_XXXXXX", gettmpdir());
1387 #ifdef AFS_LINUX20_ENV
1388 mkstemp(tmpFileName);
1390 mktemp(tmpFileName);
1392 ctPtr->textStream = fopen(tmpFileName, "w+");
1393 if (ctPtr->textStream == NULL)
1394 ERROR(BUDB_INTERNALERROR);
1396 #ifndef AFS_NT40_ENV /* This can't be done on NT */
1397 /* make the file invisible to others */
1398 code = unlink(tmpFileName);
1403 dprintf(("file is %s\n", tmpFileName));
1409 if (ctPtr->textStream != NULL) {
1410 fclose(ctPtr->textStream);
1411 ctPtr->textStream = NULL;
1417 /* bc_closeTextFile: This function closes any actual temp files associated with
1418 * a udbClientText structure.
1419 * Input: ctPtr->textStream - stream to close
1420 * tmpFileName - temp file name to delete
1426 bc_closeTextFile(udbClientTextP ctPtr, char *tmpFileName)
1430 if (ctPtr->textStream)
1431 fclose(ctPtr->textStream);
1433 if (*tmpFileName) { /* we have a valid name */
1434 code = unlink(tmpFileName);