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>
24 #include <netinet/in.h>
26 #include <sys/param.h>
28 #include <sys/resource.h>
32 #include <sys/types.h>
34 #include <afs/bubasics.h>
43 #include <afs/cellconfig.h>
47 #include "budb_errs.h"
49 #include "budb_internal.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(struct rx_call *, struct budb_volumeEntry *);
63 afs_int32 AddVolumes(struct rx_call *, struct budb_volumeList *);
64 afs_int32 CreateDump(struct rx_call *, struct budb_dumpEntry *);
65 afs_int32 DoDeleteDump(struct rx_call *, dumpId, Date, Date, budb_dumpsList *);
66 afs_int32 DoDeleteTape(struct rx_call *, struct budb_tapeEntry *);
67 afs_int32 ListDumps(struct rx_call *, afs_int32, afs_int32, Date, Date,
68 budb_dumpsList *, budb_dumpsList *);
69 afs_int32 DeleteVDP(struct rx_call *, char *, char *, afs_int32);
70 afs_int32 FindClone(struct rx_call *, afs_int32, char *, afs_int32 *);
71 afs_int32 FindDump(struct rx_call *, char *, afs_int32,
72 struct budb_dumpEntry *);
73 afs_int32 FindLatestDump(struct rx_call *, char *, char *,
74 struct budb_dumpEntry *);
75 afs_int32 FinishDump(struct rx_call *, struct budb_dumpEntry *);
76 afs_int32 FinishTape(struct rx_call *, struct budb_tapeEntry *);
77 afs_int32 GetDumps(struct rx_call *, afs_int32, afs_int32, char *,
78 afs_int32, afs_int32, afs_int32, afs_int32 *,
79 afs_int32 *, budb_dumpList *);
80 afs_int32 getExpiration(struct ubik_trans *ut, struct tape *);
81 afs_int32 makeAppended(struct ubik_trans *ut, afs_int32, afs_int32,
83 afs_int32 MakeDumpAppended(struct rx_call *, afs_int32, afs_int32,
85 afs_int32 FindLastTape(struct rx_call *, afs_int32, struct budb_dumpEntry *,
86 struct budb_tapeEntry *, struct budb_volumeEntry *);
87 afs_int32 GetTapes(struct rx_call *, afs_int32, afs_int32, char *, afs_int32,
88 afs_int32, afs_int32, afs_int32 *, afs_int32 *,
90 afs_int32 GetVolumes(struct rx_call *, afs_int32, afs_int32, char *,
91 afs_int32, afs_int32, afs_int32, afs_int32 *,
92 afs_int32 *, budb_volumeList *);
93 afs_int32 UseTape(struct rx_call *, struct budb_tapeEntry *, int *);
94 afs_int32 T_DumpHashTable(struct rx_call *, int, char *);
95 afs_int32 T_GetVersion(struct rx_call *, int *);
96 afs_int32 T_DumpDatabase(struct rx_call *, char *);
98 int volFragsDump(struct ubik_trans *, FILE *, dbadr);
100 /* Text block management */
102 struct memTextBlock {
103 struct memTextBlock *mtb_next; /* next in chain */
104 afs_int32 mtb_nbytes; /* # of bytes in this block */
105 struct blockHeader mtb_blkHeader; /* in memory header */
106 dbadr mtb_addr; /* disk address of block */
109 typedef struct memTextBlock memTextBlockT;
110 typedef memTextBlockT *memTextBlockP;
112 /* These variable are for returning debugging info about the state of the
113 server. If they get trashed during multi-threaded operation it doesn't
116 /* This is global so COUNT_REQ in krb_udp.c can refer to it. */
117 char *lastOperation; /* name of last operation */
118 static Date lastTrans; /* time of last transaction */
120 /* procsInited is sort of a lock: during a transaction only one process runs
121 while procsInited is false. */
123 static int procsInited = 0;
125 /* This variable is protected by the procsInited flag. */
127 static int (*rebuildDatabase) (struct ubik_trans *);
129 /* AwaitInitialization
130 * Wait unitl budb has initialized (InitProcs). If it hasn't
131 * within 5 seconds, then return no quorum.
134 AwaitInitialization(void)
138 while (!procsInited) {
141 else if (time(0) - start > 5)
143 #ifdef AFS_PTHREAD_ENV
153 * name is a pathname style name, determine trailing name and return
158 tailCompPtr(char *pathNamePtr)
161 ptr = strrchr(pathNamePtr, '/');
163 /* this should never happen */
164 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
166 return (pathNamePtr);
168 ptr++; /* skip the / */
173 * Check to see if the caller is a SuperUser.
180 callPermitted(struct rx_call *call)
183 struct afsconf_dir *acdir;
185 acdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
189 if (afsconf_SuperUser(acdir, call, NULL))
193 afsconf_Close(acdir);
198 * This is called by every RPC interface to create a Ubik transaction
199 * and read the database header into core
205 * sets a lock on byte 1 of the database. Looks like it enforces
206 * single threading by use of the lock.
210 InitRPC(struct ubik_trans **ut,
211 int lock, /* indicate read/write transaction */
212 int this_op) /* opcode of RCP, for COUNT_ABO */
215 float wait = 0.91; /* start waiting for 1 second */
218 /* wait for server initialization to finish if this is not InitProcs calling */
220 if ((code = AwaitInitialization()))
223 for (code = UNOQUORUM; code == UNOQUORUM;) {
225 ubik_BeginTrans(BU_dbase,
227 LOCKREAD) ? UBIK_READTRANS : UBIK_WRITETRANS),
229 if (code == UNOQUORUM) { /* no quorum elected */
231 Log("Waiting for quorum election\n");
234 #ifdef AFS_PTHREAD_ENV
237 IOMGR_Sleep((int)wait);
244 Log("Have established quorum\n");
246 /* set lock at posiion 1, for 1 byte of type lock */
247 if ((code = ubik_SetLock(*ut, 1, 1, lock))) {
248 ubik_AbortTrans(*ut);
252 /* check that dbase is initialized and setup cheader */
253 if (lock == LOCKREAD) {
254 /* init but don't fix because this is read only */
255 if ((code = CheckInit(*ut, 0))) {
256 ubik_AbortTrans(*ut);
257 if ((code = InitRPC(ut, LOCKWRITE, 0))) { /* Now fix the database */
258 LogError(code, "InitRPC: InitRPC failed\n");
261 if ((code = ubik_EndTrans(*ut))) {
262 LogError(code, "InitRPC: ubik_EndTrans failed\n");
265 goto start; /* now redo the read transaction */
268 if ((code = CheckInit(*ut, rebuildDatabase))) {
269 ubik_AbortTrans(*ut);
277 /* This is called to initialize a newly created database */
279 initialize_database(struct ubik_trans *ut)
284 static int noAuthenticationRequired; /* global state */
285 static int recheckNoAuth; /* global state */
290 struct ubik_trans *ut;
295 if ((globalConfPtr->myHost == 0) || (BU_conf == 0))
296 ERROR(BUDB_INTERNALERROR);
300 if (globalConfPtr->debugFlags & DF_NOAUTH)
301 noAuthenticationRequired = 1;
303 if (globalConfPtr->debugFlags & DF_RECHECKNOAUTH)
307 noAuthenticationRequired = afsconf_GetNoAuthFlag(BU_conf);
309 if (noAuthenticationRequired)
310 LogError(0, "Running server with security disabled\n");
314 rebuildDatabase = initialize_database;
316 if ((code = InitRPC(&ut, LOCKREAD, 0))) {
317 LogError(code, "InitProcs: InitRPC failed\n");
320 code = ubik_EndTrans(ut);
322 LogError(code, "InitProcs: ubik_EndTrans failed\n");
326 rebuildDatabase = 0; /* only do this during init */
334 int nElements; /* number in list */
335 int allocSize; /* number of elements allocated */
336 dbadr *elements; /* array of addresses */
340 InitReturnList(struct returnList *list)
344 list->elements = (dbadr *) 0;
348 FreeReturnList(struct returnList *list)
351 free(list->elements);
352 list->elements = (dbadr *) 0;
356 /* As entries are collected, they are added to a return list. Once all
357 * entries have been collected, it is then placed in the return buffer
358 * with SendReturnList(). The first *to_skipP are not recorded.
361 AddToReturnList(struct returnList *list, dbadr a, afs_int32 *to_skipP)
373 /* Up to 5 plus a maximum so SendReturnList() knows if we
374 * need to come back for more.
376 if (list->nElements >= BUDB_MAX_RETURN_LIST + 5)
377 return BUDB_LIST2BIG;
379 if (list->nElements >= list->allocSize) {
380 if (list->elements == 0) {
382 tmp = (char *)malloc(sizeof(dbadr) * size);
384 size = list->allocSize + 10;
385 tmp = (char *)realloc(list->elements, sizeof(dbadr) * size);
389 list->elements = (dbadr *) tmp;
390 list->allocSize = size;
393 list->elements[list->nElements] = a;
399 FillVolEntry(struct ubik_trans *ut, dbadr va, void *rock)
401 struct budb_volumeEntry *vol = (struct budb_volumeEntry *) rock;
405 struct volFragment vf;
407 if (dbread(ut, va, &vf, sizeof(vf)))
408 return BUDB_IO; /* The volFrag */
409 if (dbread(ut, ntohl(vf.vol), &vi, sizeof(vi)))
410 return BUDB_IO; /* The volInfo */
411 if (dbread(ut, ntohl(vf.tape), &t, sizeof(t)))
412 return BUDB_IO; /* The tape */
413 if (dbread(ut, ntohl(t.dump), &d, sizeof(d)))
414 return BUDB_IO; /* The dump */
416 strcpy(vol->name, vi.name);
417 strcpy(vol->server, vi.server);
418 strcpy(vol->tape, t.name);
419 vol->tapeSeq = ntohl(t.seq);
420 vol->dump = ntohl(d.id);
421 vol->position = ntohl(vf.position);
422 vol->clone = ntohl(vf.clone);
423 vol->incTime = ntohl(vf.incTime);
424 vol->nBytes = ntohl(vf.nBytes);
425 vol->startByte = ntohl(vf.startByte);
426 vol->flags = (ntohs(vf.flags) & VOLFRAGMENTFLAGS); /* low 16 bits here */
427 vol->flags |= (ntohl(vi.flags) & VOLINFOFLAGS); /* high 16 bits here */
428 vol->seq = ntohs(vf.sequence);
429 vol->id = ntohl(vi.id);
430 vol->partition = ntohl(vi.partition);
436 FillDumpEntry(struct ubik_trans *ut, dbadr da, void *rock)
438 struct budb_dumpEntry *dump = (struct budb_dumpEntry *)rock;
441 if (dbread(ut, da, &d, sizeof(d)))
443 dump->id = ntohl(d.id);
444 dump->flags = ntohl(d.flags);
445 dump->created = ntohl(d.created);
446 strncpy(dump->name, d.dumpName, sizeof(dump->name));
447 strncpy(dump->dumpPath, d.dumpPath, sizeof(dump->dumpPath));
448 strncpy(dump->volumeSetName, d.volumeSet, sizeof(dump->volumeSetName));
450 dump->parent = ntohl(d.parent);
451 dump->level = ntohl(d.level);
452 dump->nVolumes = ntohl(d.nVolumes);
454 tapeSet_ntoh(&d.tapes, &dump->tapes);
456 if (strlen(d.dumper.name) < sizeof(dump->dumper.name))
457 strcpy(dump->dumper.name, d.dumper.name);
458 if (strlen(d.dumper.instance) < sizeof(dump->dumper.instance))
459 strcpy(dump->dumper.instance, d.dumper.instance);
460 if (strlen(d.dumper.cell) < sizeof(dump->dumper.cell))
461 strcpy(dump->dumper.cell, d.dumper.cell);
463 /* Get the initial dumpid and the appended dump id */
464 dump->initialDumpID = ntohl(d.initialDumpID);
465 if (d.appendedDumpChain) {
466 if (dbread(ut, ntohl(d.appendedDumpChain), &ad, sizeof(ad)))
468 dump->appendedDumpID = ntohl(ad.id);
470 dump->appendedDumpID = 0;
472 /* printf("dump name %s, parent %d, level %d\n",
473 * d.dumpName, ntohl(d.parent), ntohl(d.level)); */
479 FillTapeEntry(struct ubik_trans *ut, dbadr ta, void *rock)
481 struct budb_tapeEntry *tape=(struct budb_tapeEntry *) rock;
486 if (dbread(ut, ta, &t, sizeof(t)))
489 /* Get the tape's expiration date */
490 if ((code = getExpiration(ut, &t)))
493 strcpy(tape->name, t.name);
494 tape->flags = ntohl(t.flags);
495 tape->written = ntohl(t.written);
496 tape->expires = ntohl(t.expires);
497 tape->nMBytes = ntohl(t.nMBytes);
498 tape->nBytes = ntohl(t.nBytes);
499 tape->nFiles = ntohl(t.nFiles);
500 tape->nVolumes = ntohl(t.nVolumes);
501 tape->seq = ntohl(t.seq);
502 tape->labelpos = ntohl(t.labelpos);
503 tape->useCount = ntohl(t.useCount);
504 tape->useKBytes = ntohl(t.useKBytes);
506 if (dbread(ut, ntohl(t.dump), &d, sizeof(d)))
508 tape->dump = ntohl(d.id);
512 #define returnList_t budb_dumpList *
515 * A list of elements of size e_size is in list, collected
516 * with AddToReturnList(). We will move this to a correspoding
517 * return list, eList, via FillProc(). nextInodeP tells us
518 * if there are more and how many to skip on the next request.
521 SendReturnList(struct ubik_trans *ut,
522 struct returnList *list, /* list of elements to return */
523 afs_int32(*FillProc) (struct ubik_trans *, dbadr da,
525 /* proc to fill entry */
526 int e_size, /* size of each element */
527 afs_int32 index, /* index from previous call */
528 afs_int32 *nextIndexP, /* if more elements are available */
529 afs_int32 *dbTimeP, /* time of last db update */
530 budb_dumpList *eList) /* rxgen list structure (e.g.) */
538 *dbTimeP = ntohl(db.h.lastUpdate);
540 /* Calculate how many to return. Don't let if go over
541 * BUDB_MAX_RETURN_LIST nor the size of our return list.
543 to_return = list->nElements;
544 if (to_return > BUDB_MAX_RETURN_LIST)
545 to_return = BUDB_MAX_RETURN_LIST;
546 if (eList->budb_dumpList_len && (to_return > eList->budb_dumpList_len))
547 to_return = eList->budb_dumpList_len;
549 /* Allocate space for the return values if needed and zero it */
550 if (eList->budb_dumpList_val == 0) {
551 eList->budb_dumpList_val =
552 (struct budb_dumpEntry *)malloc(e_size * to_return);
553 if (!eList->budb_dumpList_val)
556 memset(eList->budb_dumpList_val, 0, e_size * to_return);
557 eList->budb_dumpList_len = to_return;
559 e = (char *)(eList->budb_dumpList_val);
560 for (i = 0; i < to_return; i++, e += e_size) {
561 code = (*FillProc) (ut, list->elements[i], (budb_dumpEntry *) e);
566 if (list->nElements > i)
567 *nextIndexP = index + i;
571 /* Come here to delete a volInfo structure. */
574 DeleteVolInfo(struct ubik_trans *ut, dbadr via, struct volInfo *vi)
580 if (vi->firstFragment)
581 return 0; /* still some frags, don't free yet */
582 if (vi->sameNameHead == 0) { /* this is the head */
583 if (vi->sameNameChain)
584 return 0; /* empty head, some non-heads left */
586 code = ht_HashOut(ut, &db.volName, via, vi);
589 code = FreeStructure(ut, volInfo_BLOCK, via);
592 hvia = ntohl(vi->sameNameHead);
593 if (dbread(ut, hvia, &hvi, sizeof(hvi)))
596 RemoveFromList(ut, hvia, &hvi, &hvi.sameNameChain, via, vi,
599 return BUDB_DATABASEINCONSISTENT;
601 code = FreeStructure(ut, volInfo_BLOCK, via);
605 /* Detach a volume fragment from its volInfo structure. Its tape chain is
606 already freed. This routine frees the structure and the caller must not
610 DeleteVolFragment(struct ubik_trans *ut, dbadr va, struct volFragment *v)
617 if (dbread(ut, via, &vi, sizeof(vi)))
620 RemoveFromList(ut, via, &vi, &vi.firstFragment, va, v,
623 return BUDB_DATABASEINCONSISTENT;
626 if (vi.firstFragment == 0)
627 if ((code = DeleteVolInfo(ut, via, &vi)))
629 if ((code = FreeStructure(ut, volFragment_BLOCK, va)))
632 /* decrement frag counter */
634 set_word_addr(ut, via, &vi, &vi.nFrags, htonl(ntohl(vi.nFrags) - 1));
640 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
641 * The caller will remove it from the hash table if necessary. The caller is
642 * also responsible for writing the tape out if necessary. */
645 DeleteTape(struct ubik_trans *ut, dbadr ta, struct tape *t)
653 return BUDB_DATABASEINCONSISTENT;
654 if (dbread(ut, da, &d, sizeof(d)))
656 if (d.firstTape == 0)
657 return BUDB_DATABASEINCONSISTENT;
659 code = RemoveFromList(ut, da, &d, &d.firstTape, ta, t, &t->nextTape);
661 return BUDB_DATABASEINCONSISTENT;
665 /* Since the tape should have been truncated there should never be any
666 * volumes in the tape. */
667 if (t->firstVol || t->nVolumes)
668 return BUDB_DATABASEINCONSISTENT;
674 DeleteDump(struct ubik_trans *ut, dbadr da, struct dump *d)
678 code = ht_HashOut(ut, &db.dumpIden, da, d);
682 code = ht_HashOut(ut, &db.dumpName, da, d);
686 /* Since the tape should have been truncated this should never happen. */
687 if (d->firstTape || d->nVolumes)
688 ERROR(BUDB_DATABASEINCONSISTENT);
690 code = FreeStructure(ut, dump_BLOCK, da);
701 * This is called with a volumeEntry and a volInfo structure and compares
702 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
703 * search volInfo structures once it has the head volInfo structure from the
704 * volName hash table.
706 * When called from GetVolInfo the name compare is redundant.
707 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
711 VolInfoMatch(struct budb_volumeEntry *vol, struct volInfo *vi)
713 return ((strcmp(vol->name, vi->name) == 0) && /* same volume name */
714 (vol->id == ntohl(vi->id)) && /* same volume id */
715 ((vol->flags & VOLINFOFLAGS) == (ntohl(vi->flags) & VOLINFOFLAGS)) && /* same flags */
716 (vol->partition == ntohl(vi->partition)) && /* same partition (N/A) */
717 (strcmp(vol->server, vi->server) == 0)); /* same server (N/A) */
722 * This routine takes a volumeEntry structure from an RPC interface and
723 * returns the corresponding volInfo structure, creating it if necessary.
725 * The caller must write the entry out.
729 GetVolInfo(struct ubik_trans *ut, struct budb_volumeEntry *volP, dbadr *viaP,
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", volP->name, 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(struct ubik_trans *ut, dbadr tapeAddr,
821 struct tape *tapePtr, int maxVolumesToDelete)
823 dbadr volFragAddr, nextVolFragAddr, dumpAddr;
824 struct volFragment volFrag;
826 int volumesDeleted = 0;
827 afs_int32 eval, code = 0;
832 for (volFragAddr = ntohl(tapePtr->firstVol);
833 (volFragAddr && (maxVolumesToDelete > 0));
834 volFragAddr = nextVolFragAddr) {
835 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
839 nextVolFragAddr = ntohl(volFrag.sameTapeChain);
841 eval = DeleteVolFragment(ut, volFragAddr, &volFrag);
845 maxVolumesToDelete--;
849 /* reset the volume fragment pointer in the tape */
850 tapePtr->firstVol = htonl(volFragAddr);
852 /* diminish the tape's volume count */
853 tapePtr->nVolumes = htonl(ntohl(tapePtr->nVolumes) - volumesDeleted);
855 eval = dbwrite(ut, tapeAddr, tapePtr, sizeof(*tapePtr));
859 /* diminish the dump's volume count */
860 dumpAddr = ntohl(tapePtr->dump);
861 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
865 dump.nVolumes = htonl(ntohl(dump.nVolumes) - volumesDeleted);
866 eval = dbwrite(ut, dumpAddr, &dump, sizeof(dump));
875 * deletes a dump in stages, by repeatedly deleting a small number of
876 * volumes from the dump until none are left. The dump is then deleted.
878 * In the case where multiple calls are made to delete the same
879 * dump, the operation will succeed but contention for structures
880 * will result in someone getting back an error.
883 * id - id of dump to delete
887 deleteDump(struct rx_call *call, dumpId id, budb_dumpsList *dumps)
889 struct ubik_trans *ut;
890 dbadr dumpAddr, tapeAddr, appendedDump;
894 afs_int32 eval, code = 0;
897 /* iterate until the dump is truly deleted */
903 eval = InitRPC(&ut, LOCKWRITE, 1);
905 ERROR(eval); /* can't start transaction */
908 ht_LookupEntry(ut, &db.dumpIden, &dumpid, &dumpAddr, &dump);
912 ABORT(BUDB_NOENT); /* can't find dump */
914 if ((dumpid == id) && (dump.initialDumpID)) /* can't be an appended dump */
915 ABORT(BUDB_NOTINITIALDUMP);
917 tapeAddr = ntohl(dump.firstTape);
921 /* there is a tape to delete */
922 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
926 if (ntohl(tape.nVolumes)) {
927 /* tape is not empty */
928 eval = deleteSomeVolumesFromTape(ut, tapeAddr, &tape, 10);
933 if (ntohl(tape.nVolumes) == 0) {
934 /* tape is now empty, delete it */
935 eval = DeleteTape(ut, tapeAddr, &tape);
938 eval = ht_HashOut(ut, &db.tapeName, tapeAddr, &tape);
941 eval = FreeStructure(ut, tape_BLOCK, tapeAddr);
946 eval = ubik_EndTrans(ut);
950 } /* next deletion portion */
952 /* Record the dump just deleted */
953 if (dumps && (dumps->budb_dumpsList_len < BUDB_MAX_RETURN_LIST)) {
954 if (dumps->budb_dumpsList_len == 0)
955 dumps->budb_dumpsList_val =
956 (afs_int32 *) malloc(sizeof(afs_int32));
958 dumps->budb_dumpsList_val =
959 (afs_int32 *) realloc(dumps->budb_dumpsList_val,
960 (dumps->budb_dumpsList_len +
961 1) * sizeof(afs_int32));
963 if (!dumps->budb_dumpsList_val)
966 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = dumpid;
967 dumps->budb_dumpsList_len++;
970 appendedDump = ntohl(dump.appendedDumpChain);
972 /* finally done. No more tapes left in the dump. Delete the dump itself */
973 eval = DeleteDump(ut, dumpAddr, &dump);
977 /* Now delete the appended dump too */
979 eval = dbread(ut, appendedDump, &dump, sizeof(dump));
983 dumpid = ntohl(dump.id);
987 eval = ubik_EndTrans(ut);
991 Log("Delete dump %s (DumpID %u), path %s\n", dump.dumpName,
992 ntohl(dump.id), dump.dumpPath);
996 if (code && partialDel) {
997 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
998 dump.dumpName, ntohl(dump.id), dump.dumpPath, code);
1003 ubik_AbortTrans(ut);
1008 * dump selection routines - used by BUDB_GetDumps
1012 /* most recent dump selection */
1015 struct chosenDump *next;
1020 struct wantDumpRock {
1021 int maxDumps; /* max wanted */
1022 int ndumps; /* actual in chain */
1023 struct chosenDump *chain;
1028 wantDump(dbadr dumpAddr, void *dumpParam, void *dumpListPtrParam)
1030 struct dump *dumpPtr;
1031 struct wantDumpRock *rockPtr;
1033 dumpPtr = (struct dump *)dumpParam;
1034 rockPtr = (struct wantDumpRock *)dumpListPtrParam;
1036 /* if we don't have our full complement, just add another */
1037 if (rockPtr->ndumps < rockPtr->maxDumps)
1040 /* got the number we need, select based on date */
1041 if ((afs_uint32) ntohl(dumpPtr->created) > rockPtr->chain->date)
1048 rememberDump(dbadr dumpAddr, void *dumpParam, void *dumpListPtrParam)
1050 struct dump *dumpPtr;
1051 struct wantDumpRock *rockPtr;
1052 struct chosenDump *ptr, *deletedPtr, **nextPtr;
1054 dumpPtr = (struct dump *)dumpParam;
1055 rockPtr = (struct wantDumpRock *)dumpListPtrParam;
1057 ptr = (struct chosenDump *)malloc(sizeof(*ptr));
1060 memset(ptr, 0, sizeof(*ptr));
1061 ptr->addr = dumpAddr;
1062 ptr->date = (afs_uint32) ntohl(dumpPtr->created);
1064 /* Don't overflow the max */
1065 while (rockPtr->ndumps >= rockPtr->maxDumps) {
1066 /* have to drop one */
1067 deletedPtr = rockPtr->chain;
1068 rockPtr->chain = deletedPtr->next;
1073 /* now insert in the right place */
1074 for (nextPtr = &rockPtr->chain; *nextPtr; nextPtr = &((*nextPtr)->next)) {
1075 if (ptr->date < (*nextPtr)->date)
1078 ptr->next = *nextPtr;
1086 /* ---------------------------------------------
1087 * general interface routines - alphabetic
1088 * ---------------------------------------------
1092 SBUDB_AddVolume(struct rx_call *call, struct budb_volumeEntry *vol)
1096 code = AddVolume(call, vol);
1097 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, (vol ? vol->id : 0),
1103 AddVolume(struct rx_call *call, struct budb_volumeEntry *vol)
1105 struct ubik_trans *ut;
1106 dbadr da, ta, via, va;
1110 struct volFragment v;
1112 afs_int32 eval, code = 0;
1114 if (!callPermitted(call))
1115 return BUDB_NOTPERMITTED;
1117 if ((strlen(vol->name) >= sizeof(vi.name))
1118 || (strlen(vol->server) >= sizeof(vi.server))
1119 || (strlen(vol->tape) >= sizeof(t.name)))
1120 return BUDB_BADARGUMENT;
1122 eval = InitRPC(&ut, LOCKWRITE, 1);
1126 /* Find the dump in dumpid hash table */
1127 eval = ht_LookupEntry(ut, &db.dumpIden, &vol->dump, &da, &d);
1131 ABORT(BUDB_NODUMPID);
1133 /* search for the right tape in the dump */
1134 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
1135 /* read the tape entry */
1136 eval = dbread(ut, ta, &t, sizeof(t));
1140 /* Check if the right tape name */
1141 if (strcmp(t.name, vol->tape) == 0)
1145 ABORT(BUDB_NOTAPENAME);
1147 if ((t.dump != htonl(da)) || /* tape must belong to dump */
1148 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1149 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)) /* dump must be in progress */
1150 ABORT(BUDB_BADPROTOCOL);
1152 /* find or create a volume info structure */
1153 eval = GetVolInfo(ut, vol, &via, &vi);
1157 /* Create a volume fragment */
1158 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1162 v.vol = htonl(via); /* vol frag points to vol info */
1163 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1164 vi.firstFragment = htonl(va);
1165 vi.nFrags = htonl(ntohl(vi.nFrags) + 1);
1167 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1171 v.tape = htonl(ta); /* vol frag points to tape */
1172 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1173 t.firstVol = htonl(va);
1174 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1175 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1176 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes / (1024 * 1024));
1177 t.nBytes = htonl(bytes % (1024 * 1024));
1179 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1183 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1185 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1189 v.position = htonl(vol->position); /* vol frag info */
1190 v.clone = htonl(vol->clone);
1191 v.incTime = htonl(vol->incTime);
1192 v.startByte = htonl(vol->startByte);
1193 v.nBytes = htonl(vol->nBytes);
1194 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1195 v.sequence = htons(vol->seq);
1197 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1201 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1205 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1207 code = ubik_EndTrans(ut);
1211 ubik_AbortTrans(ut);
1217 SBUDB_AddVolumes(struct rx_call *call, struct budb_volumeList *vols)
1221 code = AddVolumes(call, vols);
1222 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, 0, AUD_END);
1227 AddVolumes(struct rx_call *call, struct budb_volumeList *vols)
1229 struct budb_volumeEntry *vol, *vol1;
1230 struct ubik_trans *ut;
1231 dbadr da, ta, via, va;
1235 struct volFragment v;
1237 afs_int32 eval, e, code = 0;
1239 if (!callPermitted(call))
1240 return BUDB_NOTPERMITTED;
1242 if (!vols || (vols->budb_volumeList_len <= 0)
1243 || !vols->budb_volumeList_val)
1244 return BUDB_BADARGUMENT;
1246 /* The first volume in the list of volumes to add */
1247 vol1 = (struct budb_volumeEntry *)vols->budb_volumeList_val;
1249 eval = InitRPC(&ut, LOCKWRITE, 1);
1253 /* Find the dump in dumpid hash table */
1254 eval = ht_LookupEntry(ut, &db.dumpIden, &vol1->dump, &da, &d);
1258 ABORT(BUDB_NODUMPID);
1260 /* search for the right tape in the dump */
1261 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
1262 /* read the tape entry */
1263 eval = dbread(ut, ta, &t, sizeof(t));
1267 /* Check if the right tape name */
1268 if (strcmp(t.name, vol1->tape) == 0)
1272 ABORT(BUDB_NOTAPENAME);
1274 if ((t.dump != htonl(da)) || /* tape must belong to dump */
1275 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1276 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)) /* dump must be in progress */
1277 ABORT(BUDB_BADPROTOCOL);
1279 for (vol = vol1, e = 0; e < vols->budb_volumeList_len; vol++, e++) {
1281 if ((strlen(vol->name) >= sizeof(vi.name)) || (strcmp(vol->name, "") == 0) || /* no null volnames */
1282 (strlen(vol->server) >= sizeof(vi.server))
1283 || (strlen(vol->tape) >= sizeof(t.name))
1284 || (strcmp(vol->tape, vol1->tape) != 0)) {
1285 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n", vol->name, vol->id, vol->tape, vol->dump);
1289 /* find or create a volume info structure */
1290 eval = GetVolInfo(ut, vol, &via, &vi);
1293 if (*(afs_int32 *) (&vi) == 0) {
1294 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n", vol->name, vol->tape, vol->dump);
1295 ABORT(BUDB_BADARGUMENT);
1298 /* Create a volume fragment */
1299 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1303 v.vol = htonl(via); /* vol frag points to vol info */
1304 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1305 vi.firstFragment = htonl(va);
1306 vi.nFrags = htonl(ntohl(vi.nFrags) + 1);
1307 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1311 v.tape = htonl(ta); /* vol frag points to tape */
1312 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1313 t.firstVol = htonl(va);
1314 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1315 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1316 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes / (1024 * 1024));
1317 t.nBytes = htonl(bytes % (1024 * 1024));
1319 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1321 v.position = htonl(vol->position); /* vol frag info */
1322 v.clone = htonl(vol->clone);
1323 v.incTime = htonl(vol->incTime);
1324 v.startByte = htonl(vol->startByte);
1325 v.nBytes = htonl(vol->nBytes);
1326 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1327 v.sequence = htons(vol->seq);
1329 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1333 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1336 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1340 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1344 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1348 code = ubik_EndTrans(ut);
1352 ubik_AbortTrans(ut);
1358 * records the existence of a dump in the database. This creates only
1359 * the dump record, to which one must attach tape and volume records.
1361 * 1) record the volume set
1365 SBUDB_CreateDump(struct rx_call *call, struct budb_dumpEntry *dump)
1369 code = CreateDump(call, dump);
1370 osi_auditU(call, BUDB_CrDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
1372 if (dump && !code) {
1373 Log("Create dump %s (DumpID %u), path %s\n", dump->name, dump->id,
1380 CreateDump(struct rx_call *call, struct budb_dumpEntry *dump)
1382 struct ubik_trans *ut;
1383 dbadr findDumpAddr, da;
1384 struct dump findDump, d;
1385 afs_int32 eval, code = 0;
1389 Date expiration; /* checked by Security Module */
1390 struct ktc_principal principal;
1392 if (!callPermitted(call))
1393 return BUDB_NOTPERMITTED;
1395 if (strlen(dump->name) >= sizeof(d.dumpName))
1396 return BUDB_BADARGUMENT;
1398 eval = InitRPC(&ut, LOCKWRITE, 1);
1403 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration,
1404 principal.name, principal.instance,
1405 principal.cell, &kvno);
1408 if (eval != RXKADNOAUTH)
1411 strcpy(principal.name, "");
1412 strcpy(principal.instance, "");
1413 strcpy(principal.cell, "");
1416 /* authenticated. Take user supplied principal information */
1417 if (strcmp(dump->dumper.name, "") != 0)
1418 strncpy(principal.name, dump->dumper.name,
1419 sizeof(principal.name));
1421 if (strcmp(dump->dumper.instance, "") != 0)
1422 strncpy(principal.instance, dump->dumper.instance,
1423 sizeof(principal.instance));
1425 if (strcmp(dump->dumper.cell, "") != 0)
1426 strncpy(principal.cell, dump->dumper.cell,
1427 sizeof(principal.cell));
1430 /* dump id's are time stamps */
1432 while (1) { /* allocate a unique dump id *//*w */
1435 /* ensure it is unique - seach for dumpid in hash table */
1437 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1442 if (!findDumpAddr) { /* dumpid not in use */
1443 /* update the last dump id allocated */
1444 eval = set_header_word(ut, lastDumpId, htonl(dump->id));
1450 /* dump id is in use - wait a while */
1451 #ifdef AFS_PTHREAD_ENV
1458 /* dump id supplied (e.g. for database restore) */
1460 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1465 /* Dump id must not already exist */
1467 ABORT(BUDB_DUMPIDEXISTS);
1470 /* Allocate a dump structure */
1471 memset(&d, 0, sizeof(d));
1472 eval = AllocStructure(ut, dump_BLOCK, 0, &da, &d);
1476 strcpy(d.dumpName, dump->name); /* volset.dumpname */
1477 strcpy(d.dumpPath, dump->dumpPath); /* dump node path */
1478 strcpy(d.volumeSet, dump->volumeSetName); /* volume set */
1479 d.id = htonl(dump->id);
1480 d.parent = htonl(dump->parent); /* parent id */
1481 d.level = htonl(dump->level);
1483 LogDebug(4, "dump name %s, parent %d level %d\n", dump->name,
1484 dump->parent, dump->level);
1486 /* if creation time specified, use that. Else use the dumpid time */
1487 if (dump->created == 0)
1488 dump->created = dump->id;
1489 d.created = htonl(dump->created);
1491 principal = d.dumper;
1492 tapeSet_hton(&dump->tapes, &d.tapes);
1494 d.flags = htonl(dump->flags | BUDB_DUMP_INPROGRESS);
1496 eval = ht_HashIn(ut, &db.dumpName, da, &d); /* Into dump name hash table */
1500 eval = ht_HashIn(ut, &db.dumpIden, da, &d); /* Into dumpid hash table */
1504 eval = dbwrite(ut, da, (char *)&d, sizeof(d)); /* Write the dump structure */
1508 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1512 /* If to append this dump, then append it - will write the appended dump */
1513 eval = makeAppended(ut, dump->id, dump->initialDumpID, dump->tapes.b);
1517 code = ubik_EndTrans(ut);
1518 LogDebug(5, "made dump %s, path %s\n", d.dumpName, d.dumpPath);
1522 ubik_AbortTrans(ut);
1527 SBUDB_DeleteDump(struct rx_call *call, dumpId id, Date fromTime, Date toTime,
1528 budb_dumpsList *dumps)
1532 code = DoDeleteDump(call, id, fromTime, toTime, dumps);
1533 osi_auditU(call, BUDB_DelDmpEvent, code, AUD_DATE, id, AUD_END);
1540 DoDeleteDump(struct rx_call *call, dumpId id, Date fromTime, Date toTime,
1541 budb_dumpsList *dumps)
1545 if (!callPermitted(call))
1546 return BUDB_NOTPERMITTED;
1549 code = deleteDump(call, id, dumps);
1554 SBUDB_ListDumps(struct rx_call *call, afs_int32 sflags, char *name,
1555 afs_int32 groupid, Date fromTime, Date toTime,
1556 budb_dumpsList *dumps, budb_dumpsList *flags)
1560 code = ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags);
1561 osi_auditU(call, BUDB_LstDmpEvent, code, AUD_LONG, flags, AUD_END);
1566 ListDumps(struct rx_call *call, afs_int32 sflags, afs_int32 groupid,
1567 Date fromTime, Date toTime, budb_dumpsList *dumps,
1568 budb_dumpsList *flags)
1570 struct ubik_trans *ut;
1571 struct memoryHashTable *mht;
1572 struct dump diskDump, appDiskDump;
1573 dbadr dbAddr, dbAppAddr;
1575 afs_int32 eval, code = 0;
1576 int old, hash, length, entrySize, count = 0;
1578 if (!callPermitted(call))
1579 return BUDB_NOTPERMITTED;
1581 eval = InitRPC(&ut, LOCKREAD, 1);
1585 /* Search the database */
1586 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
1588 return (BUDB_BADARGUMENT);
1590 for (old = 0; old <= 1; old++) { /*o *//* old and new hash tables */
1591 length = (old ? mht->oldLength : mht->length);
1595 for (hash = 0; hash < length; hash++) { /*h *//* for each hash bucket */
1596 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) { /*d */
1598 /* read the entry */
1599 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
1603 /* Skip appended dumps */
1604 if (ntohl(diskDump.initialDumpID) != 0) {
1608 /* Skip dumps with different goup id */
1609 if ((sflags & BUDB_OP_GROUPID)
1610 && (ntohl(diskDump.tapes.id) != groupid)) {
1614 /* Look at this dump to see if it meets the criteria for listing */
1615 if (sflags & BUDB_OP_DATES) {
1616 /* This and each appended dump should be in time */
1617 for (dbAppAddr = dbAddr; dbAppAddr;
1618 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1620 dbread(ut, dbAppAddr, &appDiskDump,
1621 sizeof(appDiskDump));
1625 if ((ntohl(appDiskDump.id) < fromTime)
1626 || (ntohl(appDiskDump.id) > toTime))
1633 /* Add it and each of its appended dump to our list to return */
1634 for (dbAppAddr = dbAddr; dbAppAddr;
1635 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1637 dbread(ut, dbAppAddr, &appDiskDump,
1638 sizeof(appDiskDump));
1642 /* Make sure we have space to list it */
1643 if (dumps->budb_dumpsList_len >= count) {
1646 dumps->budb_dumpsList_val =
1647 (afs_int32 *) malloc(count *
1649 flags->budb_dumpsList_val =
1650 (afs_int32 *) malloc(count *
1653 dumps->budb_dumpsList_val =
1654 (afs_int32 *) realloc(dumps->
1658 flags->budb_dumpsList_val =
1659 (afs_int32 *) realloc(flags->
1664 if (!dumps->budb_dumpsList_val
1665 || !dumps->budb_dumpsList_val)
1669 /* Add it to our list */
1670 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] =
1671 ntohl(appDiskDump.id);
1672 flags->budb_dumpsList_val[flags->budb_dumpsList_len] = 0;
1673 if (ntohl(appDiskDump.initialDumpID) != 0) {
1674 flags->budb_dumpsList_val[flags->
1675 budb_dumpsList_len] |=
1678 if (strcmp(appDiskDump.dumpName, DUMP_TAPE_NAME) == 0) {
1679 flags->budb_dumpsList_val[flags->
1680 budb_dumpsList_len] |=
1683 dumps->budb_dumpsList_len++;
1684 flags->budb_dumpsList_len++;
1690 code = ubik_EndTrans(ut);
1694 ubik_AbortTrans(ut);
1699 SBUDB_DeleteTape(struct rx_call *call,
1700 struct budb_tapeEntry *tape) /* tape info */
1704 code = DoDeleteTape(call, tape);
1705 osi_auditU(call, BUDB_DelTpeEvent, code, AUD_DATE,
1706 (tape ? tape->dump : 0), AUD_END);
1711 DoDeleteTape(struct rx_call *call,
1712 struct budb_tapeEntry *tape) /* tape info */
1714 struct ubik_trans *ut;
1717 afs_int32 eval, code;
1719 if (!callPermitted(call))
1720 return BUDB_NOTPERMITTED;
1722 eval = InitRPC(&ut, LOCKWRITE, 1);
1726 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
1730 eval = DeleteTape(ut, a, &t);
1734 eval = FreeStructure(ut, tape_BLOCK, a);
1738 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1742 code = ubik_EndTrans(ut);
1746 ubik_AbortTrans(ut);
1751 * Deletes old information from the database for a particular dump path
1752 * and volumset. This supercedes the old policy implemented in
1753 * UseTape, which simply matched on the volumeset.dump. Consequently
1754 * it was unable to handle name re-use.
1756 * dsname - dumpset name, i.e. volumeset.dumpname
1757 * dumpPath - full path of dump node
1758 * curDumpID - current dump in progress - so that is may be excluded
1761 * n - some error. May or may not have deleted information.
1765 SBUDB_DeleteVDP(struct rx_call *call, char *dsname, char *dumpPath,
1766 afs_int32 curDumpId)
1770 code = DeleteVDP(call, dsname, dumpPath, curDumpId);
1771 osi_auditU(call, BUDB_DelVDPEvent, code, AUD_STR, dsname, AUD_END);
1776 DeleteVDP(struct rx_call *call, char *dsname, char *dumpPath,
1777 afs_int32 curDumpId)
1782 struct ubik_trans *ut;
1783 afs_int32 eval, code = 0;
1785 if (!callPermitted(call))
1786 return BUDB_NOTPERMITTED;
1789 eval = InitRPC(&ut, LOCKREAD, 1);
1793 eval = ht_LookupEntry(ut, &db.dumpName, dsname, &dumpAddr, &dump);
1797 while (dumpAddr != 0) { /*wd */
1798 if ((strcmp(dump.dumpName, dsname) == 0)
1799 && (strcmp(dump.dumpPath, dumpPath) == 0)
1800 && (ntohl(dump.id) != curDumpId)) {
1801 eval = ubik_EndTrans(ut);
1805 eval = deleteDump(call, ntohl(dump.id), 0);
1809 /* start the traversal over since the various chains may
1815 dumpAddr = ntohl(dump.nameHashChain);
1817 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
1823 /* check if all the dumps have been examined - can terminate */
1825 eval = ubik_EndTrans(ut);
1831 ubik_AbortTrans(ut);
1837 * Given a volume name, and a dumpID, find the volume in that dump and
1838 * return the clone date of the volume (this is the clone date of the
1839 * volume at the time it was dumped).
1841 * Hashes on the volume name and traverses the fragments. Will need to read
1842 * the volumes tape entry to determine if it belongs to the dump. If the
1843 * volume is not found in the dump, then look for it in its parent dump.
1847 SBUDB_FindClone(struct rx_call *call, afs_int32 dumpID, char *volName,
1848 afs_int32 *clonetime)
1852 code = FindClone(call, dumpID, volName, clonetime);
1853 osi_auditU(call, BUDB_FndClnEvent, code, AUD_STR, volName, AUD_END);
1858 FindClone(struct rx_call *call, afs_int32 dumpID, char *volName,
1859 afs_int32 *clonetime)
1861 struct ubik_trans *ut;
1862 dbadr da, hvia, via, vfa;
1865 struct volFragment vf;
1867 int rvi; /* read the volInfo struct */
1868 afs_int32 eval, code = 0;
1870 if (!callPermitted(call))
1871 return BUDB_NOTPERMITTED;
1873 eval = InitRPC(&ut, LOCKREAD, 1);
1879 /* Search for the volume by name */
1880 eval = ht_LookupEntry(ut, &db.volName, volName, &hvia, &vi);
1884 ABORT(BUDB_NOVOLUMENAME);
1887 /* Follw the dump levels up */
1888 for (; dumpID; dumpID = ntohl(d.parent)) { /*d */
1889 /* Get the dump entry */
1890 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &da, &d);
1894 ABORT(BUDB_NODUMPID);
1896 /* seach all the volInfo entries on the sameNameChain */
1897 for (via = hvia; via; via = ntohl(vi.sameNameChain)) { /*via */
1898 if (rvi) { /* Read the volInfo entry - except first time */
1899 eval = dbread(ut, via, &vi, sizeof(vi));
1905 /* search all the volFrag entries on the volFrag */
1906 for (vfa = ntohl(vi.firstFragment); vfa; vfa = ntohl(vf.sameNameChain)) { /*vfa */
1907 eval = dbread(ut, vfa, &vf, sizeof(vf)); /* Read the volFrag entry */
1911 eval = dbread(ut, ntohl(vf.tape), &t, sizeof(t)); /* Read the tape */
1915 /* Now check to see if this fragment belongs to the dump we have */
1916 if (ntohl(t.dump) == da) {
1917 *clonetime = ntohl(vf.clone); /* return the clone */
1925 code = ubik_EndTrans(ut);
1935 * Searches each tape and each volume in the dump until the volume is found.
1936 * If the volume is not in the dump, then we search it's parent dump.
1938 * Re-write to do lookups by volume name.
1941 FindClone(struct rx_call *call, afs_int32 dumpID, char *volName,
1942 afs_int32 *clonetime)
1944 struct ubik_trans *ut;
1945 dbadr diskAddr, tapeAddr, volFragmentAddr;
1948 struct volFragment volFragment;
1949 struct volInfo volInfo;
1950 afs_int32 eval, code = 0;
1952 if (!callPermitted(call))
1953 return BUDB_NOTPERMITTED;
1955 eval = InitRPC(&ut, LOCKREAD, 1);
1961 for (; dumpID; dumpID = ntohl(dump.parent)) { /*d */
1962 /* Get the dump entry */
1963 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &diskAddr, &dump);
1967 ABORT(BUDB_NODUMPID);
1969 /* just to be sure */
1970 if (ntohl(dump.id) != dumpID) {
1971 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID,
1973 ABORT(BUDB_INTERNALERROR);
1976 /* search all the tapes in this dump */
1977 for (tapeAddr = ntohl(dump.firstTape); tapeAddr; tapeAddr = ntohl(tape.nextTape)) { /*t */
1978 /* Get the tape entry */
1979 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
1983 /* search all the volume fragments on this tape */
1984 for (volFragmentAddr = ntohl(tape.firstVol); volFragmentAddr; volFragmentAddr = ntohl(volFragment.sameTapeChain)) { /*vf */
1985 /* Get the volume fragment entry */
1987 dbread(ut, volFragmentAddr, &volFragment,
1988 sizeof(volFragment));
1992 /* Get the volume info entry */
1994 dbread(ut, ntohl(volFragment.vol), &volInfo,
1999 /* check if this volume is the one we want */
2000 if (strcmp(volInfo.name, volName) == 0) {
2001 *clonetime = ntohl(volFragment.clone);
2009 code = ubik_EndTrans(ut);
2019 * Find latest volume dump before adate.
2020 * Used by restore code when restoring a user requested volume(s)
2022 * volumeName - name of volume to match on
2023 * beforeDate - look for dumps older than this date
2025 * deptr - descriptor of most recent dump
2029 SBUDB_FindDump(struct rx_call *call, char *volumeName, afs_int32 beforeDate,
2030 struct budb_dumpEntry *deptr)
2034 code = FindDump(call, volumeName, beforeDate, deptr);
2035 osi_auditU(call, BUDB_FndDmpEvent, code, AUD_STR, volumeName, AUD_END);
2040 FindDump(struct rx_call *call, char *volumeName, afs_int32 beforeDate,
2041 struct budb_dumpEntry *deptr)
2043 struct ubik_trans *ut;
2044 dbadr volInfoAddr, volFragmentAddr;
2046 struct volInfo volInfo;
2047 struct volFragment volFragment;
2049 dbadr selectedDumpAddr = 0;
2050 afs_int32 selectedDate = 0;
2051 afs_int32 volCloned;
2053 afs_int32 eval, code = 0;
2055 if (!callPermitted(call))
2056 return BUDB_NOTPERMITTED;
2058 eval = InitRPC(&ut, LOCKREAD, 1);
2062 /* Find volinfo struct for volume name in hash table */
2064 ht_LookupEntry(ut, &db.volName, volumeName, &volInfoAddr, &volInfo);
2068 ABORT(BUDB_NOVOLUMENAME);
2070 /* Step through all the volinfo structures on the same name chain.
2071 * No need to read the first - we read it above.
2073 for (rvoli = 0; volInfoAddr;
2074 rvoli = 1, volInfoAddr = ntohl(volInfo.sameNameChain)) {
2075 if (rvoli) { /* read the volinfo structure */
2076 eval = dbread(ut, volInfoAddr, &volInfo, sizeof(volInfo));
2081 /* step through the volfrag structures */
2082 for (volFragmentAddr = ntohl(volInfo.firstFragment); volFragmentAddr;
2083 volFragmentAddr = ntohl(volFragment.sameNameChain)) {
2084 /* read the volfrag struct */
2086 dbread(ut, volFragmentAddr, &volFragment,
2087 sizeof(volFragment));
2091 volCloned = ntohl(volFragment.clone);
2093 /* now we can examine the date for most recent dump */
2094 if ((volCloned > selectedDate) && (volCloned < beforeDate)) {
2095 /* from the volfrag struct, read the tape struct */
2097 dbread(ut, ntohl(volFragment.tape), &tape, sizeof(tape));
2101 selectedDate = volCloned;
2102 selectedDumpAddr = ntohl(tape.dump);
2107 if (!selectedDumpAddr)
2110 eval = FillDumpEntry(ut, selectedDumpAddr, deptr);
2114 code = ubik_EndTrans(ut);
2122 /* BUDB_FindLatestDump
2123 * Find the latest dump of volumeset vsname with dump name dname.
2125 * vsname - volumeset name
2130 SBUDB_FindLatestDump(struct rx_call *call, char *vsname, char *dumpPath,
2131 struct budb_dumpEntry *dumpentry)
2135 code = FindLatestDump(call, vsname, dumpPath, dumpentry);
2136 osi_auditU(call, BUDB_FndLaDEvent, code, AUD_STR, vsname, AUD_END);
2141 FindLatestDump(struct rx_call *call, char *vsname, char *dumpPath,
2142 struct budb_dumpEntry *dumpentry)
2144 struct ubik_trans *ut;
2145 dbadr curdbaddr, retdbaddr, firstdbaddr;
2148 char dumpName[BU_MAXNAMELEN + 2];
2149 afs_int32 eval, code = 0;
2151 if (!callPermitted(call))
2152 return BUDB_NOTPERMITTED;
2154 eval = InitRPC(&ut, LOCKREAD, 1);
2158 if ((strcmp(vsname, "") == 0) && (strcmp(dumpPath, "") == 0)) {
2159 /* Construct a database dump name */
2160 strcpy(dumpName, DUMP_TAPE_NAME);
2161 } else if (strchr(dumpPath, '/') == 0) {
2162 int level, old, length, hash;
2163 struct dump hostDump, diskDump;
2164 struct memoryHashTable *mht;
2167 afs_uint32 bestDumpId = 0;
2169 level = atoi(dumpPath);
2171 ABORT(BUDB_BADARGUMENT);
2174 /* Brute force search of all the dumps in the database - yuck! */
2177 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
2179 ABORT(BUDB_BADARGUMENT);
2181 for (old = 0; old <= 1; old++) { /*fo */
2182 length = (old ? mht->oldLength : mht->length);
2186 for (hash = 0; hash < length; hash++) {
2188 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr;
2189 dbAddr = hostDump.idHashChain) {
2191 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
2194 dump_ntoh(&diskDump, &hostDump);
2196 if ((strcmp(hostDump.volumeSet, vsname) == 0) && /* the volumeset */
2197 (hostDump.level == level) && /* same level */
2198 (hostDump.id > bestDumpId)) { /* more recent */
2199 bestDumpId = hostDump.id;
2206 ABORT(BUDB_NODUMPNAME);
2210 /* construct the name of the dump */
2211 if ((strlen(vsname) + strlen(tailCompPtr(dumpPath))) > BU_MAXNAMELEN)
2212 ABORT(BUDB_NODUMPNAME);
2214 strcpy(dumpName, vsname);
2215 strcat(dumpName, ".");
2216 strcat(dumpName, tailCompPtr(dumpPath));
2219 LogDebug(5, "lookup on :%s:\n", dumpName);
2221 /* Lookup on dumpname in hash table */
2222 eval = ht_LookupEntry(ut, &db.dumpName, dumpName, &firstdbaddr, &d);
2229 /* folow remaining dumps in hash chain, looking for most latest dump */
2230 for (curdbaddr = firstdbaddr; curdbaddr;
2231 curdbaddr = ntohl(d.nameHashChain)) {
2232 if (curdbaddr != firstdbaddr) {
2233 eval = dbread(ut, curdbaddr, &d, sizeof(d));
2238 if ((strcmp(d.dumpPath, dumpPath) == 0) && /* Same dumppath */
2239 (strcmp(d.dumpName, dumpName) == 0) && /* Same dumpname */
2240 (ntohl(d.created) > latest)) { /* most recent */
2241 latest = ntohl(d.created);
2242 retdbaddr = curdbaddr;
2246 ABORT(BUDB_NODUMPNAME);
2249 /* return the dump found */
2250 FillDumpEntry(ut, retdbaddr, dumpentry);
2252 code = ubik_EndTrans(ut);
2256 ubik_AbortTrans(ut);
2262 SBUDB_FinishDump(struct rx_call *call, struct budb_dumpEntry *dump)
2266 code = FinishDump(call, dump);
2267 osi_auditU(call, BUDB_FinDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
2273 FinishDump(struct rx_call *call, struct budb_dumpEntry *dump)
2275 struct ubik_trans *ut;
2278 afs_int32 eval, code = 0;
2280 if (!callPermitted(call))
2281 return BUDB_NOTPERMITTED;
2283 eval = InitRPC(&ut, LOCKWRITE, 1);
2287 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &a, &d);
2291 ABORT(BUDB_NODUMPID);
2293 if ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)
2294 ABORT(BUDB_DUMPNOTINUSE);
2296 d.flags = htonl(dump->flags & ~BUDB_DUMP_INPROGRESS);
2298 /* if creation time specified set it */
2300 d.created = htonl(dump->created);
2301 dump->created = ntohl(d.created);
2303 /* Write the dump entry out */
2304 eval = dbwrite(ut, a, &d, sizeof(d));
2308 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2312 code = ubik_EndTrans(ut);
2316 ubik_AbortTrans(ut);
2321 SBUDB_FinishTape(struct rx_call *call, struct budb_tapeEntry *tape)
2325 code = FinishTape(call, tape);
2326 osi_auditU(call, BUDB_FinTpeEvent, code, AUD_DATE,
2327 (tape ? tape->dump : 0), AUD_END);
2332 FinishTape(struct rx_call *call, struct budb_tapeEntry *tape)
2334 struct ubik_trans *ut;
2338 afs_int32 eval, code = 0;
2340 if (!callPermitted(call))
2341 return BUDB_NOTPERMITTED;
2343 eval = InitRPC(&ut, LOCKWRITE, 1);
2347 /* find the tape struct in the tapename hash chain */
2348 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
2352 ABORT(BUDB_NOTAPENAME);
2354 /* Read the dump structure */
2355 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2359 /* search for the right tape on the rest of the chain */
2360 while (ntohl(d.id) != tape->dump) {
2361 a = ntohl(t.nameHashChain);
2363 ABORT(BUDB_NOTAPENAME);
2365 eval = dbread(ut, a, &t, sizeof(t));
2369 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2374 if ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0)
2375 ABORT(BUDB_TAPENOTINUSE);
2377 /* t.nBytes = htonl(tape->nBytes); */
2378 t.nFiles = htonl(tape->nFiles);
2379 t.useKBytes = htonl(tape->useKBytes);
2380 t.flags = htonl(tape->flags & ~BUDB_TAPE_BEINGWRITTEN);
2382 eval = dbwrite(ut, a, &t, sizeof(t));
2386 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2390 code = ubik_EndTrans(ut);
2394 ubik_AbortTrans(ut);
2399 * return a set of dumps that match the specified criteria
2402 * majorVersion - version of interface structures. Permits compatibility
2404 * flags - for search and select operations. Broken down into flags
2405 * for name, start point, end point and time.
2406 * name - name to search for. Interpretation based on flags
2413 * dbTimeP - time at which the database was last modified. Up to
2414 * caller (client) to take appropriate action if database
2415 * modified between successive calls
2416 * dumps - list of matching dumps
2418 * currently supported are:
2424 SBUDB_GetDumps(struct rx_call *call,
2425 afs_int32 majorVersion, /* version of interface structures */
2426 afs_int32 flags, /* search & select controls */
2427 char *name, /* s&s parameters */
2430 afs_int32 index, /* start index of returned entries */
2431 afs_int32 *nextIndexP, /* output index for next call */
2433 budb_dumpList *dumps) /* pointer to buffer */
2438 GetDumps(call, majorVersion, flags, name, start, end, index,
2439 nextIndexP, dbTimeP, dumps);
2440 osi_auditU(call, BUDB_GetDmpEvent, code, AUD_END);
2445 GetDumps(struct rx_call *call,
2446 afs_int32 majorVersion, /* version of interface structures */
2447 afs_int32 flags, /* search & select controls */
2448 char *name, /* s&s parameters */
2451 afs_int32 index, /* start index of returned entries */
2452 afs_int32 *nextIndexP, /* output index for next call */
2454 budb_dumpList *dumps) /* pointer to buffer */
2456 struct ubik_trans *ut;
2459 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2460 afs_int32 eval, code = 0;
2462 struct returnList list;
2464 /* Don't check permissions when we look up a specific dump id */
2465 if (((flags & BUDB_OP_STARTS) != BUDB_OP_DUMPID) && !callPermitted(call))
2466 return BUDB_NOTPERMITTED;
2468 if (majorVersion != BUDB_MAJORVERSION)
2469 return BUDB_OLDINTERFACE;
2471 return BUDB_ENDOFLIST;
2473 eval = InitRPC(&ut, LOCKREAD, 1);
2477 nameFlags = flags & BUDB_OP_NAMES;
2478 startFlags = flags & BUDB_OP_STARTS;
2479 endFlags = flags & BUDB_OP_ENDS;
2480 timeFlags = flags & BUDB_OP_TIMES;
2482 InitReturnList(&list);
2485 if (nameFlags == BUDB_OP_DUMPNAME) {
2486 /* not yet implemented */
2487 if (startFlags || endFlags || timeFlags)
2488 ABORT(BUDB_BADFLAGS);
2490 eval = ht_LookupEntry(ut, &db.dumpName, name, &da, &d);
2494 ABORT(BUDB_NODUMPNAME);
2497 if (strcmp(d.dumpName, name) == 0) {
2498 eval = AddToReturnList(&list, da, &toskip);
2499 if (eval == BUDB_LIST2BIG)
2505 da = ntohl(d.nameHashChain); /* get next dump w/ name */
2509 eval = dbread(ut, da, &d, sizeof(d));
2513 } else if (nameFlags == BUDB_OP_VOLUMENAME) {
2517 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2518 ABORT(BUDB_BADFLAGS);
2521 if (startFlags != BUDB_OP_STARTTIME)
2522 ABORT(BUDB_BADFLAGS);
2524 /* lookup a dump by volumename and time stamp. Find the most recent
2525 * dump of the specified volumename, that occured before the supplied
2529 /* get us a volInfo for name */
2530 eval = ht_LookupEntry(ut, &db.volName, name, &da, &vi);
2535 /* now iterate over all the entries of this name */
2536 for (va = vi.firstFragment; va != 0; va = v.sameNameChain) {
2538 eval = dbread(ut, va, &v, sizeof(v));
2543 on fragment > date ignore it - too recent;
2545 if (date on fragment < date && date on fragment > bestfound)
2546 bestfound = date on fragment;
2550 da = vi.sameNameChain;
2554 eval = dbread(ut, da, &vi, sizeof(vi));
2563 from saved volfragment address, compute dump.
2564 otherwise, return dump found
2569 } else if (startFlags == BUDB_OP_DUMPID) {
2570 if (endFlags || timeFlags)
2571 ABORT(BUDB_BADFLAGS);
2573 ABORT(BUDB_BADFLAGS); /* NYI */
2575 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
2579 ABORT(BUDB_NODUMPID);
2581 eval = AddToReturnList(&list, da, &toskip);
2584 } else if (endFlags == BUDB_OP_NPREVIOUS) {
2585 struct wantDumpRock rock;
2586 struct chosenDump *ptr, *nextPtr;
2588 /* no other flags should be set */
2590 /* end specifies how many dumps */
2592 ABORT(BUDB_BADFLAGS);
2594 memset(&rock, 0, sizeof(rock));
2595 rock.maxDumps = end;
2597 scanHashTable(ut, &db.dumpName, wantDump, rememberDump,
2600 for (ptr = rock.chain; ptr; ptr = nextPtr) {
2601 nextPtr = ptr->next;
2602 AddToReturnList(&list, ptr->addr, &toskip); /* ignore error for free */
2606 ABORT(BUDB_BADFLAGS);
2610 SendReturnList(ut, &list, FillDumpEntry,
2611 sizeof(struct budb_dumpEntry), index, nextIndexP,
2612 dbTimeP, (returnList_t) dumps);
2616 FreeReturnList(&list);
2617 code = ubik_EndTrans(ut);
2621 FreeReturnList(&list);
2622 ubik_AbortTrans(ut);
2627 * Get the expiration of a tape. Since the dump could have appended dumps,
2628 * we should use the most recent expiration date. Put the most recent
2629 * expiration tape into the given tape structure.
2632 getExpiration(struct ubik_trans *ut, struct tape *tapePtr)
2638 afs_int32 eval, code = 0;
2643 /* Get the dump for this tape */
2644 ad = ntohl(tapePtr->dump);
2645 eval = dbread(ut, ad, &d, sizeof(d));
2649 /* If not an initial dump, get the initial dump */
2650 if (d.initialDumpID) {
2651 initDump = ntohl(d.initialDumpID);
2652 eval = ht_LookupEntry(ut, &db.dumpIden, &initDump, &ad, &d);
2657 /* Cycle through the dumps and appended dumps */
2659 /* Get the first tape in this dump. No need to check the rest of the tapes */
2660 /* for this dump since they will all have the same expiration date */
2661 eval = dbread(ut, ntohl(d.firstTape), &t, sizeof(t));
2665 /* Take the greater of the expiration dates */
2666 if (ntohl(tapePtr->expires) < ntohl(t.expires))
2667 tapePtr->expires = t.expires;
2669 /* Step to and read the next appended dump */
2670 if ((ad = ntohl(d.appendedDumpChain))) {
2671 eval = dbread(ut, ad, &d, sizeof(d));
2681 /* Mark the following dump as appended to another, intial dump */
2683 makeAppended(struct ubik_trans *ut, afs_int32 appendedDumpID,
2684 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2686 dbadr ada, da, lastDumpAddr;
2688 afs_int32 eval, code = 0;
2692 if (appendedDumpID == initialDumpID)
2693 ERROR(BUDB_INTERNALERROR);
2695 /* If there is an initial dump, append this dump to it */
2696 /* Find the appended dump via its id */
2697 eval = ht_LookupEntry(ut, &db.dumpIden, &appendedDumpID, &ada, &ad);
2701 /* If the dump is already marked as appended,
2702 * then we have an internal error.
2704 if (ad.initialDumpID) {
2705 if (ntohl(ad.initialDumpID) != initialDumpID)
2706 ERROR(BUDB_INTERNALERROR);
2709 /* Update the appended dump to point to the initial dump */
2710 ad.initialDumpID = htonl(initialDumpID);
2711 ad.tapes.b = htonl(startTapeSeq);
2713 /* find the initial dump via its id */
2714 eval = ht_LookupEntry(ut, &db.dumpIden, &initialDumpID, &da, &d);
2718 /* Update the appended dump's tape format with that of the initial */
2719 strcpy(ad.tapes.format, d.tapes.format);
2721 /* starting with the initial dump step through its appended dumps till
2722 * we reach the last appended dump.
2725 while (d.appendedDumpChain) {
2726 lastDumpAddr = ntohl(d.appendedDumpChain);
2727 if (lastDumpAddr == ada)
2728 ERROR(0); /* Already appended */
2729 eval = dbread(ut, lastDumpAddr, &d, sizeof(d));
2734 /* Update the last dump to point to our new appended dump.
2735 * The appended dump is the last one in the dump chain.
2737 d.appendedDumpChain = htonl(ada);
2738 ad.appendedDumpChain = 0;
2740 /* Write the appended dump and the initial dump */
2741 eval = dbwrite(ut, ada, (char *)&ad, sizeof(ad));
2745 eval = dbwrite(ut, lastDumpAddr, (char *)&d, sizeof(d));
2749 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2758 SBUDB_MakeDumpAppended(struct rx_call *call, afs_int32 appendedDumpID,
2759 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2764 MakeDumpAppended(call, appendedDumpID, initialDumpID, startTapeSeq);
2765 osi_auditU(call, BUDB_AppDmpEvent, code, AUD_LONG, appendedDumpID,
2771 MakeDumpAppended(struct rx_call *call, afs_int32 appendedDumpID,
2772 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2774 struct ubik_trans *ut;
2775 afs_int32 eval, code = 0;
2777 if (!callPermitted(call))
2778 return BUDB_NOTPERMITTED;
2780 eval = InitRPC(&ut, LOCKWRITE, 1);
2784 eval = makeAppended(ut, appendedDumpID, initialDumpID, startTapeSeq);
2788 code = ubik_EndTrans(ut);
2792 ubik_AbortTrans(ut);
2796 /* Find the last tape of a dump-set. This includes any appended dumps */
2798 SBUDB_FindLastTape(struct rx_call *call, afs_int32 dumpID,
2799 struct budb_dumpEntry *dumpEntry,
2800 struct budb_tapeEntry *tapeEntry,
2801 struct budb_volumeEntry *volEntry)
2805 code = FindLastTape(call, dumpID, dumpEntry, tapeEntry, volEntry);
2806 osi_auditU(call, BUDB_FndLTpeEvent, code, AUD_LONG, dumpID, AUD_END);
2811 FindLastTape(struct rx_call *call, afs_int32 dumpID,
2812 struct budb_dumpEntry *dumpEntry,
2813 struct budb_tapeEntry *tapeEntry,
2814 struct budb_volumeEntry *volEntry)
2816 struct ubik_trans *ut;
2820 dbadr lastTape, thisTape;
2821 afs_int32 lastTapeSeq;
2822 struct volFragment vf;
2823 dbadr lastVol, thisVol;
2824 afs_int32 lastVolPos;
2825 afs_int32 eval, code = 0;
2827 if (!callPermitted(call))
2828 return BUDB_NOTPERMITTED;
2831 return (BUDB_BADARGUMENT);
2833 eval = InitRPC(&ut, LOCKREAD, 1);
2837 /* find and read its initial dump via its id */
2838 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &lastDump, &d);
2842 ABORT(BUDB_NODUMPID);
2844 /* Follow the append dumps link chain until we reach the last dump */
2845 while (d.appendedDumpChain) {
2846 lastDump = ntohl(d.appendedDumpChain);
2847 eval = dbread(ut, lastDump, &d, sizeof(d));
2852 /* We now have the last dump of the last appended dump */
2853 /* Copy this into our return structure */
2854 eval = FillDumpEntry(ut, lastDump, dumpEntry);
2858 /* Fail if the last dump has no tapes */
2860 ABORT(BUDB_NOTAPENAME);
2862 /* Follow the tapes in this dump until we reach the last tape */
2863 eval = dbread(ut, ntohl(d.firstTape), &t, sizeof(t));
2867 lastTape = ntohl(d.firstTape);
2868 lastTapeSeq = ntohl(t.seq);
2869 lastVol = ntohl(t.firstVol);
2871 while (t.nextTape) {
2872 thisTape = ntohl(t.nextTape);
2873 eval = dbread(ut, thisTape, &t, sizeof(t));
2877 if (ntohl(t.seq) > lastTapeSeq) {
2878 lastTape = thisTape;
2879 lastTapeSeq = ntohl(t.seq);
2880 lastVol = ntohl(t.firstVol);
2884 /* We now have the last tape of the last appended dump */
2885 /* Copy this into our return structure */
2886 eval = FillTapeEntry(ut, lastTape, tapeEntry);
2890 /* Zero volume entry if the last tape has no volumes */
2892 memset(volEntry, 0, sizeof(*volEntry));
2894 /* Follow the volumes until we reach the last volume */
2895 eval = dbread(ut, lastVol, &vf, sizeof(vf));
2899 lastVolPos = vf.position;
2901 while (vf.sameTapeChain) {
2902 thisVol = ntohl(vf.sameTapeChain);
2903 eval = dbread(ut, thisVol, &vf, sizeof(vf));
2907 if (vf.position > lastVolPos) {
2909 lastVolPos = vf.position;
2913 /* We now have the last volume of this tape */
2914 /* Copy this into our return structure */
2915 eval = FillVolEntry(ut, lastVol, volEntry);
2920 eval = ubik_EndTrans(ut);
2926 ubik_AbortTrans(ut);
2932 SBUDB_GetTapes(struct rx_call *call,
2933 afs_int32 majorVersion, /* version of interface structures */
2934 afs_int32 flags, /* search & select controls */
2935 char *name, /* s&s parameters */
2937 afs_int32 end, /* reserved: MBZ */
2938 afs_int32 index, /* start index of returned entries */
2939 afs_int32 *nextIndexP, /* output index for next call */
2941 budb_tapeList *tapes) /* pointer to buffer */
2946 GetTapes(call, majorVersion, flags, name, start, end, index,
2947 nextIndexP, dbTimeP, tapes);
2948 osi_auditU(call, BUDB_GetTpeEvent, code, AUD_END);
2953 GetTapes(struct rx_call *call,
2954 afs_int32 majorVersion, /* version of interface structures */
2955 afs_int32 flags, /* search & select controls */
2956 char *name, /* s&s parameters */
2958 afs_int32 end, /* reserved: MBZ */
2959 afs_int32 index, /* start index of returned entries */
2960 afs_int32 *nextIndexP, /* output index for next call */
2962 budb_tapeList *tapes) /* pointer to buffer */
2964 struct ubik_trans *ut;
2968 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2969 struct returnList list;
2970 afs_int32 eval, code = 0;
2973 if (!callPermitted(call))
2974 return BUDB_NOTPERMITTED;
2976 if (majorVersion != BUDB_MAJORVERSION)
2977 return BUDB_OLDINTERFACE;
2980 return BUDB_ENDOFLIST;
2982 eval = InitRPC(&ut, LOCKREAD, 1);
2986 nameFlags = flags & BUDB_OP_NAMES;
2987 startFlags = flags & BUDB_OP_STARTS;
2988 endFlags = flags & BUDB_OP_ENDS;
2989 timeFlags = flags & BUDB_OP_TIMES;
2991 InitReturnList(&list);
2994 if (nameFlags == BUDB_OP_TAPENAME) { /*it */
2995 eval = ht_LookupEntry(ut, &db.tapeName, name, &ta, &t);
2999 ABORT(BUDB_NOTAPENAME);
3002 if ((startFlags & ~BUDB_OP_DUMPID) || endFlags || timeFlags)
3003 ABORT(BUDB_BADFLAGS);
3005 /* follow the hash chain to the end */
3007 if (startFlags & BUDB_OP_DUMPID) {
3008 /* read in the dump */
3009 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
3013 /* check if both name and dump id match */
3014 if ((strcmp(name, t.name) == 0) && (ntohl(d.id) == start)) {
3015 eval = AddToReturnList(&list, ta, &toskip);
3016 if (eval && (eval != BUDB_LIST2BIG))
3021 /* Add to return list and continue search */
3022 if (strcmp(name, t.name) == 0) {
3023 eval = AddToReturnList(&list, ta, &toskip);
3024 if (eval == BUDB_LIST2BIG)
3031 ta = ntohl(t.nameHashChain);
3033 dbread(ut, ta, &t, sizeof(t));
3036 else if (nameFlags == BUDB_OP_TAPESEQ) {
3037 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
3041 ABORT(BUDB_NODUMPNAME);
3043 /* search for the right tape */
3044 ta = ntohl(d.firstTape);
3045 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
3046 eval = dbread(ut, ta, &t, sizeof(t));
3050 if (ntohl(t.seq) == end) {
3051 eval = AddToReturnList(&list, ta, &toskip);
3052 if (eval && (eval != BUDB_LIST2BIG))
3058 ABORT(BUDB_BADFLAGS);
3062 SendReturnList(ut, &list, FillTapeEntry,
3063 sizeof(struct budb_tapeEntry), index, nextIndexP,
3064 dbTimeP, (returnList_t) tapes);
3068 FreeReturnList(&list);
3069 code = ubik_EndTrans(ut);
3073 FreeReturnList(&list);
3074 ubik_AbortTrans(ut);
3079 * get a set of volumes according to the specified criteria.
3080 * See BUDB_GetDumps for general information on parameters
3081 * Currently supports:
3082 * 1) volume match - returns volumes based on volume name only.
3083 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
3084 * and start is a dumpid. Returns all volumes of the specified
3085 * name on the selected dumpid.
3089 SBUDB_GetVolumes(struct rx_call *call,
3090 afs_int32 majorVersion, /* version of interface structures */
3091 afs_int32 flags, /* search & select controls */
3092 char *name, /* - parameters for search */
3093 afs_int32 start, /* - usage depends which BUDP_OP */
3094 afs_int32 end, /* - bits are set */
3095 afs_int32 index, /* start index of returned entries */
3096 afs_int32 *nextIndexP, /* output index for next call */
3098 budb_volumeList *volumes) /* pointer to buffer */
3103 GetVolumes(call, majorVersion, flags, name, start, end, index,
3104 nextIndexP, dbTimeP, volumes);
3105 osi_auditU(call, BUDB_GetVolEvent, code, AUD_END);
3110 GetVolumes(struct rx_call *call,
3111 afs_int32 majorVersion, /* version of interface structures */
3112 afs_int32 flags, /* search & select controls */
3113 char *name, /* - parameters for search */
3114 afs_int32 start, /* - usage depends which BUDP_OP_* */
3115 afs_int32 end, /* - bits are set */
3116 afs_int32 index, /* start index of returned entries */
3117 afs_int32 *nextIndexP, /* output index for next call */
3119 budb_volumeList *volumes) /* pointer to buffer */
3121 struct ubik_trans *ut;
3124 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
3125 afs_int32 eval, code = 0;
3126 struct returnList vollist;
3129 /* Don't check permissions when we look up a specific volume name */
3130 if (((flags & BUDB_OP_NAMES) != BUDB_OP_VOLUMENAME)
3131 && !callPermitted(call))
3132 return BUDB_NOTPERMITTED;
3134 if (majorVersion != BUDB_MAJORVERSION)
3135 return BUDB_OLDINTERFACE;
3137 return BUDB_ENDOFLIST;
3139 eval = InitRPC(&ut, LOCKREAD, 1);
3143 nameFlags = flags & BUDB_OP_NAMES;
3144 startFlags = flags & BUDB_OP_STARTS;
3145 endFlags = flags & BUDB_OP_ENDS;
3146 timeFlags = flags & BUDB_OP_TIMES;
3148 InitReturnList(&vollist);
3151 /* lookup a the volume (specified by name) in the dump (specified by id) */
3152 if (nameFlags == BUDB_OP_VOLUMENAME) {
3153 /* dumpid permissible, all others off */
3154 if (((startFlags & ~BUDB_OP_DUMPID) != 0) || endFlags || timeFlags)
3155 ABORT(BUDB_BADFLAGS);
3157 /* returns ptr to volinfo of requested name */
3158 eval = ht_LookupEntry(ut, &db.volName, name, &via, &vi);
3162 ABORT(BUDB_NOVOLUMENAME);
3164 /* Iterate over all volume fragments with this name */
3166 struct volFragment v;
3169 /* traverse all the volume fragments for this volume info structure */
3170 for (va = vi.firstFragment; va; va = v.sameNameChain) {
3172 eval = dbread(ut, va, &v, sizeof(v));
3176 if (startFlags & BUDB_OP_DUMPID) {
3180 /* get the dump id for this fragment */
3181 eval = dbread(ut, ntohl(v.tape), &atape, sizeof(atape));
3186 dbread(ut, ntohl(atape.dump), &adump, sizeof(adump));
3190 /* dump id does not match */
3191 if (ntohl(adump.id) != start)
3195 eval = AddToReturnList(&vollist, va, &toskip);
3196 if (eval == BUDB_LIST2BIG)
3201 if (eval == BUDB_LIST2BIG)
3204 via = vi.sameNameChain;
3209 eval = dbread(ut, via, &vi, sizeof(vi));
3213 } else if (((nameFlags == 0) || (nameFlags == BUDB_OP_TAPENAME))
3214 && (startFlags == BUDB_OP_DUMPID)) {
3219 struct volFragment volFrag;
3222 /* lookup all volumes for a specified dump id */
3224 /* no other flags should be set */
3225 if (endFlags || timeFlags)
3226 ABORT(BUDB_BADFLAGS);
3229 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &dumpAddr, &dump);
3233 /* traverse all the tapes */
3234 for (tapeAddr = ntohl(dump.firstTape); tapeAddr; tapeAddr = ntohl(tape.nextTape)) { /*w */
3235 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
3239 if ((nameFlags != BUDB_OP_TAPENAME)
3240 || ((nameFlags == BUDB_OP_TAPENAME)
3241 && (strcmp(tape.name, name) == 0))) {
3242 /* now return all the volumes */
3243 for (volFragAddr = ntohl(tape.firstVol); volFragAddr;
3244 volFragAddr = ntohl(volFrag.sameTapeChain)) {
3245 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
3249 eval = AddToReturnList(&vollist, volFragAddr, &toskip);
3250 if (eval == BUDB_LIST2BIG)
3256 if (eval == BUDB_LIST2BIG)
3260 ABORT(BUDB_BADFLAGS);
3264 SendReturnList(ut, &vollist, FillVolEntry,
3265 sizeof(struct budb_volumeEntry), index, nextIndexP,
3266 dbTimeP, (returnList_t) volumes);
3271 FreeReturnList(&vollist);
3272 code = ubik_EndTrans(ut);
3276 FreeReturnList(&vollist);
3277 ubik_AbortTrans(ut);
3282 SBUDB_UseTape(struct rx_call *call,
3283 struct budb_tapeEntry *tape, /* tape info */
3284 afs_int32 *new) /* set if tape is new */
3288 code = UseTape(call, tape, new);
3289 osi_auditU(call, BUDB_UseTpeEvent, code, AUD_DATE,
3290 (tape ? tape->dump : 0), AUD_END);
3295 UseTape(struct rx_call *call,
3296 struct budb_tapeEntry *tape, /* tape info */
3297 int *new) /* set if tape is new */
3299 struct ubik_trans *ut;
3303 afs_int32 eval, code;
3305 if (!callPermitted(call))
3306 return BUDB_NOTPERMITTED;
3308 if (strlen(tape->name) >= sizeof(t.name))
3309 return BUDB_BADARGUMENT;
3311 eval = InitRPC(&ut, LOCKWRITE, 1);
3317 memset(&t, 0, sizeof(t));
3318 eval = AllocStructure(ut, tape_BLOCK, 0, &a, &t);
3322 strcpy(t.name, tape->name);
3324 eval = ht_HashIn(ut, &db.tapeName, a, &t);
3330 /* Since deleting a tape may change the dump (if its the same one), read in
3331 * the dump after the call to DeleteTape. */
3333 eval = ht_LookupEntry(ut, &db.dumpIden, &tape->dump, &da, &d);
3337 ABORT(BUDB_NODUMPID);
3340 tape->written = time(0); /* fill in tape struct */
3341 t.written = htonl(tape->written);
3342 t.expires = htonl(tape->expires);
3344 t.seq = htonl(tape->seq);
3345 t.useCount = htonl(tape->useCount);
3346 t.labelpos = htonl(tape->labelpos);
3348 t.flags = htonl(tape->flags | BUDB_TAPE_BEINGWRITTEN);
3350 t.nextTape = d.firstTape; /* Chain the tape to the dump */
3351 d.firstTape = htonl(a);
3353 if (tape->seq >= ntohl(d.tapes.maxTapes)) /* inc # tapes in the dump */
3354 d.tapes.maxTapes = htonl(tape->seq);
3356 eval = dbwrite(ut, a, &t, sizeof(t)); /* write tape struct */
3360 eval = dbwrite(ut, da, &d, sizeof(d)); /* write the dump struct */
3364 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
3368 LogDebug(5, "added tape %s\n", tape->name);
3370 code = ubik_EndTrans(ut);
3374 ubik_AbortTrans(ut);
3380 /* ---------------------------------------------
3381 * debug interface routines
3382 * ---------------------------------------------
3386 SBUDB_T_DumpHashTable(struct rx_call *call, afs_int32 type, char *filename)
3390 code = T_DumpHashTable(call, type, filename);
3391 osi_auditU(call, BUDB_TDmpHaEvent, code, AUD_STR, filename, AUD_END);
3396 T_DumpHashTable(struct rx_call *call, int type, char *filename)
3398 struct ubik_trans *ut;
3399 struct memoryHashTable *mht;
3401 afs_int32 eval, code = 0;
3408 char e[sizeof(struct block)]; /* unnecessarily conservative */
3411 struct volInfo e_volinfo;
3415 if (!callPermitted(call))
3416 return BUDB_NOTPERMITTED;
3418 if (strlen(filename) >= sizeof(path) - 5)
3419 return BUDB_BADARGUMENT;
3421 eval = InitRPC(&ut, LOCKWRITE, 1);
3425 if ((mht = ht_GetType(type, &e_size)) == 0)
3426 return BUDB_BADARGUMENT;
3428 sprintf(path, "%s/%s", gettmpdir(), filename);
3430 DUMP = fopen(path, "w");
3432 ABORT(BUDB_BADARGUMENT);
3435 for (old = 0;; old++) {
3436 length = (old ? mht->oldLength : mht->length);
3438 fprintf(DUMP, "Dumping %sHash Table:\n", (old ? "Old " : ""));
3440 for (hash = 0; hash < length; hash++) {
3441 a = ht_LookupBucket(ut, mht, hash, old);
3444 eval = dbread(ut, a, e, e_size);
3450 fprintf(DUMP, " in bucket %d at %d is ", hash, a);
3452 fprintf(DUMP, " at %d is ", a);
3454 case HT_dumpIden_FUNCTION:
3455 memcpy(&e_dump, e, sizeof(e_dump));
3456 fprintf(DUMP, "%d\n", ntohl(e_dump.id));
3458 case HT_dumpName_FUNCTION:
3459 memcpy(&e_dump, e, sizeof(e_dump));
3460 fprintf(DUMP, "%s\n", e_dump.dumpName);
3462 case HT_tapeName_FUNCTION:
3463 memcpy(&e_tape, e, sizeof(e_tape));
3464 fprintf(DUMP, "%s\n", e_tape.name);
3466 case HT_volName_FUNCTION:
3467 memcpy(&e_volinfo, e, sizeof(e_volinfo));
3468 fprintf(DUMP, "%s\n", e_volinfo.name);
3471 if ((ht_HashEntry(mht, e) % length) != hash)
3472 ABORT(BUDB_DATABASEINCONSISTENT);
3473 a = ntohl(*(dbadr *) (e + mht->threadOffset));
3480 fprintf(DUMP, "%d entries found\n", ent);
3481 if (ntohl(mht->ht->entries) != ent)
3482 ABORT(BUDB_DATABASEINCONSISTENT);
3484 code = ubik_EndTrans(ut);
3490 ubik_AbortTrans(ut);
3497 SBUDB_T_GetVersion(struct rx_call *call, afs_int32 *majorVersion)
3501 code = T_GetVersion(call, majorVersion);
3502 osi_auditU(call, BUDB_TGetVrEvent, code, AUD_END);
3507 T_GetVersion(struct rx_call *call, int *majorVersion)
3509 struct ubik_trans *ut;
3512 code = InitRPC(&ut, LOCKREAD, 0);
3516 *majorVersion = BUDB_MAJORVERSION;
3518 code = ubik_EndTrans(ut);
3522 /* BUDB_T_DumpDatabase
3523 * dump as much of the database as possible int /tmp/<filename>
3527 SBUDB_T_DumpDatabase(struct rx_call *call, char *filename)
3531 code = T_DumpDatabase(call, filename);
3532 osi_auditU(call, BUDB_TDmpDBEvent, code, AUD_STR, filename, AUD_END);
3537 T_DumpDatabase(struct rx_call *call, char *filename)
3541 struct ubik_trans *ut;
3544 int type, old, length, hash;
3545 struct memoryHashTable *mht;
3546 afs_int32 eval, code = 0;
3548 if (!callPermitted(call))
3549 return BUDB_NOTPERMITTED;
3551 path = (char *)malloc(strlen(gettmpdir()) + 1 + strlen(filename) + 1);
3553 return (BUDB_INTERNALERROR);
3555 sprintf(path, "%s/%s", gettmpdir(), filename);
3557 dumpfid = fopen(path, "w");
3559 return (BUDB_BADARGUMENT);
3561 eval = InitRPC(&ut, LOCKWRITE, 1);
3565 /* dump all items in the database */
3566 for (type = 1; type <= HT_MAX_FUNCTION; type++) { /*ft */
3567 mht = ht_GetType(type, &entrySize);
3569 ERROR(BUDB_BADARGUMENT);
3571 for (old = 0; old <= 1; old++) { /*fo */
3572 length = (old ? mht->oldLength : mht->length);
3576 fprintf(dumpfid, "Dumping %s Hash Table:\n", (old ? "Old " : ""));
3578 for (hash = 0; hash < length; hash++) { /*f */
3579 dbAddr = ht_LookupBucket(ut, mht, hash, old);
3581 while (dbAddr) { /*w */
3582 switch (type) { /*s */
3583 case HT_dumpIden_FUNCTION:
3585 struct dump hostDump, diskDump;
3588 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3594 "\ndumpId hash %d, entry at %u\n",
3597 "----------------------------\n");
3598 dump_ntoh(&diskDump, &hostDump);
3599 printDump(dumpfid, &hostDump);
3600 dbAddr = hostDump.idHashChain;
3604 case HT_dumpName_FUNCTION:
3606 struct dump hostDump, diskDump;
3609 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3615 "\ndumpname hash %d, entry at %u\n",
3618 "----------------------------\n");
3619 dump_ntoh(&diskDump, &hostDump);
3620 printDump(dumpfid, &hostDump);
3621 dbAddr = hostDump.nameHashChain;
3625 case HT_tapeName_FUNCTION:
3627 struct tape hostTape, diskTape;
3630 cdbread(ut, tape_BLOCK, dbAddr, &diskTape,
3636 "\ntapename hash %d, entry at %u\n",
3639 "----------------------------\n");
3640 tape_ntoh(&diskTape, &hostTape);
3641 printTape(dumpfid, &hostTape);
3642 dbAddr = hostTape.nameHashChain;
3646 case HT_volName_FUNCTION:
3648 struct volInfo hostVolInfo, diskVolInfo;
3651 cdbread(ut, volInfo_BLOCK, dbAddr,
3652 &diskVolInfo, sizeof(diskVolInfo));
3657 "\nvolname hash %d, entry at %u\n",
3660 "----------------------------\n");
3661 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3662 printVolInfo(dumpfid, &hostVolInfo);
3663 dbAddr = hostVolInfo.nameHashChain;
3665 volFragsDump(ut, dumpfid,
3666 hostVolInfo.firstFragment);
3671 fprintf(dumpfid, "unknown type %d\n", type);
3681 code = ubik_EndTrans(ut); /* is this safe if no ut started ? */
3690 volFragsDump(struct ubik_trans *ut, FILE *dumpfid, dbadr dbAddr)
3692 struct volFragment hostVolFragment, diskVolFragment;
3697 cdbread(ut, volFragment_BLOCK, dbAddr, &diskVolFragment,
3698 sizeof(diskVolFragment));
3699 if (code) { /* don't be fussy about errors */
3700 fprintf(dumpfid, "volFragsDump: Error reading database\n");
3704 fprintf(dumpfid, "\nvolfragment entry at %u\n", dbAddr);
3705 fprintf(dumpfid, "----------------------------\n");
3706 volFragment_ntoh(&diskVolFragment, &hostVolFragment);
3707 printVolFragment(dumpfid, &hostVolFragment);
3708 dbAddr = hostVolFragment.sameNameChain;
3714 /* utilities - network to host conversion
3715 * currently used for debug only
3719 volFragmentDiskToHost(struct volFragment *diskVfPtr,
3720 struct volFragment *hostVfPtr)
3722 hostVfPtr->vol = ntohl(diskVfPtr->vol);
3723 hostVfPtr->sameNameChain = ntohl(diskVfPtr->sameNameChain);
3724 hostVfPtr->tape = ntohl(diskVfPtr->tape);
3725 hostVfPtr->sameTapeChain = ntohl(diskVfPtr->sameTapeChain);
3726 hostVfPtr->position = ntohl(diskVfPtr->position);
3727 hostVfPtr->clone = ntohl(diskVfPtr->clone);
3728 hostVfPtr->incTime = ntohl(diskVfPtr->incTime);
3729 hostVfPtr->startByte = ntohl(diskVfPtr->startByte);
3730 hostVfPtr->nBytes = ntohl(diskVfPtr->nBytes);
3731 hostVfPtr->flags = ntohs(diskVfPtr->flags);
3732 hostVfPtr->sequence = ntohs(diskVfPtr->sequence);
3736 volInfoDiskToHost(struct volInfo *diskViPtr, struct volInfo *hostViPtr)
3738 strcpy(hostViPtr->name, diskViPtr->name);
3739 hostViPtr->nameHashChain = ntohl(diskViPtr->nameHashChain);
3740 hostViPtr->id = ntohl(diskViPtr->id);
3741 strcpy(hostViPtr->server, diskViPtr->server);
3742 hostViPtr->partition = ntohl(diskViPtr->partition);
3743 hostViPtr->flags = ntohl(diskViPtr->flags);
3744 hostViPtr->sameNameHead = ntohl(diskViPtr->sameNameHead);
3745 hostViPtr->sameNameChain = ntohl(diskViPtr->sameNameChain);
3746 hostViPtr->firstFragment = ntohl(diskViPtr->firstFragment);
3747 hostViPtr->nFrags = ntohl(diskViPtr->nFrags);
3751 tapeDiskToHost(struct tape *diskTapePtr, struct tape *hostTapePtr)
3753 strcpy(hostTapePtr->name, diskTapePtr->name);
3754 hostTapePtr->nameHashChain = ntohl(diskTapePtr->nameHashChain);
3755 hostTapePtr->flags = ntohl(diskTapePtr->flags);
3757 /* tape id conversion here */
3758 hostTapePtr->written = ntohl(diskTapePtr->written);
3759 hostTapePtr->nBytes = ntohl(diskTapePtr->nBytes);
3760 hostTapePtr->nFiles = ntohl(diskTapePtr->nFiles);
3761 hostTapePtr->nVolumes = ntohl(diskTapePtr->nVolumes);
3762 hostTapePtr->seq = ntohl(diskTapePtr->seq);
3763 hostTapePtr->dump = ntohl(diskTapePtr->dump);
3764 hostTapePtr->nextTape = ntohl(diskTapePtr->nextTape);
3765 hostTapePtr->firstVol = ntohl(diskTapePtr->firstVol);
3766 hostTapePtr->useCount = ntohl(diskTapePtr->useCount);
3770 dumpDiskToHost(struct dump *diskDumpPtr, struct dump *hostDumpPtr)
3772 hostDumpPtr->id = ntohl(diskDumpPtr->id);
3773 hostDumpPtr->idHashChain = ntohl(diskDumpPtr->idHashChain);
3774 strcpy(hostDumpPtr->dumpName, diskDumpPtr->dumpName);
3775 strcpy(hostDumpPtr->dumpPath, diskDumpPtr->dumpPath);
3776 strcpy(hostDumpPtr->volumeSet, diskDumpPtr->volumeSet);
3777 hostDumpPtr->nameHashChain = ntohl(diskDumpPtr->nameHashChain);
3778 hostDumpPtr->flags = ntohl(diskDumpPtr->flags);
3779 hostDumpPtr->parent = ntohl(diskDumpPtr->parent);
3780 hostDumpPtr->created = ntohl(diskDumpPtr->created);
3781 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3782 hostDumpPtr->nVolumes = ntohl(diskDumpPtr->nVolumes);
3784 /* tapeset conversion here */
3786 hostDumpPtr->firstTape = ntohl(diskDumpPtr->firstTape);
3788 /* principal conversion here */
3794 checkHash(struct ubik_trans *ut, int hashType)
3796 struct memoryHashTable *mhtPtr;
3797 int entrySize, hashTableLength;
3802 mhtPtr = ht_GetType(hashType, &entrySize);
3806 for (old = 0; old < 1; old++) {
3807 LogDebug(5, "\nold = %d\n", old);
3808 printMemoryHashTable(stdout, mhtPtr);
3810 hashTableLength = (old ? mhtPtr->oldLength : mhtPtr->length);
3812 for (bucket = 0; bucket < hashTableLength; bucket++) {
3815 entryAddr = ht_LookupBucket(ut, mhtPtr, bucket, old);
3816 while (entryAddr != 0) {
3817 LogDebug(6, "bucket %d has disk addr %d\n", bucket,
3820 case HT_dumpIden_FUNCTION:
3822 struct dump diskDump, hostDump;
3824 code = dbread(ut, entryAddr, &diskDump, entrySize);
3828 dump_ntoh(&diskDump, &hostDump);
3829 printDump(stdout, &hostDump);
3830 entryAddr = hostDump.idHashChain;
3834 case HT_dumpName_FUNCTION:
3837 case HT_tapeName_FUNCTION:
3840 case HT_volName_FUNCTION:
3842 struct volInfo diskVolInfo, hostVolInfo;
3844 code = dbread(ut, entryAddr, &diskVolInfo, entrySize);
3848 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3849 printVolInfo(stdout, &hostVolInfo);
3850 entryAddr = hostVolInfo.nameHashChain;