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
11 * ht_lookupEntry - tape ids
12 * Truncate Tape - tape id's
16 #include <afsconfig.h>
17 #include <afs/param.h>
25 #include <netinet/in.h>
27 #include <sys/param.h>
29 #include <sys/resource.h>
33 #include <sys/types.h>
35 #include <afs/bubasics.h>
44 #include <afs/cellconfig.h>
48 #include "budb_errs.h"
50 #include "error_macros.h"
52 #include "afs/audit.h"
53 #include <afs/afsutil.h>
59 extern struct ubik_dbase *BU_dbase;
60 extern struct afsconf_dir *BU_conf; /* for getting cell info */
62 afs_int32 AddVolume(), AddVolumes(), CreateDump(), DoDeleteDump(),
63 DoDeleteTape(), ListDumps();
64 afs_int32 DeleteVDP(), FindClone(), FindDump(), FindLatestDump();
65 afs_int32 FinishDump(), FinishTape(), GetDumps(), getExpiration(),
67 afs_int32 makeAppended(), MakeDumpAppended(), FindLastTape(), GetTapes();
68 afs_int32 GetVolumes(), UseTape(), T_DumpHashTable(), T_GetVersion();
70 /* Text block management */
73 struct memTextBlock *mtb_next; /* next in chain */
74 afs_int32 mtb_nbytes; /* # of bytes in this block */
75 struct blockHeader mtb_blkHeader; /* in memory header */
76 dbadr mtb_addr; /* disk address of block */
79 typedef struct memTextBlock memTextBlockT;
80 typedef memTextBlockT *memTextBlockP;
82 /* These variable are for returning debugging info about the state of the
83 server. If they get trashed during multi-threaded operation it doesn't
86 /* This is global so COUNT_REQ in krb_udp.c can refer to it. */
87 char *lastOperation; /* name of last operation */
88 static Date lastTrans; /* time of last transaction */
90 /* procsInited is sort of a lock: during a transaction only one process runs
91 while procsInited is false. */
93 static int procsInited = 0;
95 /* This variable is protected by the procsInited flag. */
97 static int (*rebuildDatabase) ();
99 /* AwaitInitialization
100 * Wait unitl budb has initialized (InitProcs). If it hasn't
101 * within 5 seconds, then return no quorum.
104 AwaitInitialization()
108 while (!procsInited) {
111 else if (time(0) - start > 5)
119 * name is a pathname style name, determine trailing name and return
124 tailCompPtr(pathNamePtr)
128 ptr = strrchr(pathNamePtr, '/');
130 /* this should never happen */
131 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
133 return (pathNamePtr);
135 ptr++; /* skip the / */
140 * Check to see if the caller is a SuperUser.
148 struct rx_call *call;
151 struct afsconf_dir *acdir;
153 acdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
157 if (afsconf_SuperUser(acdir, call, NULL))
161 afsconf_Close(acdir);
166 * This is called by every RPC interface to create a Ubik transaction
167 * and read the database header into core
173 * sets a lock on byte 1 of the database. Looks like it enforces
174 * single threading by use of the lock.
178 InitRPC(ut, lock, this_op)
179 struct ubik_trans **ut;
180 int lock; /* indicate read/write transaction */
181 int this_op; /* opcode of RCP, for COUNT_ABO */
184 float wait = 0.91; /* start waiting for 1 second */
187 /* wait for server initialization to finish if this is not InitProcs calling */
189 if (code = AwaitInitialization())
192 for (code = UNOQUORUM; code == UNOQUORUM;) {
194 ubik_BeginTrans(BU_dbase,
196 LOCKREAD) ? UBIK_READTRANS : UBIK_WRITETRANS),
198 if (code == UNOQUORUM) { /* no quorum elected */
200 Log("Waiting for quorum election\n");
203 IOMGR_Sleep((int)wait);
209 Log("Have established quorum\n");
211 /* set lock at posiion 1, for 1 byte of type lock */
212 if (code = ubik_SetLock(*ut, 1, 1, lock)) {
213 ubik_AbortTrans(*ut);
217 /* check that dbase is initialized and setup cheader */
218 if (lock == LOCKREAD) {
219 /* init but don't fix because this is read only */
220 if (code = CheckInit(*ut, 0)) {
221 ubik_AbortTrans(*ut);
222 if (code = InitRPC(ut, LOCKWRITE, 0)) { /* Now fix the database */
223 LogError(code, "InitRPC: InitRPC failed\n");
226 if (code = ubik_EndTrans(*ut)) {
227 LogError(code, "InitRPC: ubik_EndTrans failed\n");
230 goto start; /* now redo the read transaction */
233 if (code = CheckInit(*ut, rebuildDatabase)) {
234 ubik_AbortTrans(*ut);
242 /* This is called to initialize a newly created database */
244 initialize_database(ut)
245 struct ubik_trans *ut;
250 static int noAuthenticationRequired; /* global state */
251 static int recheckNoAuth; /* global state */
256 struct ubik_trans *ut;
261 if ((globalConfPtr->myHost == 0) || (BU_conf == 0))
262 ERROR(BUDB_INTERNALERROR);
266 if (globalConfPtr->debugFlags & DF_NOAUTH)
267 noAuthenticationRequired = 1;
269 if (globalConfPtr->debugFlags & DF_RECHECKNOAUTH)
273 noAuthenticationRequired = afsconf_GetNoAuthFlag(BU_conf);
275 if (noAuthenticationRequired)
276 LogError(0, "Running server with security disabled\n");
280 rebuildDatabase = initialize_database;
282 if (code = InitRPC(&ut, LOCKREAD, 0)) {
283 LogError(code, "InitProcs: InitRPC failed\n");
286 code = ubik_EndTrans(ut);
288 LogError(code, "InitProcs: ubik_EndTrans failed\n");
292 rebuildDatabase = 0; /* only do this during init */
300 int nElements; /* number in list */
301 int allocSize; /* number of elements allocated */
302 dbadr *elements; /* array of addresses */
307 struct returnList *list;
311 list->elements = (dbadr *) 0;
316 struct returnList *list;
319 free(list->elements);
320 list->elements = (dbadr *) 0;
324 /* As entries are collected, they are added to a return list. Once all
325 * entries have been collected, it is then placed in the return buffer
326 * with SendReturnList(). The first *to_skipP are not recorded.
329 AddToReturnList(list, a, to_skipP)
330 struct returnList *list;
344 /* Up to 5 plus a maximum so SendReturnList() knows if we
345 * need to come back for more.
347 if (list->nElements >= BUDB_MAX_RETURN_LIST + 5)
348 return BUDB_LIST2BIG;
350 if (list->nElements >= list->allocSize) {
351 if (list->elements == 0) {
353 tmp = (char *)malloc(sizeof(dbadr) * size);
355 size = list->allocSize + 10;
356 tmp = (char *)realloc(list->elements, sizeof(dbadr) * size);
360 list->elements = (dbadr *) tmp;
361 list->allocSize = size;
364 list->elements[list->nElements] = a;
370 FillVolEntry(ut, va, vol)
371 struct ubik_trans *ut;
373 struct budb_volumeEntry *vol;
378 struct volFragment vf;
380 if (dbread(ut, va, &vf, sizeof(vf)))
381 return BUDB_IO; /* The volFrag */
382 if (dbread(ut, ntohl(vf.vol), &vi, sizeof(vi)))
383 return BUDB_IO; /* The volInfo */
384 if (dbread(ut, ntohl(vf.tape), &t, sizeof(t)))
385 return BUDB_IO; /* The tape */
386 if (dbread(ut, ntohl(t.dump), &d, sizeof(d)))
387 return BUDB_IO; /* The dump */
389 strcpy(vol->name, vi.name);
390 strcpy(vol->server, vi.server);
391 strcpy(vol->tape, t.name);
392 vol->tapeSeq = ntohl(t.seq);
393 vol->dump = ntohl(d.id);
394 vol->position = ntohl(vf.position);
395 vol->clone = ntohl(vf.clone);
396 vol->incTime = ntohl(vf.incTime);
397 vol->nBytes = ntohl(vf.nBytes);
398 vol->startByte = ntohl(vf.startByte);
399 vol->flags = (ntohs(vf.flags) & VOLFRAGMENTFLAGS); /* low 16 bits here */
400 vol->flags |= (ntohl(vi.flags) & VOLINFOFLAGS); /* high 16 bits here */
401 vol->seq = ntohs(vf.sequence);
402 vol->id = ntohl(vi.id);
403 vol->partition = ntohl(vi.partition);
409 FillDumpEntry(ut, da, dump)
410 struct ubik_trans *ut;
412 struct budb_dumpEntry *dump;
416 if (dbread(ut, da, &d, sizeof(d)))
418 dump->id = ntohl(d.id);
419 dump->flags = ntohl(d.flags);
420 dump->created = ntohl(d.created);
421 strncpy(dump->name, d.dumpName, sizeof(dump->name));
422 strncpy(dump->dumpPath, d.dumpPath, sizeof(dump->dumpPath));
423 strncpy(dump->volumeSetName, d.volumeSet, sizeof(dump->volumeSetName));
425 dump->parent = ntohl(d.parent);
426 dump->level = ntohl(d.level);
427 dump->nVolumes = ntohl(d.nVolumes);
429 tapeSet_ntoh(&d.tapes, &dump->tapes);
431 if (strlen(d.dumper.name) < sizeof(dump->dumper.name))
432 strcpy(dump->dumper.name, d.dumper.name);
433 if (strlen(d.dumper.instance) < sizeof(dump->dumper.instance))
434 strcpy(dump->dumper.instance, d.dumper.instance);
435 if (strlen(d.dumper.cell) < sizeof(dump->dumper.cell))
436 strcpy(dump->dumper.cell, d.dumper.cell);
438 /* Get the initial dumpid and the appended dump id */
439 dump->initialDumpID = ntohl(d.initialDumpID);
440 if (d.appendedDumpChain) {
441 if (dbread(ut, ntohl(d.appendedDumpChain), &ad, sizeof(ad)))
443 dump->appendedDumpID = ntohl(ad.id);
445 dump->appendedDumpID = 0;
447 /* printf("dump name %s, parent %d, level %d\n",
448 * d.dumpName, ntohl(d.parent), ntohl(d.level)); */
454 FillTapeEntry(ut, ta, tape)
455 struct ubik_trans *ut;
457 struct budb_tapeEntry *tape;
463 if (dbread(ut, ta, &t, sizeof(t)))
466 /* Get the tape's expiration date */
467 if (code = getExpiration(ut, &t))
470 strcpy(tape->name, t.name);
471 tape->flags = ntohl(t.flags);
472 tape->written = ntohl(t.written);
473 tape->expires = ntohl(t.expires);
474 tape->nMBytes = ntohl(t.nMBytes);
475 tape->nBytes = ntohl(t.nBytes);
476 tape->nFiles = ntohl(t.nFiles);
477 tape->nVolumes = ntohl(t.nVolumes);
478 tape->seq = ntohl(t.seq);
479 tape->labelpos = ntohl(t.labelpos);
480 tape->useCount = ntohl(t.useCount);
481 tape->useKBytes = ntohl(t.useKBytes);
483 if (dbread(ut, ntohl(t.dump), &d, sizeof(d)))
485 tape->dump = ntohl(d.id);
489 #define returnList_t budb_dumpList *
492 * A list of elements of size e_size is in list, collected
493 * with AddToReturnList(). We will move this to a correspoding
494 * return list, eList, via FillProc(). nextInodeP tells us
495 * if there are more and how many to skip on the next request.
498 SendReturnList(ut, list, FillProc, e_size, index, nextIndexP, dbTimeP, eList)
499 struct ubik_trans *ut;
500 struct returnList *list; /* list of elements to return */
501 afs_int32(*FillProc) (); /* proc to fill entry */
502 int e_size; /* size of each element */
503 afs_int32 index; /* index from previous call */
504 afs_int32 *nextIndexP; /* if more elements are available */
505 afs_int32 *dbTimeP; /* time of last db update */
506 budb_dumpList *eList; /* rxgen list structure (e.g.) */
514 *dbTimeP = ntohl(db.h.lastUpdate);
516 /* Calculate how many to return. Don't let if go over
517 * BUDB_MAX_RETURN_LIST nor the size of our return list.
519 to_return = list->nElements;
520 if (to_return > BUDB_MAX_RETURN_LIST)
521 to_return = BUDB_MAX_RETURN_LIST;
522 if (eList->budb_dumpList_len && (to_return > eList->budb_dumpList_len))
523 to_return = eList->budb_dumpList_len;
525 /* Allocate space for the return values if needed and zero it */
526 if (eList->budb_dumpList_val == 0) {
527 eList->budb_dumpList_val =
528 (struct budb_dumpEntry *)malloc(e_size * to_return);
529 if (!eList->budb_dumpList_val)
532 memset(eList->budb_dumpList_val, 0, e_size * to_return);
533 eList->budb_dumpList_len = to_return;
535 e = (char *)(eList->budb_dumpList_val);
536 for (i = 0; i < to_return; i++, e += e_size) {
537 code = (*FillProc) (ut, list->elements[i], e);
542 if (list->nElements > i)
543 *nextIndexP = index + i;
547 /* Come here to delete a volInfo structure. */
550 DeleteVolInfo(ut, via, vi)
551 struct ubik_trans *ut;
559 if (vi->firstFragment)
560 return 0; /* still some frags, don't free yet */
561 if (vi->sameNameHead == 0) { /* this is the head */
562 if (vi->sameNameChain)
563 return 0; /* empty head, some non-heads left */
565 code = ht_HashOut(ut, &db.volName, via, vi);
568 code = FreeStructure(ut, volInfo_BLOCK, via);
571 hvia = ntohl(vi->sameNameHead);
572 if (dbread(ut, hvia, &hvi, sizeof(hvi)))
575 RemoveFromList(ut, hvia, &hvi, &hvi.sameNameChain, via, vi,
578 return BUDB_DATABASEINCONSISTENT;
580 code = FreeStructure(ut, volInfo_BLOCK, via);
584 /* Detach a volume fragment from its volInfo structure. Its tape chain is
585 already freed. This routine frees the structure and the caller must not
589 DeleteVolFragment(ut, va, v)
590 struct ubik_trans *ut;
592 struct volFragment *v;
599 if (dbread(ut, via, &vi, sizeof(vi)))
602 RemoveFromList(ut, via, &vi, &vi.firstFragment, va, v,
605 return BUDB_DATABASEINCONSISTENT;
608 if (vi.firstFragment == 0)
609 if (code = DeleteVolInfo(ut, via, &vi))
611 if (code = FreeStructure(ut, volFragment_BLOCK, va))
614 /* decrement frag counter */
616 set_word_addr(ut, via, &vi, &vi.nFrags, htonl(ntohl(vi.nFrags) - 1));
622 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
623 * The caller will remove it from the hash table if necessary. The caller is
624 * also responsible for writing the tape out if necessary. */
627 DeleteTape(ut, ta, t)
628 struct ubik_trans *ut;
638 return BUDB_DATABASEINCONSISTENT;
639 if (dbread(ut, da, &d, sizeof(d)))
641 if (d.firstTape == 0)
642 return BUDB_DATABASEINCONSISTENT;
644 code = RemoveFromList(ut, da, &d, &d.firstTape, ta, t, &t->nextTape);
646 return BUDB_DATABASEINCONSISTENT;
650 /* Since the tape should have been truncated there should never be any
651 * volumes in the tape. */
652 if (t->firstVol || t->nVolumes)
653 return BUDB_DATABASEINCONSISTENT;
659 DeleteDump(ut, da, d)
660 struct ubik_trans *ut;
666 code = ht_HashOut(ut, &db.dumpIden, da, d);
670 code = ht_HashOut(ut, &db.dumpName, da, d);
674 /* Since the tape should have been truncated this should never happen. */
675 if (d->firstTape || d->nVolumes)
676 ERROR(BUDB_DATABASEINCONSISTENT);
678 code = FreeStructure(ut, dump_BLOCK, da);
689 * This is called with a volumeEntry and a volInfo structure and compares
690 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
691 * search volInfo structures once it has the head volInfo structure from the
692 * volName hash table.
694 * When called from GetVolInfo the name compare is redundant.
695 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
699 VolInfoMatch(vol, vi)
700 struct budb_volumeEntry *vol;
703 return ((strcmp(vol->name, vi->name) == 0) && /* same volume name */
704 (vol->id == ntohl(vi->id)) && /* same volume id */
705 ((vol->flags & VOLINFOFLAGS) == (ntohl(vi->flags) & VOLINFOFLAGS)) && /* same flags */
706 (vol->partition == ntohl(vi->partition)) && /* same partition (N/A) */
707 (strcmp(vol->server, vi->server) == 0)); /* same server (N/A) */
712 * This routine takes a volumeEntry structure from an RPC interface and
713 * returns the corresponding volInfo structure, creating it if necessary.
715 * The caller must write the entry out.
719 GetVolInfo(ut, volP, viaP, viP)
720 struct ubik_trans *ut;
721 struct budb_volumeEntry *volP;
727 afs_int32 eval, code = 0;
729 eval = ht_LookupEntry(ut, &db.volName, volP->name, &via, viP);
734 /* allocate a new volinfo structure */
735 eval = AllocStructure(ut, volInfo_BLOCK, 0, &via, viP);
739 strcpy(viP->name, volP->name);
740 strcpy(viP->server, volP->server);
741 viP->sameNameHead = 0; /* The head of same name chain */
742 viP->sameNameChain = 0; /* Same name chain is empty */
743 viP->firstFragment = 0;
745 viP->id = htonl(volP->id);
746 viP->partition = htonl(volP->partition);
747 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
749 /* Chain onto volname hash table */
750 eval = ht_HashIn(ut, &db.volName, via, viP);
754 LogDebug(4, "volume Info for %s placed at %d\n", db.volName, via);
757 else if (!VolInfoMatch(volP, viP)) { /* Not the head volinfo struct */
758 hvia = via; /* remember the head volinfo struct */
759 memcpy(&hvi, viP, sizeof(hvi));
761 /* Search the same name chain for the correct volinfo structure */
762 for (via = ntohl(viP->sameNameChain); via;
763 via = ntohl(viP->sameNameChain)) {
764 eval = dbread(ut, via, viP, sizeof(*viP));
768 if (VolInfoMatch(volP, viP))
769 break; /* found the one */
772 /* if the correct volinfo struct isn't found, create one */
774 eval = AllocStructure(ut, volInfo_BLOCK, 0, &via, viP);
778 strcpy(viP->name, volP->name);
779 strcpy(viP->server, volP->server);
780 viP->nameHashChain = 0; /* not in hash table */
781 viP->sameNameHead = htonl(hvia); /* chain to head of sameNameChain */
782 viP->sameNameChain = hvi.sameNameChain;
783 viP->firstFragment = 0;
785 viP->id = htonl(volP->id);
786 viP->partition = htonl(volP->partition);
787 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
789 /* write the head entry's sameNameChain link */
791 set_word_addr(ut, hvia, &hvi, &hvi.sameNameChain, htonl(via));
803 /* deletesomevolumesfromtape
804 * Deletes a specified number of volumes from a tape. The tape
805 * and dump are modified to reflect the smaller number of volumes.
806 * The transaction is not terminated, it is up to the caller to
807 * finish the transaction and start a new one (if desired).
809 * maxvolumestodelete - don't delete more than this many volumes
813 deleteSomeVolumesFromTape(ut, tapeAddr, tapePtr, maxVolumesToDelete)
814 struct ubik_trans *ut;
816 struct tape *tapePtr;
817 int maxVolumesToDelete;
819 dbadr volFragAddr, nextVolFragAddr, dumpAddr;
820 struct volFragment volFrag;
822 int volumesDeleted = 0;
823 afs_int32 eval, code = 0;
828 for (volFragAddr = ntohl(tapePtr->firstVol);
829 (volFragAddr && (maxVolumesToDelete > 0));
830 volFragAddr = nextVolFragAddr) {
831 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
835 nextVolFragAddr = ntohl(volFrag.sameTapeChain);
837 eval = DeleteVolFragment(ut, volFragAddr, &volFrag);
841 maxVolumesToDelete--;
845 /* reset the volume fragment pointer in the tape */
846 tapePtr->firstVol = htonl(volFragAddr);
848 /* diminish the tape's volume count */
849 tapePtr->nVolumes = htonl(ntohl(tapePtr->nVolumes) - volumesDeleted);
851 eval = dbwrite(ut, tapeAddr, tapePtr, sizeof(*tapePtr));
855 /* diminish the dump's volume count */
856 dumpAddr = ntohl(tapePtr->dump);
857 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
861 dump.nVolumes = htonl(ntohl(dump.nVolumes) - volumesDeleted);
862 eval = dbwrite(ut, dumpAddr, &dump, sizeof(dump));
871 * deletes a dump in stages, by repeatedly deleting a small number of
872 * volumes from the dump until none are left. The dump is then deleted.
874 * In the case where multiple calls are made to delete the same
875 * dump, the operation will succeed but contention for structures
876 * will result in someone getting back an error.
879 * id - id of dump to delete
883 deleteDump(call, id, dumps)
884 struct rx_call *call;
886 budb_dumpsList *dumps;
888 struct ubik_trans *ut;
889 dbadr dumpAddr, tapeAddr, appendedDump;
893 afs_int32 eval, code = 0;
896 /* iterate until the dump is truly deleted */
902 eval = InitRPC(&ut, LOCKWRITE, 1);
904 ERROR(eval); /* can't start transaction */
907 ht_LookupEntry(ut, &db.dumpIden, &dumpid, &dumpAddr, &dump);
911 ABORT(BUDB_NOENT); /* can't find dump */
913 if ((dumpid == id) && (dump.initialDumpID)) /* can't be an appended dump */
914 ABORT(BUDB_NOTINITIALDUMP);
916 tapeAddr = ntohl(dump.firstTape);
920 /* there is a tape to delete */
921 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
925 if (ntohl(tape.nVolumes)) {
926 /* tape is not empty */
927 eval = deleteSomeVolumesFromTape(ut, tapeAddr, &tape, 10);
932 if (ntohl(tape.nVolumes) == 0) {
933 /* tape is now empty, delete it */
934 eval = DeleteTape(ut, tapeAddr, &tape);
937 eval = ht_HashOut(ut, &db.tapeName, tapeAddr, &tape);
940 eval = FreeStructure(ut, tape_BLOCK, tapeAddr);
945 eval = ubik_EndTrans(ut);
949 } /* next deletion portion */
951 /* Record the dump just deleted */
952 if (dumps && (dumps->budb_dumpsList_len < BUDB_MAX_RETURN_LIST)) {
953 if (dumps->budb_dumpsList_len == 0)
954 dumps->budb_dumpsList_val =
955 (afs_int32 *) malloc(sizeof(afs_int32));
957 dumps->budb_dumpsList_val =
958 (afs_int32 *) realloc(dumps->budb_dumpsList_val,
959 (dumps->budb_dumpsList_len +
960 1) * sizeof(afs_int32));
962 if (!dumps->budb_dumpsList_val)
965 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = dumpid;
966 dumps->budb_dumpsList_len++;
969 appendedDump = ntohl(dump.appendedDumpChain);
971 /* finally done. No more tapes left in the dump. Delete the dump itself */
972 eval = DeleteDump(ut, dumpAddr, &dump);
976 /* Now delete the appended dump too */
978 eval = dbread(ut, appendedDump, &dump, sizeof(dump));
982 dumpid = ntohl(dump.id);
986 eval = ubik_EndTrans(ut);
990 Log("Delete dump %s (DumpID %u), path %s\n", dump.dumpName,
991 ntohl(dump.id), dump.dumpPath);
995 if (code && partialDel) {
996 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
997 dump.dumpName, ntohl(dump.id), dump.dumpPath, code);
1002 ubik_AbortTrans(ut);
1007 * dump selection routines - used by BUDB_GetDumps
1011 /* most recent dump selection */
1014 struct chosenDump *next;
1019 struct wantDumpRock {
1020 int maxDumps; /* max wanted */
1021 int ndumps; /* actual in chain */
1022 struct chosenDump *chain;
1027 wantDump(dumpAddrParam, dumpParam, dumpListPtrParam)
1028 char *dumpAddrParam;
1030 char *dumpListPtrParam;
1033 struct dump *dumpPtr;
1034 struct wantDumpRock *rockPtr;
1036 dumpAddr = (dbadr) dumpAddrParam;
1037 dumpPtr = (struct dump *)dumpParam;
1038 rockPtr = (struct wantDumpRock *)dumpListPtrParam;
1040 /* if we don't have our full complement, just add another */
1041 if (rockPtr->ndumps < rockPtr->maxDumps)
1044 /* got the number we need, select based on date */
1045 if ((afs_uint32) ntohl(dumpPtr->created) > rockPtr->chain->date)
1052 rememberDump(dumpAddrParam, dumpParam, dumpListPtrParam)
1053 char *dumpAddrParam;
1055 char *dumpListPtrParam;
1058 struct dump *dumpPtr;
1059 struct wantDumpRock *rockPtr;
1060 struct chosenDump *ptr, *deletedPtr, **nextPtr;
1062 dumpAddr = (dbadr) dumpAddrParam;
1063 dumpPtr = (struct dump *)dumpParam;
1064 rockPtr = (struct wantDumpRock *)dumpListPtrParam;
1066 ptr = (struct chosenDump *)malloc(sizeof(*ptr));
1069 memset(ptr, 0, sizeof(*ptr));
1070 ptr->addr = dumpAddr;
1071 ptr->date = (afs_uint32) ntohl(dumpPtr->created);
1073 /* Don't overflow the max */
1074 while (rockPtr->ndumps >= rockPtr->maxDumps) {
1075 /* have to drop one */
1076 deletedPtr = rockPtr->chain;
1077 rockPtr->chain = deletedPtr->next;
1082 /* now insert in the right place */
1083 for (nextPtr = &rockPtr->chain; *nextPtr; nextPtr = &((*nextPtr)->next)) {
1084 if (ptr->date < (*nextPtr)->date)
1087 ptr->next = *nextPtr;
1095 /* ---------------------------------------------
1096 * general interface routines - alphabetic
1097 * ---------------------------------------------
1101 SBUDB_AddVolume(call, vol)
1102 struct rx_call *call;
1103 struct budb_volumeEntry *vol;
1107 code = AddVolume(call, vol);
1108 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, (vol ? vol->id : 0),
1114 AddVolume(call, vol)
1115 struct rx_call *call;
1116 struct budb_volumeEntry *vol;
1118 struct ubik_trans *ut;
1119 dbadr da, ta, via, va;
1123 struct volFragment v;
1125 afs_int32 eval, code = 0;
1127 if (!callPermitted(call))
1128 return BUDB_NOTPERMITTED;
1130 if ((strlen(vol->name) >= sizeof(vi.name))
1131 || (strlen(vol->server) >= sizeof(vi.server))
1132 || (strlen(vol->tape) >= sizeof(t.name)))
1133 return BUDB_BADARGUMENT;
1135 eval = InitRPC(&ut, LOCKWRITE, 1);
1139 /* Find the dump in dumpid hash table */
1140 eval = ht_LookupEntry(ut, &db.dumpIden, &vol->dump, &da, &d);
1144 ABORT(BUDB_NODUMPID);
1146 /* search for the right tape in the dump */
1147 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
1148 /* read the tape entry */
1149 eval = dbread(ut, ta, &t, sizeof(t));
1153 /* Check if the right tape name */
1154 if (strcmp(t.name, vol->tape) == 0)
1158 ABORT(BUDB_NOTAPENAME);
1160 if ((t.dump != htonl(da)) || /* tape must belong to dump */
1161 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1162 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)) /* dump must be in progress */
1163 ABORT(BUDB_BADPROTOCOL);
1165 /* find or create a volume info structure */
1166 eval = GetVolInfo(ut, vol, &via, &vi);
1170 /* Create a volume fragment */
1171 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1175 v.vol = htonl(via); /* vol frag points to vol info */
1176 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1177 vi.firstFragment = htonl(va);
1178 vi.nFrags = htonl(ntohl(vi.nFrags) + 1);
1180 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1184 v.tape = htonl(ta); /* vol frag points to tape */
1185 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1186 t.firstVol = htonl(va);
1187 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1188 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1189 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes / (1024 * 1024));
1190 t.nBytes = htonl(bytes % (1024 * 1024));
1192 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1196 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1198 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1202 v.position = htonl(vol->position); /* vol frag info */
1203 v.clone = htonl(vol->clone);
1204 v.incTime = htonl(vol->incTime);
1205 v.startByte = htonl(vol->startByte);
1206 v.nBytes = htonl(vol->nBytes);
1207 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1208 v.sequence = htons(vol->seq);
1210 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1214 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1218 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1220 code = ubik_EndTrans(ut);
1224 ubik_AbortTrans(ut);
1230 SBUDB_AddVolumes(call, vols)
1231 struct rx_call *call;
1232 struct budb_volumeList *vols;
1236 code = AddVolumes(call, vols);
1237 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, 0, AUD_END);
1242 AddVolumes(call, vols)
1243 struct rx_call *call;
1244 struct budb_volumeList *vols;
1246 struct budb_volumeEntry *vol, *vol1;
1247 struct ubik_trans *ut;
1248 dbadr da, ta, via, va;
1252 struct volFragment v;
1254 afs_int32 eval, e, code = 0;
1256 if (!callPermitted(call))
1257 return BUDB_NOTPERMITTED;
1259 if (!vols || (vols->budb_volumeList_len <= 0)
1260 || !vols->budb_volumeList_val)
1261 return BUDB_BADARGUMENT;
1263 /* The first volume in the list of volumes to add */
1264 vol1 = (struct budb_volumeEntry *)vols->budb_volumeList_val;
1266 eval = InitRPC(&ut, LOCKWRITE, 1);
1270 /* Find the dump in dumpid hash table */
1271 eval = ht_LookupEntry(ut, &db.dumpIden, &vol1->dump, &da, &d);
1275 ABORT(BUDB_NODUMPID);
1277 /* search for the right tape in the dump */
1278 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
1279 /* read the tape entry */
1280 eval = dbread(ut, ta, &t, sizeof(t));
1284 /* Check if the right tape name */
1285 if (strcmp(t.name, vol1->tape) == 0)
1289 ABORT(BUDB_NOTAPENAME);
1291 if ((t.dump != htonl(da)) || /* tape must belong to dump */
1292 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1293 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)) /* dump must be in progress */
1294 ABORT(BUDB_BADPROTOCOL);
1296 for (vol = vol1, e = 0; e < vols->budb_volumeList_len; vol++, e++) {
1298 if ((strlen(vol->name) >= sizeof(vi.name)) || (strcmp(vol->name, "") == 0) || /* no null volnames */
1299 (strlen(vol->server) >= sizeof(vi.server))
1300 || (strlen(vol->tape) >= sizeof(t.name))
1301 || (strcmp(vol->tape, vol1->tape) != 0)) {
1302 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n", vol->name, vol->id, vol->tape, vol->dump);
1306 /* find or create a volume info structure */
1307 eval = GetVolInfo(ut, vol, &via, &vi);
1310 if (*(afs_int32 *) (&vi) == 0) {
1311 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n", vol->name, vol->tape, vol->dump);
1312 ABORT(BUDB_BADARGUMENT);
1315 /* Create a volume fragment */
1316 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1320 v.vol = htonl(via); /* vol frag points to vol info */
1321 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1322 vi.firstFragment = htonl(va);
1323 vi.nFrags = htonl(ntohl(vi.nFrags) + 1);
1324 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1328 v.tape = htonl(ta); /* vol frag points to tape */
1329 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1330 t.firstVol = htonl(va);
1331 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1332 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1333 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes / (1024 * 1024));
1334 t.nBytes = htonl(bytes % (1024 * 1024));
1336 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1338 v.position = htonl(vol->position); /* vol frag info */
1339 v.clone = htonl(vol->clone);
1340 v.incTime = htonl(vol->incTime);
1341 v.startByte = htonl(vol->startByte);
1342 v.nBytes = htonl(vol->nBytes);
1343 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1344 v.sequence = htons(vol->seq);
1346 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1350 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1353 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1357 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1361 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1365 code = ubik_EndTrans(ut);
1369 ubik_AbortTrans(ut);
1375 * records the existence of a dump in the database. This creates only
1376 * the dump record, to which one must attach tape and volume records.
1378 * 1) record the volume set
1382 SBUDB_CreateDump(call, dump)
1383 struct rx_call *call;
1384 struct budb_dumpEntry *dump;
1388 code = CreateDump(call, dump);
1389 osi_auditU(call, BUDB_CrDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
1391 if (dump && !code) {
1392 Log("Create dump %s (DumpID %u), path %s\n", dump->name, dump->id,
1399 CreateDump(call, dump)
1400 struct rx_call *call;
1401 struct budb_dumpEntry *dump;
1403 struct ubik_trans *ut;
1404 dbadr findDumpAddr, da;
1405 struct dump findDump, d;
1406 afs_int32 eval, code = 0;
1410 Date expiration; /* checked by Security Module */
1411 struct ktc_principal principal;
1413 if (!callPermitted(call))
1414 return BUDB_NOTPERMITTED;
1416 if (strlen(dump->name) >= sizeof(d.dumpName))
1417 return BUDB_BADARGUMENT;
1419 eval = InitRPC(&ut, LOCKWRITE, 1);
1424 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration,
1425 principal.name, principal.instance,
1426 principal.cell, &kvno);
1429 if (eval != RXKADNOAUTH)
1432 strcpy(principal.name, "");
1433 strcpy(principal.instance, "");
1434 strcpy(principal.cell, "");
1437 /* authenticated. Take user supplied principal information */
1438 if (strcmp(dump->dumper.name, "") != 0)
1439 strncpy(principal.name, dump->dumper.name,
1440 sizeof(principal.name));
1442 if (strcmp(dump->dumper.instance, "") != 0)
1443 strncpy(principal.instance, dump->dumper.instance,
1444 sizeof(principal.instance));
1446 if (strcmp(dump->dumper.cell, "") != 0)
1447 strncpy(principal.cell, dump->dumper.cell,
1448 sizeof(principal.cell));
1451 /* dump id's are time stamps */
1453 while (1) { /* allocate a unique dump id *//*w */
1456 /* ensure it is unique - seach for dumpid in hash table */
1458 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1463 if (!findDumpAddr) { /* dumpid not in use */
1464 /* update the last dump id allocated */
1465 eval = set_header_word(ut, lastDumpId, htonl(dump->id));
1471 /* dump id is in use - wait a while */
1475 /* dump id supplied (e.g. for database restore) */
1477 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1482 /* Dump id must not already exist */
1484 ABORT(BUDB_DUMPIDEXISTS);
1487 /* Allocate a dump structure */
1488 memset(&d, 0, sizeof(d));
1489 eval = AllocStructure(ut, dump_BLOCK, 0, &da, &d);
1493 strcpy(d.dumpName, dump->name); /* volset.dumpname */
1494 strcpy(d.dumpPath, dump->dumpPath); /* dump node path */
1495 strcpy(d.volumeSet, dump->volumeSetName); /* volume set */
1496 d.id = htonl(dump->id);
1497 d.parent = htonl(dump->parent); /* parent id */
1498 d.level = htonl(dump->level);
1500 LogDebug(4, "dump name %s, parent %d level %d\n", dump->name,
1501 dump->parent, dump->level);
1503 /* if creation time specified, use that. Else use the dumpid time */
1504 if (dump->created == 0)
1505 dump->created = dump->id;
1506 d.created = htonl(dump->created);
1508 principal_hton(&principal, &d.dumper);
1509 tapeSet_hton(&dump->tapes, &d.tapes);
1511 d.flags = htonl(dump->flags | BUDB_DUMP_INPROGRESS);
1513 eval = ht_HashIn(ut, &db.dumpName, da, &d); /* Into dump name hash table */
1517 eval = ht_HashIn(ut, &db.dumpIden, da, &d); /* Into dumpid hash table */
1521 eval = dbwrite(ut, da, (char *)&d, sizeof(d)); /* Write the dump structure */
1525 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1529 /* If to append this dump, then append it - will write the appended dump */
1530 eval = makeAppended(ut, dump->id, dump->initialDumpID, dump->tapes.b);
1534 code = ubik_EndTrans(ut);
1535 LogDebug(5, "made dump %s, path %s\n", d.dumpName, d.dumpPath);
1539 ubik_AbortTrans(ut);
1544 SBUDB_DeleteDump(call, id, fromTime, toTime, dumps)
1545 struct rx_call *call;
1549 budb_dumpsList *dumps;
1553 code = DoDeleteDump(call, id, fromTime, toTime, dumps);
1554 osi_auditU(call, BUDB_DelDmpEvent, code, AUD_DATE, id, AUD_END);
1561 DoDeleteDump(call, id, fromTime, toTime, dumps)
1562 struct rx_call *call;
1566 budb_dumpsList *dumps;
1570 if (!callPermitted(call))
1571 return BUDB_NOTPERMITTED;
1574 code = deleteDump(call, id, dumps);
1579 SBUDB_ListDumps(call, sflags, name, groupid, fromTime, toTime, dumps, flags)
1580 struct rx_call *call;
1581 afs_int32 sflags, groupid;
1583 Date fromTime, toTime;
1584 budb_dumpsList *dumps, *flags;
1588 code = ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags);
1589 osi_auditU(call, BUDB_LstDmpEvent, code, AUD_LONG, flags, AUD_END);
1594 ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags)
1595 struct rx_call *call;
1596 afs_int32 sflags, groupid;
1597 Date fromTime, toTime;
1598 budb_dumpsList *dumps, *flags;
1600 struct ubik_trans *ut;
1601 struct memoryHashTable *mht;
1602 struct dump diskDump, appDiskDump;
1603 dbadr dbAddr, dbAppAddr;
1605 afs_int32 eval, code = 0;
1606 int old, hash, length, entrySize, count = 0;
1608 if (!callPermitted(call))
1609 return BUDB_NOTPERMITTED;
1611 eval = InitRPC(&ut, LOCKREAD, 1);
1615 /* Search the database */
1616 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
1618 return (BUDB_BADARGUMENT);
1620 for (old = 0; old <= 1; old++) { /*o *//* old and new hash tables */
1621 length = (old ? mht->oldLength : mht->length);
1625 for (hash = 0; hash < length; hash++) { /*h *//* for each hash bucket */
1626 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) { /*d */
1628 /* read the entry */
1629 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
1633 /* Skip appended dumps */
1634 if (ntohl(diskDump.initialDumpID) != 0) {
1638 /* Skip dumps with different goup id */
1639 if ((sflags & BUDB_OP_GROUPID)
1640 && (ntohl(diskDump.tapes.id) != groupid)) {
1644 /* Look at this dump to see if it meets the criteria for listing */
1645 if (sflags & BUDB_OP_DATES) {
1646 /* This and each appended dump should be in time */
1647 for (dbAppAddr = dbAddr; dbAppAddr;
1648 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1650 dbread(ut, dbAppAddr, &appDiskDump,
1651 sizeof(appDiskDump));
1655 if ((ntohl(appDiskDump.id) < fromTime)
1656 || (ntohl(appDiskDump.id) > toTime))
1663 /* Add it and each of its appended dump to our list to return */
1664 for (dbAppAddr = dbAddr; dbAppAddr;
1665 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1667 dbread(ut, dbAppAddr, &appDiskDump,
1668 sizeof(appDiskDump));
1672 /* Make sure we have space to list it */
1673 if (dumps->budb_dumpsList_len >= count) {
1676 dumps->budb_dumpsList_val =
1677 (afs_int32 *) malloc(count *
1679 flags->budb_dumpsList_val =
1680 (afs_int32 *) malloc(count *
1683 dumps->budb_dumpsList_val =
1684 (afs_int32 *) realloc(dumps->
1688 flags->budb_dumpsList_val =
1689 (afs_int32 *) realloc(flags->
1694 if (!dumps->budb_dumpsList_val
1695 || !dumps->budb_dumpsList_val)
1699 /* Add it to our list */
1700 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] =
1701 ntohl(appDiskDump.id);
1702 flags->budb_dumpsList_val[flags->budb_dumpsList_len] = 0;
1703 if (ntohl(appDiskDump.initialDumpID) != 0) {
1704 flags->budb_dumpsList_val[flags->
1705 budb_dumpsList_len] |=
1708 if (strcmp(appDiskDump.dumpName, DUMP_TAPE_NAME) == 0) {
1709 flags->budb_dumpsList_val[flags->
1710 budb_dumpsList_len] |=
1713 dumps->budb_dumpsList_len++;
1714 flags->budb_dumpsList_len++;
1720 code = ubik_EndTrans(ut);
1724 ubik_AbortTrans(ut);
1729 SBUDB_DeleteTape(call, tape)
1730 struct rx_call *call;
1731 struct budb_tapeEntry *tape; /* tape info */
1735 code = DoDeleteTape(call, tape);
1736 osi_auditU(call, BUDB_DelTpeEvent, code, AUD_DATE,
1737 (tape ? tape->dump : 0), AUD_END);
1742 DoDeleteTape(call, tape)
1743 struct rx_call *call;
1744 struct budb_tapeEntry *tape; /* tape info */
1746 struct ubik_trans *ut;
1749 afs_int32 eval, code;
1751 if (!callPermitted(call))
1752 return BUDB_NOTPERMITTED;
1754 eval = InitRPC(&ut, LOCKWRITE, 1);
1758 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
1762 eval = DeleteTape(ut, a, &t);
1766 eval = FreeStructure(ut, tape_BLOCK, a);
1770 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1774 code = ubik_EndTrans(ut);
1778 ubik_AbortTrans(ut);
1783 * Deletes old information from the database for a particular dump path
1784 * and volumset. This supercedes the old policy implemented in
1785 * UseTape, which simply matched on the volumeset.dump. Consequently
1786 * it was unable to handle name re-use.
1788 * dsname - dumpset name, i.e. volumeset.dumpname
1789 * dumpPath - full path of dump node
1790 * curDumpID - current dump in progress - so that is may be excluded
1793 * n - some error. May or may not have deleted information.
1797 SBUDB_DeleteVDP(call, dsname, dumpPath, curDumpId)
1798 struct rx_call *call;
1801 afs_int32 curDumpId;
1805 code = DeleteVDP(call, dsname, dumpPath, curDumpId);
1806 osi_auditU(call, BUDB_DelVDPEvent, code, AUD_STR, dsname, AUD_END);
1811 DeleteVDP(call, dsname, dumpPath, curDumpId)
1812 struct rx_call *call;
1815 afs_int32 curDumpId;
1820 struct ubik_trans *ut;
1821 afs_int32 eval, code = 0;
1823 if (!callPermitted(call))
1824 return BUDB_NOTPERMITTED;
1827 eval = InitRPC(&ut, LOCKREAD, 1);
1831 eval = ht_LookupEntry(ut, &db.dumpName, dsname, &dumpAddr, &dump);
1835 while (dumpAddr != 0) { /*wd */
1836 if ((strcmp(dump.dumpName, dsname) == 0)
1837 && (strcmp(dump.dumpPath, dumpPath) == 0)
1838 && (ntohl(dump.id) != curDumpId)) {
1839 eval = ubik_EndTrans(ut);
1843 eval = deleteDump(call, ntohl(dump.id), 0);
1847 /* start the traversal over since the various chains may
1853 dumpAddr = ntohl(dump.nameHashChain);
1855 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
1861 /* check if all the dumps have been examined - can terminate */
1863 eval = ubik_EndTrans(ut);
1869 ubik_AbortTrans(ut);
1875 * Given a volume name, and a dumpID, find the volume in that dump and
1876 * return the clone date of the volume (this is the clone date of the
1877 * volume at the time it was dumped).
1879 * Hashes on the volume name and traverses the fragments. Will need to read
1880 * the volumes tape entry to determine if it belongs to the dump. If the
1881 * volume is not found in the dump, then look for it in its parent dump.
1885 SBUDB_FindClone(call, dumpID, volName, clonetime)
1886 struct rx_call *call;
1889 afs_int32 *clonetime;
1893 code = FindClone(call, dumpID, volName, clonetime);
1894 osi_auditU(call, BUDB_FndClnEvent, code, AUD_STR, volName, AUD_END);
1899 FindClone(call, dumpID, volName, clonetime)
1900 struct rx_call *call;
1903 afs_int32 *clonetime;
1905 struct ubik_trans *ut;
1906 dbadr da, hvia, via, vfa;
1909 struct volFragment vf;
1911 int rvi; /* read the volInfo struct */
1912 afs_int32 eval, code = 0;
1914 if (!callPermitted(call))
1915 return BUDB_NOTPERMITTED;
1917 eval = InitRPC(&ut, LOCKREAD, 1);
1923 /* Search for the volume by name */
1924 eval = ht_LookupEntry(ut, &db.volName, volName, &hvia, &vi);
1928 ABORT(BUDB_NOVOLUMENAME);
1931 /* Follw the dump levels up */
1932 for (; dumpID; dumpID = ntohl(d.parent)) { /*d */
1933 /* Get the dump entry */
1934 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &da, &d);
1938 ABORT(BUDB_NODUMPID);
1940 /* seach all the volInfo entries on the sameNameChain */
1941 for (via = hvia; via; via = ntohl(vi.sameNameChain)) { /*via */
1942 if (rvi) { /* Read the volInfo entry - except first time */
1943 eval = dbread(ut, via, &vi, sizeof(vi));
1949 /* search all the volFrag entries on the volFrag */
1950 for (vfa = ntohl(vi.firstFragment); vfa; vfa = ntohl(vf.sameNameChain)) { /*vfa */
1951 eval = dbread(ut, vfa, &vf, sizeof(vf)); /* Read the volFrag entry */
1955 eval = dbread(ut, ntohl(vf.tape), &t, sizeof(t)); /* Read the tape */
1959 /* Now check to see if this fragment belongs to the dump we have */
1960 if (ntohl(t.dump) == da) {
1961 *clonetime = ntohl(vf.clone); /* return the clone */
1969 code = ubik_EndTrans(ut);
1979 * Searches each tape and each volume in the dump until the volume is found.
1980 * If the volume is not in the dump, then we search it's parent dump.
1982 * Re-write to do lookups by volume name.
1985 FindClone(call, dumpID, volName, clonetime)
1986 struct rx_call *call;
1989 afs_int32 *clonetime;
1991 struct ubik_trans *ut;
1992 dbadr diskAddr, tapeAddr, volFragmentAddr;
1995 struct volFragment volFragment;
1996 struct volInfo volInfo;
1997 afs_int32 eval, code = 0;
1999 if (!callPermitted(call))
2000 return BUDB_NOTPERMITTED;
2002 eval = InitRPC(&ut, LOCKREAD, 1);
2008 for (; dumpID; dumpID = ntohl(dump.parent)) { /*d */
2009 /* Get the dump entry */
2010 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &diskAddr, &dump);
2014 ABORT(BUDB_NODUMPID);
2016 /* just to be sure */
2017 if (ntohl(dump.id) != dumpID) {
2018 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID,
2020 ABORT(BUDB_INTERNALERROR);
2023 /* search all the tapes in this dump */
2024 for (tapeAddr = ntohl(dump.firstTape); tapeAddr; tapeAddr = ntohl(tape.nextTape)) { /*t */
2025 /* Get the tape entry */
2026 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
2030 /* search all the volume fragments on this tape */
2031 for (volFragmentAddr = ntohl(tape.firstVol); volFragmentAddr; volFragmentAddr = ntohl(volFragment.sameTapeChain)) { /*vf */
2032 /* Get the volume fragment entry */
2034 dbread(ut, volFragmentAddr, &volFragment,
2035 sizeof(volFragment));
2039 /* Get the volume info entry */
2041 dbread(ut, ntohl(volFragment.vol), &volInfo,
2046 /* check if this volume is the one we want */
2047 if (strcmp(volInfo.name, volName) == 0) {
2048 *clonetime = ntohl(volFragment.clone);
2056 code = ubik_EndTrans(ut);
2066 * Find latest volume dump before adate.
2067 * Used by restore code when restoring a user requested volume(s)
2069 * volumeName - name of volume to match on
2070 * beforeDate - look for dumps older than this date
2072 * deptr - descriptor of most recent dump
2076 SBUDB_FindDump(call, volumeName, beforeDate, deptr)
2077 struct rx_call *call;
2079 afs_int32 beforeDate;
2080 struct budb_dumpEntry *deptr;
2084 code = FindDump(call, volumeName, beforeDate, deptr);
2085 osi_auditU(call, BUDB_FndDmpEvent, code, AUD_STR, volumeName, AUD_END);
2090 FindDump(call, volumeName, beforeDate, deptr)
2091 struct rx_call *call;
2093 afs_int32 beforeDate;
2094 struct budb_dumpEntry *deptr;
2096 struct ubik_trans *ut;
2097 dbadr volInfoAddr, volFragmentAddr;
2099 struct volInfo volInfo;
2100 struct volFragment volFragment;
2102 dbadr selectedDumpAddr = 0;
2103 afs_int32 selectedDate = 0;
2104 afs_int32 volCloned;
2106 afs_int32 eval, code = 0;
2108 if (!callPermitted(call))
2109 return BUDB_NOTPERMITTED;
2111 eval = InitRPC(&ut, LOCKREAD, 1);
2115 /* Find volinfo struct for volume name in hash table */
2117 ht_LookupEntry(ut, &db.volName, volumeName, &volInfoAddr, &volInfo);
2121 ABORT(BUDB_NOVOLUMENAME);
2123 /* Step through all the volinfo structures on the same name chain.
2124 * No need to read the first - we read it above.
2126 for (rvoli = 0; volInfoAddr;
2127 rvoli = 1, volInfoAddr = ntohl(volInfo.sameNameChain)) {
2128 if (rvoli) { /* read the volinfo structure */
2129 eval = dbread(ut, volInfoAddr, &volInfo, sizeof(volInfo));
2134 /* step through the volfrag structures */
2135 for (volFragmentAddr = ntohl(volInfo.firstFragment); volFragmentAddr;
2136 volFragmentAddr = ntohl(volFragment.sameNameChain)) {
2137 /* read the volfrag struct */
2139 dbread(ut, volFragmentAddr, &volFragment,
2140 sizeof(volFragment));
2144 volCloned = ntohl(volFragment.clone);
2146 /* now we can examine the date for most recent dump */
2147 if ((volCloned > selectedDate) && (volCloned < beforeDate)) {
2148 /* from the volfrag struct, read the tape struct */
2150 dbread(ut, ntohl(volFragment.tape), &tape, sizeof(tape));
2154 selectedDate = volCloned;
2155 selectedDumpAddr = ntohl(tape.dump);
2160 if (!selectedDumpAddr)
2163 eval = FillDumpEntry(ut, selectedDumpAddr, deptr);
2167 code = ubik_EndTrans(ut);
2175 /* BUDB_FindLatestDump
2176 * Find the latest dump of volumeset vsname with dump name dname.
2178 * vsname - volumeset name
2183 SBUDB_FindLatestDump(call, vsname, dumpPath, dumpentry)
2184 struct rx_call *call;
2185 char *vsname, *dumpPath;
2186 struct budb_dumpEntry *dumpentry;
2190 code = FindLatestDump(call, vsname, dumpPath, dumpentry);
2191 osi_auditU(call, BUDB_FndLaDEvent, code, AUD_STR, vsname, AUD_END);
2196 FindLatestDump(call, vsname, dumpPath, dumpentry)
2197 struct rx_call *call;
2198 char *vsname, *dumpPath;
2199 struct budb_dumpEntry *dumpentry;
2201 struct ubik_trans *ut;
2202 dbadr curdbaddr, retdbaddr, firstdbaddr;
2205 char dumpName[BU_MAXNAMELEN + 2];
2206 afs_int32 eval, code = 0;
2208 if (!callPermitted(call))
2209 return BUDB_NOTPERMITTED;
2211 eval = InitRPC(&ut, LOCKREAD, 1);
2215 if ((strcmp(vsname, "") == 0) && (strcmp(dumpPath, "") == 0)) {
2216 /* Construct a database dump name */
2217 strcpy(dumpName, DUMP_TAPE_NAME);
2218 } else if (strchr(dumpPath, '/') == 0) {
2219 int level, old, length, hash;
2220 struct dump hostDump, diskDump;
2221 struct memoryHashTable *mht;
2224 afs_uint32 bestDumpId = 0;
2226 level = atoi(dumpPath);
2228 ABORT(BUDB_BADARGUMENT);
2231 /* Brute force search of all the dumps in the database - yuck! */
2234 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
2236 ABORT(BUDB_BADARGUMENT);
2238 for (old = 0; old <= 1; old++) { /*fo */
2239 length = (old ? mht->oldLength : mht->length);
2243 for (hash = 0; hash < length; hash++) {
2245 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr;
2246 dbAddr = hostDump.idHashChain) {
2248 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
2251 dump_ntoh(&diskDump, &hostDump);
2253 if ((strcmp(hostDump.volumeSet, vsname) == 0) && /* the volumeset */
2254 (hostDump.level == level) && /* same level */
2255 (hostDump.id > bestDumpId)) { /* more recent */
2256 bestDumpId = hostDump.id;
2263 ABORT(BUDB_NODUMPNAME);
2267 /* construct the name of the dump */
2268 if ((strlen(vsname) + strlen(tailCompPtr(dumpPath))) > BU_MAXNAMELEN)
2269 ABORT(BUDB_NODUMPNAME);
2271 strcpy(dumpName, vsname);
2272 strcat(dumpName, ".");
2273 strcat(dumpName, tailCompPtr(dumpPath));
2276 LogDebug(5, "lookup on :%s:\n", dumpName);
2278 /* Lookup on dumpname in hash table */
2279 eval = ht_LookupEntry(ut, &db.dumpName, dumpName, &firstdbaddr, &d);
2286 /* folow remaining dumps in hash chain, looking for most latest dump */
2287 for (curdbaddr = firstdbaddr; curdbaddr;
2288 curdbaddr = ntohl(d.nameHashChain)) {
2289 if (curdbaddr != firstdbaddr) {
2290 eval = dbread(ut, curdbaddr, &d, sizeof(d));
2295 if ((strcmp(d.dumpPath, dumpPath) == 0) && /* Same dumppath */
2296 (strcmp(d.dumpName, dumpName) == 0) && /* Same dumpname */
2297 (ntohl(d.created) > latest)) { /* most recent */
2298 latest = ntohl(d.created);
2299 retdbaddr = curdbaddr;
2303 ABORT(BUDB_NODUMPNAME);
2306 /* return the dump found */
2307 FillDumpEntry(ut, retdbaddr, dumpentry);
2309 code = ubik_EndTrans(ut);
2313 ubik_AbortTrans(ut);
2319 SBUDB_FinishDump(call, dump)
2320 struct rx_call *call;
2321 struct budb_dumpEntry *dump;
2325 code = FinishDump(call, dump);
2326 osi_auditU(call, BUDB_FinDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
2332 FinishDump(call, dump)
2333 struct rx_call *call;
2334 struct budb_dumpEntry *dump;
2336 struct ubik_trans *ut;
2339 afs_int32 eval, code = 0;
2341 if (!callPermitted(call))
2342 return BUDB_NOTPERMITTED;
2344 eval = InitRPC(&ut, LOCKWRITE, 1);
2348 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &a, &d);
2352 ABORT(BUDB_NODUMPID);
2354 if ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)
2355 ABORT(BUDB_DUMPNOTINUSE);
2357 d.flags = htonl(dump->flags & ~BUDB_DUMP_INPROGRESS);
2359 /* if creation time specified set it */
2361 d.created = htonl(dump->created);
2362 dump->created = ntohl(d.created);
2364 /* Write the dump entry out */
2365 eval = dbwrite(ut, a, &d, sizeof(d));
2369 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2373 code = ubik_EndTrans(ut);
2377 ubik_AbortTrans(ut);
2382 SBUDB_FinishTape(call, tape)
2383 struct rx_call *call;
2384 struct budb_tapeEntry *tape;
2388 code = FinishTape(call, tape);
2389 osi_auditU(call, BUDB_FinTpeEvent, code, AUD_DATE,
2390 (tape ? tape->dump : 0), AUD_END);
2395 FinishTape(call, tape)
2396 struct rx_call *call;
2397 struct budb_tapeEntry *tape;
2399 struct ubik_trans *ut;
2403 afs_int32 eval, code = 0;
2405 if (!callPermitted(call))
2406 return BUDB_NOTPERMITTED;
2408 eval = InitRPC(&ut, LOCKWRITE, 1);
2412 /* find the tape struct in the tapename hash chain */
2413 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
2417 ABORT(BUDB_NOTAPENAME);
2419 /* Read the dump structure */
2420 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2424 /* search for the right tape on the rest of the chain */
2425 while (ntohl(d.id) != tape->dump) {
2426 a = ntohl(t.nameHashChain);
2428 ABORT(BUDB_NOTAPENAME);
2430 eval = dbread(ut, a, &t, sizeof(t));
2434 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2439 if ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0)
2440 ABORT(BUDB_TAPENOTINUSE);
2442 /* t.nBytes = htonl(tape->nBytes); */
2443 t.nFiles = htonl(tape->nFiles);
2444 t.useKBytes = htonl(tape->useKBytes);
2445 t.flags = htonl(tape->flags & ~BUDB_TAPE_BEINGWRITTEN);
2447 eval = dbwrite(ut, a, &t, sizeof(t));
2451 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2455 code = ubik_EndTrans(ut);
2459 ubik_AbortTrans(ut);
2464 * return a set of dumps that match the specified criteria
2467 * majorVersion - version of interface structures. Permits compatibility
2469 * flags - for search and select operations. Broken down into flags
2470 * for name, start point, end point and time.
2471 * name - name to search for. Interpretation based on flags
2478 * dbTimeP - time at which the database was last modified. Up to
2479 * caller (client) to take appropriate action if database
2480 * modified between successive calls
2481 * dumps - list of matching dumps
2483 * currently supported are:
2489 SBUDB_GetDumps(call, majorVersion, flags, name, start, end, index, nextIndexP,
2491 struct rx_call *call;
2492 afs_int32 majorVersion; /* version of interface structures */
2493 afs_int32 flags; /* search & select controls */
2494 char *name; /* s&s parameters */
2497 afs_int32 index; /* start index of returned entries */
2498 afs_int32 *nextIndexP; /* output index for next call */
2500 budb_dumpList *dumps; /* pointer to buffer */
2505 GetDumps(call, majorVersion, flags, name, start, end, index,
2506 nextIndexP, dbTimeP, dumps);
2507 osi_auditU(call, BUDB_GetDmpEvent, code, AUD_END);
2512 GetDumps(call, majorVersion, flags, name, start, end, index, nextIndexP,
2514 struct rx_call *call;
2515 afs_int32 majorVersion; /* version of interface structures */
2516 afs_int32 flags; /* search & select controls */
2517 char *name; /* s&s parameters */
2520 afs_int32 index; /* start index of returned entries */
2521 afs_int32 *nextIndexP; /* output index for next call */
2523 budb_dumpList *dumps; /* pointer to buffer */
2525 struct ubik_trans *ut;
2528 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2529 afs_int32 eval, code = 0;
2531 struct returnList list;
2533 /* Don't check permissions when we look up a specific dump id */
2534 if (((flags & BUDB_OP_STARTS) != BUDB_OP_DUMPID) && !callPermitted(call))
2535 return BUDB_NOTPERMITTED;
2537 if (majorVersion != BUDB_MAJORVERSION)
2538 return BUDB_OLDINTERFACE;
2540 return BUDB_ENDOFLIST;
2542 eval = InitRPC(&ut, LOCKREAD, 1);
2546 nameFlags = flags & BUDB_OP_NAMES;
2547 startFlags = flags & BUDB_OP_STARTS;
2548 endFlags = flags & BUDB_OP_ENDS;
2549 timeFlags = flags & BUDB_OP_TIMES;
2551 InitReturnList(&list);
2554 if (nameFlags == BUDB_OP_DUMPNAME) {
2555 /* not yet implemented */
2556 if (startFlags || endFlags || timeFlags)
2557 ABORT(BUDB_BADFLAGS);
2559 eval = ht_LookupEntry(ut, &db.dumpName, name, &da, &d);
2563 ABORT(BUDB_NODUMPNAME);
2566 if (strcmp(d.dumpName, name) == 0) {
2567 eval = AddToReturnList(&list, da, &toskip);
2568 if (eval == BUDB_LIST2BIG)
2574 da = ntohl(d.nameHashChain); /* get next dump w/ name */
2578 eval = dbread(ut, da, &d, sizeof(d));
2582 } else if (nameFlags == BUDB_OP_VOLUMENAME) {
2586 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2587 ABORT(BUDB_BADFLAGS);
2590 if (startFlags != BUDB_OP_STARTTIME)
2591 ABORT(BUDB_BADFLAGS);
2593 /* lookup a dump by volumename and time stamp. Find the most recent
2594 * dump of the specified volumename, that occured before the supplied
2598 /* get us a volInfo for name */
2599 eval = ht_LookupEntry(ut, &db.volName, name, &da, &vi);
2604 /* now iterate over all the entries of this name */
2605 for (va = vi.firstFragment; va != 0; va = v.sameNameChain) {
2607 eval = dbread(ut, va, &v, sizeof(v));
2612 on fragment > date ignore it - too recent;
2614 if (date on fragment < date && date on fragment > bestfound)
2615 bestfound = date on fragment;
2619 da = vi.sameNameChain;
2623 eval = dbread(ut, da, &vi, sizeof(vi));
2632 from saved volfragment address, compute dump.
2633 otherwise, return dump found
2638 } else if (startFlags == BUDB_OP_DUMPID) {
2639 if (endFlags || timeFlags)
2640 ABORT(BUDB_BADFLAGS);
2642 ABORT(BUDB_BADFLAGS); /* NYI */
2644 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
2648 ABORT(BUDB_NODUMPID);
2650 eval = AddToReturnList(&list, da, &toskip);
2653 } else if (endFlags == BUDB_OP_NPREVIOUS) {
2654 struct wantDumpRock rock;
2655 struct chosenDump *ptr, *nextPtr;
2657 extern wantDump(), rememberDump();
2659 /* no other flags should be set */
2661 /* end specifies how many dumps */
2663 ABORT(BUDB_BADFLAGS);
2665 memset(&rock, 0, sizeof(rock));
2666 rock.maxDumps = end;
2668 scanHashTable(ut, &db.dumpName, wantDump, rememberDump,
2671 for (ptr = rock.chain; ptr; ptr = nextPtr) {
2672 nextPtr = ptr->next;
2673 AddToReturnList(&list, ptr->addr, &toskip); /* ignore error for free */
2677 ABORT(BUDB_BADFLAGS);
2681 SendReturnList(ut, &list, FillDumpEntry,
2682 sizeof(struct budb_dumpEntry), index, nextIndexP,
2683 dbTimeP, (returnList_t) dumps);
2687 FreeReturnList(&list);
2688 code = ubik_EndTrans(ut);
2692 FreeReturnList(&list);
2693 ubik_AbortTrans(ut);
2698 * Get the expiration of a tape. Since the dump could have appended dumps,
2699 * we should use the most recent expiration date. Put the most recent
2700 * expiration tape into the given tape structure.
2703 getExpiration(ut, tapePtr)
2704 struct ubik_trans *ut;
2705 struct tape *tapePtr;
2711 afs_int32 eval, code = 0;
2716 /* Get the dump for this tape */
2717 ad = ntohl(tapePtr->dump);
2718 eval = dbread(ut, ad, &d, sizeof(d));
2722 /* If not an initial dump, get the initial dump */
2723 if (d.initialDumpID) {
2724 initDump = ntohl(d.initialDumpID);
2725 eval = ht_LookupEntry(ut, &db.dumpIden, &initDump, &ad, &d);
2730 /* Cycle through the dumps and appended dumps */
2732 /* Get the first tape in this dump. No need to check the rest of the tapes */
2733 /* for this dump since they will all have the same expiration date */
2734 eval = dbread(ut, ntohl(d.firstTape), &t, sizeof(t));
2738 /* Take the greater of the expiration dates */
2739 if (ntohl(tapePtr->expires) < ntohl(t.expires))
2740 tapePtr->expires = t.expires;
2742 /* Step to and read the next appended dump */
2743 if (ad = ntohl(d.appendedDumpChain)) {
2744 eval = dbread(ut, ad, &d, sizeof(d));
2754 /* Mark the following dump as appended to another, intial dump */
2756 makeAppended(ut, appendedDumpID, initialDumpID, startTapeSeq)
2757 struct ubik_trans *ut;
2758 afs_int32 appendedDumpID;
2759 afs_int32 initialDumpID;
2760 afs_int32 startTapeSeq;
2762 dbadr ada, da, lastDumpAddr;
2764 afs_int32 eval, code = 0;
2768 if (appendedDumpID == initialDumpID)
2769 ERROR(BUDB_INTERNALERROR);
2771 /* If there is an initial dump, append this dump to it */
2772 /* Find the appended dump via its id */
2773 eval = ht_LookupEntry(ut, &db.dumpIden, &appendedDumpID, &ada, &ad);
2777 /* If the dump is already marked as appended,
2778 * then we have an internal error.
2780 if (ad.initialDumpID) {
2781 if (ntohl(ad.initialDumpID) != initialDumpID)
2782 ERROR(BUDB_INTERNALERROR);
2785 /* Update the appended dump to point to the initial dump */
2786 ad.initialDumpID = htonl(initialDumpID);
2787 ad.tapes.b = htonl(startTapeSeq);
2789 /* find the initial dump via its id */
2790 eval = ht_LookupEntry(ut, &db.dumpIden, &initialDumpID, &da, &d);
2794 /* Update the appended dump's tape format with that of the initial */
2795 strcpy(ad.tapes.format, d.tapes.format);
2797 /* starting with the initial dump step through its appended dumps till
2798 * we reach the last appended dump.
2801 while (d.appendedDumpChain) {
2802 lastDumpAddr = ntohl(d.appendedDumpChain);
2803 if (lastDumpAddr == ada)
2804 ERROR(0); /* Already appended */
2805 eval = dbread(ut, lastDumpAddr, &d, sizeof(d));
2810 /* Update the last dump to point to our new appended dump.
2811 * The appended dump is the last one in the dump chain.
2813 d.appendedDumpChain = htonl(ada);
2814 ad.appendedDumpChain = 0;
2816 /* Write the appended dump and the initial dump */
2817 eval = dbwrite(ut, ada, (char *)&ad, sizeof(ad));
2821 eval = dbwrite(ut, lastDumpAddr, (char *)&d, sizeof(d));
2825 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2834 SBUDB_MakeDumpAppended(call, appendedDumpID, initialDumpID, startTapeSeq)
2835 struct rx_call *call;
2836 afs_int32 appendedDumpID;
2837 afs_int32 initialDumpID;
2838 afs_int32 startTapeSeq;
2843 MakeDumpAppended(call, appendedDumpID, initialDumpID, startTapeSeq);
2844 osi_auditU(call, BUDB_AppDmpEvent, code, AUD_LONG, appendedDumpID,
2850 MakeDumpAppended(call, appendedDumpID, initialDumpID, startTapeSeq)
2851 struct rx_call *call;
2852 afs_int32 appendedDumpID;
2853 afs_int32 initialDumpID;
2854 afs_int32 startTapeSeq;
2856 struct ubik_trans *ut;
2857 afs_int32 eval, code = 0;
2859 if (!callPermitted(call))
2860 return BUDB_NOTPERMITTED;
2862 eval = InitRPC(&ut, LOCKWRITE, 1);
2866 eval = makeAppended(ut, appendedDumpID, initialDumpID, startTapeSeq);
2870 code = ubik_EndTrans(ut);
2874 ubik_AbortTrans(ut);
2878 /* Find the last tape of a dump-set. This includes any appended dumps */
2880 SBUDB_FindLastTape(call, dumpID, dumpEntry, tapeEntry, volEntry)
2881 struct rx_call *call;
2883 struct budb_dumpEntry *dumpEntry;
2884 struct budb_tapeEntry *tapeEntry;
2885 struct budb_volumeEntry *volEntry;
2889 code = FindLastTape(call, dumpID, dumpEntry, tapeEntry, volEntry);
2890 osi_auditU(call, BUDB_FndLTpeEvent, code, AUD_LONG, dumpID, AUD_END);
2895 FindLastTape(call, dumpID, dumpEntry, tapeEntry, volEntry)
2896 struct rx_call *call;
2898 struct budb_dumpEntry *dumpEntry;
2899 struct budb_tapeEntry *tapeEntry;
2900 struct budb_volumeEntry *volEntry;
2902 struct ubik_trans *ut;
2906 dbadr lastTape, thisTape;
2907 afs_int32 lastTapeSeq;
2908 struct volFragment vf;
2909 dbadr lastVol, thisVol;
2910 afs_int32 lastVolPos;
2911 afs_int32 eval, code = 0;
2913 if (!callPermitted(call))
2914 return BUDB_NOTPERMITTED;
2917 return (BUDB_BADARGUMENT);
2919 eval = InitRPC(&ut, LOCKREAD, 1);
2923 /* find and read its initial dump via its id */
2924 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &lastDump, &d);
2928 ABORT(BUDB_NODUMPID);
2930 /* Follow the append dumps link chain until we reach the last dump */
2931 while (d.appendedDumpChain) {
2932 lastDump = ntohl(d.appendedDumpChain);
2933 eval = dbread(ut, lastDump, &d, sizeof(d));
2938 /* We now have the last dump of the last appended dump */
2939 /* Copy this into our return structure */
2940 eval = FillDumpEntry(ut, lastDump, dumpEntry);
2944 /* Fail if the last dump has no tapes */
2946 ABORT(BUDB_NOTAPENAME);
2948 /* Follow the tapes in this dump until we reach the last tape */
2949 eval = dbread(ut, ntohl(d.firstTape), &t, sizeof(t));
2953 lastTape = ntohl(d.firstTape);
2954 lastTapeSeq = ntohl(t.seq);
2955 lastVol = ntohl(t.firstVol);
2957 while (t.nextTape) {
2958 thisTape = ntohl(t.nextTape);
2959 eval = dbread(ut, thisTape, &t, sizeof(t));
2963 if (ntohl(t.seq) > lastTapeSeq) {
2964 lastTape = thisTape;
2965 lastTapeSeq = ntohl(t.seq);
2966 lastVol = ntohl(t.firstVol);
2970 /* We now have the last tape of the last appended dump */
2971 /* Copy this into our return structure */
2972 eval = FillTapeEntry(ut, lastTape, tapeEntry);
2976 /* Zero volume entry if the last tape has no volumes */
2978 memset(volEntry, 0, sizeof(*volEntry));
2980 /* Follow the volumes until we reach the last volume */
2981 eval = dbread(ut, lastVol, &vf, sizeof(vf));
2985 lastVolPos = vf.position;
2987 while (vf.sameTapeChain) {
2988 thisVol = ntohl(vf.sameTapeChain);
2989 eval = dbread(ut, thisVol, &vf, sizeof(vf));
2993 if (vf.position > lastVolPos) {
2995 lastVolPos = vf.position;
2999 /* We now have the last volume of this tape */
3000 /* Copy this into our return structure */
3001 eval = FillVolEntry(ut, lastVol, volEntry);
3006 eval = ubik_EndTrans(ut);
3012 ubik_AbortTrans(ut);
3018 SBUDB_GetTapes(call, majorVersion, flags, name, start, end, index, nextIndexP,
3020 struct rx_call *call;
3021 afs_int32 majorVersion; /* version of interface structures */
3022 afs_int32 flags; /* search & select controls */
3023 char *name; /* s&s parameters */
3025 afs_int32 end; /* reserved: MBZ */
3026 afs_int32 index; /* start index of returned entries */
3027 afs_int32 *nextIndexP; /* output index for next call */
3029 budb_tapeList *tapes; /* pointer to buffer */
3034 GetTapes(call, majorVersion, flags, name, start, end, index,
3035 nextIndexP, dbTimeP, tapes);
3036 osi_auditU(call, BUDB_GetTpeEvent, code, AUD_END);
3041 GetTapes(call, majorVersion, flags, name, start, end, index, nextIndexP,
3043 struct rx_call *call;
3044 afs_int32 majorVersion; /* version of interface structures */
3045 afs_int32 flags; /* search & select controls */
3046 char *name; /* s&s parameters */
3048 afs_int32 end; /* reserved: MBZ */
3049 afs_int32 index; /* start index of returned entries */
3050 afs_int32 *nextIndexP; /* output index for next call */
3052 budb_tapeList *tapes; /* pointer to buffer */
3054 struct ubik_trans *ut;
3058 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
3059 struct returnList list;
3060 afs_int32 eval, code = 0;
3063 if (!callPermitted(call))
3064 return BUDB_NOTPERMITTED;
3066 if (majorVersion != BUDB_MAJORVERSION)
3067 return BUDB_OLDINTERFACE;
3070 return BUDB_ENDOFLIST;
3072 eval = InitRPC(&ut, LOCKREAD, 1);
3076 nameFlags = flags & BUDB_OP_NAMES;
3077 startFlags = flags & BUDB_OP_STARTS;
3078 endFlags = flags & BUDB_OP_ENDS;
3079 timeFlags = flags & BUDB_OP_TIMES;
3081 InitReturnList(&list);
3084 if (nameFlags == BUDB_OP_TAPENAME) { /*it */
3085 eval = ht_LookupEntry(ut, &db.tapeName, name, &ta, &t);
3089 ABORT(BUDB_NOTAPENAME);
3092 if ((startFlags & ~BUDB_OP_DUMPID) || endFlags || timeFlags)
3093 ABORT(BUDB_BADFLAGS);
3095 /* follow the hash chain to the end */
3097 if (startFlags & BUDB_OP_DUMPID) {
3098 /* read in the dump */
3099 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
3103 /* check if both name and dump id match */
3104 if ((strcmp(name, t.name) == 0) && (ntohl(d.id) == start)) {
3105 eval = AddToReturnList(&list, ta, &toskip);
3106 if (eval && (eval != BUDB_LIST2BIG))
3111 /* Add to return list and continue search */
3112 if (strcmp(name, t.name) == 0) {
3113 eval = AddToReturnList(&list, ta, &toskip);
3114 if (eval == BUDB_LIST2BIG)
3121 ta = ntohl(t.nameHashChain);
3123 dbread(ut, ta, &t, sizeof(t));
3126 else if (nameFlags == BUDB_OP_TAPESEQ) {
3127 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
3131 ABORT(BUDB_NODUMPNAME);
3133 /* search for the right tape */
3134 ta = ntohl(d.firstTape);
3135 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
3136 eval = dbread(ut, ta, &t, sizeof(t));
3140 if (ntohl(t.seq) == end) {
3141 eval = AddToReturnList(&list, ta, &toskip);
3142 if (eval && (eval != BUDB_LIST2BIG))
3148 ABORT(BUDB_BADFLAGS);
3152 SendReturnList(ut, &list, FillTapeEntry,
3153 sizeof(struct budb_tapeEntry), index, nextIndexP,
3154 dbTimeP, (returnList_t) tapes);
3158 FreeReturnList(&list);
3159 code = ubik_EndTrans(ut);
3163 FreeReturnList(&list);
3164 ubik_AbortTrans(ut);
3169 * get a set of volumes according to the specified criteria.
3170 * See BUDB_GetDumps for general information on parameters
3171 * Currently supports:
3172 * 1) volume match - returns volumes based on volume name only.
3173 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
3174 * and start is a dumpid. Returns all volumes of the specified
3175 * name on the selected dumpid.
3179 SBUDB_GetVolumes(call, majorVersion, flags, name, start, end, index,
3180 nextIndexP, dbTimeP, volumes)
3181 struct rx_call *call;
3182 afs_int32 majorVersion; /* version of interface structures */
3183 afs_int32 flags; /* search & select controls */
3184 char *name; /* - parameters for search */
3185 afs_int32 start; /* - usage depends which BUDP_OP_* */
3186 afs_int32 end; /* - bits are set */
3187 afs_int32 index; /* start index of returned entries */
3188 afs_int32 *nextIndexP; /* output index for next call */
3190 budb_volumeList *volumes; /* pointer to buffer */
3195 GetVolumes(call, majorVersion, flags, name, start, end, index,
3196 nextIndexP, dbTimeP, volumes);
3197 osi_auditU(call, BUDB_GetVolEvent, code, AUD_END);
3202 GetVolumes(call, majorVersion, flags, name, start, end, index, nextIndexP,
3204 struct rx_call *call;
3205 afs_int32 majorVersion; /* version of interface structures */
3206 afs_int32 flags; /* search & select controls */
3207 char *name; /* - parameters for search */
3208 afs_int32 start; /* - usage depends which BUDP_OP_* */
3209 afs_int32 end; /* - bits are set */
3210 afs_int32 index; /* start index of returned entries */
3211 afs_int32 *nextIndexP; /* output index for next call */
3213 budb_volumeList *volumes; /* pointer to buffer */
3215 struct ubik_trans *ut;
3218 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
3219 afs_int32 eval, code = 0;
3220 struct returnList vollist;
3223 /* Don't check permissions when we look up a specific volume name */
3224 if (((flags & BUDB_OP_NAMES) != BUDB_OP_VOLUMENAME)
3225 && !callPermitted(call))
3226 return BUDB_NOTPERMITTED;
3228 if (majorVersion != BUDB_MAJORVERSION)
3229 return BUDB_OLDINTERFACE;
3231 return BUDB_ENDOFLIST;
3233 eval = InitRPC(&ut, LOCKREAD, 1);
3237 nameFlags = flags & BUDB_OP_NAMES;
3238 startFlags = flags & BUDB_OP_STARTS;
3239 endFlags = flags & BUDB_OP_ENDS;
3240 timeFlags = flags & BUDB_OP_TIMES;
3242 InitReturnList(&vollist);
3245 /* lookup a the volume (specified by name) in the dump (specified by id) */
3246 if (nameFlags == BUDB_OP_VOLUMENAME) {
3247 /* dumpid permissible, all others off */
3248 if (((startFlags & ~BUDB_OP_DUMPID) != 0) || endFlags || timeFlags)
3249 ABORT(BUDB_BADFLAGS);
3251 /* returns ptr to volinfo of requested name */
3252 eval = ht_LookupEntry(ut, &db.volName, name, &via, &vi);
3256 ABORT(BUDB_NOVOLUMENAME);
3258 /* Iterate over all volume fragments with this name */
3260 struct volFragment v;
3263 /* traverse all the volume fragments for this volume info structure */
3264 for (va = vi.firstFragment; va; va = v.sameNameChain) {
3266 eval = dbread(ut, va, &v, sizeof(v));
3270 if (startFlags & BUDB_OP_DUMPID) {
3274 /* get the dump id for this fragment */
3275 eval = dbread(ut, ntohl(v.tape), &atape, sizeof(atape));
3280 dbread(ut, ntohl(atape.dump), &adump, sizeof(adump));
3284 /* dump id does not match */
3285 if (ntohl(adump.id) != start)
3289 eval = AddToReturnList(&vollist, va, &toskip);
3290 if (eval == BUDB_LIST2BIG)
3295 if (eval == BUDB_LIST2BIG)
3298 via = vi.sameNameChain;
3303 eval = dbread(ut, via, &vi, sizeof(vi));
3307 } else if (((nameFlags == 0) || (nameFlags == BUDB_OP_TAPENAME))
3308 && (startFlags == BUDB_OP_DUMPID)) {
3313 struct volFragment volFrag;
3316 /* lookup all volumes for a specified dump id */
3318 /* no other flags should be set */
3319 if (endFlags || timeFlags)
3320 ABORT(BUDB_BADFLAGS);
3323 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &dumpAddr, &dump);
3327 /* traverse all the tapes */
3328 for (tapeAddr = ntohl(dump.firstTape); tapeAddr; tapeAddr = ntohl(tape.nextTape)) { /*w */
3329 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
3333 if ((nameFlags != BUDB_OP_TAPENAME)
3334 || ((nameFlags == BUDB_OP_TAPENAME)
3335 && (strcmp(tape.name, name) == 0))) {
3336 /* now return all the volumes */
3337 for (volFragAddr = ntohl(tape.firstVol); volFragAddr;
3338 volFragAddr = ntohl(volFrag.sameTapeChain)) {
3339 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
3343 eval = AddToReturnList(&vollist, volFragAddr, &toskip);
3344 if (eval == BUDB_LIST2BIG)
3350 if (eval == BUDB_LIST2BIG)
3354 ABORT(BUDB_BADFLAGS);
3358 SendReturnList(ut, &vollist, FillVolEntry,
3359 sizeof(struct budb_volumeEntry), index, nextIndexP,
3360 dbTimeP, (returnList_t) volumes);
3365 FreeReturnList(&vollist);
3366 code = ubik_EndTrans(ut);
3370 FreeReturnList(&vollist);
3371 ubik_AbortTrans(ut);
3376 SBUDB_UseTape(call, tape, new)
3377 struct rx_call *call;
3378 struct budb_tapeEntry *tape; /* tape info */
3379 afs_int32 *new; /* set if tape is new */
3383 code = UseTape(call, tape, new);
3384 osi_auditU(call, BUDB_UseTpeEvent, code, AUD_DATE,
3385 (tape ? tape->dump : 0), AUD_END);
3390 UseTape(call, tape, new)
3391 struct rx_call *call;
3392 struct budb_tapeEntry *tape; /* tape info */
3393 int *new; /* set if tape is new */
3395 struct ubik_trans *ut;
3399 afs_int32 eval, code;
3401 if (!callPermitted(call))
3402 return BUDB_NOTPERMITTED;
3404 if (strlen(tape->name) >= sizeof(t.name))
3405 return BUDB_BADARGUMENT;
3407 eval = InitRPC(&ut, LOCKWRITE, 1);
3413 memset(&t, 0, sizeof(t));
3414 eval = AllocStructure(ut, tape_BLOCK, 0, &a, &t);
3418 strcpy(t.name, tape->name);
3420 eval = ht_HashIn(ut, &db.tapeName, a, &t);
3426 /* Since deleting a tape may change the dump (if its the same one), read in
3427 * the dump after the call to DeleteTape. */
3429 eval = ht_LookupEntry(ut, &db.dumpIden, &tape->dump, &da, &d);
3433 ABORT(BUDB_NODUMPID);
3436 tape->written = time(0); /* fill in tape struct */
3437 t.written = htonl(tape->written);
3438 t.expires = htonl(tape->expires);
3440 t.seq = htonl(tape->seq);
3441 t.useCount = htonl(tape->useCount);
3442 t.labelpos = htonl(tape->labelpos);
3444 t.flags = htonl(tape->flags | BUDB_TAPE_BEINGWRITTEN);
3446 t.nextTape = d.firstTape; /* Chain the tape to the dump */
3447 d.firstTape = htonl(a);
3449 if (tape->seq >= ntohl(d.tapes.maxTapes)) /* inc # tapes in the dump */
3450 d.tapes.maxTapes = htonl(tape->seq);
3452 eval = dbwrite(ut, a, &t, sizeof(t)); /* write tape struct */
3456 eval = dbwrite(ut, da, &d, sizeof(d)); /* write the dump struct */
3460 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
3464 LogDebug(5, "added tape %s\n", tape->name);
3466 code = ubik_EndTrans(ut);
3470 ubik_AbortTrans(ut);
3476 /* ---------------------------------------------
3477 * debug interface routines
3478 * ---------------------------------------------
3482 SBUDB_T_DumpHashTable(call, type, filename)
3483 struct rx_call *call;
3489 code = T_DumpHashTable(call, type, filename);
3490 osi_auditU(call, BUDB_TDmpHaEvent, code, AUD_STR, filename, AUD_END);
3495 T_DumpHashTable(call, type, filename)
3496 struct rx_call *call;
3500 struct ubik_trans *ut;
3501 struct memoryHashTable *mht;
3503 afs_int32 eval, code = 0;
3510 char e[sizeof(struct block)]; /* unnecessarily conservative */
3514 if (!callPermitted(call))
3515 return BUDB_NOTPERMITTED;
3517 if (strlen(filename) >= sizeof(path) - 5)
3518 return BUDB_BADARGUMENT;
3520 eval = InitRPC(&ut, LOCKWRITE, 1);
3524 if ((mht = ht_GetType(type, &e_size)) == 0)
3525 return BUDB_BADARGUMENT;
3527 sprintf(path, "%s/%s", gettmpdir(), filename);
3529 DUMP = fopen(path, "w");
3531 ABORT(BUDB_BADARGUMENT);
3534 for (old = 0;; old++) {
3535 length = (old ? mht->oldLength : mht->length);
3537 fprintf(DUMP, "Dumping %sHash Table:\n", (old ? "Old " : ""));
3539 for (hash = 0; hash < length; hash++) {
3540 a = ht_LookupBucket(ut, mht, hash, old);
3543 eval = dbread(ut, a, e, e_size);
3549 fprintf(DUMP, " in bucket %d at %d is ", hash, a);
3551 fprintf(DUMP, " at %d is ", a);
3553 case HT_dumpIden_FUNCTION:
3554 fprintf(DUMP, "%d\n", ntohl(((struct dump *)e)->id));
3556 case HT_dumpName_FUNCTION:
3557 fprintf(DUMP, "%s\n", ((struct dump *)e)->dumpName);
3559 case HT_tapeName_FUNCTION:
3560 fprintf(DUMP, "%s\n", ((struct tape *)e)->name);
3562 case HT_volName_FUNCTION:
3563 fprintf(DUMP, "%s\n", ((struct volInfo *)e)->name);
3566 if ((ht_HashEntry(mht, e) % length) != hash)
3567 ABORT(BUDB_DATABASEINCONSISTENT);
3568 a = ntohl(*(dbadr *) (e + mht->threadOffset));
3575 fprintf(DUMP, "%d entries found\n", ent);
3576 if (ntohl(mht->ht->entries) != ent)
3577 ABORT(BUDB_DATABASEINCONSISTENT);
3579 code = ubik_EndTrans(ut);
3585 ubik_AbortTrans(ut);
3592 SBUDB_T_GetVersion(call, majorVersion)
3593 struct rx_call *call;
3594 afs_int32 *majorVersion;
3598 code = T_GetVersion(call, majorVersion);
3599 osi_auditU(call, BUDB_TGetVrEvent, code, AUD_END);
3604 T_GetVersion(call, majorVersion)
3605 struct rx_call *call;
3608 struct ubik_trans *ut;
3611 code = InitRPC(&ut, LOCKREAD, 0);
3615 *majorVersion = BUDB_MAJORVERSION;
3617 code = ubik_EndTrans(ut);
3621 /* BUDB_T_DumpDatabase
3622 * dump as much of the database as possible int /tmp/<filename>
3626 SBUDB_T_DumpDatabase(call, filename)
3627 struct rx_call *call;
3632 code = T_DumpDatabase(call, filename);
3633 osi_auditU(call, BUDB_TDmpDBEvent, code, AUD_STR, filename, AUD_END);
3638 T_DumpDatabase(call, filename)
3639 struct rx_call *call;
3644 struct ubik_trans *ut;
3647 int type, old, length, hash;
3648 struct memoryHashTable *mht;
3649 afs_int32 eval, code = 0;
3651 if (!callPermitted(call))
3652 return BUDB_NOTPERMITTED;
3654 path = (char *)malloc(strlen(gettmpdir()) + 1 + strlen(filename) + 1);
3656 return (BUDB_INTERNALERROR);
3658 sprintf(path, "%s/%s", gettmpdir(), filename);
3660 dumpfid = fopen(path, "w");
3662 return (BUDB_BADARGUMENT);
3664 eval = InitRPC(&ut, LOCKWRITE, 1);
3668 /* dump all items in the database */
3669 for (type = 1; type <= HT_MAX_FUNCTION; type++) { /*ft */
3670 mht = ht_GetType(type, &entrySize);
3672 ERROR(BUDB_BADARGUMENT);
3674 for (old = 0; old <= 1; old++) { /*fo */
3675 length = (old ? mht->oldLength : mht->length);
3679 fprintf(dumpfid, "Dumping %s Hash Table:\n", (old ? "Old " : ""));
3681 for (hash = 0; hash < length; hash++) { /*f */
3682 dbAddr = ht_LookupBucket(ut, mht, hash, old);
3684 while (dbAddr) { /*w */
3685 switch (type) { /*s */
3686 case HT_dumpIden_FUNCTION:
3688 struct dump hostDump, diskDump;
3691 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3697 "\ndumpId hash %d, entry at %u\n",
3700 "----------------------------\n");
3701 dump_ntoh(&diskDump, &hostDump);
3702 printDump(dumpfid, &hostDump);
3703 dbAddr = hostDump.idHashChain;
3707 case HT_dumpName_FUNCTION:
3709 struct dump hostDump, diskDump;
3712 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3718 "\ndumpname hash %d, entry at %u\n",
3721 "----------------------------\n");
3722 dump_ntoh(&diskDump, &hostDump);
3723 printDump(dumpfid, &hostDump);
3724 dbAddr = hostDump.nameHashChain;
3728 case HT_tapeName_FUNCTION:
3730 struct tape hostTape, diskTape;
3733 cdbread(ut, tape_BLOCK, dbAddr, &diskTape,
3739 "\ntapename hash %d, entry at %u\n",
3742 "----------------------------\n");
3743 tape_ntoh(&diskTape, &hostTape);
3744 printTape(dumpfid, &hostTape);
3745 dbAddr = hostTape.nameHashChain;
3749 case HT_volName_FUNCTION:
3751 struct volInfo hostVolInfo, diskVolInfo;
3754 cdbread(ut, volInfo_BLOCK, dbAddr,
3755 &diskVolInfo, sizeof(diskVolInfo));
3760 "\nvolname hash %d, entry at %u\n",
3763 "----------------------------\n");
3764 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3765 printVolInfo(dumpfid, &hostVolInfo);
3766 dbAddr = hostVolInfo.nameHashChain;
3768 volFragsDump(ut, dumpfid,
3769 hostVolInfo.firstFragment);
3774 fprintf(dumpfid, "unknown type %d\n", type);
3784 code = ubik_EndTrans(ut); /* is this safe if no ut started ? */
3793 volFragsDump(ut, dumpfid, dbAddr)
3794 struct ubik_trans *ut;
3798 struct volFragment hostVolFragment, diskVolFragment;
3803 cdbread(ut, volFragment_BLOCK, dbAddr, &diskVolFragment,
3804 sizeof(diskVolFragment));
3805 if (code) { /* don't be fussy about errors */
3806 fprintf(dumpfid, "volFragsDump: Error reading database\n");
3810 fprintf(dumpfid, "\nvolfragment entry at %u\n", dbAddr);
3811 fprintf(dumpfid, "----------------------------\n");
3812 volFragment_ntoh(&diskVolFragment, &hostVolFragment);
3813 printVolFragment(dumpfid, &hostVolFragment);
3814 dbAddr = hostVolFragment.sameNameChain;
3820 /* utilities - network to host conversion
3821 * currently used for debug only
3824 volFragmentDiskToHost(diskVfPtr, hostVfPtr)
3825 struct volFragment *diskVfPtr, *hostVfPtr;
3827 hostVfPtr->vol = ntohl(diskVfPtr->vol);
3828 hostVfPtr->sameNameChain = ntohl(diskVfPtr->sameNameChain);
3829 hostVfPtr->tape = ntohl(diskVfPtr->tape);
3830 hostVfPtr->sameTapeChain = ntohl(diskVfPtr->sameTapeChain);
3831 hostVfPtr->position = ntohl(diskVfPtr->position);
3832 hostVfPtr->clone = ntohl(diskVfPtr->clone);
3833 hostVfPtr->incTime = ntohl(diskVfPtr->incTime);
3834 hostVfPtr->startByte = ntohl(diskVfPtr->startByte);
3835 hostVfPtr->nBytes = ntohl(diskVfPtr->nBytes);
3836 hostVfPtr->flags = ntohs(diskVfPtr->flags);
3837 hostVfPtr->sequence = ntohs(diskVfPtr->sequence);
3840 volInfoDiskToHost(diskViPtr, hostViPtr)
3841 struct volInfo *diskViPtr, *hostViPtr;
3843 strcpy(hostViPtr->name, diskViPtr->name);
3844 hostViPtr->nameHashChain = ntohl(diskViPtr->nameHashChain);
3845 hostViPtr->id = ntohl(diskViPtr->id);
3846 strcpy(hostViPtr->server, diskViPtr->server);
3847 hostViPtr->partition = ntohl(diskViPtr->partition);
3848 hostViPtr->flags = ntohl(diskViPtr->flags);
3849 hostViPtr->sameNameHead = ntohl(diskViPtr->sameNameHead);
3850 hostViPtr->sameNameChain = ntohl(diskViPtr->sameNameChain);
3851 hostViPtr->firstFragment = ntohl(diskViPtr->firstFragment);
3852 hostViPtr->nFrags = ntohl(diskViPtr->nFrags);
3855 tapeDiskToHost(diskTapePtr, hostTapePtr)
3856 struct tape *diskTapePtr, *hostTapePtr;
3858 strcpy(hostTapePtr->name, diskTapePtr->name);
3859 hostTapePtr->nameHashChain = ntohl(diskTapePtr->nameHashChain);
3860 hostTapePtr->flags = ntohl(diskTapePtr->flags);
3862 /* tape id conversion here */
3863 hostTapePtr->written = ntohl(diskTapePtr->written);
3864 hostTapePtr->nBytes = ntohl(diskTapePtr->nBytes);
3865 hostTapePtr->nFiles = ntohl(diskTapePtr->nFiles);
3866 hostTapePtr->nVolumes = ntohl(diskTapePtr->nVolumes);
3867 hostTapePtr->seq = ntohl(diskTapePtr->seq);
3868 hostTapePtr->dump = ntohl(diskTapePtr->dump);
3869 hostTapePtr->nextTape = ntohl(diskTapePtr->nextTape);
3870 hostTapePtr->firstVol = ntohl(diskTapePtr->firstVol);
3871 hostTapePtr->useCount = ntohl(diskTapePtr->useCount);
3874 dumpDiskToHost(diskDumpPtr, hostDumpPtr)
3875 struct dump *diskDumpPtr, *hostDumpPtr;
3877 hostDumpPtr->id = ntohl(diskDumpPtr->id);
3878 hostDumpPtr->idHashChain = ntohl(diskDumpPtr->idHashChain);
3879 strcpy(hostDumpPtr->dumpName, diskDumpPtr->dumpName);
3880 strcpy(hostDumpPtr->dumpPath, diskDumpPtr->dumpPath);
3881 strcpy(hostDumpPtr->volumeSet, diskDumpPtr->volumeSet);
3882 hostDumpPtr->nameHashChain = ntohl(diskDumpPtr->nameHashChain);
3883 hostDumpPtr->flags = ntohl(diskDumpPtr->flags);
3884 hostDumpPtr->parent = ntohl(diskDumpPtr->parent);
3885 hostDumpPtr->created = ntohl(diskDumpPtr->created);
3886 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3887 hostDumpPtr->nVolumes = ntohl(diskDumpPtr->nVolumes);
3889 /* tapeset conversion here */
3891 hostDumpPtr->firstTape = ntohl(diskDumpPtr->firstTape);
3893 /* principal conversion here */
3899 checkHash(ut, hashType)
3900 struct ubik_trans *ut;
3903 struct memoryHashTable *mhtPtr;
3904 int entrySize, hashTableLength;
3909 mhtPtr = ht_GetType(hashType, &entrySize);
3913 for (old = 0; old < 1; old++) {
3914 LogDebug(5, "\nold = %d\n", old);
3915 printMemoryHashTable(stdout, mhtPtr);
3917 hashTableLength = (old ? mhtPtr->oldLength : mhtPtr->length);
3919 for (bucket = 0; bucket < hashTableLength; bucket++) {
3922 entryAddr = ht_LookupBucket(ut, mhtPtr, bucket, old);
3923 while (entryAddr != 0) {
3924 LogDebug(6, "bucket %d has disk addr %d\n", bucket,
3927 case HT_dumpIden_FUNCTION:
3929 struct dump diskDump, hostDump;
3931 code = dbread(ut, entryAddr, &diskDump, entrySize);
3935 dump_ntoh(&diskDump, &hostDump);
3936 printDump(stdout, &hostDump);
3937 entryAddr = hostDump.idHashChain;
3941 case HT_dumpName_FUNCTION:
3944 case HT_tapeName_FUNCTION:
3947 case HT_volName_FUNCTION:
3949 struct volInfo diskVolInfo, hostVolInfo;
3951 code = dbread(ut, entryAddr, &diskVolInfo, entrySize);
3955 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3956 printVolInfo(stdout, &hostVolInfo);
3957 entryAddr = hostVolInfo.nameHashChain;