2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * ht_lookupEntry - tape ids
12 * Truncate Tape - tape id's
16 #include <afsconfig.h>
17 #include <afs/param.h>
24 #include <netinet/in.h>
26 #include <sys/param.h>
28 #include <sys/resource.h>
31 #include <sys/types.h>
33 #include <afs/bubasics.h>
42 #include <afs/cellconfig.h>
46 #include "budb_errs.h"
48 #include "error_macros.h"
50 #include "afs/audit.h"
51 #include <afs/afsutil.h>
57 extern struct ubik_dbase *BU_dbase;
58 extern struct afsconf_dir *BU_conf; /* for getting cell info */
59 extern afs_int32 myHost;
60 extern struct memoryDB db; /* incore copies of db structures */
62 afs_int32 AddVolume(), AddVolumes(), CreateDump(), DoDeleteDump(), DoDeleteTape(), ListDumps();
63 afs_int32 DeleteVDP(), FindClone(), FindDump(), FindLatestDump();
64 afs_int32 FinishDump(), FinishTape(), GetDumps(), getExpiration(), T_DumpDatabase();
65 afs_int32 makeAppended(), MakeDumpAppended(), FindLastTape(), GetTapes();
66 afs_int32 GetVolumes(), UseTape(), T_DumpHashTable(), T_GetVersion();
68 /* Text block management */
72 struct memTextBlock *mtb_next; /* next in chain */
73 afs_int32 mtb_nbytes; /* # of bytes in this block */
74 struct blockHeader mtb_blkHeader; /* in memory header */
75 dbadr mtb_addr; /* disk address of block */
78 typedef struct memTextBlock memTextBlockT;
79 typedef memTextBlockT *memTextBlockP;
81 /* These variable are for returning debugging info about the state of the
82 server. If they get trashed during multi-threaded operation it doesn't
85 /* This is global so COUNT_REQ in krb_udp.c can refer to it. */
86 char *lastOperation; /* name of last operation */
87 static Date lastTrans; /* time of last transaction */
89 /* procsInited is sort of a lock: during a transaction only one process runs
90 while procsInited is false. */
92 static int procsInited = 0;
94 /* This variable is protected by the procsInited flag. */
96 static int (*rebuildDatabase)();
98 /* AwaitInitialization
99 * Wait unitl budb has initialized (InitProcs). If it hasn't
100 * within 5 seconds, then return no quorum.
103 AwaitInitialization()
109 if (!start) start = time(0);
110 else if (time(0)-start > 5) return UNOQUORUM;
117 * name is a pathname style name, determine trailing name and return
122 tailCompPtr(pathNamePtr)
126 ptr = strrchr(pathNamePtr, '/');
129 /* this should never happen */
130 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
135 ptr++; /* skip the / */
140 * Check to see if the caller is a SuperUser.
147 struct rx_call *call;
150 struct afsconf_dir *acdir;
152 acdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
153 if (!acdir) return 0;
155 if ( afsconf_SuperUser(acdir, call, (char *)0) )
159 if (acdir) afsconf_Close(acdir);
164 * This is called by every RPC interface to create a Ubik transaction
165 * and read the database header into core
171 * sets a lock on byte 1 of the database. Looks like it enforces
172 * single threading by use of the lock.
176 InitRPC (ut, lock, this_op)
177 struct ubik_trans **ut;
178 int lock; /* indicate read/write transaction */
179 int this_op; /* opcode of RCP, for COUNT_ABO */
182 float wait = 0.91; /* start waiting for 1 second */
185 /* wait for server initialization to finish if this is not InitProcs calling */
187 if (code = AwaitInitialization())
190 for (code = UNOQUORUM; code == UNOQUORUM; )
192 code = ubik_BeginTrans(BU_dbase,
193 ((lock == LOCKREAD) ? UBIK_READTRANS : UBIK_WRITETRANS),
195 if (code == UNOQUORUM)
196 { /* no quorum elected */
197 if (wait < 1) Log("Waiting for quorum election\n");
198 if (wait < 15.0) wait *= 1.1;
199 IOMGR_Sleep ((int)wait);
202 if (code) return code;
203 if (wait > 1) Log("Have established quorum\n");
205 /* set lock at posiion 1, for 1 byte of type lock */
206 if (code = ubik_SetLock (*ut, 1, 1, lock))
208 ubik_AbortTrans (*ut);
212 /* check that dbase is initialized and setup cheader */
213 if (lock == LOCKREAD)
215 /* init but don't fix because this is read only */
216 if ( code = CheckInit(*ut, 0) )
218 ubik_AbortTrans(*ut);
219 if ( code = InitRPC(ut, LOCKWRITE, 0) ) /* Now fix the database */
221 LogError(code, "InitRPC: InitRPC failed\n");
224 if ( code = ubik_EndTrans(*ut) )
226 LogError(code, "InitRPC: ubik_EndTrans failed\n");
229 goto start; /* now redo the read transaction */
234 if (code = CheckInit(*ut, rebuildDatabase))
236 ubik_AbortTrans(*ut);
244 /* This is called to initialize a newly created database */
245 static int initialize_database (ut)
246 struct ubik_trans *ut;
251 static int noAuthenticationRequired; /* global state */
252 static int recheckNoAuth; /* global state */
257 struct ubik_trans *ut;
262 if ( (globalConfPtr->myHost == 0) || (BU_conf == 0) )
263 ERROR(BUDB_INTERNALERROR);
267 if ( globalConfPtr->debugFlags & DF_NOAUTH )
268 noAuthenticationRequired = 1;
270 if ( globalConfPtr->debugFlags & DF_RECHECKNOAUTH )
274 noAuthenticationRequired = afsconf_GetNoAuthFlag(BU_conf);
276 if (noAuthenticationRequired)
277 LogError(0, "Running server with security disabled\n");
281 rebuildDatabase = initialize_database;
283 if (code = InitRPC (&ut, LOCKREAD, 0))
285 LogError(code, "InitProcs: InitRPC failed\n");
288 code = ubik_EndTrans(ut);
291 LogError(code, "InitProcs: ubik_EndTrans failed\n");
295 rebuildDatabase = 0; /* only do this during init */
303 int nElements; /* number in list */
304 int allocSize; /* number of elements allocated */
305 dbadr *elements; /* array of addresses */
308 static void InitReturnList (list)
309 struct returnList *list;
313 list->elements = (dbadr *)0;
316 static void FreeReturnList (list)
317 struct returnList *list;
319 if (list->elements) free(list->elements);
320 list->elements = (dbadr *)0;
324 /* As entries are collected, they are added to a return list. Once all
325 * entries have been collected, it is then placed in the return buffer
326 * with SendReturnList(). The first *to_skipP are not recorded.
328 static afs_int32 AddToReturnList (list, a, to_skipP)
329 struct returnList *list;
336 if (a == 0) return 0;
342 /* Up to 5 plus a maximum so SendReturnList() knows if we
343 * need to come back for more.
345 if (list->nElements >= BUDB_MAX_RETURN_LIST+5)
346 return BUDB_LIST2BIG;
348 if (list->nElements >= list->allocSize) {
349 if (list->elements == 0) {
351 tmp = (char *) malloc (sizeof(dbadr) * size);
353 size = list->allocSize + 10;
354 tmp = (char *) realloc (list->elements, sizeof(dbadr) * size);
356 if (!tmp) return BUDB_NOMEM;
357 list->elements = (dbadr *) tmp;
358 list->allocSize = size;
361 list->elements[list->nElements] = a;
366 afs_int32 FillVolEntry(ut, va, vol)
367 struct ubik_trans *ut;
369 struct budb_volumeEntry *vol;
374 struct volFragment vf;
376 if (dbread (ut, va, &vf, sizeof(vf))) return BUDB_IO; /* The volFrag */
377 if (dbread (ut, ntohl(vf.vol), &vi, sizeof(vi))) return BUDB_IO; /* The volInfo */
378 if (dbread (ut, ntohl(vf.tape), &t, sizeof(t))) return BUDB_IO; /* The tape */
379 if (dbread (ut, ntohl(t.dump), &d, sizeof(d))) return BUDB_IO; /* The dump */
381 strcpy (vol->name, vi.name);
382 strcpy (vol->server, vi.server);
383 strcpy (vol->tape, t.name);
384 vol->tapeSeq = ntohl(t.seq);
385 vol->dump = ntohl(d.id);
386 vol->position = ntohl(vf.position);
387 vol->clone = ntohl(vf.clone);
388 vol->incTime = ntohl(vf.incTime);
389 vol->nBytes = ntohl(vf.nBytes);
390 vol->startByte = ntohl(vf.startByte);
391 vol->flags = (ntohs(vf.flags) & VOLFRAGMENTFLAGS); /* low 16 bits here */
392 vol->flags |= (ntohl(vi.flags) & VOLINFOFLAGS); /* high 16 bits here */
393 vol->seq = ntohs(vf.sequence);
394 vol->id = ntohl(vi.id);
395 vol->partition = ntohl(vi.partition);
400 afs_int32 FillDumpEntry (ut, da, dump)
401 struct ubik_trans *ut;
403 struct budb_dumpEntry *dump;
407 if (dbread (ut, da, &d, sizeof(d))) return BUDB_IO;
408 dump->id = ntohl(d.id);
409 dump->flags = ntohl(d.flags);
410 dump->created = ntohl(d.created);
411 strncpy (dump->name, d.dumpName, sizeof(dump->name));
412 strncpy (dump->dumpPath, d.dumpPath, sizeof(dump->dumpPath));
413 strncpy (dump->volumeSetName, d.volumeSet, sizeof(dump->volumeSetName));
415 dump->parent = ntohl(d.parent);
416 dump->level = ntohl(d.level);
417 dump->nVolumes = ntohl(d.nVolumes);
419 tapeSet_ntoh(&d.tapes, &dump->tapes);
421 if (strlen(d.dumper.name) < sizeof(dump->dumper.name))
422 strcpy (dump->dumper.name, d.dumper.name);
423 if (strlen(d.dumper.instance) < sizeof(dump->dumper.instance))
424 strcpy (dump->dumper.instance, d.dumper.instance);
425 if (strlen(d.dumper.cell) < sizeof(dump->dumper.cell))
426 strcpy (dump->dumper.cell, d.dumper.cell);
428 /* Get the initial dumpid and the appended dump id */
429 dump->initialDumpID = ntohl(d.initialDumpID);
430 if (d.appendedDumpChain)
432 if (dbread (ut, ntohl(d.appendedDumpChain), &ad, sizeof(ad))) return BUDB_IO;
433 dump->appendedDumpID = ntohl(ad.id);
436 dump->appendedDumpID = 0;
438 /* printf("dump name %s, parent %d, level %d\n",
439 d.dumpName, ntohl(d.parent), ntohl(d.level)); */
444 afs_int32 FillTapeEntry (ut, ta, tape)
445 struct ubik_trans *ut;
447 struct budb_tapeEntry *tape;
453 if ( dbread (ut, ta, &t, sizeof(t)) )
456 /* Get the tape's expiration date */
457 if ( code = getExpiration(ut,&t) )
460 strcpy (tape->name, t.name);
461 tape->flags = ntohl(t.flags);
462 tape->written = ntohl(t.written);
463 tape->expires = ntohl(t.expires);
464 tape->nMBytes = ntohl(t.nMBytes);
465 tape->nBytes = ntohl(t.nBytes);
466 tape->nFiles = ntohl(t.nFiles);
467 tape->nVolumes = ntohl(t.nVolumes);
468 tape->seq = ntohl(t.seq);
469 tape->labelpos = ntohl(t.labelpos);
470 tape->useCount = ntohl(t.useCount);
471 tape->useKBytes = ntohl(t.useKBytes);
473 if (dbread (ut, ntohl(t.dump), &d, sizeof(d))) return BUDB_IO;
474 tape->dump = ntohl(d.id);
478 #define returnList_t budb_dumpList *
481 * A list of elements of size e_size is in list, collected
482 * with AddToReturnList(). We will move this to a correspoding
483 * return list, eList, via FillProc(). nextInodeP tells us
484 * if there are more and how many to skip on the next request.
487 SendReturnList (ut, list, FillProc, e_size, index, nextIndexP, dbTimeP, eList)
488 struct ubik_trans *ut;
489 struct returnList *list; /* list of elements to return */
490 afs_int32 (*FillProc)(); /* proc to fill entry */
491 int e_size; /* size of each element */
492 afs_int32 index; /* index from previous call */
493 afs_int32 *nextIndexP; /* if more elements are available */
494 afs_int32 *dbTimeP; /* time of last db update */
495 budb_dumpList *eList; /* rxgen list structure (e.g.) */
503 *dbTimeP = ntohl(db.h.lastUpdate);
505 /* Calculate how many to return. Don't let if go over
506 * BUDB_MAX_RETURN_LIST nor the size of our return list.
508 to_return = list->nElements;
509 if (to_return > BUDB_MAX_RETURN_LIST)
510 to_return = BUDB_MAX_RETURN_LIST;
511 if (eList->budb_dumpList_len && (to_return > eList->budb_dumpList_len))
512 to_return = eList->budb_dumpList_len;
514 /* Allocate space for the return values if needed and zero it */
515 if (eList->budb_dumpList_val == 0) {
516 eList->budb_dumpList_val = (struct budb_dumpEntry *)malloc (e_size * to_return);
517 if (!eList->budb_dumpList_val) return(BUDB_NOMEM);
519 memset(eList->budb_dumpList_val, 0, e_size * to_return);
520 eList->budb_dumpList_len = to_return;
522 e = (char *)(eList->budb_dumpList_val);
523 for (i=0; i<to_return; i++, e += e_size) {
524 code = (*FillProc) (ut, list->elements[i], e);
525 if (code) return code;
528 if (list->nElements > i)
529 *nextIndexP = index + i;
533 /* Come here to delete a volInfo structure. */
535 static afs_int32 DeleteVolInfo (ut, via, vi)
536 struct ubik_trans *ut;
543 if (vi->firstFragment) return 0; /* still some frags, don't free yet */
544 if (vi->sameNameHead == 0) { /* this is the head */
545 if (vi->sameNameChain) return 0; /* empty head, some non-heads left */
547 code = ht_HashOut (ut, &db.volName, via, vi);
548 if (code) return code;
549 code = FreeStructure (ut, volInfo_BLOCK, via);
552 hvia = ntohl(vi->sameNameHead);
553 if (dbread (ut, hvia, &hvi, sizeof(hvi))) return BUDB_IO;
554 code = RemoveFromList (ut, hvia, &hvi, &hvi.sameNameChain, via, vi, &vi->sameNameChain);
555 if (code == -1) return BUDB_DATABASEINCONSISTENT;
556 if (code == 0) code = FreeStructure (ut, volInfo_BLOCK, via);
560 /* Detach a volume fragment from its volInfo structure. Its tape chain is
561 already freed. This routine frees the structure and the caller must not
564 static afs_int32 DeleteVolFragment (ut, va, v)
565 struct ubik_trans *ut;
567 struct volFragment *v;
573 if (dbread (ut, via, &vi, sizeof(vi))) return BUDB_IO;
574 code = RemoveFromList (ut, via, &vi, &vi.firstFragment, va, v, &v->sameNameChain);
575 if (code == -1) return BUDB_DATABASEINCONSISTENT;
576 if (code) return code;
577 if (vi.firstFragment == 0)
578 if (code = DeleteVolInfo (ut, via, &vi)) return code;
579 if (code = FreeStructure (ut, volFragment_BLOCK, va)) return code;
581 /* decrement frag counter */
582 code = set_word_addr (ut, via, &vi, &vi.nFrags, htonl(ntohl(vi.nFrags)-1));
583 if (code) return code;
587 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
588 * The caller will remove it from the hash table if necessary. The caller is
589 * also responsible for writing the tape out if necessary. */
591 static afs_int32 DeleteTape (ut, ta, t)
592 struct ubik_trans *ut;
600 if (da == 0) return BUDB_DATABASEINCONSISTENT;
601 if (dbread (ut, da, &d, sizeof(d))) return BUDB_IO;
602 if (d.firstTape == 0) return BUDB_DATABASEINCONSISTENT;
604 code = RemoveFromList (ut, da, &d, &d.firstTape, ta, t, &t->nextTape);
605 if (code == -1) return BUDB_DATABASEINCONSISTENT;
606 if (code) return code;
608 /* Since the tape should have been truncated there should never be any
609 * volumes in the tape. */
610 if (t->firstVol || t->nVolumes) return BUDB_DATABASEINCONSISTENT;
616 DeleteDump (ut, da, d)
617 struct ubik_trans *ut;
623 code = ht_HashOut (ut, &db.dumpIden, da, d);
624 if (code) ERROR(code);
626 code = ht_HashOut (ut, &db.dumpName, da, d);
627 if (code) ERROR(code);
629 /* Since the tape should have been truncated this should never happen. */
630 if (d->firstTape || d->nVolumes) ERROR(BUDB_DATABASEINCONSISTENT);
632 code = FreeStructure (ut, dump_BLOCK, da);
633 if (code) ERROR(code);
642 * This is called with a volumeEntry and a volInfo structure and compares
643 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
644 * search volInfo structures once it has the head volInfo structure from the
645 * volName hash table.
647 * When called from GetVolInfo the name compare is redundant.
648 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
651 static int VolInfoMatch (vol, vi)
652 struct budb_volumeEntry *vol;
655 return ( (strcmp (vol->name, vi->name) == 0) && /* same volume name */
656 (vol->id == ntohl(vi->id)) && /* same volume id */
657 ((vol->flags & VOLINFOFLAGS) ==
658 (ntohl(vi->flags) & VOLINFOFLAGS)) && /* same flags */
659 (vol->partition == ntohl(vi->partition)) && /* same partition (N/A)*/
660 (strcmp (vol->server, vi->server) == 0) ); /* same server (N/A) */
665 * This routine takes a volumeEntry structure from an RPC interface and
666 * returns the corresponding volInfo structure, creating it if necessary.
668 * The caller must write the entry out.
671 static afs_int32 GetVolInfo (ut, volP, viaP, viP)
672 struct ubik_trans *ut;
673 struct budb_volumeEntry *volP;
679 afs_int32 eval, code = 0;
681 eval = ht_LookupEntry (ut, &db.volName, volP->name, &via, viP);
682 if (eval) ERROR(eval);
686 /* allocate a new volinfo structure */
687 eval = AllocStructure (ut, volInfo_BLOCK, 0, &via, viP);
688 if (eval) ERROR(eval);
690 strcpy (viP->name, volP->name);
691 strcpy (viP->server, volP->server);
692 viP->sameNameHead = 0; /* The head of same name chain */
693 viP->sameNameChain = 0; /* Same name chain is empty */
694 viP->firstFragment = 0;
696 viP->id = htonl(volP->id);
697 viP->partition = htonl(volP->partition);
698 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
700 /* Chain onto volname hash table */
701 eval = ht_HashIn (ut, &db.volName, via, viP);
702 if (eval) ERROR(eval);
704 LogDebug(4, "volume Info for %s placed at %d\n", db.volName, via);
707 else if ( !VolInfoMatch(volP,viP) ) /* Not the head volinfo struct */
709 hvia = via; /* remember the head volinfo struct */
710 memcpy(&hvi, viP, sizeof(hvi));
712 /* Search the same name chain for the correct volinfo structure */
713 for (via=ntohl(viP->sameNameChain); via; via=ntohl(viP->sameNameChain))
715 eval = dbread (ut, via, viP, sizeof(*viP));
716 if (eval) ERROR(eval);
718 if ( VolInfoMatch(volP,viP) ) break; /* found the one */
721 /* if the correct volinfo struct isn't found, create one */
724 eval = AllocStructure (ut, volInfo_BLOCK, 0, &via, viP);
725 if (eval) ERROR(eval);
727 strcpy (viP->name, volP->name);
728 strcpy (viP->server, volP->server);
729 viP->nameHashChain = 0; /* not in hash table */
730 viP->sameNameHead = htonl(hvia); /* chain to head of sameNameChain */
731 viP->sameNameChain = hvi.sameNameChain;
732 viP->firstFragment = 0;
734 viP->id = htonl(volP->id);
735 viP->partition = htonl(volP->partition);
736 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
738 /* write the head entry's sameNameChain link */
739 eval = set_word_addr (ut, hvia, &hvi, &hvi.sameNameChain, htonl(via));
740 if (eval) ERROR(eval);
750 /* deletesomevolumesfromtape
751 * Deletes a specified number of volumes from a tape. The tape
752 * and dump are modified to reflect the smaller number of volumes.
753 * The transaction is not terminated, it is up to the caller to
754 * finish the transaction and start a new one (if desired).
756 * maxvolumestodelete - don't delete more than this many volumes
760 deleteSomeVolumesFromTape(ut, tapeAddr, tapePtr, maxVolumesToDelete)
761 struct ubik_trans *ut;
763 struct tape *tapePtr;
764 int maxVolumesToDelete;
766 dbadr volFragAddr, nextVolFragAddr, dumpAddr;
767 struct volFragment volFrag;
769 int volumesDeleted = 0;
770 afs_int32 eval, code = 0;
772 if (!tapePtr) ERROR(0);
774 for (volFragAddr=ntohl(tapePtr->firstVol); (volFragAddr && (maxVolumesToDelete > 0));
775 volFragAddr=nextVolFragAddr)
777 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
778 if (eval) ERROR(eval);
780 nextVolFragAddr = ntohl(volFrag.sameTapeChain);
782 eval = DeleteVolFragment(ut, volFragAddr, &volFrag);
783 if (eval) ERROR(eval);
785 maxVolumesToDelete--;
789 /* reset the volume fragment pointer in the tape */
790 tapePtr->firstVol = htonl(volFragAddr);
792 /* diminish the tape's volume count */
793 tapePtr->nVolumes = htonl(ntohl(tapePtr->nVolumes) - volumesDeleted);
795 eval = dbwrite(ut, tapeAddr, tapePtr, sizeof(*tapePtr));
796 if (eval) ERROR(eval);
798 /* diminish the dump's volume count */
799 dumpAddr = ntohl(tapePtr->dump);
800 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
801 if (eval) ERROR(eval);
803 dump.nVolumes = htonl(ntohl(dump.nVolumes) - volumesDeleted);
804 eval = dbwrite(ut, dumpAddr, &dump, sizeof(dump));
805 if (eval) ERROR(eval);
812 * deletes a dump in stages, by repeatedly deleting a small number of
813 * volumes from the dump until none are left. The dump is then deleted.
815 * In the case where multiple calls are made to delete the same
816 * dump, the operation will succeed but contention for structures
817 * will result in someone getting back an error.
820 * id - id of dump to delete
824 deleteDump(call, id, dumps)
825 struct rx_call *call;
827 budb_dumpsList *dumps;
829 struct ubik_trans *ut;
830 dbadr dumpAddr, tapeAddr, appendedDump;
835 afs_int32 eval, code = 0;
838 /* iterate until the dump is truly deleted */
846 eval = InitRPC(&ut, LOCKWRITE, 1);
847 if (eval) ERROR(eval); /* can't start transaction */
849 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpid, &dumpAddr, &dump);
850 if (eval) ABORT(eval);
851 if (!dumpAddr) ABORT(BUDB_NOENT); /* can't find dump */
853 if ( (dumpid == id) && (dump.initialDumpID) ) /* can't be an appended dump */
854 ABORT(BUDB_NOTINITIALDUMP);
856 tapeAddr = ntohl(dump.firstTape);
857 if (tapeAddr == 0) break;
859 /* there is a tape to delete */
860 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
861 if (eval) ABORT(eval);
863 if ( ntohl(tape.nVolumes) )
865 /* tape is not empty */
866 eval = deleteSomeVolumesFromTape(ut, tapeAddr, &tape, 10);
867 if (eval) ABORT(eval);
870 if ( ntohl(tape.nVolumes) == 0 )
872 /* tape is now empty, delete it */
873 eval = DeleteTape(ut, tapeAddr, &tape);
874 if (eval) ABORT(eval);
875 eval = ht_HashOut(ut, &db.tapeName, tapeAddr, &tape);
876 if (eval) ABORT(eval);
877 eval = FreeStructure(ut, tape_BLOCK, tapeAddr);
878 if (eval) ABORT(eval);
881 eval = ubik_EndTrans(ut);
882 if (eval) ERROR(eval);
884 } /* next deletion portion */
886 /* Record the dump just deleted */
887 if (dumps && (dumps->budb_dumpsList_len < BUDB_MAX_RETURN_LIST))
889 if (dumps->budb_dumpsList_len == 0)
890 dumps->budb_dumpsList_val = (afs_int32 *) malloc(sizeof(afs_int32));
892 dumps->budb_dumpsList_val =
893 (afs_int32 *) realloc(dumps->budb_dumpsList_val,
894 (dumps->budb_dumpsList_len+1)*sizeof(afs_int32));
896 if ( !dumps->budb_dumpsList_val ) ABORT(BUDB_NOMEM);
898 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = dumpid;
899 dumps->budb_dumpsList_len++;
902 appendedDump = ntohl(dump.appendedDumpChain);
904 /* finally done. No more tapes left in the dump. Delete the dump itself */
905 eval = DeleteDump(ut, dumpAddr, &dump);
906 if (eval) ABORT(eval);
908 /* Now delete the appended dump too */
911 eval = dbread(ut, appendedDump, &dump, sizeof(dump));
912 if (eval) ABORT(eval);
914 dumpid = ntohl(dump.id);
919 eval = ubik_EndTrans(ut);
920 if (eval) ERROR(eval);
922 Log("Delete dump %s (DumpID %u), path %s\n",
923 dump.dumpName, ntohl(dump.id), dump.dumpPath);
927 if (code && partialDel) {
928 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
929 dump.dumpName, ntohl(dump.id), dump.dumpPath, code);
939 * dump selection routines - used by BUDB_GetDumps
943 /* most recent dump selection */
947 struct chosenDump *next;
954 int maxDumps; /* max wanted */
955 int ndumps; /* actual in chain */
956 struct chosenDump *chain;
960 wantDump(dumpAddrParam, dumpParam, dumpListPtrParam)
963 char *dumpListPtrParam;
966 struct dump *dumpPtr;
967 struct wantDumpRock *rockPtr;
969 dumpAddr = (dbadr) dumpAddrParam;
970 dumpPtr = (struct dump *) dumpParam;
971 rockPtr = (struct wantDumpRock *) dumpListPtrParam;
973 /* if we don't have our full complement, just add another */
974 if ( rockPtr->ndumps < rockPtr->maxDumps )
977 /* got the number we need, select based on date */
978 if ( (afs_uint32) ntohl(dumpPtr->created) > rockPtr->chain->date )
984 rememberDump(dumpAddrParam, dumpParam, dumpListPtrParam)
987 char *dumpListPtrParam;
990 struct dump *dumpPtr;
991 struct wantDumpRock *rockPtr;
992 struct chosenDump *ptr, *deletedPtr, **nextPtr;
994 dumpAddr = (dbadr) dumpAddrParam;
995 dumpPtr = (struct dump *) dumpParam;
996 rockPtr = (struct wantDumpRock *) dumpListPtrParam;
998 ptr = (struct chosenDump *) malloc(sizeof(*ptr));
1001 memset(ptr, 0, sizeof(*ptr));
1002 ptr->addr = dumpAddr;
1003 ptr->date = (afs_uint32) ntohl(dumpPtr->created);
1005 /* Don't overflow the max */
1006 while (rockPtr->ndumps >= rockPtr->maxDumps) {
1007 /* have to drop one */
1008 deletedPtr = rockPtr->chain;
1009 rockPtr->chain = deletedPtr->next;
1014 /* now insert in the right place */
1015 for (nextPtr = &rockPtr->chain; *nextPtr; nextPtr = &((*nextPtr)->next)) {
1016 if (ptr->date < (*nextPtr)->date)
1019 ptr->next = *nextPtr;
1027 /* ---------------------------------------------
1028 * general interface routines - alphabetic
1029 * ---------------------------------------------
1032 afs_int32 SBUDB_AddVolume (call, vol)
1033 struct rx_call *call;
1034 struct budb_volumeEntry *vol;
1038 code = AddVolume (call, vol);
1039 osi_auditU (call, BUDB_AddVolEvent, code, AUD_LONG, (vol ? vol->id : 0), AUD_END);
1043 afs_int32 AddVolume (call, vol)
1044 struct rx_call *call;
1045 struct budb_volumeEntry *vol;
1047 struct ubik_trans *ut;
1048 dbadr da, ta, via, va;
1052 struct volFragment v;
1054 afs_int32 eval, code = 0;
1056 if ( !callPermitted(call) )
1057 return BUDB_NOTPERMITTED;
1059 if ( ( strlen(vol->name) >= sizeof(vi.name) ) ||
1060 ( strlen(vol->server) >= sizeof(vi.server) ) ||
1061 ( strlen(vol->tape) >= sizeof(t.name) ) )
1062 return BUDB_BADARGUMENT;
1064 eval = InitRPC (&ut, LOCKWRITE, 1);
1065 if (eval) return eval;
1067 /* Find the dump in dumpid hash table */
1068 eval = ht_LookupEntry (ut, &db.dumpIden, &vol->dump, &da, &d);
1069 if (eval) ABORT(eval);
1070 if (!da) ABORT(BUDB_NODUMPID);
1072 /* search for the right tape in the dump */
1073 for (ta=ntohl(d.firstTape); ta; ta=ntohl(t.nextTape))
1075 /* read the tape entry */
1076 eval = dbread(ut, ta, &t, sizeof(t));
1077 if (eval) ABORT(eval);
1079 /* Check if the right tape name */
1080 if ( strcmp(t.name, vol->tape) == 0 )
1083 if (!ta) ABORT(BUDB_NOTAPENAME);
1085 if ( (t.dump != htonl(da)) || /* tape must belong to dump */
1086 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1087 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0) ) /* dump must be in progress */
1088 ABORT(BUDB_BADPROTOCOL);
1090 /* find or create a volume info structure */
1091 eval = GetVolInfo(ut, vol, &via, &vi);
1092 if (eval) ABORT(eval);
1094 /* Create a volume fragment */
1095 eval = AllocStructure (ut, volFragment_BLOCK, 0, &va, &v);
1096 if (eval) ABORT(eval);
1098 v.vol = htonl(via); /* vol frag points to vol info */
1099 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1100 vi.firstFragment = htonl(va);
1101 vi.nFrags = htonl(ntohl(vi.nFrags)+1);
1103 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1104 if (eval) ABORT(eval);
1106 v.tape = htonl(ta); /* vol frag points to tape */
1107 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1108 t.firstVol = htonl(va);
1109 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1110 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1111 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes/(1024*1024));
1112 t.nBytes = htonl(bytes % (1024*1024));
1114 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1115 if (eval) ABORT(eval);
1117 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1119 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1120 if (eval) ABORT(eval);
1122 v.position = htonl(vol->position); /* vol frag info */
1123 v.clone = htonl(vol->clone);
1124 v.incTime = htonl(vol->incTime);
1125 v.startByte = htonl(vol->startByte);
1126 v.nBytes = htonl(vol->nBytes);
1127 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1128 v.sequence = htons(vol->seq);
1130 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1131 if (eval) ABORT(eval);
1133 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1134 if (eval) ABORT(eval);
1136 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1138 code = ubik_EndTrans(ut);
1142 ubik_AbortTrans(ut);
1147 afs_int32 SBUDB_AddVolumes (call, vols)
1148 struct rx_call *call;
1149 struct budb_volumeList *vols;
1153 code = AddVolumes (call, vols);
1154 osi_auditU (call, BUDB_AddVolEvent, code, AUD_LONG, 0, AUD_END);
1158 afs_int32 AddVolumes (call, vols)
1159 struct rx_call *call;
1160 struct budb_volumeList *vols;
1162 struct budb_volumeEntry *vol, *vol1;
1163 struct ubik_trans *ut;
1164 dbadr da, ta, via, va;
1168 struct volFragment v;
1170 afs_int32 eval, e, code = 0;
1172 if ( !callPermitted(call) )
1173 return BUDB_NOTPERMITTED;
1175 if (!vols || (vols->budb_volumeList_len <= 0) || !vols->budb_volumeList_val)
1176 return BUDB_BADARGUMENT;
1178 /* The first volume in the list of volumes to add */
1179 vol1 = (struct budb_volumeEntry *)vols->budb_volumeList_val;
1181 eval = InitRPC (&ut, LOCKWRITE, 1);
1182 if (eval) return eval;
1184 /* Find the dump in dumpid hash table */
1185 eval = ht_LookupEntry (ut, &db.dumpIden, &vol1->dump, &da, &d);
1186 if (eval) ABORT(eval);
1187 if (!da) ABORT(BUDB_NODUMPID);
1189 /* search for the right tape in the dump */
1190 for (ta=ntohl(d.firstTape); ta; ta=ntohl(t.nextTape)) {
1191 /* read the tape entry */
1192 eval = dbread(ut, ta, &t, sizeof(t));
1193 if (eval) ABORT(eval);
1195 /* Check if the right tape name */
1196 if ( strcmp(t.name, vol1->tape) == 0 )
1199 if (!ta) ABORT(BUDB_NOTAPENAME);
1201 if ( (t.dump != htonl(da)) || /* tape must belong to dump */
1202 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1203 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0) ) /* dump must be in progress */
1204 ABORT(BUDB_BADPROTOCOL);
1206 for (vol=vol1, e=0; e < vols->budb_volumeList_len; vol++, e++) {
1208 if ( ( strlen(vol->name) >= sizeof(vi.name) ) ||
1209 ( strcmp(vol->name, "") == 0 ) || /* no null volnames */
1210 ( strlen(vol->server) >= sizeof(vi.server) ) ||
1211 ( strlen(vol->tape) >= sizeof(t.name) ) ||
1212 ( strcmp(vol->tape, vol1->tape) != 0 ) ) {
1213 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n",
1214 vol->name, vol->id, vol->tape, vol->dump);
1218 /* find or create a volume info structure */
1219 eval = GetVolInfo(ut, vol, &via, &vi);
1220 if (eval) ABORT(eval);
1221 if (*(afs_int32 *)(&vi) == 0) {
1222 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n",
1223 vol->name, vol->tape, vol->dump);
1224 ABORT(BUDB_BADARGUMENT);
1227 /* Create a volume fragment */
1228 eval = AllocStructure (ut, volFragment_BLOCK, 0, &va, &v);
1229 if (eval) ABORT(eval);
1231 v.vol = htonl(via); /* vol frag points to vol info */
1232 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1233 vi.firstFragment = htonl(va);
1234 vi.nFrags = htonl(ntohl(vi.nFrags)+1);
1235 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1236 if (eval) ABORT(eval);
1238 v.tape = htonl(ta); /* vol frag points to tape */
1239 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1240 t.firstVol = htonl(va);
1241 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1242 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1243 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes/(1024*1024));
1244 t.nBytes = htonl(bytes % (1024*1024));
1246 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1248 v.position = htonl(vol->position); /* vol frag info */
1249 v.clone = htonl(vol->clone);
1250 v.incTime = htonl(vol->incTime);
1251 v.startByte = htonl(vol->startByte);
1252 v.nBytes = htonl(vol->nBytes);
1253 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1254 v.sequence = htons(vol->seq);
1256 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1257 if (eval) ABORT(eval);
1259 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1262 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1263 if (eval) ABORT(eval);
1265 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1266 if (eval) ABORT(eval);
1268 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1269 if (eval) ABORT(eval);
1271 code = ubik_EndTrans(ut);
1275 ubik_AbortTrans(ut);
1281 * records the existence of a dump in the database. This creates only
1282 * the dump record, to which one must attach tape and volume records.
1284 * 1) record the volume set
1287 afs_int32 SBUDB_CreateDump(call, dump)
1288 struct rx_call *call;
1289 struct budb_dumpEntry *dump;
1293 code = CreateDump(call, dump);
1294 osi_auditU (call, BUDB_CrDmpEvent, code, AUD_DATE, (dump ? dump->id : 0), AUD_END);
1295 if (dump && !code) {
1296 Log("Create dump %s (DumpID %u), path %s\n",
1297 dump->name, dump->id, dump->dumpPath);
1302 afs_int32 CreateDump(call, dump)
1303 struct rx_call *call;
1304 struct budb_dumpEntry *dump;
1306 struct ubik_trans *ut;
1307 dbadr findDumpAddr, da;
1308 struct dump findDump, d;
1309 afs_int32 eval, code = 0;
1313 Date expiration; /* checked by Security Module */
1314 struct ktc_principal principal;
1316 if ( !callPermitted(call) )
1317 return BUDB_NOTPERMITTED;
1319 if (strlen(dump->name) >= sizeof(d.dumpName))
1320 return BUDB_BADARGUMENT;
1322 eval = InitRPC (&ut, LOCKWRITE, 1);
1323 if (eval) return eval;
1325 eval = rxkad_GetServerInfo( rx_ConnectionOf(call),
1326 &level, &expiration,
1334 if (eval != RXKADNOAUTH) ABORT(eval);
1336 strcpy(principal.name, "");
1337 strcpy(principal.instance, "");
1338 strcpy(principal.cell, "");
1343 /* authenticated. Take user supplied principal information */
1344 if ( strcmp(dump->dumper.name, "") != 0 )
1345 strncpy(principal.name, dump->dumper.name, sizeof(principal.name));
1347 if ( strcmp(dump->dumper.instance, "") != 0 )
1348 strncpy(principal.instance, dump->dumper.instance, sizeof(principal.instance));
1350 if ( strcmp(dump->dumper.cell, "") != 0 )
1351 strncpy(principal.cell, dump->dumper.cell, sizeof(principal.cell));
1354 /* dump id's are time stamps */
1357 while (1) /* allocate a unique dump id */
1361 /* ensure it is unique - seach for dumpid in hash table */
1362 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr, &findDump);
1363 if (eval) ABORT(eval);
1365 if (!findDumpAddr) /* dumpid not in use */
1367 /* update the last dump id allocated */
1368 eval = set_header_word(ut, lastDumpId, htonl(dump->id));
1369 if (eval) ABORT(eval);
1373 /* dump id is in use - wait a while */
1379 /* dump id supplied (e.g. for database restore) */
1380 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr, &findDump);
1381 if (eval) ABORT(eval);
1383 /* Dump id must not already exist */
1384 if (findDumpAddr) ABORT(BUDB_DUMPIDEXISTS);
1387 /* Allocate a dump structure */
1388 memset(&d, 0, sizeof(d));
1389 eval = AllocStructure (ut, dump_BLOCK, 0, &da, &d);
1390 if (eval) ABORT(eval);
1392 strcpy(d.dumpName, dump->name); /* volset.dumpname */
1393 strcpy(d.dumpPath, dump->dumpPath); /* dump node path */
1394 strcpy(d.volumeSet, dump->volumeSetName); /* volume set */
1395 d.id = htonl(dump->id);
1396 d.parent = htonl(dump->parent); /* parent id */
1397 d.level = htonl(dump->level);
1399 LogDebug(4, "dump name %s, parent %d level %d\n", dump->name, dump->parent, dump->level);
1401 /* if creation time specified, use that. Else use the dumpid time */
1402 if (dump->created == 0) dump->created = dump->id;
1403 d.created = htonl(dump->created);
1405 principal_hton(&principal, &d.dumper);
1406 tapeSet_hton(&dump->tapes, &d.tapes);
1408 d.flags = htonl(dump->flags | BUDB_DUMP_INPROGRESS);
1410 eval = ht_HashIn (ut, &db.dumpName, da, &d); /* Into dump name hash table */
1411 if (eval) ABORT(eval);
1413 eval = ht_HashIn (ut, &db.dumpIden, da, &d); /* Into dumpid hash table */
1414 if (eval) ABORT(eval);
1416 eval = dbwrite (ut, da, (char *)&d, sizeof(d)); /* Write the dump structure */
1417 if (eval) ABORT(eval);
1419 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
1420 if (eval) ABORT(eval);
1422 /* If to append this dump, then append it - will write the appended dump */
1423 eval = makeAppended(ut, dump->id, dump->initialDumpID, dump->tapes.b);
1424 if (eval) ABORT(eval);
1426 code = ubik_EndTrans(ut);
1427 LogDebug(5, "made dump %s, path %s\n", d.dumpName, d.dumpPath);
1431 ubik_AbortTrans(ut);
1435 afs_int32 SBUDB_DeleteDump (call, id, fromTime, toTime, dumps)
1436 struct rx_call *call;
1440 budb_dumpsList *dumps;
1444 code = DoDeleteDump (call, id, fromTime, toTime, dumps);
1445 osi_auditU (call, BUDB_DelDmpEvent, code, AUD_DATE, id, AUD_END);
1451 afs_int32 DoDeleteDump (call, id, fromTime, toTime, dumps)
1452 struct rx_call *call;
1456 budb_dumpsList *dumps;
1460 if ( !callPermitted(call) )
1461 return BUDB_NOTPERMITTED;
1463 if (id) code = deleteDump(call, id, dumps);
1467 afs_int32 SBUDB_ListDumps (call, sflags, name, groupid, fromTime, toTime, dumps, flags)
1468 struct rx_call *call;
1469 afs_int32 sflags, groupid;
1471 Date fromTime, toTime;
1472 budb_dumpsList *dumps, *flags;
1476 code = ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags);
1477 osi_auditU (call, BUDB_LstDmpEvent, code, AUD_LONG, flags, AUD_END);
1481 afs_int32 ListDumps (call, sflags, groupid, fromTime, toTime, dumps, flags)
1482 struct rx_call *call;
1483 afs_int32 sflags, groupid;
1484 Date fromTime, toTime;
1485 budb_dumpsList *dumps, *flags;
1487 struct ubik_trans *ut;
1488 struct memoryHashTable *mht;
1489 struct dump diskDump, appDiskDump;
1490 dbadr dbAddr, dbAppAddr;
1492 afs_int32 eval, code = 0;
1493 int old, hash, length, entrySize, j, k, count=0;
1494 afs_uint32 toList, toFlag;
1496 if ( !callPermitted(call) )
1497 return BUDB_NOTPERMITTED;
1499 eval= InitRPC (&ut, LOCKREAD, 1);
1500 if (eval) return(eval);
1502 /* Search the database */
1503 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
1504 if (!mht) return(BUDB_BADARGUMENT);
1506 for (old=0; old<=1; old++) { /*o*/ /* old and new hash tables */
1507 length = (old ? mht->oldLength : mht->length);
1508 if (length == 0) continue;
1510 for (hash=0; hash<length; hash++) { /*h*/ /* for each hash bucket */
1511 for (dbAddr = ht_LookupBucket(ut,mht,hash,old); dbAddr;
1512 dbAddr = ntohl(diskDump.idHashChain)) { /*d*/
1514 /* read the entry */
1515 eval = dbread (ut, dbAddr, &diskDump, sizeof(diskDump));
1516 if (eval) ABORT(eval);
1518 /* Skip appended dumps */
1519 if (ntohl(diskDump.initialDumpID) != 0) {
1523 /* Skip dumps with different goup id */
1524 if ((sflags & BUDB_OP_GROUPID) && (ntohl(diskDump.tapes.id) != groupid)) {
1528 /* Look at this dump to see if it meets the criteria for listing */
1529 if (sflags & BUDB_OP_DATES) {
1530 /* This and each appended dump should be in time */
1531 for (dbAppAddr=dbAddr; dbAppAddr; dbAppAddr=ntohl(appDiskDump.appendedDumpChain)) {
1532 eval = dbread (ut, dbAppAddr, &appDiskDump, sizeof(appDiskDump));
1533 if (eval) ABORT(eval);
1535 if ((ntohl(appDiskDump.id) < fromTime) || (ntohl(appDiskDump.id) > toTime))
1538 if (dbAppAddr) continue; /*nope*/
1541 /* Add it and each of its appended dump to our list to return */
1542 for (dbAppAddr=dbAddr; dbAppAddr; dbAppAddr=ntohl(appDiskDump.appendedDumpChain)) {
1543 eval = dbread (ut, dbAppAddr, &appDiskDump, sizeof(appDiskDump));
1544 if (eval) ABORT(eval);
1546 /* Make sure we have space to list it */
1547 if (dumps->budb_dumpsList_len >= count) {
1550 dumps->budb_dumpsList_val = (afs_int32 *)malloc(count * sizeof(afs_int32));
1551 flags->budb_dumpsList_val = (afs_int32 *)malloc(count * sizeof(afs_int32));
1553 dumps->budb_dumpsList_val =
1554 (afs_int32 *)realloc(dumps->budb_dumpsList_val, count*sizeof(afs_int32));
1555 flags->budb_dumpsList_val =
1556 (afs_int32 *)realloc(flags->budb_dumpsList_val, count*sizeof(afs_int32));
1558 if (!dumps->budb_dumpsList_val || !dumps->budb_dumpsList_val)
1562 /* Add it to our list */
1563 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = ntohl(appDiskDump.id);
1564 flags->budb_dumpsList_val[flags->budb_dumpsList_len] = 0;
1565 if ( ntohl(appDiskDump.initialDumpID) != 0 ) {
1566 flags->budb_dumpsList_val[flags->budb_dumpsList_len] |= BUDB_OP_APPDUMP;
1568 if (strcmp(appDiskDump.dumpName,DUMP_TAPE_NAME) == 0) {
1569 flags->budb_dumpsList_val[flags->budb_dumpsList_len] |= BUDB_OP_DBDUMP;
1571 dumps->budb_dumpsList_len++;
1572 flags->budb_dumpsList_len++;
1578 code = ubik_EndTrans(ut);
1582 ubik_AbortTrans(ut);
1586 afs_int32 SBUDB_DeleteTape (call, tape)
1587 struct rx_call *call;
1588 struct budb_tapeEntry *tape; /* tape info */
1592 code = DoDeleteTape (call, tape);
1593 osi_auditU (call, BUDB_DelTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
1597 afs_int32 DoDeleteTape (call, tape)
1598 struct rx_call *call;
1599 struct budb_tapeEntry *tape; /* tape info */
1601 struct ubik_trans *ut;
1604 afs_int32 eval, code;
1606 if ( !callPermitted(call) )
1607 return BUDB_NOTPERMITTED;
1609 eval = InitRPC (&ut, LOCKWRITE, 1);
1610 if (eval) return eval;
1612 eval = ht_LookupEntry (ut, &db.tapeName, tape->name, &a, &t);
1613 if (eval) ABORT(eval);
1615 eval = DeleteTape (ut, a, &t);
1616 if (eval) ABORT(eval);
1618 eval = FreeStructure (ut, tape_BLOCK, a);
1619 if (eval) ABORT(eval);
1621 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
1622 if (eval) ABORT(eval);
1624 code = ubik_EndTrans(ut);
1628 ubik_AbortTrans(ut);
1633 * Deletes old information from the database for a particular dump path
1634 * and volumset. This supercedes the old policy implemented in
1635 * UseTape, which simply matched on the volumeset.dump. Consequently
1636 * it was unable to handle name re-use.
1638 * dsname - dumpset name, i.e. volumeset.dumpname
1639 * dumpPath - full path of dump node
1640 * curDumpID - current dump in progress - so that is may be excluded
1643 * n - some error. May or may not have deleted information.
1646 afs_int32 SBUDB_DeleteVDP (call, dsname, dumpPath, curDumpId)
1647 struct rx_call *call;
1650 afs_int32 curDumpId;
1654 code = DeleteVDP (call, dsname, dumpPath, curDumpId);
1655 osi_auditU (call, BUDB_DelVDPEvent, code, AUD_STR, dsname, AUD_END);
1659 afs_int32 DeleteVDP (call, dsname, dumpPath, curDumpId)
1660 struct rx_call *call;
1663 afs_int32 curDumpId;
1668 struct ubik_trans *ut;
1669 afs_int32 eval, code = 0;
1671 if ( !callPermitted(call) )
1672 return BUDB_NOTPERMITTED;
1676 eval = InitRPC (&ut, LOCKREAD, 1);
1677 if (eval) return(eval);
1679 eval = ht_LookupEntry(ut, &db.dumpName, dsname, &dumpAddr, &dump);
1680 if (eval) ABORT(eval);
1682 while ( dumpAddr != 0 )
1684 if ( (strcmp(dump.dumpName, dsname) == 0) &&
1685 (strcmp(dump.dumpPath, dumpPath) == 0) &&
1686 (ntohl(dump.id) != curDumpId) )
1688 eval = ubik_EndTrans(ut);
1689 if (eval) return(eval);
1691 eval = deleteDump(call, ntohl(dump.id), 0);
1692 if (eval) return(eval);
1694 /* start the traversal over since the various chains may
1700 dumpAddr = ntohl(dump.nameHashChain);
1703 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
1704 if (eval) ABORT(eval);
1708 /* check if all the dumps have been examined - can terminate */
1711 eval = ubik_EndTrans(ut);
1717 ubik_AbortTrans(ut);
1723 * Given a volume name, and a dumpID, find the volume in that dump and
1724 * return the clone date of the volume (this is the clone date of the
1725 * volume at the time it was dumped).
1727 * Hashes on the volume name and traverses the fragments. Will need to read
1728 * the volumes tape entry to determine if it belongs to the dump. If the
1729 * volume is not found in the dump, then look for it in its parent dump.
1732 afs_int32 SBUDB_FindClone(call, dumpID, volName, clonetime)
1733 struct rx_call *call;
1736 afs_int32 *clonetime;
1740 code = FindClone (call, dumpID, volName, clonetime);
1741 osi_auditU (call, BUDB_FndClnEvent, code, AUD_STR, volName, AUD_END);
1745 afs_int32 FindClone (call, dumpID, volName, clonetime)
1746 struct rx_call *call;
1749 afs_int32 *clonetime;
1751 struct ubik_trans *ut;
1752 dbadr da, ta, hvia, via, vfa;
1755 struct volFragment vf;
1757 int rvi; /* read the volInfo struct */
1758 afs_int32 eval, code = 0;
1760 if ( !callPermitted(call) )
1761 return BUDB_NOTPERMITTED;
1763 eval = InitRPC (&ut, LOCKREAD, 1);
1764 if (eval) return(eval);
1768 /* Search for the volume by name */
1769 eval = ht_LookupEntry (ut, &db.volName, volName, &hvia, &vi);
1770 if (eval) ABORT(eval);
1771 if (!hvia) ABORT(BUDB_NOVOLUMENAME);
1774 /* Follw the dump levels up */
1775 for (; dumpID; dumpID = ntohl(d.parent))
1777 /* Get the dump entry */
1778 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &da, &d);
1779 if (eval) ABORT(eval);
1780 if (!da) ABORT(BUDB_NODUMPID);
1782 /* seach all the volInfo entries on the sameNameChain */
1783 for (via=hvia; via; via=ntohl(vi.sameNameChain))
1785 if (rvi) /* Read the volInfo entry - except first time */
1787 eval = dbread(ut, via, &vi, sizeof(vi));
1788 if (eval) ABORT(eval);
1792 /* search all the volFrag entries on the volFrag */
1793 for (vfa=ntohl(vi.firstFragment); vfa; vfa=ntohl(vf.sameNameChain))
1795 eval = dbread(ut, vfa, &vf, sizeof(vf)); /* Read the volFrag entry */
1796 if (eval) ABORT(eval);
1798 eval = dbread(ut, ntohl(vf.tape), &t, sizeof(t)); /* Read the tape */
1799 if (eval) ABORT(eval);
1801 /* Now check to see if this fragment belongs to the dump we have */
1802 if (ntohl(t.dump) == da)
1804 *clonetime = ntohl(vf.clone); /* return the clone */
1812 code = ubik_EndTrans(ut);
1822 * Searches each tape and each volume in the dump until the volume is found.
1823 * If the volume is not in the dump, then we search it's parent dump.
1825 * Re-write to do lookups by volume name.
1827 afs_int32 FindClone (call, dumpID, volName, clonetime)
1828 struct rx_call *call;
1831 afs_int32 *clonetime;
1833 struct ubik_trans *ut;
1834 dbadr diskAddr, tapeAddr, volFragmentAddr;
1837 struct volFragment volFragment;
1838 struct volInfo volInfo;
1839 afs_int32 eval, code = 0;
1841 if ( !callPermitted(call) )
1842 return BUDB_NOTPERMITTED;
1844 eval = InitRPC (&ut, LOCKREAD, 1);
1845 if (eval) return(eval);
1849 for (; dumpID; dumpID = ntohl(dump.parent))
1851 /* Get the dump entry */
1852 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &diskAddr, &dump);
1853 if (eval) ABORT(eval);
1854 if (!diskAddr) ABORT(BUDB_NODUMPID);
1856 /* just to be sure */
1857 if (ntohl(dump.id) != dumpID)
1859 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID, ntohl(dump.id));
1860 ABORT(BUDB_INTERNALERROR);
1863 /* search all the tapes in this dump */
1864 for (tapeAddr=ntohl(dump.firstTape); tapeAddr; tapeAddr=ntohl(tape.nextTape))
1866 /* Get the tape entry */
1867 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
1868 if (eval) ABORT(eval);
1870 /* search all the volume fragments on this tape */
1871 for (volFragmentAddr=ntohl(tape.firstVol); volFragmentAddr;
1872 volFragmentAddr=ntohl(volFragment.sameTapeChain))
1874 /* Get the volume fragment entry */
1875 eval = dbread(ut, volFragmentAddr, &volFragment, sizeof(volFragment));
1876 if (eval) ABORT(eval);
1878 /* Get the volume info entry */
1879 eval = dbread(ut, ntohl(volFragment.vol), &volInfo, sizeof(volInfo));
1880 if (eval) ABORT(eval);
1882 /* check if this volume is the one we want */
1883 if ( strcmp(volInfo.name,volName) == 0 )
1885 *clonetime = ntohl(volFragment.clone);
1893 code = ubik_EndTrans(ut);
1903 * Find latest volume dump before adate.
1904 * Used by restore code when restoring a user requested volume(s)
1906 * volumeName - name of volume to match on
1907 * beforeDate - look for dumps older than this date
1909 * deptr - descriptor of most recent dump
1912 afs_int32 SBUDB_FindDump (call, volumeName, beforeDate, deptr)
1913 struct rx_call *call;
1915 afs_int32 beforeDate;
1916 struct budb_dumpEntry *deptr;
1920 code = FindDump (call, volumeName, beforeDate, deptr);
1921 osi_auditU (call, BUDB_FndDmpEvent, code, AUD_STR, volumeName, AUD_END);
1925 afs_int32 FindDump (call, volumeName, beforeDate, deptr)
1926 struct rx_call *call;
1928 afs_int32 beforeDate;
1929 struct budb_dumpEntry *deptr;
1931 struct ubik_trans *ut;
1932 dbadr volInfoAddr, volFragmentAddr;
1934 struct volInfo volInfo;
1935 struct volFragment volFragment;
1937 dbadr selectedDumpAddr = 0;
1938 afs_int32 selectedDate = 0;
1939 afs_int32 volCloned;
1941 afs_int32 eval, code = 0;
1943 if ( !callPermitted(call) )
1944 return BUDB_NOTPERMITTED;
1946 eval = InitRPC (&ut, LOCKREAD, 1);
1947 if (eval) return eval;
1949 /* Find volinfo struct for volume name in hash table */
1950 eval = ht_LookupEntry (ut, &db.volName, volumeName, &volInfoAddr, &volInfo);
1951 if (eval) ABORT(eval);
1952 if (!volInfoAddr) ABORT(BUDB_NOVOLUMENAME);
1954 /* Step through all the volinfo structures on the same name chain.
1955 * No need to read the first - we read it above.
1957 for (rvoli=0; volInfoAddr; rvoli=1, volInfoAddr=ntohl(volInfo.sameNameChain))
1959 if (rvoli) /* read the volinfo structure */
1961 eval = dbread(ut, volInfoAddr, &volInfo, sizeof(volInfo));
1962 if (eval) ABORT(eval);
1965 /* step through the volfrag structures */
1966 for (volFragmentAddr=ntohl(volInfo.firstFragment); volFragmentAddr;
1967 volFragmentAddr=ntohl(volFragment.sameNameChain))
1969 /* read the volfrag struct */
1970 eval = dbread(ut, volFragmentAddr, &volFragment, sizeof(volFragment));
1971 if (eval) ABORT(eval);
1973 volCloned = ntohl(volFragment.clone);
1975 /* now we can examine the date for most recent dump */
1976 if ( (volCloned > selectedDate) && (volCloned < beforeDate) )
1978 /* from the volfrag struct, read the tape struct */
1979 eval = dbread(ut, ntohl(volFragment.tape), &tape, sizeof(tape));
1980 if (eval) ABORT(eval);
1982 selectedDate = volCloned;
1983 selectedDumpAddr = ntohl(tape.dump);
1988 if (!selectedDumpAddr) ABORT(BUDB_NOENT);
1990 eval = FillDumpEntry(ut, selectedDumpAddr, deptr);
1991 if (eval) ABORT(eval);
1993 code = ubik_EndTrans(ut);
2001 /* BUDB_FindLatestDump
2002 * Find the latest dump of volumeset vsname with dump name dname.
2004 * vsname - volumeset name
2008 afs_int32 SBUDB_FindLatestDump (call, vsname, dumpPath, dumpentry)
2009 struct rx_call *call;
2010 char *vsname, *dumpPath;
2011 struct budb_dumpEntry *dumpentry;
2015 code = FindLatestDump (call, vsname, dumpPath, dumpentry);
2016 osi_auditU (call, BUDB_FndLaDEvent, code, AUD_STR, vsname, AUD_END);
2020 afs_int32 FindLatestDump (call, vsname, dumpPath, dumpentry)
2021 struct rx_call *call;
2022 char *vsname, *dumpPath;
2023 struct budb_dumpEntry *dumpentry;
2025 struct ubik_trans *ut;
2026 dbadr curdbaddr, retdbaddr, firstdbaddr;
2029 char dumpName[BU_MAXNAMELEN+2];
2030 afs_int32 eval, code = 0;
2032 if ( !callPermitted(call) )
2033 return BUDB_NOTPERMITTED;
2035 eval = InitRPC(&ut, LOCKREAD, 1);
2036 if (eval) return(eval);
2038 if ( (strcmp(vsname,"") == 0) && (strcmp(dumpPath,"") == 0) )
2040 /* Construct a database dump name */
2041 strcpy(dumpName, DUMP_TAPE_NAME);
2043 else if (strchr(dumpPath,'/') == 0) {
2044 int level, old, length, hash;
2045 struct dump hostDump, diskDump;
2046 struct memoryHashTable *mht;
2049 afs_uint32 bestDumpId=0;
2051 level = atoi(dumpPath);
2053 ABORT(BUDB_BADARGUMENT);
2056 /* Brute force search of all the dumps in the database - yuck! */
2059 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
2060 if (!mht) ABORT(BUDB_BADARGUMENT);
2062 for (old=0; old <= 1; old++) { /*fo*/
2063 length = (old ? mht->oldLength : mht->length);
2064 if (!length) continue;
2066 for (hash=0; hash<length; hash++) {
2068 for (dbAddr = ht_LookupBucket(ut,mht,hash,old); dbAddr;
2069 dbAddr = hostDump.idHashChain) {
2071 eval = dbread (ut, dbAddr, &diskDump, sizeof(diskDump));
2072 if (eval) ABORT(eval);
2073 dump_ntoh(&diskDump, &hostDump);
2075 if ( (strcmp(hostDump.volumeSet,vsname) == 0) && /* the volumeset */
2076 (hostDump.level == level) && /* same level */
2077 (hostDump.id > bestDumpId) ) { /* more recent */
2078 bestDumpId = hostDump.id;
2085 ABORT(BUDB_NODUMPNAME);
2091 /* construct the name of the dump */
2092 if ( (strlen(vsname) + strlen(tailCompPtr(dumpPath))) > BU_MAXNAMELEN )
2093 ABORT(BUDB_NODUMPNAME);
2095 strcpy(dumpName, vsname);
2096 strcat(dumpName, ".");
2097 strcat(dumpName, tailCompPtr(dumpPath));
2100 LogDebug(5, "lookup on :%s:\n", dumpName);
2102 /* Lookup on dumpname in hash table */
2103 eval = ht_LookupEntry(ut, &db.dumpName, dumpName, &firstdbaddr, &d);
2104 if (eval) ABORT(eval);
2109 /* folow remaining dumps in hash chain, looking for most latest dump */
2110 for (curdbaddr=firstdbaddr; curdbaddr; curdbaddr=ntohl(d.nameHashChain))
2112 if (curdbaddr != firstdbaddr) {
2113 eval = dbread(ut, curdbaddr, &d, sizeof(d));
2114 if (eval) ABORT(eval);
2117 if ( (strcmp(d.dumpPath, dumpPath) == 0) && /* Same dumppath */
2118 (strcmp(d.dumpName, dumpName) == 0) && /* Same dumpname */
2119 (ntohl(d.created) > latest) ) /* most recent */
2121 latest = ntohl(d.created);
2122 retdbaddr = curdbaddr;
2125 if (!retdbaddr) ABORT(BUDB_NODUMPNAME);
2128 /* return the dump found */
2129 FillDumpEntry(ut, retdbaddr, dumpentry);
2131 code = ubik_EndTrans(ut);
2135 ubik_AbortTrans(ut);
2140 afs_int32 SBUDB_FinishDump (call, dump)
2141 struct rx_call *call;
2142 struct budb_dumpEntry *dump;
2146 code = FinishDump (call, dump);
2147 osi_auditU (call, BUDB_FinDmpEvent, code, AUD_DATE, (dump ? dump->id : 0), AUD_END);
2151 afs_int32 FinishDump (call, dump)
2152 struct rx_call *call;
2153 struct budb_dumpEntry *dump;
2155 struct ubik_trans *ut;
2158 afs_int32 eval, code = 0;
2160 if ( !callPermitted(call) )
2161 return BUDB_NOTPERMITTED;
2163 eval = InitRPC(&ut, LOCKWRITE, 1);
2164 if (eval) return eval;
2166 eval = ht_LookupEntry (ut, &db.dumpIden, &dump->id, &a, &d);
2167 if (eval) ABORT(eval);
2168 if (!a) ABORT(BUDB_NODUMPID);
2170 if ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)
2171 ABORT(BUDB_DUMPNOTINUSE);
2173 d.flags = htonl(dump->flags & ~BUDB_DUMP_INPROGRESS);
2175 /* if creation time specified set it */
2176 if (dump->created) d.created = htonl(dump->created);
2177 dump->created = ntohl(d.created);
2179 /* Write the dump entry out */
2180 eval = dbwrite(ut, a, &d, sizeof(d));
2181 if (eval) ABORT(eval);
2183 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2184 if (eval) ABORT(eval);
2186 code = ubik_EndTrans(ut);
2190 ubik_AbortTrans(ut);
2194 afs_int32 SBUDB_FinishTape (call, tape)
2195 struct rx_call *call;
2196 struct budb_tapeEntry *tape;
2200 code = FinishTape (call, tape);
2201 osi_auditU (call, BUDB_FinTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
2205 afs_int32 FinishTape (call, tape)
2206 struct rx_call *call;
2207 struct budb_tapeEntry *tape;
2209 struct ubik_trans *ut;
2213 afs_int32 eval, code = 0;
2215 if ( !callPermitted(call) )
2216 return BUDB_NOTPERMITTED;
2218 eval = InitRPC (&ut, LOCKWRITE, 1);
2219 if (eval) return eval;
2221 /* find the tape struct in the tapename hash chain */
2222 eval = ht_LookupEntry (ut, &db.tapeName, tape->name, &a, &t);
2223 if (eval) ABORT(eval);
2224 if (!a) ABORT(BUDB_NOTAPENAME);
2226 /* Read the dump structure */
2227 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2228 if (eval) ABORT(eval);
2230 /* search for the right tape on the rest of the chain */
2231 while (ntohl(d.id) != tape->dump)
2233 a = ntohl(t.nameHashChain);
2234 if (!a) ABORT(BUDB_NOTAPENAME);
2236 eval = dbread(ut, a, &t, sizeof(t));
2237 if (eval) ABORT(eval);
2239 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2240 if (eval) ABORT(eval);
2243 if ( (ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0 )
2244 ABORT(BUDB_TAPENOTINUSE);
2246 /* t.nBytes = htonl(tape->nBytes); */
2247 t.nFiles = htonl(tape->nFiles);
2248 t.useKBytes = htonl(tape->useKBytes);
2249 t.flags = htonl(tape->flags & ~BUDB_TAPE_BEINGWRITTEN);
2251 eval = dbwrite(ut, a, &t, sizeof(t));
2252 if (eval) ABORT(BUDB_IO);
2254 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
2255 if (eval) ABORT(eval);
2257 code = ubik_EndTrans(ut);
2261 ubik_AbortTrans(ut);
2266 * return a set of dumps that match the specified criteria
2269 * majorVersion - version of interface structures. Permits compatibility
2271 * flags - for search and select operations. Broken down into flags
2272 * for name, start point, end point and time.
2273 * name - name to search for. Interpretation based on flags
2280 * dbTimeP - time at which the database was last modified. Up to
2281 * caller (client) to take appropriate action if database
2282 * modified between successive calls
2283 * dumps - list of matching dumps
2285 * currently supported are:
2290 afs_int32 SBUDB_GetDumps (call, majorVersion, flags, name, start, end,
2291 index, nextIndexP, dbTimeP, dumps)
2292 struct rx_call *call;
2293 afs_int32 majorVersion; /* version of interface structures */
2294 afs_int32 flags; /* search & select controls */
2295 char *name; /* s&s parameters */
2298 afs_int32 index; /* start index of returned entries */
2299 afs_int32 *nextIndexP; /* output index for next call */
2301 budb_dumpList *dumps; /* pointer to buffer */
2305 code = GetDumps (call, majorVersion, flags, name, start, end,
2306 index, nextIndexP, dbTimeP, dumps);
2307 osi_auditU (call, BUDB_GetDmpEvent, code, AUD_END);
2311 afs_int32 GetDumps (call, majorVersion, flags, name, start, end,
2312 index, nextIndexP, dbTimeP, dumps)
2313 struct rx_call *call;
2314 afs_int32 majorVersion; /* version of interface structures */
2315 afs_int32 flags; /* search & select controls */
2316 char *name; /* s&s parameters */
2319 afs_int32 index; /* start index of returned entries */
2320 afs_int32 *nextIndexP; /* output index for next call */
2322 budb_dumpList *dumps; /* pointer to buffer */
2324 struct ubik_trans *ut;
2327 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2328 afs_int32 eval, code = 0;
2330 struct returnList list;
2332 /* Don't check permissions when we look up a specific dump id */
2333 if ( ((flags & BUDB_OP_STARTS) != BUDB_OP_DUMPID) && !callPermitted(call) )
2334 return BUDB_NOTPERMITTED;
2336 if (majorVersion != BUDB_MAJORVERSION) return BUDB_OLDINTERFACE;
2337 if (index < 0) return BUDB_ENDOFLIST;
2339 eval = InitRPC (&ut, LOCKREAD, 1);
2340 if (eval) return eval;
2342 nameFlags = flags & BUDB_OP_NAMES;
2343 startFlags = flags & BUDB_OP_STARTS;
2344 endFlags = flags & BUDB_OP_ENDS;
2345 timeFlags = flags & BUDB_OP_TIMES;
2347 InitReturnList (&list);
2350 if (nameFlags == BUDB_OP_DUMPNAME)
2352 /* not yet implemented */
2353 if (startFlags || endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
2355 eval = ht_LookupEntry (ut, &db.dumpName, name, &da, &d);
2356 if (eval) ABORT(eval);
2357 if (!da) ABORT(BUDB_NODUMPNAME);
2361 if (strcmp (d.dumpName, name) == 0)
2363 eval = AddToReturnList (&list, da, &toskip);
2364 if (eval == BUDB_LIST2BIG) break;
2365 if (eval) ABORT(eval);
2368 da = ntohl(d.nameHashChain); /* get next dump w/ name */
2371 eval = dbread (ut, da, &d, sizeof(d));
2372 if (eval) ABORT(eval);
2376 if ( nameFlags == BUDB_OP_VOLUMENAME )
2381 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2382 ABORT(BUDB_BADFLAGS);
2385 if (startFlags != BUDB_OP_STARTTIME) ABORT(BUDB_BADFLAGS);
2387 /* lookup a dump by volumename and time stamp. Find the most recent
2388 * dump of the specified volumename, that occured before the supplied
2392 /* get us a volInfo for name */
2393 eval = ht_LookupEntry(ut, &db.volName, name, &da, &vi);
2394 if (eval) ABORT(eval);
2398 /* now iterate over all the entries of this name */
2399 for ( va = vi.firstFragment; va != 0; va = v.sameNameChain )
2402 eval = dbread(ut, va, &v, sizeof(v));
2403 if (eval) ABORT(eval);
2405 if date on fragment > date
2406 ignore it - too recent;
2408 if ( date on fragment < date && date on fragment > bestfound )
2409 bestfound = date on fragment;
2413 da = vi.sameNameChain;
2417 eval = dbread(ut, da, &vi, sizeof(vi));
2418 if (eval) ABORT(eval);
2424 from saved volfragment address, compute dump.
2425 otherwise, return dump found
2429 else if (startFlags == BUDB_OP_DUMPID)
2431 if (endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
2432 if (nameFlags) ABORT(BUDB_BADFLAGS); /* NYI */
2434 eval = ht_LookupEntry (ut, &db.dumpIden, &start, &da, &d);
2435 if (eval) ABORT(eval);
2436 if (!da) ABORT(BUDB_NODUMPID);
2438 eval = AddToReturnList (&list, da, &toskip);
2439 if (eval) ABORT(eval);
2441 else if (endFlags == BUDB_OP_NPREVIOUS)
2443 struct wantDumpRock rock;
2444 struct chosenDump *ptr, *nextPtr;
2446 extern wantDump(), rememberDump();
2448 /* no other flags should be set */
2450 /* end specifies how many dumps */
2451 if (!end) ABORT(BUDB_BADFLAGS);
2453 memset(&rock, 0, sizeof(rock));
2454 rock.maxDumps = end;
2456 scanHashTable(ut, &db.dumpName, wantDump, rememberDump, (char *) &rock);
2458 for (ptr=rock.chain; ptr; ptr=nextPtr)
2460 nextPtr = ptr->next;
2461 AddToReturnList (&list, ptr->addr, &toskip); /* ignore error for free */
2467 ABORT(BUDB_BADFLAGS);
2470 eval = SendReturnList (ut, &list, FillDumpEntry, sizeof(struct budb_dumpEntry),
2471 index, nextIndexP, dbTimeP, (returnList_t)dumps);
2472 if (eval) ABORT(eval);
2475 FreeReturnList(&list);
2476 code = ubik_EndTrans(ut);
2480 FreeReturnList(&list);
2481 ubik_AbortTrans(ut);
2486 * Get the expiration of a tape. Since the dump could have appended dumps,
2487 * we should use the most recent expiration date. Put the most recent
2488 * expiration tape into the given tape structure.
2490 afs_int32 getExpiration (ut, tapePtr)
2491 struct ubik_trans *ut;
2492 struct tape *tapePtr;
2498 afs_int32 eval, code = 0;
2500 if (!tapePtr) ERROR(0);
2502 /* Get the dump for this tape */
2503 ad = ntohl(tapePtr->dump);
2504 eval = dbread(ut,ad,&d,sizeof(d));
2505 if (eval) ERROR(eval);
2507 /* If not an initial dump, get the initial dump */
2508 if (d.initialDumpID)
2510 initDump = ntohl(d.initialDumpID);
2511 eval = ht_LookupEntry (ut, &db.dumpIden, &initDump, &ad, &d);
2512 if (eval) ERROR(eval);
2515 /* Cycle through the dumps and appended dumps */
2518 /* Get the first tape in this dump. No need to check the rest of the tapes */
2519 /* for this dump since they will all have the same expiration date */
2520 eval = dbread (ut, ntohl(d.firstTape), &t, sizeof(t));
2521 if (eval) ERROR(eval);
2523 /* Take the greater of the expiration dates */
2524 if ( ntohl(tapePtr->expires) < ntohl(t.expires) )
2525 tapePtr->expires = t.expires;
2527 /* Step to and read the next appended dump */
2528 if ( ad = ntohl(d.appendedDumpChain) )
2530 eval = dbread(ut,ad,&d,sizeof(d));
2531 if (eval) ERROR(eval);
2539 /* Mark the following dump as appended to another, intial dump */
2540 afs_int32 makeAppended (ut, appendedDumpID, initialDumpID, startTapeSeq)
2541 struct ubik_trans *ut;
2542 afs_int32 appendedDumpID;
2543 afs_int32 initialDumpID;
2544 afs_int32 startTapeSeq;
2546 dbadr ada, da, lastDumpAddr;
2548 afs_int32 eval, code = 0;
2552 if (appendedDumpID == initialDumpID)
2553 ERROR(BUDB_INTERNALERROR);
2555 /* If there is an initial dump, append this dump to it */
2556 /* Find the appended dump via its id */
2557 eval = ht_LookupEntry(ut,&db.dumpIden,&appendedDumpID,&ada,&ad);
2558 if (eval) ERROR(eval);
2560 /* If the dump is already marked as appended,
2561 * then we have an internal error.
2563 if (ad.initialDumpID) {
2564 if (ntohl(ad.initialDumpID) != initialDumpID)
2565 ERROR(BUDB_INTERNALERROR);
2568 /* Update the appended dump to point to the initial dump */
2569 ad.initialDumpID = htonl(initialDumpID);
2570 ad.tapes.b = htonl(startTapeSeq);
2572 /* find the initial dump via its id */
2573 eval = ht_LookupEntry(ut,&db.dumpIden,&initialDumpID,&da,&d);
2574 if (eval) ERROR(eval);
2576 /* Update the appended dump's tape format with that of the initial */
2577 strcpy(ad.tapes.format, d.tapes.format);
2579 /* starting with the initial dump step through its appended dumps till
2580 * we reach the last appended dump.
2583 while (d.appendedDumpChain) {
2584 lastDumpAddr = ntohl(d.appendedDumpChain);
2585 if (lastDumpAddr == ada) ERROR(0); /* Already appended */
2586 eval = dbread(ut, lastDumpAddr, &d, sizeof(d));
2587 if (eval) ERROR(eval);
2590 /* Update the last dump to point to our new appended dump.
2591 * The appended dump is the last one in the dump chain.
2593 d.appendedDumpChain = htonl(ada);
2594 ad.appendedDumpChain = 0;
2596 /* Write the appended dump and the initial dump */
2597 eval = dbwrite(ut,ada,(char *)&ad,sizeof(ad));
2598 if (eval) ERROR(eval);
2600 eval = dbwrite (ut, lastDumpAddr, (char *)&d, sizeof(d));
2601 if (eval) ERROR(eval);
2603 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
2604 if (eval) ERROR(eval);
2610 afs_int32 SBUDB_MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq)
2611 struct rx_call *call;
2612 afs_int32 appendedDumpID;
2613 afs_int32 initialDumpID;
2614 afs_int32 startTapeSeq;
2618 code = MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq);
2619 osi_auditU (call, BUDB_AppDmpEvent, code, AUD_LONG, appendedDumpID, AUD_END);
2623 afs_int32 MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq)
2624 struct rx_call *call;
2625 afs_int32 appendedDumpID;
2626 afs_int32 initialDumpID;
2627 afs_int32 startTapeSeq;
2629 struct ubik_trans *ut;
2630 afs_int32 eval, code = 0;
2632 if ( !callPermitted(call) )
2633 return BUDB_NOTPERMITTED;
2635 eval = InitRPC (&ut, LOCKWRITE, 1);
2636 if (eval) return(eval);
2638 eval = makeAppended(ut,appendedDumpID,initialDumpID,startTapeSeq);
2639 if (eval) ABORT(eval);
2641 code = ubik_EndTrans(ut);
2645 ubik_AbortTrans(ut);
2649 /* Find the last tape of a dump-set. This includes any appended dumps */
2650 afs_int32 SBUDB_FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry)
2651 struct rx_call *call;
2653 struct budb_dumpEntry *dumpEntry;
2654 struct budb_tapeEntry *tapeEntry;
2655 struct budb_volumeEntry *volEntry;
2659 code = FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry);
2660 osi_auditU (call, BUDB_FndLTpeEvent, code, AUD_LONG, dumpID, AUD_END);
2664 afs_int32 FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry)
2665 struct rx_call *call;
2667 struct budb_dumpEntry *dumpEntry;
2668 struct budb_tapeEntry *tapeEntry;
2669 struct budb_volumeEntry *volEntry;
2671 struct ubik_trans *ut;
2675 dbadr lastTape, thisTape;
2676 afs_int32 lastTapeSeq;
2677 struct volFragment vf;
2678 dbadr lastVol, thisVol;
2679 afs_int32 lastVolPos;
2680 afs_int32 eval, code = 0;
2682 if ( !callPermitted(call) )
2683 return BUDB_NOTPERMITTED;
2685 if (!dumpID) return(BUDB_BADARGUMENT);
2687 eval = InitRPC (&ut, LOCKREAD, 1);
2688 if (eval) return(eval);
2690 /* find and read its initial dump via its id */
2691 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &lastDump, &d);
2692 if (eval) ABORT(eval);
2693 if (!lastDump) ABORT(BUDB_NODUMPID);
2695 /* Follow the append dumps link chain until we reach the last dump */
2696 while (d.appendedDumpChain)
2698 lastDump = ntohl(d.appendedDumpChain);
2699 eval = dbread(ut,lastDump,&d,sizeof(d));
2700 if (eval) ABORT(eval);
2703 /* We now have the last dump of the last appended dump */
2704 /* Copy this into our return structure */
2705 eval = FillDumpEntry(ut,lastDump,dumpEntry);
2706 if (eval) ABORT(eval);
2708 /* Fail if the last dump has no tapes */
2709 if (!d.firstTape) ABORT(BUDB_NOTAPENAME);
2711 /* Follow the tapes in this dump until we reach the last tape */
2712 eval = dbread (ut, ntohl(d.firstTape), &t, sizeof(t));
2713 if (eval) ABORT(eval);
2715 lastTape = ntohl(d.firstTape);
2716 lastTapeSeq = ntohl(t.seq);
2717 lastVol = ntohl(t.firstVol);
2721 thisTape = ntohl(t.nextTape);
2722 eval = dbread(ut,thisTape,&t,sizeof(t));
2723 if (eval) ABORT(eval);
2725 if (ntohl(t.seq) > lastTapeSeq)
2727 lastTape = thisTape;
2728 lastTapeSeq = ntohl(t.seq);
2729 lastVol = ntohl(t.firstVol);
2733 /* We now have the last tape of the last appended dump */
2734 /* Copy this into our return structure */
2735 eval = FillTapeEntry(ut,lastTape,tapeEntry);
2736 if (eval) ABORT(eval);
2738 /* Zero volume entry if the last tape has no volumes */
2740 memset(volEntry, 0, sizeof(*volEntry));
2742 /* Follow the volumes until we reach the last volume */
2743 eval = dbread (ut,lastVol,&vf,sizeof(vf));
2744 if (eval) ABORT(eval);
2746 lastVolPos = vf.position;
2748 while (vf.sameTapeChain) {
2749 thisVol = ntohl(vf.sameTapeChain);
2750 eval = dbread(ut,thisVol,&vf,sizeof(vf));
2751 if (eval) ABORT(eval);
2753 if (vf.position > lastVolPos) {
2755 lastVolPos = vf.position;
2759 /* We now have the last volume of this tape */
2760 /* Copy this into our return structure */
2761 eval = FillVolEntry(ut,lastVol,volEntry);
2762 if (eval) ABORT(eval);
2765 eval = ubik_EndTrans(ut);
2766 if (!code) code = eval;
2770 ubik_AbortTrans(ut);
2775 afs_int32 SBUDB_GetTapes (call, majorVersion, flags, name, start, end, index, nextIndexP,
2777 struct rx_call *call;
2778 afs_int32 majorVersion; /* version of interface structures */
2779 afs_int32 flags; /* search & select controls */
2780 char *name; /* s&s parameters */
2782 afs_int32 end; /* reserved: MBZ */
2783 afs_int32 index; /* start index of returned entries */
2784 afs_int32 *nextIndexP; /* output index for next call */
2786 budb_tapeList *tapes; /* pointer to buffer */
2790 code = GetTapes (call, majorVersion, flags, name, start, end,
2791 index, nextIndexP, dbTimeP, tapes);
2792 osi_auditU (call, BUDB_GetTpeEvent, code, AUD_END);
2796 afs_int32 GetTapes (call, majorVersion, flags, name, start, end,
2797 index, nextIndexP, dbTimeP, tapes)
2798 struct rx_call *call;
2799 afs_int32 majorVersion; /* version of interface structures */
2800 afs_int32 flags; /* search & select controls */
2801 char *name; /* s&s parameters */
2803 afs_int32 end; /* reserved: MBZ */
2804 afs_int32 index; /* start index of returned entries */
2805 afs_int32 *nextIndexP; /* output index for next call */
2807 budb_tapeList *tapes; /* pointer to buffer */
2809 struct ubik_trans *ut;
2813 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2814 struct returnList list;
2815 afs_int32 eval, code = 0;
2818 if ( !callPermitted(call) )
2819 return BUDB_NOTPERMITTED;
2821 if (majorVersion != BUDB_MAJORVERSION)
2822 return BUDB_OLDINTERFACE;
2824 if (index < 0) return BUDB_ENDOFLIST;
2826 eval = InitRPC (&ut, LOCKREAD, 1);
2827 if (eval) return eval;
2829 nameFlags = flags & BUDB_OP_NAMES;
2830 startFlags = flags & BUDB_OP_STARTS;
2831 endFlags = flags & BUDB_OP_ENDS;
2832 timeFlags = flags & BUDB_OP_TIMES;
2834 InitReturnList (&list);
2837 if (nameFlags == BUDB_OP_TAPENAME)
2839 eval = ht_LookupEntry (ut, &db.tapeName, name, &ta, &t);
2840 if (eval) ABORT(eval);
2841 if (!ta) ABORT(BUDB_NOTAPENAME);
2844 if ( (startFlags & ~BUDB_OP_DUMPID) || endFlags || timeFlags ) ABORT(BUDB_BADFLAGS);
2846 /* follow the hash chain to the end */
2849 if (startFlags & BUDB_OP_DUMPID)
2851 /* read in the dump */
2852 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2853 if (eval) ABORT(eval);
2855 /* check if both name and dump id match */
2856 if ( (strcmp(name, t.name) == 0) && (ntohl(d.id) == start) )
2858 eval = AddToReturnList (&list, ta, &toskip);
2859 if (eval && (eval != BUDB_LIST2BIG)) ABORT(eval);
2865 /* Add to return list and continue search */
2866 if ( strcmp(name, t.name) == 0 )
2868 eval = AddToReturnList (&list, ta, &toskip);
2869 if (eval == BUDB_LIST2BIG) break;
2870 if (eval) ABORT(eval);
2874 ta = ntohl(t.nameHashChain);
2875 if (ta) dbread(ut, ta, &t, sizeof(t));
2878 else if (nameFlags == BUDB_OP_TAPESEQ)
2880 eval = ht_LookupEntry(ut,&db.dumpIden, &start, &da, &d);
2881 if (eval) ABORT(eval);
2882 if (!da) ABORT(BUDB_NODUMPNAME);
2884 /* search for the right tape */
2885 ta = ntohl(d.firstTape);
2886 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape))
2888 eval = dbread(ut, ta, &t, sizeof(t));
2889 if (eval) ABORT(eval);
2891 if (ntohl(t.seq) == end)
2893 eval = AddToReturnList (&list, ta, &toskip);
2894 if (eval && (eval != BUDB_LIST2BIG)) ABORT(eval);
2901 ABORT (BUDB_BADFLAGS);
2904 eval = SendReturnList (ut, &list, FillTapeEntry,
2905 sizeof(struct budb_tapeEntry),
2906 index, nextIndexP, dbTimeP, (returnList_t)tapes);
2907 if (eval) ABORT(eval);
2909 FreeReturnList(&list);
2910 code = ubik_EndTrans(ut);
2914 FreeReturnList(&list);
2915 ubik_AbortTrans(ut);
2920 * get a set of volumes according to the specified criteria.
2921 * See BUDB_GetDumps for general information on parameters
2922 * Currently supports:
2923 * 1) volume match - returns volumes based on volume name only.
2924 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
2925 * and start is a dumpid. Returns all volumes of the specified
2926 * name on the selected dumpid.
2929 afs_int32 SBUDB_GetVolumes (call, majorVersion, flags, name, start, end,
2930 index, nextIndexP, dbTimeP, volumes)
2931 struct rx_call *call;
2932 afs_int32 majorVersion; /* version of interface structures */
2933 afs_int32 flags; /* search & select controls */
2934 char *name; /* - parameters for search */
2935 afs_int32 start; /* - usage depends which BUDP_OP_* */
2936 afs_int32 end; /* - bits are set */
2937 afs_int32 index; /* start index of returned entries */
2938 afs_int32 *nextIndexP; /* output index for next call */
2940 budb_volumeList *volumes; /* pointer to buffer */
2944 code = GetVolumes (call, majorVersion, flags, name, start, end,
2945 index, nextIndexP, dbTimeP, volumes);
2946 osi_auditU (call, BUDB_GetVolEvent, code, AUD_END);
2950 afs_int32 GetVolumes (call, majorVersion, flags, name, start, end,
2951 index, nextIndexP, dbTimeP, volumes)
2952 struct rx_call *call;
2953 afs_int32 majorVersion; /* version of interface structures */
2954 afs_int32 flags; /* search & select controls */
2955 char *name; /* - parameters for search */
2956 afs_int32 start; /* - usage depends which BUDP_OP_* */
2957 afs_int32 end; /* - bits are set */
2958 afs_int32 index; /* start index of returned entries */
2959 afs_int32 *nextIndexP; /* output index for next call */
2961 budb_volumeList *volumes; /* pointer to buffer */
2963 struct ubik_trans *ut;
2966 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2967 afs_int32 eval, code = 0;
2968 struct returnList vollist;
2971 /* Don't check permissions when we look up a specific volume name */
2972 if ( ((flags & BUDB_OP_NAMES) != BUDB_OP_VOLUMENAME) && !callPermitted(call) )
2973 return BUDB_NOTPERMITTED;
2975 if (majorVersion != BUDB_MAJORVERSION) return BUDB_OLDINTERFACE;
2976 if (index < 0) return BUDB_ENDOFLIST;
2978 eval = InitRPC (&ut, LOCKREAD, 1);
2979 if (eval) return eval;
2981 nameFlags = flags & BUDB_OP_NAMES;
2982 startFlags = flags & BUDB_OP_STARTS;
2983 endFlags = flags & BUDB_OP_ENDS;
2984 timeFlags = flags & BUDB_OP_TIMES;
2986 InitReturnList (&vollist);
2989 /* lookup a the volume (specified by name) in the dump (specified by id) */
2990 if (nameFlags == BUDB_OP_VOLUMENAME)
2992 /* dumpid permissible, all others off */
2993 if ( ((startFlags & ~BUDB_OP_DUMPID) != 0) || endFlags || timeFlags )
2994 ABORT(BUDB_BADFLAGS);
2996 /* returns ptr to volinfo of requested name */
2997 eval = ht_LookupEntry (ut, &db.volName, name, &via, &vi);
2998 if (eval) ABORT(eval);
2999 if (!via) ABORT(BUDB_NOVOLUMENAME);
3001 /* Iterate over all volume fragments with this name */
3004 struct volFragment v;
3007 /* traverse all the volume fragments for this volume info structure */
3008 for (va=vi.firstFragment; va; va=v.sameNameChain)
3011 eval = dbread (ut, va, &v, sizeof(v));
3012 if (eval) ABORT(eval);
3014 if ( startFlags & BUDB_OP_DUMPID )
3019 /* get the dump id for this fragment */
3020 eval = dbread(ut, ntohl(v.tape), &atape, sizeof(atape));
3021 if (eval) ABORT(eval);
3023 eval = dbread(ut, ntohl(atape.dump), &adump, sizeof(adump));
3024 if (eval) ABORT(BUDB_IO);
3026 /* dump id does not match */
3027 if ( ntohl(adump.id) != start )
3031 eval = AddToReturnList (&vollist, va, &toskip);
3032 if (eval == BUDB_LIST2BIG) break;
3033 if (eval) ABORT(eval);
3035 if (eval == BUDB_LIST2BIG) break;
3037 via = vi.sameNameChain;
3038 if (via == 0) break;
3041 eval = dbread (ut, via, &vi, sizeof(vi));
3042 if (eval) ABORT(eval);
3045 else if ( ((nameFlags == 0) || (nameFlags == BUDB_OP_TAPENAME)) &&
3046 (startFlags == BUDB_OP_DUMPID) )
3052 struct volFragment volFrag;
3055 /* lookup all volumes for a specified dump id */
3057 /* no other flags should be set */
3058 if (endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
3061 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &dumpAddr, &dump);
3062 if (eval) ABORT(eval);
3064 /* traverse all the tapes */
3065 for (tapeAddr=ntohl(dump.firstTape); tapeAddr; tapeAddr=ntohl(tape.nextTape))
3067 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
3068 if (eval) ABORT(eval);
3070 if ( ( nameFlags != BUDB_OP_TAPENAME ) ||
3071 ((nameFlags == BUDB_OP_TAPENAME) && (strcmp(tape.name,name) == 0)) )
3073 /* now return all the volumes */
3074 for (volFragAddr=ntohl(tape.firstVol); volFragAddr;
3075 volFragAddr=ntohl(volFrag.sameTapeChain))
3077 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
3078 if (eval) ABORT(eval);
3080 eval = AddToReturnList(&vollist, volFragAddr, &toskip);
3081 if (eval == BUDB_LIST2BIG) break;
3082 if (eval) ABORT(eval);
3085 if (eval == BUDB_LIST2BIG) break;
3090 ABORT(BUDB_BADFLAGS);
3093 eval = SendReturnList(ut, &vollist, FillVolEntry, sizeof(struct budb_volumeEntry),
3094 index, nextIndexP, dbTimeP, (returnList_t)volumes);
3095 if (eval) ABORT(eval);
3098 FreeReturnList(&vollist);
3099 code = ubik_EndTrans(ut);
3103 FreeReturnList(&vollist);
3104 ubik_AbortTrans(ut);
3108 afs_int32 SBUDB_UseTape (call, tape, new)
3109 struct rx_call *call;
3110 struct budb_tapeEntry *tape; /* tape info */
3111 afs_int32 *new; /* set if tape is new */
3115 code = UseTape (call, tape, new);
3116 osi_auditU (call, BUDB_UseTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
3120 afs_int32 UseTape (call, tape, new)
3121 struct rx_call *call;
3122 struct budb_tapeEntry *tape; /* tape info */
3123 int *new; /* set if tape is new */
3125 struct ubik_trans *ut;
3129 afs_int32 eval, code;
3131 if ( !callPermitted(call) )
3132 return BUDB_NOTPERMITTED;
3134 if (strlen (tape->name) >= sizeof(t.name)) return BUDB_BADARGUMENT;
3136 eval = InitRPC (&ut, LOCKWRITE, 1);
3137 if (eval) return eval;
3141 memset(&t, 0, sizeof(t));
3142 eval = AllocStructure (ut, tape_BLOCK, 0, &a, &t);
3143 if (eval) ABORT(eval);
3145 strcpy (t.name, tape->name);
3147 eval = ht_HashIn (ut, &db.tapeName, a, &t);
3148 if (eval) ABORT(eval);
3152 /* Since deleting a tape may change the dump (if its the same one), read in
3153 the dump after the call to DeleteTape. */
3155 eval = ht_LookupEntry (ut, &db.dumpIden, &tape->dump, &da, &d);
3156 if (eval) ABORT(eval);
3157 if (!da) ABORT(BUDB_NODUMPID);
3159 if (!tape->written) tape->written = time(0); /* fill in tape struct */
3160 t.written = htonl(tape->written);
3161 t.expires = htonl(tape->expires);
3163 t.seq = htonl(tape->seq);
3164 t.useCount = htonl(tape->useCount);
3165 t.labelpos = htonl(tape->labelpos);
3167 t.flags = htonl(tape->flags | BUDB_TAPE_BEINGWRITTEN);
3169 t.nextTape = d.firstTape; /* Chain the tape to the dump */
3170 d.firstTape = htonl(a);
3172 if (tape->seq >= ntohl(d.tapes.maxTapes)) /* inc # tapes in the dump */
3173 d.tapes.maxTapes = htonl(tape->seq);
3175 eval = dbwrite (ut, a, &t, sizeof(t)); /* write tape struct */
3176 if (eval) ABORT(eval);
3178 eval = dbwrite (ut, da, &d, sizeof(d)); /* write the dump struct */
3179 if (eval) ABORT(eval);
3181 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
3182 if (eval) ABORT(eval);
3184 LogDebug(5, "added tape %s\n", tape->name);
3186 code = ubik_EndTrans(ut);
3190 ubik_AbortTrans(ut);
3196 /* ---------------------------------------------
3197 * debug interface routines
3198 * ---------------------------------------------
3201 afs_int32 SBUDB_T_DumpHashTable (call, type, filename)
3202 struct rx_call *call;
3208 code = T_DumpHashTable (call, type, filename);
3209 osi_auditU (call, BUDB_TDmpHaEvent, code, AUD_STR, filename, AUD_END);
3213 afs_int32 T_DumpHashTable (call, type, filename)
3214 struct rx_call *call;
3218 struct ubik_trans *ut;
3219 struct memoryHashTable *mht;
3221 afs_int32 eval, code = 0;
3228 char e[sizeof(struct block)]; /* unnecessarily conservative */
3232 if ( !callPermitted(call) )
3233 return BUDB_NOTPERMITTED;
3235 if (strlen (filename) >= sizeof(path)-5) return BUDB_BADARGUMENT;
3237 eval = InitRPC (&ut, LOCKWRITE, 1);
3238 if (eval) return eval;
3240 if ((mht = ht_GetType (type, &e_size)) == 0) return BUDB_BADARGUMENT;
3242 sprintf(path, "%s/%s", gettmpdir(), filename);
3244 DUMP = fopen (path, "w");
3245 if (!DUMP) ABORT(BUDB_BADARGUMENT);
3248 for (old=0; ; old++)
3250 length = (old ? mht->oldLength : mht->length);
3251 if (length) fprintf (DUMP, "Dumping %sHash Table:\n", (old?"Old ":""));
3253 for (hash=0; hash<length; hash++)
3255 a = ht_LookupBucket (ut, mht, hash, old);
3259 eval = dbread (ut, a, e, e_size);
3260 if (eval) ABORT(eval);
3263 if (a == first_a) fprintf (DUMP, " in bucket %d at %d is ", hash, a);
3264 else fprintf (DUMP, " at %d is ", a);
3266 case HT_dumpIden_FUNCTION:
3267 fprintf (DUMP, "%d\n", ntohl(((struct dump *)e)->id));
3269 case HT_dumpName_FUNCTION:
3270 fprintf (DUMP, "%s\n", ((struct dump *)e)->dumpName);
3272 case HT_tapeName_FUNCTION:
3273 fprintf (DUMP, "%s\n", ((struct tape *)e)->name);
3275 case HT_volName_FUNCTION:
3276 fprintf (DUMP, "%s\n", ((struct volInfo *)e)->name);
3279 if ((ht_HashEntry(mht,e) % length) != hash) ABORT(BUDB_DATABASEINCONSISTENT);
3280 a = ntohl(*(dbadr *)(e + mht->threadOffset));
3286 fprintf (DUMP, "%d entries found\n", ent);
3287 if (ntohl(mht->ht->entries) != ent) ABORT(BUDB_DATABASEINCONSISTENT);
3289 code = ubik_EndTrans(ut);
3290 if (DUMP) fclose (DUMP);
3294 ubik_AbortTrans(ut);
3295 if (DUMP) fclose (DUMP);
3299 afs_int32 SBUDB_T_GetVersion (call, majorVersion)
3300 struct rx_call *call;
3301 afs_int32 *majorVersion;
3305 code = T_GetVersion (call, majorVersion);
3306 osi_auditU (call, BUDB_TGetVrEvent, code, AUD_END);
3310 afs_int32 T_GetVersion (call, majorVersion)
3311 struct rx_call *call;
3314 struct ubik_trans *ut;
3317 code = InitRPC (&ut, LOCKREAD, 0);
3318 if (code) return(code);
3320 *majorVersion = BUDB_MAJORVERSION;
3322 code = ubik_EndTrans(ut);
3326 /* BUDB_T_DumpDatabase
3327 * dump as much of the database as possible int /tmp/<filename>
3330 afs_int32 SBUDB_T_DumpDatabase (call, filename)
3331 struct rx_call *call;
3336 code = T_DumpDatabase (call, filename);
3337 osi_auditU (call, BUDB_TDmpDBEvent, code, AUD_STR, filename, AUD_END);
3341 afs_int32 T_DumpDatabase (call, filename)
3342 struct rx_call *call;
3347 struct ubik_trans *ut;
3350 int type, old, length, hash;
3352 struct memoryHashTable *mht;
3353 afs_int32 eval, code = 0;
3355 if ( !callPermitted(call) )
3356 return BUDB_NOTPERMITTED;
3358 path = (char *) malloc(strlen(gettmpdir())+1+strlen(filename)+1);
3359 if (!path) return(BUDB_INTERNALERROR);
3361 sprintf(path, "%s/%s", gettmpdir(), filename);
3363 dumpfid = fopen(path, "w");
3364 if (!dumpfid) return(BUDB_BADARGUMENT);
3366 eval = InitRPC (&ut, LOCKWRITE, 1);
3367 if (eval) return(eval);
3369 /* dump all items in the database */
3370 for ( type=1; type<=HT_MAX_FUNCTION; type++ )
3372 mht = ht_GetType (type, &entrySize);
3373 if (!mht) ERROR(BUDB_BADARGUMENT);
3375 for ( old =0; old <= 1; old++ )
3377 length = ( old ? mht->oldLength : mht->length);
3378 if (!length) continue;
3380 fprintf (dumpfid, "Dumping %s Hash Table:\n", (old ? "Old ":""));
3382 for ( hash = 0; hash < length; hash++ )
3384 dbAddr = ht_LookupBucket (ut, mht, hash, old);
3390 case HT_dumpIden_FUNCTION:
3392 struct dump hostDump, diskDump;
3394 eval = cdbread (ut, dump_BLOCK, dbAddr, &diskDump, sizeof(diskDump));
3395 if (eval) ERROR(eval);
3397 fprintf(dumpfid, "\ndumpId hash %d, entry at %u: block %d, index %d\n",
3398 hash, dbAddr, block, index);
3399 fprintf(dumpfid, "----------------------------\n");
3400 dump_ntoh(&diskDump, &hostDump);
3401 printDump(dumpfid, &hostDump);
3402 dbAddr = hostDump.idHashChain;
3406 case HT_dumpName_FUNCTION:
3408 struct dump hostDump, diskDump;
3410 eval = cdbread (ut, dump_BLOCK, dbAddr, &diskDump, sizeof(diskDump));
3411 if (eval) ERROR(eval);
3414 "\ndumpname hash %d, entry at %u: block %d, index %d\n",
3415 hash, dbAddr, block, index);
3416 fprintf(dumpfid, "----------------------------\n");
3417 dump_ntoh(&diskDump, &hostDump);
3418 printDump(dumpfid, &hostDump);
3419 dbAddr = hostDump.nameHashChain;
3423 case HT_tapeName_FUNCTION:
3425 struct tape hostTape, diskTape;
3427 eval = cdbread (ut, tape_BLOCK, dbAddr, &diskTape, sizeof(diskTape));
3428 if (eval) ERROR(eval);
3431 "\ntapename hash %d, entry at %u: block %d, index %d\n",
3432 hash, dbAddr, block, index);
3433 fprintf(dumpfid, "----------------------------\n");
3434 tape_ntoh(&diskTape, &hostTape);
3435 printTape(dumpfid, &hostTape);
3436 dbAddr = hostTape.nameHashChain;
3440 case HT_volName_FUNCTION:
3442 struct volInfo hostVolInfo, diskVolInfo;
3444 eval = cdbread (ut, volInfo_BLOCK, dbAddr, &diskVolInfo, sizeof(diskVolInfo));
3445 if (eval) ERROR(eval);
3448 "\nvolname hash %d, entry at %u: block %d, index %d\n",
3449 hash, dbAddr, block, index);
3450 fprintf(dumpfid, "----------------------------\n");
3451 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3452 printVolInfo(dumpfid, &hostVolInfo);
3453 dbAddr = hostVolInfo.nameHashChain;
3455 volFragsDump(ut, dumpfid,
3456 hostVolInfo.firstFragment);
3461 fprintf(dumpfid, "unknown type %d\n", type);
3471 code = ubik_EndTrans(ut); /* is this safe if no ut started ?*/
3472 if (dumpfid) fclose(dumpfid);
3473 if (path) free(path);
3477 volFragsDump(ut, dumpfid, dbAddr)
3478 struct ubik_trans *ut;
3482 struct volFragment hostVolFragment, diskVolFragment;
3488 code = cdbread (ut, volFragment_BLOCK, dbAddr, &diskVolFragment, sizeof(diskVolFragment));
3489 if (code) { /* don't be fussy about errors */
3490 fprintf(dumpfid, "volFragsDump: Error reading database\n");
3494 fprintf(dumpfid, "\nvolfragment entry at %u: block %d, index %d\n",
3495 dbAddr, block, index);
3496 fprintf(dumpfid, "----------------------------\n");
3497 volFragment_ntoh(&diskVolFragment, &hostVolFragment);
3498 printVolFragment(dumpfid, &hostVolFragment);
3499 dbAddr = hostVolFragment.sameNameChain;
3505 /* utilities - network to host conversion
3506 * currently used for debug only
3509 volFragmentDiskToHost(diskVfPtr, hostVfPtr)
3510 struct volFragment *diskVfPtr, *hostVfPtr;
3512 hostVfPtr->vol = ntohl(diskVfPtr->vol);
3513 hostVfPtr->sameNameChain = ntohl(diskVfPtr->sameNameChain);
3514 hostVfPtr->tape = ntohl(diskVfPtr->tape);
3515 hostVfPtr->sameTapeChain = ntohl(diskVfPtr->sameTapeChain);
3516 hostVfPtr->position = ntohl(diskVfPtr->position);
3517 hostVfPtr->clone = ntohl(diskVfPtr->clone);
3518 hostVfPtr->incTime = ntohl(diskVfPtr->incTime);
3519 hostVfPtr->startByte = ntohl(diskVfPtr->startByte);
3520 hostVfPtr->nBytes = ntohl(diskVfPtr->nBytes);
3521 hostVfPtr->flags = ntohs(diskVfPtr->flags);
3522 hostVfPtr->sequence = ntohs(diskVfPtr->sequence);
3525 volInfoDiskToHost(diskViPtr, hostViPtr)
3526 struct volInfo *diskViPtr, *hostViPtr;
3528 strcpy(hostViPtr->name, diskViPtr->name);
3529 hostViPtr->nameHashChain = ntohl(diskViPtr->nameHashChain);
3530 hostViPtr->id = ntohl(diskViPtr->id);
3531 strcpy(hostViPtr->server, diskViPtr->server);
3532 hostViPtr->partition = ntohl(diskViPtr->partition);
3533 hostViPtr->flags = ntohl(diskViPtr->flags);
3534 hostViPtr->sameNameHead = ntohl(diskViPtr->sameNameHead);
3535 hostViPtr->sameNameChain = ntohl(diskViPtr->sameNameChain);
3536 hostViPtr->firstFragment = ntohl(diskViPtr->firstFragment);
3537 hostViPtr->nFrags = ntohl(diskViPtr->nFrags);
3540 tapeDiskToHost(diskTapePtr, hostTapePtr)
3541 struct tape *diskTapePtr, *hostTapePtr;
3543 strcpy(hostTapePtr->name, diskTapePtr->name);
3544 hostTapePtr->nameHashChain = ntohl(diskTapePtr->nameHashChain);
3545 hostTapePtr->flags = ntohl(diskTapePtr->flags);
3547 /* tape id conversion here */
3548 hostTapePtr->written = ntohl(diskTapePtr->written);
3549 hostTapePtr->nBytes = ntohl(diskTapePtr->nBytes);
3550 hostTapePtr->nFiles = ntohl(diskTapePtr->nFiles);
3551 hostTapePtr->nVolumes = ntohl(diskTapePtr->nVolumes);
3552 hostTapePtr->seq = ntohl(diskTapePtr->seq);
3553 hostTapePtr->dump = ntohl(diskTapePtr->dump);
3554 hostTapePtr->nextTape = ntohl(diskTapePtr->nextTape);
3555 hostTapePtr->firstVol = ntohl(diskTapePtr->firstVol);
3556 hostTapePtr->useCount = ntohl(diskTapePtr->useCount);
3559 dumpDiskToHost(diskDumpPtr, hostDumpPtr)
3560 struct dump *diskDumpPtr, *hostDumpPtr;
3562 hostDumpPtr->id = ntohl(diskDumpPtr->id);
3563 hostDumpPtr->idHashChain = ntohl(diskDumpPtr->idHashChain);
3564 strcpy(hostDumpPtr->dumpName, diskDumpPtr->dumpName);
3565 strcpy(hostDumpPtr->dumpPath, diskDumpPtr->dumpPath);
3566 strcpy(hostDumpPtr->volumeSet, diskDumpPtr->volumeSet);
3567 hostDumpPtr->nameHashChain = ntohl(diskDumpPtr->nameHashChain);
3568 hostDumpPtr->flags = ntohl(diskDumpPtr->flags);
3569 hostDumpPtr->parent = ntohl(diskDumpPtr->parent);
3570 hostDumpPtr->created = ntohl(diskDumpPtr->created);
3571 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3572 hostDumpPtr->nVolumes = ntohl(diskDumpPtr->nVolumes);
3574 /* tapeset conversion here */
3576 hostDumpPtr->firstTape = ntohl(diskDumpPtr->firstTape);
3578 /* principal conversion here */
3583 checkHash(ut,hashType)
3584 struct ubik_trans *ut;
3587 struct memoryHashTable *mhtPtr;
3588 int entrySize, hashTableLength;
3593 mhtPtr = ht_GetType(hashType, &entrySize);
3597 for ( old = 0; old < 1; old++)
3599 LogDebug(5, "\nold = %d\n", old);
3600 printMemoryHashTable(stdout, mhtPtr);
3602 hashTableLength = ( old ? mhtPtr->oldLength : mhtPtr->length);
3604 for ( bucket = 0; bucket < hashTableLength; bucket++ )
3608 entryAddr = ht_LookupBucket (ut, mhtPtr, bucket, old);
3609 while (entryAddr != 0)
3611 LogDebug(6, "bucket %d has disk addr %d\n", bucket, entryAddr);
3614 case HT_dumpIden_FUNCTION:
3616 struct dump diskDump, hostDump;
3618 code = dbread(ut, entryAddr, &diskDump, entrySize);
3619 if (code) ERROR(-1);
3621 dump_ntoh(&diskDump, &hostDump);
3622 printDump(stdout, &hostDump);
3623 entryAddr = hostDump.idHashChain;
3627 case HT_dumpName_FUNCTION:
3630 case HT_tapeName_FUNCTION:
3633 case HT_volName_FUNCTION:
3635 struct volInfo diskVolInfo, hostVolInfo;
3637 code = dbread(ut, entryAddr, &diskVolInfo, entrySize);
3638 if (code) ERROR(-1);
3640 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3641 printVolInfo(stdout, &hostVolInfo);
3642 entryAddr = hostVolInfo.nameHashChain;