2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 /* Interface and supporting routines for the backup system's ubik database */
12 #include <afsconfig.h>
15 #ifdef IGNORE_SOME_GCC_WARNINGS
16 # pragma GCC diagnostic warning "-Wstrict-prototypes"
19 #include <sys/types.h>
23 #elif defined(AFS_SUN5_ENV)
26 #include <sys/param.h> /* for hostnames etc */
29 #include <afs/cellconfig.h>
31 #include <afs/volser.h>
32 #include <afs/volser_prototypes.h>
33 #include <afs/afsutil.h>
34 #include <afs/bubasics.h>
35 #include <afs/budb_client.h>
37 #include <afs/com_err.h>
41 #include "error_macros.h"
42 #include "bucoord_internal.h"
43 #include "bucoord_prototypes.h"
47 /* -------------------------------------
49 * -------------------------------------
52 struct udbHandleS udbHandle;
54 /* -------------------------------------
55 * interface routines (alphabetic)
56 * -------------------------------------
59 afs_int32 bcdb_AddVolume(register struct budb_volumeEntry *veptr)
63 code = ubik_BUDB_AddVolume(udbHandle.uh_client, 0, veptr);
67 afs_int32 bcdb_AddVolumes(register struct budb_volumeEntry *veptr, afs_int32 count)
69 struct budb_volumeList volumeList;
72 volumeList.budb_volumeList_len = count;
73 volumeList.budb_volumeList_val = veptr;
74 code = ubik_BUDB_AddVolumes(udbHandle.uh_client, 0, &volumeList);
79 afs_int32 bcdb_CreateDump(register struct budb_dumpEntry *deptr)
83 code = ubik_BUDB_CreateDump(udbHandle.uh_client, 0, deptr);
87 afs_int32 bcdb_deleteDump(afs_int32 dumpID, afs_int32 fromTime, afs_int32 toTime,
88 budb_dumpsList *dumps)
91 budb_dumpsList dumpsList, *dumpsPtr;
93 dumpsList.budb_dumpsList_len = 0;
94 dumpsList.budb_dumpsList_val = 0;
95 dumpsPtr = (dumps ? dumps : &dumpsList);
98 ubik_BUDB_DeleteDump(udbHandle.uh_client, 0, dumpID, fromTime,
100 if (dumpsList.budb_dumpsList_val)
101 free(dumpsList.budb_dumpsList_val);
105 afs_int32 bcdb_listDumps (afs_int32 sflags, afs_int32 groupId,
106 afs_int32 fromTime, afs_int32 toTime,
107 budb_dumpsList *dumps, budb_dumpsList *flags)
110 budb_dumpsList dumpsList, *dumpsPtr;
111 budb_dumpsList flagsList, *flagsPtr;
113 dumpsList.budb_dumpsList_len = 0;
114 dumpsList.budb_dumpsList_val = 0;
115 dumpsPtr = (dumps ? dumps : &dumpsList);
117 flagsList.budb_dumpsList_len = 0;
118 flagsList.budb_dumpsList_val = 0;
119 flagsPtr = (flags ? flags : &flagsList);
122 ubik_BUDB_ListDumps(udbHandle.uh_client, 0, sflags, "", groupId,
123 fromTime, toTime, dumpsPtr, flagsPtr);
125 if (dumpsList.budb_dumpsList_val)
126 free(dumpsList.budb_dumpsList_val);
127 if (flagsList.budb_dumpsList_val)
128 free(flagsList.budb_dumpsList_val);
133 afs_int32 bcdb_DeleteVDP(char *dumpSetName, char *dumpPath, afs_int32 dumpID)
138 ubik_BUDB_DeleteVDP(udbHandle.uh_client, 0, dumpSetName,
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
157 afs_int32 bcdb_FindClone(afs_int32 dumpID, char *volName, afs_int32 *clonetime)
161 ubik_BUDB_FindClone(udbHandle.uh_client, 0, dumpID, volName,
167 * scan entire database for latest volume dump before adate. Optimize
168 * further by reading only the first line of the dump and if it is older
169 * than the oldest acceptable dump we've found so far, we don't bother
170 * scanning the dump file we've just opened
172 * Used by restore code when restoring a user requested volume(s)
174 * volumeName - name of volume to match on
175 * beforeDate - look for dumps older than this date
177 * deptr - desciptor of most recent dump
179 * should be able to implement this in a single call rather than
180 * the current multiple bcdb_ call algorithm.
184 bcdb_FindDump(char *volumeName, afs_int32 beforeDate,
185 struct budb_dumpEntry *deptr)
189 ubik_BUDB_FindDump(udbHandle.uh_client, 0, volumeName,
195 * find a dump by id. Currently insists on a single return value.
197 * dumpID - id to lookup
201 bcdb_FindDumpByID(afs_int32 dumpID, struct budb_dumpEntry *deptr)
203 register afs_int32 code;
208 /* initialize the dump list */
209 dl.budb_dumpList_len = 0;
210 dl.budb_dumpList_val = 0;
212 /* outline algorithm */
213 code = ubik_BUDB_GetDumps(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_DUMPID, "", /* no name */
217 &nextindex, &dbTime, &dl);
220 || (dl.budb_dumpList_len != 1) /* single retn val expected */
222 /* printf("bcdb_FindDumpByID: code %d, nvalues %d\n",
223 code, dl.budb_dumpList_len); */
225 code = 1; /* multiple id's */
229 memcpy(deptr, dl.budb_dumpList_val, sizeof(*deptr));
232 if (dl.budb_dumpList_val) {
233 /* free any allocated structures */
234 free(dl.budb_dumpList_val);
239 memset(deptr, 0, sizeof(*deptr));
243 /* bcdb_FindLastVolClone
244 * Returns the clone time, from the most recent dump of volName, when
245 * dumped in the volume set volSetName, with dump schedule dumpName.
246 * The clone time can be used to check if the volume has been correctly
247 * re-cloned, and also is used as the time from which to do the current
250 * volSetName - name of volume set
251 * dumpName - full path of dump node
252 * volName - name of volume for whom a clone time is required
253 * clonetime - ptr to vbl for result
255 * 0 - clonetime set appropriately
257 * used only for warning generation. Suggest that this be omitted.
261 bcdb_FindLastVolClone(char *volSetName, char *dumpName, char *volName,
262 afs_int32 *clonetime)
266 * match on volumeset and dump path
267 * search for the volume name
272 /* bcdb_FindLatestDump
273 * find the latest dump with volume set component avname and the
274 * specified dump pathname. Used to find a dump, relative to which an
275 * incremental dump can be done. Defines the parent <-> child relations
278 * avname: volume set name
279 * dumpPath: full path of dump node
281 * 0: adentry: dump entry structure filled in.
282 * -1: probably an internal error
285 * Need to store volumeset name in dump in order to implement this.
286 * Need new routine since params are two strings
290 bcdb_FindLatestDump(char *volSetName, char *dumpPath,
291 struct budb_dumpEntry *deptr)
295 ubik_BUDB_FindLatestDump(udbHandle.uh_client, 0, volSetName,
304 * dumpid: dump id to which tape beint32s
305 * tapeName: name of tape
309 bcdb_FindTape(afs_int32 dumpid, char *tapeName,
310 struct budb_tapeEntry *teptr)
317 memset(teptr, 0, sizeof(*teptr));
318 tl.budb_tapeList_len = 0;
319 tl.budb_tapeList_val = 0;
322 ubik_BUDB_GetTapes(udbHandle.uh_client, 0, BUDB_MAJORVERSION,
323 BUDB_OP_TAPENAME | BUDB_OP_DUMPID, tapeName, dumpid, 0, 0,
324 &next, &dbTime, &tl);
329 if (tl.budb_tapeList_len != 1)
330 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
332 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
335 if (tl.budb_tapeList_val)
336 free(tl.budb_tapeList_val);
341 bcdb_FindTapeSeq(afs_int32 dumpid, afs_int32 tapeSeq,
342 struct budb_tapeEntry *teptr)
349 memset(teptr, 0, sizeof(*teptr));
350 tl.budb_tapeList_len = 0;
351 tl.budb_tapeList_val = 0;
354 ubik_BUDB_GetTapes(udbHandle.uh_client, 0, BUDB_MAJORVERSION,
355 BUDB_OP_TAPESEQ | BUDB_OP_DUMPID, "", dumpid, tapeSeq, 0,
356 &next, &dbTime, &tl);
360 if (tl.budb_tapeList_len != 1)
361 ERROR(BC_NOTUNIQUE); /* expecting a single descriptor */
363 memcpy(teptr, tl.budb_tapeList_val, sizeof(*teptr));
366 if (tl.budb_tapeList_val)
367 free(tl.budb_tapeList_val);
373 * - this is part of dblookup. The existing semantics will not work since
374 * they do lookups based on dump id.
375 * - in the restore code, it uses this to extract information about
376 * the volume. Need current semantics. Could filter the output, selecting
378 * - Suggest that the lookup be based on volume name only, with optional
379 * match on backup, and readonly volumes.
380 * - Further, need to check if the volume structure returns enough
385 bcdb_FindVolumes(afs_int32 dumpID, char *volumeName,
386 struct budb_volumeEntry *returnArray,
387 afs_int32 last, afs_int32 *next, afs_int32 maxa,
394 vl.budb_volumeList_len = maxa;
395 vl.budb_volumeList_val = returnArray;
397 /* outline algorithm */
398 code = ubik_BUDB_GetVolumes(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME | BUDB_OP_DUMPID, volumeName, /* name */
402 next, /* nextindex */
405 *nEntries = vl.budb_volumeList_len;
410 bcdb_FinishDump(register struct budb_dumpEntry *deptr)
413 code = ubik_BUDB_FinishDump(udbHandle.uh_client, 0, deptr);
418 bcdb_FinishTape(register struct budb_tapeEntry *teptr)
421 code = ubik_BUDB_FinishTape(udbHandle.uh_client, 0, teptr);
426 /* bcdb_LookupVolumes
430 bcdb_LookupVolume(char *volumeName, struct budb_volumeEntry *returnArray,
431 afs_int32 last, afs_int32 *next, afs_int32 maxa,
438 vl.budb_volumeList_len = maxa;
439 vl.budb_volumeList_val = returnArray;
441 /* outline algorithm */
442 code = ubik_BUDB_GetVolumes(udbHandle.uh_client, 0, BUDB_MAJORVERSION, BUDB_OP_VOLUMENAME, volumeName, /* name */
446 next, /* nextindex */
452 *nEntries = vl.budb_volumeList_len;
457 bcdb_UseTape(struct budb_tapeEntry *teptr, afs_int32 *newFlag)
460 code = ubik_BUDB_UseTape(udbHandle.uh_client, 0, teptr, newFlag);
465 /* ---- text configuration handling routines ----
468 * The caller should pass in/out a fid for an unlinked, open file to prevent
469 * tampering with the files contents;
473 * extract the specified textType and put it in a temporary, local
476 * ctPtr - ptr to client structure with all the required information
480 bcdb_GetTextFile(register udbClientTextP ctPtr)
482 afs_int32 bufferSize;
483 afs_int32 offset, nextOffset;
487 /* Initialize charlistT_val. We try to deallocate this structure based on
489 memset((void *)&charList, 0, sizeof(charList));
491 /* check params and cleanup any previous state */
492 if (ctPtr->lockHandle == 0)
493 ERROR(BUDB_INTERNALERROR);
495 if (ctPtr->textStream == NULL) /* Should have an open stream */
496 ERROR(BUDB_INTERNALERROR);
498 /* allocate a buffer */
500 charList.charListT_val = (char *)malloc(bufferSize);
501 if (charList.charListT_val == 0)
502 ERROR(BUDB_INTERNALERROR);
503 charList.charListT_len = bufferSize;
508 while (nextOffset != -1) {
510 charList.charListT_len = bufferSize;
512 ubik_BUDB_GetText(udbHandle.uh_client, 0, ctPtr->lockHandle,
513 ctPtr->textType, bufferSize, offset, &nextOffset,
520 fwrite(charList.charListT_val, sizeof(char),
521 charList.charListT_len, ctPtr->textStream);
522 if (ferror(ctPtr->textStream))
523 ERROR(BUDB_INTERNALERROR);
525 ctPtr->textSize += charList.charListT_len;
528 /* get text version */
530 ubik_BUDB_GetTextVersion(udbHandle.uh_client, 0,
531 ctPtr->textType, &ctPtr->textVersion);
536 fflush(ctPtr->textStream); /* debug */
538 /* exit, leaving the configuration text file open */
539 if (charList.charListT_val)
540 free(charList.charListT_val);
544 if (ctPtr->textStream != NULL) {
545 fclose(ctPtr->textStream);
546 ctPtr->textStream = NULL;
553 * save the text file in ubik database
555 * textType - identifies type of configuration file
556 * filename - where to get the text from
560 bcdb_SaveTextFile(udbClientTextP ctPtr)
562 afs_int32 bufferSize;
563 afs_int32 offset, chunkSize, fileSize;
567 /* allocate a buffer */
569 charList.charListT_val = (char *)malloc(bufferSize);
570 if (charList.charListT_val == 0)
571 ERROR(BUDB_INTERNALERROR);
572 charList.charListT_len = bufferSize;
574 if (ctPtr->textStream == NULL)
575 ERROR(BUDB_INTERNALERROR);
576 rewind(ctPtr->textStream);
578 fileSize = (afs_int32) filesize(ctPtr->textStream);
580 afs_dprintf(("filesize is %d\n", fileSize));
582 rewind(ctPtr->textStream);
584 /* special case empty files */
586 charList.charListT_len = 0;
588 ubik_BUDB_SaveText(udbHandle.uh_client, 0,
589 ctPtr->lockHandle, ctPtr->textType, 0,
590 BUDB_TEXT_COMPLETE, &charList);
595 while (fileSize != 0) {
596 chunkSize = MIN(fileSize, bufferSize);
598 fread(charList.charListT_val, sizeof(char), chunkSize,
601 if (code != chunkSize)
602 printf("code = %d\n", code);
603 if (ferror(ctPtr->textStream))
604 ERROR(BUDB_INTERNALERROR);
606 charList.charListT_len = chunkSize;
608 ubik_BUDB_SaveText(udbHandle.uh_client, 0,
609 ctPtr->lockHandle, ctPtr->textType, offset,
610 (chunkSize == fileSize) ? BUDB_TEXT_COMPLETE : 0,
615 fileSize -= chunkSize;
620 /* if ( ctPtr->textStream >= 0 )
621 * close(ctPtr->textStream); */
622 if (charList.charListT_val)
623 free(charList.charListT_val);
628 bcdb_FindLastTape(afs_int32 dumpID, struct budb_dumpEntry *dumpEntry,
629 struct budb_tapeEntry *tapeEntry,
630 struct budb_volumeEntry *volEntry)
632 return (ubik_BUDB_FindLastTape(udbHandle.uh_client, 0, dumpID, dumpEntry,
633 tapeEntry, volEntry));
637 bcdb_MakeDumpAppended(afs_int32 appendedDumpID, afs_int32 initialDumpID,
638 afs_int32 startTapeSeq)
640 return (ubik_BUDB_MakeDumpAppended(udbHandle.uh_client, 0, appendedDumpID,
641 initialDumpID, startTapeSeq));
645 /* -------------------------------------
646 * misc. support routines
647 * -------------------------------------
651 filesize(FILE *stream)
656 offset = ftell(stream);
657 fseek(stream, (afs_int32) 0, 2); /* end of file */
658 size = ftell(stream);
659 fseek(stream, offset, 0);
664 /* ------------------------------------
665 * misc. support routines - general text management
666 * ------------------------------------
671 * locks the text described by the ctPtr
673 * ctptr - client text ptr
680 bc_LockText(udbClientTextP ctPtr)
683 afs_int32 timeout, j = 0;
685 if (ctPtr->lockHandle != 0)
686 return (1); /* already locked */
689 ((ctPtr->textSize == 0) ? 30 : ((ctPtr->textSize / 50000) + 10));
693 ubik_BUDB_GetLock(udbHandle.uh_client, 0,
694 udbHandle.uh_instanceId, ctPtr->textType, timeout,
696 if ((code != BUDB_LOCKED) && (code != BUDB_SELFLOCKED)) {
700 /* Mention something every 30 seconds */
702 afs_com_err(whoami, code,
703 "; Waiting for db configuration text unlock");
706 #ifdef AFS_PTHREAD_ENV
715 ctPtr->lockHandle = 0;
720 * unlocks the text described by the ctPtr
722 * ctptr - client text ptr
729 bc_UnlockText(udbClientTextP ctPtr)
733 if (ctPtr->lockHandle == 0)
737 ubik_BUDB_FreeLock(udbHandle.uh_client, 0, ctPtr->lockHandle);
738 ctPtr->lockHandle = 0;
740 /* Don't try to analyse the error. Let the lock timeout */
744 /* bc_CheckTextVersion
747 * n - out of date or error
751 bc_CheckTextVersion(udbClientTextP ctPtr)
756 if (ctPtr->textVersion == -1)
757 return (BC_VERSIONMISMATCH);
760 ubik_BUDB_GetTextVersion(udbHandle.uh_client, 0,
761 ctPtr->textType, &tversion);
764 if (tversion != ctPtr->textVersion)
765 return (BC_VERSIONMISMATCH);
769 /* -------------------------------------
770 * initialization routines
771 * -------------------------------------
774 static afsconf_secflags
775 parseSecFlags(int noAuthFlag, int localauth, const char **confdir) {
776 afsconf_secflags secFlags;
780 secFlags |= AFSCONF_SECOPTS_NOAUTH;
783 secFlags |= AFSCONF_SECOPTS_LOCALAUTH;
784 *confdir = AFSDIR_SERVER_ETC_DIRPATH;
786 *confdir = AFSDIR_CLIENT_ETC_DIRPATH;
792 * Initialize a client for the vl ubik database.
795 vldbClientInit(int noAuthFlag, int localauth, char *cellName,
796 struct ubik_client **cstruct,
800 struct afsconf_dir *acdir;
801 struct rx_securityClass *sc;
802 afs_int32 i, scIndex = 0; /* Index of Rx security object - noauth */
803 struct afsconf_cell info;
804 struct rx_connection *serverconns[VLDB_MAXSERVERS];
805 afsconf_secflags secFlags;
808 secFlags = parseSecFlags(noAuthFlag, localauth, &confdir);
809 secFlags |= AFSCONF_SECOPTS_FALLBACK_NULL;
811 /* This just preserves old behaviour of using the default cell when
812 * passed an empty string */
813 if (cellName && cellName[0] == '\0')
816 /* Find out about the given cell */
817 acdir = afsconf_Open(confdir);
819 afs_com_err(whoami, 0, "Can't open configuration directory '%s'", confdir);
820 ERROR(BC_NOCELLCONFIG);
823 code = afsconf_GetCellInfo(acdir, cellName, AFSCONF_VLDBSERVICE, &info);
825 afs_com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
826 cellName, confdir, AFSDIR_CELLSERVDB_FILE);
827 ERROR(BC_NOCELLCONFIG);
830 code = afsconf_PickClientSecObj(acdir, secFlags, &info, cellName,
831 &sc, &scIndex, expires);
833 afs_com_err(whoami, code, "(configuring connection security)");
834 ERROR(BC_NOCELLCONFIG);
836 if (scIndex == 0 && !noAuthFlag)
837 afs_com_err(whoami, 0, "Can't get tokens - running unauthenticated");
839 /* tell UV module about default authentication */
840 UV_SetSecurity(sc, scIndex);
842 if (info.numServers > VLDB_MAXSERVERS) {
843 afs_com_err(whoami, 0,
844 "Warning: %d VLDB servers exist for cell '%s', can only remember the first %d",
845 info.numServers, cellName, VLDB_MAXSERVERS);
846 info.numServers = VLDB_MAXSERVERS;
849 for (i = 0; i < info.numServers; i++)
851 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
852 info.hostAddr[i].sin_port, USER_SERVICE_ID, sc,
857 code = ubik_ClientInit(serverconns, cstruct);
859 afs_com_err(whoami, code, "; Can't initialize ubik connection to vldb");
865 afsconf_Close(acdir);
870 * initialize a client for the backup systems ubik database.
874 udbClientInit(int noAuthFlag, int localauth, char *cellName)
876 struct afsconf_cell info;
877 struct afsconf_dir *acdir;
883 secFlags = parseSecFlags(noAuthFlag, localauth, &confdir);
884 secFlags |= AFSCONF_SECOPTS_FALLBACK_NULL;
886 if (cellName && cellName[0] == '\0')
889 acdir = afsconf_Open(confdir);
891 afs_com_err(whoami, 0, "Can't open configuration directory '%s'",
893 ERROR(BC_NOCELLCONFIG);
896 code = afsconf_GetCellInfo(acdir, cellName, 0, &info);
898 afs_com_err(whoami, code, "; Can't find cell %s's hosts in %s/%s",
899 cellName, confdir, AFSDIR_CELLSERVDB_FILE);
900 ERROR(BC_NOCELLCONFIG);
903 code = afsconf_PickClientSecObj(acdir, secFlags, &info, cellName,
904 &udbHandle.uh_secobj,
905 &udbHandle.uh_scIndex, NULL);
907 afs_com_err(whoami, code, "(configuring connection security)");
908 ERROR(BC_NOCELLCONFIG);
910 if (&udbHandle.uh_scIndex == 0 && !noAuthFlag)
911 afs_com_err(whoami, 0, "Can't get tokens - running unauthenticated");
913 if (info.numServers > MAXSERVERS) {
914 afs_com_err(whoami, 0,
915 "Warning: %d BDB servers exist for cell '%s', can only remember the first %d",
916 info.numServers, cellName, MAXSERVERS);
917 info.numServers = MAXSERVERS;
920 /* establish connections to the servers. Check for failed connections? */
921 for (i = 0; i < info.numServers; i++) {
922 udbHandle.uh_serverConn[i] =
923 rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
924 htons(AFSCONF_BUDBPORT), BUDB_SERVICE,
925 udbHandle.uh_secobj, udbHandle.uh_scIndex);
927 udbHandle.uh_serverConn[i] = 0;
929 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
931 afs_com_err(whoami, code,
932 "; Can't initialize ubik connection to backup database");
936 /* Try to quickly find a good site by setting deadtime low */
937 for (i = 0; i < info.numServers; i++)
938 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 1);
940 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
941 &udbHandle.uh_instanceId);
943 /* Reset dead time back up to default */
944 for (i = 0; i < info.numServers; i++)
945 rx_SetConnDeadTime(udbHandle.uh_client->conns[i], 60);
947 /* If did not find a site on first quick pass, try again */
950 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
951 &udbHandle.uh_instanceId);
953 afs_com_err(whoami, code, "; Can't access backup database");
959 afsconf_Close(acdir);
963 /* -------------------------------------
964 * specialized ubik support
965 * -------------------------------------
973 * 1) first call with SINGLESERVER set, record the server to be used.
974 * 2) subsequent calls use that server. If a failure is encountered,
975 * the state is cleaned up and the error returned back to the caller.
976 * 3) upon completion, the user must make a dummy call with
977 * END_SINGLESERVER set, to clean up state.
978 * 4) if the vanilla ubik_Call is ever modified, the END_SINGLESERVER
979 * flag can be discarded. The first call without SINGLESERVER set
980 * can clean up the state.
983 struct ubikCallState {
984 afs_int32 ucs_flags; /* state flags */
985 afs_int32 ucs_selectedServer; /* which server selected */
988 static struct ubikCallState uServer;
990 /* ubik_Call_SingleServer
991 * variant of ubik_Call. This is used by the backup system to initiate
992 * a series of calls to a single ubik server. The first call sets up
993 * process state (not recorded in ubik) that requires all further calls
994 * of that group to be made to the same server process.
996 * call this instead of stub and we'll guarantee to find a host that's up.
997 * in the future, we should also put in a protocol to find the sync site
1001 ubik_Call_SingleServer(int (*aproc) (), struct ubik_client *aclient,
1002 afs_int32 aflags, char *p1, char *p2, char *p3,
1003 char *p4, char *p5, char *p6, char *p7, char *p8,
1004 char *p9, char *p10, char *p11, char *p12, char *p13,
1005 char *p14, char *p15, char *p16)
1007 register afs_int32 code;
1008 afs_int32 someCode, newHost, thisHost;
1009 register afs_int32 i;
1010 register afs_int32 count;
1013 struct rx_connection *tc;
1014 struct rx_peer *rxp;
1016 if ((aflags & (UF_SINGLESERVER | UF_END_SINGLESERVER)) != 0) {
1017 if (((aflags & UF_SINGLESERVER) != 0)
1018 && ((uServer.ucs_flags & UF_SINGLESERVER) != 0)
1021 /* have a selected server */
1022 tc = aclient->conns[uServer.ucs_selectedServer];
1025 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11,
1026 p12, p13, p14, p15, p16);
1028 /* error. Clean up single server state */
1029 memset(&uServer, 0, sizeof(uServer));
1032 } else if ((aflags & UF_END_SINGLESERVER) != 0) {
1033 memset(&uServer, 0, sizeof(uServer));
1038 someCode = UNOSERVERS;
1044 /* tc is the next conn to try */
1045 tc = aclient->conns[count];
1048 pass = 1; /* in pass 1, we look at down hosts, too */
1052 break; /* nothing left to try */
1054 if (pass == 0 && (aclient->states[count] & CFLastFailed)) {
1056 continue; /* this guy's down, try someone else first */
1060 (*aproc) (tc, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12,
1061 p13, p14, p15, p16);
1063 /* note that getting a UNOTSYNC error code back does *not* guarantee
1064 * that there is a sync site yet elected. However, if there is a
1065 * sync site out there somewhere, and you're trying an operation that
1066 * requires a sync site, ubik will return UNOTSYNC, indicating the
1067 * operation won't work until you find a sync site
1069 if (code == UNOTSYNC) { /*ns */
1070 /* means that this requires a sync site to work */
1071 someCode = code; /* remember an error, if this fails */
1073 /* now see if we can find the sync site host */
1074 code = VOTE_GetSyncSite(tc, &newHost);
1075 if (code == 0 && newHost != 0) {
1076 newHost = htonl(newHost); /* convert back to network order */
1078 /* position count at the appropriate slot in the client
1079 * structure and retry. If we can't find in slot, we'll just
1080 * continue through the whole list
1082 for (i = 0; i < MAXSERVERS; i++) { /*f */
1083 rxp = rx_PeerOf(aclient->conns[i]);
1084 if (!(thisHost = rx_HostOf(rxp))) {
1085 count++; /* host not found, try the next dude */
1088 if (thisHost == newHost) {
1089 /* avoid asking in a loop */
1090 if (chaseCount++ > 2)
1092 count = i; /* we were told to use this one */
1097 count++; /* not directed, keep looking for a sync site */
1100 else if (code == UNOQUORUM) { /* this guy is still recovering */
1104 } else if (code < 0) { /* network errors */
1106 aclient->states[count] |= CFLastFailed;
1110 /* ok, operation worked */
1111 aclient->states[count] &= ~CFLastFailed;
1112 /* either misc ubik code, or misc application code (incl success)
1115 /* if the call succeeded, setup connection state for subsequent
1119 && ((aflags & UF_SINGLESERVER) != 0)
1121 /* need to save state */
1122 uServer.ucs_flags = UF_SINGLESERVER;
1123 uServer.ucs_selectedServer = count;
1133 /* -------------------------------------
1134 * debug and test routines
1135 * -------------------------------------
1139 * For testing only. Open a connect to the database server running on
1142 * 0 - ubik connection established in the global udbHandle structure
1149 afs_int32 serverList[MAXSERVERS];
1155 /* get our host name */
1156 gethostname(hostname, sizeof(hostname));
1157 /* strcpy(hostname, "hops"); */
1160 args[1] = "-servers";
1163 code = ubik_ParseClientList(3, args, serverList);
1165 afs_com_err(whoami, code, "; udbLocalInit: parsing ubik server list");
1169 udbHandle.uh_scIndex = RX_SCINDEX_NULL;
1170 udbHandle.uh_secobj = (struct rx_securityClass *)
1171 rxnull_NewClientSecurityObject();
1173 for (i = 0; serverList[i] != 0; i++) {
1174 udbHandle.uh_serverConn[i] =
1175 rx_NewConnection(serverList[i], htons(AFSCONF_BUDBPORT),
1176 BUDB_SERVICE, udbHandle.uh_secobj,
1177 udbHandle.uh_scIndex);
1178 if (udbHandle.uh_serverConn[i] == 0) {
1179 afs_com_err(whoami, 0, "connection %d failed", i);
1183 udbHandle.uh_serverConn[i] = 0;
1184 code = ubik_ClientInit(udbHandle.uh_serverConn, &udbHandle.uh_client);
1186 afs_com_err(whoami, code, "; in ubik_ClientInit");
1191 ubik_BUDB_GetInstanceId(udbHandle.uh_client, 0,
1192 &udbHandle.uh_instanceId);
1194 afs_com_err(whoami, code, "; Can't estblish instance Id");
1202 /* bc_openTextFile - This function opens a temp file to read in the
1203 * config text recd from the bu server. On Unix, an unlink() is done on
1204 * the file as soon as it is opened, so when the program exits, the file will
1205 * be removed automatically, while being invisible while in use.
1206 * On NT, however, the file must be explicitly deleted after use with an unlink()
1208 * Pointer to a udhClientTextP struct. The open stream ptr is stored in
1209 * the udbClientTextP.textStream member.
1210 * Output: The temp file name is returned in tmpFileName. This should be used
1211 * to delete the file when done with it.
1217 bc_openTextFile(udbClientTextP ctPtr, char *tmpFileName)
1221 if (ctPtr->textStream != NULL)
1222 fclose(ctPtr->textStream);
1224 sprintf(tmpFileName, "%s/bu_XXXXXX", gettmpdir());
1225 #ifdef AFS_LINUX20_ENV
1226 mkstemp(tmpFileName);
1228 mktemp(tmpFileName);
1230 ctPtr->textStream = fopen(tmpFileName, "w+");
1231 if (ctPtr->textStream == NULL)
1232 ERROR(BUDB_INTERNALERROR);
1234 #ifndef AFS_NT40_ENV /* This can't be done on NT */
1235 /* make the file invisible to others */
1236 code = unlink(tmpFileName);
1241 afs_dprintf(("file is %s\n", tmpFileName));
1247 if (ctPtr->textStream != NULL) {
1248 fclose(ctPtr->textStream);
1249 ctPtr->textStream = NULL;
1255 /* bc_closeTextFile: This function closes any actual temp files associated with
1256 * a udbClientText structure.
1257 * Input: ctPtr->textStream - stream to close
1258 * tmpFileName - temp file name to delete
1264 bc_closeTextFile(udbClientTextP ctPtr, char *tmpFileName)
1268 if (ctPtr->textStream)
1269 fclose(ctPtr->textStream);
1271 if (*tmpFileName) { /* we have a valid name */
1272 code = unlink(tmpFileName);