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>
40 #include <sys/types.h>
42 #include <afs/bubasics.h>
51 #include <afs/cellconfig.h>
55 #include "budb_errs.h"
57 #include "error_macros.h"
59 #include "afs/audit.h"
60 #include <afs/afsutil.h>
66 extern struct ubik_dbase *BU_dbase;
67 extern struct afsconf_dir *BU_conf; /* for getting cell info */
69 afs_int32 AddVolume(), AddVolumes(), CreateDump(), DoDeleteDump(),
70 DoDeleteTape(), ListDumps();
71 afs_int32 DeleteVDP(), FindClone(), FindDump(), FindLatestDump();
72 afs_int32 FinishDump(), FinishTape(), GetDumps(), getExpiration(),
74 afs_int32 makeAppended(), MakeDumpAppended(), FindLastTape(), GetTapes();
75 afs_int32 GetVolumes(), UseTape(), T_DumpHashTable(), T_GetVersion();
77 /* Text block management */
80 struct memTextBlock *mtb_next; /* next in chain */
81 afs_int32 mtb_nbytes; /* # of bytes in this block */
82 struct blockHeader mtb_blkHeader; /* in memory header */
83 dbadr mtb_addr; /* disk address of block */
86 typedef struct memTextBlock memTextBlockT;
87 typedef memTextBlockT *memTextBlockP;
89 /* These variable are for returning debugging info about the state of the
90 server. If they get trashed during multi-threaded operation it doesn't
93 /* This is global so COUNT_REQ in krb_udp.c can refer to it. */
94 char *lastOperation; /* name of last operation */
95 static Date lastTrans; /* time of last transaction */
97 /* procsInited is sort of a lock: during a transaction only one process runs
98 while procsInited is false. */
100 static int procsInited = 0;
102 /* This variable is protected by the procsInited flag. */
104 static int (*rebuildDatabase) ();
106 /* AwaitInitialization
107 * Wait unitl budb has initialized (InitProcs). If it hasn't
108 * within 5 seconds, then return no quorum.
111 AwaitInitialization()
115 while (!procsInited) {
118 else if (time(0) - start > 5)
126 * name is a pathname style name, determine trailing name and return
131 tailCompPtr(pathNamePtr)
135 ptr = strrchr(pathNamePtr, '/');
137 /* this should never happen */
138 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
140 return (pathNamePtr);
142 ptr++; /* skip the / */
147 * Check to see if the caller is a SuperUser.
155 struct rx_call *call;
158 struct afsconf_dir *acdir;
160 acdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
164 if (afsconf_SuperUser(acdir, call, NULL))
168 afsconf_Close(acdir);
173 * This is called by every RPC interface to create a Ubik transaction
174 * and read the database header into core
180 * sets a lock on byte 1 of the database. Looks like it enforces
181 * single threading by use of the lock.
185 InitRPC(ut, lock, this_op)
186 struct ubik_trans **ut;
187 int lock; /* indicate read/write transaction */
188 int this_op; /* opcode of RCP, for COUNT_ABO */
191 float wait = 0.91; /* start waiting for 1 second */
194 /* wait for server initialization to finish if this is not InitProcs calling */
196 if (code = AwaitInitialization())
199 for (code = UNOQUORUM; code == UNOQUORUM;) {
201 ubik_BeginTrans(BU_dbase,
203 LOCKREAD) ? UBIK_READTRANS : UBIK_WRITETRANS),
205 if (code == UNOQUORUM) { /* no quorum elected */
207 Log("Waiting for quorum election\n");
210 IOMGR_Sleep((int)wait);
216 Log("Have established quorum\n");
218 /* set lock at posiion 1, for 1 byte of type lock */
219 if (code = ubik_SetLock(*ut, 1, 1, lock)) {
220 ubik_AbortTrans(*ut);
224 /* check that dbase is initialized and setup cheader */
225 if (lock == LOCKREAD) {
226 /* init but don't fix because this is read only */
227 if (code = CheckInit(*ut, 0)) {
228 ubik_AbortTrans(*ut);
229 if (code = InitRPC(ut, LOCKWRITE, 0)) { /* Now fix the database */
230 LogError(code, "InitRPC: InitRPC failed\n");
233 if (code = ubik_EndTrans(*ut)) {
234 LogError(code, "InitRPC: ubik_EndTrans failed\n");
237 goto start; /* now redo the read transaction */
240 if (code = CheckInit(*ut, rebuildDatabase)) {
241 ubik_AbortTrans(*ut);
249 /* This is called to initialize a newly created database */
251 initialize_database(ut)
252 struct ubik_trans *ut;
257 static int noAuthenticationRequired; /* global state */
258 static int recheckNoAuth; /* global state */
263 struct ubik_trans *ut;
268 if ((globalConfPtr->myHost == 0) || (BU_conf == 0))
269 ERROR(BUDB_INTERNALERROR);
273 if (globalConfPtr->debugFlags & DF_NOAUTH)
274 noAuthenticationRequired = 1;
276 if (globalConfPtr->debugFlags & DF_RECHECKNOAUTH)
280 noAuthenticationRequired = afsconf_GetNoAuthFlag(BU_conf);
282 if (noAuthenticationRequired)
283 LogError(0, "Running server with security disabled\n");
287 rebuildDatabase = initialize_database;
289 if (code = InitRPC(&ut, LOCKREAD, 0)) {
290 LogError(code, "InitProcs: InitRPC failed\n");
293 code = ubik_EndTrans(ut);
295 LogError(code, "InitProcs: ubik_EndTrans failed\n");
299 rebuildDatabase = 0; /* only do this during init */
307 int nElements; /* number in list */
308 int allocSize; /* number of elements allocated */
309 dbadr *elements; /* array of addresses */
314 struct returnList *list;
318 list->elements = (dbadr *) 0;
323 struct returnList *list;
326 free(list->elements);
327 list->elements = (dbadr *) 0;
331 /* As entries are collected, they are added to a return list. Once all
332 * entries have been collected, it is then placed in the return buffer
333 * with SendReturnList(). The first *to_skipP are not recorded.
336 AddToReturnList(list, a, to_skipP)
337 struct returnList *list;
351 /* Up to 5 plus a maximum so SendReturnList() knows if we
352 * need to come back for more.
354 if (list->nElements >= BUDB_MAX_RETURN_LIST + 5)
355 return BUDB_LIST2BIG;
357 if (list->nElements >= list->allocSize) {
358 if (list->elements == 0) {
360 tmp = (char *)malloc(sizeof(dbadr) * size);
362 size = list->allocSize + 10;
363 tmp = (char *)realloc(list->elements, sizeof(dbadr) * size);
367 list->elements = (dbadr *) tmp;
368 list->allocSize = size;
371 list->elements[list->nElements] = a;
377 FillVolEntry(ut, va, vol)
378 struct ubik_trans *ut;
380 struct budb_volumeEntry *vol;
385 struct volFragment vf;
387 if (dbread(ut, va, &vf, sizeof(vf)))
388 return BUDB_IO; /* The volFrag */
389 if (dbread(ut, ntohl(vf.vol), &vi, sizeof(vi)))
390 return BUDB_IO; /* The volInfo */
391 if (dbread(ut, ntohl(vf.tape), &t, sizeof(t)))
392 return BUDB_IO; /* The tape */
393 if (dbread(ut, ntohl(t.dump), &d, sizeof(d)))
394 return BUDB_IO; /* The dump */
396 strcpy(vol->name, vi.name);
397 strcpy(vol->server, vi.server);
398 strcpy(vol->tape, t.name);
399 vol->tapeSeq = ntohl(t.seq);
400 vol->dump = ntohl(d.id);
401 vol->position = ntohl(vf.position);
402 vol->clone = ntohl(vf.clone);
403 vol->incTime = ntohl(vf.incTime);
404 vol->nBytes = ntohl(vf.nBytes);
405 vol->startByte = ntohl(vf.startByte);
406 vol->flags = (ntohs(vf.flags) & VOLFRAGMENTFLAGS); /* low 16 bits here */
407 vol->flags |= (ntohl(vi.flags) & VOLINFOFLAGS); /* high 16 bits here */
408 vol->seq = ntohs(vf.sequence);
409 vol->id = ntohl(vi.id);
410 vol->partition = ntohl(vi.partition);
416 FillDumpEntry(ut, da, dump)
417 struct ubik_trans *ut;
419 struct budb_dumpEntry *dump;
423 if (dbread(ut, da, &d, sizeof(d)))
425 dump->id = ntohl(d.id);
426 dump->flags = ntohl(d.flags);
427 dump->created = ntohl(d.created);
428 strncpy(dump->name, d.dumpName, sizeof(dump->name));
429 strncpy(dump->dumpPath, d.dumpPath, sizeof(dump->dumpPath));
430 strncpy(dump->volumeSetName, d.volumeSet, sizeof(dump->volumeSetName));
432 dump->parent = ntohl(d.parent);
433 dump->level = ntohl(d.level);
434 dump->nVolumes = ntohl(d.nVolumes);
436 tapeSet_ntoh(&d.tapes, &dump->tapes);
438 if (strlen(d.dumper.name) < sizeof(dump->dumper.name))
439 strcpy(dump->dumper.name, d.dumper.name);
440 if (strlen(d.dumper.instance) < sizeof(dump->dumper.instance))
441 strcpy(dump->dumper.instance, d.dumper.instance);
442 if (strlen(d.dumper.cell) < sizeof(dump->dumper.cell))
443 strcpy(dump->dumper.cell, d.dumper.cell);
445 /* Get the initial dumpid and the appended dump id */
446 dump->initialDumpID = ntohl(d.initialDumpID);
447 if (d.appendedDumpChain) {
448 if (dbread(ut, ntohl(d.appendedDumpChain), &ad, sizeof(ad)))
450 dump->appendedDumpID = ntohl(ad.id);
452 dump->appendedDumpID = 0;
454 /* printf("dump name %s, parent %d, level %d\n",
455 * d.dumpName, ntohl(d.parent), ntohl(d.level)); */
461 FillTapeEntry(ut, ta, tape)
462 struct ubik_trans *ut;
464 struct budb_tapeEntry *tape;
470 if (dbread(ut, ta, &t, sizeof(t)))
473 /* Get the tape's expiration date */
474 if (code = getExpiration(ut, &t))
477 strcpy(tape->name, t.name);
478 tape->flags = ntohl(t.flags);
479 tape->written = ntohl(t.written);
480 tape->expires = ntohl(t.expires);
481 tape->nMBytes = ntohl(t.nMBytes);
482 tape->nBytes = ntohl(t.nBytes);
483 tape->nFiles = ntohl(t.nFiles);
484 tape->nVolumes = ntohl(t.nVolumes);
485 tape->seq = ntohl(t.seq);
486 tape->labelpos = ntohl(t.labelpos);
487 tape->useCount = ntohl(t.useCount);
488 tape->useKBytes = ntohl(t.useKBytes);
490 if (dbread(ut, ntohl(t.dump), &d, sizeof(d)))
492 tape->dump = ntohl(d.id);
496 #define returnList_t budb_dumpList *
499 * A list of elements of size e_size is in list, collected
500 * with AddToReturnList(). We will move this to a correspoding
501 * return list, eList, via FillProc(). nextInodeP tells us
502 * if there are more and how many to skip on the next request.
505 SendReturnList(ut, list, FillProc, e_size, index, nextIndexP, dbTimeP, eList)
506 struct ubik_trans *ut;
507 struct returnList *list; /* list of elements to return */
508 afs_int32(*FillProc) (); /* proc to fill entry */
509 int e_size; /* size of each element */
510 afs_int32 index; /* index from previous call */
511 afs_int32 *nextIndexP; /* if more elements are available */
512 afs_int32 *dbTimeP; /* time of last db update */
513 budb_dumpList *eList; /* rxgen list structure (e.g.) */
521 *dbTimeP = ntohl(db.h.lastUpdate);
523 /* Calculate how many to return. Don't let if go over
524 * BUDB_MAX_RETURN_LIST nor the size of our return list.
526 to_return = list->nElements;
527 if (to_return > BUDB_MAX_RETURN_LIST)
528 to_return = BUDB_MAX_RETURN_LIST;
529 if (eList->budb_dumpList_len && (to_return > eList->budb_dumpList_len))
530 to_return = eList->budb_dumpList_len;
532 /* Allocate space for the return values if needed and zero it */
533 if (eList->budb_dumpList_val == 0) {
534 eList->budb_dumpList_val =
535 (struct budb_dumpEntry *)malloc(e_size * to_return);
536 if (!eList->budb_dumpList_val)
539 memset(eList->budb_dumpList_val, 0, e_size * to_return);
540 eList->budb_dumpList_len = to_return;
542 e = (char *)(eList->budb_dumpList_val);
543 for (i = 0; i < to_return; i++, e += e_size) {
544 code = (*FillProc) (ut, list->elements[i], e);
549 if (list->nElements > i)
550 *nextIndexP = index + i;
554 /* Come here to delete a volInfo structure. */
557 DeleteVolInfo(ut, via, vi)
558 struct ubik_trans *ut;
566 if (vi->firstFragment)
567 return 0; /* still some frags, don't free yet */
568 if (vi->sameNameHead == 0) { /* this is the head */
569 if (vi->sameNameChain)
570 return 0; /* empty head, some non-heads left */
572 code = ht_HashOut(ut, &db.volName, via, vi);
575 code = FreeStructure(ut, volInfo_BLOCK, via);
578 hvia = ntohl(vi->sameNameHead);
579 if (dbread(ut, hvia, &hvi, sizeof(hvi)))
582 RemoveFromList(ut, hvia, &hvi, &hvi.sameNameChain, via, vi,
585 return BUDB_DATABASEINCONSISTENT;
587 code = FreeStructure(ut, volInfo_BLOCK, via);
591 /* Detach a volume fragment from its volInfo structure. Its tape chain is
592 already freed. This routine frees the structure and the caller must not
596 DeleteVolFragment(ut, va, v)
597 struct ubik_trans *ut;
599 struct volFragment *v;
606 if (dbread(ut, via, &vi, sizeof(vi)))
609 RemoveFromList(ut, via, &vi, &vi.firstFragment, va, v,
612 return BUDB_DATABASEINCONSISTENT;
615 if (vi.firstFragment == 0)
616 if (code = DeleteVolInfo(ut, via, &vi))
618 if (code = FreeStructure(ut, volFragment_BLOCK, va))
621 /* decrement frag counter */
623 set_word_addr(ut, via, &vi, &vi.nFrags, htonl(ntohl(vi.nFrags) - 1));
629 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
630 * The caller will remove it from the hash table if necessary. The caller is
631 * also responsible for writing the tape out if necessary. */
634 DeleteTape(ut, ta, t)
635 struct ubik_trans *ut;
645 return BUDB_DATABASEINCONSISTENT;
646 if (dbread(ut, da, &d, sizeof(d)))
648 if (d.firstTape == 0)
649 return BUDB_DATABASEINCONSISTENT;
651 code = RemoveFromList(ut, da, &d, &d.firstTape, ta, t, &t->nextTape);
653 return BUDB_DATABASEINCONSISTENT;
657 /* Since the tape should have been truncated there should never be any
658 * volumes in the tape. */
659 if (t->firstVol || t->nVolumes)
660 return BUDB_DATABASEINCONSISTENT;
666 DeleteDump(ut, da, d)
667 struct ubik_trans *ut;
673 code = ht_HashOut(ut, &db.dumpIden, da, d);
677 code = ht_HashOut(ut, &db.dumpName, da, d);
681 /* Since the tape should have been truncated this should never happen. */
682 if (d->firstTape || d->nVolumes)
683 ERROR(BUDB_DATABASEINCONSISTENT);
685 code = FreeStructure(ut, dump_BLOCK, da);
696 * This is called with a volumeEntry and a volInfo structure and compares
697 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
698 * search volInfo structures once it has the head volInfo structure from the
699 * volName hash table.
701 * When called from GetVolInfo the name compare is redundant.
702 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
706 VolInfoMatch(vol, vi)
707 struct budb_volumeEntry *vol;
710 return ((strcmp(vol->name, vi->name) == 0) && /* same volume name */
711 (vol->id == ntohl(vi->id)) && /* same volume id */
712 ((vol->flags & VOLINFOFLAGS) == (ntohl(vi->flags) & VOLINFOFLAGS)) && /* same flags */
713 (vol->partition == ntohl(vi->partition)) && /* same partition (N/A) */
714 (strcmp(vol->server, vi->server) == 0)); /* same server (N/A) */
719 * This routine takes a volumeEntry structure from an RPC interface and
720 * returns the corresponding volInfo structure, creating it if necessary.
722 * The caller must write the entry out.
726 GetVolInfo(ut, volP, viaP, viP)
727 struct ubik_trans *ut;
728 struct budb_volumeEntry *volP;
734 afs_int32 eval, code = 0;
736 eval = ht_LookupEntry(ut, &db.volName, volP->name, &via, viP);
741 /* allocate a new volinfo structure */
742 eval = AllocStructure(ut, volInfo_BLOCK, 0, &via, viP);
746 strcpy(viP->name, volP->name);
747 strcpy(viP->server, volP->server);
748 viP->sameNameHead = 0; /* The head of same name chain */
749 viP->sameNameChain = 0; /* Same name chain is empty */
750 viP->firstFragment = 0;
752 viP->id = htonl(volP->id);
753 viP->partition = htonl(volP->partition);
754 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
756 /* Chain onto volname hash table */
757 eval = ht_HashIn(ut, &db.volName, via, viP);
761 LogDebug(4, "volume Info for %s placed at %d\n", db.volName, via);
764 else if (!VolInfoMatch(volP, viP)) { /* Not the head volinfo struct */
765 hvia = via; /* remember the head volinfo struct */
766 memcpy(&hvi, viP, sizeof(hvi));
768 /* Search the same name chain for the correct volinfo structure */
769 for (via = ntohl(viP->sameNameChain); via;
770 via = ntohl(viP->sameNameChain)) {
771 eval = dbread(ut, via, viP, sizeof(*viP));
775 if (VolInfoMatch(volP, viP))
776 break; /* found the one */
779 /* if the correct volinfo struct isn't found, create one */
781 eval = AllocStructure(ut, volInfo_BLOCK, 0, &via, viP);
785 strcpy(viP->name, volP->name);
786 strcpy(viP->server, volP->server);
787 viP->nameHashChain = 0; /* not in hash table */
788 viP->sameNameHead = htonl(hvia); /* chain to head of sameNameChain */
789 viP->sameNameChain = hvi.sameNameChain;
790 viP->firstFragment = 0;
792 viP->id = htonl(volP->id);
793 viP->partition = htonl(volP->partition);
794 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
796 /* write the head entry's sameNameChain link */
798 set_word_addr(ut, hvia, &hvi, &hvi.sameNameChain, htonl(via));
810 /* deletesomevolumesfromtape
811 * Deletes a specified number of volumes from a tape. The tape
812 * and dump are modified to reflect the smaller number of volumes.
813 * The transaction is not terminated, it is up to the caller to
814 * finish the transaction and start a new one (if desired).
816 * maxvolumestodelete - don't delete more than this many volumes
820 deleteSomeVolumesFromTape(ut, tapeAddr, tapePtr, maxVolumesToDelete)
821 struct ubik_trans *ut;
823 struct tape *tapePtr;
824 int maxVolumesToDelete;
826 dbadr volFragAddr, nextVolFragAddr, dumpAddr;
827 struct volFragment volFrag;
829 int volumesDeleted = 0;
830 afs_int32 eval, code = 0;
835 for (volFragAddr = ntohl(tapePtr->firstVol);
836 (volFragAddr && (maxVolumesToDelete > 0));
837 volFragAddr = nextVolFragAddr) {
838 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
842 nextVolFragAddr = ntohl(volFrag.sameTapeChain);
844 eval = DeleteVolFragment(ut, volFragAddr, &volFrag);
848 maxVolumesToDelete--;
852 /* reset the volume fragment pointer in the tape */
853 tapePtr->firstVol = htonl(volFragAddr);
855 /* diminish the tape's volume count */
856 tapePtr->nVolumes = htonl(ntohl(tapePtr->nVolumes) - volumesDeleted);
858 eval = dbwrite(ut, tapeAddr, tapePtr, sizeof(*tapePtr));
862 /* diminish the dump's volume count */
863 dumpAddr = ntohl(tapePtr->dump);
864 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
868 dump.nVolumes = htonl(ntohl(dump.nVolumes) - volumesDeleted);
869 eval = dbwrite(ut, dumpAddr, &dump, sizeof(dump));
878 * deletes a dump in stages, by repeatedly deleting a small number of
879 * volumes from the dump until none are left. The dump is then deleted.
881 * In the case where multiple calls are made to delete the same
882 * dump, the operation will succeed but contention for structures
883 * will result in someone getting back an error.
886 * id - id of dump to delete
890 deleteDump(call, id, dumps)
891 struct rx_call *call;
893 budb_dumpsList *dumps;
895 struct ubik_trans *ut;
896 dbadr dumpAddr, tapeAddr, appendedDump;
900 afs_int32 eval, code = 0;
903 /* iterate until the dump is truly deleted */
909 eval = InitRPC(&ut, LOCKWRITE, 1);
911 ERROR(eval); /* can't start transaction */
914 ht_LookupEntry(ut, &db.dumpIden, &dumpid, &dumpAddr, &dump);
918 ABORT(BUDB_NOENT); /* can't find dump */
920 if ((dumpid == id) && (dump.initialDumpID)) /* can't be an appended dump */
921 ABORT(BUDB_NOTINITIALDUMP);
923 tapeAddr = ntohl(dump.firstTape);
927 /* there is a tape to delete */
928 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
932 if (ntohl(tape.nVolumes)) {
933 /* tape is not empty */
934 eval = deleteSomeVolumesFromTape(ut, tapeAddr, &tape, 10);
939 if (ntohl(tape.nVolumes) == 0) {
940 /* tape is now empty, delete it */
941 eval = DeleteTape(ut, tapeAddr, &tape);
944 eval = ht_HashOut(ut, &db.tapeName, tapeAddr, &tape);
947 eval = FreeStructure(ut, tape_BLOCK, tapeAddr);
952 eval = ubik_EndTrans(ut);
956 } /* next deletion portion */
958 /* Record the dump just deleted */
959 if (dumps && (dumps->budb_dumpsList_len < BUDB_MAX_RETURN_LIST)) {
960 if (dumps->budb_dumpsList_len == 0)
961 dumps->budb_dumpsList_val =
962 (afs_int32 *) malloc(sizeof(afs_int32));
964 dumps->budb_dumpsList_val =
965 (afs_int32 *) realloc(dumps->budb_dumpsList_val,
966 (dumps->budb_dumpsList_len +
967 1) * sizeof(afs_int32));
969 if (!dumps->budb_dumpsList_val)
972 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = dumpid;
973 dumps->budb_dumpsList_len++;
976 appendedDump = ntohl(dump.appendedDumpChain);
978 /* finally done. No more tapes left in the dump. Delete the dump itself */
979 eval = DeleteDump(ut, dumpAddr, &dump);
983 /* Now delete the appended dump too */
985 eval = dbread(ut, appendedDump, &dump, sizeof(dump));
989 dumpid = ntohl(dump.id);
993 eval = ubik_EndTrans(ut);
997 Log("Delete dump %s (DumpID %u), path %s\n", dump.dumpName,
998 ntohl(dump.id), dump.dumpPath);
1002 if (code && partialDel) {
1003 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
1004 dump.dumpName, ntohl(dump.id), dump.dumpPath, code);
1009 ubik_AbortTrans(ut);
1014 * dump selection routines - used by BUDB_GetDumps
1018 /* most recent dump selection */
1021 struct chosenDump *next;
1026 struct wantDumpRock {
1027 int maxDumps; /* max wanted */
1028 int ndumps; /* actual in chain */
1029 struct chosenDump *chain;
1034 wantDump(dumpAddrParam, dumpParam, dumpListPtrParam)
1035 char *dumpAddrParam;
1037 char *dumpListPtrParam;
1040 struct dump *dumpPtr;
1041 struct wantDumpRock *rockPtr;
1043 dumpAddr = (dbadr) dumpAddrParam;
1044 dumpPtr = (struct dump *)dumpParam;
1045 rockPtr = (struct wantDumpRock *)dumpListPtrParam;
1047 /* if we don't have our full complement, just add another */
1048 if (rockPtr->ndumps < rockPtr->maxDumps)
1051 /* got the number we need, select based on date */
1052 if ((afs_uint32) ntohl(dumpPtr->created) > rockPtr->chain->date)
1059 rememberDump(dumpAddrParam, dumpParam, dumpListPtrParam)
1060 char *dumpAddrParam;
1062 char *dumpListPtrParam;
1065 struct dump *dumpPtr;
1066 struct wantDumpRock *rockPtr;
1067 struct chosenDump *ptr, *deletedPtr, **nextPtr;
1069 dumpAddr = (dbadr) dumpAddrParam;
1070 dumpPtr = (struct dump *)dumpParam;
1071 rockPtr = (struct wantDumpRock *)dumpListPtrParam;
1073 ptr = (struct chosenDump *)malloc(sizeof(*ptr));
1076 memset(ptr, 0, sizeof(*ptr));
1077 ptr->addr = dumpAddr;
1078 ptr->date = (afs_uint32) ntohl(dumpPtr->created);
1080 /* Don't overflow the max */
1081 while (rockPtr->ndumps >= rockPtr->maxDumps) {
1082 /* have to drop one */
1083 deletedPtr = rockPtr->chain;
1084 rockPtr->chain = deletedPtr->next;
1089 /* now insert in the right place */
1090 for (nextPtr = &rockPtr->chain; *nextPtr; nextPtr = &((*nextPtr)->next)) {
1091 if (ptr->date < (*nextPtr)->date)
1094 ptr->next = *nextPtr;
1102 /* ---------------------------------------------
1103 * general interface routines - alphabetic
1104 * ---------------------------------------------
1108 SBUDB_AddVolume(call, vol)
1109 struct rx_call *call;
1110 struct budb_volumeEntry *vol;
1114 code = AddVolume(call, vol);
1115 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, (vol ? vol->id : 0),
1121 AddVolume(call, vol)
1122 struct rx_call *call;
1123 struct budb_volumeEntry *vol;
1125 struct ubik_trans *ut;
1126 dbadr da, ta, via, va;
1130 struct volFragment v;
1132 afs_int32 eval, code = 0;
1134 if (!callPermitted(call))
1135 return BUDB_NOTPERMITTED;
1137 if ((strlen(vol->name) >= sizeof(vi.name))
1138 || (strlen(vol->server) >= sizeof(vi.server))
1139 || (strlen(vol->tape) >= sizeof(t.name)))
1140 return BUDB_BADARGUMENT;
1142 eval = InitRPC(&ut, LOCKWRITE, 1);
1146 /* Find the dump in dumpid hash table */
1147 eval = ht_LookupEntry(ut, &db.dumpIden, &vol->dump, &da, &d);
1151 ABORT(BUDB_NODUMPID);
1153 /* search for the right tape in the dump */
1154 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
1155 /* read the tape entry */
1156 eval = dbread(ut, ta, &t, sizeof(t));
1160 /* Check if the right tape name */
1161 if (strcmp(t.name, vol->tape) == 0)
1165 ABORT(BUDB_NOTAPENAME);
1167 if ((t.dump != htonl(da)) || /* tape must belong to dump */
1168 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1169 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)) /* dump must be in progress */
1170 ABORT(BUDB_BADPROTOCOL);
1172 /* find or create a volume info structure */
1173 eval = GetVolInfo(ut, vol, &via, &vi);
1177 /* Create a volume fragment */
1178 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1182 v.vol = htonl(via); /* vol frag points to vol info */
1183 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1184 vi.firstFragment = htonl(va);
1185 vi.nFrags = htonl(ntohl(vi.nFrags) + 1);
1187 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1191 v.tape = htonl(ta); /* vol frag points to tape */
1192 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1193 t.firstVol = htonl(va);
1194 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1195 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1196 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes / (1024 * 1024));
1197 t.nBytes = htonl(bytes % (1024 * 1024));
1199 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1203 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1205 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1209 v.position = htonl(vol->position); /* vol frag info */
1210 v.clone = htonl(vol->clone);
1211 v.incTime = htonl(vol->incTime);
1212 v.startByte = htonl(vol->startByte);
1213 v.nBytes = htonl(vol->nBytes);
1214 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1215 v.sequence = htons(vol->seq);
1217 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1221 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1225 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1227 code = ubik_EndTrans(ut);
1231 ubik_AbortTrans(ut);
1237 SBUDB_AddVolumes(call, vols)
1238 struct rx_call *call;
1239 struct budb_volumeList *vols;
1243 code = AddVolumes(call, vols);
1244 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, 0, AUD_END);
1249 AddVolumes(call, vols)
1250 struct rx_call *call;
1251 struct budb_volumeList *vols;
1253 struct budb_volumeEntry *vol, *vol1;
1254 struct ubik_trans *ut;
1255 dbadr da, ta, via, va;
1259 struct volFragment v;
1261 afs_int32 eval, e, code = 0;
1263 if (!callPermitted(call))
1264 return BUDB_NOTPERMITTED;
1266 if (!vols || (vols->budb_volumeList_len <= 0)
1267 || !vols->budb_volumeList_val)
1268 return BUDB_BADARGUMENT;
1270 /* The first volume in the list of volumes to add */
1271 vol1 = (struct budb_volumeEntry *)vols->budb_volumeList_val;
1273 eval = InitRPC(&ut, LOCKWRITE, 1);
1277 /* Find the dump in dumpid hash table */
1278 eval = ht_LookupEntry(ut, &db.dumpIden, &vol1->dump, &da, &d);
1282 ABORT(BUDB_NODUMPID);
1284 /* search for the right tape in the dump */
1285 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
1286 /* read the tape entry */
1287 eval = dbread(ut, ta, &t, sizeof(t));
1291 /* Check if the right tape name */
1292 if (strcmp(t.name, vol1->tape) == 0)
1296 ABORT(BUDB_NOTAPENAME);
1298 if ((t.dump != htonl(da)) || /* tape must belong to dump */
1299 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1300 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)) /* dump must be in progress */
1301 ABORT(BUDB_BADPROTOCOL);
1303 for (vol = vol1, e = 0; e < vols->budb_volumeList_len; vol++, e++) {
1305 if ((strlen(vol->name) >= sizeof(vi.name)) || (strcmp(vol->name, "") == 0) || /* no null volnames */
1306 (strlen(vol->server) >= sizeof(vi.server))
1307 || (strlen(vol->tape) >= sizeof(t.name))
1308 || (strcmp(vol->tape, vol1->tape) != 0)) {
1309 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n", vol->name, vol->id, vol->tape, vol->dump);
1313 /* find or create a volume info structure */
1314 eval = GetVolInfo(ut, vol, &via, &vi);
1317 if (*(afs_int32 *) (&vi) == 0) {
1318 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n", vol->name, vol->tape, vol->dump);
1319 ABORT(BUDB_BADARGUMENT);
1322 /* Create a volume fragment */
1323 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1327 v.vol = htonl(via); /* vol frag points to vol info */
1328 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1329 vi.firstFragment = htonl(va);
1330 vi.nFrags = htonl(ntohl(vi.nFrags) + 1);
1331 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1335 v.tape = htonl(ta); /* vol frag points to tape */
1336 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1337 t.firstVol = htonl(va);
1338 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1339 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1340 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes / (1024 * 1024));
1341 t.nBytes = htonl(bytes % (1024 * 1024));
1343 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1345 v.position = htonl(vol->position); /* vol frag info */
1346 v.clone = htonl(vol->clone);
1347 v.incTime = htonl(vol->incTime);
1348 v.startByte = htonl(vol->startByte);
1349 v.nBytes = htonl(vol->nBytes);
1350 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1351 v.sequence = htons(vol->seq);
1353 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1357 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1360 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1364 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1368 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1372 code = ubik_EndTrans(ut);
1376 ubik_AbortTrans(ut);
1382 * records the existence of a dump in the database. This creates only
1383 * the dump record, to which one must attach tape and volume records.
1385 * 1) record the volume set
1389 SBUDB_CreateDump(call, dump)
1390 struct rx_call *call;
1391 struct budb_dumpEntry *dump;
1395 code = CreateDump(call, dump);
1396 osi_auditU(call, BUDB_CrDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
1398 if (dump && !code) {
1399 Log("Create dump %s (DumpID %u), path %s\n", dump->name, dump->id,
1406 CreateDump(call, dump)
1407 struct rx_call *call;
1408 struct budb_dumpEntry *dump;
1410 struct ubik_trans *ut;
1411 dbadr findDumpAddr, da;
1412 struct dump findDump, d;
1413 afs_int32 eval, code = 0;
1417 Date expiration; /* checked by Security Module */
1418 struct ktc_principal principal;
1420 if (!callPermitted(call))
1421 return BUDB_NOTPERMITTED;
1423 if (strlen(dump->name) >= sizeof(d.dumpName))
1424 return BUDB_BADARGUMENT;
1426 eval = InitRPC(&ut, LOCKWRITE, 1);
1431 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration,
1432 principal.name, principal.instance,
1433 principal.cell, &kvno);
1436 if (eval != RXKADNOAUTH)
1439 strcpy(principal.name, "");
1440 strcpy(principal.instance, "");
1441 strcpy(principal.cell, "");
1444 /* authenticated. Take user supplied principal information */
1445 if (strcmp(dump->dumper.name, "") != 0)
1446 strncpy(principal.name, dump->dumper.name,
1447 sizeof(principal.name));
1449 if (strcmp(dump->dumper.instance, "") != 0)
1450 strncpy(principal.instance, dump->dumper.instance,
1451 sizeof(principal.instance));
1453 if (strcmp(dump->dumper.cell, "") != 0)
1454 strncpy(principal.cell, dump->dumper.cell,
1455 sizeof(principal.cell));
1458 /* dump id's are time stamps */
1460 while (1) { /* allocate a unique dump id *//*w */
1463 /* ensure it is unique - seach for dumpid in hash table */
1465 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1470 if (!findDumpAddr) { /* dumpid not in use */
1471 /* update the last dump id allocated */
1472 eval = set_header_word(ut, lastDumpId, htonl(dump->id));
1478 /* dump id is in use - wait a while */
1482 /* dump id supplied (e.g. for database restore) */
1484 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1489 /* Dump id must not already exist */
1491 ABORT(BUDB_DUMPIDEXISTS);
1494 /* Allocate a dump structure */
1495 memset(&d, 0, sizeof(d));
1496 eval = AllocStructure(ut, dump_BLOCK, 0, &da, &d);
1500 strcpy(d.dumpName, dump->name); /* volset.dumpname */
1501 strcpy(d.dumpPath, dump->dumpPath); /* dump node path */
1502 strcpy(d.volumeSet, dump->volumeSetName); /* volume set */
1503 d.id = htonl(dump->id);
1504 d.parent = htonl(dump->parent); /* parent id */
1505 d.level = htonl(dump->level);
1507 LogDebug(4, "dump name %s, parent %d level %d\n", dump->name,
1508 dump->parent, dump->level);
1510 /* if creation time specified, use that. Else use the dumpid time */
1511 if (dump->created == 0)
1512 dump->created = dump->id;
1513 d.created = htonl(dump->created);
1515 principal_hton(&principal, &d.dumper);
1516 tapeSet_hton(&dump->tapes, &d.tapes);
1518 d.flags = htonl(dump->flags | BUDB_DUMP_INPROGRESS);
1520 eval = ht_HashIn(ut, &db.dumpName, da, &d); /* Into dump name hash table */
1524 eval = ht_HashIn(ut, &db.dumpIden, da, &d); /* Into dumpid hash table */
1528 eval = dbwrite(ut, da, (char *)&d, sizeof(d)); /* Write the dump structure */
1532 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1536 /* If to append this dump, then append it - will write the appended dump */
1537 eval = makeAppended(ut, dump->id, dump->initialDumpID, dump->tapes.b);
1541 code = ubik_EndTrans(ut);
1542 LogDebug(5, "made dump %s, path %s\n", d.dumpName, d.dumpPath);
1546 ubik_AbortTrans(ut);
1551 SBUDB_DeleteDump(call, id, fromTime, toTime, dumps)
1552 struct rx_call *call;
1556 budb_dumpsList *dumps;
1560 code = DoDeleteDump(call, id, fromTime, toTime, dumps);
1561 osi_auditU(call, BUDB_DelDmpEvent, code, AUD_DATE, id, AUD_END);
1568 DoDeleteDump(call, id, fromTime, toTime, dumps)
1569 struct rx_call *call;
1573 budb_dumpsList *dumps;
1577 if (!callPermitted(call))
1578 return BUDB_NOTPERMITTED;
1581 code = deleteDump(call, id, dumps);
1586 SBUDB_ListDumps(call, sflags, name, groupid, fromTime, toTime, dumps, flags)
1587 struct rx_call *call;
1588 afs_int32 sflags, groupid;
1590 Date fromTime, toTime;
1591 budb_dumpsList *dumps, *flags;
1595 code = ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags);
1596 osi_auditU(call, BUDB_LstDmpEvent, code, AUD_LONG, flags, AUD_END);
1601 ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags)
1602 struct rx_call *call;
1603 afs_int32 sflags, groupid;
1604 Date fromTime, toTime;
1605 budb_dumpsList *dumps, *flags;
1607 struct ubik_trans *ut;
1608 struct memoryHashTable *mht;
1609 struct dump diskDump, appDiskDump;
1610 dbadr dbAddr, dbAppAddr;
1612 afs_int32 eval, code = 0;
1613 int old, hash, length, entrySize, count = 0;
1615 if (!callPermitted(call))
1616 return BUDB_NOTPERMITTED;
1618 eval = InitRPC(&ut, LOCKREAD, 1);
1622 /* Search the database */
1623 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
1625 return (BUDB_BADARGUMENT);
1627 for (old = 0; old <= 1; old++) { /*o *//* old and new hash tables */
1628 length = (old ? mht->oldLength : mht->length);
1632 for (hash = 0; hash < length; hash++) { /*h *//* for each hash bucket */
1633 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) { /*d */
1635 /* read the entry */
1636 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
1640 /* Skip appended dumps */
1641 if (ntohl(diskDump.initialDumpID) != 0) {
1645 /* Skip dumps with different goup id */
1646 if ((sflags & BUDB_OP_GROUPID)
1647 && (ntohl(diskDump.tapes.id) != groupid)) {
1651 /* Look at this dump to see if it meets the criteria for listing */
1652 if (sflags & BUDB_OP_DATES) {
1653 /* This and each appended dump should be in time */
1654 for (dbAppAddr = dbAddr; dbAppAddr;
1655 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1657 dbread(ut, dbAppAddr, &appDiskDump,
1658 sizeof(appDiskDump));
1662 if ((ntohl(appDiskDump.id) < fromTime)
1663 || (ntohl(appDiskDump.id) > toTime))
1670 /* Add it and each of its appended dump to our list to return */
1671 for (dbAppAddr = dbAddr; dbAppAddr;
1672 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1674 dbread(ut, dbAppAddr, &appDiskDump,
1675 sizeof(appDiskDump));
1679 /* Make sure we have space to list it */
1680 if (dumps->budb_dumpsList_len >= count) {
1683 dumps->budb_dumpsList_val =
1684 (afs_int32 *) malloc(count *
1686 flags->budb_dumpsList_val =
1687 (afs_int32 *) malloc(count *
1690 dumps->budb_dumpsList_val =
1691 (afs_int32 *) realloc(dumps->
1695 flags->budb_dumpsList_val =
1696 (afs_int32 *) realloc(flags->
1701 if (!dumps->budb_dumpsList_val
1702 || !dumps->budb_dumpsList_val)
1706 /* Add it to our list */
1707 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] =
1708 ntohl(appDiskDump.id);
1709 flags->budb_dumpsList_val[flags->budb_dumpsList_len] = 0;
1710 if (ntohl(appDiskDump.initialDumpID) != 0) {
1711 flags->budb_dumpsList_val[flags->
1712 budb_dumpsList_len] |=
1715 if (strcmp(appDiskDump.dumpName, DUMP_TAPE_NAME) == 0) {
1716 flags->budb_dumpsList_val[flags->
1717 budb_dumpsList_len] |=
1720 dumps->budb_dumpsList_len++;
1721 flags->budb_dumpsList_len++;
1727 code = ubik_EndTrans(ut);
1731 ubik_AbortTrans(ut);
1736 SBUDB_DeleteTape(call, tape)
1737 struct rx_call *call;
1738 struct budb_tapeEntry *tape; /* tape info */
1742 code = DoDeleteTape(call, tape);
1743 osi_auditU(call, BUDB_DelTpeEvent, code, AUD_DATE,
1744 (tape ? tape->dump : 0), AUD_END);
1749 DoDeleteTape(call, tape)
1750 struct rx_call *call;
1751 struct budb_tapeEntry *tape; /* tape info */
1753 struct ubik_trans *ut;
1756 afs_int32 eval, code;
1758 if (!callPermitted(call))
1759 return BUDB_NOTPERMITTED;
1761 eval = InitRPC(&ut, LOCKWRITE, 1);
1765 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
1769 eval = DeleteTape(ut, a, &t);
1773 eval = FreeStructure(ut, tape_BLOCK, a);
1777 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1781 code = ubik_EndTrans(ut);
1785 ubik_AbortTrans(ut);
1790 * Deletes old information from the database for a particular dump path
1791 * and volumset. This supercedes the old policy implemented in
1792 * UseTape, which simply matched on the volumeset.dump. Consequently
1793 * it was unable to handle name re-use.
1795 * dsname - dumpset name, i.e. volumeset.dumpname
1796 * dumpPath - full path of dump node
1797 * curDumpID - current dump in progress - so that is may be excluded
1800 * n - some error. May or may not have deleted information.
1804 SBUDB_DeleteVDP(call, dsname, dumpPath, curDumpId)
1805 struct rx_call *call;
1808 afs_int32 curDumpId;
1812 code = DeleteVDP(call, dsname, dumpPath, curDumpId);
1813 osi_auditU(call, BUDB_DelVDPEvent, code, AUD_STR, dsname, AUD_END);
1818 DeleteVDP(call, dsname, dumpPath, curDumpId)
1819 struct rx_call *call;
1822 afs_int32 curDumpId;
1827 struct ubik_trans *ut;
1828 afs_int32 eval, code = 0;
1830 if (!callPermitted(call))
1831 return BUDB_NOTPERMITTED;
1834 eval = InitRPC(&ut, LOCKREAD, 1);
1838 eval = ht_LookupEntry(ut, &db.dumpName, dsname, &dumpAddr, &dump);
1842 while (dumpAddr != 0) { /*wd */
1843 if ((strcmp(dump.dumpName, dsname) == 0)
1844 && (strcmp(dump.dumpPath, dumpPath) == 0)
1845 && (ntohl(dump.id) != curDumpId)) {
1846 eval = ubik_EndTrans(ut);
1850 eval = deleteDump(call, ntohl(dump.id), 0);
1854 /* start the traversal over since the various chains may
1860 dumpAddr = ntohl(dump.nameHashChain);
1862 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
1868 /* check if all the dumps have been examined - can terminate */
1870 eval = ubik_EndTrans(ut);
1876 ubik_AbortTrans(ut);
1882 * Given a volume name, and a dumpID, find the volume in that dump and
1883 * return the clone date of the volume (this is the clone date of the
1884 * volume at the time it was dumped).
1886 * Hashes on the volume name and traverses the fragments. Will need to read
1887 * the volumes tape entry to determine if it belongs to the dump. If the
1888 * volume is not found in the dump, then look for it in its parent dump.
1892 SBUDB_FindClone(call, dumpID, volName, clonetime)
1893 struct rx_call *call;
1896 afs_int32 *clonetime;
1900 code = FindClone(call, dumpID, volName, clonetime);
1901 osi_auditU(call, BUDB_FndClnEvent, code, AUD_STR, volName, AUD_END);
1906 FindClone(call, dumpID, volName, clonetime)
1907 struct rx_call *call;
1910 afs_int32 *clonetime;
1912 struct ubik_trans *ut;
1913 dbadr da, hvia, via, vfa;
1916 struct volFragment vf;
1918 int rvi; /* read the volInfo struct */
1919 afs_int32 eval, code = 0;
1921 if (!callPermitted(call))
1922 return BUDB_NOTPERMITTED;
1924 eval = InitRPC(&ut, LOCKREAD, 1);
1930 /* Search for the volume by name */
1931 eval = ht_LookupEntry(ut, &db.volName, volName, &hvia, &vi);
1935 ABORT(BUDB_NOVOLUMENAME);
1938 /* Follw the dump levels up */
1939 for (; dumpID; dumpID = ntohl(d.parent)) { /*d */
1940 /* Get the dump entry */
1941 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &da, &d);
1945 ABORT(BUDB_NODUMPID);
1947 /* seach all the volInfo entries on the sameNameChain */
1948 for (via = hvia; via; via = ntohl(vi.sameNameChain)) { /*via */
1949 if (rvi) { /* Read the volInfo entry - except first time */
1950 eval = dbread(ut, via, &vi, sizeof(vi));
1956 /* search all the volFrag entries on the volFrag */
1957 for (vfa = ntohl(vi.firstFragment); vfa; vfa = ntohl(vf.sameNameChain)) { /*vfa */
1958 eval = dbread(ut, vfa, &vf, sizeof(vf)); /* Read the volFrag entry */
1962 eval = dbread(ut, ntohl(vf.tape), &t, sizeof(t)); /* Read the tape */
1966 /* Now check to see if this fragment belongs to the dump we have */
1967 if (ntohl(t.dump) == da) {
1968 *clonetime = ntohl(vf.clone); /* return the clone */
1976 code = ubik_EndTrans(ut);
1986 * Searches each tape and each volume in the dump until the volume is found.
1987 * If the volume is not in the dump, then we search it's parent dump.
1989 * Re-write to do lookups by volume name.
1992 FindClone(call, dumpID, volName, clonetime)
1993 struct rx_call *call;
1996 afs_int32 *clonetime;
1998 struct ubik_trans *ut;
1999 dbadr diskAddr, tapeAddr, volFragmentAddr;
2002 struct volFragment volFragment;
2003 struct volInfo volInfo;
2004 afs_int32 eval, code = 0;
2006 if (!callPermitted(call))
2007 return BUDB_NOTPERMITTED;
2009 eval = InitRPC(&ut, LOCKREAD, 1);
2015 for (; dumpID; dumpID = ntohl(dump.parent)) { /*d */
2016 /* Get the dump entry */
2017 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &diskAddr, &dump);
2021 ABORT(BUDB_NODUMPID);
2023 /* just to be sure */
2024 if (ntohl(dump.id) != dumpID) {
2025 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID,
2027 ABORT(BUDB_INTERNALERROR);
2030 /* search all the tapes in this dump */
2031 for (tapeAddr = ntohl(dump.firstTape); tapeAddr; tapeAddr = ntohl(tape.nextTape)) { /*t */
2032 /* Get the tape entry */
2033 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
2037 /* search all the volume fragments on this tape */
2038 for (volFragmentAddr = ntohl(tape.firstVol); volFragmentAddr; volFragmentAddr = ntohl(volFragment.sameTapeChain)) { /*vf */
2039 /* Get the volume fragment entry */
2041 dbread(ut, volFragmentAddr, &volFragment,
2042 sizeof(volFragment));
2046 /* Get the volume info entry */
2048 dbread(ut, ntohl(volFragment.vol), &volInfo,
2053 /* check if this volume is the one we want */
2054 if (strcmp(volInfo.name, volName) == 0) {
2055 *clonetime = ntohl(volFragment.clone);
2063 code = ubik_EndTrans(ut);
2073 * Find latest volume dump before adate.
2074 * Used by restore code when restoring a user requested volume(s)
2076 * volumeName - name of volume to match on
2077 * beforeDate - look for dumps older than this date
2079 * deptr - descriptor of most recent dump
2083 SBUDB_FindDump(call, volumeName, beforeDate, deptr)
2084 struct rx_call *call;
2086 afs_int32 beforeDate;
2087 struct budb_dumpEntry *deptr;
2091 code = FindDump(call, volumeName, beforeDate, deptr);
2092 osi_auditU(call, BUDB_FndDmpEvent, code, AUD_STR, volumeName, AUD_END);
2097 FindDump(call, volumeName, beforeDate, deptr)
2098 struct rx_call *call;
2100 afs_int32 beforeDate;
2101 struct budb_dumpEntry *deptr;
2103 struct ubik_trans *ut;
2104 dbadr volInfoAddr, volFragmentAddr;
2106 struct volInfo volInfo;
2107 struct volFragment volFragment;
2109 dbadr selectedDumpAddr = 0;
2110 afs_int32 selectedDate = 0;
2111 afs_int32 volCloned;
2113 afs_int32 eval, code = 0;
2115 if (!callPermitted(call))
2116 return BUDB_NOTPERMITTED;
2118 eval = InitRPC(&ut, LOCKREAD, 1);
2122 /* Find volinfo struct for volume name in hash table */
2124 ht_LookupEntry(ut, &db.volName, volumeName, &volInfoAddr, &volInfo);
2128 ABORT(BUDB_NOVOLUMENAME);
2130 /* Step through all the volinfo structures on the same name chain.
2131 * No need to read the first - we read it above.
2133 for (rvoli = 0; volInfoAddr;
2134 rvoli = 1, volInfoAddr = ntohl(volInfo.sameNameChain)) {
2135 if (rvoli) { /* read the volinfo structure */
2136 eval = dbread(ut, volInfoAddr, &volInfo, sizeof(volInfo));
2141 /* step through the volfrag structures */
2142 for (volFragmentAddr = ntohl(volInfo.firstFragment); volFragmentAddr;
2143 volFragmentAddr = ntohl(volFragment.sameNameChain)) {
2144 /* read the volfrag struct */
2146 dbread(ut, volFragmentAddr, &volFragment,
2147 sizeof(volFragment));
2151 volCloned = ntohl(volFragment.clone);
2153 /* now we can examine the date for most recent dump */
2154 if ((volCloned > selectedDate) && (volCloned < beforeDate)) {
2155 /* from the volfrag struct, read the tape struct */
2157 dbread(ut, ntohl(volFragment.tape), &tape, sizeof(tape));
2161 selectedDate = volCloned;
2162 selectedDumpAddr = ntohl(tape.dump);
2167 if (!selectedDumpAddr)
2170 eval = FillDumpEntry(ut, selectedDumpAddr, deptr);
2174 code = ubik_EndTrans(ut);
2182 /* BUDB_FindLatestDump
2183 * Find the latest dump of volumeset vsname with dump name dname.
2185 * vsname - volumeset name
2190 SBUDB_FindLatestDump(call, vsname, dumpPath, dumpentry)
2191 struct rx_call *call;
2192 char *vsname, *dumpPath;
2193 struct budb_dumpEntry *dumpentry;
2197 code = FindLatestDump(call, vsname, dumpPath, dumpentry);
2198 osi_auditU(call, BUDB_FndLaDEvent, code, AUD_STR, vsname, AUD_END);
2203 FindLatestDump(call, vsname, dumpPath, dumpentry)
2204 struct rx_call *call;
2205 char *vsname, *dumpPath;
2206 struct budb_dumpEntry *dumpentry;
2208 struct ubik_trans *ut;
2209 dbadr curdbaddr, retdbaddr, firstdbaddr;
2212 char dumpName[BU_MAXNAMELEN + 2];
2213 afs_int32 eval, code = 0;
2215 if (!callPermitted(call))
2216 return BUDB_NOTPERMITTED;
2218 eval = InitRPC(&ut, LOCKREAD, 1);
2222 if ((strcmp(vsname, "") == 0) && (strcmp(dumpPath, "") == 0)) {
2223 /* Construct a database dump name */
2224 strcpy(dumpName, DUMP_TAPE_NAME);
2225 } else if (strchr(dumpPath, '/') == 0) {
2226 int level, old, length, hash;
2227 struct dump hostDump, diskDump;
2228 struct memoryHashTable *mht;
2231 afs_uint32 bestDumpId = 0;
2233 level = atoi(dumpPath);
2235 ABORT(BUDB_BADARGUMENT);
2238 /* Brute force search of all the dumps in the database - yuck! */
2241 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
2243 ABORT(BUDB_BADARGUMENT);
2245 for (old = 0; old <= 1; old++) { /*fo */
2246 length = (old ? mht->oldLength : mht->length);
2250 for (hash = 0; hash < length; hash++) {
2252 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr;
2253 dbAddr = hostDump.idHashChain) {
2255 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
2258 dump_ntoh(&diskDump, &hostDump);
2260 if ((strcmp(hostDump.volumeSet, vsname) == 0) && /* the volumeset */
2261 (hostDump.level == level) && /* same level */
2262 (hostDump.id > bestDumpId)) { /* more recent */
2263 bestDumpId = hostDump.id;
2270 ABORT(BUDB_NODUMPNAME);
2274 /* construct the name of the dump */
2275 if ((strlen(vsname) + strlen(tailCompPtr(dumpPath))) > BU_MAXNAMELEN)
2276 ABORT(BUDB_NODUMPNAME);
2278 strcpy(dumpName, vsname);
2279 strcat(dumpName, ".");
2280 strcat(dumpName, tailCompPtr(dumpPath));
2283 LogDebug(5, "lookup on :%s:\n", dumpName);
2285 /* Lookup on dumpname in hash table */
2286 eval = ht_LookupEntry(ut, &db.dumpName, dumpName, &firstdbaddr, &d);
2293 /* folow remaining dumps in hash chain, looking for most latest dump */
2294 for (curdbaddr = firstdbaddr; curdbaddr;
2295 curdbaddr = ntohl(d.nameHashChain)) {
2296 if (curdbaddr != firstdbaddr) {
2297 eval = dbread(ut, curdbaddr, &d, sizeof(d));
2302 if ((strcmp(d.dumpPath, dumpPath) == 0) && /* Same dumppath */
2303 (strcmp(d.dumpName, dumpName) == 0) && /* Same dumpname */
2304 (ntohl(d.created) > latest)) { /* most recent */
2305 latest = ntohl(d.created);
2306 retdbaddr = curdbaddr;
2310 ABORT(BUDB_NODUMPNAME);
2313 /* return the dump found */
2314 FillDumpEntry(ut, retdbaddr, dumpentry);
2316 code = ubik_EndTrans(ut);
2320 ubik_AbortTrans(ut);
2326 SBUDB_FinishDump(call, dump)
2327 struct rx_call *call;
2328 struct budb_dumpEntry *dump;
2332 code = FinishDump(call, dump);
2333 osi_auditU(call, BUDB_FinDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
2339 FinishDump(call, dump)
2340 struct rx_call *call;
2341 struct budb_dumpEntry *dump;
2343 struct ubik_trans *ut;
2346 afs_int32 eval, code = 0;
2348 if (!callPermitted(call))
2349 return BUDB_NOTPERMITTED;
2351 eval = InitRPC(&ut, LOCKWRITE, 1);
2355 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &a, &d);
2359 ABORT(BUDB_NODUMPID);
2361 if ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)
2362 ABORT(BUDB_DUMPNOTINUSE);
2364 d.flags = htonl(dump->flags & ~BUDB_DUMP_INPROGRESS);
2366 /* if creation time specified set it */
2368 d.created = htonl(dump->created);
2369 dump->created = ntohl(d.created);
2371 /* Write the dump entry out */
2372 eval = dbwrite(ut, a, &d, sizeof(d));
2376 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2380 code = ubik_EndTrans(ut);
2384 ubik_AbortTrans(ut);
2389 SBUDB_FinishTape(call, tape)
2390 struct rx_call *call;
2391 struct budb_tapeEntry *tape;
2395 code = FinishTape(call, tape);
2396 osi_auditU(call, BUDB_FinTpeEvent, code, AUD_DATE,
2397 (tape ? tape->dump : 0), AUD_END);
2402 FinishTape(call, tape)
2403 struct rx_call *call;
2404 struct budb_tapeEntry *tape;
2406 struct ubik_trans *ut;
2410 afs_int32 eval, code = 0;
2412 if (!callPermitted(call))
2413 return BUDB_NOTPERMITTED;
2415 eval = InitRPC(&ut, LOCKWRITE, 1);
2419 /* find the tape struct in the tapename hash chain */
2420 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
2424 ABORT(BUDB_NOTAPENAME);
2426 /* Read the dump structure */
2427 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2431 /* search for the right tape on the rest of the chain */
2432 while (ntohl(d.id) != tape->dump) {
2433 a = ntohl(t.nameHashChain);
2435 ABORT(BUDB_NOTAPENAME);
2437 eval = dbread(ut, a, &t, sizeof(t));
2441 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2446 if ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0)
2447 ABORT(BUDB_TAPENOTINUSE);
2449 /* t.nBytes = htonl(tape->nBytes); */
2450 t.nFiles = htonl(tape->nFiles);
2451 t.useKBytes = htonl(tape->useKBytes);
2452 t.flags = htonl(tape->flags & ~BUDB_TAPE_BEINGWRITTEN);
2454 eval = dbwrite(ut, a, &t, sizeof(t));
2458 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2462 code = ubik_EndTrans(ut);
2466 ubik_AbortTrans(ut);
2471 * return a set of dumps that match the specified criteria
2474 * majorVersion - version of interface structures. Permits compatibility
2476 * flags - for search and select operations. Broken down into flags
2477 * for name, start point, end point and time.
2478 * name - name to search for. Interpretation based on flags
2485 * dbTimeP - time at which the database was last modified. Up to
2486 * caller (client) to take appropriate action if database
2487 * modified between successive calls
2488 * dumps - list of matching dumps
2490 * currently supported are:
2496 SBUDB_GetDumps(call, majorVersion, flags, name, start, end, index, nextIndexP,
2498 struct rx_call *call;
2499 afs_int32 majorVersion; /* version of interface structures */
2500 afs_int32 flags; /* search & select controls */
2501 char *name; /* s&s parameters */
2504 afs_int32 index; /* start index of returned entries */
2505 afs_int32 *nextIndexP; /* output index for next call */
2507 budb_dumpList *dumps; /* pointer to buffer */
2512 GetDumps(call, majorVersion, flags, name, start, end, index,
2513 nextIndexP, dbTimeP, dumps);
2514 osi_auditU(call, BUDB_GetDmpEvent, code, AUD_END);
2519 GetDumps(call, majorVersion, flags, name, start, end, index, nextIndexP,
2521 struct rx_call *call;
2522 afs_int32 majorVersion; /* version of interface structures */
2523 afs_int32 flags; /* search & select controls */
2524 char *name; /* s&s parameters */
2527 afs_int32 index; /* start index of returned entries */
2528 afs_int32 *nextIndexP; /* output index for next call */
2530 budb_dumpList *dumps; /* pointer to buffer */
2532 struct ubik_trans *ut;
2535 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2536 afs_int32 eval, code = 0;
2538 struct returnList list;
2540 /* Don't check permissions when we look up a specific dump id */
2541 if (((flags & BUDB_OP_STARTS) != BUDB_OP_DUMPID) && !callPermitted(call))
2542 return BUDB_NOTPERMITTED;
2544 if (majorVersion != BUDB_MAJORVERSION)
2545 return BUDB_OLDINTERFACE;
2547 return BUDB_ENDOFLIST;
2549 eval = InitRPC(&ut, LOCKREAD, 1);
2553 nameFlags = flags & BUDB_OP_NAMES;
2554 startFlags = flags & BUDB_OP_STARTS;
2555 endFlags = flags & BUDB_OP_ENDS;
2556 timeFlags = flags & BUDB_OP_TIMES;
2558 InitReturnList(&list);
2561 if (nameFlags == BUDB_OP_DUMPNAME) {
2562 /* not yet implemented */
2563 if (startFlags || endFlags || timeFlags)
2564 ABORT(BUDB_BADFLAGS);
2566 eval = ht_LookupEntry(ut, &db.dumpName, name, &da, &d);
2570 ABORT(BUDB_NODUMPNAME);
2573 if (strcmp(d.dumpName, name) == 0) {
2574 eval = AddToReturnList(&list, da, &toskip);
2575 if (eval == BUDB_LIST2BIG)
2581 da = ntohl(d.nameHashChain); /* get next dump w/ name */
2585 eval = dbread(ut, da, &d, sizeof(d));
2589 } else if (nameFlags == BUDB_OP_VOLUMENAME) {
2593 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2594 ABORT(BUDB_BADFLAGS);
2597 if (startFlags != BUDB_OP_STARTTIME)
2598 ABORT(BUDB_BADFLAGS);
2600 /* lookup a dump by volumename and time stamp. Find the most recent
2601 * dump of the specified volumename, that occured before the supplied
2605 /* get us a volInfo for name */
2606 eval = ht_LookupEntry(ut, &db.volName, name, &da, &vi);
2611 /* now iterate over all the entries of this name */
2612 for (va = vi.firstFragment; va != 0; va = v.sameNameChain) {
2614 eval = dbread(ut, va, &v, sizeof(v));
2619 on fragment > date ignore it - too recent;
2621 if (date on fragment < date && date on fragment > bestfound)
2622 bestfound = date on fragment;
2626 da = vi.sameNameChain;
2630 eval = dbread(ut, da, &vi, sizeof(vi));
2639 from saved volfragment address, compute dump.
2640 otherwise, return dump found
2645 } else if (startFlags == BUDB_OP_DUMPID) {
2646 if (endFlags || timeFlags)
2647 ABORT(BUDB_BADFLAGS);
2649 ABORT(BUDB_BADFLAGS); /* NYI */
2651 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
2655 ABORT(BUDB_NODUMPID);
2657 eval = AddToReturnList(&list, da, &toskip);
2660 } else if (endFlags == BUDB_OP_NPREVIOUS) {
2661 struct wantDumpRock rock;
2662 struct chosenDump *ptr, *nextPtr;
2664 extern wantDump(), rememberDump();
2666 /* no other flags should be set */
2668 /* end specifies how many dumps */
2670 ABORT(BUDB_BADFLAGS);
2672 memset(&rock, 0, sizeof(rock));
2673 rock.maxDumps = end;
2675 scanHashTable(ut, &db.dumpName, wantDump, rememberDump,
2678 for (ptr = rock.chain; ptr; ptr = nextPtr) {
2679 nextPtr = ptr->next;
2680 AddToReturnList(&list, ptr->addr, &toskip); /* ignore error for free */
2684 ABORT(BUDB_BADFLAGS);
2688 SendReturnList(ut, &list, FillDumpEntry,
2689 sizeof(struct budb_dumpEntry), index, nextIndexP,
2690 dbTimeP, (returnList_t) dumps);
2694 FreeReturnList(&list);
2695 code = ubik_EndTrans(ut);
2699 FreeReturnList(&list);
2700 ubik_AbortTrans(ut);
2705 * Get the expiration of a tape. Since the dump could have appended dumps,
2706 * we should use the most recent expiration date. Put the most recent
2707 * expiration tape into the given tape structure.
2710 getExpiration(ut, tapePtr)
2711 struct ubik_trans *ut;
2712 struct tape *tapePtr;
2718 afs_int32 eval, code = 0;
2723 /* Get the dump for this tape */
2724 ad = ntohl(tapePtr->dump);
2725 eval = dbread(ut, ad, &d, sizeof(d));
2729 /* If not an initial dump, get the initial dump */
2730 if (d.initialDumpID) {
2731 initDump = ntohl(d.initialDumpID);
2732 eval = ht_LookupEntry(ut, &db.dumpIden, &initDump, &ad, &d);
2737 /* Cycle through the dumps and appended dumps */
2739 /* Get the first tape in this dump. No need to check the rest of the tapes */
2740 /* for this dump since they will all have the same expiration date */
2741 eval = dbread(ut, ntohl(d.firstTape), &t, sizeof(t));
2745 /* Take the greater of the expiration dates */
2746 if (ntohl(tapePtr->expires) < ntohl(t.expires))
2747 tapePtr->expires = t.expires;
2749 /* Step to and read the next appended dump */
2750 if (ad = ntohl(d.appendedDumpChain)) {
2751 eval = dbread(ut, ad, &d, sizeof(d));
2761 /* Mark the following dump as appended to another, intial dump */
2763 makeAppended(ut, appendedDumpID, initialDumpID, startTapeSeq)
2764 struct ubik_trans *ut;
2765 afs_int32 appendedDumpID;
2766 afs_int32 initialDumpID;
2767 afs_int32 startTapeSeq;
2769 dbadr ada, da, lastDumpAddr;
2771 afs_int32 eval, code = 0;
2775 if (appendedDumpID == initialDumpID)
2776 ERROR(BUDB_INTERNALERROR);
2778 /* If there is an initial dump, append this dump to it */
2779 /* Find the appended dump via its id */
2780 eval = ht_LookupEntry(ut, &db.dumpIden, &appendedDumpID, &ada, &ad);
2784 /* If the dump is already marked as appended,
2785 * then we have an internal error.
2787 if (ad.initialDumpID) {
2788 if (ntohl(ad.initialDumpID) != initialDumpID)
2789 ERROR(BUDB_INTERNALERROR);
2792 /* Update the appended dump to point to the initial dump */
2793 ad.initialDumpID = htonl(initialDumpID);
2794 ad.tapes.b = htonl(startTapeSeq);
2796 /* find the initial dump via its id */
2797 eval = ht_LookupEntry(ut, &db.dumpIden, &initialDumpID, &da, &d);
2801 /* Update the appended dump's tape format with that of the initial */
2802 strcpy(ad.tapes.format, d.tapes.format);
2804 /* starting with the initial dump step through its appended dumps till
2805 * we reach the last appended dump.
2808 while (d.appendedDumpChain) {
2809 lastDumpAddr = ntohl(d.appendedDumpChain);
2810 if (lastDumpAddr == ada)
2811 ERROR(0); /* Already appended */
2812 eval = dbread(ut, lastDumpAddr, &d, sizeof(d));
2817 /* Update the last dump to point to our new appended dump.
2818 * The appended dump is the last one in the dump chain.
2820 d.appendedDumpChain = htonl(ada);
2821 ad.appendedDumpChain = 0;
2823 /* Write the appended dump and the initial dump */
2824 eval = dbwrite(ut, ada, (char *)&ad, sizeof(ad));
2828 eval = dbwrite(ut, lastDumpAddr, (char *)&d, sizeof(d));
2832 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2841 SBUDB_MakeDumpAppended(call, appendedDumpID, initialDumpID, startTapeSeq)
2842 struct rx_call *call;
2843 afs_int32 appendedDumpID;
2844 afs_int32 initialDumpID;
2845 afs_int32 startTapeSeq;
2850 MakeDumpAppended(call, appendedDumpID, initialDumpID, startTapeSeq);
2851 osi_auditU(call, BUDB_AppDmpEvent, code, AUD_LONG, appendedDumpID,
2857 MakeDumpAppended(call, appendedDumpID, initialDumpID, startTapeSeq)
2858 struct rx_call *call;
2859 afs_int32 appendedDumpID;
2860 afs_int32 initialDumpID;
2861 afs_int32 startTapeSeq;
2863 struct ubik_trans *ut;
2864 afs_int32 eval, code = 0;
2866 if (!callPermitted(call))
2867 return BUDB_NOTPERMITTED;
2869 eval = InitRPC(&ut, LOCKWRITE, 1);
2873 eval = makeAppended(ut, appendedDumpID, initialDumpID, startTapeSeq);
2877 code = ubik_EndTrans(ut);
2881 ubik_AbortTrans(ut);
2885 /* Find the last tape of a dump-set. This includes any appended dumps */
2887 SBUDB_FindLastTape(call, dumpID, dumpEntry, tapeEntry, volEntry)
2888 struct rx_call *call;
2890 struct budb_dumpEntry *dumpEntry;
2891 struct budb_tapeEntry *tapeEntry;
2892 struct budb_volumeEntry *volEntry;
2896 code = FindLastTape(call, dumpID, dumpEntry, tapeEntry, volEntry);
2897 osi_auditU(call, BUDB_FndLTpeEvent, code, AUD_LONG, dumpID, AUD_END);
2902 FindLastTape(call, dumpID, dumpEntry, tapeEntry, volEntry)
2903 struct rx_call *call;
2905 struct budb_dumpEntry *dumpEntry;
2906 struct budb_tapeEntry *tapeEntry;
2907 struct budb_volumeEntry *volEntry;
2909 struct ubik_trans *ut;
2913 dbadr lastTape, thisTape;
2914 afs_int32 lastTapeSeq;
2915 struct volFragment vf;
2916 dbadr lastVol, thisVol;
2917 afs_int32 lastVolPos;
2918 afs_int32 eval, code = 0;
2920 if (!callPermitted(call))
2921 return BUDB_NOTPERMITTED;
2924 return (BUDB_BADARGUMENT);
2926 eval = InitRPC(&ut, LOCKREAD, 1);
2930 /* find and read its initial dump via its id */
2931 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &lastDump, &d);
2935 ABORT(BUDB_NODUMPID);
2937 /* Follow the append dumps link chain until we reach the last dump */
2938 while (d.appendedDumpChain) {
2939 lastDump = ntohl(d.appendedDumpChain);
2940 eval = dbread(ut, lastDump, &d, sizeof(d));
2945 /* We now have the last dump of the last appended dump */
2946 /* Copy this into our return structure */
2947 eval = FillDumpEntry(ut, lastDump, dumpEntry);
2951 /* Fail if the last dump has no tapes */
2953 ABORT(BUDB_NOTAPENAME);
2955 /* Follow the tapes in this dump until we reach the last tape */
2956 eval = dbread(ut, ntohl(d.firstTape), &t, sizeof(t));
2960 lastTape = ntohl(d.firstTape);
2961 lastTapeSeq = ntohl(t.seq);
2962 lastVol = ntohl(t.firstVol);
2964 while (t.nextTape) {
2965 thisTape = ntohl(t.nextTape);
2966 eval = dbread(ut, thisTape, &t, sizeof(t));
2970 if (ntohl(t.seq) > lastTapeSeq) {
2971 lastTape = thisTape;
2972 lastTapeSeq = ntohl(t.seq);
2973 lastVol = ntohl(t.firstVol);
2977 /* We now have the last tape of the last appended dump */
2978 /* Copy this into our return structure */
2979 eval = FillTapeEntry(ut, lastTape, tapeEntry);
2983 /* Zero volume entry if the last tape has no volumes */
2985 memset(volEntry, 0, sizeof(*volEntry));
2987 /* Follow the volumes until we reach the last volume */
2988 eval = dbread(ut, lastVol, &vf, sizeof(vf));
2992 lastVolPos = vf.position;
2994 while (vf.sameTapeChain) {
2995 thisVol = ntohl(vf.sameTapeChain);
2996 eval = dbread(ut, thisVol, &vf, sizeof(vf));
3000 if (vf.position > lastVolPos) {
3002 lastVolPos = vf.position;
3006 /* We now have the last volume of this tape */
3007 /* Copy this into our return structure */
3008 eval = FillVolEntry(ut, lastVol, volEntry);
3013 eval = ubik_EndTrans(ut);
3019 ubik_AbortTrans(ut);
3025 SBUDB_GetTapes(call, majorVersion, flags, name, start, end, index, nextIndexP,
3027 struct rx_call *call;
3028 afs_int32 majorVersion; /* version of interface structures */
3029 afs_int32 flags; /* search & select controls */
3030 char *name; /* s&s parameters */
3032 afs_int32 end; /* reserved: MBZ */
3033 afs_int32 index; /* start index of returned entries */
3034 afs_int32 *nextIndexP; /* output index for next call */
3036 budb_tapeList *tapes; /* pointer to buffer */
3041 GetTapes(call, majorVersion, flags, name, start, end, index,
3042 nextIndexP, dbTimeP, tapes);
3043 osi_auditU(call, BUDB_GetTpeEvent, code, AUD_END);
3048 GetTapes(call, majorVersion, flags, name, start, end, index, nextIndexP,
3050 struct rx_call *call;
3051 afs_int32 majorVersion; /* version of interface structures */
3052 afs_int32 flags; /* search & select controls */
3053 char *name; /* s&s parameters */
3055 afs_int32 end; /* reserved: MBZ */
3056 afs_int32 index; /* start index of returned entries */
3057 afs_int32 *nextIndexP; /* output index for next call */
3059 budb_tapeList *tapes; /* pointer to buffer */
3061 struct ubik_trans *ut;
3065 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
3066 struct returnList list;
3067 afs_int32 eval, code = 0;
3070 if (!callPermitted(call))
3071 return BUDB_NOTPERMITTED;
3073 if (majorVersion != BUDB_MAJORVERSION)
3074 return BUDB_OLDINTERFACE;
3077 return BUDB_ENDOFLIST;
3079 eval = InitRPC(&ut, LOCKREAD, 1);
3083 nameFlags = flags & BUDB_OP_NAMES;
3084 startFlags = flags & BUDB_OP_STARTS;
3085 endFlags = flags & BUDB_OP_ENDS;
3086 timeFlags = flags & BUDB_OP_TIMES;
3088 InitReturnList(&list);
3091 if (nameFlags == BUDB_OP_TAPENAME) { /*it */
3092 eval = ht_LookupEntry(ut, &db.tapeName, name, &ta, &t);
3096 ABORT(BUDB_NOTAPENAME);
3099 if ((startFlags & ~BUDB_OP_DUMPID) || endFlags || timeFlags)
3100 ABORT(BUDB_BADFLAGS);
3102 /* follow the hash chain to the end */
3104 if (startFlags & BUDB_OP_DUMPID) {
3105 /* read in the dump */
3106 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
3110 /* check if both name and dump id match */
3111 if ((strcmp(name, t.name) == 0) && (ntohl(d.id) == start)) {
3112 eval = AddToReturnList(&list, ta, &toskip);
3113 if (eval && (eval != BUDB_LIST2BIG))
3118 /* Add to return list and continue search */
3119 if (strcmp(name, t.name) == 0) {
3120 eval = AddToReturnList(&list, ta, &toskip);
3121 if (eval == BUDB_LIST2BIG)
3128 ta = ntohl(t.nameHashChain);
3130 dbread(ut, ta, &t, sizeof(t));
3133 else if (nameFlags == BUDB_OP_TAPESEQ) {
3134 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
3138 ABORT(BUDB_NODUMPNAME);
3140 /* search for the right tape */
3141 ta = ntohl(d.firstTape);
3142 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
3143 eval = dbread(ut, ta, &t, sizeof(t));
3147 if (ntohl(t.seq) == end) {
3148 eval = AddToReturnList(&list, ta, &toskip);
3149 if (eval && (eval != BUDB_LIST2BIG))
3155 ABORT(BUDB_BADFLAGS);
3159 SendReturnList(ut, &list, FillTapeEntry,
3160 sizeof(struct budb_tapeEntry), index, nextIndexP,
3161 dbTimeP, (returnList_t) tapes);
3165 FreeReturnList(&list);
3166 code = ubik_EndTrans(ut);
3170 FreeReturnList(&list);
3171 ubik_AbortTrans(ut);
3176 * get a set of volumes according to the specified criteria.
3177 * See BUDB_GetDumps for general information on parameters
3178 * Currently supports:
3179 * 1) volume match - returns volumes based on volume name only.
3180 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
3181 * and start is a dumpid. Returns all volumes of the specified
3182 * name on the selected dumpid.
3186 SBUDB_GetVolumes(call, majorVersion, flags, name, start, end, index,
3187 nextIndexP, dbTimeP, volumes)
3188 struct rx_call *call;
3189 afs_int32 majorVersion; /* version of interface structures */
3190 afs_int32 flags; /* search & select controls */
3191 char *name; /* - parameters for search */
3192 afs_int32 start; /* - usage depends which BUDP_OP_* */
3193 afs_int32 end; /* - bits are set */
3194 afs_int32 index; /* start index of returned entries */
3195 afs_int32 *nextIndexP; /* output index for next call */
3197 budb_volumeList *volumes; /* pointer to buffer */
3202 GetVolumes(call, majorVersion, flags, name, start, end, index,
3203 nextIndexP, dbTimeP, volumes);
3204 osi_auditU(call, BUDB_GetVolEvent, code, AUD_END);
3209 GetVolumes(call, majorVersion, flags, name, start, end, index, nextIndexP,
3211 struct rx_call *call;
3212 afs_int32 majorVersion; /* version of interface structures */
3213 afs_int32 flags; /* search & select controls */
3214 char *name; /* - parameters for search */
3215 afs_int32 start; /* - usage depends which BUDP_OP_* */
3216 afs_int32 end; /* - bits are set */
3217 afs_int32 index; /* start index of returned entries */
3218 afs_int32 *nextIndexP; /* output index for next call */
3220 budb_volumeList *volumes; /* pointer to buffer */
3222 struct ubik_trans *ut;
3225 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
3226 afs_int32 eval, code = 0;
3227 struct returnList vollist;
3230 /* Don't check permissions when we look up a specific volume name */
3231 if (((flags & BUDB_OP_NAMES) != BUDB_OP_VOLUMENAME)
3232 && !callPermitted(call))
3233 return BUDB_NOTPERMITTED;
3235 if (majorVersion != BUDB_MAJORVERSION)
3236 return BUDB_OLDINTERFACE;
3238 return BUDB_ENDOFLIST;
3240 eval = InitRPC(&ut, LOCKREAD, 1);
3244 nameFlags = flags & BUDB_OP_NAMES;
3245 startFlags = flags & BUDB_OP_STARTS;
3246 endFlags = flags & BUDB_OP_ENDS;
3247 timeFlags = flags & BUDB_OP_TIMES;
3249 InitReturnList(&vollist);
3252 /* lookup a the volume (specified by name) in the dump (specified by id) */
3253 if (nameFlags == BUDB_OP_VOLUMENAME) {
3254 /* dumpid permissible, all others off */
3255 if (((startFlags & ~BUDB_OP_DUMPID) != 0) || endFlags || timeFlags)
3256 ABORT(BUDB_BADFLAGS);
3258 /* returns ptr to volinfo of requested name */
3259 eval = ht_LookupEntry(ut, &db.volName, name, &via, &vi);
3263 ABORT(BUDB_NOVOLUMENAME);
3265 /* Iterate over all volume fragments with this name */
3267 struct volFragment v;
3270 /* traverse all the volume fragments for this volume info structure */
3271 for (va = vi.firstFragment; va; va = v.sameNameChain) {
3273 eval = dbread(ut, va, &v, sizeof(v));
3277 if (startFlags & BUDB_OP_DUMPID) {
3281 /* get the dump id for this fragment */
3282 eval = dbread(ut, ntohl(v.tape), &atape, sizeof(atape));
3287 dbread(ut, ntohl(atape.dump), &adump, sizeof(adump));
3291 /* dump id does not match */
3292 if (ntohl(adump.id) != start)
3296 eval = AddToReturnList(&vollist, va, &toskip);
3297 if (eval == BUDB_LIST2BIG)
3302 if (eval == BUDB_LIST2BIG)
3305 via = vi.sameNameChain;
3310 eval = dbread(ut, via, &vi, sizeof(vi));
3314 } else if (((nameFlags == 0) || (nameFlags == BUDB_OP_TAPENAME))
3315 && (startFlags == BUDB_OP_DUMPID)) {
3320 struct volFragment volFrag;
3323 /* lookup all volumes for a specified dump id */
3325 /* no other flags should be set */
3326 if (endFlags || timeFlags)
3327 ABORT(BUDB_BADFLAGS);
3330 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &dumpAddr, &dump);
3334 /* traverse all the tapes */
3335 for (tapeAddr = ntohl(dump.firstTape); tapeAddr; tapeAddr = ntohl(tape.nextTape)) { /*w */
3336 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
3340 if ((nameFlags != BUDB_OP_TAPENAME)
3341 || ((nameFlags == BUDB_OP_TAPENAME)
3342 && (strcmp(tape.name, name) == 0))) {
3343 /* now return all the volumes */
3344 for (volFragAddr = ntohl(tape.firstVol); volFragAddr;
3345 volFragAddr = ntohl(volFrag.sameTapeChain)) {
3346 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
3350 eval = AddToReturnList(&vollist, volFragAddr, &toskip);
3351 if (eval == BUDB_LIST2BIG)
3357 if (eval == BUDB_LIST2BIG)
3361 ABORT(BUDB_BADFLAGS);
3365 SendReturnList(ut, &vollist, FillVolEntry,
3366 sizeof(struct budb_volumeEntry), index, nextIndexP,
3367 dbTimeP, (returnList_t) volumes);
3372 FreeReturnList(&vollist);
3373 code = ubik_EndTrans(ut);
3377 FreeReturnList(&vollist);
3378 ubik_AbortTrans(ut);
3383 SBUDB_UseTape(call, tape, new)
3384 struct rx_call *call;
3385 struct budb_tapeEntry *tape; /* tape info */
3386 afs_int32 *new; /* set if tape is new */
3390 code = UseTape(call, tape, new);
3391 osi_auditU(call, BUDB_UseTpeEvent, code, AUD_DATE,
3392 (tape ? tape->dump : 0), AUD_END);
3397 UseTape(call, tape, new)
3398 struct rx_call *call;
3399 struct budb_tapeEntry *tape; /* tape info */
3400 int *new; /* set if tape is new */
3402 struct ubik_trans *ut;
3406 afs_int32 eval, code;
3408 if (!callPermitted(call))
3409 return BUDB_NOTPERMITTED;
3411 if (strlen(tape->name) >= sizeof(t.name))
3412 return BUDB_BADARGUMENT;
3414 eval = InitRPC(&ut, LOCKWRITE, 1);
3420 memset(&t, 0, sizeof(t));
3421 eval = AllocStructure(ut, tape_BLOCK, 0, &a, &t);
3425 strcpy(t.name, tape->name);
3427 eval = ht_HashIn(ut, &db.tapeName, a, &t);
3433 /* Since deleting a tape may change the dump (if its the same one), read in
3434 * the dump after the call to DeleteTape. */
3436 eval = ht_LookupEntry(ut, &db.dumpIden, &tape->dump, &da, &d);
3440 ABORT(BUDB_NODUMPID);
3443 tape->written = time(0); /* fill in tape struct */
3444 t.written = htonl(tape->written);
3445 t.expires = htonl(tape->expires);
3447 t.seq = htonl(tape->seq);
3448 t.useCount = htonl(tape->useCount);
3449 t.labelpos = htonl(tape->labelpos);
3451 t.flags = htonl(tape->flags | BUDB_TAPE_BEINGWRITTEN);
3453 t.nextTape = d.firstTape; /* Chain the tape to the dump */
3454 d.firstTape = htonl(a);
3456 if (tape->seq >= ntohl(d.tapes.maxTapes)) /* inc # tapes in the dump */
3457 d.tapes.maxTapes = htonl(tape->seq);
3459 eval = dbwrite(ut, a, &t, sizeof(t)); /* write tape struct */
3463 eval = dbwrite(ut, da, &d, sizeof(d)); /* write the dump struct */
3467 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
3471 LogDebug(5, "added tape %s\n", tape->name);
3473 code = ubik_EndTrans(ut);
3477 ubik_AbortTrans(ut);
3483 /* ---------------------------------------------
3484 * debug interface routines
3485 * ---------------------------------------------
3489 SBUDB_T_DumpHashTable(call, type, filename)
3490 struct rx_call *call;
3496 code = T_DumpHashTable(call, type, filename);
3497 osi_auditU(call, BUDB_TDmpHaEvent, code, AUD_STR, filename, AUD_END);
3502 T_DumpHashTable(call, type, filename)
3503 struct rx_call *call;
3507 struct ubik_trans *ut;
3508 struct memoryHashTable *mht;
3510 afs_int32 eval, code = 0;
3517 char e[sizeof(struct block)]; /* unnecessarily conservative */
3521 if (!callPermitted(call))
3522 return BUDB_NOTPERMITTED;
3524 if (strlen(filename) >= sizeof(path) - 5)
3525 return BUDB_BADARGUMENT;
3527 eval = InitRPC(&ut, LOCKWRITE, 1);
3531 if ((mht = ht_GetType(type, &e_size)) == 0)
3532 return BUDB_BADARGUMENT;
3534 sprintf(path, "%s/%s", gettmpdir(), filename);
3536 DUMP = fopen(path, "w");
3538 ABORT(BUDB_BADARGUMENT);
3541 for (old = 0;; old++) {
3542 length = (old ? mht->oldLength : mht->length);
3544 fprintf(DUMP, "Dumping %sHash Table:\n", (old ? "Old " : ""));
3546 for (hash = 0; hash < length; hash++) {
3547 a = ht_LookupBucket(ut, mht, hash, old);
3550 eval = dbread(ut, a, e, e_size);
3556 fprintf(DUMP, " in bucket %d at %d is ", hash, a);
3558 fprintf(DUMP, " at %d is ", a);
3560 case HT_dumpIden_FUNCTION:
3561 fprintf(DUMP, "%d\n", ntohl(((struct dump *)e)->id));
3563 case HT_dumpName_FUNCTION:
3564 fprintf(DUMP, "%s\n", ((struct dump *)e)->dumpName);
3566 case HT_tapeName_FUNCTION:
3567 fprintf(DUMP, "%s\n", ((struct tape *)e)->name);
3569 case HT_volName_FUNCTION:
3570 fprintf(DUMP, "%s\n", ((struct volInfo *)e)->name);
3573 if ((ht_HashEntry(mht, e) % length) != hash)
3574 ABORT(BUDB_DATABASEINCONSISTENT);
3575 a = ntohl(*(dbadr *) (e + mht->threadOffset));
3582 fprintf(DUMP, "%d entries found\n", ent);
3583 if (ntohl(mht->ht->entries) != ent)
3584 ABORT(BUDB_DATABASEINCONSISTENT);
3586 code = ubik_EndTrans(ut);
3592 ubik_AbortTrans(ut);
3599 SBUDB_T_GetVersion(call, majorVersion)
3600 struct rx_call *call;
3601 afs_int32 *majorVersion;
3605 code = T_GetVersion(call, majorVersion);
3606 osi_auditU(call, BUDB_TGetVrEvent, code, AUD_END);
3611 T_GetVersion(call, majorVersion)
3612 struct rx_call *call;
3615 struct ubik_trans *ut;
3618 code = InitRPC(&ut, LOCKREAD, 0);
3622 *majorVersion = BUDB_MAJORVERSION;
3624 code = ubik_EndTrans(ut);
3628 /* BUDB_T_DumpDatabase
3629 * dump as much of the database as possible int /tmp/<filename>
3633 SBUDB_T_DumpDatabase(call, filename)
3634 struct rx_call *call;
3639 code = T_DumpDatabase(call, filename);
3640 osi_auditU(call, BUDB_TDmpDBEvent, code, AUD_STR, filename, AUD_END);
3645 T_DumpDatabase(call, filename)
3646 struct rx_call *call;
3651 struct ubik_trans *ut;
3654 int type, old, length, hash;
3655 struct memoryHashTable *mht;
3656 afs_int32 eval, code = 0;
3658 if (!callPermitted(call))
3659 return BUDB_NOTPERMITTED;
3661 path = (char *)malloc(strlen(gettmpdir()) + 1 + strlen(filename) + 1);
3663 return (BUDB_INTERNALERROR);
3665 sprintf(path, "%s/%s", gettmpdir(), filename);
3667 dumpfid = fopen(path, "w");
3669 return (BUDB_BADARGUMENT);
3671 eval = InitRPC(&ut, LOCKWRITE, 1);
3675 /* dump all items in the database */
3676 for (type = 1; type <= HT_MAX_FUNCTION; type++) { /*ft */
3677 mht = ht_GetType(type, &entrySize);
3679 ERROR(BUDB_BADARGUMENT);
3681 for (old = 0; old <= 1; old++) { /*fo */
3682 length = (old ? mht->oldLength : mht->length);
3686 fprintf(dumpfid, "Dumping %s Hash Table:\n", (old ? "Old " : ""));
3688 for (hash = 0; hash < length; hash++) { /*f */
3689 dbAddr = ht_LookupBucket(ut, mht, hash, old);
3691 while (dbAddr) { /*w */
3692 switch (type) { /*s */
3693 case HT_dumpIden_FUNCTION:
3695 struct dump hostDump, diskDump;
3698 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3704 "\ndumpId hash %d, entry at %u\n",
3707 "----------------------------\n");
3708 dump_ntoh(&diskDump, &hostDump);
3709 printDump(dumpfid, &hostDump);
3710 dbAddr = hostDump.idHashChain;
3714 case HT_dumpName_FUNCTION:
3716 struct dump hostDump, diskDump;
3719 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3725 "\ndumpname hash %d, entry at %u\n",
3728 "----------------------------\n");
3729 dump_ntoh(&diskDump, &hostDump);
3730 printDump(dumpfid, &hostDump);
3731 dbAddr = hostDump.nameHashChain;
3735 case HT_tapeName_FUNCTION:
3737 struct tape hostTape, diskTape;
3740 cdbread(ut, tape_BLOCK, dbAddr, &diskTape,
3746 "\ntapename hash %d, entry at %u\n",
3749 "----------------------------\n");
3750 tape_ntoh(&diskTape, &hostTape);
3751 printTape(dumpfid, &hostTape);
3752 dbAddr = hostTape.nameHashChain;
3756 case HT_volName_FUNCTION:
3758 struct volInfo hostVolInfo, diskVolInfo;
3761 cdbread(ut, volInfo_BLOCK, dbAddr,
3762 &diskVolInfo, sizeof(diskVolInfo));
3767 "\nvolname hash %d, entry at %u\n",
3770 "----------------------------\n");
3771 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3772 printVolInfo(dumpfid, &hostVolInfo);
3773 dbAddr = hostVolInfo.nameHashChain;
3775 volFragsDump(ut, dumpfid,
3776 hostVolInfo.firstFragment);
3781 fprintf(dumpfid, "unknown type %d\n", type);
3791 code = ubik_EndTrans(ut); /* is this safe if no ut started ? */
3800 volFragsDump(ut, dumpfid, dbAddr)
3801 struct ubik_trans *ut;
3805 struct volFragment hostVolFragment, diskVolFragment;
3810 cdbread(ut, volFragment_BLOCK, dbAddr, &diskVolFragment,
3811 sizeof(diskVolFragment));
3812 if (code) { /* don't be fussy about errors */
3813 fprintf(dumpfid, "volFragsDump: Error reading database\n");
3817 fprintf(dumpfid, "\nvolfragment entry at %u\n", dbAddr);
3818 fprintf(dumpfid, "----------------------------\n");
3819 volFragment_ntoh(&diskVolFragment, &hostVolFragment);
3820 printVolFragment(dumpfid, &hostVolFragment);
3821 dbAddr = hostVolFragment.sameNameChain;
3827 /* utilities - network to host conversion
3828 * currently used for debug only
3831 volFragmentDiskToHost(diskVfPtr, hostVfPtr)
3832 struct volFragment *diskVfPtr, *hostVfPtr;
3834 hostVfPtr->vol = ntohl(diskVfPtr->vol);
3835 hostVfPtr->sameNameChain = ntohl(diskVfPtr->sameNameChain);
3836 hostVfPtr->tape = ntohl(diskVfPtr->tape);
3837 hostVfPtr->sameTapeChain = ntohl(diskVfPtr->sameTapeChain);
3838 hostVfPtr->position = ntohl(diskVfPtr->position);
3839 hostVfPtr->clone = ntohl(diskVfPtr->clone);
3840 hostVfPtr->incTime = ntohl(diskVfPtr->incTime);
3841 hostVfPtr->startByte = ntohl(diskVfPtr->startByte);
3842 hostVfPtr->nBytes = ntohl(diskVfPtr->nBytes);
3843 hostVfPtr->flags = ntohs(diskVfPtr->flags);
3844 hostVfPtr->sequence = ntohs(diskVfPtr->sequence);
3847 volInfoDiskToHost(diskViPtr, hostViPtr)
3848 struct volInfo *diskViPtr, *hostViPtr;
3850 strcpy(hostViPtr->name, diskViPtr->name);
3851 hostViPtr->nameHashChain = ntohl(diskViPtr->nameHashChain);
3852 hostViPtr->id = ntohl(diskViPtr->id);
3853 strcpy(hostViPtr->server, diskViPtr->server);
3854 hostViPtr->partition = ntohl(diskViPtr->partition);
3855 hostViPtr->flags = ntohl(diskViPtr->flags);
3856 hostViPtr->sameNameHead = ntohl(diskViPtr->sameNameHead);
3857 hostViPtr->sameNameChain = ntohl(diskViPtr->sameNameChain);
3858 hostViPtr->firstFragment = ntohl(diskViPtr->firstFragment);
3859 hostViPtr->nFrags = ntohl(diskViPtr->nFrags);
3862 tapeDiskToHost(diskTapePtr, hostTapePtr)
3863 struct tape *diskTapePtr, *hostTapePtr;
3865 strcpy(hostTapePtr->name, diskTapePtr->name);
3866 hostTapePtr->nameHashChain = ntohl(diskTapePtr->nameHashChain);
3867 hostTapePtr->flags = ntohl(diskTapePtr->flags);
3869 /* tape id conversion here */
3870 hostTapePtr->written = ntohl(diskTapePtr->written);
3871 hostTapePtr->nBytes = ntohl(diskTapePtr->nBytes);
3872 hostTapePtr->nFiles = ntohl(diskTapePtr->nFiles);
3873 hostTapePtr->nVolumes = ntohl(diskTapePtr->nVolumes);
3874 hostTapePtr->seq = ntohl(diskTapePtr->seq);
3875 hostTapePtr->dump = ntohl(diskTapePtr->dump);
3876 hostTapePtr->nextTape = ntohl(diskTapePtr->nextTape);
3877 hostTapePtr->firstVol = ntohl(diskTapePtr->firstVol);
3878 hostTapePtr->useCount = ntohl(diskTapePtr->useCount);
3881 dumpDiskToHost(diskDumpPtr, hostDumpPtr)
3882 struct dump *diskDumpPtr, *hostDumpPtr;
3884 hostDumpPtr->id = ntohl(diskDumpPtr->id);
3885 hostDumpPtr->idHashChain = ntohl(diskDumpPtr->idHashChain);
3886 strcpy(hostDumpPtr->dumpName, diskDumpPtr->dumpName);
3887 strcpy(hostDumpPtr->dumpPath, diskDumpPtr->dumpPath);
3888 strcpy(hostDumpPtr->volumeSet, diskDumpPtr->volumeSet);
3889 hostDumpPtr->nameHashChain = ntohl(diskDumpPtr->nameHashChain);
3890 hostDumpPtr->flags = ntohl(diskDumpPtr->flags);
3891 hostDumpPtr->parent = ntohl(diskDumpPtr->parent);
3892 hostDumpPtr->created = ntohl(diskDumpPtr->created);
3893 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3894 hostDumpPtr->nVolumes = ntohl(diskDumpPtr->nVolumes);
3896 /* tapeset conversion here */
3898 hostDumpPtr->firstTape = ntohl(diskDumpPtr->firstTape);
3900 /* principal conversion here */
3906 checkHash(ut, hashType)
3907 struct ubik_trans *ut;
3910 struct memoryHashTable *mhtPtr;
3911 int entrySize, hashTableLength;
3916 mhtPtr = ht_GetType(hashType, &entrySize);
3920 for (old = 0; old < 1; old++) {
3921 LogDebug(5, "\nold = %d\n", old);
3922 printMemoryHashTable(stdout, mhtPtr);
3924 hashTableLength = (old ? mhtPtr->oldLength : mhtPtr->length);
3926 for (bucket = 0; bucket < hashTableLength; bucket++) {
3929 entryAddr = ht_LookupBucket(ut, mhtPtr, bucket, old);
3930 while (entryAddr != 0) {
3931 LogDebug(6, "bucket %d has disk addr %d\n", bucket,
3934 case HT_dumpIden_FUNCTION:
3936 struct dump diskDump, hostDump;
3938 code = dbread(ut, entryAddr, &diskDump, entrySize);
3942 dump_ntoh(&diskDump, &hostDump);
3943 printDump(stdout, &hostDump);
3944 entryAddr = hostDump.idHashChain;
3948 case HT_dumpName_FUNCTION:
3951 case HT_tapeName_FUNCTION:
3954 case HT_volName_FUNCTION:
3956 struct volInfo diskVolInfo, hostVolInfo;
3958 code = dbread(ut, entryAddr, &diskVolInfo, entrySize);
3962 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3963 printVolInfo(stdout, &hostVolInfo);
3964 entryAddr = hostVolInfo.nameHashChain;