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 <afs/param.h>
20 #include <netinet/in.h>
22 #include <sys/param.h>
24 #include <sys/resource.h>
27 #include <sys/types.h>
29 #include <afs/bubasics.h>
38 #include <afs/cellconfig.h>
42 #include "budb_errs.h"
44 #include "error_macros.h"
46 #include "afs/audit.h"
47 #include <afs/afsutil.h>
53 extern struct ubik_dbase *BU_dbase;
54 extern struct afsconf_dir *BU_conf; /* for getting cell info */
55 extern afs_int32 myHost;
56 extern struct memoryDB db; /* incore copies of db structures */
58 afs_int32 AddVolume(), AddVolumes(), CreateDump(), DoDeleteDump(), DoDeleteTape(), ListDumps();
59 afs_int32 DeleteVDP(), FindClone(), FindDump(), FindLatestDump();
60 afs_int32 FinishDump(), FinishTape(), GetDumps(), getExpiration(), T_DumpDatabase();
61 afs_int32 makeAppended(), MakeDumpAppended(), FindLastTape(), GetTapes();
62 afs_int32 GetVolumes(), UseTape(), T_DumpHashTable(), T_GetVersion();
64 /* Text block management */
68 struct memTextBlock *mtb_next; /* next in chain */
69 afs_int32 mtb_nbytes; /* # of bytes in this block */
70 struct blockHeader mtb_blkHeader; /* in memory header */
71 dbadr mtb_addr; /* disk address of block */
74 typedef struct memTextBlock memTextBlockT;
75 typedef memTextBlockT *memTextBlockP;
77 /* These variable are for returning debugging info about the state of the
78 server. If they get trashed during multi-threaded operation it doesn't
81 /* This is global so COUNT_REQ in krb_udp.c can refer to it. */
82 char *lastOperation; /* name of last operation */
83 static Date lastTrans; /* time of last transaction */
85 /* procsInited is sort of a lock: during a transaction only one process runs
86 while procsInited is false. */
88 static int procsInited = 0;
90 /* This variable is protected by the procsInited flag. */
92 static int (*rebuildDatabase)();
94 /* AwaitInitialization
95 * Wait unitl budb has initialized (InitProcs). If it hasn't
96 * within 5 seconds, then return no quorum.
105 if (!start) start = time(0);
106 else if (time(0)-start > 5) return UNOQUORUM;
113 * name is a pathname style name, determine trailing name and return
118 tailCompPtr(pathNamePtr)
122 ptr = rindex(pathNamePtr, '/');
125 /* this should never happen */
126 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
131 ptr++; /* skip the / */
136 * Check to see if the caller is a SuperUser.
143 struct rx_call *call;
146 struct afsconf_dir *acdir;
148 acdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
149 if (!acdir) return 0;
151 if ( afsconf_SuperUser(acdir, call, (char *)0) )
155 if (acdir) afsconf_Close(acdir);
160 * This is called by every RPC interface to create a Ubik transaction
161 * and read the database header into core
167 * sets a lock on byte 1 of the database. Looks like it enforces
168 * single threading by use of the lock.
172 InitRPC (ut, lock, this_op)
173 struct ubik_trans **ut;
174 int lock; /* indicate read/write transaction */
175 int this_op; /* opcode of RCP, for COUNT_ABO */
178 float wait = 0.91; /* start waiting for 1 second */
181 /* wait for server initialization to finish if this is not InitProcs calling */
183 if (code = AwaitInitialization())
186 for (code = UNOQUORUM; code == UNOQUORUM; )
188 code = ubik_BeginTrans(BU_dbase,
189 ((lock == LOCKREAD) ? UBIK_READTRANS : UBIK_WRITETRANS),
191 if (code == UNOQUORUM)
192 { /* no quorum elected */
193 if (wait < 1) Log("Waiting for quorum election\n");
194 if (wait < 15.0) wait *= 1.1;
195 IOMGR_Sleep ((int)wait);
198 if (code) return code;
199 if (wait > 1) Log("Have established quorum\n");
201 /* set lock at posiion 1, for 1 byte of type lock */
202 if (code = ubik_SetLock (*ut, 1, 1, lock))
204 ubik_AbortTrans (*ut);
208 /* check that dbase is initialized and setup cheader */
209 if (lock == LOCKREAD)
211 /* init but don't fix because this is read only */
212 if ( code = CheckInit(*ut, 0) )
214 ubik_AbortTrans(*ut);
215 if ( code = InitRPC(ut, LOCKWRITE, 0) ) /* Now fix the database */
217 LogError(code, "InitRPC: InitRPC failed\n");
220 if ( code = ubik_EndTrans(*ut) )
222 LogError(code, "InitRPC: ubik_EndTrans failed\n");
225 goto start; /* now redo the read transaction */
230 if (code = CheckInit(*ut, rebuildDatabase))
232 ubik_AbortTrans(*ut);
240 /* This is called to initialize a newly created database */
241 static int initialize_database (ut)
242 struct ubik_trans *ut;
247 static int noAuthenticationRequired; /* global state */
248 static int recheckNoAuth; /* global state */
253 struct ubik_trans *ut;
258 if ( (globalConfPtr->myHost == 0) || (BU_conf == 0) )
259 ERROR(BUDB_INTERNALERROR);
263 if ( globalConfPtr->debugFlags & DF_NOAUTH )
264 noAuthenticationRequired = 1;
266 if ( globalConfPtr->debugFlags & DF_RECHECKNOAUTH )
270 noAuthenticationRequired = afsconf_GetNoAuthFlag(BU_conf);
272 if (noAuthenticationRequired)
273 LogError(0, "Running server with security disabled\n");
277 rebuildDatabase = initialize_database;
279 if (code = InitRPC (&ut, LOCKREAD, 0))
281 LogError(code, "InitProcs: InitRPC failed\n");
284 code = ubik_EndTrans(ut);
287 LogError(code, "InitProcs: ubik_EndTrans failed\n");
291 rebuildDatabase = 0; /* only do this during init */
299 int nElements; /* number in list */
300 int allocSize; /* number of elements allocated */
301 dbadr *elements; /* array of addresses */
304 static void InitReturnList (list)
305 struct returnList *list;
309 list->elements = (dbadr *)0;
312 static void FreeReturnList (list)
313 struct returnList *list;
315 if (list->elements) free(list->elements);
316 list->elements = (dbadr *)0;
320 /* As entries are collected, they are added to a return list. Once all
321 * entries have been collected, it is then placed in the return buffer
322 * with SendReturnList(). The first *to_skipP are not recorded.
324 static afs_int32 AddToReturnList (list, a, to_skipP)
325 struct returnList *list;
332 if (a == 0) return 0;
338 /* Up to 5 plus a maximum so SendReturnList() knows if we
339 * need to come back for more.
341 if (list->nElements >= BUDB_MAX_RETURN_LIST+5)
342 return BUDB_LIST2BIG;
344 if (list->nElements >= list->allocSize) {
345 if (list->elements == 0) {
347 tmp = (char *) malloc (sizeof(dbadr) * size);
349 size = list->allocSize + 10;
350 tmp = (char *) realloc (list->elements, sizeof(dbadr) * size);
352 if (!tmp) return BUDB_NOMEM;
353 list->elements = (dbadr *) tmp;
354 list->allocSize = size;
357 list->elements[list->nElements] = a;
362 afs_int32 FillVolEntry(ut, va, vol)
363 struct ubik_trans *ut;
365 struct budb_volumeEntry *vol;
370 struct volFragment vf;
372 if (dbread (ut, va, &vf, sizeof(vf))) return BUDB_IO; /* The volFrag */
373 if (dbread (ut, ntohl(vf.vol), &vi, sizeof(vi))) return BUDB_IO; /* The volInfo */
374 if (dbread (ut, ntohl(vf.tape), &t, sizeof(t))) return BUDB_IO; /* The tape */
375 if (dbread (ut, ntohl(t.dump), &d, sizeof(d))) return BUDB_IO; /* The dump */
377 strcpy (vol->name, vi.name);
378 strcpy (vol->server, vi.server);
379 strcpy (vol->tape, t.name);
380 vol->tapeSeq = ntohl(t.seq);
381 vol->dump = ntohl(d.id);
382 vol->position = ntohl(vf.position);
383 vol->clone = ntohl(vf.clone);
384 vol->incTime = ntohl(vf.incTime);
385 vol->nBytes = ntohl(vf.nBytes);
386 vol->startByte = ntohl(vf.startByte);
387 vol->flags = (ntohs(vf.flags) & VOLFRAGMENTFLAGS); /* low 16 bits here */
388 vol->flags |= (ntohl(vi.flags) & VOLINFOFLAGS); /* high 16 bits here */
389 vol->seq = ntohs(vf.sequence);
390 vol->id = ntohl(vi.id);
391 vol->partition = ntohl(vi.partition);
396 afs_int32 FillDumpEntry (ut, da, dump)
397 struct ubik_trans *ut;
399 struct budb_dumpEntry *dump;
403 if (dbread (ut, da, &d, sizeof(d))) return BUDB_IO;
404 dump->id = ntohl(d.id);
405 dump->flags = ntohl(d.flags);
406 dump->created = ntohl(d.created);
407 strncpy (dump->name, d.dumpName, sizeof(dump->name));
408 strncpy (dump->dumpPath, d.dumpPath, sizeof(dump->dumpPath));
409 strncpy (dump->volumeSetName, d.volumeSet, sizeof(dump->volumeSetName));
411 dump->parent = ntohl(d.parent);
412 dump->level = ntohl(d.level);
413 dump->nVolumes = ntohl(d.nVolumes);
415 tapeSet_ntoh(&d.tapes, &dump->tapes);
417 if (strlen(d.dumper.name) < sizeof(dump->dumper.name))
418 strcpy (dump->dumper.name, d.dumper.name);
419 if (strlen(d.dumper.instance) < sizeof(dump->dumper.instance))
420 strcpy (dump->dumper.instance, d.dumper.instance);
421 if (strlen(d.dumper.cell) < sizeof(dump->dumper.cell))
422 strcpy (dump->dumper.cell, d.dumper.cell);
424 /* Get the initial dumpid and the appended dump id */
425 dump->initialDumpID = ntohl(d.initialDumpID);
426 if (d.appendedDumpChain)
428 if (dbread (ut, ntohl(d.appendedDumpChain), &ad, sizeof(ad))) return BUDB_IO;
429 dump->appendedDumpID = ntohl(ad.id);
432 dump->appendedDumpID = 0;
434 /* printf("dump name %s, parent %d, level %d\n",
435 d.dumpName, ntohl(d.parent), ntohl(d.level)); */
440 afs_int32 FillTapeEntry (ut, ta, tape)
441 struct ubik_trans *ut;
443 struct budb_tapeEntry *tape;
449 if ( dbread (ut, ta, &t, sizeof(t)) )
452 /* Get the tape's expiration date */
453 if ( code = getExpiration(ut,&t) )
456 strcpy (tape->name, t.name);
457 tape->flags = ntohl(t.flags);
458 tape->written = ntohl(t.written);
459 tape->expires = ntohl(t.expires);
460 tape->nMBytes = ntohl(t.nMBytes);
461 tape->nBytes = ntohl(t.nBytes);
462 tape->nFiles = ntohl(t.nFiles);
463 tape->nVolumes = ntohl(t.nVolumes);
464 tape->seq = ntohl(t.seq);
465 tape->labelpos = ntohl(t.labelpos);
466 tape->useCount = ntohl(t.useCount);
467 tape->useKBytes = ntohl(t.useKBytes);
469 if (dbread (ut, ntohl(t.dump), &d, sizeof(d))) return BUDB_IO;
470 tape->dump = ntohl(d.id);
474 #define returnList_t budb_dumpList *
477 * A list of elements of size e_size is in list, collected
478 * with AddToReturnList(). We will move this to a correspoding
479 * return list, eList, via FillProc(). nextInodeP tells us
480 * if there are more and how many to skip on the next request.
483 SendReturnList (ut, list, FillProc, e_size, index, nextIndexP, dbTimeP, eList)
484 struct ubik_trans *ut;
485 struct returnList *list; /* list of elements to return */
486 afs_int32 (*FillProc)(); /* proc to fill entry */
487 int e_size; /* size of each element */
488 afs_int32 index; /* index from previous call */
489 afs_int32 *nextIndexP; /* if more elements are available */
490 afs_int32 *dbTimeP; /* time of last db update */
491 budb_dumpList *eList; /* rxgen list structure (e.g.) */
499 *dbTimeP = ntohl(db.h.lastUpdate);
501 /* Calculate how many to return. Don't let if go over
502 * BUDB_MAX_RETURN_LIST nor the size of our return list.
504 to_return = list->nElements;
505 if (to_return > BUDB_MAX_RETURN_LIST)
506 to_return = BUDB_MAX_RETURN_LIST;
507 if (eList->budb_dumpList_len && (to_return > eList->budb_dumpList_len))
508 to_return = eList->budb_dumpList_len;
510 /* Allocate space for the return values if needed and zero it */
511 if (eList->budb_dumpList_val == 0) {
512 eList->budb_dumpList_val = (struct budb_dumpEntry *)malloc (e_size * to_return);
513 if (!eList->budb_dumpList_val) return(BUDB_NOMEM);
515 bzero(eList->budb_dumpList_val, e_size * to_return);
516 eList->budb_dumpList_len = to_return;
518 e = (char *)(eList->budb_dumpList_val);
519 for (i=0; i<to_return; i++, e += e_size) {
520 code = (*FillProc) (ut, list->elements[i], e);
521 if (code) return code;
524 if (list->nElements > i)
525 *nextIndexP = index + i;
529 /* Come here to delete a volInfo structure. */
531 static afs_int32 DeleteVolInfo (ut, via, vi)
532 struct ubik_trans *ut;
539 if (vi->firstFragment) return 0; /* still some frags, don't free yet */
540 if (vi->sameNameHead == 0) { /* this is the head */
541 if (vi->sameNameChain) return 0; /* empty head, some non-heads left */
543 code = ht_HashOut (ut, &db.volName, via, vi);
544 if (code) return code;
545 code = FreeStructure (ut, volInfo_BLOCK, via);
548 hvia = ntohl(vi->sameNameHead);
549 if (dbread (ut, hvia, &hvi, sizeof(hvi))) return BUDB_IO;
550 code = RemoveFromList (ut, hvia, &hvi, &hvi.sameNameChain, via, vi, &vi->sameNameChain);
551 if (code == -1) return BUDB_DATABASEINCONSISTENT;
552 if (code == 0) code = FreeStructure (ut, volInfo_BLOCK, via);
556 /* Detach a volume fragment from its volInfo structure. Its tape chain is
557 already freed. This routine frees the structure and the caller must not
560 static afs_int32 DeleteVolFragment (ut, va, v)
561 struct ubik_trans *ut;
563 struct volFragment *v;
569 if (dbread (ut, via, &vi, sizeof(vi))) return BUDB_IO;
570 code = RemoveFromList (ut, via, &vi, &vi.firstFragment, va, v, &v->sameNameChain);
571 if (code == -1) return BUDB_DATABASEINCONSISTENT;
572 if (code) return code;
573 if (vi.firstFragment == 0)
574 if (code = DeleteVolInfo (ut, via, &vi)) return code;
575 if (code = FreeStructure (ut, volFragment_BLOCK, va)) return code;
577 /* decrement frag counter */
578 code = set_word_addr (ut, via, &vi, &vi.nFrags, htonl(ntohl(vi.nFrags)-1));
579 if (code) return code;
583 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
584 * The caller will remove it from the hash table if necessary. The caller is
585 * also responsible for writing the tape out if necessary. */
587 static afs_int32 DeleteTape (ut, ta, t)
588 struct ubik_trans *ut;
596 if (da == 0) return BUDB_DATABASEINCONSISTENT;
597 if (dbread (ut, da, &d, sizeof(d))) return BUDB_IO;
598 if (d.firstTape == 0) return BUDB_DATABASEINCONSISTENT;
600 code = RemoveFromList (ut, da, &d, &d.firstTape, ta, t, &t->nextTape);
601 if (code == -1) return BUDB_DATABASEINCONSISTENT;
602 if (code) return code;
604 /* Since the tape should have been truncated there should never be any
605 * volumes in the tape. */
606 if (t->firstVol || t->nVolumes) return BUDB_DATABASEINCONSISTENT;
612 DeleteDump (ut, da, d)
613 struct ubik_trans *ut;
619 code = ht_HashOut (ut, &db.dumpIden, da, d);
620 if (code) ERROR(code);
622 code = ht_HashOut (ut, &db.dumpName, da, d);
623 if (code) ERROR(code);
625 /* Since the tape should have been truncated this should never happen. */
626 if (d->firstTape || d->nVolumes) ERROR(BUDB_DATABASEINCONSISTENT);
628 code = FreeStructure (ut, dump_BLOCK, da);
629 if (code) ERROR(code);
638 * This is called with a volumeEntry and a volInfo structure and compares
639 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
640 * search volInfo structures once it has the head volInfo structure from the
641 * volName hash table.
643 * When called from GetVolInfo the name compare is redundant.
644 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
647 static int VolInfoMatch (vol, vi)
648 struct budb_volumeEntry *vol;
651 return ( (strcmp (vol->name, vi->name) == 0) && /* same volume name */
652 (vol->id == ntohl(vi->id)) && /* same volume id */
653 ((vol->flags & VOLINFOFLAGS) ==
654 (ntohl(vi->flags) & VOLINFOFLAGS)) && /* same flags */
655 (vol->partition == ntohl(vi->partition)) && /* same partition (N/A)*/
656 (strcmp (vol->server, vi->server) == 0) ); /* same server (N/A) */
661 * This routine takes a volumeEntry structure from an RPC interface and
662 * returns the corresponding volInfo structure, creating it if necessary.
664 * The caller must write the entry out.
667 static afs_int32 GetVolInfo (ut, volP, viaP, viP)
668 struct ubik_trans *ut;
669 struct budb_volumeEntry *volP;
675 afs_int32 eval, code = 0;
677 eval = ht_LookupEntry (ut, &db.volName, volP->name, &via, viP);
678 if (eval) ERROR(eval);
682 /* allocate a new volinfo structure */
683 eval = AllocStructure (ut, volInfo_BLOCK, 0, &via, viP);
684 if (eval) ERROR(eval);
686 strcpy (viP->name, volP->name);
687 strcpy (viP->server, volP->server);
688 viP->sameNameHead = 0; /* The head of same name chain */
689 viP->sameNameChain = 0; /* Same name chain is empty */
690 viP->firstFragment = 0;
692 viP->id = htonl(volP->id);
693 viP->partition = htonl(volP->partition);
694 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
696 /* Chain onto volname hash table */
697 eval = ht_HashIn (ut, &db.volName, via, viP);
698 if (eval) ERROR(eval);
700 LogDebug(4, "volume Info for %s placed at %d\n", db.volName, via);
703 else if ( !VolInfoMatch(volP,viP) ) /* Not the head volinfo struct */
705 hvia = via; /* remember the head volinfo struct */
706 bcopy(viP, &hvi, sizeof(hvi));
708 /* Search the same name chain for the correct volinfo structure */
709 for (via=ntohl(viP->sameNameChain); via; via=ntohl(viP->sameNameChain))
711 eval = dbread (ut, via, viP, sizeof(*viP));
712 if (eval) ERROR(eval);
714 if ( VolInfoMatch(volP,viP) ) break; /* found the one */
717 /* if the correct volinfo struct isn't found, create one */
720 eval = AllocStructure (ut, volInfo_BLOCK, 0, &via, viP);
721 if (eval) ERROR(eval);
723 strcpy (viP->name, volP->name);
724 strcpy (viP->server, volP->server);
725 viP->nameHashChain = 0; /* not in hash table */
726 viP->sameNameHead = htonl(hvia); /* chain to head of sameNameChain */
727 viP->sameNameChain = hvi.sameNameChain;
728 viP->firstFragment = 0;
730 viP->id = htonl(volP->id);
731 viP->partition = htonl(volP->partition);
732 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
734 /* write the head entry's sameNameChain link */
735 eval = set_word_addr (ut, hvia, &hvi, &hvi.sameNameChain, htonl(via));
736 if (eval) ERROR(eval);
746 /* deletesomevolumesfromtape
747 * Deletes a specified number of volumes from a tape. The tape
748 * and dump are modified to reflect the smaller number of volumes.
749 * The transaction is not terminated, it is up to the caller to
750 * finish the transaction and start a new one (if desired).
752 * maxvolumestodelete - don't delete more than this many volumes
756 deleteSomeVolumesFromTape(ut, tapeAddr, tapePtr, maxVolumesToDelete)
757 struct ubik_trans *ut;
759 struct tape *tapePtr;
760 int maxVolumesToDelete;
762 dbadr volFragAddr, nextVolFragAddr, dumpAddr;
763 struct volFragment volFrag;
765 int volumesDeleted = 0;
766 afs_int32 eval, code = 0;
768 if (!tapePtr) ERROR(0);
770 for (volFragAddr=ntohl(tapePtr->firstVol); (volFragAddr && (maxVolumesToDelete > 0));
771 volFragAddr=nextVolFragAddr)
773 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
774 if (eval) ERROR(eval);
776 nextVolFragAddr = ntohl(volFrag.sameTapeChain);
778 eval = DeleteVolFragment(ut, volFragAddr, &volFrag);
779 if (eval) ERROR(eval);
781 maxVolumesToDelete--;
785 /* reset the volume fragment pointer in the tape */
786 tapePtr->firstVol = htonl(volFragAddr);
788 /* diminish the tape's volume count */
789 tapePtr->nVolumes = htonl(ntohl(tapePtr->nVolumes) - volumesDeleted);
791 eval = dbwrite(ut, tapeAddr, tapePtr, sizeof(*tapePtr));
792 if (eval) ERROR(eval);
794 /* diminish the dump's volume count */
795 dumpAddr = ntohl(tapePtr->dump);
796 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
797 if (eval) ERROR(eval);
799 dump.nVolumes = htonl(ntohl(dump.nVolumes) - volumesDeleted);
800 eval = dbwrite(ut, dumpAddr, &dump, sizeof(dump));
801 if (eval) ERROR(eval);
808 * deletes a dump in stages, by repeatedly deleting a small number of
809 * volumes from the dump until none are left. The dump is then deleted.
811 * In the case where multiple calls are made to delete the same
812 * dump, the operation will succeed but contention for structures
813 * will result in someone getting back an error.
816 * id - id of dump to delete
820 deleteDump(call, id, dumps)
821 struct rx_call *call;
823 budb_dumpsList *dumps;
825 struct ubik_trans *ut;
826 dbadr dumpAddr, tapeAddr, appendedDump;
831 afs_int32 eval, code = 0;
834 /* iterate until the dump is truly deleted */
842 eval = InitRPC(&ut, LOCKWRITE, 1);
843 if (eval) ERROR(eval); /* can't start transaction */
845 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpid, &dumpAddr, &dump);
846 if (eval) ABORT(eval);
847 if (!dumpAddr) ABORT(BUDB_NOENT); /* can't find dump */
849 if ( (dumpid == id) && (dump.initialDumpID) ) /* can't be an appended dump */
850 ABORT(BUDB_NOTINITIALDUMP);
852 tapeAddr = ntohl(dump.firstTape);
853 if (tapeAddr == 0) break;
855 /* there is a tape to delete */
856 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
857 if (eval) ABORT(eval);
859 if ( ntohl(tape.nVolumes) )
861 /* tape is not empty */
862 eval = deleteSomeVolumesFromTape(ut, tapeAddr, &tape, 10);
863 if (eval) ABORT(eval);
866 if ( ntohl(tape.nVolumes) == 0 )
868 /* tape is now empty, delete it */
869 eval = DeleteTape(ut, tapeAddr, &tape);
870 if (eval) ABORT(eval);
871 eval = ht_HashOut(ut, &db.tapeName, tapeAddr, &tape);
872 if (eval) ABORT(eval);
873 eval = FreeStructure(ut, tape_BLOCK, tapeAddr);
874 if (eval) ABORT(eval);
877 eval = ubik_EndTrans(ut);
878 if (eval) ERROR(eval);
880 } /* next deletion portion */
882 /* Record the dump just deleted */
883 if (dumps && (dumps->budb_dumpsList_len < BUDB_MAX_RETURN_LIST))
885 if (dumps->budb_dumpsList_len == 0)
886 dumps->budb_dumpsList_val = (afs_int32 *) malloc(sizeof(afs_int32));
888 dumps->budb_dumpsList_val =
889 (afs_int32 *) realloc(dumps->budb_dumpsList_val,
890 (dumps->budb_dumpsList_len+1)*sizeof(afs_int32));
892 if ( !dumps->budb_dumpsList_val ) ABORT(BUDB_NOMEM);
894 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = dumpid;
895 dumps->budb_dumpsList_len++;
898 appendedDump = ntohl(dump.appendedDumpChain);
900 /* finally done. No more tapes left in the dump. Delete the dump itself */
901 eval = DeleteDump(ut, dumpAddr, &dump);
902 if (eval) ABORT(eval);
904 /* Now delete the appended dump too */
907 eval = dbread(ut, appendedDump, &dump, sizeof(dump));
908 if (eval) ABORT(eval);
910 dumpid = ntohl(dump.id);
915 eval = ubik_EndTrans(ut);
916 if (eval) ERROR(eval);
918 Log("Delete dump %s (DumpID %u), path %s\n",
919 dump.dumpName, ntohl(dump.id), dump.dumpPath);
923 if (code && partialDel) {
924 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
925 dump.dumpName, ntohl(dump.id), dump.dumpPath, code);
935 * dump selection routines - used by BUDB_GetDumps
939 /* most recent dump selection */
943 struct chosenDump *next;
950 int maxDumps; /* max wanted */
951 int ndumps; /* actual in chain */
952 struct chosenDump *chain;
956 wantDump(dumpAddrParam, dumpParam, dumpListPtrParam)
959 char *dumpListPtrParam;
962 struct dump *dumpPtr;
963 struct wantDumpRock *rockPtr;
965 dumpAddr = (dbadr) dumpAddrParam;
966 dumpPtr = (struct dump *) dumpParam;
967 rockPtr = (struct wantDumpRock *) dumpListPtrParam;
969 /* if we don't have our full complement, just add another */
970 if ( rockPtr->ndumps < rockPtr->maxDumps )
973 /* got the number we need, select based on date */
974 if ( (afs_uint32) ntohl(dumpPtr->created) > rockPtr->chain->date )
980 rememberDump(dumpAddrParam, dumpParam, dumpListPtrParam)
983 char *dumpListPtrParam;
986 struct dump *dumpPtr;
987 struct wantDumpRock *rockPtr;
988 struct chosenDump *ptr, *deletedPtr, **nextPtr;
990 dumpAddr = (dbadr) dumpAddrParam;
991 dumpPtr = (struct dump *) dumpParam;
992 rockPtr = (struct wantDumpRock *) dumpListPtrParam;
994 ptr = (struct chosenDump *) malloc(sizeof(*ptr));
997 bzero(ptr, sizeof(*ptr));
998 ptr->addr = dumpAddr;
999 ptr->date = (afs_uint32) ntohl(dumpPtr->created);
1001 /* Don't overflow the max */
1002 while (rockPtr->ndumps >= rockPtr->maxDumps) {
1003 /* have to drop one */
1004 deletedPtr = rockPtr->chain;
1005 rockPtr->chain = deletedPtr->next;
1010 /* now insert in the right place */
1011 for (nextPtr = &rockPtr->chain; *nextPtr; nextPtr = &((*nextPtr)->next)) {
1012 if (ptr->date < (*nextPtr)->date)
1015 ptr->next = *nextPtr;
1023 /* ---------------------------------------------
1024 * general interface routines - alphabetic
1025 * ---------------------------------------------
1028 afs_int32 BUDB_AddVolume (call, vol)
1029 struct rx_call *call;
1030 struct budb_volumeEntry *vol;
1034 code = AddVolume (call, vol);
1035 osi_auditU (call, BUDB_AddVolEvent, code, AUD_LONG, (vol ? vol->id : 0), AUD_END);
1039 afs_int32 AddVolume (call, vol)
1040 struct rx_call *call;
1041 struct budb_volumeEntry *vol;
1043 struct ubik_trans *ut;
1044 dbadr da, ta, via, va;
1048 struct volFragment v;
1050 afs_int32 eval, code = 0;
1052 if ( !callPermitted(call) )
1053 return BUDB_NOTPERMITTED;
1055 if ( ( strlen(vol->name) >= sizeof(vi.name) ) ||
1056 ( strlen(vol->server) >= sizeof(vi.server) ) ||
1057 ( strlen(vol->tape) >= sizeof(t.name) ) )
1058 return BUDB_BADARGUMENT;
1060 eval = InitRPC (&ut, LOCKWRITE, 1);
1061 if (eval) return eval;
1063 /* Find the dump in dumpid hash table */
1064 eval = ht_LookupEntry (ut, &db.dumpIden, &vol->dump, &da, &d);
1065 if (eval) ABORT(eval);
1066 if (!da) ABORT(BUDB_NODUMPID);
1068 /* search for the right tape in the dump */
1069 for (ta=ntohl(d.firstTape); ta; ta=ntohl(t.nextTape))
1071 /* read the tape entry */
1072 eval = dbread(ut, ta, &t, sizeof(t));
1073 if (eval) ABORT(eval);
1075 /* Check if the right tape name */
1076 if ( strcmp(t.name, vol->tape) == 0 )
1079 if (!ta) ABORT(BUDB_NOTAPENAME);
1081 if ( (t.dump != htonl(da)) || /* tape must belong to dump */
1082 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1083 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0) ) /* dump must be in progress */
1084 ABORT(BUDB_BADPROTOCOL);
1086 /* find or create a volume info structure */
1087 eval = GetVolInfo(ut, vol, &via, &vi);
1088 if (eval) ABORT(eval);
1090 /* Create a volume fragment */
1091 eval = AllocStructure (ut, volFragment_BLOCK, 0, &va, &v);
1092 if (eval) ABORT(eval);
1094 v.vol = htonl(via); /* vol frag points to vol info */
1095 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1096 vi.firstFragment = htonl(va);
1097 vi.nFrags = htonl(ntohl(vi.nFrags)+1);
1099 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1100 if (eval) ABORT(eval);
1102 v.tape = htonl(ta); /* vol frag points to tape */
1103 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1104 t.firstVol = htonl(va);
1105 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1106 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1107 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes/(1024*1024));
1108 t.nBytes = htonl(bytes % (1024*1024));
1110 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1111 if (eval) ABORT(eval);
1113 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1115 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1116 if (eval) ABORT(eval);
1118 v.position = htonl(vol->position); /* vol frag info */
1119 v.clone = htonl(vol->clone);
1120 v.incTime = htonl(vol->incTime);
1121 v.startByte = htonl(vol->startByte);
1122 v.nBytes = htonl(vol->nBytes);
1123 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1124 v.sequence = htons(vol->seq);
1126 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1127 if (eval) ABORT(eval);
1129 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1130 if (eval) ABORT(eval);
1132 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1134 code = ubik_EndTrans(ut);
1138 ubik_AbortTrans(ut);
1143 afs_int32 BUDB_AddVolumes (call, vols)
1144 struct rx_call *call;
1145 struct budb_volumeList *vols;
1149 code = AddVolumes (call, vols);
1150 osi_auditU (call, BUDB_AddVolEvent, code, AUD_LONG, 0, AUD_END);
1154 afs_int32 AddVolumes (call, vols)
1155 struct rx_call *call;
1156 struct budb_volumeList *vols;
1158 struct budb_volumeEntry *vol, *vol1;
1159 struct ubik_trans *ut;
1160 dbadr da, ta, via, va;
1164 struct volFragment v;
1166 afs_int32 eval, e, code = 0;
1168 if ( !callPermitted(call) )
1169 return BUDB_NOTPERMITTED;
1171 if (!vols || (vols->budb_volumeList_len <= 0) || !vols->budb_volumeList_val)
1172 return BUDB_BADARGUMENT;
1174 /* The first volume in the list of volumes to add */
1175 vol1 = (struct budb_volumeEntry *)vols->budb_volumeList_val;
1177 eval = InitRPC (&ut, LOCKWRITE, 1);
1178 if (eval) return eval;
1180 /* Find the dump in dumpid hash table */
1181 eval = ht_LookupEntry (ut, &db.dumpIden, &vol1->dump, &da, &d);
1182 if (eval) ABORT(eval);
1183 if (!da) ABORT(BUDB_NODUMPID);
1185 /* search for the right tape in the dump */
1186 for (ta=ntohl(d.firstTape); ta; ta=ntohl(t.nextTape)) {
1187 /* read the tape entry */
1188 eval = dbread(ut, ta, &t, sizeof(t));
1189 if (eval) ABORT(eval);
1191 /* Check if the right tape name */
1192 if ( strcmp(t.name, vol1->tape) == 0 )
1195 if (!ta) ABORT(BUDB_NOTAPENAME);
1197 if ( (t.dump != htonl(da)) || /* tape must belong to dump */
1198 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1199 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0) ) /* dump must be in progress */
1200 ABORT(BUDB_BADPROTOCOL);
1202 for (vol=vol1, e=0; e < vols->budb_volumeList_len; vol++, e++) {
1204 if ( ( strlen(vol->name) >= sizeof(vi.name) ) ||
1205 ( strcmp(vol->name, "") == 0 ) || /* no null volnames */
1206 ( strlen(vol->server) >= sizeof(vi.server) ) ||
1207 ( strlen(vol->tape) >= sizeof(t.name) ) ||
1208 ( strcmp(vol->tape, vol1->tape) != 0 ) ) {
1209 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n",
1210 vol->name, vol->id, vol->tape, vol->dump);
1214 /* find or create a volume info structure */
1215 eval = GetVolInfo(ut, vol, &via, &vi);
1216 if (eval) ABORT(eval);
1217 if (*(afs_int32 *)(&vi) == 0) {
1218 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n",
1219 vol->name, vol->tape, vol->dump);
1220 ABORT(BUDB_BADARGUMENT);
1223 /* Create a volume fragment */
1224 eval = AllocStructure (ut, volFragment_BLOCK, 0, &va, &v);
1225 if (eval) ABORT(eval);
1227 v.vol = htonl(via); /* vol frag points to vol info */
1228 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1229 vi.firstFragment = htonl(va);
1230 vi.nFrags = htonl(ntohl(vi.nFrags)+1);
1231 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1232 if (eval) ABORT(eval);
1234 v.tape = htonl(ta); /* vol frag points to tape */
1235 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1236 t.firstVol = htonl(va);
1237 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1238 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1239 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes/(1024*1024));
1240 t.nBytes = htonl(bytes % (1024*1024));
1242 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1244 v.position = htonl(vol->position); /* vol frag info */
1245 v.clone = htonl(vol->clone);
1246 v.incTime = htonl(vol->incTime);
1247 v.startByte = htonl(vol->startByte);
1248 v.nBytes = htonl(vol->nBytes);
1249 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1250 v.sequence = htons(vol->seq);
1252 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1253 if (eval) ABORT(eval);
1255 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1258 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1259 if (eval) ABORT(eval);
1261 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1262 if (eval) ABORT(eval);
1264 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1265 if (eval) ABORT(eval);
1267 code = ubik_EndTrans(ut);
1271 ubik_AbortTrans(ut);
1277 * records the existence of a dump in the database. This creates only
1278 * the dump record, to which one must attach tape and volume records.
1280 * 1) record the volume set
1283 afs_int32 BUDB_CreateDump(call, dump)
1284 struct rx_call *call;
1285 struct budb_dumpEntry *dump;
1289 code = CreateDump(call, dump);
1290 osi_auditU (call, BUDB_CrDmpEvent, code, AUD_DATE, (dump ? dump->id : 0), AUD_END);
1291 if (dump && !code) {
1292 Log("Create dump %s (DumpID %u), path %s\n",
1293 dump->name, dump->id, dump->dumpPath);
1298 afs_int32 CreateDump(call, dump)
1299 struct rx_call *call;
1300 struct budb_dumpEntry *dump;
1302 struct ubik_trans *ut;
1303 dbadr findDumpAddr, da;
1304 struct dump findDump, d;
1305 afs_int32 eval, code = 0;
1309 Date expiration; /* checked by Security Module */
1310 struct ktc_principal principal;
1312 if ( !callPermitted(call) )
1313 return BUDB_NOTPERMITTED;
1315 if (strlen(dump->name) >= sizeof(d.dumpName))
1316 return BUDB_BADARGUMENT;
1318 eval = InitRPC (&ut, LOCKWRITE, 1);
1319 if (eval) return eval;
1321 eval = rxkad_GetServerInfo( rx_ConnectionOf(call),
1322 &level, &expiration,
1330 if (eval != RXKADNOAUTH) ABORT(eval);
1332 strcpy(principal.name, "");
1333 strcpy(principal.instance, "");
1334 strcpy(principal.cell, "");
1339 /* authenticated. Take user supplied principal information */
1340 if ( strcmp(dump->dumper.name, "") != 0 )
1341 strncpy(principal.name, dump->dumper.name, sizeof(principal.name));
1343 if ( strcmp(dump->dumper.instance, "") != 0 )
1344 strncpy(principal.instance, dump->dumper.instance, sizeof(principal.instance));
1346 if ( strcmp(dump->dumper.cell, "") != 0 )
1347 strncpy(principal.cell, dump->dumper.cell, sizeof(principal.cell));
1350 /* dump id's are time stamps */
1353 while (1) /* allocate a unique dump id */
1357 /* ensure it is unique - seach for dumpid in hash table */
1358 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr, &findDump);
1359 if (eval) ABORT(eval);
1361 if (!findDumpAddr) /* dumpid not in use */
1363 /* update the last dump id allocated */
1364 eval = set_header_word(ut, lastDumpId, htonl(dump->id));
1365 if (eval) ABORT(eval);
1369 /* dump id is in use - wait a while */
1375 /* dump id supplied (e.g. for database restore) */
1376 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr, &findDump);
1377 if (eval) ABORT(eval);
1379 /* Dump id must not already exist */
1380 if (findDumpAddr) ABORT(BUDB_DUMPIDEXISTS);
1383 /* Allocate a dump structure */
1384 bzero (&d, sizeof(d));
1385 eval = AllocStructure (ut, dump_BLOCK, 0, &da, &d);
1386 if (eval) ABORT(eval);
1388 strcpy(d.dumpName, dump->name); /* volset.dumpname */
1389 strcpy(d.dumpPath, dump->dumpPath); /* dump node path */
1390 strcpy(d.volumeSet, dump->volumeSetName); /* volume set */
1391 d.id = htonl(dump->id);
1392 d.parent = htonl(dump->parent); /* parent id */
1393 d.level = htonl(dump->level);
1395 LogDebug(4, "dump name %s, parent %d level %d\n", dump->name, dump->parent, dump->level);
1397 /* if creation time specified, use that. Else use the dumpid time */
1398 if (dump->created == 0) dump->created = dump->id;
1399 d.created = htonl(dump->created);
1401 principal_hton(&principal, &d.dumper);
1402 tapeSet_hton(&dump->tapes, &d.tapes);
1404 d.flags = htonl(dump->flags | BUDB_DUMP_INPROGRESS);
1406 eval = ht_HashIn (ut, &db.dumpName, da, &d); /* Into dump name hash table */
1407 if (eval) ABORT(eval);
1409 eval = ht_HashIn (ut, &db.dumpIden, da, &d); /* Into dumpid hash table */
1410 if (eval) ABORT(eval);
1412 eval = dbwrite (ut, da, (char *)&d, sizeof(d)); /* Write the dump structure */
1413 if (eval) ABORT(eval);
1415 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
1416 if (eval) ABORT(eval);
1418 /* If to append this dump, then append it - will write the appended dump */
1419 eval = makeAppended(ut, dump->id, dump->initialDumpID, dump->tapes.b);
1420 if (eval) ABORT(eval);
1422 code = ubik_EndTrans(ut);
1423 LogDebug(5, "made dump %s, path %s\n", d.dumpName, d.dumpPath);
1427 ubik_AbortTrans(ut);
1431 afs_int32 BUDB_DeleteDump (call, id, fromTime, toTime, dumps)
1432 struct rx_call *call;
1436 budb_dumpsList *dumps;
1440 code = DoDeleteDump (call, id, fromTime, toTime, dumps);
1441 osi_auditU (call, BUDB_DelDmpEvent, code, AUD_DATE, id, AUD_END);
1447 afs_int32 DoDeleteDump (call, id, fromTime, toTime, dumps)
1448 struct rx_call *call;
1452 budb_dumpsList *dumps;
1456 if ( !callPermitted(call) )
1457 return BUDB_NOTPERMITTED;
1459 if (id) code = deleteDump(call, id, dumps);
1463 afs_int32 BUDB_ListDumps (call, sflags, name, groupid, fromTime, toTime, dumps, flags)
1464 struct rx_call *call;
1465 afs_int32 sflags, groupid;
1467 Date fromTime, toTime;
1468 budb_dumpsList *dumps, *flags;
1472 code = ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags);
1473 osi_auditU (call, BUDB_LstDmpEvent, code, AUD_LONG, flags, AUD_END);
1477 afs_int32 ListDumps (call, sflags, groupid, fromTime, toTime, dumps, flags)
1478 struct rx_call *call;
1479 afs_int32 sflags, groupid;
1480 Date fromTime, toTime;
1481 budb_dumpsList *dumps, *flags;
1483 struct ubik_trans *ut;
1484 struct memoryHashTable *mht;
1485 struct dump diskDump, appDiskDump;
1486 dbadr dbAddr, dbAppAddr;
1488 afs_int32 eval, code = 0;
1489 int old, hash, length, entrySize, j, k, count=0;
1490 afs_uint32 toList, toFlag;
1492 if ( !callPermitted(call) )
1493 return BUDB_NOTPERMITTED;
1495 eval= InitRPC (&ut, LOCKREAD, 1);
1496 if (eval) return(eval);
1498 /* Search the database */
1499 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
1500 if (!mht) return(BUDB_BADARGUMENT);
1502 for (old=0; old<=1; old++) { /*o*/ /* old and new hash tables */
1503 length = (old ? mht->oldLength : mht->length);
1504 if (length == 0) continue;
1506 for (hash=0; hash<length; hash++) { /*h*/ /* for each hash bucket */
1507 for (dbAddr = ht_LookupBucket(ut,mht,hash,old); dbAddr;
1508 dbAddr = ntohl(diskDump.idHashChain)) { /*d*/
1510 /* read the entry */
1511 eval = dbread (ut, dbAddr, &diskDump, sizeof(diskDump));
1512 if (eval) ABORT(eval);
1514 /* Skip appended dumps */
1515 if (ntohl(diskDump.initialDumpID) != 0) {
1519 /* Skip dumps with different goup id */
1520 if ((sflags & BUDB_OP_GROUPID) && (ntohl(diskDump.tapes.id) != groupid)) {
1524 /* Look at this dump to see if it meets the criteria for listing */
1525 if (sflags & BUDB_OP_DATES) {
1526 /* This and each appended dump should be in time */
1527 for (dbAppAddr=dbAddr; dbAppAddr; dbAppAddr=ntohl(appDiskDump.appendedDumpChain)) {
1528 eval = dbread (ut, dbAppAddr, &appDiskDump, sizeof(appDiskDump));
1529 if (eval) ABORT(eval);
1531 if ((ntohl(appDiskDump.id) < fromTime) || (ntohl(appDiskDump.id) > toTime))
1534 if (dbAppAddr) continue; /*nope*/
1537 /* Add it and each of its appended dump to our list to return */
1538 for (dbAppAddr=dbAddr; dbAppAddr; dbAppAddr=ntohl(appDiskDump.appendedDumpChain)) {
1539 eval = dbread (ut, dbAppAddr, &appDiskDump, sizeof(appDiskDump));
1540 if (eval) ABORT(eval);
1542 /* Make sure we have space to list it */
1543 if (dumps->budb_dumpsList_len >= count) {
1546 dumps->budb_dumpsList_val = (afs_int32 *)malloc(count * sizeof(afs_int32));
1547 flags->budb_dumpsList_val = (afs_int32 *)malloc(count * sizeof(afs_int32));
1549 dumps->budb_dumpsList_val =
1550 (afs_int32 *)realloc(dumps->budb_dumpsList_val, count*sizeof(afs_int32));
1551 flags->budb_dumpsList_val =
1552 (afs_int32 *)realloc(flags->budb_dumpsList_val, count*sizeof(afs_int32));
1554 if (!dumps->budb_dumpsList_val || !dumps->budb_dumpsList_val)
1558 /* Add it to our list */
1559 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = ntohl(appDiskDump.id);
1560 flags->budb_dumpsList_val[flags->budb_dumpsList_len] = 0;
1561 if ( ntohl(appDiskDump.initialDumpID) != 0 ) {
1562 flags->budb_dumpsList_val[flags->budb_dumpsList_len] |= BUDB_OP_APPDUMP;
1564 if (strcmp(appDiskDump.dumpName,DUMP_TAPE_NAME) == 0) {
1565 flags->budb_dumpsList_val[flags->budb_dumpsList_len] |= BUDB_OP_DBDUMP;
1567 dumps->budb_dumpsList_len++;
1568 flags->budb_dumpsList_len++;
1574 code = ubik_EndTrans(ut);
1578 ubik_AbortTrans(ut);
1582 afs_int32 BUDB_DeleteTape (call, tape)
1583 struct rx_call *call;
1584 struct budb_tapeEntry *tape; /* tape info */
1588 code = DoDeleteTape (call, tape);
1589 osi_auditU (call, BUDB_DelTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
1593 afs_int32 DoDeleteTape (call, tape)
1594 struct rx_call *call;
1595 struct budb_tapeEntry *tape; /* tape info */
1597 struct ubik_trans *ut;
1600 afs_int32 eval, code;
1602 if ( !callPermitted(call) )
1603 return BUDB_NOTPERMITTED;
1605 eval = InitRPC (&ut, LOCKWRITE, 1);
1606 if (eval) return eval;
1608 eval = ht_LookupEntry (ut, &db.tapeName, tape->name, &a, &t);
1609 if (eval) ABORT(eval);
1611 eval = DeleteTape (ut, a, &t);
1612 if (eval) ABORT(eval);
1614 eval = FreeStructure (ut, tape_BLOCK, a);
1615 if (eval) ABORT(eval);
1617 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
1618 if (eval) ABORT(eval);
1620 code = ubik_EndTrans(ut);
1624 ubik_AbortTrans(ut);
1629 * Deletes old information from the database for a particular dump path
1630 * and volumset. This supercedes the old policy implemented in
1631 * UseTape, which simply matched on the volumeset.dump. Consequently
1632 * it was unable to handle name re-use.
1634 * dsname - dumpset name, i.e. volumeset.dumpname
1635 * dumpPath - full path of dump node
1636 * curDumpID - current dump in progress - so that is may be excluded
1639 * n - some error. May or may not have deleted information.
1642 afs_int32 BUDB_DeleteVDP (call, dsname, dumpPath, curDumpId)
1643 struct rx_call *call;
1646 afs_int32 curDumpId;
1650 code = DeleteVDP (call, dsname, dumpPath, curDumpId);
1651 osi_auditU (call, BUDB_DelVDPEvent, code, AUD_STR, dsname, AUD_END);
1655 afs_int32 DeleteVDP (call, dsname, dumpPath, curDumpId)
1656 struct rx_call *call;
1659 afs_int32 curDumpId;
1664 struct ubik_trans *ut;
1665 afs_int32 eval, code = 0;
1667 if ( !callPermitted(call) )
1668 return BUDB_NOTPERMITTED;
1672 eval = InitRPC (&ut, LOCKREAD, 1);
1673 if (eval) return(eval);
1675 eval = ht_LookupEntry(ut, &db.dumpName, dsname, &dumpAddr, &dump);
1676 if (eval) ABORT(eval);
1678 while ( dumpAddr != 0 )
1680 if ( (strcmp(dump.dumpName, dsname) == 0) &&
1681 (strcmp(dump.dumpPath, dumpPath) == 0) &&
1682 (ntohl(dump.id) != curDumpId) )
1684 eval = ubik_EndTrans(ut);
1685 if (eval) return(eval);
1687 eval = deleteDump(call, ntohl(dump.id), 0);
1688 if (eval) return(eval);
1690 /* start the traversal over since the various chains may
1696 dumpAddr = ntohl(dump.nameHashChain);
1699 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
1700 if (eval) ABORT(eval);
1704 /* check if all the dumps have been examined - can terminate */
1707 eval = ubik_EndTrans(ut);
1713 ubik_AbortTrans(ut);
1719 * Given a volume name, and a dumpID, find the volume in that dump and
1720 * return the clone date of the volume (this is the clone date of the
1721 * volume at the time it was dumped).
1723 * Hashes on the volume name and traverses the fragments. Will need to read
1724 * the volumes tape entry to determine if it belongs to the dump. If the
1725 * volume is not found in the dump, then look for it in its parent dump.
1728 afs_int32 BUDB_FindClone(call, dumpID, volName, clonetime)
1729 struct rx_call *call;
1732 afs_int32 *clonetime;
1736 code = FindClone (call, dumpID, volName, clonetime);
1737 osi_auditU (call, BUDB_FndClnEvent, code, AUD_STR, volName, AUD_END);
1741 afs_int32 FindClone (call, dumpID, volName, clonetime)
1742 struct rx_call *call;
1745 afs_int32 *clonetime;
1747 struct ubik_trans *ut;
1748 dbadr da, ta, hvia, via, vfa;
1751 struct volFragment vf;
1753 int rvi; /* read the volInfo struct */
1754 afs_int32 eval, code = 0;
1756 if ( !callPermitted(call) )
1757 return BUDB_NOTPERMITTED;
1759 eval = InitRPC (&ut, LOCKREAD, 1);
1760 if (eval) return(eval);
1764 /* Search for the volume by name */
1765 eval = ht_LookupEntry (ut, &db.volName, volName, &hvia, &vi);
1766 if (eval) ABORT(eval);
1767 if (!hvia) ABORT(BUDB_NOVOLUMENAME);
1770 /* Follw the dump levels up */
1771 for (; dumpID; dumpID = ntohl(d.parent))
1773 /* Get the dump entry */
1774 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &da, &d);
1775 if (eval) ABORT(eval);
1776 if (!da) ABORT(BUDB_NODUMPID);
1778 /* seach all the volInfo entries on the sameNameChain */
1779 for (via=hvia; via; via=ntohl(vi.sameNameChain))
1781 if (rvi) /* Read the volInfo entry - except first time */
1783 eval = dbread(ut, via, &vi, sizeof(vi));
1784 if (eval) ABORT(eval);
1788 /* search all the volFrag entries on the volFrag */
1789 for (vfa=ntohl(vi.firstFragment); vfa; vfa=ntohl(vf.sameNameChain))
1791 eval = dbread(ut, vfa, &vf, sizeof(vf)); /* Read the volFrag entry */
1792 if (eval) ABORT(eval);
1794 eval = dbread(ut, ntohl(vf.tape), &t, sizeof(t)); /* Read the tape */
1795 if (eval) ABORT(eval);
1797 /* Now check to see if this fragment belongs to the dump we have */
1798 if (ntohl(t.dump) == da)
1800 *clonetime = ntohl(vf.clone); /* return the clone */
1808 code = ubik_EndTrans(ut);
1818 * Searches each tape and each volume in the dump until the volume is found.
1819 * If the volume is not in the dump, then we search it's parent dump.
1821 * Re-write to do lookups by volume name.
1823 afs_int32 FindClone (call, dumpID, volName, clonetime)
1824 struct rx_call *call;
1827 afs_int32 *clonetime;
1829 struct ubik_trans *ut;
1830 dbadr diskAddr, tapeAddr, volFragmentAddr;
1833 struct volFragment volFragment;
1834 struct volInfo volInfo;
1835 afs_int32 eval, code = 0;
1837 if ( !callPermitted(call) )
1838 return BUDB_NOTPERMITTED;
1840 eval = InitRPC (&ut, LOCKREAD, 1);
1841 if (eval) return(eval);
1845 for (; dumpID; dumpID = ntohl(dump.parent))
1847 /* Get the dump entry */
1848 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &diskAddr, &dump);
1849 if (eval) ABORT(eval);
1850 if (!diskAddr) ABORT(BUDB_NODUMPID);
1852 /* just to be sure */
1853 if (ntohl(dump.id) != dumpID)
1855 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID, ntohl(dump.id));
1856 ABORT(BUDB_INTERNALERROR);
1859 /* search all the tapes in this dump */
1860 for (tapeAddr=ntohl(dump.firstTape); tapeAddr; tapeAddr=ntohl(tape.nextTape))
1862 /* Get the tape entry */
1863 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
1864 if (eval) ABORT(eval);
1866 /* search all the volume fragments on this tape */
1867 for (volFragmentAddr=ntohl(tape.firstVol); volFragmentAddr;
1868 volFragmentAddr=ntohl(volFragment.sameTapeChain))
1870 /* Get the volume fragment entry */
1871 eval = dbread(ut, volFragmentAddr, &volFragment, sizeof(volFragment));
1872 if (eval) ABORT(eval);
1874 /* Get the volume info entry */
1875 eval = dbread(ut, ntohl(volFragment.vol), &volInfo, sizeof(volInfo));
1876 if (eval) ABORT(eval);
1878 /* check if this volume is the one we want */
1879 if ( strcmp(volInfo.name,volName) == 0 )
1881 *clonetime = ntohl(volFragment.clone);
1889 code = ubik_EndTrans(ut);
1899 * Find latest volume dump before adate.
1900 * Used by restore code when restoring a user requested volume(s)
1902 * volumeName - name of volume to match on
1903 * beforeDate - look for dumps older than this date
1905 * deptr - descriptor of most recent dump
1908 afs_int32 BUDB_FindDump (call, volumeName, beforeDate, deptr)
1909 struct rx_call *call;
1911 afs_int32 beforeDate;
1912 struct budb_dumpEntry *deptr;
1916 code = FindDump (call, volumeName, beforeDate, deptr);
1917 osi_auditU (call, BUDB_FndDmpEvent, code, AUD_STR, volumeName, AUD_END);
1921 afs_int32 FindDump (call, volumeName, beforeDate, deptr)
1922 struct rx_call *call;
1924 afs_int32 beforeDate;
1925 struct budb_dumpEntry *deptr;
1927 struct ubik_trans *ut;
1928 dbadr volInfoAddr, volFragmentAddr;
1930 struct volInfo volInfo;
1931 struct volFragment volFragment;
1933 dbadr selectedDumpAddr = 0;
1934 afs_int32 selectedDate = 0;
1935 afs_int32 volCloned;
1937 afs_int32 eval, code = 0;
1939 if ( !callPermitted(call) )
1940 return BUDB_NOTPERMITTED;
1942 eval = InitRPC (&ut, LOCKREAD, 1);
1943 if (eval) return eval;
1945 /* Find volinfo struct for volume name in hash table */
1946 eval = ht_LookupEntry (ut, &db.volName, volumeName, &volInfoAddr, &volInfo);
1947 if (eval) ABORT(eval);
1948 if (!volInfoAddr) ABORT(BUDB_NOVOLUMENAME);
1950 /* Step through all the volinfo structures on the same name chain.
1951 * No need to read the first - we read it above.
1953 for (rvoli=0; volInfoAddr; rvoli=1, volInfoAddr=ntohl(volInfo.sameNameChain))
1955 if (rvoli) /* read the volinfo structure */
1957 eval = dbread(ut, volInfoAddr, &volInfo, sizeof(volInfo));
1958 if (eval) ABORT(eval);
1961 /* step through the volfrag structures */
1962 for (volFragmentAddr=ntohl(volInfo.firstFragment); volFragmentAddr;
1963 volFragmentAddr=ntohl(volFragment.sameNameChain))
1965 /* read the volfrag struct */
1966 eval = dbread(ut, volFragmentAddr, &volFragment, sizeof(volFragment));
1967 if (eval) ABORT(eval);
1969 volCloned = ntohl(volFragment.clone);
1971 /* now we can examine the date for most recent dump */
1972 if ( (volCloned > selectedDate) && (volCloned < beforeDate) )
1974 /* from the volfrag struct, read the tape struct */
1975 eval = dbread(ut, ntohl(volFragment.tape), &tape, sizeof(tape));
1976 if (eval) ABORT(eval);
1978 selectedDate = volCloned;
1979 selectedDumpAddr = ntohl(tape.dump);
1984 if (!selectedDumpAddr) ABORT(BUDB_NOENT);
1986 eval = FillDumpEntry(ut, selectedDumpAddr, deptr);
1987 if (eval) ABORT(eval);
1989 code = ubik_EndTrans(ut);
1997 /* BUDB_FindLatestDump
1998 * Find the latest dump of volumeset vsname with dump name dname.
2000 * vsname - volumeset name
2004 afs_int32 BUDB_FindLatestDump (call, vsname, dumpPath, dumpentry)
2005 struct rx_call *call;
2006 char *vsname, *dumpPath;
2007 struct budb_dumpEntry *dumpentry;
2011 code = FindLatestDump (call, vsname, dumpPath, dumpentry);
2012 osi_auditU (call, BUDB_FndLaDEvent, code, AUD_STR, vsname, AUD_END);
2016 afs_int32 FindLatestDump (call, vsname, dumpPath, dumpentry)
2017 struct rx_call *call;
2018 char *vsname, *dumpPath;
2019 struct budb_dumpEntry *dumpentry;
2021 struct ubik_trans *ut;
2022 dbadr curdbaddr, retdbaddr, firstdbaddr;
2025 char dumpName[BU_MAXNAMELEN+2];
2026 afs_int32 eval, code = 0;
2028 if ( !callPermitted(call) )
2029 return BUDB_NOTPERMITTED;
2031 eval = InitRPC(&ut, LOCKREAD, 1);
2032 if (eval) return(eval);
2034 if ( (strcmp(vsname,"") == 0) && (strcmp(dumpPath,"") == 0) )
2036 /* Construct a database dump name */
2037 strcpy(dumpName, DUMP_TAPE_NAME);
2039 else if (index(dumpPath,'/') == 0) {
2040 int level, old, length, hash;
2041 struct dump hostDump, diskDump;
2042 struct memoryHashTable *mht;
2045 afs_uint32 bestDumpId=0;
2047 level = atoi(dumpPath);
2049 ABORT(BUDB_BADARGUMENT);
2052 /* Brute force search of all the dumps in the database - yuck! */
2055 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
2056 if (!mht) ABORT(BUDB_BADARGUMENT);
2058 for (old=0; old <= 1; old++) { /*fo*/
2059 length = (old ? mht->oldLength : mht->length);
2060 if (!length) continue;
2062 for (hash=0; hash<length; hash++) {
2064 for (dbAddr = ht_LookupBucket(ut,mht,hash,old); dbAddr;
2065 dbAddr = hostDump.idHashChain) {
2067 eval = dbread (ut, dbAddr, &diskDump, sizeof(diskDump));
2068 if (eval) ABORT(eval);
2069 dump_ntoh(&diskDump, &hostDump);
2071 if ( (strcmp(hostDump.volumeSet,vsname) == 0) && /* the volumeset */
2072 (hostDump.level == level) && /* same level */
2073 (hostDump.id > bestDumpId) ) { /* more recent */
2074 bestDumpId = hostDump.id;
2081 ABORT(BUDB_NODUMPNAME);
2087 /* construct the name of the dump */
2088 if ( (strlen(vsname) + strlen(tailCompPtr(dumpPath))) > BU_MAXNAMELEN )
2089 ABORT(BUDB_NODUMPNAME);
2091 strcpy(dumpName, vsname);
2092 strcat(dumpName, ".");
2093 strcat(dumpName, tailCompPtr(dumpPath));
2096 LogDebug(5, "lookup on :%s:\n", dumpName);
2098 /* Lookup on dumpname in hash table */
2099 eval = ht_LookupEntry(ut, &db.dumpName, dumpName, &firstdbaddr, &d);
2100 if (eval) ABORT(eval);
2105 /* folow remaining dumps in hash chain, looking for most latest dump */
2106 for (curdbaddr=firstdbaddr; curdbaddr; curdbaddr=ntohl(d.nameHashChain))
2108 if (curdbaddr != firstdbaddr) {
2109 eval = dbread(ut, curdbaddr, &d, sizeof(d));
2110 if (eval) ABORT(eval);
2113 if ( (strcmp(d.dumpPath, dumpPath) == 0) && /* Same dumppath */
2114 (strcmp(d.dumpName, dumpName) == 0) && /* Same dumpname */
2115 (ntohl(d.created) > latest) ) /* most recent */
2117 latest = ntohl(d.created);
2118 retdbaddr = curdbaddr;
2121 if (!retdbaddr) ABORT(BUDB_NODUMPNAME);
2124 /* return the dump found */
2125 FillDumpEntry(ut, retdbaddr, dumpentry);
2127 code = ubik_EndTrans(ut);
2131 ubik_AbortTrans(ut);
2136 afs_int32 BUDB_FinishDump (call, dump)
2137 struct rx_call *call;
2138 struct budb_dumpEntry *dump;
2142 code = FinishDump (call, dump);
2143 osi_auditU (call, BUDB_FinDmpEvent, code, AUD_DATE, (dump ? dump->id : 0), AUD_END);
2147 afs_int32 FinishDump (call, dump)
2148 struct rx_call *call;
2149 struct budb_dumpEntry *dump;
2151 struct ubik_trans *ut;
2154 afs_int32 eval, code = 0;
2156 if ( !callPermitted(call) )
2157 return BUDB_NOTPERMITTED;
2159 eval = InitRPC(&ut, LOCKWRITE, 1);
2160 if (eval) return eval;
2162 eval = ht_LookupEntry (ut, &db.dumpIden, &dump->id, &a, &d);
2163 if (eval) ABORT(eval);
2164 if (!a) ABORT(BUDB_NODUMPID);
2166 if ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)
2167 ABORT(BUDB_DUMPNOTINUSE);
2169 d.flags = htonl(dump->flags & ~BUDB_DUMP_INPROGRESS);
2171 /* if creation time specified set it */
2172 if (dump->created) d.created = htonl(dump->created);
2173 dump->created = ntohl(d.created);
2175 /* Write the dump entry out */
2176 eval = dbwrite(ut, a, &d, sizeof(d));
2177 if (eval) ABORT(eval);
2179 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2180 if (eval) ABORT(eval);
2182 code = ubik_EndTrans(ut);
2186 ubik_AbortTrans(ut);
2190 afs_int32 BUDB_FinishTape (call, tape)
2191 struct rx_call *call;
2192 struct budb_tapeEntry *tape;
2196 code = FinishTape (call, tape);
2197 osi_auditU (call, BUDB_FinTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
2201 afs_int32 FinishTape (call, tape)
2202 struct rx_call *call;
2203 struct budb_tapeEntry *tape;
2205 struct ubik_trans *ut;
2209 afs_int32 eval, code = 0;
2211 if ( !callPermitted(call) )
2212 return BUDB_NOTPERMITTED;
2214 eval = InitRPC (&ut, LOCKWRITE, 1);
2215 if (eval) return eval;
2217 /* find the tape struct in the tapename hash chain */
2218 eval = ht_LookupEntry (ut, &db.tapeName, tape->name, &a, &t);
2219 if (eval) ABORT(eval);
2220 if (!a) ABORT(BUDB_NOTAPENAME);
2222 /* Read the dump structure */
2223 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2224 if (eval) ABORT(eval);
2226 /* search for the right tape on the rest of the chain */
2227 while (ntohl(d.id) != tape->dump)
2229 a = ntohl(t.nameHashChain);
2230 if (!a) ABORT(BUDB_NOTAPENAME);
2232 eval = dbread(ut, a, &t, sizeof(t));
2233 if (eval) ABORT(eval);
2235 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2236 if (eval) ABORT(eval);
2239 if ( (ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0 )
2240 ABORT(BUDB_TAPENOTINUSE);
2242 /* t.nBytes = htonl(tape->nBytes); */
2243 t.nFiles = htonl(tape->nFiles);
2244 t.useKBytes = htonl(tape->useKBytes);
2245 t.flags = htonl(tape->flags & ~BUDB_TAPE_BEINGWRITTEN);
2247 eval = dbwrite(ut, a, &t, sizeof(t));
2248 if (eval) ABORT(BUDB_IO);
2250 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
2251 if (eval) ABORT(eval);
2253 code = ubik_EndTrans(ut);
2257 ubik_AbortTrans(ut);
2262 * return a set of dumps that match the specified criteria
2265 * majorVersion - version of interface structures. Permits compatibility
2267 * flags - for search and select operations. Broken down into flags
2268 * for name, start point, end point and time.
2269 * name - name to search for. Interpretation based on flags
2276 * dbTimeP - time at which the database was last modified. Up to
2277 * caller (client) to take appropriate action if database
2278 * modified between successive calls
2279 * dumps - list of matching dumps
2281 * currently supported are:
2286 afs_int32 BUDB_GetDumps (call, majorVersion, flags, name, start, end,
2287 index, nextIndexP, dbTimeP, dumps)
2288 struct rx_call *call;
2289 int majorVersion; /* version of interface structures */
2290 afs_int32 flags; /* search & select controls */
2291 char *name; /* s&s parameters */
2294 afs_int32 index; /* start index of returned entries */
2295 afs_int32 *nextIndexP; /* output index for next call */
2297 budb_dumpList *dumps; /* pointer to buffer */
2301 code = GetDumps (call, majorVersion, flags, name, start, end,
2302 index, nextIndexP, dbTimeP, dumps);
2303 osi_auditU (call, BUDB_GetDmpEvent, code, AUD_END);
2307 afs_int32 GetDumps (call, majorVersion, flags, name, start, end,
2308 index, nextIndexP, dbTimeP, dumps)
2309 struct rx_call *call;
2310 int majorVersion; /* version of interface structures */
2311 afs_int32 flags; /* search & select controls */
2312 char *name; /* s&s parameters */
2315 afs_int32 index; /* start index of returned entries */
2316 afs_int32 *nextIndexP; /* output index for next call */
2318 budb_dumpList *dumps; /* pointer to buffer */
2320 struct ubik_trans *ut;
2323 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2324 afs_int32 eval, code = 0;
2326 struct returnList list;
2328 /* Don't check permissions when we look up a specific dump id */
2329 if ( ((flags & BUDB_OP_STARTS) != BUDB_OP_DUMPID) && !callPermitted(call) )
2330 return BUDB_NOTPERMITTED;
2332 if (majorVersion != BUDB_MAJORVERSION) return BUDB_OLDINTERFACE;
2333 if (index < 0) return BUDB_ENDOFLIST;
2335 eval = InitRPC (&ut, LOCKREAD, 1);
2336 if (eval) return eval;
2338 nameFlags = flags & BUDB_OP_NAMES;
2339 startFlags = flags & BUDB_OP_STARTS;
2340 endFlags = flags & BUDB_OP_ENDS;
2341 timeFlags = flags & BUDB_OP_TIMES;
2343 InitReturnList (&list);
2346 if (nameFlags == BUDB_OP_DUMPNAME)
2348 /* not yet implemented */
2349 if (startFlags || endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
2351 eval = ht_LookupEntry (ut, &db.dumpName, name, &da, &d);
2352 if (eval) ABORT(eval);
2353 if (!da) ABORT(BUDB_NODUMPNAME);
2357 if (strcmp (d.dumpName, name) == 0)
2359 eval = AddToReturnList (&list, da, &toskip);
2360 if (eval == BUDB_LIST2BIG) break;
2361 if (eval) ABORT(eval);
2364 da = ntohl(d.nameHashChain); /* get next dump w/ name */
2367 eval = dbread (ut, da, &d, sizeof(d));
2368 if (eval) ABORT(eval);
2372 if ( nameFlags == BUDB_OP_VOLUMENAME )
2377 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2378 ABORT(BUDB_BADFLAGS);
2381 if (startFlags != BUDB_OP_STARTTIME) ABORT(BUDB_BADFLAGS);
2383 /* lookup a dump by volumename and time stamp. Find the most recent
2384 * dump of the specified volumename, that occured before the supplied
2388 /* get us a volInfo for name */
2389 eval = ht_LookupEntry(ut, &db.volName, name, &da, &vi);
2390 if (eval) ABORT(eval);
2394 /* now iterate over all the entries of this name */
2395 for ( va = vi.firstFragment; va != 0; va = v.sameNameChain )
2398 eval = dbread(ut, va, &v, sizeof(v));
2399 if (eval) ABORT(eval);
2401 if date on fragment > date
2402 ignore it - too recent;
2404 if ( date on fragment < date && date on fragment > bestfound )
2405 bestfound = date on fragment;
2409 da = vi.sameNameChain;
2413 eval = dbread(ut, da, &vi, sizeof(vi));
2414 if (eval) ABORT(eval);
2420 from saved volfragment address, compute dump.
2421 otherwise, return dump found
2425 else if (startFlags == BUDB_OP_DUMPID)
2427 if (endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
2428 if (nameFlags) ABORT(BUDB_BADFLAGS); /* NYI */
2430 eval = ht_LookupEntry (ut, &db.dumpIden, &start, &da, &d);
2431 if (eval) ABORT(eval);
2432 if (!da) ABORT(BUDB_NODUMPID);
2434 eval = AddToReturnList (&list, da, &toskip);
2435 if (eval) ABORT(eval);
2437 else if (endFlags == BUDB_OP_NPREVIOUS)
2439 struct wantDumpRock rock;
2440 struct chosenDump *ptr, *nextPtr;
2442 extern wantDump(), rememberDump();
2444 /* no other flags should be set */
2446 /* end specifies how many dumps */
2447 if (!end) ABORT(BUDB_BADFLAGS);
2449 bzero(&rock, sizeof(rock));
2450 rock.maxDumps = end;
2452 scanHashTable(ut, &db.dumpName, wantDump, rememberDump, (char *) &rock);
2454 for (ptr=rock.chain; ptr; ptr=nextPtr)
2456 nextPtr = ptr->next;
2457 AddToReturnList (&list, ptr->addr, &toskip); /* ignore error for free */
2463 ABORT(BUDB_BADFLAGS);
2466 eval = SendReturnList (ut, &list, FillDumpEntry, sizeof(struct budb_dumpEntry),
2467 index, nextIndexP, dbTimeP, (returnList_t)dumps);
2468 if (eval) ABORT(eval);
2471 FreeReturnList(&list);
2472 code = ubik_EndTrans(ut);
2476 FreeReturnList(&list);
2477 ubik_AbortTrans(ut);
2482 * Get the expiration of a tape. Since the dump could have appended dumps,
2483 * we should use the most recent expiration date. Put the most recent
2484 * expiration tape into the given tape structure.
2486 afs_int32 getExpiration (ut, tapePtr)
2487 struct ubik_trans *ut;
2488 struct tape *tapePtr;
2494 afs_int32 eval, code = 0;
2496 if (!tapePtr) ERROR(0);
2498 /* Get the dump for this tape */
2499 ad = ntohl(tapePtr->dump);
2500 eval = dbread(ut,ad,&d,sizeof(d));
2501 if (eval) ERROR(eval);
2503 /* If not an initial dump, get the initial dump */
2504 if (d.initialDumpID)
2506 initDump = ntohl(d.initialDumpID);
2507 eval = ht_LookupEntry (ut, &db.dumpIden, &initDump, &ad, &d);
2508 if (eval) ERROR(eval);
2511 /* Cycle through the dumps and appended dumps */
2514 /* Get the first tape in this dump. No need to check the rest of the tapes */
2515 /* for this dump since they will all have the same expiration date */
2516 eval = dbread (ut, ntohl(d.firstTape), &t, sizeof(t));
2517 if (eval) ERROR(eval);
2519 /* Take the greater of the expiration dates */
2520 if ( ntohl(tapePtr->expires) < ntohl(t.expires) )
2521 tapePtr->expires = t.expires;
2523 /* Step to and read the next appended dump */
2524 if ( ad = ntohl(d.appendedDumpChain) )
2526 eval = dbread(ut,ad,&d,sizeof(d));
2527 if (eval) ERROR(eval);
2535 /* Mark the following dump as appended to another, intial dump */
2536 afs_int32 makeAppended (ut, appendedDumpID, initialDumpID, startTapeSeq)
2537 struct ubik_trans *ut;
2538 afs_int32 appendedDumpID;
2539 afs_int32 initialDumpID;
2540 afs_int32 startTapeSeq;
2542 dbadr ada, da, lastDumpAddr;
2544 afs_int32 eval, code = 0;
2548 if (appendedDumpID == initialDumpID)
2549 ERROR(BUDB_INTERNALERROR);
2551 /* If there is an initial dump, append this dump to it */
2552 /* Find the appended dump via its id */
2553 eval = ht_LookupEntry(ut,&db.dumpIden,&appendedDumpID,&ada,&ad);
2554 if (eval) ERROR(eval);
2556 /* If the dump is already marked as appended,
2557 * then we have an internal error.
2559 if (ad.initialDumpID) {
2560 if (ntohl(ad.initialDumpID) != initialDumpID)
2561 ERROR(BUDB_INTERNALERROR);
2564 /* Update the appended dump to point to the initial dump */
2565 ad.initialDumpID = htonl(initialDumpID);
2566 ad.tapes.b = htonl(startTapeSeq);
2568 /* find the initial dump via its id */
2569 eval = ht_LookupEntry(ut,&db.dumpIden,&initialDumpID,&da,&d);
2570 if (eval) ERROR(eval);
2572 /* Update the appended dump's tape format with that of the initial */
2573 strcpy(ad.tapes.format, d.tapes.format);
2575 /* starting with the initial dump step through its appended dumps till
2576 * we reach the last appended dump.
2579 while (d.appendedDumpChain) {
2580 lastDumpAddr = ntohl(d.appendedDumpChain);
2581 if (lastDumpAddr == ada) ERROR(0); /* Already appended */
2582 eval = dbread(ut, lastDumpAddr, &d, sizeof(d));
2583 if (eval) ERROR(eval);
2586 /* Update the last dump to point to our new appended dump.
2587 * The appended dump is the last one in the dump chain.
2589 d.appendedDumpChain = htonl(ada);
2590 ad.appendedDumpChain = 0;
2592 /* Write the appended dump and the initial dump */
2593 eval = dbwrite(ut,ada,(char *)&ad,sizeof(ad));
2594 if (eval) ERROR(eval);
2596 eval = dbwrite (ut, lastDumpAddr, (char *)&d, sizeof(d));
2597 if (eval) ERROR(eval);
2599 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
2600 if (eval) ERROR(eval);
2606 afs_int32 BUDB_MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq)
2607 struct rx_call *call;
2608 afs_int32 appendedDumpID;
2609 afs_int32 initialDumpID;
2610 afs_int32 startTapeSeq;
2614 code = MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq);
2615 osi_auditU (call, BUDB_AppDmpEvent, code, AUD_LONG, appendedDumpID, AUD_END);
2619 afs_int32 MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq)
2620 struct rx_call *call;
2621 afs_int32 appendedDumpID;
2622 afs_int32 initialDumpID;
2623 afs_int32 startTapeSeq;
2625 struct ubik_trans *ut;
2626 afs_int32 eval, code = 0;
2628 if ( !callPermitted(call) )
2629 return BUDB_NOTPERMITTED;
2631 eval = InitRPC (&ut, LOCKWRITE, 1);
2632 if (eval) return(eval);
2634 eval = makeAppended(ut,appendedDumpID,initialDumpID,startTapeSeq);
2635 if (eval) ABORT(eval);
2637 code = ubik_EndTrans(ut);
2641 ubik_AbortTrans(ut);
2645 /* Find the last tape of a dump-set. This includes any appended dumps */
2646 afs_int32 BUDB_FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry)
2647 struct rx_call *call;
2649 struct budb_dumpEntry *dumpEntry;
2650 struct budb_tapeEntry *tapeEntry;
2651 struct budb_volumeEntry *volEntry;
2655 code = FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry);
2656 osi_auditU (call, BUDB_FndLTpeEvent, code, AUD_LONG, dumpID, AUD_END);
2660 afs_int32 FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry)
2661 struct rx_call *call;
2663 struct budb_dumpEntry *dumpEntry;
2664 struct budb_tapeEntry *tapeEntry;
2665 struct budb_volumeEntry *volEntry;
2667 struct ubik_trans *ut;
2671 dbadr lastTape, thisTape;
2672 afs_int32 lastTapeSeq;
2673 struct volFragment vf;
2674 dbadr lastVol, thisVol;
2675 afs_int32 lastVolPos;
2676 afs_int32 eval, code = 0;
2678 if ( !callPermitted(call) )
2679 return BUDB_NOTPERMITTED;
2681 if (!dumpID) return(BUDB_BADARGUMENT);
2683 eval = InitRPC (&ut, LOCKREAD, 1);
2684 if (eval) return(eval);
2686 /* find and read its initial dump via its id */
2687 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &lastDump, &d);
2688 if (eval) ABORT(eval);
2689 if (!lastDump) ABORT(BUDB_NODUMPID);
2691 /* Follow the append dumps link chain until we reach the last dump */
2692 while (d.appendedDumpChain)
2694 lastDump = ntohl(d.appendedDumpChain);
2695 eval = dbread(ut,lastDump,&d,sizeof(d));
2696 if (eval) ABORT(eval);
2699 /* We now have the last dump of the last appended dump */
2700 /* Copy this into our return structure */
2701 eval = FillDumpEntry(ut,lastDump,dumpEntry);
2702 if (eval) ABORT(eval);
2704 /* Fail if the last dump has no tapes */
2705 if (!d.firstTape) ABORT(BUDB_NOTAPENAME);
2707 /* Follow the tapes in this dump until we reach the last tape */
2708 eval = dbread (ut, ntohl(d.firstTape), &t, sizeof(t));
2709 if (eval) ABORT(eval);
2711 lastTape = ntohl(d.firstTape);
2712 lastTapeSeq = ntohl(t.seq);
2713 lastVol = ntohl(t.firstVol);
2717 thisTape = ntohl(t.nextTape);
2718 eval = dbread(ut,thisTape,&t,sizeof(t));
2719 if (eval) ABORT(eval);
2721 if (ntohl(t.seq) > lastTapeSeq)
2723 lastTape = thisTape;
2724 lastTapeSeq = ntohl(t.seq);
2725 lastVol = ntohl(t.firstVol);
2729 /* We now have the last tape of the last appended dump */
2730 /* Copy this into our return structure */
2731 eval = FillTapeEntry(ut,lastTape,tapeEntry);
2732 if (eval) ABORT(eval);
2734 /* Zero volume entry if the last tape has no volumes */
2736 bzero(volEntry, sizeof(*volEntry));
2738 /* Follow the volumes until we reach the last volume */
2739 eval = dbread (ut,lastVol,&vf,sizeof(vf));
2740 if (eval) ABORT(eval);
2742 lastVolPos = vf.position;
2744 while (vf.sameTapeChain) {
2745 thisVol = ntohl(vf.sameTapeChain);
2746 eval = dbread(ut,thisVol,&vf,sizeof(vf));
2747 if (eval) ABORT(eval);
2749 if (vf.position > lastVolPos) {
2751 lastVolPos = vf.position;
2755 /* We now have the last volume of this tape */
2756 /* Copy this into our return structure */
2757 eval = FillVolEntry(ut,lastVol,volEntry);
2758 if (eval) ABORT(eval);
2761 eval = ubik_EndTrans(ut);
2762 if (!code) code = eval;
2766 ubik_AbortTrans(ut);
2771 afs_int32 BUDB_GetTapes (call, majorVersion, flags, name, start, end, index, nextIndexP,
2773 struct rx_call *call;
2774 int majorVersion; /* version of interface structures */
2775 afs_int32 flags; /* search & select controls */
2776 char *name; /* s&s parameters */
2778 afs_int32 end; /* reserved: MBZ */
2779 afs_int32 index; /* start index of returned entries */
2780 afs_int32 *nextIndexP; /* output index for next call */
2782 budb_tapeList *tapes; /* pointer to buffer */
2786 code = GetTapes (call, majorVersion, flags, name, start, end,
2787 index, nextIndexP, dbTimeP, tapes);
2788 osi_auditU (call, BUDB_GetTpeEvent, code, AUD_END);
2792 afs_int32 GetTapes (call, majorVersion, flags, name, start, end,
2793 index, nextIndexP, dbTimeP, tapes)
2794 struct rx_call *call;
2795 int majorVersion; /* version of interface structures */
2796 afs_int32 flags; /* search & select controls */
2797 char *name; /* s&s parameters */
2799 afs_int32 end; /* reserved: MBZ */
2800 afs_int32 index; /* start index of returned entries */
2801 afs_int32 *nextIndexP; /* output index for next call */
2803 budb_tapeList *tapes; /* pointer to buffer */
2805 struct ubik_trans *ut;
2809 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2810 struct returnList list;
2811 afs_int32 eval, code = 0;
2814 if ( !callPermitted(call) )
2815 return BUDB_NOTPERMITTED;
2817 if (majorVersion != BUDB_MAJORVERSION)
2818 return BUDB_OLDINTERFACE;
2820 if (index < 0) return BUDB_ENDOFLIST;
2822 eval = InitRPC (&ut, LOCKREAD, 1);
2823 if (eval) return eval;
2825 nameFlags = flags & BUDB_OP_NAMES;
2826 startFlags = flags & BUDB_OP_STARTS;
2827 endFlags = flags & BUDB_OP_ENDS;
2828 timeFlags = flags & BUDB_OP_TIMES;
2830 InitReturnList (&list);
2833 if (nameFlags == BUDB_OP_TAPENAME)
2835 eval = ht_LookupEntry (ut, &db.tapeName, name, &ta, &t);
2836 if (eval) ABORT(eval);
2837 if (!ta) ABORT(BUDB_NOTAPENAME);
2840 if ( (startFlags & ~BUDB_OP_DUMPID) || endFlags || timeFlags ) ABORT(BUDB_BADFLAGS);
2842 /* follow the hash chain to the end */
2845 if (startFlags & BUDB_OP_DUMPID)
2847 /* read in the dump */
2848 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2849 if (eval) ABORT(eval);
2851 /* check if both name and dump id match */
2852 if ( (strcmp(name, t.name) == 0) && (ntohl(d.id) == start) )
2854 eval = AddToReturnList (&list, ta, &toskip);
2855 if (eval && (eval != BUDB_LIST2BIG)) ABORT(eval);
2861 /* Add to return list and continue search */
2862 if ( strcmp(name, t.name) == 0 )
2864 eval = AddToReturnList (&list, ta, &toskip);
2865 if (eval == BUDB_LIST2BIG) break;
2866 if (eval) ABORT(eval);
2870 ta = ntohl(t.nameHashChain);
2871 if (ta) dbread(ut, ta, &t, sizeof(t));
2874 else if (nameFlags == BUDB_OP_TAPESEQ)
2876 eval = ht_LookupEntry(ut,&db.dumpIden, &start, &da, &d);
2877 if (eval) ABORT(eval);
2878 if (!da) ABORT(BUDB_NODUMPNAME);
2880 /* search for the right tape */
2881 ta = ntohl(d.firstTape);
2882 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape))
2884 eval = dbread(ut, ta, &t, sizeof(t));
2885 if (eval) ABORT(eval);
2887 if (ntohl(t.seq) == end)
2889 eval = AddToReturnList (&list, ta, &toskip);
2890 if (eval && (eval != BUDB_LIST2BIG)) ABORT(eval);
2897 ABORT (BUDB_BADFLAGS);
2900 eval = SendReturnList (ut, &list, FillTapeEntry,
2901 sizeof(struct budb_tapeEntry),
2902 index, nextIndexP, dbTimeP, (returnList_t)tapes);
2903 if (eval) ABORT(eval);
2905 FreeReturnList(&list);
2906 code = ubik_EndTrans(ut);
2910 FreeReturnList(&list);
2911 ubik_AbortTrans(ut);
2916 * get a set of volumes according to the specified criteria.
2917 * See BUDB_GetDumps for general information on parameters
2918 * Currently supports:
2919 * 1) volume match - returns volumes based on volume name only.
2920 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
2921 * and start is a dumpid. Returns all volumes of the specified
2922 * name on the selected dumpid.
2925 afs_int32 BUDB_GetVolumes (call, majorVersion, flags, name, start, end,
2926 index, nextIndexP, dbTimeP, volumes)
2927 struct rx_call *call;
2928 int majorVersion; /* version of interface structures */
2929 afs_int32 flags; /* search & select controls */
2930 char *name; /* - parameters for search */
2931 afs_int32 start; /* - usage depends which BUDP_OP_* */
2932 afs_int32 end; /* - bits are set */
2933 afs_int32 index; /* start index of returned entries */
2934 afs_int32 *nextIndexP; /* output index for next call */
2936 budb_volumeList *volumes; /* pointer to buffer */
2940 code = GetVolumes (call, majorVersion, flags, name, start, end,
2941 index, nextIndexP, dbTimeP, volumes);
2942 osi_auditU (call, BUDB_GetVolEvent, code, AUD_END);
2946 afs_int32 GetVolumes (call, majorVersion, flags, name, start, end,
2947 index, nextIndexP, dbTimeP, volumes)
2948 struct rx_call *call;
2949 int majorVersion; /* version of interface structures */
2950 afs_int32 flags; /* search & select controls */
2951 char *name; /* - parameters for search */
2952 afs_int32 start; /* - usage depends which BUDP_OP_* */
2953 afs_int32 end; /* - bits are set */
2954 afs_int32 index; /* start index of returned entries */
2955 afs_int32 *nextIndexP; /* output index for next call */
2957 budb_volumeList *volumes; /* pointer to buffer */
2959 struct ubik_trans *ut;
2962 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2963 afs_int32 eval, code = 0;
2964 struct returnList vollist;
2967 /* Don't check permissions when we look up a specific volume name */
2968 if ( ((flags & BUDB_OP_NAMES) != BUDB_OP_VOLUMENAME) && !callPermitted(call) )
2969 return BUDB_NOTPERMITTED;
2971 if (majorVersion != BUDB_MAJORVERSION) return BUDB_OLDINTERFACE;
2972 if (index < 0) return BUDB_ENDOFLIST;
2974 eval = InitRPC (&ut, LOCKREAD, 1);
2975 if (eval) return eval;
2977 nameFlags = flags & BUDB_OP_NAMES;
2978 startFlags = flags & BUDB_OP_STARTS;
2979 endFlags = flags & BUDB_OP_ENDS;
2980 timeFlags = flags & BUDB_OP_TIMES;
2982 InitReturnList (&vollist);
2985 /* lookup a the volume (specified by name) in the dump (specified by id) */
2986 if (nameFlags == BUDB_OP_VOLUMENAME)
2988 /* dumpid permissible, all others off */
2989 if ( ((startFlags & ~BUDB_OP_DUMPID) != 0) || endFlags || timeFlags )
2990 ABORT(BUDB_BADFLAGS);
2992 /* returns ptr to volinfo of requested name */
2993 eval = ht_LookupEntry (ut, &db.volName, name, &via, &vi);
2994 if (eval) ABORT(eval);
2995 if (!via) ABORT(BUDB_NOVOLUMENAME);
2997 /* Iterate over all volume fragments with this name */
3000 struct volFragment v;
3003 /* traverse all the volume fragments for this volume info structure */
3004 for (va=vi.firstFragment; va; va=v.sameNameChain)
3007 eval = dbread (ut, va, &v, sizeof(v));
3008 if (eval) ABORT(eval);
3010 if ( startFlags & BUDB_OP_DUMPID )
3015 /* get the dump id for this fragment */
3016 eval = dbread(ut, ntohl(v.tape), &atape, sizeof(atape));
3017 if (eval) ABORT(eval);
3019 eval = dbread(ut, ntohl(atape.dump), &adump, sizeof(adump));
3020 if (eval) ABORT(BUDB_IO);
3022 /* dump id does not match */
3023 if ( ntohl(adump.id) != start )
3027 eval = AddToReturnList (&vollist, va, &toskip);
3028 if (eval == BUDB_LIST2BIG) break;
3029 if (eval) ABORT(eval);
3031 if (eval == BUDB_LIST2BIG) break;
3033 via = vi.sameNameChain;
3034 if (via == 0) break;
3037 eval = dbread (ut, via, &vi, sizeof(vi));
3038 if (eval) ABORT(eval);
3041 else if ( ((nameFlags == 0) || (nameFlags == BUDB_OP_TAPENAME)) &&
3042 (startFlags == BUDB_OP_DUMPID) )
3048 struct volFragment volFrag;
3051 /* lookup all volumes for a specified dump id */
3053 /* no other flags should be set */
3054 if (endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
3057 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &dumpAddr, &dump);
3058 if (eval) ABORT(eval);
3060 /* traverse all the tapes */
3061 for (tapeAddr=ntohl(dump.firstTape); tapeAddr; tapeAddr=ntohl(tape.nextTape))
3063 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
3064 if (eval) ABORT(eval);
3066 if ( ( nameFlags != BUDB_OP_TAPENAME ) ||
3067 ((nameFlags == BUDB_OP_TAPENAME) && (strcmp(tape.name,name) == 0)) )
3069 /* now return all the volumes */
3070 for (volFragAddr=ntohl(tape.firstVol); volFragAddr;
3071 volFragAddr=ntohl(volFrag.sameTapeChain))
3073 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
3074 if (eval) ABORT(eval);
3076 eval = AddToReturnList(&vollist, volFragAddr, &toskip);
3077 if (eval == BUDB_LIST2BIG) break;
3078 if (eval) ABORT(eval);
3081 if (eval == BUDB_LIST2BIG) break;
3086 ABORT(BUDB_BADFLAGS);
3089 eval = SendReturnList(ut, &vollist, FillVolEntry, sizeof(struct budb_volumeEntry),
3090 index, nextIndexP, dbTimeP, (returnList_t)volumes);
3091 if (eval) ABORT(eval);
3094 FreeReturnList(&vollist);
3095 code = ubik_EndTrans(ut);
3099 FreeReturnList(&vollist);
3100 ubik_AbortTrans(ut);
3104 afs_int32 BUDB_UseTape (call, tape, new)
3105 struct rx_call *call;
3106 struct budb_tapeEntry *tape; /* tape info */
3107 int *new; /* set if tape is new */
3111 code = UseTape (call, tape, new);
3112 osi_auditU (call, BUDB_UseTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
3116 afs_int32 UseTape (call, tape, new)
3117 struct rx_call *call;
3118 struct budb_tapeEntry *tape; /* tape info */
3119 int *new; /* set if tape is new */
3121 struct ubik_trans *ut;
3125 afs_int32 eval, code;
3127 if ( !callPermitted(call) )
3128 return BUDB_NOTPERMITTED;
3130 if (strlen (tape->name) >= sizeof(t.name)) return BUDB_BADARGUMENT;
3132 eval = InitRPC (&ut, LOCKWRITE, 1);
3133 if (eval) return eval;
3137 bzero (&t, sizeof(t));
3138 eval = AllocStructure (ut, tape_BLOCK, 0, &a, &t);
3139 if (eval) ABORT(eval);
3141 strcpy (t.name, tape->name);
3143 eval = ht_HashIn (ut, &db.tapeName, a, &t);
3144 if (eval) ABORT(eval);
3148 /* Since deleting a tape may change the dump (if its the same one), read in
3149 the dump after the call to DeleteTape. */
3151 eval = ht_LookupEntry (ut, &db.dumpIden, &tape->dump, &da, &d);
3152 if (eval) ABORT(eval);
3153 if (!da) ABORT(BUDB_NODUMPID);
3155 if (!tape->written) tape->written = time(0); /* fill in tape struct */
3156 t.written = htonl(tape->written);
3157 t.expires = htonl(tape->expires);
3159 t.seq = htonl(tape->seq);
3160 t.useCount = htonl(tape->useCount);
3161 t.labelpos = htonl(tape->labelpos);
3163 t.flags = htonl(tape->flags | BUDB_TAPE_BEINGWRITTEN);
3165 t.nextTape = d.firstTape; /* Chain the tape to the dump */
3166 d.firstTape = htonl(a);
3168 if (tape->seq >= ntohl(d.tapes.maxTapes)) /* inc # tapes in the dump */
3169 d.tapes.maxTapes = htonl(tape->seq);
3171 eval = dbwrite (ut, a, &t, sizeof(t)); /* write tape struct */
3172 if (eval) ABORT(eval);
3174 eval = dbwrite (ut, da, &d, sizeof(d)); /* write the dump struct */
3175 if (eval) ABORT(eval);
3177 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
3178 if (eval) ABORT(eval);
3180 LogDebug(5, "added tape %s\n", tape->name);
3182 code = ubik_EndTrans(ut);
3186 ubik_AbortTrans(ut);
3192 /* ---------------------------------------------
3193 * debug interface routines
3194 * ---------------------------------------------
3197 afs_int32 BUDB_T_DumpHashTable (call, type, filename)
3198 struct rx_call *call;
3204 code = T_DumpHashTable (call, type, filename);
3205 osi_auditU (call, BUDB_TDmpHaEvent, code, AUD_STR, filename, AUD_END);
3209 afs_int32 T_DumpHashTable (call, type, filename)
3210 struct rx_call *call;
3214 struct ubik_trans *ut;
3215 struct memoryHashTable *mht;
3217 afs_int32 eval, code = 0;
3224 char e[sizeof(struct block)]; /* unnecessarily conservative */
3228 if ( !callPermitted(call) )
3229 return BUDB_NOTPERMITTED;
3231 if (strlen (filename) >= sizeof(path)-5) return BUDB_BADARGUMENT;
3233 eval = InitRPC (&ut, LOCKWRITE, 1);
3234 if (eval) return eval;
3236 if ((mht = ht_GetType (type, &e_size)) == 0) return BUDB_BADARGUMENT;
3238 sprintf(path, "%s/%s", gettmpdir(), filename);
3240 DUMP = fopen (path, "w");
3241 if (!DUMP) ABORT(BUDB_BADARGUMENT);
3244 for (old=0; ; old++)
3246 length = (old ? mht->oldLength : mht->length);
3247 if (length) fprintf (DUMP, "Dumping %sHash Table:\n", (old?"Old ":""));
3249 for (hash=0; hash<length; hash++)
3251 a = ht_LookupBucket (ut, mht, hash, old);
3255 eval = dbread (ut, a, e, e_size);
3256 if (eval) ABORT(eval);
3259 if (a == first_a) fprintf (DUMP, " in bucket %d at %d is ", hash, a);
3260 else fprintf (DUMP, " at %d is ", a);
3262 case HT_dumpIden_FUNCTION:
3263 fprintf (DUMP, "%d\n", ntohl(((struct dump *)e)->id));
3265 case HT_dumpName_FUNCTION:
3266 fprintf (DUMP, "%s\n", ((struct dump *)e)->dumpName);
3268 case HT_tapeName_FUNCTION:
3269 fprintf (DUMP, "%s\n", ((struct tape *)e)->name);
3271 case HT_volName_FUNCTION:
3272 fprintf (DUMP, "%s\n", ((struct volInfo *)e)->name);
3275 if ((ht_HashEntry(mht,e) % length) != hash) ABORT(BUDB_DATABASEINCONSISTENT);
3276 a = ntohl(*(dbadr *)(e + mht->threadOffset));
3282 fprintf (DUMP, "%d entries found\n", ent);
3283 if (ntohl(mht->ht->entries) != ent) ABORT(BUDB_DATABASEINCONSISTENT);
3285 code = ubik_EndTrans(ut);
3286 if (DUMP) fclose (DUMP);
3290 ubik_AbortTrans(ut);
3291 if (DUMP) fclose (DUMP);
3295 afs_int32 BUDB_T_GetVersion (call, majorVersion)
3296 struct rx_call *call;
3301 code = T_GetVersion (call, majorVersion);
3302 osi_auditU (call, BUDB_TGetVrEvent, code, AUD_END);
3306 afs_int32 T_GetVersion (call, majorVersion)
3307 struct rx_call *call;
3310 struct ubik_trans *ut;
3313 code = InitRPC (&ut, LOCKREAD, 0);
3314 if (code) return(code);
3316 *majorVersion = BUDB_MAJORVERSION;
3318 code = ubik_EndTrans(ut);
3322 /* BUDB_T_DumpDatabase
3323 * dump as much of the database as possible int /tmp/<filename>
3326 afs_int32 BUDB_T_DumpDatabase (call, filename)
3327 struct rx_call *call;
3332 code = T_DumpDatabase (call, filename);
3333 osi_auditU (call, BUDB_TDmpDBEvent, code, AUD_STR, filename, AUD_END);
3337 afs_int32 T_DumpDatabase (call, filename)
3338 struct rx_call *call;
3343 struct ubik_trans *ut;
3346 int type, old, length, hash;
3348 struct memoryHashTable *mht;
3349 afs_int32 eval, code = 0;
3351 if ( !callPermitted(call) )
3352 return BUDB_NOTPERMITTED;
3354 path = (char *) malloc(strlen(gettmpdir())+1+strlen(filename)+1);
3355 if (!path) return(BUDB_INTERNALERROR);
3357 sprintf(path, "%s/%s", gettmpdir(), filename);
3359 dumpfid = fopen(path, "w");
3360 if (!dumpfid) return(BUDB_BADARGUMENT);
3362 eval = InitRPC (&ut, LOCKWRITE, 1);
3363 if (eval) return(eval);
3365 /* dump all items in the database */
3366 for ( type=1; type<=HT_MAX_FUNCTION; type++ )
3368 mht = ht_GetType (type, &entrySize);
3369 if (!mht) ERROR(BUDB_BADARGUMENT);
3371 for ( old =0; old <= 1; old++ )
3373 length = ( old ? mht->oldLength : mht->length);
3374 if (!length) continue;
3376 fprintf (dumpfid, "Dumping %s Hash Table:\n", (old ? "Old ":""));
3378 for ( hash = 0; hash < length; hash++ )
3380 dbAddr = ht_LookupBucket (ut, mht, hash, old);
3386 case HT_dumpIden_FUNCTION:
3388 struct dump hostDump, diskDump;
3390 eval = cdbread (ut, dump_BLOCK, dbAddr, &diskDump, sizeof(diskDump));
3391 if (eval) ERROR(eval);
3393 fprintf(dumpfid, "\ndumpId hash %d, entry at %u: block %d, index %d\n",
3394 hash, dbAddr, block, index);
3395 fprintf(dumpfid, "----------------------------\n");
3396 dump_ntoh(&diskDump, &hostDump);
3397 printDump(dumpfid, &hostDump);
3398 dbAddr = hostDump.idHashChain;
3402 case HT_dumpName_FUNCTION:
3404 struct dump hostDump, diskDump;
3406 eval = cdbread (ut, dump_BLOCK, dbAddr, &diskDump, sizeof(diskDump));
3407 if (eval) ERROR(eval);
3410 "\ndumpname hash %d, entry at %u: block %d, index %d\n",
3411 hash, dbAddr, block, index);
3412 fprintf(dumpfid, "----------------------------\n");
3413 dump_ntoh(&diskDump, &hostDump);
3414 printDump(dumpfid, &hostDump);
3415 dbAddr = hostDump.nameHashChain;
3419 case HT_tapeName_FUNCTION:
3421 struct tape hostTape, diskTape;
3423 eval = cdbread (ut, tape_BLOCK, dbAddr, &diskTape, sizeof(diskTape));
3424 if (eval) ERROR(eval);
3427 "\ntapename hash %d, entry at %u: block %d, index %d\n",
3428 hash, dbAddr, block, index);
3429 fprintf(dumpfid, "----------------------------\n");
3430 tape_ntoh(&diskTape, &hostTape);
3431 printTape(dumpfid, &hostTape);
3432 dbAddr = hostTape.nameHashChain;
3436 case HT_volName_FUNCTION:
3438 struct volInfo hostVolInfo, diskVolInfo;
3440 eval = cdbread (ut, volInfo_BLOCK, dbAddr, &diskVolInfo, sizeof(diskVolInfo));
3441 if (eval) ERROR(eval);
3444 "\nvolname hash %d, entry at %u: block %d, index %d\n",
3445 hash, dbAddr, block, index);
3446 fprintf(dumpfid, "----------------------------\n");
3447 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3448 printVolInfo(dumpfid, &hostVolInfo);
3449 dbAddr = hostVolInfo.nameHashChain;
3451 volFragsDump(ut, dumpfid,
3452 hostVolInfo.firstFragment);
3457 fprintf(dumpfid, "unknown type %d\n", type);
3467 code = ubik_EndTrans(ut); /* is this safe if no ut started ?*/
3468 if (dumpfid) fclose(dumpfid);
3469 if (path) free(path);
3473 volFragsDump(ut, dumpfid, dbAddr)
3474 struct ubik_trans *ut;
3478 struct volFragment hostVolFragment, diskVolFragment;
3484 code = cdbread (ut, volFragment_BLOCK, dbAddr, &diskVolFragment, sizeof(diskVolFragment));
3485 if (code) { /* don't be fussy about errors */
3486 fprintf(dumpfid, "volFragsDump: Error reading database\n");
3490 fprintf(dumpfid, "\nvolfragment entry at %u: block %d, index %d\n",
3491 dbAddr, block, index);
3492 fprintf(dumpfid, "----------------------------\n");
3493 volFragment_ntoh(&diskVolFragment, &hostVolFragment);
3494 printVolFragment(dumpfid, &hostVolFragment);
3495 dbAddr = hostVolFragment.sameNameChain;
3501 /* utilities - network to host conversion
3502 * currently used for debug only
3505 volFragmentDiskToHost(diskVfPtr, hostVfPtr)
3506 struct volFragment *diskVfPtr, *hostVfPtr;
3508 hostVfPtr->vol = ntohl(diskVfPtr->vol);
3509 hostVfPtr->sameNameChain = ntohl(diskVfPtr->sameNameChain);
3510 hostVfPtr->tape = ntohl(diskVfPtr->tape);
3511 hostVfPtr->sameTapeChain = ntohl(diskVfPtr->sameTapeChain);
3512 hostVfPtr->position = ntohl(diskVfPtr->position);
3513 hostVfPtr->clone = ntohl(diskVfPtr->clone);
3514 hostVfPtr->incTime = ntohl(diskVfPtr->incTime);
3515 hostVfPtr->startByte = ntohl(diskVfPtr->startByte);
3516 hostVfPtr->nBytes = ntohl(diskVfPtr->nBytes);
3517 hostVfPtr->flags = ntohs(diskVfPtr->flags);
3518 hostVfPtr->sequence = ntohs(diskVfPtr->sequence);
3521 volInfoDiskToHost(diskViPtr, hostViPtr)
3522 struct volInfo *diskViPtr, *hostViPtr;
3524 strcpy(hostViPtr->name, diskViPtr->name);
3525 hostViPtr->nameHashChain = ntohl(diskViPtr->nameHashChain);
3526 hostViPtr->id = ntohl(diskViPtr->id);
3527 strcpy(hostViPtr->server, diskViPtr->server);
3528 hostViPtr->partition = ntohl(diskViPtr->partition);
3529 hostViPtr->flags = ntohl(diskViPtr->flags);
3530 hostViPtr->sameNameHead = ntohl(diskViPtr->sameNameHead);
3531 hostViPtr->sameNameChain = ntohl(diskViPtr->sameNameChain);
3532 hostViPtr->firstFragment = ntohl(diskViPtr->firstFragment);
3533 hostViPtr->nFrags = ntohl(diskViPtr->nFrags);
3536 tapeDiskToHost(diskTapePtr, hostTapePtr)
3537 struct tape *diskTapePtr, *hostTapePtr;
3539 strcpy(hostTapePtr->name, diskTapePtr->name);
3540 hostTapePtr->nameHashChain = ntohl(diskTapePtr->nameHashChain);
3541 hostTapePtr->flags = ntohl(diskTapePtr->flags);
3543 /* tape id conversion here */
3544 hostTapePtr->written = ntohl(diskTapePtr->written);
3545 hostTapePtr->nBytes = ntohl(diskTapePtr->nBytes);
3546 hostTapePtr->nFiles = ntohl(diskTapePtr->nFiles);
3547 hostTapePtr->nVolumes = ntohl(diskTapePtr->nVolumes);
3548 hostTapePtr->seq = ntohl(diskTapePtr->seq);
3549 hostTapePtr->dump = ntohl(diskTapePtr->dump);
3550 hostTapePtr->nextTape = ntohl(diskTapePtr->nextTape);
3551 hostTapePtr->firstVol = ntohl(diskTapePtr->firstVol);
3552 hostTapePtr->useCount = ntohl(diskTapePtr->useCount);
3555 dumpDiskToHost(diskDumpPtr, hostDumpPtr)
3556 struct dump *diskDumpPtr, *hostDumpPtr;
3558 hostDumpPtr->id = ntohl(diskDumpPtr->id);
3559 hostDumpPtr->idHashChain = ntohl(diskDumpPtr->idHashChain);
3560 strcpy(hostDumpPtr->dumpName, diskDumpPtr->dumpName);
3561 strcpy(hostDumpPtr->dumpPath, diskDumpPtr->dumpPath);
3562 strcpy(hostDumpPtr->volumeSet, diskDumpPtr->volumeSet);
3563 hostDumpPtr->nameHashChain = ntohl(diskDumpPtr->nameHashChain);
3564 hostDumpPtr->flags = ntohl(diskDumpPtr->flags);
3565 hostDumpPtr->parent = ntohl(diskDumpPtr->parent);
3566 hostDumpPtr->created = ntohl(diskDumpPtr->created);
3567 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3568 hostDumpPtr->nVolumes = ntohl(diskDumpPtr->nVolumes);
3570 /* tapeset conversion here */
3572 hostDumpPtr->firstTape = ntohl(diskDumpPtr->firstTape);
3574 /* principal conversion here */
3579 checkHash(ut,hashType)
3580 struct ubik_trans *ut;
3583 struct memoryHashTable *mhtPtr;
3584 int entrySize, hashTableLength;
3589 mhtPtr = ht_GetType(hashType, &entrySize);
3593 for ( old = 0; old < 1; old++)
3595 LogDebug(5, "\nold = %d\n", old);
3596 printMemoryHashTable(stdout, mhtPtr);
3598 hashTableLength = ( old ? mhtPtr->oldLength : mhtPtr->length);
3600 for ( bucket = 0; bucket < hashTableLength; bucket++ )
3604 entryAddr = ht_LookupBucket (ut, mhtPtr, bucket, old);
3605 while (entryAddr != 0)
3607 LogDebug(6, "bucket %d has disk addr %d\n", bucket, entryAddr);
3610 case HT_dumpIden_FUNCTION:
3612 struct dump diskDump, hostDump;
3614 code = dbread(ut, entryAddr, &diskDump, entrySize);
3615 if (code) ERROR(-1);
3617 dump_ntoh(&diskDump, &hostDump);
3618 printDump(stdout, &hostDump);
3619 entryAddr = hostDump.idHashChain;
3623 case HT_dumpName_FUNCTION:
3626 case HT_tapeName_FUNCTION:
3629 case HT_volName_FUNCTION:
3631 struct volInfo diskVolInfo, hostVolInfo;
3633 code = dbread(ut, entryAddr, &diskVolInfo, entrySize);
3634 if (code) ERROR(-1);
3636 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3637 printVolInfo(stdout, &hostVolInfo);
3638 entryAddr = hostVolInfo.nameHashChain;