2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 /* Interface and supporting routines for the backup system's ubik database */
12 #include <afsconfig.h>
17 #ifdef IGNORE_SOME_GCC_WARNINGS
18 # pragma GCC diagnostic warning "-Wstrict-prototypes"
21 #include <sys/types.h>
25 #elif defined(AFS_SUN5_ENV)
28 #include <sys/param.h> /* for hostnames etc */
31 #include <afs/cellconfig.h>
33 #include <afs/volser.h>
34 #include <afs/volser_prototypes.h>
35 #include <afs/afsutil.h>
36 #include <afs/bubasics.h>
37 #include <afs/budb_client.h>
39 #include <afs/com_err.h>
43 #include "error_macros.h"
44 #include "bucoord_internal.h"
45 #include "bucoord_prototypes.h"
49 /* -------------------------------------
51 * -------------------------------------
54 struct udbHandleS udbHandle;
56 /* -------------------------------------
57 * interface routines (alphabetic)
58 * -------------------------------------
61 afs_int32 bcdb_AddVolume(struct budb_volumeEntry *veptr)
65 code = ubik_BUDB_AddVolume(udbHandle.uh_client, 0, veptr);
69 afs_int32 bcdb_AddVolumes(struct budb_volumeEntry *veptr, afs_int32 count)
71 struct budb_volumeList volumeList;
74 volumeList.budb_volumeList_len = count;
75 volumeList.budb_volumeList_val = veptr;
76 code = ubik_BUDB_AddVolumes(udbHandle.uh_client, 0, &volumeList);
81 afs_int32 bcdb_CreateDump(struct budb_dumpEntry *deptr)
85 code = ubik_BUDB_CreateDump(udbHandle.uh_client, 0, deptr);
89 afs_int32 bcdb_deleteDump(afs_int32 dumpID, afs_int32 fromTime, afs_int32 toTime,
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);
100 ubik_BUDB_DeleteDump(udbHandle.uh_client, 0, dumpID, fromTime,
102 if (dumpsList.budb_dumpsList_val)
103 free(dumpsList.budb_dumpsList_val);
107 afs_int32 bcdb_listDumps (afs_int32 sflags, afs_int32 groupId,
108 afs_int32 fromTime, afs_int32 toTime,
109 budb_dumpsList *dumps, budb_dumpsList *flags)
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);
124 ubik_BUDB_ListDumps(udbHandle.uh_client, 0, sflags, "", groupId,
125 fromTime, toTime, dumpsPtr, flagsPtr);
127 if (dumpsList.budb_dumpsList_val)
128 free(dumpsList.budb_dumpsList_val);
129 if (flagsList.budb_dumpsList_val)
130 free(flagsList.budb_dumpsList_val);
135 afs_int32 bcdb_DeleteVDP(char *dumpSetName, char *dumpPath, afs_int32 dumpID)
140 ubik_BUDB_DeleteVDP(udbHandle.uh_client, 0, dumpSetName,
146 * Returns the clone time of a volume by going up the parent chain.
147 * If no clone time is found, a clone time of 0 is returned, forcing
150 * dumpID - of the first dump to examine.
151 * volName - name of the volume for whom a clone time is required
152 * clonetime - ptr to vbl for returning result
154 * 0 - clonetime set appropriately
155 * -1 - error occured in traversing chain, clone time set to 0.
156 * -2 - no clone times found, clone time set to 0
159 afs_int32 bcdb_FindClone(afs_int32 dumpID, char *volName, afs_int32 *clonetime)
163 ubik_BUDB_FindClone(udbHandle.uh_client, 0, dumpID, volName,
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.
186 bcdb_FindDump(char *volumeName, afs_int32 beforeDate,
187 struct budb_dumpEntry *deptr)
191 ubik_BUDB_FindDump(udbHandle.uh_client, 0, volumeName,
197 * find a dump by id. Currently insists on a single return value.
199 * dumpID - id to lookup
203 bcdb_FindDumpByID(afs_int32 dumpID, struct budb_dumpEntry *deptr)
210 /* initialize the dump list */
211 dl.budb_dumpList_len = 0;
212 dl.budb_dumpList_val = 0;
214 /* outline algorithm */
215 code = ubik_BUDB_GetDumps(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_DUMPID, "", /* no name */
219 &nextindex, &dbTime, &dl);
222 || (dl.budb_dumpList_len != 1) /* single retn val expected */
224 /* printf("bcdb_FindDumpByID: code %d, nvalues %d\n",
225 code, dl.budb_dumpList_len); */
227 code = 1; /* multiple id's */
231 memcpy(deptr, dl.budb_dumpList_val, sizeof(*deptr));
234 if (dl.budb_dumpList_val) {
235 /* free any allocated structures */
236 free(dl.budb_dumpList_val);
241 memset(deptr, 0, sizeof(*deptr));
245 /* bcdb_FindLastVolClone
246 * Returns the clone time, from the most recent dump of volName, when
247 * dumped in the volume set volSetName, with dump schedule dumpName.
248 * The clone time can be used to check if the volume has been correctly
249 * re-cloned, and also is used as the time from which to do the current
252 * volSetName - name of volume set
253 * dumpName - full path of dump node
254 * volName - name of volume for whom a clone time is required
255 * clonetime - ptr to vbl for result
257 * 0 - clonetime set appropriately
259 * used only for warning generation. Suggest that this be omitted.
263 bcdb_FindLastVolClone(char *volSetName, char *dumpName, char *volName,
264 afs_int32 *clonetime)
268 * match on volumeset and dump path
269 * search for the volume name
274 /* bcdb_FindLatestDump
275 * find the latest dump with volume set component avname and the
276 * specified dump pathname. Used to find a dump, relative to which an
277 * incremental dump can be done. Defines the parent <-> child relations
280 * avname: volume set name
281 * dumpPath: full path of dump node
283 * 0: adentry: dump entry structure filled in.
284 * -1: probably an internal error
287 * Need to store volumeset name in dump in order to implement this.
288 * Need new routine since params are two strings
292 bcdb_FindLatestDump(char *volSetName, char *dumpPath,
293 struct budb_dumpEntry *deptr)
297 ubik_BUDB_FindLatestDump(udbHandle.uh_client, 0, volSetName,
306 * dumpid: dump id to which tape beint32s
307 * tapeName: name of tape
311 bcdb_FindTape(afs_int32 dumpid, char *tapeName,
312 struct budb_tapeEntry *teptr)
319 memset(teptr, 0, sizeof(*teptr));
320 tl.budb_tapeList_len = 0;
321 tl.budb_tapeList_val = 0;
324 ubik_BUDB_GetTapes(udbHandle.uh_client, 0, BUDB_MAJORVERSION,
325 BUDB_OP_TAPENAME | BUDB_OP_DUMPID, tapeName, dumpid, 0, 0,
326 &next, &dbTime, &tl);
331 if (tl.budb_tapeList_len != 1)
332 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
334 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
337 if (tl.budb_tapeList_val)
338 free(tl.budb_tapeList_val);
343 bcdb_FindTapeSeq(afs_int32 dumpid, afs_int32 tapeSeq,
344 struct budb_tapeEntry *teptr)
351 memset(teptr, 0, sizeof(*teptr));
352 tl.budb_tapeList_len = 0;
353 tl.budb_tapeList_val = 0;
356 ubik_BUDB_GetTapes(udbHandle.uh_client, 0, BUDB_MAJORVERSION,
357 BUDB_OP_TAPESEQ | BUDB_OP_DUMPID, "", dumpid, tapeSeq, 0,
358 &next, &dbTime, &tl);
362 if (tl.budb_tapeList_len != 1)
363 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
365 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
368 if (tl.budb_tapeList_val)
369 free(tl.budb_tapeList_val);
375 * - this is part of dblookup. The existing semantics will not work since
376 * they do lookups based on dump id.
377 * - in the restore code, it uses this to extract information about
378 * the volume. Need current semantics. Could filter the output, selecting
380 * - Suggest that the lookup be based on volume name only, with optional
381 * match on backup, and readonly volumes.
382 * - Further, need to check if the volume structure returns enough
387 bcdb_FindVolumes(afs_int32 dumpID, char *volumeName,
388 struct budb_volumeEntry *returnArray,
389 afs_int32 last, afs_int32 *next, afs_int32 maxa,
396 vl.budb_volumeList_len = maxa;
397 vl.budb_volumeList_val = returnArray;
399 /* outline algorithm */
400 code = ubik_BUDB_GetVolumes(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME | BUDB_OP_DUMPID, volumeName, /* name */
404 next, /* nextindex */
407 *nEntries = vl.budb_volumeList_len;
412 bcdb_FinishDump(struct budb_dumpEntry *deptr)
415 code = ubik_BUDB_FinishDump(udbHandle.uh_client, 0, deptr);
420 bcdb_FinishTape(struct budb_tapeEntry *teptr)
423 code = ubik_BUDB_FinishTape(udbHandle.uh_client, 0, teptr);
428 /* bcdb_LookupVolumes
432 bcdb_LookupVolume(char *volumeName, struct budb_volumeEntry *returnArray,
433 afs_int32 last, afs_int32 *next, afs_int32 maxa,
440 vl.budb_volumeList_len = maxa;
441 vl.budb_volumeList_val = returnArray;
443 /* outline algorithm */
444 code = ubik_BUDB_GetVolumes(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME, volumeName, /* name */
448 next, /* nextindex */
454 *nEntries = vl.budb_volumeList_len;
459 bcdb_UseTape(struct budb_tapeEntry *teptr, afs_int32 *newFlag)
462 code = ubik_BUDB_UseTape(udbHandle.uh_client, 0, teptr, newFlag);
467 /* ---- text configuration handling routines ----
470 * The caller should pass in/out a fid for an unlinked, open file to prevent
471 * tampering with the files contents;
475 * extract the specified textType and put it in a temporary, local
478 * ctPtr - ptr to client structure with all the required information
482 bcdb_GetTextFile(udbClientTextP ctPtr)
484 afs_int32 bufferSize;
485 afs_int32 offset, nextOffset;
489 /* Initialize charlistT_val. We try to deallocate this structure based on
491 memset((void *)&charList, 0, sizeof(charList));
493 /* check params and cleanup any previous state */
494 if (ctPtr->lockHandle == 0)
495 ERROR(BUDB_INTERNALERROR);
497 if (ctPtr->textStream == NULL) /* Should have an open stream */
498 ERROR(BUDB_INTERNALERROR);
500 /* allocate a buffer */
502 charList.charListT_val = (char *)malloc(bufferSize);
503 if (charList.charListT_val == 0)
504 ERROR(BUDB_INTERNALERROR);
505 charList.charListT_len = bufferSize;
510 while (nextOffset != -1) {
512 charList.charListT_len = bufferSize;
514 ubik_BUDB_GetText(udbHandle.uh_client, 0, ctPtr->lockHandle,
515 ctPtr->textType, bufferSize, offset, &nextOffset,
522 fwrite(charList.charListT_val, sizeof(char),
523 charList.charListT_len, ctPtr->textStream);
524 if (ferror(ctPtr->textStream))
525 ERROR(BUDB_INTERNALERROR);
527 ctPtr->textSize += charList.charListT_len;
530 /* get text version */
532 ubik_BUDB_GetTextVersion(udbHandle.uh_client, 0,
533 ctPtr->textType, &ctPtr->textVersion);
538 fflush(ctPtr->textStream); /* debug */
540 /* exit, leaving the configuration text file open */
541 if (charList.charListT_val)
542 free(charList.charListT_val);
546 if (ctPtr->textStream != NULL) {
547 fclose(ctPtr->textStream);
548 ctPtr->textStream = NULL;
555 * save the text file in ubik database
557 * textType - identifies type of configuration file
558 * filename - where to get the text from
562 bcdb_SaveTextFile(udbClientTextP ctPtr)
564 afs_int32 bufferSize;
565 afs_int32 offset, chunkSize, fileSize;
569 /* allocate a buffer */
571 charList.charListT_val = (char *)malloc(bufferSize);
572 if (charList.charListT_val == 0)
573 ERROR(BUDB_INTERNALERROR);
574 charList.charListT_len = bufferSize;
576 if (ctPtr->textStream == NULL)
577 ERROR(BUDB_INTERNALERROR);
578 rewind(ctPtr->textStream);
580 fileSize = (afs_int32) filesize(ctPtr->textStream);
582 afs_dprintf(("filesize is %d\n", fileSize));
584 rewind(ctPtr->textStream);
586 /* special case empty files */
588 charList.charListT_len = 0;
590 ubik_BUDB_SaveText(udbHandle.uh_client, 0,
591 ctPtr->lockHandle, ctPtr->textType, 0,
592 BUDB_TEXT_COMPLETE, &charList);
597 while (fileSize != 0) {
598 chunkSize = MIN(fileSize, bufferSize);
600 fread(charList.charListT_val, sizeof(char), chunkSize,
603 if (code != chunkSize)
604 printf("code = %d\n", code);
605 if (ferror(ctPtr->textStream))
606 ERROR(BUDB_INTERNALERROR);
608 charList.charListT_len = chunkSize;
610 ubik_BUDB_SaveText(udbHandle.uh_client, 0,
611 ctPtr->lockHandle, ctPtr->textType, offset,
612 (chunkSize == fileSize) ? BUDB_TEXT_COMPLETE : 0,
617 fileSize -= chunkSize;
622 /* if ( ctPtr->textStream >= 0 )
623 * close(ctPtr->textStream); */
624 if (charList.charListT_val)
625 free(charList.charListT_val);
630 bcdb_FindLastTape(afs_int32 dumpID, struct budb_dumpEntry *dumpEntry,
631 struct budb_tapeEntry *tapeEntry,
632 struct budb_volumeEntry *volEntry)
634 return (ubik_BUDB_FindLastTape(udbHandle.uh_client, 0, dumpID, dumpEntry,
635 tapeEntry, volEntry));
639 bcdb_MakeDumpAppended(afs_int32 appendedDumpID, afs_int32 initialDumpID,
640 afs_int32 startTapeSeq)
642 return (ubik_BUDB_MakeDumpAppended(udbHandle.uh_client, 0, appendedDumpID,
643 initialDumpID, startTapeSeq));
647 /* -------------------------------------
648 * misc. support routines
649 * -------------------------------------
653 filesize(FILE *stream)
658 offset = ftell(stream);
659 fseek(stream, (afs_int32) 0, 2); /* end of file */
660 size = ftell(stream);
661 fseek(stream, offset, 0);
666 /* ------------------------------------
667 * misc. support routines - general text management
668 * ------------------------------------
673 * locks the text described by the ctPtr
675 * ctptr - client text ptr
682 bc_LockText(udbClientTextP ctPtr)
685 afs_int32 timeout, j = 0;
687 if (ctPtr->lockHandle != 0)
688 return (1); /* already locked */
691 ((ctPtr->textSize == 0) ? 30 : ((ctPtr->textSize / 50000) + 10));
695 ubik_BUDB_GetLock(udbHandle.uh_client, 0,
696 udbHandle.uh_instanceId, ctPtr->textType, timeout,
698 if ((code != BUDB_LOCKED) && (code != BUDB_SELFLOCKED)) {
702 /* Mention something every 30 seconds */
704 afs_com_err(whoami, code,
705 "; Waiting for db configuration text unlock");
708 #ifdef AFS_PTHREAD_ENV
717 ctPtr->lockHandle = 0;
722 * unlocks the text described by the ctPtr
724 * ctptr - client text ptr
731 bc_UnlockText(udbClientTextP ctPtr)
735 if (ctPtr->lockHandle == 0)
739 ubik_BUDB_FreeLock(udbHandle.uh_client, 0, ctPtr->lockHandle);
740 ctPtr->lockHandle = 0;
742 /* Don't try to analyse the error. Let the lock timeout */
746 /* bc_CheckTextVersion
749 * n - out of date or error
753 bc_CheckTextVersion(udbClientTextP ctPtr)
758 if (ctPtr->textVersion == -1)
759 return (BC_VERSIONMISMATCH);
762 ubik_BUDB_GetTextVersion(udbHandle.uh_client, 0,
763 ctPtr->textType, &tversion);
766 if (tversion != ctPtr->textVersion)
767 return (BC_VERSIONMISMATCH);
771 /* -------------------------------------
772 * initialization routines
773 * -------------------------------------
776 static afsconf_secflags
777 parseSecFlags(int noAuthFlag, int localauth, const char **confdir) {
778 afsconf_secflags secFlags;
782 secFlags |= AFSCONF_SECOPTS_NOAUTH;
785 secFlags |= AFSCONF_SECOPTS_LOCALAUTH;
786 *confdir = AFSDIR_SERVER_ETC_DIRPATH;
788 *confdir = AFSDIR_CLIENT_ETC_DIRPATH;
794 * Initialize a client for the vl ubik database.
797 vldbClientInit(int noAuthFlag, int localauth, char *cellName,
798 struct ubik_client **cstruct,
802 struct afsconf_dir *acdir;
803 struct rx_securityClass *sc;
804 afs_int32 i, scIndex = RX_SECIDX_NULL;
805 struct afsconf_cell info;
806 struct rx_connection *serverconns[VLDB_MAXSERVERS];
807 afsconf_secflags secFlags;
810 secFlags = parseSecFlags(noAuthFlag, localauth, &confdir);
811 secFlags |= AFSCONF_SECOPTS_FALLBACK_NULL;
813 /* This just preserves old behaviour of using the default cell when
814 * passed an empty string */
815 if (cellName && cellName[0] == '\0')
818 /* Find out about the given cell */
819 acdir = afsconf_Open(confdir);
821 afs_com_err(whoami, 0, "Can't open configuration directory '%s'", confdir);
822 ERROR(BC_NOCELLCONFIG);
825 code = afsconf_GetCellInfo(acdir, cellName, AFSCONF_VLDBSERVICE, &info);
827 afs_com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
828 cellName, confdir, AFSDIR_CELLSERVDB_FILE);
829 ERROR(BC_NOCELLCONFIG);
832 code = afsconf_PickClientSecObj(acdir, secFlags, &info, cellName,
833 &sc, &scIndex, expires);
835 afs_com_err(whoami, code, "(configuring connection security)");
836 ERROR(BC_NOCELLCONFIG);
838 if (scIndex == RX_SECIDX_NULL && !noAuthFlag)
839 afs_com_err(whoami, 0, "Can't get tokens - running unauthenticated");
841 /* tell UV module about default authentication */
842 UV_SetSecurity(sc, scIndex);
844 if (info.numServers > VLDB_MAXSERVERS) {
845 afs_com_err(whoami, 0,
846 "Warning: %d VLDB servers exist for cell '%s', can only remember the first %d",
847 info.numServers, cellName, VLDB_MAXSERVERS);
848 info.numServers = VLDB_MAXSERVERS;
851 for (i = 0; i < info.numServers; i++)
853 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
854 info.hostAddr[i].sin_port, USER_SERVICE_ID, sc,
859 code = ubik_ClientInit(serverconns, cstruct);
861 afs_com_err(whoami, code, "; Can't initialize ubik connection to vldb");
867 afsconf_Close(acdir);
872 * initialize a client for the backup systems ubik database.
876 udbClientInit(int noAuthFlag, int localauth, char *cellName)
878 struct afsconf_cell info;
879 struct afsconf_dir *acdir;
885 secFlags = parseSecFlags(noAuthFlag, localauth, &confdir);
886 secFlags |= AFSCONF_SECOPTS_FALLBACK_NULL;
888 if (cellName && cellName[0] == '\0')
891 acdir = afsconf_Open(confdir);
893 afs_com_err(whoami, 0, "Can't open configuration directory '%s'",
895 ERROR(BC_NOCELLCONFIG);
898 code = afsconf_GetCellInfo(acdir, cellName, 0, &info);
900 afs_com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
901 cellName, confdir, AFSDIR_CELLSERVDB_FILE);
902 ERROR(BC_NOCELLCONFIG);
905 code = afsconf_PickClientSecObj(acdir, secFlags, &info, cellName,
906 &udbHandle.uh_secobj,
907 &udbHandle.uh_scIndex, NULL);
909 afs_com_err(whoami, code, "(configuring connection security)");
910 ERROR(BC_NOCELLCONFIG);
912 if (&udbHandle.uh_scIndex == RX_SECIDX_NULL && !noAuthFlag)
913 afs_com_err(whoami, 0, "Can't get tokens - running unauthenticated");
915 if (info.numServers > MAXSERVERS) {
916 afs_com_err(whoami, 0,
917 "Warning: %d BDB servers exist for cell '%s', can only remember the first %d",
918 info.numServers, cellName, MAXSERVERS);
919 info.numServers = MAXSERVERS;
922 /* establish connections to the servers. Check for failed connections? */
923 for (i = 0; i < info.numServers; i++) {
924 udbHandle.uh_serverConn[i] =
925 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
926 htons(AFSCONF_BUDBPORT), BUDB_SERVICE,
927 udbHandle.uh_secobj, udbHandle.uh_scIndex);
929 udbHandle.uh_serverConn[i] = 0;
931 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
933 afs_com_err(whoami, code,
934 "; Can't initialize ubik connection to backup database");
938 /* Try to quickly find a good site by setting deadtime low */
939 for (i = 0; i < info.numServers; i++)
940 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 1);
942 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
943 &udbHandle.uh_instanceId);
945 /* Reset dead time back up to default */
946 for (i = 0; i < info.numServers; i++)
947 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 60);
949 /* If did not find a site on first quick pass, try again */
952 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
953 &udbHandle.uh_instanceId);
955 afs_com_err(whoami, code, "; Can't access backup database");
961 afsconf_Close(acdir);
965 /* -------------------------------------
966 * specialized ubik support
967 * -------------------------------------
975 * 1) first call with SINGLESERVER set, record the server to be used.
976 * 2) subsequent calls use that server. If a failure is encountered,
977 * the state is cleaned up and the error returned back to the caller.
978 * 3) upon completion, the user must make a dummy call with
979 * END_SINGLESERVER set, to clean up state.
980 * 4) if the vanilla ubik_Call is ever modified, the END_SINGLESERVER
981 * flag can be discarded. The first call without SINGLESERVER set
982 * can clean up the state.
985 struct ubikCallState {
986 afs_int32 ucs_flags; /* state flags */
987 afs_int32 ucs_selectedServer; /* which server selected */
990 static struct ubikCallState uServer;
992 /* ubik_Call_SingleServer
993 * variant of ubik_Call. This is used by the backup system to initiate
994 * a series of calls to a single ubik server. The first call sets up
995 * process state (not recorded in ubik) that requires all further calls
996 * of that group to be made to the same server process.
998 * call this instead of stub and we'll guarantee to find a host that's up.
999 * in the future, we should also put in a protocol to find the sync site
1003 ubik_Call_SingleServer(int (*aproc) (), struct ubik_client *aclient,
1004 afs_int32 aflags, char *p1, char *p2, char *p3,
1005 char *p4, char *p5, char *p6, char *p7, char *p8,
1006 char *p9, char *p10, char *p11, char *p12, char *p13,
1007 char *p14, char *p15, char *p16)
1010 afs_int32 someCode, newHost, thisHost;
1015 struct rx_connection *tc;
1016 struct rx_peer *rxp;
1018 if ((aflags & (UF_SINGLESERVER | UF_END_SINGLESERVER)) != 0) {
1019 if (((aflags & UF_SINGLESERVER) != 0)
1020 && ((uServer.ucs_flags & UF_SINGLESERVER) != 0)
1023 /* have a selected server */
1024 tc = aclient->conns[uServer.ucs_selectedServer];
1027 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11,
1028 p12, p13, p14, p15, p16);
1030 /* error. Clean up single server state */
1031 memset(&uServer, 0, sizeof(uServer));
1034 } else if ((aflags & UF_END_SINGLESERVER) != 0) {
1035 memset(&uServer, 0, sizeof(uServer));
1040 someCode = UNOSERVERS;
1046 /* tc is the next conn to try */
1047 tc = aclient->conns[count];
1050 pass = 1; /* in pass 1, we look at down hosts, too */
1054 break; /* nothing left to try */
1056 if (pass == 0 && (aclient->states[count] & CFLastFailed)) {
1058 continue; /* this guy's down, try someone else first */
1062 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12,
1063 p13, p14, p15, p16);
1065 /* note that getting a UNOTSYNC error code back does *not* guarantee
1066 * that there is a sync site yet elected. However, if there is a
1067 * sync site out there somewhere, and you're trying an operation that
1068 * requires a sync site, ubik will return UNOTSYNC, indicating the
1069 * operation won't work until you find a sync site
1071 if (code == UNOTSYNC) { /*ns */
1072 /* means that this requires a sync site to work */
1073 someCode = code; /* remember an error, if this fails */
1075 /* now see if we can find the sync site host */
1076 code = VOTE_GetSyncSite(tc, &newHost);
1077 if (code == 0 && newHost != 0) {
1078 newHost = htonl(newHost); /* convert back to network order */
1080 /* position count at the appropriate slot in the client
1081 * structure and retry. If we can't find in slot, we'll just
1082 * continue through the whole list
1084 for (i = 0; i < MAXSERVERS; i++) { /*f */
1085 rxp = rx_PeerOf(aclient->conns[i]);
1086 if (!(thisHost = rx_HostOf(rxp))) {
1087 count++; /* host not found, try the next dude */
1090 if (thisHost == newHost) {
1091 /* avoid asking in a loop */
1092 if (chaseCount++ > 2)
1094 count = i; /* we were told to use this one */
1099 count++; /* not directed, keep looking for a sync site */
1102 else if (code == UNOQUORUM) { /* this guy is still recovering */
1106 } else if (code < 0) { /* network errors */
1108 aclient->states[count] |= CFLastFailed;
1112 /* ok, operation worked */
1113 aclient->states[count] &= ~CFLastFailed;
1114 /* either misc ubik code, or misc application code (incl success)
1117 /* if the call succeeded, setup connection state for subsequent
1121 && ((aflags & UF_SINGLESERVER) != 0)
1123 /* need to save state */
1124 uServer.ucs_flags = UF_SINGLESERVER;
1125 uServer.ucs_selectedServer = count;
1135 /* -------------------------------------
1136 * debug and test routines
1137 * -------------------------------------
1141 * For testing only. Open a connect to the database server running on
1144 * 0 - ubik connection established in the global udbHandle structure
1151 afs_uint32 serverList[MAXSERVERS];
1157 /* get our host name */
1158 gethostname(hostname, sizeof(hostname));
1159 /* strcpy(hostname, "hops"); */
1162 args[1] = "-servers";
1165 code = ubik_ParseClientList(3, args, serverList);
1167 afs_com_err(whoami, code, "; udbLocalInit: parsing ubik server list");
1171 udbHandle.uh_scIndex = RX_SECIDX_NULL;
1172 udbHandle.uh_secobj = (struct rx_securityClass *)
1173 rxnull_NewClientSecurityObject();
1175 for (i = 0; serverList[i] != 0; i++) {
1176 udbHandle.uh_serverConn[i] =
1177 rx_NewConnection(serverList[i], htons(AFSCONF_BUDBPORT),
1178 BUDB_SERVICE, udbHandle.uh_secobj,
1179 udbHandle.uh_scIndex);
1180 if (udbHandle.uh_serverConn[i] == 0) {
1181 afs_com_err(whoami, 0, "connection %d failed", i);
1185 udbHandle.uh_serverConn[i] = 0;
1186 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1188 afs_com_err(whoami, code, "; in ubik_ClientInit");
1193 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
1194 &udbHandle.uh_instanceId);
1196 afs_com_err(whoami, code, "; Can't estblish instance Id");
1204 /* bc_openTextFile - This function opens a temp file to read in the
1205 * config text recd from the bu server. On Unix, an unlink() is done on
1206 * the file as soon as it is opened, so when the program exits, the file will
1207 * be removed automatically, while being invisible while in use.
1208 * On NT, however, the file must be explicitly deleted after use with an unlink()
1210 * Pointer to a udhClientTextP struct. The open stream ptr is stored in
1211 * the udbClientTextP.textStream member.
1212 * Output: The temp file name is returned in tmpFileName. This should be used
1213 * to delete the file when done with it.
1219 bc_openTextFile(udbClientTextP ctPtr, char *tmpFileName)
1226 if (ctPtr->textStream != NULL) {
1227 fclose(ctPtr->textStream);
1228 ctPtr->textStream = NULL;
1231 sprintf(tmpFileName, "%s/bu_XXXXXX", gettmpdir());
1233 fd = mkstemp(tmpFileName);
1235 ERROR(BUDB_INTERNALERROR);
1236 ctPtr->textStream = fdopen(fd, "w+");
1238 mktemp(tmpFileName);
1239 ctPtr->textStream = fopen(tmpFileName, "w+");
1241 if (ctPtr->textStream == NULL)
1242 ERROR(BUDB_INTERNALERROR);
1244 #ifndef AFS_NT40_ENV /* This can't be done on NT */
1245 /* make the file invisible to others */
1246 code = unlink(tmpFileName);
1251 afs_dprintf(("file is %s\n", tmpFileName));
1257 if (ctPtr->textStream != NULL) {
1258 fclose(ctPtr->textStream);
1259 ctPtr->textStream = NULL;
1265 /* bc_closeTextFile: This function closes any actual temp files associated with
1266 * a udbClientText structure.
1267 * Input: ctPtr->textStream - stream to close
1268 * tmpFileName - temp file name to delete
1274 bc_closeTextFile(udbClientTextP ctPtr, char *tmpFileName)
1278 if (ctPtr->textStream)
1279 fclose(ctPtr->textStream);
1281 if (*tmpFileName) { /* we have a valid name */
1282 code = unlink(tmpFileName);