1 /* Copyright (C) 1990, 1989 Transarc Corporation - All rights reserved */
3 * (C) COPYRIGHT IBM CORPORATION 1989
4 * LICENSED MATERIALS - PROPERTY OF IBM
8 * ht_lookupEntry - tape ids
9 * Truncate Tape - tape id's
13 #include <afs/param.h>
17 #include <netinet/in.h>
19 #include <sys/param.h>
21 #include <sys/resource.h>
24 #include <sys/types.h>
26 #include <afs/bubasics.h>
35 #include <afs/cellconfig.h>
39 #include "budb_errs.h"
41 #include "error_macros.h"
43 #include "afs/audit.h"
44 #include <afs/afsutil.h>
50 extern struct ubik_dbase *BU_dbase;
51 extern struct afsconf_dir *BU_conf; /* for getting cell info */
52 extern afs_int32 myHost;
53 extern struct memoryDB db; /* incore copies of db structures */
55 afs_int32 AddVolume(), AddVolumes(), CreateDump(), DoDeleteDump(), DoDeleteTape(), ListDumps();
56 afs_int32 DeleteVDP(), FindClone(), FindDump(), FindLatestDump();
57 afs_int32 FinishDump(), FinishTape(), GetDumps(), getExpiration(), T_DumpDatabase();
58 afs_int32 makeAppended(), MakeDumpAppended(), FindLastTape(), GetTapes();
59 afs_int32 GetVolumes(), UseTape(), T_DumpHashTable(), T_GetVersion();
61 /* Text block management */
65 struct memTextBlock *mtb_next; /* next in chain */
66 afs_int32 mtb_nbytes; /* # of bytes in this block */
67 struct blockHeader mtb_blkHeader; /* in memory header */
68 dbadr mtb_addr; /* disk address of block */
71 typedef struct memTextBlock memTextBlockT;
72 typedef memTextBlockT *memTextBlockP;
74 /* These variable are for returning debugging info about the state of the
75 server. If they get trashed during multi-threaded operation it doesn't
78 /* This is global so COUNT_REQ in krb_udp.c can refer to it. */
79 char *lastOperation; /* name of last operation */
80 static Date lastTrans; /* time of last transaction */
82 /* procsInited is sort of a lock: during a transaction only one process runs
83 while procsInited is false. */
85 static int procsInited = 0;
87 /* This variable is protected by the procsInited flag. */
89 static int (*rebuildDatabase)();
91 /* AwaitInitialization
92 * Wait unitl budb has initialized (InitProcs). If it hasn't
93 * within 5 seconds, then return no quorum.
102 if (!start) start = time(0);
103 else if (time(0)-start > 5) return UNOQUORUM;
110 * name is a pathname style name, determine trailing name and return
115 tailCompPtr(pathNamePtr)
119 ptr = rindex(pathNamePtr, '/');
122 /* this should never happen */
123 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
128 ptr++; /* skip the / */
133 * Check to see if the caller is a SuperUser.
140 struct rx_call *call;
143 struct afsconf_dir *acdir;
145 acdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
146 if (!acdir) return 0;
148 if ( afsconf_SuperUser(acdir, call, (char *)0) )
152 if (acdir) afsconf_Close(acdir);
157 * This is called by every RPC interface to create a Ubik transaction
158 * and read the database header into core
164 * sets a lock on byte 1 of the database. Looks like it enforces
165 * single threading by use of the lock.
169 InitRPC (ut, lock, this_op)
170 struct ubik_trans **ut;
171 int lock; /* indicate read/write transaction */
172 int this_op; /* opcode of RCP, for COUNT_ABO */
175 float wait = 0.91; /* start waiting for 1 second */
178 /* wait for server initialization to finish if this is not InitProcs calling */
180 if (code = AwaitInitialization())
183 for (code = UNOQUORUM; code == UNOQUORUM; )
185 code = ubik_BeginTrans(BU_dbase,
186 ((lock == LOCKREAD) ? UBIK_READTRANS : UBIK_WRITETRANS),
188 if (code == UNOQUORUM)
189 { /* no quorum elected */
190 if (wait < 1) Log("Waiting for quorum election\n");
191 if (wait < 15.0) wait *= 1.1;
192 IOMGR_Sleep ((int)wait);
195 if (code) return code;
196 if (wait > 1) Log("Have established quorum\n");
198 /* set lock at posiion 1, for 1 byte of type lock */
199 if (code = ubik_SetLock (*ut, 1, 1, lock))
201 ubik_AbortTrans (*ut);
205 /* check that dbase is initialized and setup cheader */
206 if (lock == LOCKREAD)
208 /* init but don't fix because this is read only */
209 if ( code = CheckInit(*ut, 0) )
211 ubik_AbortTrans(*ut);
212 if ( code = InitRPC(ut, LOCKWRITE, 0) ) /* Now fix the database */
214 LogError(code, "InitRPC: InitRPC failed\n");
217 if ( code = ubik_EndTrans(*ut) )
219 LogError(code, "InitRPC: ubik_EndTrans failed\n");
222 goto start; /* now redo the read transaction */
227 if (code = CheckInit(*ut, rebuildDatabase))
229 ubik_AbortTrans(*ut);
237 /* This is called to initialize a newly created database */
238 static int initialize_database (ut)
239 struct ubik_trans *ut;
244 static int noAuthenticationRequired; /* global state */
245 static int recheckNoAuth; /* global state */
250 struct ubik_trans *ut;
255 if ( (globalConfPtr->myHost == 0) || (BU_conf == 0) )
256 ERROR(BUDB_INTERNALERROR);
260 if ( globalConfPtr->debugFlags & DF_NOAUTH )
261 noAuthenticationRequired = 1;
263 if ( globalConfPtr->debugFlags & DF_RECHECKNOAUTH )
267 noAuthenticationRequired = afsconf_GetNoAuthFlag(BU_conf);
269 if (noAuthenticationRequired)
270 LogError(0, "Running server with security disabled\n");
274 rebuildDatabase = initialize_database;
276 if (code = InitRPC (&ut, LOCKREAD, 0))
278 LogError(code, "InitProcs: InitRPC failed\n");
281 code = ubik_EndTrans(ut);
284 LogError(code, "InitProcs: ubik_EndTrans failed\n");
288 rebuildDatabase = 0; /* only do this during init */
296 int nElements; /* number in list */
297 int allocSize; /* number of elements allocated */
298 dbadr *elements; /* array of addresses */
301 static void InitReturnList (list)
302 struct returnList *list;
306 list->elements = (dbadr *)0;
309 static void FreeReturnList (list)
310 struct returnList *list;
312 if (list->elements) free(list->elements);
313 list->elements = (dbadr *)0;
317 /* As entries are collected, they are added to a return list. Once all
318 * entries have been collected, it is then placed in the return buffer
319 * with SendReturnList(). The first *to_skipP are not recorded.
321 static afs_int32 AddToReturnList (list, a, to_skipP)
322 struct returnList *list;
329 if (a == 0) return 0;
335 /* Up to 5 plus a maximum so SendReturnList() knows if we
336 * need to come back for more.
338 if (list->nElements >= BUDB_MAX_RETURN_LIST+5)
339 return BUDB_LIST2BIG;
341 if (list->nElements >= list->allocSize) {
342 if (list->elements == 0) {
344 tmp = (char *) malloc (sizeof(dbadr) * size);
346 size = list->allocSize + 10;
347 tmp = (char *) realloc (list->elements, sizeof(dbadr) * size);
349 if (!tmp) return BUDB_NOMEM;
350 list->elements = (dbadr *) tmp;
351 list->allocSize = size;
354 list->elements[list->nElements] = a;
359 afs_int32 FillVolEntry(ut, va, vol)
360 struct ubik_trans *ut;
362 struct budb_volumeEntry *vol;
367 struct volFragment vf;
369 if (dbread (ut, va, &vf, sizeof(vf))) return BUDB_IO; /* The volFrag */
370 if (dbread (ut, ntohl(vf.vol), &vi, sizeof(vi))) return BUDB_IO; /* The volInfo */
371 if (dbread (ut, ntohl(vf.tape), &t, sizeof(t))) return BUDB_IO; /* The tape */
372 if (dbread (ut, ntohl(t.dump), &d, sizeof(d))) return BUDB_IO; /* The dump */
374 strcpy (vol->name, vi.name);
375 strcpy (vol->server, vi.server);
376 strcpy (vol->tape, t.name);
377 vol->tapeSeq = ntohl(t.seq);
378 vol->dump = ntohl(d.id);
379 vol->position = ntohl(vf.position);
380 vol->clone = ntohl(vf.clone);
381 vol->incTime = ntohl(vf.incTime);
382 vol->nBytes = ntohl(vf.nBytes);
383 vol->startByte = ntohl(vf.startByte);
384 vol->flags = (ntohs(vf.flags) & VOLFRAGMENTFLAGS); /* low 16 bits here */
385 vol->flags |= (ntohl(vi.flags) & VOLINFOFLAGS); /* high 16 bits here */
386 vol->seq = ntohs(vf.sequence);
387 vol->id = ntohl(vi.id);
388 vol->partition = ntohl(vi.partition);
393 afs_int32 FillDumpEntry (ut, da, dump)
394 struct ubik_trans *ut;
396 struct budb_dumpEntry *dump;
400 if (dbread (ut, da, &d, sizeof(d))) return BUDB_IO;
401 dump->id = ntohl(d.id);
402 dump->flags = ntohl(d.flags);
403 dump->created = ntohl(d.created);
404 strncpy (dump->name, d.dumpName, sizeof(dump->name));
405 strncpy (dump->dumpPath, d.dumpPath, sizeof(dump->dumpPath));
406 strncpy (dump->volumeSetName, d.volumeSet, sizeof(dump->volumeSetName));
408 dump->parent = ntohl(d.parent);
409 dump->level = ntohl(d.level);
410 dump->nVolumes = ntohl(d.nVolumes);
412 tapeSet_ntoh(&d.tapes, &dump->tapes);
414 if (strlen(d.dumper.name) < sizeof(dump->dumper.name))
415 strcpy (dump->dumper.name, d.dumper.name);
416 if (strlen(d.dumper.instance) < sizeof(dump->dumper.instance))
417 strcpy (dump->dumper.instance, d.dumper.instance);
418 if (strlen(d.dumper.cell) < sizeof(dump->dumper.cell))
419 strcpy (dump->dumper.cell, d.dumper.cell);
421 /* Get the initial dumpid and the appended dump id */
422 dump->initialDumpID = ntohl(d.initialDumpID);
423 if (d.appendedDumpChain)
425 if (dbread (ut, ntohl(d.appendedDumpChain), &ad, sizeof(ad))) return BUDB_IO;
426 dump->appendedDumpID = ntohl(ad.id);
429 dump->appendedDumpID = 0;
431 /* printf("dump name %s, parent %d, level %d\n",
432 d.dumpName, ntohl(d.parent), ntohl(d.level)); */
437 afs_int32 FillTapeEntry (ut, ta, tape)
438 struct ubik_trans *ut;
440 struct budb_tapeEntry *tape;
446 if ( dbread (ut, ta, &t, sizeof(t)) )
449 /* Get the tape's expiration date */
450 if ( code = getExpiration(ut,&t) )
453 strcpy (tape->name, t.name);
454 tape->flags = ntohl(t.flags);
455 tape->written = ntohl(t.written);
456 tape->expires = ntohl(t.expires);
457 tape->nMBytes = ntohl(t.nMBytes);
458 tape->nBytes = ntohl(t.nBytes);
459 tape->nFiles = ntohl(t.nFiles);
460 tape->nVolumes = ntohl(t.nVolumes);
461 tape->seq = ntohl(t.seq);
462 tape->labelpos = ntohl(t.labelpos);
463 tape->useCount = ntohl(t.useCount);
464 tape->useKBytes = ntohl(t.useKBytes);
466 if (dbread (ut, ntohl(t.dump), &d, sizeof(d))) return BUDB_IO;
467 tape->dump = ntohl(d.id);
471 #define returnList_t budb_dumpList *
474 * A list of elements of size e_size is in list, collected
475 * with AddToReturnList(). We will move this to a correspoding
476 * return list, eList, via FillProc(). nextInodeP tells us
477 * if there are more and how many to skip on the next request.
480 SendReturnList (ut, list, FillProc, e_size, index, nextIndexP, dbTimeP, eList)
481 struct ubik_trans *ut;
482 struct returnList *list; /* list of elements to return */
483 afs_int32 (*FillProc)(); /* proc to fill entry */
484 int e_size; /* size of each element */
485 afs_int32 index; /* index from previous call */
486 afs_int32 *nextIndexP; /* if more elements are available */
487 afs_int32 *dbTimeP; /* time of last db update */
488 budb_dumpList *eList; /* rxgen list structure (e.g.) */
496 *dbTimeP = ntohl(db.h.lastUpdate);
498 /* Calculate how many to return. Don't let if go over
499 * BUDB_MAX_RETURN_LIST nor the size of our return list.
501 to_return = list->nElements;
502 if (to_return > BUDB_MAX_RETURN_LIST)
503 to_return = BUDB_MAX_RETURN_LIST;
504 if (eList->budb_dumpList_len && (to_return > eList->budb_dumpList_len))
505 to_return = eList->budb_dumpList_len;
507 /* Allocate space for the return values if needed and zero it */
508 if (eList->budb_dumpList_val == 0) {
509 eList->budb_dumpList_val = (struct budb_dumpEntry *)malloc (e_size * to_return);
510 if (!eList->budb_dumpList_val) return(BUDB_NOMEM);
512 bzero(eList->budb_dumpList_val, e_size * to_return);
513 eList->budb_dumpList_len = to_return;
515 e = (char *)(eList->budb_dumpList_val);
516 for (i=0; i<to_return; i++, e += e_size) {
517 code = (*FillProc) (ut, list->elements[i], e);
518 if (code) return code;
521 if (list->nElements > i)
522 *nextIndexP = index + i;
526 /* Come here to delete a volInfo structure. */
528 static afs_int32 DeleteVolInfo (ut, via, vi)
529 struct ubik_trans *ut;
536 if (vi->firstFragment) return 0; /* still some frags, don't free yet */
537 if (vi->sameNameHead == 0) { /* this is the head */
538 if (vi->sameNameChain) return 0; /* empty head, some non-heads left */
540 code = ht_HashOut (ut, &db.volName, via, vi);
541 if (code) return code;
542 code = FreeStructure (ut, volInfo_BLOCK, via);
545 hvia = ntohl(vi->sameNameHead);
546 if (dbread (ut, hvia, &hvi, sizeof(hvi))) return BUDB_IO;
547 code = RemoveFromList (ut, hvia, &hvi, &hvi.sameNameChain, via, vi, &vi->sameNameChain);
548 if (code == -1) return BUDB_DATABASEINCONSISTENT;
549 if (code == 0) code = FreeStructure (ut, volInfo_BLOCK, via);
553 /* Detach a volume fragment from its volInfo structure. Its tape chain is
554 already freed. This routine frees the structure and the caller must not
557 static afs_int32 DeleteVolFragment (ut, va, v)
558 struct ubik_trans *ut;
560 struct volFragment *v;
566 if (dbread (ut, via, &vi, sizeof(vi))) return BUDB_IO;
567 code = RemoveFromList (ut, via, &vi, &vi.firstFragment, va, v, &v->sameNameChain);
568 if (code == -1) return BUDB_DATABASEINCONSISTENT;
569 if (code) return code;
570 if (vi.firstFragment == 0)
571 if (code = DeleteVolInfo (ut, via, &vi)) return code;
572 if (code = FreeStructure (ut, volFragment_BLOCK, va)) return code;
574 /* decrement frag counter */
575 code = set_word_addr (ut, via, &vi, &vi.nFrags, htonl(ntohl(vi.nFrags)-1));
576 if (code) return code;
580 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
581 * The caller will remove it from the hash table if necessary. The caller is
582 * also responsible for writing the tape out if necessary. */
584 static afs_int32 DeleteTape (ut, ta, t)
585 struct ubik_trans *ut;
593 if (da == 0) return BUDB_DATABASEINCONSISTENT;
594 if (dbread (ut, da, &d, sizeof(d))) return BUDB_IO;
595 if (d.firstTape == 0) return BUDB_DATABASEINCONSISTENT;
597 code = RemoveFromList (ut, da, &d, &d.firstTape, ta, t, &t->nextTape);
598 if (code == -1) return BUDB_DATABASEINCONSISTENT;
599 if (code) return code;
601 /* Since the tape should have been truncated there should never be any
602 * volumes in the tape. */
603 if (t->firstVol || t->nVolumes) return BUDB_DATABASEINCONSISTENT;
609 DeleteDump (ut, da, d)
610 struct ubik_trans *ut;
616 code = ht_HashOut (ut, &db.dumpIden, da, d);
617 if (code) ERROR(code);
619 code = ht_HashOut (ut, &db.dumpName, da, d);
620 if (code) ERROR(code);
622 /* Since the tape should have been truncated this should never happen. */
623 if (d->firstTape || d->nVolumes) ERROR(BUDB_DATABASEINCONSISTENT);
625 code = FreeStructure (ut, dump_BLOCK, da);
626 if (code) ERROR(code);
635 * This is called with a volumeEntry and a volInfo structure and compares
636 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
637 * search volInfo structures once it has the head volInfo structure from the
638 * volName hash table.
640 * When called from GetVolInfo the name compare is redundant.
641 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
644 static int VolInfoMatch (vol, vi)
645 struct budb_volumeEntry *vol;
648 return ( (strcmp (vol->name, vi->name) == 0) && /* same volume name */
649 (vol->id == ntohl(vi->id)) && /* same volume id */
650 ((vol->flags & VOLINFOFLAGS) ==
651 (ntohl(vi->flags) & VOLINFOFLAGS)) && /* same flags */
652 (vol->partition == ntohl(vi->partition)) && /* same partition (N/A)*/
653 (strcmp (vol->server, vi->server) == 0) ); /* same server (N/A) */
658 * This routine takes a volumeEntry structure from an RPC interface and
659 * returns the corresponding volInfo structure, creating it if necessary.
661 * The caller must write the entry out.
664 static afs_int32 GetVolInfo (ut, volP, viaP, viP)
665 struct ubik_trans *ut;
666 struct budb_volumeEntry *volP;
672 afs_int32 eval, code = 0;
674 eval = ht_LookupEntry (ut, &db.volName, volP->name, &via, viP);
675 if (eval) ERROR(eval);
679 /* allocate a new volinfo structure */
680 eval = AllocStructure (ut, volInfo_BLOCK, 0, &via, viP);
681 if (eval) ERROR(eval);
683 strcpy (viP->name, volP->name);
684 strcpy (viP->server, volP->server);
685 viP->sameNameHead = 0; /* The head of same name chain */
686 viP->sameNameChain = 0; /* Same name chain is empty */
687 viP->firstFragment = 0;
689 viP->id = htonl(volP->id);
690 viP->partition = htonl(volP->partition);
691 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
693 /* Chain onto volname hash table */
694 eval = ht_HashIn (ut, &db.volName, via, viP);
695 if (eval) ERROR(eval);
697 LogDebug(4, "volume Info for %s placed at %d\n", db.volName, via);
700 else if ( !VolInfoMatch(volP,viP) ) /* Not the head volinfo struct */
702 hvia = via; /* remember the head volinfo struct */
703 bcopy(viP, &hvi, sizeof(hvi));
705 /* Search the same name chain for the correct volinfo structure */
706 for (via=ntohl(viP->sameNameChain); via; via=ntohl(viP->sameNameChain))
708 eval = dbread (ut, via, viP, sizeof(*viP));
709 if (eval) ERROR(eval);
711 if ( VolInfoMatch(volP,viP) ) break; /* found the one */
714 /* if the correct volinfo struct isn't found, create one */
717 eval = AllocStructure (ut, volInfo_BLOCK, 0, &via, viP);
718 if (eval) ERROR(eval);
720 strcpy (viP->name, volP->name);
721 strcpy (viP->server, volP->server);
722 viP->nameHashChain = 0; /* not in hash table */
723 viP->sameNameHead = htonl(hvia); /* chain to head of sameNameChain */
724 viP->sameNameChain = hvi.sameNameChain;
725 viP->firstFragment = 0;
727 viP->id = htonl(volP->id);
728 viP->partition = htonl(volP->partition);
729 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
731 /* write the head entry's sameNameChain link */
732 eval = set_word_addr (ut, hvia, &hvi, &hvi.sameNameChain, htonl(via));
733 if (eval) ERROR(eval);
743 /* deletesomevolumesfromtape
744 * Deletes a specified number of volumes from a tape. The tape
745 * and dump are modified to reflect the smaller number of volumes.
746 * The transaction is not terminated, it is up to the caller to
747 * finish the transaction and start a new one (if desired).
749 * maxvolumestodelete - don't delete more than this many volumes
753 deleteSomeVolumesFromTape(ut, tapeAddr, tapePtr, maxVolumesToDelete)
754 struct ubik_trans *ut;
756 struct tape *tapePtr;
757 int maxVolumesToDelete;
759 dbadr volFragAddr, nextVolFragAddr, dumpAddr;
760 struct volFragment volFrag;
762 int volumesDeleted = 0;
763 afs_int32 eval, code = 0;
765 if (!tapePtr) ERROR(0);
767 for (volFragAddr=ntohl(tapePtr->firstVol); (volFragAddr && (maxVolumesToDelete > 0));
768 volFragAddr=nextVolFragAddr)
770 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
771 if (eval) ERROR(eval);
773 nextVolFragAddr = ntohl(volFrag.sameTapeChain);
775 eval = DeleteVolFragment(ut, volFragAddr, &volFrag);
776 if (eval) ERROR(eval);
778 maxVolumesToDelete--;
782 /* reset the volume fragment pointer in the tape */
783 tapePtr->firstVol = htonl(volFragAddr);
785 /* diminish the tape's volume count */
786 tapePtr->nVolumes = htonl(ntohl(tapePtr->nVolumes) - volumesDeleted);
788 eval = dbwrite(ut, tapeAddr, tapePtr, sizeof(*tapePtr));
789 if (eval) ERROR(eval);
791 /* diminish the dump's volume count */
792 dumpAddr = ntohl(tapePtr->dump);
793 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
794 if (eval) ERROR(eval);
796 dump.nVolumes = htonl(ntohl(dump.nVolumes) - volumesDeleted);
797 eval = dbwrite(ut, dumpAddr, &dump, sizeof(dump));
798 if (eval) ERROR(eval);
805 * deletes a dump in stages, by repeatedly deleting a small number of
806 * volumes from the dump until none are left. The dump is then deleted.
808 * In the case where multiple calls are made to delete the same
809 * dump, the operation will succeed but contention for structures
810 * will result in someone getting back an error.
813 * id - id of dump to delete
817 deleteDump(call, id, dumps)
818 struct rx_call *call;
820 budb_dumpsList *dumps;
822 struct ubik_trans *ut;
823 dbadr dumpAddr, tapeAddr, appendedDump;
828 afs_int32 eval, code = 0;
831 /* iterate until the dump is truly deleted */
839 eval = InitRPC(&ut, LOCKWRITE, 1);
840 if (eval) ERROR(eval); /* can't start transaction */
842 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpid, &dumpAddr, &dump);
843 if (eval) ABORT(eval);
844 if (!dumpAddr) ABORT(BUDB_NOENT); /* can't find dump */
846 if ( (dumpid == id) && (dump.initialDumpID) ) /* can't be an appended dump */
847 ABORT(BUDB_NOTINITIALDUMP);
849 tapeAddr = ntohl(dump.firstTape);
850 if (tapeAddr == 0) break;
852 /* there is a tape to delete */
853 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
854 if (eval) ABORT(eval);
856 if ( ntohl(tape.nVolumes) )
858 /* tape is not empty */
859 eval = deleteSomeVolumesFromTape(ut, tapeAddr, &tape, 10);
860 if (eval) ABORT(eval);
863 if ( ntohl(tape.nVolumes) == 0 )
865 /* tape is now empty, delete it */
866 eval = DeleteTape(ut, tapeAddr, &tape);
867 if (eval) ABORT(eval);
868 eval = ht_HashOut(ut, &db.tapeName, tapeAddr, &tape);
869 if (eval) ABORT(eval);
870 eval = FreeStructure(ut, tape_BLOCK, tapeAddr);
871 if (eval) ABORT(eval);
874 eval = ubik_EndTrans(ut);
875 if (eval) ERROR(eval);
877 } /* next deletion portion */
879 /* Record the dump just deleted */
880 if (dumps && (dumps->budb_dumpsList_len < BUDB_MAX_RETURN_LIST))
882 if (dumps->budb_dumpsList_len == 0)
883 dumps->budb_dumpsList_val = (afs_int32 *) malloc(sizeof(afs_int32));
885 dumps->budb_dumpsList_val =
886 (afs_int32 *) realloc(dumps->budb_dumpsList_val,
887 (dumps->budb_dumpsList_len+1)*sizeof(afs_int32));
889 if ( !dumps->budb_dumpsList_val ) ABORT(BUDB_NOMEM);
891 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = dumpid;
892 dumps->budb_dumpsList_len++;
895 appendedDump = ntohl(dump.appendedDumpChain);
897 /* finally done. No more tapes left in the dump. Delete the dump itself */
898 eval = DeleteDump(ut, dumpAddr, &dump);
899 if (eval) ABORT(eval);
901 /* Now delete the appended dump too */
904 eval = dbread(ut, appendedDump, &dump, sizeof(dump));
905 if (eval) ABORT(eval);
907 dumpid = ntohl(dump.id);
912 eval = ubik_EndTrans(ut);
913 if (eval) ERROR(eval);
915 Log("Delete dump %s (DumpID %u), path %s\n",
916 dump.dumpName, ntohl(dump.id), dump.dumpPath);
920 if (code && partialDel) {
921 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
922 dump.dumpName, ntohl(dump.id), dump.dumpPath, code);
932 * dump selection routines - used by BUDB_GetDumps
936 /* most recent dump selection */
940 struct chosenDump *next;
947 int maxDumps; /* max wanted */
948 int ndumps; /* actual in chain */
949 struct chosenDump *chain;
953 wantDump(dumpAddrParam, dumpParam, dumpListPtrParam)
956 char *dumpListPtrParam;
959 struct dump *dumpPtr;
960 struct wantDumpRock *rockPtr;
962 dumpAddr = (dbadr) dumpAddrParam;
963 dumpPtr = (struct dump *) dumpParam;
964 rockPtr = (struct wantDumpRock *) dumpListPtrParam;
966 /* if we don't have our full complement, just add another */
967 if ( rockPtr->ndumps < rockPtr->maxDumps )
970 /* got the number we need, select based on date */
971 if ( (afs_uint32) ntohl(dumpPtr->created) > rockPtr->chain->date )
977 rememberDump(dumpAddrParam, dumpParam, dumpListPtrParam)
980 char *dumpListPtrParam;
983 struct dump *dumpPtr;
984 struct wantDumpRock *rockPtr;
985 struct chosenDump *ptr, *deletedPtr, **nextPtr;
987 dumpAddr = (dbadr) dumpAddrParam;
988 dumpPtr = (struct dump *) dumpParam;
989 rockPtr = (struct wantDumpRock *) dumpListPtrParam;
991 ptr = (struct chosenDump *) malloc(sizeof(*ptr));
994 bzero(ptr, sizeof(*ptr));
995 ptr->addr = dumpAddr;
996 ptr->date = (afs_uint32) ntohl(dumpPtr->created);
998 /* Don't overflow the max */
999 while (rockPtr->ndumps >= rockPtr->maxDumps) {
1000 /* have to drop one */
1001 deletedPtr = rockPtr->chain;
1002 rockPtr->chain = deletedPtr->next;
1007 /* now insert in the right place */
1008 for (nextPtr = &rockPtr->chain; *nextPtr; nextPtr = &((*nextPtr)->next)) {
1009 if (ptr->date < (*nextPtr)->date)
1012 ptr->next = *nextPtr;
1020 /* ---------------------------------------------
1021 * general interface routines - alphabetic
1022 * ---------------------------------------------
1025 afs_int32 BUDB_AddVolume (call, vol)
1026 struct rx_call *call;
1027 struct budb_volumeEntry *vol;
1031 code = AddVolume (call, vol);
1032 osi_auditU (call, BUDB_AddVolEvent, code, AUD_LONG, (vol ? vol->id : 0), AUD_END);
1036 afs_int32 AddVolume (call, vol)
1037 struct rx_call *call;
1038 struct budb_volumeEntry *vol;
1040 struct ubik_trans *ut;
1041 dbadr da, ta, via, va;
1045 struct volFragment v;
1047 afs_int32 eval, code = 0;
1049 if ( !callPermitted(call) )
1050 return BUDB_NOTPERMITTED;
1052 if ( ( strlen(vol->name) >= sizeof(vi.name) ) ||
1053 ( strlen(vol->server) >= sizeof(vi.server) ) ||
1054 ( strlen(vol->tape) >= sizeof(t.name) ) )
1055 return BUDB_BADARGUMENT;
1057 eval = InitRPC (&ut, LOCKWRITE, 1);
1058 if (eval) return eval;
1060 /* Find the dump in dumpid hash table */
1061 eval = ht_LookupEntry (ut, &db.dumpIden, &vol->dump, &da, &d);
1062 if (eval) ABORT(eval);
1063 if (!da) ABORT(BUDB_NODUMPID);
1065 /* search for the right tape in the dump */
1066 for (ta=ntohl(d.firstTape); ta; ta=ntohl(t.nextTape))
1068 /* read the tape entry */
1069 eval = dbread(ut, ta, &t, sizeof(t));
1070 if (eval) ABORT(eval);
1072 /* Check if the right tape name */
1073 if ( strcmp(t.name, vol->tape) == 0 )
1076 if (!ta) ABORT(BUDB_NOTAPENAME);
1078 if ( (t.dump != htonl(da)) || /* tape must belong to dump */
1079 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1080 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0) ) /* dump must be in progress */
1081 ABORT(BUDB_BADPROTOCOL);
1083 /* find or create a volume info structure */
1084 eval = GetVolInfo(ut, vol, &via, &vi);
1085 if (eval) ABORT(eval);
1087 /* Create a volume fragment */
1088 eval = AllocStructure (ut, volFragment_BLOCK, 0, &va, &v);
1089 if (eval) ABORT(eval);
1091 v.vol = htonl(via); /* vol frag points to vol info */
1092 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1093 vi.firstFragment = htonl(va);
1094 vi.nFrags = htonl(ntohl(vi.nFrags)+1);
1096 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1097 if (eval) ABORT(eval);
1099 v.tape = htonl(ta); /* vol frag points to tape */
1100 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1101 t.firstVol = htonl(va);
1102 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1103 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1104 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes/(1024*1024));
1105 t.nBytes = htonl(bytes % (1024*1024));
1107 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1108 if (eval) ABORT(eval);
1110 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1112 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1113 if (eval) ABORT(eval);
1115 v.position = htonl(vol->position); /* vol frag info */
1116 v.clone = htonl(vol->clone);
1117 v.incTime = htonl(vol->incTime);
1118 v.startByte = htonl(vol->startByte);
1119 v.nBytes = htonl(vol->nBytes);
1120 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1121 v.sequence = htons(vol->seq);
1123 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1124 if (eval) ABORT(eval);
1126 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1127 if (eval) ABORT(eval);
1129 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1131 code = ubik_EndTrans(ut);
1135 ubik_AbortTrans(ut);
1140 afs_int32 BUDB_AddVolumes (call, vols)
1141 struct rx_call *call;
1142 struct budb_volumeList *vols;
1146 code = AddVolumes (call, vols);
1147 osi_auditU (call, BUDB_AddVolEvent, code, AUD_LONG, 0, AUD_END);
1151 afs_int32 AddVolumes (call, vols)
1152 struct rx_call *call;
1153 struct budb_volumeList *vols;
1155 struct budb_volumeEntry *vol, *vol1;
1156 struct ubik_trans *ut;
1157 dbadr da, ta, via, va;
1161 struct volFragment v;
1163 afs_int32 eval, e, code = 0;
1165 if ( !callPermitted(call) )
1166 return BUDB_NOTPERMITTED;
1168 if (!vols || (vols->budb_volumeList_len <= 0) || !vols->budb_volumeList_val)
1169 return BUDB_BADARGUMENT;
1171 /* The first volume in the list of volumes to add */
1172 vol1 = (struct budb_volumeEntry *)vols->budb_volumeList_val;
1174 eval = InitRPC (&ut, LOCKWRITE, 1);
1175 if (eval) return eval;
1177 /* Find the dump in dumpid hash table */
1178 eval = ht_LookupEntry (ut, &db.dumpIden, &vol1->dump, &da, &d);
1179 if (eval) ABORT(eval);
1180 if (!da) ABORT(BUDB_NODUMPID);
1182 /* search for the right tape in the dump */
1183 for (ta=ntohl(d.firstTape); ta; ta=ntohl(t.nextTape)) {
1184 /* read the tape entry */
1185 eval = dbread(ut, ta, &t, sizeof(t));
1186 if (eval) ABORT(eval);
1188 /* Check if the right tape name */
1189 if ( strcmp(t.name, vol1->tape) == 0 )
1192 if (!ta) ABORT(BUDB_NOTAPENAME);
1194 if ( (t.dump != htonl(da)) || /* tape must belong to dump */
1195 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1196 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0) ) /* dump must be in progress */
1197 ABORT(BUDB_BADPROTOCOL);
1199 for (vol=vol1, e=0; e < vols->budb_volumeList_len; vol++, e++) {
1201 if ( ( strlen(vol->name) >= sizeof(vi.name) ) ||
1202 ( strcmp(vol->name, "") == 0 ) || /* no null volnames */
1203 ( strlen(vol->server) >= sizeof(vi.server) ) ||
1204 ( strlen(vol->tape) >= sizeof(t.name) ) ||
1205 ( strcmp(vol->tape, vol1->tape) != 0 ) ) {
1206 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n",
1207 vol->name, vol->id, vol->tape, vol->dump);
1211 /* find or create a volume info structure */
1212 eval = GetVolInfo(ut, vol, &via, &vi);
1213 if (eval) ABORT(eval);
1214 if (*(afs_int32 *)(&vi) == 0) {
1215 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n",
1216 vol->name, vol->tape, vol->dump);
1217 ABORT(BUDB_BADARGUMENT);
1220 /* Create a volume fragment */
1221 eval = AllocStructure (ut, volFragment_BLOCK, 0, &va, &v);
1222 if (eval) ABORT(eval);
1224 v.vol = htonl(via); /* vol frag points to vol info */
1225 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1226 vi.firstFragment = htonl(va);
1227 vi.nFrags = htonl(ntohl(vi.nFrags)+1);
1228 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1229 if (eval) ABORT(eval);
1231 v.tape = htonl(ta); /* vol frag points to tape */
1232 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1233 t.firstVol = htonl(va);
1234 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1235 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1236 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes/(1024*1024));
1237 t.nBytes = htonl(bytes % (1024*1024));
1239 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1241 v.position = htonl(vol->position); /* vol frag info */
1242 v.clone = htonl(vol->clone);
1243 v.incTime = htonl(vol->incTime);
1244 v.startByte = htonl(vol->startByte);
1245 v.nBytes = htonl(vol->nBytes);
1246 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1247 v.sequence = htons(vol->seq);
1249 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1250 if (eval) ABORT(eval);
1252 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1255 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1256 if (eval) ABORT(eval);
1258 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1259 if (eval) ABORT(eval);
1261 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1262 if (eval) ABORT(eval);
1264 code = ubik_EndTrans(ut);
1268 ubik_AbortTrans(ut);
1274 * records the existence of a dump in the database. This creates only
1275 * the dump record, to which one must attach tape and volume records.
1277 * 1) record the volume set
1280 afs_int32 BUDB_CreateDump(call, dump)
1281 struct rx_call *call;
1282 struct budb_dumpEntry *dump;
1286 code = CreateDump(call, dump);
1287 osi_auditU (call, BUDB_CrDmpEvent, code, AUD_DATE, (dump ? dump->id : 0), AUD_END);
1288 if (dump && !code) {
1289 Log("Create dump %s (DumpID %u), path %s\n",
1290 dump->name, dump->id, dump->dumpPath);
1295 afs_int32 CreateDump(call, dump)
1296 struct rx_call *call;
1297 struct budb_dumpEntry *dump;
1299 struct ubik_trans *ut;
1300 dbadr findDumpAddr, da;
1301 struct dump findDump, d;
1302 afs_int32 eval, code = 0;
1306 Date expiration; /* checked by Security Module */
1307 struct ktc_principal principal;
1309 if ( !callPermitted(call) )
1310 return BUDB_NOTPERMITTED;
1312 if (strlen(dump->name) >= sizeof(d.dumpName))
1313 return BUDB_BADARGUMENT;
1315 eval = InitRPC (&ut, LOCKWRITE, 1);
1316 if (eval) return eval;
1318 eval = rxkad_GetServerInfo( rx_ConnectionOf(call),
1319 &level, &expiration,
1327 if (eval != RXKADNOAUTH) ABORT(eval);
1329 strcpy(principal.name, "");
1330 strcpy(principal.instance, "");
1331 strcpy(principal.cell, "");
1336 /* authenticated. Take user supplied principal information */
1337 if ( strcmp(dump->dumper.name, "") != 0 )
1338 strncpy(principal.name, dump->dumper.name, sizeof(principal.name));
1340 if ( strcmp(dump->dumper.instance, "") != 0 )
1341 strncpy(principal.instance, dump->dumper.instance, sizeof(principal.instance));
1343 if ( strcmp(dump->dumper.cell, "") != 0 )
1344 strncpy(principal.cell, dump->dumper.cell, sizeof(principal.cell));
1347 /* dump id's are time stamps */
1350 while (1) /* allocate a unique dump id */
1354 /* ensure it is unique - seach for dumpid in hash table */
1355 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr, &findDump);
1356 if (eval) ABORT(eval);
1358 if (!findDumpAddr) /* dumpid not in use */
1360 /* update the last dump id allocated */
1361 eval = set_header_word(ut, lastDumpId, htonl(dump->id));
1362 if (eval) ABORT(eval);
1366 /* dump id is in use - wait a while */
1372 /* dump id supplied (e.g. for database restore) */
1373 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr, &findDump);
1374 if (eval) ABORT(eval);
1376 /* Dump id must not already exist */
1377 if (findDumpAddr) ABORT(BUDB_DUMPIDEXISTS);
1380 /* Allocate a dump structure */
1381 bzero (&d, sizeof(d));
1382 eval = AllocStructure (ut, dump_BLOCK, 0, &da, &d);
1383 if (eval) ABORT(eval);
1385 strcpy(d.dumpName, dump->name); /* volset.dumpname */
1386 strcpy(d.dumpPath, dump->dumpPath); /* dump node path */
1387 strcpy(d.volumeSet, dump->volumeSetName); /* volume set */
1388 d.id = htonl(dump->id);
1389 d.parent = htonl(dump->parent); /* parent id */
1390 d.level = htonl(dump->level);
1392 LogDebug(4, "dump name %s, parent %d level %d\n", dump->name, dump->parent, dump->level);
1394 /* if creation time specified, use that. Else use the dumpid time */
1395 if (dump->created == 0) dump->created = dump->id;
1396 d.created = htonl(dump->created);
1398 principal_hton(&principal, &d.dumper);
1399 tapeSet_hton(&dump->tapes, &d.tapes);
1401 d.flags = htonl(dump->flags | BUDB_DUMP_INPROGRESS);
1403 eval = ht_HashIn (ut, &db.dumpName, da, &d); /* Into dump name hash table */
1404 if (eval) ABORT(eval);
1406 eval = ht_HashIn (ut, &db.dumpIden, da, &d); /* Into dumpid hash table */
1407 if (eval) ABORT(eval);
1409 eval = dbwrite (ut, da, (char *)&d, sizeof(d)); /* Write the dump structure */
1410 if (eval) ABORT(eval);
1412 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
1413 if (eval) ABORT(eval);
1415 /* If to append this dump, then append it - will write the appended dump */
1416 eval = makeAppended(ut, dump->id, dump->initialDumpID, dump->tapes.b);
1417 if (eval) ABORT(eval);
1419 code = ubik_EndTrans(ut);
1420 LogDebug(5, "made dump %s, path %s\n", d.dumpName, d.dumpPath);
1424 ubik_AbortTrans(ut);
1428 afs_int32 BUDB_DeleteDump (call, id, fromTime, toTime, dumps)
1429 struct rx_call *call;
1433 budb_dumpsList *dumps;
1437 code = DoDeleteDump (call, id, fromTime, toTime, dumps);
1438 osi_auditU (call, BUDB_DelDmpEvent, code, AUD_DATE, id, AUD_END);
1444 afs_int32 DoDeleteDump (call, id, fromTime, toTime, dumps)
1445 struct rx_call *call;
1449 budb_dumpsList *dumps;
1453 if ( !callPermitted(call) )
1454 return BUDB_NOTPERMITTED;
1456 if (id) code = deleteDump(call, id, dumps);
1460 afs_int32 BUDB_ListDumps (call, sflags, name, groupid, fromTime, toTime, dumps, flags)
1461 struct rx_call *call;
1462 afs_int32 sflags, groupid;
1464 Date fromTime, toTime;
1465 budb_dumpsList *dumps, *flags;
1469 code = ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags);
1470 osi_auditU (call, BUDB_LstDmpEvent, code, AUD_LONG, flags, AUD_END);
1474 afs_int32 ListDumps (call, sflags, groupid, fromTime, toTime, dumps, flags)
1475 struct rx_call *call;
1476 afs_int32 sflags, groupid;
1477 Date fromTime, toTime;
1478 budb_dumpsList *dumps, *flags;
1480 struct ubik_trans *ut;
1481 struct memoryHashTable *mht;
1482 struct dump diskDump, appDiskDump;
1483 dbadr dbAddr, dbAppAddr;
1485 afs_int32 eval, code = 0;
1486 int old, hash, length, entrySize, j, k, count=0;
1487 afs_uint32 toList, toFlag;
1489 if ( !callPermitted(call) )
1490 return BUDB_NOTPERMITTED;
1492 eval= InitRPC (&ut, LOCKREAD, 1);
1493 if (eval) return(eval);
1495 /* Search the database */
1496 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
1497 if (!mht) return(BUDB_BADARGUMENT);
1499 for (old=0; old<=1; old++) { /*o*/ /* old and new hash tables */
1500 length = (old ? mht->oldLength : mht->length);
1501 if (length == 0) continue;
1503 for (hash=0; hash<length; hash++) { /*h*/ /* for each hash bucket */
1504 for (dbAddr = ht_LookupBucket(ut,mht,hash,old); dbAddr;
1505 dbAddr = ntohl(diskDump.idHashChain)) { /*d*/
1507 /* read the entry */
1508 eval = dbread (ut, dbAddr, &diskDump, sizeof(diskDump));
1509 if (eval) ABORT(eval);
1511 /* Skip appended dumps */
1512 if (ntohl(diskDump.initialDumpID) != 0) {
1516 /* Skip dumps with different goup id */
1517 if ((sflags & BUDB_OP_GROUPID) && (ntohl(diskDump.tapes.id) != groupid)) {
1521 /* Look at this dump to see if it meets the criteria for listing */
1522 if (sflags & BUDB_OP_DATES) {
1523 /* This and each appended dump should be in time */
1524 for (dbAppAddr=dbAddr; dbAppAddr; dbAppAddr=ntohl(appDiskDump.appendedDumpChain)) {
1525 eval = dbread (ut, dbAppAddr, &appDiskDump, sizeof(appDiskDump));
1526 if (eval) ABORT(eval);
1528 if ((ntohl(appDiskDump.id) < fromTime) || (ntohl(appDiskDump.id) > toTime))
1531 if (dbAppAddr) continue; /*nope*/
1534 /* Add it and each of its appended dump to our list to return */
1535 for (dbAppAddr=dbAddr; dbAppAddr; dbAppAddr=ntohl(appDiskDump.appendedDumpChain)) {
1536 eval = dbread (ut, dbAppAddr, &appDiskDump, sizeof(appDiskDump));
1537 if (eval) ABORT(eval);
1539 /* Make sure we have space to list it */
1540 if (dumps->budb_dumpsList_len >= count) {
1543 dumps->budb_dumpsList_val = (afs_int32 *)malloc(count * sizeof(afs_int32));
1544 flags->budb_dumpsList_val = (afs_int32 *)malloc(count * sizeof(afs_int32));
1546 dumps->budb_dumpsList_val =
1547 (afs_int32 *)realloc(dumps->budb_dumpsList_val, count*sizeof(afs_int32));
1548 flags->budb_dumpsList_val =
1549 (afs_int32 *)realloc(flags->budb_dumpsList_val, count*sizeof(afs_int32));
1551 if (!dumps->budb_dumpsList_val || !dumps->budb_dumpsList_val)
1555 /* Add it to our list */
1556 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = ntohl(appDiskDump.id);
1557 flags->budb_dumpsList_val[flags->budb_dumpsList_len] = 0;
1558 if ( ntohl(appDiskDump.initialDumpID) != 0 ) {
1559 flags->budb_dumpsList_val[flags->budb_dumpsList_len] |= BUDB_OP_APPDUMP;
1561 if (strcmp(appDiskDump.dumpName,DUMP_TAPE_NAME) == 0) {
1562 flags->budb_dumpsList_val[flags->budb_dumpsList_len] |= BUDB_OP_DBDUMP;
1564 dumps->budb_dumpsList_len++;
1565 flags->budb_dumpsList_len++;
1571 code = ubik_EndTrans(ut);
1575 ubik_AbortTrans(ut);
1579 afs_int32 BUDB_DeleteTape (call, tape)
1580 struct rx_call *call;
1581 struct budb_tapeEntry *tape; /* tape info */
1585 code = DoDeleteTape (call, tape);
1586 osi_auditU (call, BUDB_DelTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
1590 afs_int32 DoDeleteTape (call, tape)
1591 struct rx_call *call;
1592 struct budb_tapeEntry *tape; /* tape info */
1594 struct ubik_trans *ut;
1597 afs_int32 eval, code;
1599 if ( !callPermitted(call) )
1600 return BUDB_NOTPERMITTED;
1602 eval = InitRPC (&ut, LOCKWRITE, 1);
1603 if (eval) return eval;
1605 eval = ht_LookupEntry (ut, &db.tapeName, tape->name, &a, &t);
1606 if (eval) ABORT(eval);
1608 eval = DeleteTape (ut, a, &t);
1609 if (eval) ABORT(eval);
1611 eval = FreeStructure (ut, tape_BLOCK, a);
1612 if (eval) ABORT(eval);
1614 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
1615 if (eval) ABORT(eval);
1617 code = ubik_EndTrans(ut);
1621 ubik_AbortTrans(ut);
1626 * Deletes old information from the database for a particular dump path
1627 * and volumset. This supercedes the old policy implemented in
1628 * UseTape, which simply matched on the volumeset.dump. Consequently
1629 * it was unable to handle name re-use.
1631 * dsname - dumpset name, i.e. volumeset.dumpname
1632 * dumpPath - full path of dump node
1633 * curDumpID - current dump in progress - so that is may be excluded
1636 * n - some error. May or may not have deleted information.
1639 afs_int32 BUDB_DeleteVDP (call, dsname, dumpPath, curDumpId)
1640 struct rx_call *call;
1643 afs_int32 curDumpId;
1647 code = DeleteVDP (call, dsname, dumpPath, curDumpId);
1648 osi_auditU (call, BUDB_DelVDPEvent, code, AUD_STR, dsname, AUD_END);
1652 afs_int32 DeleteVDP (call, dsname, dumpPath, curDumpId)
1653 struct rx_call *call;
1656 afs_int32 curDumpId;
1661 struct ubik_trans *ut;
1662 afs_int32 eval, code = 0;
1664 if ( !callPermitted(call) )
1665 return BUDB_NOTPERMITTED;
1669 eval = InitRPC (&ut, LOCKREAD, 1);
1670 if (eval) return(eval);
1672 eval = ht_LookupEntry(ut, &db.dumpName, dsname, &dumpAddr, &dump);
1673 if (eval) ABORT(eval);
1675 while ( dumpAddr != 0 )
1677 if ( (strcmp(dump.dumpName, dsname) == 0) &&
1678 (strcmp(dump.dumpPath, dumpPath) == 0) &&
1679 (ntohl(dump.id) != curDumpId) )
1681 eval = ubik_EndTrans(ut);
1682 if (eval) return(eval);
1684 eval = deleteDump(call, ntohl(dump.id), 0);
1685 if (eval) return(eval);
1687 /* start the traversal over since the various chains may
1693 dumpAddr = ntohl(dump.nameHashChain);
1696 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
1697 if (eval) ABORT(eval);
1701 /* check if all the dumps have been examined - can terminate */
1704 eval = ubik_EndTrans(ut);
1710 ubik_AbortTrans(ut);
1716 * Given a volume name, and a dumpID, find the volume in that dump and
1717 * return the clone date of the volume (this is the clone date of the
1718 * volume at the time it was dumped).
1720 * Hashes on the volume name and traverses the fragments. Will need to read
1721 * the volumes tape entry to determine if it belongs to the dump. If the
1722 * volume is not found in the dump, then look for it in its parent dump.
1725 afs_int32 BUDB_FindClone(call, dumpID, volName, clonetime)
1726 struct rx_call *call;
1729 afs_int32 *clonetime;
1733 code = FindClone (call, dumpID, volName, clonetime);
1734 osi_auditU (call, BUDB_FndClnEvent, code, AUD_STR, volName, AUD_END);
1738 afs_int32 FindClone (call, dumpID, volName, clonetime)
1739 struct rx_call *call;
1742 afs_int32 *clonetime;
1744 struct ubik_trans *ut;
1745 dbadr da, ta, hvia, via, vfa;
1748 struct volFragment vf;
1750 int rvi; /* read the volInfo struct */
1751 afs_int32 eval, code = 0;
1753 if ( !callPermitted(call) )
1754 return BUDB_NOTPERMITTED;
1756 eval = InitRPC (&ut, LOCKREAD, 1);
1757 if (eval) return(eval);
1761 /* Search for the volume by name */
1762 eval = ht_LookupEntry (ut, &db.volName, volName, &hvia, &vi);
1763 if (eval) ABORT(eval);
1764 if (!hvia) ABORT(BUDB_NOVOLUMENAME);
1767 /* Follw the dump levels up */
1768 for (; dumpID; dumpID = ntohl(d.parent))
1770 /* Get the dump entry */
1771 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &da, &d);
1772 if (eval) ABORT(eval);
1773 if (!da) ABORT(BUDB_NODUMPID);
1775 /* seach all the volInfo entries on the sameNameChain */
1776 for (via=hvia; via; via=ntohl(vi.sameNameChain))
1778 if (rvi) /* Read the volInfo entry - except first time */
1780 eval = dbread(ut, via, &vi, sizeof(vi));
1781 if (eval) ABORT(eval);
1785 /* search all the volFrag entries on the volFrag */
1786 for (vfa=ntohl(vi.firstFragment); vfa; vfa=ntohl(vf.sameNameChain))
1788 eval = dbread(ut, vfa, &vf, sizeof(vf)); /* Read the volFrag entry */
1789 if (eval) ABORT(eval);
1791 eval = dbread(ut, ntohl(vf.tape), &t, sizeof(t)); /* Read the tape */
1792 if (eval) ABORT(eval);
1794 /* Now check to see if this fragment belongs to the dump we have */
1795 if (ntohl(t.dump) == da)
1797 *clonetime = ntohl(vf.clone); /* return the clone */
1805 code = ubik_EndTrans(ut);
1815 * Searches each tape and each volume in the dump until the volume is found.
1816 * If the volume is not in the dump, then we search it's parent dump.
1818 * Re-write to do lookups by volume name.
1820 afs_int32 FindClone (call, dumpID, volName, clonetime)
1821 struct rx_call *call;
1824 afs_int32 *clonetime;
1826 struct ubik_trans *ut;
1827 dbadr diskAddr, tapeAddr, volFragmentAddr;
1830 struct volFragment volFragment;
1831 struct volInfo volInfo;
1832 afs_int32 eval, code = 0;
1834 if ( !callPermitted(call) )
1835 return BUDB_NOTPERMITTED;
1837 eval = InitRPC (&ut, LOCKREAD, 1);
1838 if (eval) return(eval);
1842 for (; dumpID; dumpID = ntohl(dump.parent))
1844 /* Get the dump entry */
1845 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &diskAddr, &dump);
1846 if (eval) ABORT(eval);
1847 if (!diskAddr) ABORT(BUDB_NODUMPID);
1849 /* just to be sure */
1850 if (ntohl(dump.id) != dumpID)
1852 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID, ntohl(dump.id));
1853 ABORT(BUDB_INTERNALERROR);
1856 /* search all the tapes in this dump */
1857 for (tapeAddr=ntohl(dump.firstTape); tapeAddr; tapeAddr=ntohl(tape.nextTape))
1859 /* Get the tape entry */
1860 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
1861 if (eval) ABORT(eval);
1863 /* search all the volume fragments on this tape */
1864 for (volFragmentAddr=ntohl(tape.firstVol); volFragmentAddr;
1865 volFragmentAddr=ntohl(volFragment.sameTapeChain))
1867 /* Get the volume fragment entry */
1868 eval = dbread(ut, volFragmentAddr, &volFragment, sizeof(volFragment));
1869 if (eval) ABORT(eval);
1871 /* Get the volume info entry */
1872 eval = dbread(ut, ntohl(volFragment.vol), &volInfo, sizeof(volInfo));
1873 if (eval) ABORT(eval);
1875 /* check if this volume is the one we want */
1876 if ( strcmp(volInfo.name,volName) == 0 )
1878 *clonetime = ntohl(volFragment.clone);
1886 code = ubik_EndTrans(ut);
1896 * Find latest volume dump before adate.
1897 * Used by restore code when restoring a user requested volume(s)
1899 * volumeName - name of volume to match on
1900 * beforeDate - look for dumps older than this date
1902 * deptr - descriptor of most recent dump
1905 afs_int32 BUDB_FindDump (call, volumeName, beforeDate, deptr)
1906 struct rx_call *call;
1908 afs_int32 beforeDate;
1909 struct budb_dumpEntry *deptr;
1913 code = FindDump (call, volumeName, beforeDate, deptr);
1914 osi_auditU (call, BUDB_FndDmpEvent, code, AUD_STR, volumeName, AUD_END);
1918 afs_int32 FindDump (call, volumeName, beforeDate, deptr)
1919 struct rx_call *call;
1921 afs_int32 beforeDate;
1922 struct budb_dumpEntry *deptr;
1924 struct ubik_trans *ut;
1925 dbadr volInfoAddr, volFragmentAddr;
1927 struct volInfo volInfo;
1928 struct volFragment volFragment;
1930 dbadr selectedDumpAddr = 0;
1931 afs_int32 selectedDate = 0;
1932 afs_int32 volCloned;
1934 afs_int32 eval, code = 0;
1936 if ( !callPermitted(call) )
1937 return BUDB_NOTPERMITTED;
1939 eval = InitRPC (&ut, LOCKREAD, 1);
1940 if (eval) return eval;
1942 /* Find volinfo struct for volume name in hash table */
1943 eval = ht_LookupEntry (ut, &db.volName, volumeName, &volInfoAddr, &volInfo);
1944 if (eval) ABORT(eval);
1945 if (!volInfoAddr) ABORT(BUDB_NOVOLUMENAME);
1947 /* Step through all the volinfo structures on the same name chain.
1948 * No need to read the first - we read it above.
1950 for (rvoli=0; volInfoAddr; rvoli=1, volInfoAddr=ntohl(volInfo.sameNameChain))
1952 if (rvoli) /* read the volinfo structure */
1954 eval = dbread(ut, volInfoAddr, &volInfo, sizeof(volInfo));
1955 if (eval) ABORT(eval);
1958 /* step through the volfrag structures */
1959 for (volFragmentAddr=ntohl(volInfo.firstFragment); volFragmentAddr;
1960 volFragmentAddr=ntohl(volFragment.sameNameChain))
1962 /* read the volfrag struct */
1963 eval = dbread(ut, volFragmentAddr, &volFragment, sizeof(volFragment));
1964 if (eval) ABORT(eval);
1966 volCloned = ntohl(volFragment.clone);
1968 /* now we can examine the date for most recent dump */
1969 if ( (volCloned > selectedDate) && (volCloned < beforeDate) )
1971 /* from the volfrag struct, read the tape struct */
1972 eval = dbread(ut, ntohl(volFragment.tape), &tape, sizeof(tape));
1973 if (eval) ABORT(eval);
1975 selectedDate = volCloned;
1976 selectedDumpAddr = ntohl(tape.dump);
1981 if (!selectedDumpAddr) ABORT(BUDB_NOENT);
1983 eval = FillDumpEntry(ut, selectedDumpAddr, deptr);
1984 if (eval) ABORT(eval);
1986 code = ubik_EndTrans(ut);
1994 /* BUDB_FindLatestDump
1995 * Find the latest dump of volumeset vsname with dump name dname.
1997 * vsname - volumeset name
2001 afs_int32 BUDB_FindLatestDump (call, vsname, dumpPath, dumpentry)
2002 struct rx_call *call;
2003 char *vsname, *dumpPath;
2004 struct budb_dumpEntry *dumpentry;
2008 code = FindLatestDump (call, vsname, dumpPath, dumpentry);
2009 osi_auditU (call, BUDB_FndLaDEvent, code, AUD_STR, vsname, AUD_END);
2013 afs_int32 FindLatestDump (call, vsname, dumpPath, dumpentry)
2014 struct rx_call *call;
2015 char *vsname, *dumpPath;
2016 struct budb_dumpEntry *dumpentry;
2018 struct ubik_trans *ut;
2019 dbadr curdbaddr, retdbaddr, firstdbaddr;
2022 char dumpName[BU_MAXNAMELEN+2];
2023 afs_int32 eval, code = 0;
2025 if ( !callPermitted(call) )
2026 return BUDB_NOTPERMITTED;
2028 eval = InitRPC(&ut, LOCKREAD, 1);
2029 if (eval) return(eval);
2031 if ( (strcmp(vsname,"") == 0) && (strcmp(dumpPath,"") == 0) )
2033 /* Construct a database dump name */
2034 strcpy(dumpName, DUMP_TAPE_NAME);
2036 else if (index(dumpPath,'/') == 0) {
2037 int level, old, length, hash;
2038 struct dump hostDump, diskDump;
2039 struct memoryHashTable *mht;
2042 afs_uint32 bestDumpId=0;
2044 level = atoi(dumpPath);
2046 ABORT(BUDB_BADARGUMENT);
2049 /* Brute force search of all the dumps in the database - yuck! */
2052 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
2053 if (!mht) ABORT(BUDB_BADARGUMENT);
2055 for (old=0; old <= 1; old++) { /*fo*/
2056 length = (old ? mht->oldLength : mht->length);
2057 if (!length) continue;
2059 for (hash=0; hash<length; hash++) {
2061 for (dbAddr = ht_LookupBucket(ut,mht,hash,old); dbAddr;
2062 dbAddr = hostDump.idHashChain) {
2064 eval = dbread (ut, dbAddr, &diskDump, sizeof(diskDump));
2065 if (eval) ABORT(eval);
2066 dump_ntoh(&diskDump, &hostDump);
2068 if ( (strcmp(hostDump.volumeSet,vsname) == 0) && /* the volumeset */
2069 (hostDump.level == level) && /* same level */
2070 (hostDump.id > bestDumpId) ) { /* more recent */
2071 bestDumpId = hostDump.id;
2078 ABORT(BUDB_NODUMPNAME);
2084 /* construct the name of the dump */
2085 if ( (strlen(vsname) + strlen(tailCompPtr(dumpPath))) > BU_MAXNAMELEN )
2086 ABORT(BUDB_NODUMPNAME);
2088 strcpy(dumpName, vsname);
2089 strcat(dumpName, ".");
2090 strcat(dumpName, tailCompPtr(dumpPath));
2093 LogDebug(5, "lookup on :%s:\n", dumpName);
2095 /* Lookup on dumpname in hash table */
2096 eval = ht_LookupEntry(ut, &db.dumpName, dumpName, &firstdbaddr, &d);
2097 if (eval) ABORT(eval);
2102 /* folow remaining dumps in hash chain, looking for most latest dump */
2103 for (curdbaddr=firstdbaddr; curdbaddr; curdbaddr=ntohl(d.nameHashChain))
2105 if (curdbaddr != firstdbaddr) {
2106 eval = dbread(ut, curdbaddr, &d, sizeof(d));
2107 if (eval) ABORT(eval);
2110 if ( (strcmp(d.dumpPath, dumpPath) == 0) && /* Same dumppath */
2111 (strcmp(d.dumpName, dumpName) == 0) && /* Same dumpname */
2112 (ntohl(d.created) > latest) ) /* most recent */
2114 latest = ntohl(d.created);
2115 retdbaddr = curdbaddr;
2118 if (!retdbaddr) ABORT(BUDB_NODUMPNAME);
2121 /* return the dump found */
2122 FillDumpEntry(ut, retdbaddr, dumpentry);
2124 code = ubik_EndTrans(ut);
2128 ubik_AbortTrans(ut);
2133 afs_int32 BUDB_FinishDump (call, dump)
2134 struct rx_call *call;
2135 struct budb_dumpEntry *dump;
2139 code = FinishDump (call, dump);
2140 osi_auditU (call, BUDB_FinDmpEvent, code, AUD_DATE, (dump ? dump->id : 0), AUD_END);
2144 afs_int32 FinishDump (call, dump)
2145 struct rx_call *call;
2146 struct budb_dumpEntry *dump;
2148 struct ubik_trans *ut;
2151 afs_int32 eval, code = 0;
2153 if ( !callPermitted(call) )
2154 return BUDB_NOTPERMITTED;
2156 eval = InitRPC(&ut, LOCKWRITE, 1);
2157 if (eval) return eval;
2159 eval = ht_LookupEntry (ut, &db.dumpIden, &dump->id, &a, &d);
2160 if (eval) ABORT(eval);
2161 if (!a) ABORT(BUDB_NODUMPID);
2163 if ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)
2164 ABORT(BUDB_DUMPNOTINUSE);
2166 d.flags = htonl(dump->flags & ~BUDB_DUMP_INPROGRESS);
2168 /* if creation time specified set it */
2169 if (dump->created) d.created = htonl(dump->created);
2170 dump->created = ntohl(d.created);
2172 /* Write the dump entry out */
2173 eval = dbwrite(ut, a, &d, sizeof(d));
2174 if (eval) ABORT(eval);
2176 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2177 if (eval) ABORT(eval);
2179 code = ubik_EndTrans(ut);
2183 ubik_AbortTrans(ut);
2187 afs_int32 BUDB_FinishTape (call, tape)
2188 struct rx_call *call;
2189 struct budb_tapeEntry *tape;
2193 code = FinishTape (call, tape);
2194 osi_auditU (call, BUDB_FinTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
2198 afs_int32 FinishTape (call, tape)
2199 struct rx_call *call;
2200 struct budb_tapeEntry *tape;
2202 struct ubik_trans *ut;
2206 afs_int32 eval, code = 0;
2208 if ( !callPermitted(call) )
2209 return BUDB_NOTPERMITTED;
2211 eval = InitRPC (&ut, LOCKWRITE, 1);
2212 if (eval) return eval;
2214 /* find the tape struct in the tapename hash chain */
2215 eval = ht_LookupEntry (ut, &db.tapeName, tape->name, &a, &t);
2216 if (eval) ABORT(eval);
2217 if (!a) ABORT(BUDB_NOTAPENAME);
2219 /* Read the dump structure */
2220 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2221 if (eval) ABORT(eval);
2223 /* search for the right tape on the rest of the chain */
2224 while (ntohl(d.id) != tape->dump)
2226 a = ntohl(t.nameHashChain);
2227 if (!a) ABORT(BUDB_NOTAPENAME);
2229 eval = dbread(ut, a, &t, sizeof(t));
2230 if (eval) ABORT(eval);
2232 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2233 if (eval) ABORT(eval);
2236 if ( (ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0 )
2237 ABORT(BUDB_TAPENOTINUSE);
2239 /* t.nBytes = htonl(tape->nBytes); */
2240 t.nFiles = htonl(tape->nFiles);
2241 t.useKBytes = htonl(tape->useKBytes);
2242 t.flags = htonl(tape->flags & ~BUDB_TAPE_BEINGWRITTEN);
2244 eval = dbwrite(ut, a, &t, sizeof(t));
2245 if (eval) ABORT(BUDB_IO);
2247 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
2248 if (eval) ABORT(eval);
2250 code = ubik_EndTrans(ut);
2254 ubik_AbortTrans(ut);
2259 * return a set of dumps that match the specified criteria
2262 * majorVersion - version of interface structures. Permits compatibility
2264 * flags - for search and select operations. Broken down into flags
2265 * for name, start point, end point and time.
2266 * name - name to search for. Interpretation based on flags
2273 * dbTimeP - time at which the database was last modified. Up to
2274 * caller (client) to take appropriate action if database
2275 * modified between successive calls
2276 * dumps - list of matching dumps
2278 * currently supported are:
2283 afs_int32 BUDB_GetDumps (call, majorVersion, flags, name, start, end,
2284 index, nextIndexP, dbTimeP, dumps)
2285 struct rx_call *call;
2286 int majorVersion; /* version of interface structures */
2287 afs_int32 flags; /* search & select controls */
2288 char *name; /* s&s parameters */
2291 afs_int32 index; /* start index of returned entries */
2292 afs_int32 *nextIndexP; /* output index for next call */
2294 budb_dumpList *dumps; /* pointer to buffer */
2298 code = GetDumps (call, majorVersion, flags, name, start, end,
2299 index, nextIndexP, dbTimeP, dumps);
2300 osi_auditU (call, BUDB_GetDmpEvent, code, AUD_END);
2304 afs_int32 GetDumps (call, majorVersion, flags, name, start, end,
2305 index, nextIndexP, dbTimeP, dumps)
2306 struct rx_call *call;
2307 int majorVersion; /* version of interface structures */
2308 afs_int32 flags; /* search & select controls */
2309 char *name; /* s&s parameters */
2312 afs_int32 index; /* start index of returned entries */
2313 afs_int32 *nextIndexP; /* output index for next call */
2315 budb_dumpList *dumps; /* pointer to buffer */
2317 struct ubik_trans *ut;
2320 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2321 afs_int32 eval, code = 0;
2323 struct returnList list;
2325 /* Don't check permissions when we look up a specific dump id */
2326 if ( ((flags & BUDB_OP_STARTS) != BUDB_OP_DUMPID) && !callPermitted(call) )
2327 return BUDB_NOTPERMITTED;
2329 if (majorVersion != BUDB_MAJORVERSION) return BUDB_OLDINTERFACE;
2330 if (index < 0) return BUDB_ENDOFLIST;
2332 eval = InitRPC (&ut, LOCKREAD, 1);
2333 if (eval) return eval;
2335 nameFlags = flags & BUDB_OP_NAMES;
2336 startFlags = flags & BUDB_OP_STARTS;
2337 endFlags = flags & BUDB_OP_ENDS;
2338 timeFlags = flags & BUDB_OP_TIMES;
2340 InitReturnList (&list);
2343 if (nameFlags == BUDB_OP_DUMPNAME)
2345 /* not yet implemented */
2346 if (startFlags || endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
2348 eval = ht_LookupEntry (ut, &db.dumpName, name, &da, &d);
2349 if (eval) ABORT(eval);
2350 if (!da) ABORT(BUDB_NODUMPNAME);
2354 if (strcmp (d.dumpName, name) == 0)
2356 eval = AddToReturnList (&list, da, &toskip);
2357 if (eval == BUDB_LIST2BIG) break;
2358 if (eval) ABORT(eval);
2361 da = ntohl(d.nameHashChain); /* get next dump w/ name */
2364 eval = dbread (ut, da, &d, sizeof(d));
2365 if (eval) ABORT(eval);
2369 if ( nameFlags == BUDB_OP_VOLUMENAME )
2374 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2375 ABORT(BUDB_BADFLAGS);
2378 if (startFlags != BUDB_OP_STARTTIME) ABORT(BUDB_BADFLAGS);
2380 /* lookup a dump by volumename and time stamp. Find the most recent
2381 * dump of the specified volumename, that occured before the supplied
2385 /* get us a volInfo for name */
2386 eval = ht_LookupEntry(ut, &db.volName, name, &da, &vi);
2387 if (eval) ABORT(eval);
2391 /* now iterate over all the entries of this name */
2392 for ( va = vi.firstFragment; va != 0; va = v.sameNameChain )
2395 eval = dbread(ut, va, &v, sizeof(v));
2396 if (eval) ABORT(eval);
2398 if date on fragment > date
2399 ignore it - too recent;
2401 if ( date on fragment < date && date on fragment > bestfound )
2402 bestfound = date on fragment;
2406 da = vi.sameNameChain;
2410 eval = dbread(ut, da, &vi, sizeof(vi));
2411 if (eval) ABORT(eval);
2417 from saved volfragment address, compute dump.
2418 otherwise, return dump found
2422 else if (startFlags == BUDB_OP_DUMPID)
2424 if (endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
2425 if (nameFlags) ABORT(BUDB_BADFLAGS); /* NYI */
2427 eval = ht_LookupEntry (ut, &db.dumpIden, &start, &da, &d);
2428 if (eval) ABORT(eval);
2429 if (!da) ABORT(BUDB_NODUMPID);
2431 eval = AddToReturnList (&list, da, &toskip);
2432 if (eval) ABORT(eval);
2434 else if (endFlags == BUDB_OP_NPREVIOUS)
2436 struct wantDumpRock rock;
2437 struct chosenDump *ptr, *nextPtr;
2439 extern wantDump(), rememberDump();
2441 /* no other flags should be set */
2443 /* end specifies how many dumps */
2444 if (!end) ABORT(BUDB_BADFLAGS);
2446 bzero(&rock, sizeof(rock));
2447 rock.maxDumps = end;
2449 scanHashTable(ut, &db.dumpName, wantDump, rememberDump, (char *) &rock);
2451 for (ptr=rock.chain; ptr; ptr=nextPtr)
2453 nextPtr = ptr->next;
2454 AddToReturnList (&list, ptr->addr, &toskip); /* ignore error for free */
2460 ABORT(BUDB_BADFLAGS);
2463 eval = SendReturnList (ut, &list, FillDumpEntry, sizeof(struct budb_dumpEntry),
2464 index, nextIndexP, dbTimeP, (returnList_t)dumps);
2465 if (eval) ABORT(eval);
2468 FreeReturnList(&list);
2469 code = ubik_EndTrans(ut);
2473 FreeReturnList(&list);
2474 ubik_AbortTrans(ut);
2479 * Get the expiration of a tape. Since the dump could have appended dumps,
2480 * we should use the most recent expiration date. Put the most recent
2481 * expiration tape into the given tape structure.
2483 afs_int32 getExpiration (ut, tapePtr)
2484 struct ubik_trans *ut;
2485 struct tape *tapePtr;
2491 afs_int32 eval, code = 0;
2493 if (!tapePtr) ERROR(0);
2495 /* Get the dump for this tape */
2496 ad = ntohl(tapePtr->dump);
2497 eval = dbread(ut,ad,&d,sizeof(d));
2498 if (eval) ERROR(eval);
2500 /* If not an initial dump, get the initial dump */
2501 if (d.initialDumpID)
2503 initDump = ntohl(d.initialDumpID);
2504 eval = ht_LookupEntry (ut, &db.dumpIden, &initDump, &ad, &d);
2505 if (eval) ERROR(eval);
2508 /* Cycle through the dumps and appended dumps */
2511 /* Get the first tape in this dump. No need to check the rest of the tapes */
2512 /* for this dump since they will all have the same expiration date */
2513 eval = dbread (ut, ntohl(d.firstTape), &t, sizeof(t));
2514 if (eval) ERROR(eval);
2516 /* Take the greater of the expiration dates */
2517 if ( ntohl(tapePtr->expires) < ntohl(t.expires) )
2518 tapePtr->expires = t.expires;
2520 /* Step to and read the next appended dump */
2521 if ( ad = ntohl(d.appendedDumpChain) )
2523 eval = dbread(ut,ad,&d,sizeof(d));
2524 if (eval) ERROR(eval);
2532 /* Mark the following dump as appended to another, intial dump */
2533 afs_int32 makeAppended (ut, appendedDumpID, initialDumpID, startTapeSeq)
2534 struct ubik_trans *ut;
2535 afs_int32 appendedDumpID;
2536 afs_int32 initialDumpID;
2537 afs_int32 startTapeSeq;
2539 dbadr ada, da, lastDumpAddr;
2541 afs_int32 eval, code = 0;
2545 if (appendedDumpID == initialDumpID)
2546 ERROR(BUDB_INTERNALERROR);
2548 /* If there is an initial dump, append this dump to it */
2549 /* Find the appended dump via its id */
2550 eval = ht_LookupEntry(ut,&db.dumpIden,&appendedDumpID,&ada,&ad);
2551 if (eval) ERROR(eval);
2553 /* If the dump is already marked as appended,
2554 * then we have an internal error.
2556 if (ad.initialDumpID) {
2557 if (ntohl(ad.initialDumpID) != initialDumpID)
2558 ERROR(BUDB_INTERNALERROR);
2561 /* Update the appended dump to point to the initial dump */
2562 ad.initialDumpID = htonl(initialDumpID);
2563 ad.tapes.b = htonl(startTapeSeq);
2565 /* find the initial dump via its id */
2566 eval = ht_LookupEntry(ut,&db.dumpIden,&initialDumpID,&da,&d);
2567 if (eval) ERROR(eval);
2569 /* Update the appended dump's tape format with that of the initial */
2570 strcpy(ad.tapes.format, d.tapes.format);
2572 /* starting with the initial dump step through its appended dumps till
2573 * we reach the last appended dump.
2576 while (d.appendedDumpChain) {
2577 lastDumpAddr = ntohl(d.appendedDumpChain);
2578 if (lastDumpAddr == ada) ERROR(0); /* Already appended */
2579 eval = dbread(ut, lastDumpAddr, &d, sizeof(d));
2580 if (eval) ERROR(eval);
2583 /* Update the last dump to point to our new appended dump.
2584 * The appended dump is the last one in the dump chain.
2586 d.appendedDumpChain = htonl(ada);
2587 ad.appendedDumpChain = 0;
2589 /* Write the appended dump and the initial dump */
2590 eval = dbwrite(ut,ada,(char *)&ad,sizeof(ad));
2591 if (eval) ERROR(eval);
2593 eval = dbwrite (ut, lastDumpAddr, (char *)&d, sizeof(d));
2594 if (eval) ERROR(eval);
2596 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
2597 if (eval) ERROR(eval);
2603 afs_int32 BUDB_MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq)
2604 struct rx_call *call;
2605 afs_int32 appendedDumpID;
2606 afs_int32 initialDumpID;
2607 afs_int32 startTapeSeq;
2611 code = MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq);
2612 osi_auditU (call, BUDB_AppDmpEvent, code, AUD_LONG, appendedDumpID, AUD_END);
2616 afs_int32 MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq)
2617 struct rx_call *call;
2618 afs_int32 appendedDumpID;
2619 afs_int32 initialDumpID;
2620 afs_int32 startTapeSeq;
2622 struct ubik_trans *ut;
2623 afs_int32 eval, code = 0;
2625 if ( !callPermitted(call) )
2626 return BUDB_NOTPERMITTED;
2628 eval = InitRPC (&ut, LOCKWRITE, 1);
2629 if (eval) return(eval);
2631 eval = makeAppended(ut,appendedDumpID,initialDumpID,startTapeSeq);
2632 if (eval) ABORT(eval);
2634 code = ubik_EndTrans(ut);
2638 ubik_AbortTrans(ut);
2642 /* Find the last tape of a dump-set. This includes any appended dumps */
2643 afs_int32 BUDB_FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry)
2644 struct rx_call *call;
2646 struct budb_dumpEntry *dumpEntry;
2647 struct budb_tapeEntry *tapeEntry;
2648 struct budb_volumeEntry *volEntry;
2652 code = FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry);
2653 osi_auditU (call, BUDB_FndLTpeEvent, code, AUD_LONG, dumpID, AUD_END);
2657 afs_int32 FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry)
2658 struct rx_call *call;
2660 struct budb_dumpEntry *dumpEntry;
2661 struct budb_tapeEntry *tapeEntry;
2662 struct budb_volumeEntry *volEntry;
2664 struct ubik_trans *ut;
2668 dbadr lastTape, thisTape;
2669 afs_int32 lastTapeSeq;
2670 struct volFragment vf;
2671 dbadr lastVol, thisVol;
2672 afs_int32 lastVolPos;
2673 afs_int32 eval, code = 0;
2675 if ( !callPermitted(call) )
2676 return BUDB_NOTPERMITTED;
2678 if (!dumpID) return(BUDB_BADARGUMENT);
2680 eval = InitRPC (&ut, LOCKREAD, 1);
2681 if (eval) return(eval);
2683 /* find and read its initial dump via its id */
2684 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &lastDump, &d);
2685 if (eval) ABORT(eval);
2686 if (!lastDump) ABORT(BUDB_NODUMPID);
2688 /* Follow the append dumps link chain until we reach the last dump */
2689 while (d.appendedDumpChain)
2691 lastDump = ntohl(d.appendedDumpChain);
2692 eval = dbread(ut,lastDump,&d,sizeof(d));
2693 if (eval) ABORT(eval);
2696 /* We now have the last dump of the last appended dump */
2697 /* Copy this into our return structure */
2698 eval = FillDumpEntry(ut,lastDump,dumpEntry);
2699 if (eval) ABORT(eval);
2701 /* Fail if the last dump has no tapes */
2702 if (!d.firstTape) ABORT(BUDB_NOTAPENAME);
2704 /* Follow the tapes in this dump until we reach the last tape */
2705 eval = dbread (ut, ntohl(d.firstTape), &t, sizeof(t));
2706 if (eval) ABORT(eval);
2708 lastTape = ntohl(d.firstTape);
2709 lastTapeSeq = ntohl(t.seq);
2710 lastVol = ntohl(t.firstVol);
2714 thisTape = ntohl(t.nextTape);
2715 eval = dbread(ut,thisTape,&t,sizeof(t));
2716 if (eval) ABORT(eval);
2718 if (ntohl(t.seq) > lastTapeSeq)
2720 lastTape = thisTape;
2721 lastTapeSeq = ntohl(t.seq);
2722 lastVol = ntohl(t.firstVol);
2726 /* We now have the last tape of the last appended dump */
2727 /* Copy this into our return structure */
2728 eval = FillTapeEntry(ut,lastTape,tapeEntry);
2729 if (eval) ABORT(eval);
2731 /* Zero volume entry if the last tape has no volumes */
2733 bzero(volEntry, sizeof(*volEntry));
2735 /* Follow the volumes until we reach the last volume */
2736 eval = dbread (ut,lastVol,&vf,sizeof(vf));
2737 if (eval) ABORT(eval);
2739 lastVolPos = vf.position;
2741 while (vf.sameTapeChain) {
2742 thisVol = ntohl(vf.sameTapeChain);
2743 eval = dbread(ut,thisVol,&vf,sizeof(vf));
2744 if (eval) ABORT(eval);
2746 if (vf.position > lastVolPos) {
2748 lastVolPos = vf.position;
2752 /* We now have the last volume of this tape */
2753 /* Copy this into our return structure */
2754 eval = FillVolEntry(ut,lastVol,volEntry);
2755 if (eval) ABORT(eval);
2758 eval = ubik_EndTrans(ut);
2759 if (!code) code = eval;
2763 ubik_AbortTrans(ut);
2768 afs_int32 BUDB_GetTapes (call, majorVersion, flags, name, start, end, index, nextIndexP,
2770 struct rx_call *call;
2771 int majorVersion; /* version of interface structures */
2772 afs_int32 flags; /* search & select controls */
2773 char *name; /* s&s parameters */
2775 afs_int32 end; /* reserved: MBZ */
2776 afs_int32 index; /* start index of returned entries */
2777 afs_int32 *nextIndexP; /* output index for next call */
2779 budb_tapeList *tapes; /* pointer to buffer */
2783 code = GetTapes (call, majorVersion, flags, name, start, end,
2784 index, nextIndexP, dbTimeP, tapes);
2785 osi_auditU (call, BUDB_GetTpeEvent, code, AUD_END);
2789 afs_int32 GetTapes (call, majorVersion, flags, name, start, end,
2790 index, nextIndexP, dbTimeP, tapes)
2791 struct rx_call *call;
2792 int majorVersion; /* version of interface structures */
2793 afs_int32 flags; /* search & select controls */
2794 char *name; /* s&s parameters */
2796 afs_int32 end; /* reserved: MBZ */
2797 afs_int32 index; /* start index of returned entries */
2798 afs_int32 *nextIndexP; /* output index for next call */
2800 budb_tapeList *tapes; /* pointer to buffer */
2802 struct ubik_trans *ut;
2806 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2807 struct returnList list;
2808 afs_int32 eval, code = 0;
2811 if ( !callPermitted(call) )
2812 return BUDB_NOTPERMITTED;
2814 if (majorVersion != BUDB_MAJORVERSION)
2815 return BUDB_OLDINTERFACE;
2817 if (index < 0) return BUDB_ENDOFLIST;
2819 eval = InitRPC (&ut, LOCKREAD, 1);
2820 if (eval) return eval;
2822 nameFlags = flags & BUDB_OP_NAMES;
2823 startFlags = flags & BUDB_OP_STARTS;
2824 endFlags = flags & BUDB_OP_ENDS;
2825 timeFlags = flags & BUDB_OP_TIMES;
2827 InitReturnList (&list);
2830 if (nameFlags == BUDB_OP_TAPENAME)
2832 eval = ht_LookupEntry (ut, &db.tapeName, name, &ta, &t);
2833 if (eval) ABORT(eval);
2834 if (!ta) ABORT(BUDB_NOTAPENAME);
2837 if ( (startFlags & ~BUDB_OP_DUMPID) || endFlags || timeFlags ) ABORT(BUDB_BADFLAGS);
2839 /* follow the hash chain to the end */
2842 if (startFlags & BUDB_OP_DUMPID)
2844 /* read in the dump */
2845 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2846 if (eval) ABORT(eval);
2848 /* check if both name and dump id match */
2849 if ( (strcmp(name, t.name) == 0) && (ntohl(d.id) == start) )
2851 eval = AddToReturnList (&list, ta, &toskip);
2852 if (eval && (eval != BUDB_LIST2BIG)) ABORT(eval);
2858 /* Add to return list and continue search */
2859 if ( strcmp(name, t.name) == 0 )
2861 eval = AddToReturnList (&list, ta, &toskip);
2862 if (eval == BUDB_LIST2BIG) break;
2863 if (eval) ABORT(eval);
2867 ta = ntohl(t.nameHashChain);
2868 if (ta) dbread(ut, ta, &t, sizeof(t));
2871 else if (nameFlags == BUDB_OP_TAPESEQ)
2873 eval = ht_LookupEntry(ut,&db.dumpIden, &start, &da, &d);
2874 if (eval) ABORT(eval);
2875 if (!da) ABORT(BUDB_NODUMPNAME);
2877 /* search for the right tape */
2878 ta = ntohl(d.firstTape);
2879 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape))
2881 eval = dbread(ut, ta, &t, sizeof(t));
2882 if (eval) ABORT(eval);
2884 if (ntohl(t.seq) == end)
2886 eval = AddToReturnList (&list, ta, &toskip);
2887 if (eval && (eval != BUDB_LIST2BIG)) ABORT(eval);
2894 ABORT (BUDB_BADFLAGS);
2897 eval = SendReturnList (ut, &list, FillTapeEntry,
2898 sizeof(struct budb_tapeEntry),
2899 index, nextIndexP, dbTimeP, (returnList_t)tapes);
2900 if (eval) ABORT(eval);
2902 FreeReturnList(&list);
2903 code = ubik_EndTrans(ut);
2907 FreeReturnList(&list);
2908 ubik_AbortTrans(ut);
2913 * get a set of volumes according to the specified criteria.
2914 * See BUDB_GetDumps for general information on parameters
2915 * Currently supports:
2916 * 1) volume match - returns volumes based on volume name only.
2917 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
2918 * and start is a dumpid. Returns all volumes of the specified
2919 * name on the selected dumpid.
2922 afs_int32 BUDB_GetVolumes (call, majorVersion, flags, name, start, end,
2923 index, nextIndexP, dbTimeP, volumes)
2924 struct rx_call *call;
2925 int majorVersion; /* version of interface structures */
2926 afs_int32 flags; /* search & select controls */
2927 char *name; /* - parameters for search */
2928 afs_int32 start; /* - usage depends which BUDP_OP_* */
2929 afs_int32 end; /* - bits are set */
2930 afs_int32 index; /* start index of returned entries */
2931 afs_int32 *nextIndexP; /* output index for next call */
2933 budb_volumeList *volumes; /* pointer to buffer */
2937 code = GetVolumes (call, majorVersion, flags, name, start, end,
2938 index, nextIndexP, dbTimeP, volumes);
2939 osi_auditU (call, BUDB_GetVolEvent, code, AUD_END);
2943 afs_int32 GetVolumes (call, majorVersion, flags, name, start, end,
2944 index, nextIndexP, dbTimeP, volumes)
2945 struct rx_call *call;
2946 int majorVersion; /* version of interface structures */
2947 afs_int32 flags; /* search & select controls */
2948 char *name; /* - parameters for search */
2949 afs_int32 start; /* - usage depends which BUDP_OP_* */
2950 afs_int32 end; /* - bits are set */
2951 afs_int32 index; /* start index of returned entries */
2952 afs_int32 *nextIndexP; /* output index for next call */
2954 budb_volumeList *volumes; /* pointer to buffer */
2956 struct ubik_trans *ut;
2959 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2960 afs_int32 eval, code = 0;
2961 struct returnList vollist;
2964 /* Don't check permissions when we look up a specific volume name */
2965 if ( ((flags & BUDB_OP_NAMES) != BUDB_OP_VOLUMENAME) && !callPermitted(call) )
2966 return BUDB_NOTPERMITTED;
2968 if (majorVersion != BUDB_MAJORVERSION) return BUDB_OLDINTERFACE;
2969 if (index < 0) return BUDB_ENDOFLIST;
2971 eval = InitRPC (&ut, LOCKREAD, 1);
2972 if (eval) return eval;
2974 nameFlags = flags & BUDB_OP_NAMES;
2975 startFlags = flags & BUDB_OP_STARTS;
2976 endFlags = flags & BUDB_OP_ENDS;
2977 timeFlags = flags & BUDB_OP_TIMES;
2979 InitReturnList (&vollist);
2982 /* lookup a the volume (specified by name) in the dump (specified by id) */
2983 if (nameFlags == BUDB_OP_VOLUMENAME)
2985 /* dumpid permissible, all others off */
2986 if ( ((startFlags & ~BUDB_OP_DUMPID) != 0) || endFlags || timeFlags )
2987 ABORT(BUDB_BADFLAGS);
2989 /* returns ptr to volinfo of requested name */
2990 eval = ht_LookupEntry (ut, &db.volName, name, &via, &vi);
2991 if (eval) ABORT(eval);
2992 if (!via) ABORT(BUDB_NOVOLUMENAME);
2994 /* Iterate over all volume fragments with this name */
2997 struct volFragment v;
3000 /* traverse all the volume fragments for this volume info structure */
3001 for (va=vi.firstFragment; va; va=v.sameNameChain)
3004 eval = dbread (ut, va, &v, sizeof(v));
3005 if (eval) ABORT(eval);
3007 if ( startFlags & BUDB_OP_DUMPID )
3012 /* get the dump id for this fragment */
3013 eval = dbread(ut, ntohl(v.tape), &atape, sizeof(atape));
3014 if (eval) ABORT(eval);
3016 eval = dbread(ut, ntohl(atape.dump), &adump, sizeof(adump));
3017 if (eval) ABORT(BUDB_IO);
3019 /* dump id does not match */
3020 if ( ntohl(adump.id) != start )
3024 eval = AddToReturnList (&vollist, va, &toskip);
3025 if (eval == BUDB_LIST2BIG) break;
3026 if (eval) ABORT(eval);
3028 if (eval == BUDB_LIST2BIG) break;
3030 via = vi.sameNameChain;
3031 if (via == 0) break;
3034 eval = dbread (ut, via, &vi, sizeof(vi));
3035 if (eval) ABORT(eval);
3038 else if ( ((nameFlags == 0) || (nameFlags == BUDB_OP_TAPENAME)) &&
3039 (startFlags == BUDB_OP_DUMPID) )
3045 struct volFragment volFrag;
3048 /* lookup all volumes for a specified dump id */
3050 /* no other flags should be set */
3051 if (endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
3054 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &dumpAddr, &dump);
3055 if (eval) ABORT(eval);
3057 /* traverse all the tapes */
3058 for (tapeAddr=ntohl(dump.firstTape); tapeAddr; tapeAddr=ntohl(tape.nextTape))
3060 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
3061 if (eval) ABORT(eval);
3063 if ( ( nameFlags != BUDB_OP_TAPENAME ) ||
3064 ((nameFlags == BUDB_OP_TAPENAME) && (strcmp(tape.name,name) == 0)) )
3066 /* now return all the volumes */
3067 for (volFragAddr=ntohl(tape.firstVol); volFragAddr;
3068 volFragAddr=ntohl(volFrag.sameTapeChain))
3070 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
3071 if (eval) ABORT(eval);
3073 eval = AddToReturnList(&vollist, volFragAddr, &toskip);
3074 if (eval == BUDB_LIST2BIG) break;
3075 if (eval) ABORT(eval);
3078 if (eval == BUDB_LIST2BIG) break;
3083 ABORT(BUDB_BADFLAGS);
3086 eval = SendReturnList(ut, &vollist, FillVolEntry, sizeof(struct budb_volumeEntry),
3087 index, nextIndexP, dbTimeP, (returnList_t)volumes);
3088 if (eval) ABORT(eval);
3091 FreeReturnList(&vollist);
3092 code = ubik_EndTrans(ut);
3096 FreeReturnList(&vollist);
3097 ubik_AbortTrans(ut);
3101 afs_int32 BUDB_UseTape (call, tape, new)
3102 struct rx_call *call;
3103 struct budb_tapeEntry *tape; /* tape info */
3104 int *new; /* set if tape is new */
3108 code = UseTape (call, tape, new);
3109 osi_auditU (call, BUDB_UseTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
3113 afs_int32 UseTape (call, tape, new)
3114 struct rx_call *call;
3115 struct budb_tapeEntry *tape; /* tape info */
3116 int *new; /* set if tape is new */
3118 struct ubik_trans *ut;
3122 afs_int32 eval, code;
3124 if ( !callPermitted(call) )
3125 return BUDB_NOTPERMITTED;
3127 if (strlen (tape->name) >= sizeof(t.name)) return BUDB_BADARGUMENT;
3129 eval = InitRPC (&ut, LOCKWRITE, 1);
3130 if (eval) return eval;
3134 bzero (&t, sizeof(t));
3135 eval = AllocStructure (ut, tape_BLOCK, 0, &a, &t);
3136 if (eval) ABORT(eval);
3138 strcpy (t.name, tape->name);
3140 eval = ht_HashIn (ut, &db.tapeName, a, &t);
3141 if (eval) ABORT(eval);
3145 /* Since deleting a tape may change the dump (if its the same one), read in
3146 the dump after the call to DeleteTape. */
3148 eval = ht_LookupEntry (ut, &db.dumpIden, &tape->dump, &da, &d);
3149 if (eval) ABORT(eval);
3150 if (!da) ABORT(BUDB_NODUMPID);
3152 if (!tape->written) tape->written = time(0); /* fill in tape struct */
3153 t.written = htonl(tape->written);
3154 t.expires = htonl(tape->expires);
3156 t.seq = htonl(tape->seq);
3157 t.useCount = htonl(tape->useCount);
3158 t.labelpos = htonl(tape->labelpos);
3160 t.flags = htonl(tape->flags | BUDB_TAPE_BEINGWRITTEN);
3162 t.nextTape = d.firstTape; /* Chain the tape to the dump */
3163 d.firstTape = htonl(a);
3165 if (tape->seq >= ntohl(d.tapes.maxTapes)) /* inc # tapes in the dump */
3166 d.tapes.maxTapes = htonl(tape->seq);
3168 eval = dbwrite (ut, a, &t, sizeof(t)); /* write tape struct */
3169 if (eval) ABORT(eval);
3171 eval = dbwrite (ut, da, &d, sizeof(d)); /* write the dump struct */
3172 if (eval) ABORT(eval);
3174 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
3175 if (eval) ABORT(eval);
3177 LogDebug(5, "added tape %s\n", tape->name);
3179 code = ubik_EndTrans(ut);
3183 ubik_AbortTrans(ut);
3189 /* ---------------------------------------------
3190 * debug interface routines
3191 * ---------------------------------------------
3194 afs_int32 BUDB_T_DumpHashTable (call, type, filename)
3195 struct rx_call *call;
3201 code = T_DumpHashTable (call, type, filename);
3202 osi_auditU (call, BUDB_TDmpHaEvent, code, AUD_STR, filename, AUD_END);
3206 afs_int32 T_DumpHashTable (call, type, filename)
3207 struct rx_call *call;
3211 struct ubik_trans *ut;
3212 struct memoryHashTable *mht;
3214 afs_int32 eval, code = 0;
3221 char e[sizeof(struct block)]; /* unnecessarily conservative */
3225 if ( !callPermitted(call) )
3226 return BUDB_NOTPERMITTED;
3228 if (strlen (filename) >= sizeof(path)-5) return BUDB_BADARGUMENT;
3230 eval = InitRPC (&ut, LOCKWRITE, 1);
3231 if (eval) return eval;
3233 if ((mht = ht_GetType (type, &e_size)) == 0) return BUDB_BADARGUMENT;
3235 sprintf(path, "%s/%s", gettmpdir(), filename);
3237 DUMP = fopen (path, "w");
3238 if (!DUMP) ABORT(BUDB_BADARGUMENT);
3241 for (old=0; ; old++)
3243 length = (old ? mht->oldLength : mht->length);
3244 if (length) fprintf (DUMP, "Dumping %sHash Table:\n", (old?"Old ":""));
3246 for (hash=0; hash<length; hash++)
3248 a = ht_LookupBucket (ut, mht, hash, old);
3252 eval = dbread (ut, a, e, e_size);
3253 if (eval) ABORT(eval);
3256 if (a == first_a) fprintf (DUMP, " in bucket %d at %d is ", hash, a);
3257 else fprintf (DUMP, " at %d is ", a);
3259 case HT_dumpIden_FUNCTION:
3260 fprintf (DUMP, "%d\n", ntohl(((struct dump *)e)->id));
3262 case HT_dumpName_FUNCTION:
3263 fprintf (DUMP, "%s\n", ((struct dump *)e)->dumpName);
3265 case HT_tapeName_FUNCTION:
3266 fprintf (DUMP, "%s\n", ((struct tape *)e)->name);
3268 case HT_volName_FUNCTION:
3269 fprintf (DUMP, "%s\n", ((struct volInfo *)e)->name);
3272 if ((ht_HashEntry(mht,e) % length) != hash) ABORT(BUDB_DATABASEINCONSISTENT);
3273 a = ntohl(*(dbadr *)(e + mht->threadOffset));
3279 fprintf (DUMP, "%d entries found\n", ent);
3280 if (ntohl(mht->ht->entries) != ent) ABORT(BUDB_DATABASEINCONSISTENT);
3282 code = ubik_EndTrans(ut);
3283 if (DUMP) fclose (DUMP);
3287 ubik_AbortTrans(ut);
3288 if (DUMP) fclose (DUMP);
3292 afs_int32 BUDB_T_GetVersion (call, majorVersion)
3293 struct rx_call *call;
3298 code = T_GetVersion (call, majorVersion);
3299 osi_auditU (call, BUDB_TGetVrEvent, code, AUD_END);
3303 afs_int32 T_GetVersion (call, majorVersion)
3304 struct rx_call *call;
3307 struct ubik_trans *ut;
3310 code = InitRPC (&ut, LOCKREAD, 0);
3311 if (code) return(code);
3313 *majorVersion = BUDB_MAJORVERSION;
3315 code = ubik_EndTrans(ut);
3319 /* BUDB_T_DumpDatabase
3320 * dump as much of the database as possible int /tmp/<filename>
3323 afs_int32 BUDB_T_DumpDatabase (call, filename)
3324 struct rx_call *call;
3329 code = T_DumpDatabase (call, filename);
3330 osi_auditU (call, BUDB_TDmpDBEvent, code, AUD_STR, filename, AUD_END);
3334 afs_int32 T_DumpDatabase (call, filename)
3335 struct rx_call *call;
3340 struct ubik_trans *ut;
3343 int type, old, length, hash;
3345 struct memoryHashTable *mht;
3346 afs_int32 eval, code = 0;
3348 if ( !callPermitted(call) )
3349 return BUDB_NOTPERMITTED;
3351 path = (char *) malloc(strlen(gettmpdir())+1+strlen(filename)+1);
3352 if (!path) return(BUDB_INTERNALERROR);
3354 sprintf(path, "%s/%s", gettmpdir(), filename);
3356 dumpfid = fopen(path, "w");
3357 if (!dumpfid) return(BUDB_BADARGUMENT);
3359 eval = InitRPC (&ut, LOCKWRITE, 1);
3360 if (eval) return(eval);
3362 /* dump all items in the database */
3363 for ( type=1; type<=HT_MAX_FUNCTION; type++ )
3365 mht = ht_GetType (type, &entrySize);
3366 if (!mht) ERROR(BUDB_BADARGUMENT);
3368 for ( old =0; old <= 1; old++ )
3370 length = ( old ? mht->oldLength : mht->length);
3371 if (!length) continue;
3373 fprintf (dumpfid, "Dumping %s Hash Table:\n", (old ? "Old ":""));
3375 for ( hash = 0; hash < length; hash++ )
3377 dbAddr = ht_LookupBucket (ut, mht, hash, old);
3383 case HT_dumpIden_FUNCTION:
3385 struct dump hostDump, diskDump;
3387 eval = cdbread (ut, dump_BLOCK, dbAddr, &diskDump, sizeof(diskDump));
3388 if (eval) ERROR(eval);
3390 fprintf(dumpfid, "\ndumpId hash %d, entry at %u: block %d, index %d\n",
3391 hash, dbAddr, block, index);
3392 fprintf(dumpfid, "----------------------------\n");
3393 dump_ntoh(&diskDump, &hostDump);
3394 printDump(dumpfid, &hostDump);
3395 dbAddr = hostDump.idHashChain;
3399 case HT_dumpName_FUNCTION:
3401 struct dump hostDump, diskDump;
3403 eval = cdbread (ut, dump_BLOCK, dbAddr, &diskDump, sizeof(diskDump));
3404 if (eval) ERROR(eval);
3407 "\ndumpname hash %d, entry at %u: block %d, index %d\n",
3408 hash, dbAddr, block, index);
3409 fprintf(dumpfid, "----------------------------\n");
3410 dump_ntoh(&diskDump, &hostDump);
3411 printDump(dumpfid, &hostDump);
3412 dbAddr = hostDump.nameHashChain;
3416 case HT_tapeName_FUNCTION:
3418 struct tape hostTape, diskTape;
3420 eval = cdbread (ut, tape_BLOCK, dbAddr, &diskTape, sizeof(diskTape));
3421 if (eval) ERROR(eval);
3424 "\ntapename hash %d, entry at %u: block %d, index %d\n",
3425 hash, dbAddr, block, index);
3426 fprintf(dumpfid, "----------------------------\n");
3427 tape_ntoh(&diskTape, &hostTape);
3428 printTape(dumpfid, &hostTape);
3429 dbAddr = hostTape.nameHashChain;
3433 case HT_volName_FUNCTION:
3435 struct volInfo hostVolInfo, diskVolInfo;
3437 eval = cdbread (ut, volInfo_BLOCK, dbAddr, &diskVolInfo, sizeof(diskVolInfo));
3438 if (eval) ERROR(eval);
3441 "\nvolname hash %d, entry at %u: block %d, index %d\n",
3442 hash, dbAddr, block, index);
3443 fprintf(dumpfid, "----------------------------\n");
3444 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3445 printVolInfo(dumpfid, &hostVolInfo);
3446 dbAddr = hostVolInfo.nameHashChain;
3448 volFragsDump(ut, dumpfid,
3449 hostVolInfo.firstFragment);
3454 fprintf(dumpfid, "unknown type %d\n", type);
3464 code = ubik_EndTrans(ut); /* is this safe if no ut started ?*/
3465 if (dumpfid) fclose(dumpfid);
3466 if (path) free(path);
3470 volFragsDump(ut, dumpfid, dbAddr)
3471 struct ubik_trans *ut;
3475 struct volFragment hostVolFragment, diskVolFragment;
3481 code = cdbread (ut, volFragment_BLOCK, dbAddr, &diskVolFragment, sizeof(diskVolFragment));
3482 if (code) { /* don't be fussy about errors */
3483 fprintf(dumpfid, "volFragsDump: Error reading database\n");
3487 fprintf(dumpfid, "\nvolfragment entry at %u: block %d, index %d\n",
3488 dbAddr, block, index);
3489 fprintf(dumpfid, "----------------------------\n");
3490 volFragment_ntoh(&diskVolFragment, &hostVolFragment);
3491 printVolFragment(dumpfid, &hostVolFragment);
3492 dbAddr = hostVolFragment.sameNameChain;
3498 /* utilities - network to host conversion
3499 * currently used for debug only
3502 volFragmentDiskToHost(diskVfPtr, hostVfPtr)
3503 struct volFragment *diskVfPtr, *hostVfPtr;
3505 hostVfPtr->vol = ntohl(diskVfPtr->vol);
3506 hostVfPtr->sameNameChain = ntohl(diskVfPtr->sameNameChain);
3507 hostVfPtr->tape = ntohl(diskVfPtr->tape);
3508 hostVfPtr->sameTapeChain = ntohl(diskVfPtr->sameTapeChain);
3509 hostVfPtr->position = ntohl(diskVfPtr->position);
3510 hostVfPtr->clone = ntohl(diskVfPtr->clone);
3511 hostVfPtr->incTime = ntohl(diskVfPtr->incTime);
3512 hostVfPtr->startByte = ntohl(diskVfPtr->startByte);
3513 hostVfPtr->nBytes = ntohl(diskVfPtr->nBytes);
3514 hostVfPtr->flags = ntohs(diskVfPtr->flags);
3515 hostVfPtr->sequence = ntohs(diskVfPtr->sequence);
3518 volInfoDiskToHost(diskViPtr, hostViPtr)
3519 struct volInfo *diskViPtr, *hostViPtr;
3521 strcpy(hostViPtr->name, diskViPtr->name);
3522 hostViPtr->nameHashChain = ntohl(diskViPtr->nameHashChain);
3523 hostViPtr->id = ntohl(diskViPtr->id);
3524 strcpy(hostViPtr->server, diskViPtr->server);
3525 hostViPtr->partition = ntohl(diskViPtr->partition);
3526 hostViPtr->flags = ntohl(diskViPtr->flags);
3527 hostViPtr->sameNameHead = ntohl(diskViPtr->sameNameHead);
3528 hostViPtr->sameNameChain = ntohl(diskViPtr->sameNameChain);
3529 hostViPtr->firstFragment = ntohl(diskViPtr->firstFragment);
3530 hostViPtr->nFrags = ntohl(diskViPtr->nFrags);
3533 tapeDiskToHost(diskTapePtr, hostTapePtr)
3534 struct tape *diskTapePtr, *hostTapePtr;
3536 strcpy(hostTapePtr->name, diskTapePtr->name);
3537 hostTapePtr->nameHashChain = ntohl(diskTapePtr->nameHashChain);
3538 hostTapePtr->flags = ntohl(diskTapePtr->flags);
3540 /* tape id conversion here */
3541 hostTapePtr->written = ntohl(diskTapePtr->written);
3542 hostTapePtr->nBytes = ntohl(diskTapePtr->nBytes);
3543 hostTapePtr->nFiles = ntohl(diskTapePtr->nFiles);
3544 hostTapePtr->nVolumes = ntohl(diskTapePtr->nVolumes);
3545 hostTapePtr->seq = ntohl(diskTapePtr->seq);
3546 hostTapePtr->dump = ntohl(diskTapePtr->dump);
3547 hostTapePtr->nextTape = ntohl(diskTapePtr->nextTape);
3548 hostTapePtr->firstVol = ntohl(diskTapePtr->firstVol);
3549 hostTapePtr->useCount = ntohl(diskTapePtr->useCount);
3552 dumpDiskToHost(diskDumpPtr, hostDumpPtr)
3553 struct dump *diskDumpPtr, *hostDumpPtr;
3555 hostDumpPtr->id = ntohl(diskDumpPtr->id);
3556 hostDumpPtr->idHashChain = ntohl(diskDumpPtr->idHashChain);
3557 strcpy(hostDumpPtr->dumpName, diskDumpPtr->dumpName);
3558 strcpy(hostDumpPtr->dumpPath, diskDumpPtr->dumpPath);
3559 strcpy(hostDumpPtr->volumeSet, diskDumpPtr->volumeSet);
3560 hostDumpPtr->nameHashChain = ntohl(diskDumpPtr->nameHashChain);
3561 hostDumpPtr->flags = ntohl(diskDumpPtr->flags);
3562 hostDumpPtr->parent = ntohl(diskDumpPtr->parent);
3563 hostDumpPtr->created = ntohl(diskDumpPtr->created);
3564 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3565 hostDumpPtr->nVolumes = ntohl(diskDumpPtr->nVolumes);
3567 /* tapeset conversion here */
3569 hostDumpPtr->firstTape = ntohl(diskDumpPtr->firstTape);
3571 /* principal conversion here */
3576 checkHash(ut,hashType)
3577 struct ubik_trans *ut;
3580 struct memoryHashTable *mhtPtr;
3581 int entrySize, hashTableLength;
3586 mhtPtr = ht_GetType(hashType, &entrySize);
3590 for ( old = 0; old < 1; old++)
3592 LogDebug(5, "\nold = %d\n", old);
3593 printMemoryHashTable(stdout, mhtPtr);
3595 hashTableLength = ( old ? mhtPtr->oldLength : mhtPtr->length);
3597 for ( bucket = 0; bucket < hashTableLength; bucket++ )
3601 entryAddr = ht_LookupBucket (ut, mhtPtr, bucket, old);
3602 while (entryAddr != 0)
3604 LogDebug(6, "bucket %d has disk addr %d\n", bucket, entryAddr);
3607 case HT_dumpIden_FUNCTION:
3609 struct dump diskDump, hostDump;
3611 code = dbread(ut, entryAddr, &diskDump, entrySize);
3612 if (code) ERROR(-1);
3614 dump_ntoh(&diskDump, &hostDump);
3615 printDump(stdout, &hostDump);
3616 entryAddr = hostDump.idHashChain;
3620 case HT_dumpName_FUNCTION:
3623 case HT_tapeName_FUNCTION:
3626 case HT_volName_FUNCTION:
3628 struct volInfo diskVolInfo, hostVolInfo;
3630 code = dbread(ut, entryAddr, &diskVolInfo, entrySize);
3631 if (code) ERROR(-1);
3633 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3634 printVolInfo(stdout, &hostVolInfo);
3635 entryAddr = hostVolInfo.nameHashChain;