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>
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>
38 #include "error_macros.h"
42 /* -------------------------------------
44 * -------------------------------------
47 struct udbHandleS udbHandle;
49 /* -------------------------------------
50 * interface routines (alphabetic)
51 * -------------------------------------
55 register struct budb_volumeEntry *veptr;
59 code = ubik_Call( BUDB_AddVolume, udbHandle.uh_client, 0, veptr);
63 bcdb_AddVolumes(veptr, count)
64 register struct budb_volumeEntry *veptr;
67 struct budb_volumeList volumeList;
70 volumeList.budb_volumeList_len = count;
71 volumeList.budb_volumeList_val = veptr;
72 code = ubik_Call(BUDB_AddVolumes, udbHandle.uh_client, 0, &volumeList);
77 bcdb_CreateDump(deptr)
78 register struct budb_dumpEntry *deptr;
82 code = ubik_Call(BUDB_CreateDump, udbHandle.uh_client, 0, deptr);
86 bcdb_deleteDump(dumpID, fromTime, toTime, dumps)
90 budb_dumpsList *dumps;
93 budb_dumpsList dumpsList, *dumpsPtr;
95 dumpsList.budb_dumpsList_len = 0;
96 dumpsList.budb_dumpsList_val = 0;
97 dumpsPtr = ( dumps ? dumps : &dumpsList );
99 code = ubik_Call(BUDB_DeleteDump, udbHandle.uh_client, 0, dumpID, fromTime, toTime, dumpsPtr);
100 if (dumpsList.budb_dumpsList_val) free(dumpsList.budb_dumpsList_val);
104 bcdb_listDumps(sflags, groupId, fromTime, toTime, dumps, flags)
108 budb_dumpsList *dumps;
109 budb_dumpsList *flags;
111 afs_int32 code, sflag=0;
112 budb_dumpsList dumpsList, *dumpsPtr;
113 budb_dumpsList flagsList, *flagsPtr;
115 dumpsList.budb_dumpsList_len = 0;
116 dumpsList.budb_dumpsList_val = 0;
117 dumpsPtr = (dumps ? dumps : &dumpsList);
119 flagsList.budb_dumpsList_len = 0;
120 flagsList.budb_dumpsList_val = 0;
121 flagsPtr = (flags ? flags : &flagsList);
123 code = ubik_Call(BUDB_ListDumps, udbHandle.uh_client, 0,
124 sflags, "", groupId, fromTime, toTime, dumpsPtr, flagsPtr);
126 if (dumpsList.budb_dumpsList_val) free(dumpsList.budb_dumpsList_val);
127 if (flagsList.budb_dumpsList_val) free(flagsList.budb_dumpsList_val);
132 bcdb_DeleteVDP(dumpSetName, dumpPath, dumpID)
139 code = ubik_Call( BUDB_DeleteVDP, udbHandle.uh_client, 0, dumpSetName, dumpPath, dumpID);
144 * Returns the clone time of a volume by going up the parent chain.
145 * If no clone time is found, a clone time of 0 is returned, forcing
148 * dumpID - of the first dump to examine.
149 * volName - name of the volume for whom a clone time is required
150 * clonetime - ptr to vbl for returning result
152 * 0 - clonetime set appropriately
153 * -1 - error occured in traversing chain, clone time set to 0.
154 * -2 - no clone times found, clone time set to 0
158 bcdb_FindClone(dumpID, volName, clonetime)
161 afs_int32 *clonetime;
164 code = ubik_Call( BUDB_FindClone, udbHandle.uh_client, 0, dumpID, volName, clonetime);
169 * scan entire database for latest volume dump before adate. Optimize
170 * further by reading only the first line of the dump and if it is older
171 * than the oldest acceptable dump we've found so far, we don't bother
172 * scanning the dump file we've just opened
174 * Used by restore code when restoring a user requested volume(s)
176 * volumeName - name of volume to match on
177 * beforeDate - look for dumps older than this date
179 * deptr - desciptor of most recent dump
181 * should be able to implement this in a single call rather than
182 * the current multiple bcdb_ call algorithm.
185 bcdb_FindDump(volumeName, beforeDate, deptr)
187 afs_int32 beforeDate;
188 struct budb_dumpEntry *deptr;
191 code = ubik_Call( BUDB_FindDump, udbHandle.uh_client, 0, volumeName, beforeDate, deptr);
196 * find a dump by id. Currently insists on a single return value.
198 * dumpID - id to lookup
201 bcdb_FindDumpByID(dumpID, deptr)
203 register struct budb_dumpEntry *deptr;
205 register afs_int32 code;
210 /* initialize the dump list */
211 dl.budb_dumpList_len = 0;
212 dl.budb_dumpList_val = 0;
214 /* outline algorithm */
215 code = ubik_Call (BUDB_GetDumps, udbHandle.uh_client, 0,
227 || (dl.budb_dumpList_len != 1) /* single retn val expected */
230 /* printf("bcdb_FindDumpByID: code %d, nvalues %d\n",
231 code, dl.budb_dumpList_len); */
233 code = 1; /* multiple id's */
237 memcpy(deptr, dl.budb_dumpList_val, sizeof(*deptr));
240 if ( dl.budb_dumpList_val )
242 /* free any allocated structures */
243 free(dl.budb_dumpList_val);
248 memset(deptr, 0, sizeof(*deptr));
252 /* bcdb_FindLastVolClone
253 * Returns the clone time, from the most recent dump of volName, when
254 * dumped in the volume set volSetName, with dump schedule dumpName.
255 * The clone time can be used to check if the volume has been correctly
256 * re-cloned, and also is used as the time from which to do the current
259 * volSetName - name of volume set
260 * dumpName - full path of dump node
261 * volName - name of volume for whom a clone time is required
262 * clonetime - ptr to vbl for result
264 * 0 - clonetime set appropriately
266 * used only for warning generation. Suggest that this be omitted.
270 bcdb_FindLastVolClone(volSetName, dumpName, volName, clonetime)
274 afs_int32 *clonetime;
278 match on volumeset and dump path
279 search for the volume name
284 /* bcdb_FindLatestDump
285 * find the latest dump with volume set component avname and the
286 * specified dump pathname. Used to find a dump, relative to which an
287 * incremental dump can be done. Defines the parent <-> child relations
290 * avname: volume set name
291 * dumpPath: full path of dump node
293 * 0: adentry: dump entry structure filled in.
294 * -1: probably an internal error
297 * Need to store volumeset name in dump in order to implement this.
298 * Need new routine since params are two strings
301 bcdb_FindLatestDump(volSetName, dumpPath, deptr)
304 struct budb_dumpEntry *deptr;
307 code = ubik_Call( BUDB_FindLatestDump, udbHandle.uh_client, 0,
308 volSetName, dumpPath, deptr);
316 * dumpid: dump id to which tape beint32s
317 * tapeName: name of tape
320 bcdb_FindTape(dumpid, tapeName, teptr)
323 struct budb_tapeEntry *teptr;
330 memset(teptr, 0, sizeof(*teptr));
331 tl.budb_tapeList_len = 0;
332 tl.budb_tapeList_val = 0;
334 code = ubik_Call( BUDB_GetTapes, udbHandle.uh_client, 0,
336 BUDB_OP_TAPENAME|BUDB_OP_DUMPID,
337 tapeName, dumpid, 0, 0, &next, &dbTime, &tl);
339 if (code) ERROR(code);
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;
366 code = ubik_Call( BUDB_GetTapes, udbHandle.uh_client, 0,
368 BUDB_OP_TAPESEQ|BUDB_OP_DUMPID,
369 "", dumpid, tapeSeq, 0, &next, &dbTime, &tl);
370 if (code) ERROR(code);
372 if (tl.budb_tapeList_len != 1)
373 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
375 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
378 if ( tl.budb_tapeList_val )
379 free(tl.budb_tapeList_val);
385 * - this is part of dblookup. The existing semantics will not work since
386 * they do lookups based on dump id.
387 * - in the restore code, it uses this to extract information about
388 * the volume. Need current semantics. Could filter the output, selecting
390 * - Suggest that the lookup be based on volume name only, with optional
391 * match on backup, and readonly volumes.
392 * - Further, need to check if the volume structure returns enough
397 bcdb_FindVolumes(dumpID, volumeName, returnArray, last, next, maxa, nEntries)
400 struct budb_volumeEntry *returnArray;
410 vl.budb_volumeList_len = maxa;
411 vl.budb_volumeList_val = returnArray;
413 /* outline algorithm */
414 code = ubik_Call (BUDB_GetVolumes, udbHandle.uh_client, 0,
416 BUDB_OP_VOLUMENAME|BUDB_OP_DUMPID,
417 volumeName, /* name */
421 next, /* nextindex */
425 *nEntries = vl.budb_volumeList_len;
430 bcdb_FinishDump(deptr)
431 register struct budb_dumpEntry *deptr;
434 code = ubik_Call (BUDB_FinishDump, udbHandle.uh_client, 0, deptr);
438 bcdb_FinishTape(teptr)
439 register struct budb_tapeEntry *teptr;
442 code = ubik_Call (BUDB_FinishTape, udbHandle.uh_client, 0, teptr);
447 /* bcdb_LookupVolumes
451 bcdb_LookupVolume(volumeName, returnArray, last, next, maxa, nEntries)
453 struct budb_volumeEntry *returnArray;
463 vl.budb_volumeList_len = maxa;
464 vl.budb_volumeList_val = returnArray;
466 /* outline algorithm */
467 code = ubik_Call (BUDB_GetVolumes, udbHandle.uh_client, 0,
470 volumeName, /* name */
474 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 )
542 charList.charListT_len = bufferSize;
543 code = ubik_Call(BUDB_GetText, udbHandle.uh_client, 0,
544 ctPtr->lockHandle, ctPtr->textType, bufferSize,
545 offset, &nextOffset, &charList);
550 code = fwrite(charList.charListT_val, sizeof(char),
551 charList.charListT_len, ctPtr->textStream);
552 if ( ferror(ctPtr->textStream) )
553 ERROR(BUDB_INTERNALERROR);
555 ctPtr->textSize += charList.charListT_len;
558 /* get text version */
559 code = ubik_Call(BUDB_GetTextVersion, udbHandle.uh_client, 0,
560 ctPtr->textType, &ctPtr->textVersion);
565 fflush(ctPtr->textStream); /* debug */
567 /* exit, leaving the configuration text file open */
568 if ( charList.charListT_val )
569 free(charList.charListT_val);
573 if ( ctPtr->textStream != NULL )
575 fclose(ctPtr->textStream);
576 ctPtr->textStream = NULL;
583 * save the text file in ubik database
585 * textType - identifies type of configuration file
586 * filename - where to get the text from
589 bcdb_SaveTextFile(ctPtr)
590 udbClientTextP ctPtr;
592 afs_int32 bufferSize;
593 afs_int32 offset, chunkSize, fileSize;
596 afs_int32 filesize();
598 /* allocate a buffer */
600 charList.charListT_val = (char *) malloc(bufferSize);
601 if ( charList.charListT_val == 0 )
602 ERROR(BUDB_INTERNALERROR);
603 charList.charListT_len = bufferSize;
605 if ( ctPtr->textStream == NULL )
606 ERROR(BUDB_INTERNALERROR);
607 rewind(ctPtr->textStream);
609 fileSize = (afs_int32) filesize(ctPtr->textStream);
611 dprintf(("filesize is %d\n", fileSize));
613 rewind(ctPtr->textStream);
615 /* special case empty files */
618 charList.charListT_len = 0;
619 code = ubik_Call(BUDB_SaveText, udbHandle.uh_client, 0,
620 ctPtr->lockHandle, ctPtr->textType, 0,
621 BUDB_TEXT_COMPLETE, &charList);
626 while ( fileSize != 0 )
628 chunkSize = MIN(fileSize, bufferSize);
629 code = fread(charList.charListT_val, sizeof(char), chunkSize,
632 if ( code != chunkSize )
633 printf("code = %d\n", code );
634 if ( ferror(ctPtr->textStream ) )
635 ERROR(BUDB_INTERNALERROR);
637 charList.charListT_len = chunkSize;
638 code = ubik_Call(BUDB_SaveText, udbHandle.uh_client, 0,
639 ctPtr->lockHandle, ctPtr->textType, offset,
640 (chunkSize == fileSize) ? BUDB_TEXT_COMPLETE: 0,
645 fileSize -= chunkSize;
650 /* if ( ctPtr->textStream >= 0 )
651 close(ctPtr->textStream); */
652 if ( charList.charListT_val )
653 free(charList.charListT_val);
657 bcdb_FindLastTape(dumpID, dumpEntry, tapeEntry, volEntry)
659 struct budb_dumpEntry *dumpEntry;
660 struct budb_tapeEntry *tapeEntry;
661 struct budb_volumeEntry *volEntry;
663 return( ubik_Call(BUDB_FindLastTape,udbHandle.uh_client,0,
664 dumpID,dumpEntry,tapeEntry,volEntry) );
667 bcdb_MakeDumpAppended(appendedDumpID, initialDumpID, startTapeSeq)
668 afs_int32 appendedDumpID;
669 afs_int32 initialDumpID;
670 afs_int32 startTapeSeq;
672 return( ubik_Call(BUDB_MakeDumpAppended,udbHandle.uh_client,0,
673 appendedDumpID,initialDumpID,startTapeSeq) );
677 /* -------------------------------------
678 * misc. support routines
679 * -------------------------------------
689 offset = ftell(stream);
690 fseek(stream, (afs_int32) 0, 2); /* end of file */
691 size = ftell(stream);
692 fseek(stream, offset, 0);
697 /* ------------------------------------
698 * misc. support routines - general text management
699 * ------------------------------------
704 * locks the text described by the ctPtr
706 * ctptr - client text ptr
713 register udbClientTextP ctPtr;
716 afs_int32 timeout, j = 0;
718 if (ctPtr->lockHandle != 0) return(1); /* already locked */
720 timeout = ( (ctPtr->textSize == 0) ? 30 : ((ctPtr->textSize/50000) + 10) );
723 code = ubik_Call(BUDB_GetLock, udbHandle.uh_client, 0,
724 udbHandle.uh_instanceId, ctPtr->textType, timeout,
726 if ( (code != BUDB_LOCKED) && (code != BUDB_SELFLOCKED) ) {
730 /* Mention something every 30 seconds */
732 com_err(whoami, code,"; Waiting for db configuration text unlock");
735 #ifdef AFS_PTHREAD_ENV
743 if (code) ctPtr->lockHandle = 0;
748 * unlocks the text described by the ctPtr
750 * ctptr - client text ptr
757 register udbClientTextP ctPtr;
761 if ( ctPtr->lockHandle == 0 )
764 code = ubik_Call(BUDB_FreeLock, udbHandle.uh_client, 0, ctPtr->lockHandle);
765 ctPtr->lockHandle = 0;
767 /* Don't try to analyse the error. Let the lock timeout */
771 /* bc_CheckTextVersion
774 * n - out of date or error
777 bc_CheckTextVersion(ctPtr)
778 register udbClientTextP ctPtr;
783 if ( ctPtr->textVersion == -1 )
784 return(BC_VERSIONMISMATCH);
786 code = ubik_Call(BUDB_GetTextVersion, udbHandle.uh_client, 0,
787 ctPtr->textType, &tversion);
790 if ( tversion != ctPtr->textVersion )
791 return(BC_VERSIONMISMATCH);
795 /* -------------------------------------
796 * initialization routines
797 * -------------------------------------
801 * Initialize a client for the vl ubik database.
803 vldbClientInit(noAuthFlag, localauth, cellName, cstruct, ttoken)
807 struct ubik_client **cstruct;
808 struct ktc_token *ttoken;
811 struct afsconf_dir *acdir;
812 struct rc_securityClass *sc;
813 afs_int32 i, scIndex = 0; /* Index of Rx security object - noauth */
814 struct afsconf_cell info;
815 struct ktc_principal sname;
816 struct rx_connection *serverconns[VLDB_MAXSERVERS];
819 /* Find out about the given cell */
820 acdir = afsconf_Open((localauth ? AFSDIR_SERVER_ETC_DIRPATH :
821 AFSDIR_CLIENT_ETC_DIRPATH));
824 com_err(whoami,0,"Can't open configuration directory '%s'",
825 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
826 AFSDIR_CLIENT_ETC_DIRPATH));
827 ERROR(BC_NOCELLCONFIG);
834 code = afsconf_GetLocalCell(acdir, cname, sizeof(cname));
837 com_err(whoami, code, "; Can't get the local cell name - check %s/%s", (localauth ? AFSDIR_SERVER_ETC_DIRPATH : AFSDIR_CLIENT_ETC_DIRPATH),
838 AFSDIR_THISCELL_FILE);
841 strcpy(cellName, cname);
844 code = afsconf_GetCellInfo(acdir, cellName, AFSCONF_VLDBSERVICE, &info);
847 com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
848 cellName, (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
849 AFSDIR_CLIENT_ETC_DIRPATH),
850 AFSDIR_CELLSERVDB_FILE);
851 ERROR(BC_NOCELLCONFIG);
855 * Grab tickets if we care about authentication.
860 code = afsconf_GetLatestKey (acdir, 0, 0);
863 com_err(whoami, code, "; Can't get key from local key file");
868 code = afsconf_ClientAuth(acdir, &sc, &scIndex);
871 com_err(whoami, code, "; Calling ClientAuth");
875 ttoken->endTime = NEVERDATE;
882 strcpy(sname.cell, info.name);
883 sname.instance[0] = 0;
884 strcpy(sname.name, "afs");
886 code = ktc_GetToken(&sname, ttoken, sizeof(struct ktc_token), (char *)0);
889 com_err(whoami,code, 0,"; Can't get AFS tokens - running unauthenticated");
893 if ( (ttoken->kvno < 0) || (ttoken->kvno > 255) )
894 com_err(whoami, 0, "Funny kvno (%d) in ticket, proceeding", ttoken->kvno);
903 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
906 sc = (struct rx_securityClass *)
907 rxkad_NewClientSecurityObject(rxkad_clear, &ttoken->sessionKey,
908 ttoken->kvno, ttoken->ticketLen,
912 com_err(whoami, 0, "Unsupported authentication type %d", scIndex);
920 com_err(whoami, 0, "Can't create a security object with security index %d",
925 /* tell UV module about default authentication */
926 UV_SetSecurity(sc, scIndex);
928 if (info.numServers > VLDB_MAXSERVERS)
931 "Warning: %d VLDB servers exist for cell '%s', can only remember the first %d",
932 info.numServers, cellName, VLDB_MAXSERVERS);
933 info.numServers = VLDB_MAXSERVERS;
936 for (i=0; i<info.numServers; i++)
937 serverconns[i] = rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
938 info.hostAddr[i].sin_port,
939 USER_SERVICE_ID, sc, scIndex);
943 code = ubik_ClientInit(serverconns, cstruct);
946 com_err(whoami,code,"; Can't initialize ubik connection to vldb");
951 if (acdir) afsconf_Close(acdir);
956 * initialize a client for the backup systems ubik database.
960 udbClientInit(noAuthFlag, localauth, cellName)
965 afs_int32 serverList[MAXSERVERS];
967 struct ktc_principal principal;
968 struct ktc_token token;
969 struct afsconf_cell info;
970 struct afsconf_dir *acdir;
974 acdir = afsconf_Open((localauth ? AFSDIR_SERVER_ETC_DIRPATH :
975 AFSDIR_CLIENT_ETC_DIRPATH));
978 com_err(whoami,0,"Can't open configuration directory '%s'",
979 (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
980 AFSDIR_CLIENT_ETC_DIRPATH));
981 ERROR(BC_NOCELLCONFIG);
988 code = afsconf_GetLocalCell(acdir, cname, sizeof(cname));
991 com_err(whoami, code, "; Can't get the local cell name - check %s/%s", (localauth ? AFSDIR_SERVER_ETC_DIRPATH : AFSDIR_CLIENT_ETC_DIRPATH),
992 AFSDIR_THISCELL_FILE);
995 strcpy(cellName, cname);
998 code = afsconf_GetCellInfo(acdir, cellName, 0, &info);
1001 com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
1002 cellName, (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
1003 AFSDIR_CLIENT_ETC_DIRPATH),
1004 AFSDIR_CELLSERVDB_FILE);
1005 ERROR(BC_NOCELLCONFIG);
1008 udbHandle.uh_scIndex = RX_SCINDEX_NULL;
1012 code = afsconf_GetLatestKey (acdir, 0, 0);
1015 com_err(whoami, code, "; Can't get key from local key file");
1020 code = afsconf_ClientAuth(acdir, &udbHandle.uh_secobj, &udbHandle.uh_scIndex);
1023 com_err(whoami, code, "; Calling ClientAuth");
1032 /* setup principal */
1033 strcpy(principal.cell, info.name);
1034 principal.instance[0] = 0;
1035 strcpy(principal.name, "afs");
1038 code = ktc_GetToken(&principal, &token, sizeof(token), (char *)0);
1041 com_err(whoami, code, "; Can't get tokens - running unauthenticated");
1045 if ((token.kvno < 0) || (token.kvno > 255))
1046 com_err(whoami, 0, "Unexpected kvno (%d) in ticket - proceeding",
1048 udbHandle.uh_scIndex = RX_SCINDEX_KAD; /* Kerberos */
1052 switch (udbHandle.uh_scIndex)
1055 udbHandle.uh_secobj = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
1059 udbHandle.uh_secobj = (struct rx_securityClass *)
1060 rxkad_NewClientSecurityObject(rxkad_clear, &token.sessionKey,
1061 token.kvno, token.ticketLen,
1066 com_err(whoami, 0, "Unsupported authentication type %d", udbHandle.uh_scIndex );
1072 if (!udbHandle.uh_secobj)
1074 com_err(whoami, 0, "Can't create a security object with security index %d",
1075 udbHandle.uh_secobj);
1079 if (info.numServers > MAXSERVERS)
1082 "Warning: %d BDB servers exist for cell '%s', can only remember the first %d",
1083 info.numServers, cellName, MAXSERVERS);
1084 info.numServers = MAXSERVERS;
1087 /* establish connections to the servers. Check for failed connections? */
1088 for (i = 0; i < info.numServers; i++) {
1089 udbHandle.uh_serverConn[i] = rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
1090 htons(AFSCONF_BUDBPORT),
1092 udbHandle.uh_secobj,
1093 udbHandle.uh_scIndex);
1095 udbHandle.uh_serverConn[i] = 0;
1097 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1099 com_err(whoami,code,"; Can't initialize ubik connection to backup database");
1103 /* Try to quickly find a good site by setting deadtime low */
1104 for (i = 0; i < info.numServers; i++)
1105 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 1);
1106 code = ubik_Call(BUDB_GetInstanceId, udbHandle.uh_client, 0, &udbHandle.uh_instanceId);
1108 /* Reset dead time back up to default */
1109 for (i = 0; i < info.numServers; i++)
1110 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 60);
1112 /* If did not find a site on first quick pass, try again */
1114 code = ubik_Call(BUDB_GetInstanceId, udbHandle.uh_client, 0, &udbHandle.uh_instanceId);
1116 com_err(whoami,code,"; Can't access backup database");
1121 if (acdir) afsconf_Close(acdir);
1125 /* -------------------------------------
1126 * specialized ubik support
1127 * -------------------------------------
1135 * 1) first call with SINGLESERVER set, record the server to be used.
1136 * 2) subsequent calls use that server. If a failure is encountered,
1137 * the state is cleaned up and the error returned back to the caller.
1138 * 3) upon completion, the user must make a dummy call with
1139 * END_SINGLESERVER set, to clean up state.
1140 * 4) if the vanilla ubik_Call is ever modified, the END_SINGLESERVER
1141 * flag can be discarded. The first call without SINGLESERVER set
1142 * can clean up the state.
1145 struct ubikCallState
1147 afs_int32 ucs_flags; /* state flags */
1148 afs_int32 ucs_selectedServer; /* which server selected */
1151 static struct ubikCallState uServer;
1153 /* ubik_Call_SingleServer
1154 * variant of ubik_Call. This is used by the backup system to initiate
1155 * a series of calls to a single ubik server. The first call sets up
1156 * process state (not recorded in ubik) that requires all further calls
1157 * of that group to be made to the same server process.
1159 * call this instead of stub and we'll guarantee to find a host that's up.
1160 * in the future, we should also put in a protocol to find the sync site
1164 ubik_Call_SingleServer(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16)
1165 register struct ubik_client *aclient;
1168 char *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14, *p15, *p16;
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 )
1181 if ( ((aflags & UF_SINGLESERVER) != 0 )
1182 && ((uServer.ucs_flags & UF_SINGLESERVER ) != 0)
1186 /* have a selected server */
1187 tc = aclient->conns[uServer.ucs_selectedServer];
1189 code = (*aproc)(tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11,
1190 p12, p13, p14, p15, p16);
1193 /* error. Clean up single server state */
1194 memset(&uServer, 0, sizeof(uServer));
1199 if ( (aflags & UF_END_SINGLESERVER) != 0 )
1201 memset(&uServer, 0, sizeof(uServer));
1206 someCode = UNOSERVERS;
1213 /* tc is the next conn to try */
1214 tc = aclient->conns[count];
1218 pass = 1; /* in pass 1, we look at down hosts, too */
1222 else break; /* nothing left to try */
1224 if (pass == 0 && (aclient->states[count] & CFLastFailed)) {
1226 continue; /* this guy's down, try someone else first */
1229 code = (*aproc)(tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16);
1231 /* note that getting a UNOTSYNC error code back does *not* guarantee
1232 * that there is a sync site yet elected. However, if there is a
1233 * sync site out there somewhere, and you're trying an operation that
1234 * requires a sync site, ubik will return UNOTSYNC, indicating the
1235 * operation won't work until you find a sync site
1237 if (code == UNOTSYNC)
1239 /* means that this requires a sync site to work */
1240 someCode = code; /* remember an error, if this fails */
1242 /* now see if we can find the sync site host */
1243 code = VOTE_GetSyncSite(tc, &newHost);
1244 if (code == 0 && newHost != 0) {
1245 newHost = htonl(newHost); /* convert back to network order */
1247 /* position count at the appropriate slot in the client
1248 * structure and retry. If we can't find in slot, we'll just
1249 * continue through the whole list
1251 for(i=0;i<MAXSERVERS;i++)
1253 rxp = rx_PeerOf(aclient->conns[i]);
1254 if (!(thisHost = rx_HostOf(rxp))) {
1255 count++; /* host not found, try the next dude */
1258 if (thisHost == newHost)
1260 /* avoid asking in a loop */
1261 if (chaseCount++ > 2)
1263 count = i; /* we were told to use this one */
1268 else count++; /* not directed, keep looking for a sync site */
1271 else if (code == UNOQUORUM) { /* this guy is still recovering */
1276 else if (code < 0) { /* network errors */
1278 aclient->states[count] |= CFLastFailed;
1284 /* ok, operation worked */
1285 aclient->states[count] &= ~CFLastFailed;
1286 /* either misc ubik code, or misc application code (incl success)
1289 /* if the call succeeded, setup connection state for subsequent
1293 && (aflags & UF_SINGLESERVER != 0)
1296 /* need to save state */
1297 uServer.ucs_flags = UF_SINGLESERVER;
1298 uServer.ucs_selectedServer = count;
1308 /* -------------------------------------
1309 * debug and test routines
1310 * -------------------------------------
1314 * For testing only. Open a connect to the database server running on
1317 * 0 - ubik connection established in the global udbHandle structure
1323 afs_int32 serverList[MAXSERVERS];
1329 /* get our host name */
1330 gethostname(hostname, sizeof(hostname));
1331 /* strcpy(hostname, "hops"); */
1334 args[1] = "-servers";
1337 code = ubik_ParseClientList(3, args, serverList);
1340 com_err(whoami, code, "; udbLocalInit: parsing ubik server list");
1344 udbHandle.uh_scIndex = RX_SCINDEX_NULL;
1345 udbHandle.uh_secobj = (struct rx_securityClass *)
1346 rxnull_NewClientSecurityObject();
1348 for ( i = 0; serverList[i] != 0; i++ )
1350 udbHandle.uh_serverConn[i] = rx_NewConnection (serverList[i],
1351 htons(AFSCONF_BUDBPORT),
1353 udbHandle.uh_secobj,
1354 udbHandle.uh_scIndex);
1355 if ( udbHandle.uh_serverConn[i] == 0 )
1357 com_err(whoami, 0, "connection %d failed", i);
1361 udbHandle.uh_serverConn[i] = 0;
1362 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1365 com_err(whoami, code, "; in ubik_ClientInit");
1369 code = ubik_Call(BUDB_GetInstanceId, udbHandle.uh_client, 0, &udbHandle.uh_instanceId);
1372 com_err(whoami, code, "; Can't estblish instance Id");
1380 /* bc_openTextFile - This function opens a temp file to read in the
1381 * config text recd from the bu server. On Unix, an unlink() is done on
1382 * the file as soon as it is opened, so when the program exits, the file will
1383 * be removed automatically, while being invisible while in use.
1384 * On NT, however, the file must be explicitly deleted after use with an unlink()
1386 * Pointer to a udhClientTextP struct. The open stream ptr is stored in
1387 * the udbClientTextP.textStream member.
1388 * Output: The temp file name is returned in tmpFileName. This should be used
1389 * to delete the file when done with it.
1394 int bc_openTextFile(udbClientTextP ctPtr, char *tmpFileName)
1398 if ( ctPtr->textStream != NULL )
1399 fclose(ctPtr->textStream);
1401 sprintf(tmpFileName, "%s/bu_XXXXXX", gettmpdir());
1402 #ifdef AFS_LINUX20_ENV
1403 mkstemp(tmpFileName);
1405 mktemp(tmpFileName);
1407 ctPtr->textStream = fopen(tmpFileName, "w+");
1408 if ( ctPtr->textStream == NULL )
1409 ERROR(BUDB_INTERNALERROR);
1411 #ifndef AFS_NT40_ENV /* This can't be done on NT */
1412 /* make the file invisible to others */
1413 code = unlink(tmpFileName);
1418 dprintf(("file is %s\n", tmpFileName));
1424 if ( ctPtr->textStream != NULL )
1426 fclose(ctPtr->textStream);
1427 ctPtr->textStream = NULL;
1433 /* bc_closeTextFile: This function closes any actual temp files associated with
1434 * a udbClientText structure.
1435 * Input: ctPtr->textStream - stream to close
1436 * tmpFileName - temp file name to delete
1441 int bc_closeTextFile(udbClientTextP ctPtr, char *tmpFileName)
1445 if (ctPtr->textStream)
1446 fclose(ctPtr->textStream);
1448 if (*tmpFileName) { /* we have a valid name */
1449 code = unlink(tmpFileName);