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>
39 #include <sys/types.h>
41 #include <afs/bubasics.h>
50 #include <afs/cellconfig.h>
54 #include "budb_errs.h"
56 #include "error_macros.h"
58 #include "afs/audit.h"
59 #include <afs/afsutil.h>
65 extern struct ubik_dbase *BU_dbase;
66 extern struct afsconf_dir *BU_conf; /* for getting cell info */
67 extern afs_int32 myHost;
68 extern struct memoryDB db; /* incore copies of db structures */
70 afs_int32 AddVolume(), AddVolumes(), CreateDump(), DoDeleteDump(), DoDeleteTape(), ListDumps();
71 afs_int32 DeleteVDP(), FindClone(), FindDump(), FindLatestDump();
72 afs_int32 FinishDump(), FinishTape(), GetDumps(), getExpiration(), T_DumpDatabase();
73 afs_int32 makeAppended(), MakeDumpAppended(), FindLastTape(), GetTapes();
74 afs_int32 GetVolumes(), UseTape(), T_DumpHashTable(), T_GetVersion();
76 /* Text block management */
80 struct memTextBlock *mtb_next; /* next in chain */
81 afs_int32 mtb_nbytes; /* # of bytes in this block */
82 struct blockHeader mtb_blkHeader; /* in memory header */
83 dbadr mtb_addr; /* disk address of block */
86 typedef struct memTextBlock memTextBlockT;
87 typedef memTextBlockT *memTextBlockP;
89 /* These variable are for returning debugging info about the state of the
90 server. If they get trashed during multi-threaded operation it doesn't
93 /* This is global so COUNT_REQ in krb_udp.c can refer to it. */
94 char *lastOperation; /* name of last operation */
95 static Date lastTrans; /* time of last transaction */
97 /* procsInited is sort of a lock: during a transaction only one process runs
98 while procsInited is false. */
100 static int procsInited = 0;
102 /* This variable is protected by the procsInited flag. */
104 static int (*rebuildDatabase)();
106 /* AwaitInitialization
107 * Wait unitl budb has initialized (InitProcs). If it hasn't
108 * within 5 seconds, then return no quorum.
111 AwaitInitialization()
117 if (!start) start = time(0);
118 else if (time(0)-start > 5) return UNOQUORUM;
125 * name is a pathname style name, determine trailing name and return
130 tailCompPtr(pathNamePtr)
134 ptr = strrchr(pathNamePtr, '/');
137 /* this should never happen */
138 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
143 ptr++; /* skip the / */
148 * Check to see if the caller is a SuperUser.
155 struct rx_call *call;
158 struct afsconf_dir *acdir;
160 acdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
161 if (!acdir) return 0;
163 if ( afsconf_SuperUser(acdir, call, NULL) )
167 if (acdir) afsconf_Close(acdir);
172 * This is called by every RPC interface to create a Ubik transaction
173 * and read the database header into core
179 * sets a lock on byte 1 of the database. Looks like it enforces
180 * single threading by use of the lock.
184 InitRPC (ut, lock, this_op)
185 struct ubik_trans **ut;
186 int lock; /* indicate read/write transaction */
187 int this_op; /* opcode of RCP, for COUNT_ABO */
190 float wait = 0.91; /* start waiting for 1 second */
193 /* wait for server initialization to finish if this is not InitProcs calling */
195 if (code = AwaitInitialization())
198 for (code = UNOQUORUM; code == UNOQUORUM; )
200 code = ubik_BeginTrans(BU_dbase,
201 ((lock == LOCKREAD) ? UBIK_READTRANS : UBIK_WRITETRANS),
203 if (code == UNOQUORUM)
204 { /* no quorum elected */
205 if (wait < 1) Log("Waiting for quorum election\n");
206 if (wait < 15.0) wait *= 1.1;
207 IOMGR_Sleep ((int)wait);
210 if (code) return code;
211 if (wait > 1) Log("Have established quorum\n");
213 /* set lock at posiion 1, for 1 byte of type lock */
214 if (code = ubik_SetLock (*ut, 1, 1, lock))
216 ubik_AbortTrans (*ut);
220 /* check that dbase is initialized and setup cheader */
221 if (lock == LOCKREAD)
223 /* init but don't fix because this is read only */
224 if ( code = CheckInit(*ut, 0) )
226 ubik_AbortTrans(*ut);
227 if ( code = InitRPC(ut, LOCKWRITE, 0) ) /* Now fix the database */
229 LogError(code, "InitRPC: InitRPC failed\n");
232 if ( code = ubik_EndTrans(*ut) )
234 LogError(code, "InitRPC: ubik_EndTrans failed\n");
237 goto start; /* now redo the read transaction */
242 if (code = CheckInit(*ut, rebuildDatabase))
244 ubik_AbortTrans(*ut);
252 /* This is called to initialize a newly created database */
253 static int initialize_database (ut)
254 struct ubik_trans *ut;
259 static int noAuthenticationRequired; /* global state */
260 static int recheckNoAuth; /* global state */
265 struct ubik_trans *ut;
270 if ( (globalConfPtr->myHost == 0) || (BU_conf == 0) )
271 ERROR(BUDB_INTERNALERROR);
275 if ( globalConfPtr->debugFlags & DF_NOAUTH )
276 noAuthenticationRequired = 1;
278 if ( globalConfPtr->debugFlags & DF_RECHECKNOAUTH )
282 noAuthenticationRequired = afsconf_GetNoAuthFlag(BU_conf);
284 if (noAuthenticationRequired)
285 LogError(0, "Running server with security disabled\n");
289 rebuildDatabase = initialize_database;
291 if (code = InitRPC (&ut, LOCKREAD, 0))
293 LogError(code, "InitProcs: InitRPC failed\n");
296 code = ubik_EndTrans(ut);
299 LogError(code, "InitProcs: ubik_EndTrans failed\n");
303 rebuildDatabase = 0; /* only do this during init */
311 int nElements; /* number in list */
312 int allocSize; /* number of elements allocated */
313 dbadr *elements; /* array of addresses */
316 static void InitReturnList (list)
317 struct returnList *list;
321 list->elements = (dbadr *)0;
324 static void FreeReturnList (list)
325 struct returnList *list;
327 if (list->elements) free(list->elements);
328 list->elements = (dbadr *)0;
332 /* As entries are collected, they are added to a return list. Once all
333 * entries have been collected, it is then placed in the return buffer
334 * with SendReturnList(). The first *to_skipP are not recorded.
336 static afs_int32 AddToReturnList (list, a, to_skipP)
337 struct returnList *list;
344 if (a == 0) return 0;
350 /* Up to 5 plus a maximum so SendReturnList() knows if we
351 * need to come back for more.
353 if (list->nElements >= BUDB_MAX_RETURN_LIST+5)
354 return BUDB_LIST2BIG;
356 if (list->nElements >= list->allocSize) {
357 if (list->elements == 0) {
359 tmp = (char *) malloc (sizeof(dbadr) * size);
361 size = list->allocSize + 10;
362 tmp = (char *) realloc (list->elements, sizeof(dbadr) * size);
364 if (!tmp) return BUDB_NOMEM;
365 list->elements = (dbadr *) tmp;
366 list->allocSize = size;
369 list->elements[list->nElements] = a;
374 afs_int32 FillVolEntry(ut, va, vol)
375 struct ubik_trans *ut;
377 struct budb_volumeEntry *vol;
382 struct volFragment vf;
384 if (dbread (ut, va, &vf, sizeof(vf))) return BUDB_IO; /* The volFrag */
385 if (dbread (ut, ntohl(vf.vol), &vi, sizeof(vi))) return BUDB_IO; /* The volInfo */
386 if (dbread (ut, ntohl(vf.tape), &t, sizeof(t))) return BUDB_IO; /* The tape */
387 if (dbread (ut, ntohl(t.dump), &d, sizeof(d))) return BUDB_IO; /* The dump */
389 strcpy (vol->name, vi.name);
390 strcpy (vol->server, vi.server);
391 strcpy (vol->tape, t.name);
392 vol->tapeSeq = ntohl(t.seq);
393 vol->dump = ntohl(d.id);
394 vol->position = ntohl(vf.position);
395 vol->clone = ntohl(vf.clone);
396 vol->incTime = ntohl(vf.incTime);
397 vol->nBytes = ntohl(vf.nBytes);
398 vol->startByte = ntohl(vf.startByte);
399 vol->flags = (ntohs(vf.flags) & VOLFRAGMENTFLAGS); /* low 16 bits here */
400 vol->flags |= (ntohl(vi.flags) & VOLINFOFLAGS); /* high 16 bits here */
401 vol->seq = ntohs(vf.sequence);
402 vol->id = ntohl(vi.id);
403 vol->partition = ntohl(vi.partition);
408 afs_int32 FillDumpEntry (ut, da, dump)
409 struct ubik_trans *ut;
411 struct budb_dumpEntry *dump;
415 if (dbread (ut, da, &d, sizeof(d))) return BUDB_IO;
416 dump->id = ntohl(d.id);
417 dump->flags = ntohl(d.flags);
418 dump->created = ntohl(d.created);
419 strncpy (dump->name, d.dumpName, sizeof(dump->name));
420 strncpy (dump->dumpPath, d.dumpPath, sizeof(dump->dumpPath));
421 strncpy (dump->volumeSetName, d.volumeSet, sizeof(dump->volumeSetName));
423 dump->parent = ntohl(d.parent);
424 dump->level = ntohl(d.level);
425 dump->nVolumes = ntohl(d.nVolumes);
427 tapeSet_ntoh(&d.tapes, &dump->tapes);
429 if (strlen(d.dumper.name) < sizeof(dump->dumper.name))
430 strcpy (dump->dumper.name, d.dumper.name);
431 if (strlen(d.dumper.instance) < sizeof(dump->dumper.instance))
432 strcpy (dump->dumper.instance, d.dumper.instance);
433 if (strlen(d.dumper.cell) < sizeof(dump->dumper.cell))
434 strcpy (dump->dumper.cell, d.dumper.cell);
436 /* Get the initial dumpid and the appended dump id */
437 dump->initialDumpID = ntohl(d.initialDumpID);
438 if (d.appendedDumpChain)
440 if (dbread (ut, ntohl(d.appendedDumpChain), &ad, sizeof(ad))) return BUDB_IO;
441 dump->appendedDumpID = ntohl(ad.id);
444 dump->appendedDumpID = 0;
446 /* printf("dump name %s, parent %d, level %d\n",
447 d.dumpName, ntohl(d.parent), ntohl(d.level)); */
452 afs_int32 FillTapeEntry (ut, ta, tape)
453 struct ubik_trans *ut;
455 struct budb_tapeEntry *tape;
461 if ( dbread (ut, ta, &t, sizeof(t)) )
464 /* Get the tape's expiration date */
465 if ( code = getExpiration(ut,&t) )
468 strcpy (tape->name, t.name);
469 tape->flags = ntohl(t.flags);
470 tape->written = ntohl(t.written);
471 tape->expires = ntohl(t.expires);
472 tape->nMBytes = ntohl(t.nMBytes);
473 tape->nBytes = ntohl(t.nBytes);
474 tape->nFiles = ntohl(t.nFiles);
475 tape->nVolumes = ntohl(t.nVolumes);
476 tape->seq = ntohl(t.seq);
477 tape->labelpos = ntohl(t.labelpos);
478 tape->useCount = ntohl(t.useCount);
479 tape->useKBytes = ntohl(t.useKBytes);
481 if (dbread (ut, ntohl(t.dump), &d, sizeof(d))) return BUDB_IO;
482 tape->dump = ntohl(d.id);
486 #define returnList_t budb_dumpList *
489 * A list of elements of size e_size is in list, collected
490 * with AddToReturnList(). We will move this to a correspoding
491 * return list, eList, via FillProc(). nextInodeP tells us
492 * if there are more and how many to skip on the next request.
495 SendReturnList (ut, list, FillProc, e_size, index, nextIndexP, dbTimeP, eList)
496 struct ubik_trans *ut;
497 struct returnList *list; /* list of elements to return */
498 afs_int32 (*FillProc)(); /* proc to fill entry */
499 int e_size; /* size of each element */
500 afs_int32 index; /* index from previous call */
501 afs_int32 *nextIndexP; /* if more elements are available */
502 afs_int32 *dbTimeP; /* time of last db update */
503 budb_dumpList *eList; /* rxgen list structure (e.g.) */
511 *dbTimeP = ntohl(db.h.lastUpdate);
513 /* Calculate how many to return. Don't let if go over
514 * BUDB_MAX_RETURN_LIST nor the size of our return list.
516 to_return = list->nElements;
517 if (to_return > BUDB_MAX_RETURN_LIST)
518 to_return = BUDB_MAX_RETURN_LIST;
519 if (eList->budb_dumpList_len && (to_return > eList->budb_dumpList_len))
520 to_return = eList->budb_dumpList_len;
522 /* Allocate space for the return values if needed and zero it */
523 if (eList->budb_dumpList_val == 0) {
524 eList->budb_dumpList_val = (struct budb_dumpEntry *)malloc (e_size * to_return);
525 if (!eList->budb_dumpList_val) return(BUDB_NOMEM);
527 memset(eList->budb_dumpList_val, 0, e_size * to_return);
528 eList->budb_dumpList_len = to_return;
530 e = (char *)(eList->budb_dumpList_val);
531 for (i=0; i<to_return; i++, e += e_size) {
532 code = (*FillProc) (ut, list->elements[i], e);
533 if (code) return code;
536 if (list->nElements > i)
537 *nextIndexP = index + i;
541 /* Come here to delete a volInfo structure. */
543 static afs_int32 DeleteVolInfo (ut, via, vi)
544 struct ubik_trans *ut;
551 if (vi->firstFragment) return 0; /* still some frags, don't free yet */
552 if (vi->sameNameHead == 0) { /* this is the head */
553 if (vi->sameNameChain) return 0; /* empty head, some non-heads left */
555 code = ht_HashOut (ut, &db.volName, via, vi);
556 if (code) return code;
557 code = FreeStructure (ut, volInfo_BLOCK, via);
560 hvia = ntohl(vi->sameNameHead);
561 if (dbread (ut, hvia, &hvi, sizeof(hvi))) return BUDB_IO;
562 code = RemoveFromList (ut, hvia, &hvi, &hvi.sameNameChain, via, vi, &vi->sameNameChain);
563 if (code == -1) return BUDB_DATABASEINCONSISTENT;
564 if (code == 0) code = FreeStructure (ut, volInfo_BLOCK, via);
568 /* Detach a volume fragment from its volInfo structure. Its tape chain is
569 already freed. This routine frees the structure and the caller must not
572 static afs_int32 DeleteVolFragment (ut, va, v)
573 struct ubik_trans *ut;
575 struct volFragment *v;
581 if (dbread (ut, via, &vi, sizeof(vi))) return BUDB_IO;
582 code = RemoveFromList (ut, via, &vi, &vi.firstFragment, va, v, &v->sameNameChain);
583 if (code == -1) return BUDB_DATABASEINCONSISTENT;
584 if (code) return code;
585 if (vi.firstFragment == 0)
586 if (code = DeleteVolInfo (ut, via, &vi)) return code;
587 if (code = FreeStructure (ut, volFragment_BLOCK, va)) return code;
589 /* decrement frag counter */
590 code = set_word_addr (ut, via, &vi, &vi.nFrags, htonl(ntohl(vi.nFrags)-1));
591 if (code) return code;
595 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
596 * The caller will remove it from the hash table if necessary. The caller is
597 * also responsible for writing the tape out if necessary. */
599 static afs_int32 DeleteTape (ut, ta, t)
600 struct ubik_trans *ut;
608 if (da == 0) return BUDB_DATABASEINCONSISTENT;
609 if (dbread (ut, da, &d, sizeof(d))) return BUDB_IO;
610 if (d.firstTape == 0) return BUDB_DATABASEINCONSISTENT;
612 code = RemoveFromList (ut, da, &d, &d.firstTape, ta, t, &t->nextTape);
613 if (code == -1) return BUDB_DATABASEINCONSISTENT;
614 if (code) return code;
616 /* Since the tape should have been truncated there should never be any
617 * volumes in the tape. */
618 if (t->firstVol || t->nVolumes) return BUDB_DATABASEINCONSISTENT;
624 DeleteDump (ut, da, d)
625 struct ubik_trans *ut;
631 code = ht_HashOut (ut, &db.dumpIden, da, d);
632 if (code) ERROR(code);
634 code = ht_HashOut (ut, &db.dumpName, da, d);
635 if (code) ERROR(code);
637 /* Since the tape should have been truncated this should never happen. */
638 if (d->firstTape || d->nVolumes) ERROR(BUDB_DATABASEINCONSISTENT);
640 code = FreeStructure (ut, dump_BLOCK, da);
641 if (code) ERROR(code);
650 * This is called with a volumeEntry and a volInfo structure and compares
651 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
652 * search volInfo structures once it has the head volInfo structure from the
653 * volName hash table.
655 * When called from GetVolInfo the name compare is redundant.
656 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
659 static int VolInfoMatch (vol, vi)
660 struct budb_volumeEntry *vol;
663 return ( (strcmp (vol->name, vi->name) == 0) && /* same volume name */
664 (vol->id == ntohl(vi->id)) && /* same volume id */
665 ((vol->flags & VOLINFOFLAGS) ==
666 (ntohl(vi->flags) & VOLINFOFLAGS)) && /* same flags */
667 (vol->partition == ntohl(vi->partition)) && /* same partition (N/A)*/
668 (strcmp (vol->server, vi->server) == 0) ); /* same server (N/A) */
673 * This routine takes a volumeEntry structure from an RPC interface and
674 * returns the corresponding volInfo structure, creating it if necessary.
676 * The caller must write the entry out.
679 static afs_int32 GetVolInfo (ut, volP, viaP, viP)
680 struct ubik_trans *ut;
681 struct budb_volumeEntry *volP;
687 afs_int32 eval, code = 0;
689 eval = ht_LookupEntry (ut, &db.volName, volP->name, &via, viP);
690 if (eval) ERROR(eval);
694 /* allocate a new volinfo structure */
695 eval = AllocStructure (ut, volInfo_BLOCK, 0, &via, viP);
696 if (eval) ERROR(eval);
698 strcpy (viP->name, volP->name);
699 strcpy (viP->server, volP->server);
700 viP->sameNameHead = 0; /* The head of same name chain */
701 viP->sameNameChain = 0; /* Same name chain is empty */
702 viP->firstFragment = 0;
704 viP->id = htonl(volP->id);
705 viP->partition = htonl(volP->partition);
706 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
708 /* Chain onto volname hash table */
709 eval = ht_HashIn (ut, &db.volName, via, viP);
710 if (eval) ERROR(eval);
712 LogDebug(4, "volume Info for %s placed at %d\n", db.volName, via);
715 else if ( !VolInfoMatch(volP,viP) ) /* Not the head volinfo struct */
717 hvia = via; /* remember the head volinfo struct */
718 memcpy(&hvi, viP, sizeof(hvi));
720 /* Search the same name chain for the correct volinfo structure */
721 for (via=ntohl(viP->sameNameChain); via; via=ntohl(viP->sameNameChain))
723 eval = dbread (ut, via, viP, sizeof(*viP));
724 if (eval) ERROR(eval);
726 if ( VolInfoMatch(volP,viP) ) break; /* found the one */
729 /* if the correct volinfo struct isn't found, create one */
732 eval = AllocStructure (ut, volInfo_BLOCK, 0, &via, viP);
733 if (eval) ERROR(eval);
735 strcpy (viP->name, volP->name);
736 strcpy (viP->server, volP->server);
737 viP->nameHashChain = 0; /* not in hash table */
738 viP->sameNameHead = htonl(hvia); /* chain to head of sameNameChain */
739 viP->sameNameChain = hvi.sameNameChain;
740 viP->firstFragment = 0;
742 viP->id = htonl(volP->id);
743 viP->partition = htonl(volP->partition);
744 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
746 /* write the head entry's sameNameChain link */
747 eval = set_word_addr (ut, hvia, &hvi, &hvi.sameNameChain, htonl(via));
748 if (eval) ERROR(eval);
758 /* deletesomevolumesfromtape
759 * Deletes a specified number of volumes from a tape. The tape
760 * and dump are modified to reflect the smaller number of volumes.
761 * The transaction is not terminated, it is up to the caller to
762 * finish the transaction and start a new one (if desired).
764 * maxvolumestodelete - don't delete more than this many volumes
768 deleteSomeVolumesFromTape(ut, tapeAddr, tapePtr, maxVolumesToDelete)
769 struct ubik_trans *ut;
771 struct tape *tapePtr;
772 int maxVolumesToDelete;
774 dbadr volFragAddr, nextVolFragAddr, dumpAddr;
775 struct volFragment volFrag;
777 int volumesDeleted = 0;
778 afs_int32 eval, code = 0;
780 if (!tapePtr) ERROR(0);
782 for (volFragAddr=ntohl(tapePtr->firstVol); (volFragAddr && (maxVolumesToDelete > 0));
783 volFragAddr=nextVolFragAddr)
785 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
786 if (eval) ERROR(eval);
788 nextVolFragAddr = ntohl(volFrag.sameTapeChain);
790 eval = DeleteVolFragment(ut, volFragAddr, &volFrag);
791 if (eval) ERROR(eval);
793 maxVolumesToDelete--;
797 /* reset the volume fragment pointer in the tape */
798 tapePtr->firstVol = htonl(volFragAddr);
800 /* diminish the tape's volume count */
801 tapePtr->nVolumes = htonl(ntohl(tapePtr->nVolumes) - volumesDeleted);
803 eval = dbwrite(ut, tapeAddr, tapePtr, sizeof(*tapePtr));
804 if (eval) ERROR(eval);
806 /* diminish the dump's volume count */
807 dumpAddr = ntohl(tapePtr->dump);
808 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
809 if (eval) ERROR(eval);
811 dump.nVolumes = htonl(ntohl(dump.nVolumes) - volumesDeleted);
812 eval = dbwrite(ut, dumpAddr, &dump, sizeof(dump));
813 if (eval) ERROR(eval);
820 * deletes a dump in stages, by repeatedly deleting a small number of
821 * volumes from the dump until none are left. The dump is then deleted.
823 * In the case where multiple calls are made to delete the same
824 * dump, the operation will succeed but contention for structures
825 * will result in someone getting back an error.
828 * id - id of dump to delete
832 deleteDump(call, id, dumps)
833 struct rx_call *call;
835 budb_dumpsList *dumps;
837 struct ubik_trans *ut;
838 dbadr dumpAddr, tapeAddr, appendedDump;
843 afs_int32 eval, code = 0;
846 /* iterate until the dump is truly deleted */
854 eval = InitRPC(&ut, LOCKWRITE, 1);
855 if (eval) ERROR(eval); /* can't start transaction */
857 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpid, &dumpAddr, &dump);
858 if (eval) ABORT(eval);
859 if (!dumpAddr) ABORT(BUDB_NOENT); /* can't find dump */
861 if ( (dumpid == id) && (dump.initialDumpID) ) /* can't be an appended dump */
862 ABORT(BUDB_NOTINITIALDUMP);
864 tapeAddr = ntohl(dump.firstTape);
865 if (tapeAddr == 0) break;
867 /* there is a tape to delete */
868 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
869 if (eval) ABORT(eval);
871 if ( ntohl(tape.nVolumes) )
873 /* tape is not empty */
874 eval = deleteSomeVolumesFromTape(ut, tapeAddr, &tape, 10);
875 if (eval) ABORT(eval);
878 if ( ntohl(tape.nVolumes) == 0 )
880 /* tape is now empty, delete it */
881 eval = DeleteTape(ut, tapeAddr, &tape);
882 if (eval) ABORT(eval);
883 eval = ht_HashOut(ut, &db.tapeName, tapeAddr, &tape);
884 if (eval) ABORT(eval);
885 eval = FreeStructure(ut, tape_BLOCK, tapeAddr);
886 if (eval) ABORT(eval);
889 eval = ubik_EndTrans(ut);
890 if (eval) ERROR(eval);
892 } /* next deletion portion */
894 /* Record the dump just deleted */
895 if (dumps && (dumps->budb_dumpsList_len < BUDB_MAX_RETURN_LIST))
897 if (dumps->budb_dumpsList_len == 0)
898 dumps->budb_dumpsList_val = (afs_int32 *) malloc(sizeof(afs_int32));
900 dumps->budb_dumpsList_val =
901 (afs_int32 *) realloc(dumps->budb_dumpsList_val,
902 (dumps->budb_dumpsList_len+1)*sizeof(afs_int32));
904 if ( !dumps->budb_dumpsList_val ) ABORT(BUDB_NOMEM);
906 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = dumpid;
907 dumps->budb_dumpsList_len++;
910 appendedDump = ntohl(dump.appendedDumpChain);
912 /* finally done. No more tapes left in the dump. Delete the dump itself */
913 eval = DeleteDump(ut, dumpAddr, &dump);
914 if (eval) ABORT(eval);
916 /* Now delete the appended dump too */
919 eval = dbread(ut, appendedDump, &dump, sizeof(dump));
920 if (eval) ABORT(eval);
922 dumpid = ntohl(dump.id);
927 eval = ubik_EndTrans(ut);
928 if (eval) ERROR(eval);
930 Log("Delete dump %s (DumpID %u), path %s\n",
931 dump.dumpName, ntohl(dump.id), dump.dumpPath);
935 if (code && partialDel) {
936 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
937 dump.dumpName, ntohl(dump.id), dump.dumpPath, code);
947 * dump selection routines - used by BUDB_GetDumps
951 /* most recent dump selection */
955 struct chosenDump *next;
962 int maxDumps; /* max wanted */
963 int ndumps; /* actual in chain */
964 struct chosenDump *chain;
968 wantDump(dumpAddrParam, dumpParam, dumpListPtrParam)
971 char *dumpListPtrParam;
974 struct dump *dumpPtr;
975 struct wantDumpRock *rockPtr;
977 dumpAddr = (dbadr) dumpAddrParam;
978 dumpPtr = (struct dump *) dumpParam;
979 rockPtr = (struct wantDumpRock *) dumpListPtrParam;
981 /* if we don't have our full complement, just add another */
982 if ( rockPtr->ndumps < rockPtr->maxDumps )
985 /* got the number we need, select based on date */
986 if ( (afs_uint32) ntohl(dumpPtr->created) > rockPtr->chain->date )
992 rememberDump(dumpAddrParam, dumpParam, dumpListPtrParam)
995 char *dumpListPtrParam;
998 struct dump *dumpPtr;
999 struct wantDumpRock *rockPtr;
1000 struct chosenDump *ptr, *deletedPtr, **nextPtr;
1002 dumpAddr = (dbadr) dumpAddrParam;
1003 dumpPtr = (struct dump *) dumpParam;
1004 rockPtr = (struct wantDumpRock *) dumpListPtrParam;
1006 ptr = (struct chosenDump *) malloc(sizeof(*ptr));
1009 memset(ptr, 0, sizeof(*ptr));
1010 ptr->addr = dumpAddr;
1011 ptr->date = (afs_uint32) ntohl(dumpPtr->created);
1013 /* Don't overflow the max */
1014 while (rockPtr->ndumps >= rockPtr->maxDumps) {
1015 /* have to drop one */
1016 deletedPtr = rockPtr->chain;
1017 rockPtr->chain = deletedPtr->next;
1022 /* now insert in the right place */
1023 for (nextPtr = &rockPtr->chain; *nextPtr; nextPtr = &((*nextPtr)->next)) {
1024 if (ptr->date < (*nextPtr)->date)
1027 ptr->next = *nextPtr;
1035 /* ---------------------------------------------
1036 * general interface routines - alphabetic
1037 * ---------------------------------------------
1040 afs_int32 SBUDB_AddVolume (call, vol)
1041 struct rx_call *call;
1042 struct budb_volumeEntry *vol;
1046 code = AddVolume (call, vol);
1047 osi_auditU (call, BUDB_AddVolEvent, code, AUD_LONG, (vol ? vol->id : 0), AUD_END);
1051 afs_int32 AddVolume (call, vol)
1052 struct rx_call *call;
1053 struct budb_volumeEntry *vol;
1055 struct ubik_trans *ut;
1056 dbadr da, ta, via, va;
1060 struct volFragment v;
1062 afs_int32 eval, code = 0;
1064 if ( !callPermitted(call) )
1065 return BUDB_NOTPERMITTED;
1067 if ( ( strlen(vol->name) >= sizeof(vi.name) ) ||
1068 ( strlen(vol->server) >= sizeof(vi.server) ) ||
1069 ( strlen(vol->tape) >= sizeof(t.name) ) )
1070 return BUDB_BADARGUMENT;
1072 eval = InitRPC (&ut, LOCKWRITE, 1);
1073 if (eval) return eval;
1075 /* Find the dump in dumpid hash table */
1076 eval = ht_LookupEntry (ut, &db.dumpIden, &vol->dump, &da, &d);
1077 if (eval) ABORT(eval);
1078 if (!da) ABORT(BUDB_NODUMPID);
1080 /* search for the right tape in the dump */
1081 for (ta=ntohl(d.firstTape); ta; ta=ntohl(t.nextTape))
1083 /* read the tape entry */
1084 eval = dbread(ut, ta, &t, sizeof(t));
1085 if (eval) ABORT(eval);
1087 /* Check if the right tape name */
1088 if ( strcmp(t.name, vol->tape) == 0 )
1091 if (!ta) ABORT(BUDB_NOTAPENAME);
1093 if ( (t.dump != htonl(da)) || /* tape must belong to dump */
1094 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1095 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0) ) /* dump must be in progress */
1096 ABORT(BUDB_BADPROTOCOL);
1098 /* find or create a volume info structure */
1099 eval = GetVolInfo(ut, vol, &via, &vi);
1100 if (eval) ABORT(eval);
1102 /* Create a volume fragment */
1103 eval = AllocStructure (ut, volFragment_BLOCK, 0, &va, &v);
1104 if (eval) ABORT(eval);
1106 v.vol = htonl(via); /* vol frag points to vol info */
1107 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1108 vi.firstFragment = htonl(va);
1109 vi.nFrags = htonl(ntohl(vi.nFrags)+1);
1111 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1112 if (eval) ABORT(eval);
1114 v.tape = htonl(ta); /* vol frag points to tape */
1115 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1116 t.firstVol = htonl(va);
1117 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1118 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1119 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes/(1024*1024));
1120 t.nBytes = htonl(bytes % (1024*1024));
1122 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1123 if (eval) ABORT(eval);
1125 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1127 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1128 if (eval) ABORT(eval);
1130 v.position = htonl(vol->position); /* vol frag info */
1131 v.clone = htonl(vol->clone);
1132 v.incTime = htonl(vol->incTime);
1133 v.startByte = htonl(vol->startByte);
1134 v.nBytes = htonl(vol->nBytes);
1135 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1136 v.sequence = htons(vol->seq);
1138 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1139 if (eval) ABORT(eval);
1141 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1142 if (eval) ABORT(eval);
1144 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1146 code = ubik_EndTrans(ut);
1150 ubik_AbortTrans(ut);
1155 afs_int32 SBUDB_AddVolumes (call, vols)
1156 struct rx_call *call;
1157 struct budb_volumeList *vols;
1161 code = AddVolumes (call, vols);
1162 osi_auditU (call, BUDB_AddVolEvent, code, AUD_LONG, 0, AUD_END);
1166 afs_int32 AddVolumes (call, vols)
1167 struct rx_call *call;
1168 struct budb_volumeList *vols;
1170 struct budb_volumeEntry *vol, *vol1;
1171 struct ubik_trans *ut;
1172 dbadr da, ta, via, va;
1176 struct volFragment v;
1178 afs_int32 eval, e, code = 0;
1180 if ( !callPermitted(call) )
1181 return BUDB_NOTPERMITTED;
1183 if (!vols || (vols->budb_volumeList_len <= 0) || !vols->budb_volumeList_val)
1184 return BUDB_BADARGUMENT;
1186 /* The first volume in the list of volumes to add */
1187 vol1 = (struct budb_volumeEntry *)vols->budb_volumeList_val;
1189 eval = InitRPC (&ut, LOCKWRITE, 1);
1190 if (eval) return eval;
1192 /* Find the dump in dumpid hash table */
1193 eval = ht_LookupEntry (ut, &db.dumpIden, &vol1->dump, &da, &d);
1194 if (eval) ABORT(eval);
1195 if (!da) ABORT(BUDB_NODUMPID);
1197 /* search for the right tape in the dump */
1198 for (ta=ntohl(d.firstTape); ta; ta=ntohl(t.nextTape)) {
1199 /* read the tape entry */
1200 eval = dbread(ut, ta, &t, sizeof(t));
1201 if (eval) ABORT(eval);
1203 /* Check if the right tape name */
1204 if ( strcmp(t.name, vol1->tape) == 0 )
1207 if (!ta) ABORT(BUDB_NOTAPENAME);
1209 if ( (t.dump != htonl(da)) || /* tape must belong to dump */
1210 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1211 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0) ) /* dump must be in progress */
1212 ABORT(BUDB_BADPROTOCOL);
1214 for (vol=vol1, e=0; e < vols->budb_volumeList_len; vol++, e++) {
1216 if ( ( strlen(vol->name) >= sizeof(vi.name) ) ||
1217 ( strcmp(vol->name, "") == 0 ) || /* no null volnames */
1218 ( strlen(vol->server) >= sizeof(vi.server) ) ||
1219 ( strlen(vol->tape) >= sizeof(t.name) ) ||
1220 ( strcmp(vol->tape, vol1->tape) != 0 ) ) {
1221 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n",
1222 vol->name, vol->id, vol->tape, vol->dump);
1226 /* find or create a volume info structure */
1227 eval = GetVolInfo(ut, vol, &via, &vi);
1228 if (eval) ABORT(eval);
1229 if (*(afs_int32 *)(&vi) == 0) {
1230 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n",
1231 vol->name, vol->tape, vol->dump);
1232 ABORT(BUDB_BADARGUMENT);
1235 /* Create a volume fragment */
1236 eval = AllocStructure (ut, volFragment_BLOCK, 0, &va, &v);
1237 if (eval) ABORT(eval);
1239 v.vol = htonl(via); /* vol frag points to vol info */
1240 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1241 vi.firstFragment = htonl(va);
1242 vi.nFrags = htonl(ntohl(vi.nFrags)+1);
1243 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1244 if (eval) ABORT(eval);
1246 v.tape = htonl(ta); /* vol frag points to tape */
1247 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1248 t.firstVol = htonl(va);
1249 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1250 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1251 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes/(1024*1024));
1252 t.nBytes = htonl(bytes % (1024*1024));
1254 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1256 v.position = htonl(vol->position); /* vol frag info */
1257 v.clone = htonl(vol->clone);
1258 v.incTime = htonl(vol->incTime);
1259 v.startByte = htonl(vol->startByte);
1260 v.nBytes = htonl(vol->nBytes);
1261 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1262 v.sequence = htons(vol->seq);
1264 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1265 if (eval) ABORT(eval);
1267 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1270 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1271 if (eval) ABORT(eval);
1273 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1274 if (eval) ABORT(eval);
1276 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1277 if (eval) ABORT(eval);
1279 code = ubik_EndTrans(ut);
1283 ubik_AbortTrans(ut);
1289 * records the existence of a dump in the database. This creates only
1290 * the dump record, to which one must attach tape and volume records.
1292 * 1) record the volume set
1295 afs_int32 SBUDB_CreateDump(call, dump)
1296 struct rx_call *call;
1297 struct budb_dumpEntry *dump;
1301 code = CreateDump(call, dump);
1302 osi_auditU (call, BUDB_CrDmpEvent, code, AUD_DATE, (dump ? dump->id : 0), AUD_END);
1303 if (dump && !code) {
1304 Log("Create dump %s (DumpID %u), path %s\n",
1305 dump->name, dump->id, dump->dumpPath);
1310 afs_int32 CreateDump(call, dump)
1311 struct rx_call *call;
1312 struct budb_dumpEntry *dump;
1314 struct ubik_trans *ut;
1315 dbadr findDumpAddr, da;
1316 struct dump findDump, d;
1317 afs_int32 eval, code = 0;
1321 Date expiration; /* checked by Security Module */
1322 struct ktc_principal principal;
1324 if ( !callPermitted(call) )
1325 return BUDB_NOTPERMITTED;
1327 if (strlen(dump->name) >= sizeof(d.dumpName))
1328 return BUDB_BADARGUMENT;
1330 eval = InitRPC (&ut, LOCKWRITE, 1);
1331 if (eval) return eval;
1333 eval = rxkad_GetServerInfo( rx_ConnectionOf(call),
1334 &level, &expiration,
1342 if (eval != RXKADNOAUTH) ABORT(eval);
1344 strcpy(principal.name, "");
1345 strcpy(principal.instance, "");
1346 strcpy(principal.cell, "");
1351 /* authenticated. Take user supplied principal information */
1352 if ( strcmp(dump->dumper.name, "") != 0 )
1353 strncpy(principal.name, dump->dumper.name, sizeof(principal.name));
1355 if ( strcmp(dump->dumper.instance, "") != 0 )
1356 strncpy(principal.instance, dump->dumper.instance, sizeof(principal.instance));
1358 if ( strcmp(dump->dumper.cell, "") != 0 )
1359 strncpy(principal.cell, dump->dumper.cell, sizeof(principal.cell));
1362 /* dump id's are time stamps */
1365 while (1) /* allocate a unique dump id */
1369 /* ensure it is unique - seach for dumpid in hash table */
1370 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr, &findDump);
1371 if (eval) ABORT(eval);
1373 if (!findDumpAddr) /* dumpid not in use */
1375 /* update the last dump id allocated */
1376 eval = set_header_word(ut, lastDumpId, htonl(dump->id));
1377 if (eval) ABORT(eval);
1381 /* dump id is in use - wait a while */
1387 /* dump id supplied (e.g. for database restore) */
1388 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr, &findDump);
1389 if (eval) ABORT(eval);
1391 /* Dump id must not already exist */
1392 if (findDumpAddr) ABORT(BUDB_DUMPIDEXISTS);
1395 /* Allocate a dump structure */
1396 memset(&d, 0, sizeof(d));
1397 eval = AllocStructure (ut, dump_BLOCK, 0, &da, &d);
1398 if (eval) ABORT(eval);
1400 strcpy(d.dumpName, dump->name); /* volset.dumpname */
1401 strcpy(d.dumpPath, dump->dumpPath); /* dump node path */
1402 strcpy(d.volumeSet, dump->volumeSetName); /* volume set */
1403 d.id = htonl(dump->id);
1404 d.parent = htonl(dump->parent); /* parent id */
1405 d.level = htonl(dump->level);
1407 LogDebug(4, "dump name %s, parent %d level %d\n", dump->name, dump->parent, dump->level);
1409 /* if creation time specified, use that. Else use the dumpid time */
1410 if (dump->created == 0) dump->created = dump->id;
1411 d.created = htonl(dump->created);
1413 principal_hton(&principal, &d.dumper);
1414 tapeSet_hton(&dump->tapes, &d.tapes);
1416 d.flags = htonl(dump->flags | BUDB_DUMP_INPROGRESS);
1418 eval = ht_HashIn (ut, &db.dumpName, da, &d); /* Into dump name hash table */
1419 if (eval) ABORT(eval);
1421 eval = ht_HashIn (ut, &db.dumpIden, da, &d); /* Into dumpid hash table */
1422 if (eval) ABORT(eval);
1424 eval = dbwrite (ut, da, (char *)&d, sizeof(d)); /* Write the dump structure */
1425 if (eval) ABORT(eval);
1427 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
1428 if (eval) ABORT(eval);
1430 /* If to append this dump, then append it - will write the appended dump */
1431 eval = makeAppended(ut, dump->id, dump->initialDumpID, dump->tapes.b);
1432 if (eval) ABORT(eval);
1434 code = ubik_EndTrans(ut);
1435 LogDebug(5, "made dump %s, path %s\n", d.dumpName, d.dumpPath);
1439 ubik_AbortTrans(ut);
1443 afs_int32 SBUDB_DeleteDump (call, id, fromTime, toTime, dumps)
1444 struct rx_call *call;
1448 budb_dumpsList *dumps;
1452 code = DoDeleteDump (call, id, fromTime, toTime, dumps);
1453 osi_auditU (call, BUDB_DelDmpEvent, code, AUD_DATE, id, AUD_END);
1459 afs_int32 DoDeleteDump (call, id, fromTime, toTime, dumps)
1460 struct rx_call *call;
1464 budb_dumpsList *dumps;
1468 if ( !callPermitted(call) )
1469 return BUDB_NOTPERMITTED;
1471 if (id) code = deleteDump(call, id, dumps);
1475 afs_int32 SBUDB_ListDumps (call, sflags, name, groupid, fromTime, toTime, dumps, flags)
1476 struct rx_call *call;
1477 afs_int32 sflags, groupid;
1479 Date fromTime, toTime;
1480 budb_dumpsList *dumps, *flags;
1484 code = ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags);
1485 osi_auditU (call, BUDB_LstDmpEvent, code, AUD_LONG, flags, AUD_END);
1489 afs_int32 ListDumps (call, sflags, groupid, fromTime, toTime, dumps, flags)
1490 struct rx_call *call;
1491 afs_int32 sflags, groupid;
1492 Date fromTime, toTime;
1493 budb_dumpsList *dumps, *flags;
1495 struct ubik_trans *ut;
1496 struct memoryHashTable *mht;
1497 struct dump diskDump, appDiskDump;
1498 dbadr dbAddr, dbAppAddr;
1500 afs_int32 eval, code = 0;
1501 int old, hash, length, entrySize, j, k, count=0;
1502 afs_uint32 toList, toFlag;
1504 if ( !callPermitted(call) )
1505 return BUDB_NOTPERMITTED;
1507 eval= InitRPC (&ut, LOCKREAD, 1);
1508 if (eval) return(eval);
1510 /* Search the database */
1511 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
1512 if (!mht) return(BUDB_BADARGUMENT);
1514 for (old=0; old<=1; old++) { /*o*/ /* old and new hash tables */
1515 length = (old ? mht->oldLength : mht->length);
1516 if (length == 0) continue;
1518 for (hash=0; hash<length; hash++) { /*h*/ /* for each hash bucket */
1519 for (dbAddr = ht_LookupBucket(ut,mht,hash,old); dbAddr;
1520 dbAddr = ntohl(diskDump.idHashChain)) { /*d*/
1522 /* read the entry */
1523 eval = dbread (ut, dbAddr, &diskDump, sizeof(diskDump));
1524 if (eval) ABORT(eval);
1526 /* Skip appended dumps */
1527 if (ntohl(diskDump.initialDumpID) != 0) {
1531 /* Skip dumps with different goup id */
1532 if ((sflags & BUDB_OP_GROUPID) && (ntohl(diskDump.tapes.id) != groupid)) {
1536 /* Look at this dump to see if it meets the criteria for listing */
1537 if (sflags & BUDB_OP_DATES) {
1538 /* This and each appended dump should be in time */
1539 for (dbAppAddr=dbAddr; dbAppAddr; dbAppAddr=ntohl(appDiskDump.appendedDumpChain)) {
1540 eval = dbread (ut, dbAppAddr, &appDiskDump, sizeof(appDiskDump));
1541 if (eval) ABORT(eval);
1543 if ((ntohl(appDiskDump.id) < fromTime) || (ntohl(appDiskDump.id) > toTime))
1546 if (dbAppAddr) continue; /*nope*/
1549 /* Add it and each of its appended dump to our list to return */
1550 for (dbAppAddr=dbAddr; dbAppAddr; dbAppAddr=ntohl(appDiskDump.appendedDumpChain)) {
1551 eval = dbread (ut, dbAppAddr, &appDiskDump, sizeof(appDiskDump));
1552 if (eval) ABORT(eval);
1554 /* Make sure we have space to list it */
1555 if (dumps->budb_dumpsList_len >= count) {
1558 dumps->budb_dumpsList_val = (afs_int32 *)malloc(count * sizeof(afs_int32));
1559 flags->budb_dumpsList_val = (afs_int32 *)malloc(count * sizeof(afs_int32));
1561 dumps->budb_dumpsList_val =
1562 (afs_int32 *)realloc(dumps->budb_dumpsList_val, count*sizeof(afs_int32));
1563 flags->budb_dumpsList_val =
1564 (afs_int32 *)realloc(flags->budb_dumpsList_val, count*sizeof(afs_int32));
1566 if (!dumps->budb_dumpsList_val || !dumps->budb_dumpsList_val)
1570 /* Add it to our list */
1571 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = ntohl(appDiskDump.id);
1572 flags->budb_dumpsList_val[flags->budb_dumpsList_len] = 0;
1573 if ( ntohl(appDiskDump.initialDumpID) != 0 ) {
1574 flags->budb_dumpsList_val[flags->budb_dumpsList_len] |= BUDB_OP_APPDUMP;
1576 if (strcmp(appDiskDump.dumpName,DUMP_TAPE_NAME) == 0) {
1577 flags->budb_dumpsList_val[flags->budb_dumpsList_len] |= BUDB_OP_DBDUMP;
1579 dumps->budb_dumpsList_len++;
1580 flags->budb_dumpsList_len++;
1586 code = ubik_EndTrans(ut);
1590 ubik_AbortTrans(ut);
1594 afs_int32 SBUDB_DeleteTape (call, tape)
1595 struct rx_call *call;
1596 struct budb_tapeEntry *tape; /* tape info */
1600 code = DoDeleteTape (call, tape);
1601 osi_auditU (call, BUDB_DelTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
1605 afs_int32 DoDeleteTape (call, tape)
1606 struct rx_call *call;
1607 struct budb_tapeEntry *tape; /* tape info */
1609 struct ubik_trans *ut;
1612 afs_int32 eval, code;
1614 if ( !callPermitted(call) )
1615 return BUDB_NOTPERMITTED;
1617 eval = InitRPC (&ut, LOCKWRITE, 1);
1618 if (eval) return eval;
1620 eval = ht_LookupEntry (ut, &db.tapeName, tape->name, &a, &t);
1621 if (eval) ABORT(eval);
1623 eval = DeleteTape (ut, a, &t);
1624 if (eval) ABORT(eval);
1626 eval = FreeStructure (ut, tape_BLOCK, a);
1627 if (eval) ABORT(eval);
1629 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
1630 if (eval) ABORT(eval);
1632 code = ubik_EndTrans(ut);
1636 ubik_AbortTrans(ut);
1641 * Deletes old information from the database for a particular dump path
1642 * and volumset. This supercedes the old policy implemented in
1643 * UseTape, which simply matched on the volumeset.dump. Consequently
1644 * it was unable to handle name re-use.
1646 * dsname - dumpset name, i.e. volumeset.dumpname
1647 * dumpPath - full path of dump node
1648 * curDumpID - current dump in progress - so that is may be excluded
1651 * n - some error. May or may not have deleted information.
1654 afs_int32 SBUDB_DeleteVDP (call, dsname, dumpPath, curDumpId)
1655 struct rx_call *call;
1658 afs_int32 curDumpId;
1662 code = DeleteVDP (call, dsname, dumpPath, curDumpId);
1663 osi_auditU (call, BUDB_DelVDPEvent, code, AUD_STR, dsname, AUD_END);
1667 afs_int32 DeleteVDP (call, dsname, dumpPath, curDumpId)
1668 struct rx_call *call;
1671 afs_int32 curDumpId;
1676 struct ubik_trans *ut;
1677 afs_int32 eval, code = 0;
1679 if ( !callPermitted(call) )
1680 return BUDB_NOTPERMITTED;
1684 eval = InitRPC (&ut, LOCKREAD, 1);
1685 if (eval) return(eval);
1687 eval = ht_LookupEntry(ut, &db.dumpName, dsname, &dumpAddr, &dump);
1688 if (eval) ABORT(eval);
1690 while ( dumpAddr != 0 )
1692 if ( (strcmp(dump.dumpName, dsname) == 0) &&
1693 (strcmp(dump.dumpPath, dumpPath) == 0) &&
1694 (ntohl(dump.id) != curDumpId) )
1696 eval = ubik_EndTrans(ut);
1697 if (eval) return(eval);
1699 eval = deleteDump(call, ntohl(dump.id), 0);
1700 if (eval) return(eval);
1702 /* start the traversal over since the various chains may
1708 dumpAddr = ntohl(dump.nameHashChain);
1711 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
1712 if (eval) ABORT(eval);
1716 /* check if all the dumps have been examined - can terminate */
1719 eval = ubik_EndTrans(ut);
1725 ubik_AbortTrans(ut);
1731 * Given a volume name, and a dumpID, find the volume in that dump and
1732 * return the clone date of the volume (this is the clone date of the
1733 * volume at the time it was dumped).
1735 * Hashes on the volume name and traverses the fragments. Will need to read
1736 * the volumes tape entry to determine if it belongs to the dump. If the
1737 * volume is not found in the dump, then look for it in its parent dump.
1740 afs_int32 SBUDB_FindClone(call, dumpID, volName, clonetime)
1741 struct rx_call *call;
1744 afs_int32 *clonetime;
1748 code = FindClone (call, dumpID, volName, clonetime);
1749 osi_auditU (call, BUDB_FndClnEvent, code, AUD_STR, volName, AUD_END);
1753 afs_int32 FindClone (call, dumpID, volName, clonetime)
1754 struct rx_call *call;
1757 afs_int32 *clonetime;
1759 struct ubik_trans *ut;
1760 dbadr da, ta, hvia, via, vfa;
1763 struct volFragment vf;
1765 int rvi; /* read the volInfo struct */
1766 afs_int32 eval, code = 0;
1768 if ( !callPermitted(call) )
1769 return BUDB_NOTPERMITTED;
1771 eval = InitRPC (&ut, LOCKREAD, 1);
1772 if (eval) return(eval);
1776 /* Search for the volume by name */
1777 eval = ht_LookupEntry (ut, &db.volName, volName, &hvia, &vi);
1778 if (eval) ABORT(eval);
1779 if (!hvia) ABORT(BUDB_NOVOLUMENAME);
1782 /* Follw the dump levels up */
1783 for (; dumpID; dumpID = ntohl(d.parent))
1785 /* Get the dump entry */
1786 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &da, &d);
1787 if (eval) ABORT(eval);
1788 if (!da) ABORT(BUDB_NODUMPID);
1790 /* seach all the volInfo entries on the sameNameChain */
1791 for (via=hvia; via; via=ntohl(vi.sameNameChain))
1793 if (rvi) /* Read the volInfo entry - except first time */
1795 eval = dbread(ut, via, &vi, sizeof(vi));
1796 if (eval) ABORT(eval);
1800 /* search all the volFrag entries on the volFrag */
1801 for (vfa=ntohl(vi.firstFragment); vfa; vfa=ntohl(vf.sameNameChain))
1803 eval = dbread(ut, vfa, &vf, sizeof(vf)); /* Read the volFrag entry */
1804 if (eval) ABORT(eval);
1806 eval = dbread(ut, ntohl(vf.tape), &t, sizeof(t)); /* Read the tape */
1807 if (eval) ABORT(eval);
1809 /* Now check to see if this fragment belongs to the dump we have */
1810 if (ntohl(t.dump) == da)
1812 *clonetime = ntohl(vf.clone); /* return the clone */
1820 code = ubik_EndTrans(ut);
1830 * Searches each tape and each volume in the dump until the volume is found.
1831 * If the volume is not in the dump, then we search it's parent dump.
1833 * Re-write to do lookups by volume name.
1835 afs_int32 FindClone (call, dumpID, volName, clonetime)
1836 struct rx_call *call;
1839 afs_int32 *clonetime;
1841 struct ubik_trans *ut;
1842 dbadr diskAddr, tapeAddr, volFragmentAddr;
1845 struct volFragment volFragment;
1846 struct volInfo volInfo;
1847 afs_int32 eval, code = 0;
1849 if ( !callPermitted(call) )
1850 return BUDB_NOTPERMITTED;
1852 eval = InitRPC (&ut, LOCKREAD, 1);
1853 if (eval) return(eval);
1857 for (; dumpID; dumpID = ntohl(dump.parent))
1859 /* Get the dump entry */
1860 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &diskAddr, &dump);
1861 if (eval) ABORT(eval);
1862 if (!diskAddr) ABORT(BUDB_NODUMPID);
1864 /* just to be sure */
1865 if (ntohl(dump.id) != dumpID)
1867 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID, ntohl(dump.id));
1868 ABORT(BUDB_INTERNALERROR);
1871 /* search all the tapes in this dump */
1872 for (tapeAddr=ntohl(dump.firstTape); tapeAddr; tapeAddr=ntohl(tape.nextTape))
1874 /* Get the tape entry */
1875 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
1876 if (eval) ABORT(eval);
1878 /* search all the volume fragments on this tape */
1879 for (volFragmentAddr=ntohl(tape.firstVol); volFragmentAddr;
1880 volFragmentAddr=ntohl(volFragment.sameTapeChain))
1882 /* Get the volume fragment entry */
1883 eval = dbread(ut, volFragmentAddr, &volFragment, sizeof(volFragment));
1884 if (eval) ABORT(eval);
1886 /* Get the volume info entry */
1887 eval = dbread(ut, ntohl(volFragment.vol), &volInfo, sizeof(volInfo));
1888 if (eval) ABORT(eval);
1890 /* check if this volume is the one we want */
1891 if ( strcmp(volInfo.name,volName) == 0 )
1893 *clonetime = ntohl(volFragment.clone);
1901 code = ubik_EndTrans(ut);
1911 * Find latest volume dump before adate.
1912 * Used by restore code when restoring a user requested volume(s)
1914 * volumeName - name of volume to match on
1915 * beforeDate - look for dumps older than this date
1917 * deptr - descriptor of most recent dump
1920 afs_int32 SBUDB_FindDump (call, volumeName, beforeDate, deptr)
1921 struct rx_call *call;
1923 afs_int32 beforeDate;
1924 struct budb_dumpEntry *deptr;
1928 code = FindDump (call, volumeName, beforeDate, deptr);
1929 osi_auditU (call, BUDB_FndDmpEvent, code, AUD_STR, volumeName, AUD_END);
1933 afs_int32 FindDump (call, volumeName, beforeDate, deptr)
1934 struct rx_call *call;
1936 afs_int32 beforeDate;
1937 struct budb_dumpEntry *deptr;
1939 struct ubik_trans *ut;
1940 dbadr volInfoAddr, volFragmentAddr;
1942 struct volInfo volInfo;
1943 struct volFragment volFragment;
1945 dbadr selectedDumpAddr = 0;
1946 afs_int32 selectedDate = 0;
1947 afs_int32 volCloned;
1949 afs_int32 eval, code = 0;
1951 if ( !callPermitted(call) )
1952 return BUDB_NOTPERMITTED;
1954 eval = InitRPC (&ut, LOCKREAD, 1);
1955 if (eval) return eval;
1957 /* Find volinfo struct for volume name in hash table */
1958 eval = ht_LookupEntry (ut, &db.volName, volumeName, &volInfoAddr, &volInfo);
1959 if (eval) ABORT(eval);
1960 if (!volInfoAddr) ABORT(BUDB_NOVOLUMENAME);
1962 /* Step through all the volinfo structures on the same name chain.
1963 * No need to read the first - we read it above.
1965 for (rvoli=0; volInfoAddr; rvoli=1, volInfoAddr=ntohl(volInfo.sameNameChain))
1967 if (rvoli) /* read the volinfo structure */
1969 eval = dbread(ut, volInfoAddr, &volInfo, sizeof(volInfo));
1970 if (eval) ABORT(eval);
1973 /* step through the volfrag structures */
1974 for (volFragmentAddr=ntohl(volInfo.firstFragment); volFragmentAddr;
1975 volFragmentAddr=ntohl(volFragment.sameNameChain))
1977 /* read the volfrag struct */
1978 eval = dbread(ut, volFragmentAddr, &volFragment, sizeof(volFragment));
1979 if (eval) ABORT(eval);
1981 volCloned = ntohl(volFragment.clone);
1983 /* now we can examine the date for most recent dump */
1984 if ( (volCloned > selectedDate) && (volCloned < beforeDate) )
1986 /* from the volfrag struct, read the tape struct */
1987 eval = dbread(ut, ntohl(volFragment.tape), &tape, sizeof(tape));
1988 if (eval) ABORT(eval);
1990 selectedDate = volCloned;
1991 selectedDumpAddr = ntohl(tape.dump);
1996 if (!selectedDumpAddr) ABORT(BUDB_NOENT);
1998 eval = FillDumpEntry(ut, selectedDumpAddr, deptr);
1999 if (eval) ABORT(eval);
2001 code = ubik_EndTrans(ut);
2009 /* BUDB_FindLatestDump
2010 * Find the latest dump of volumeset vsname with dump name dname.
2012 * vsname - volumeset name
2016 afs_int32 SBUDB_FindLatestDump (call, vsname, dumpPath, dumpentry)
2017 struct rx_call *call;
2018 char *vsname, *dumpPath;
2019 struct budb_dumpEntry *dumpentry;
2023 code = FindLatestDump (call, vsname, dumpPath, dumpentry);
2024 osi_auditU (call, BUDB_FndLaDEvent, code, AUD_STR, vsname, AUD_END);
2028 afs_int32 FindLatestDump (call, vsname, dumpPath, dumpentry)
2029 struct rx_call *call;
2030 char *vsname, *dumpPath;
2031 struct budb_dumpEntry *dumpentry;
2033 struct ubik_trans *ut;
2034 dbadr curdbaddr, retdbaddr, firstdbaddr;
2037 char dumpName[BU_MAXNAMELEN+2];
2038 afs_int32 eval, code = 0;
2040 if ( !callPermitted(call) )
2041 return BUDB_NOTPERMITTED;
2043 eval = InitRPC(&ut, LOCKREAD, 1);
2044 if (eval) return(eval);
2046 if ( (strcmp(vsname,"") == 0) && (strcmp(dumpPath,"") == 0) )
2048 /* Construct a database dump name */
2049 strcpy(dumpName, DUMP_TAPE_NAME);
2051 else if (strchr(dumpPath,'/') == 0) {
2052 int level, old, length, hash;
2053 struct dump hostDump, diskDump;
2054 struct memoryHashTable *mht;
2057 afs_uint32 bestDumpId=0;
2059 level = atoi(dumpPath);
2061 ABORT(BUDB_BADARGUMENT);
2064 /* Brute force search of all the dumps in the database - yuck! */
2067 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
2068 if (!mht) ABORT(BUDB_BADARGUMENT);
2070 for (old=0; old <= 1; old++) { /*fo*/
2071 length = (old ? mht->oldLength : mht->length);
2072 if (!length) continue;
2074 for (hash=0; hash<length; hash++) {
2076 for (dbAddr = ht_LookupBucket(ut,mht,hash,old); dbAddr;
2077 dbAddr = hostDump.idHashChain) {
2079 eval = dbread (ut, dbAddr, &diskDump, sizeof(diskDump));
2080 if (eval) ABORT(eval);
2081 dump_ntoh(&diskDump, &hostDump);
2083 if ( (strcmp(hostDump.volumeSet,vsname) == 0) && /* the volumeset */
2084 (hostDump.level == level) && /* same level */
2085 (hostDump.id > bestDumpId) ) { /* more recent */
2086 bestDumpId = hostDump.id;
2093 ABORT(BUDB_NODUMPNAME);
2099 /* construct the name of the dump */
2100 if ( (strlen(vsname) + strlen(tailCompPtr(dumpPath))) > BU_MAXNAMELEN )
2101 ABORT(BUDB_NODUMPNAME);
2103 strcpy(dumpName, vsname);
2104 strcat(dumpName, ".");
2105 strcat(dumpName, tailCompPtr(dumpPath));
2108 LogDebug(5, "lookup on :%s:\n", dumpName);
2110 /* Lookup on dumpname in hash table */
2111 eval = ht_LookupEntry(ut, &db.dumpName, dumpName, &firstdbaddr, &d);
2112 if (eval) ABORT(eval);
2117 /* folow remaining dumps in hash chain, looking for most latest dump */
2118 for (curdbaddr=firstdbaddr; curdbaddr; curdbaddr=ntohl(d.nameHashChain))
2120 if (curdbaddr != firstdbaddr) {
2121 eval = dbread(ut, curdbaddr, &d, sizeof(d));
2122 if (eval) ABORT(eval);
2125 if ( (strcmp(d.dumpPath, dumpPath) == 0) && /* Same dumppath */
2126 (strcmp(d.dumpName, dumpName) == 0) && /* Same dumpname */
2127 (ntohl(d.created) > latest) ) /* most recent */
2129 latest = ntohl(d.created);
2130 retdbaddr = curdbaddr;
2133 if (!retdbaddr) ABORT(BUDB_NODUMPNAME);
2136 /* return the dump found */
2137 FillDumpEntry(ut, retdbaddr, dumpentry);
2139 code = ubik_EndTrans(ut);
2143 ubik_AbortTrans(ut);
2148 afs_int32 SBUDB_FinishDump (call, dump)
2149 struct rx_call *call;
2150 struct budb_dumpEntry *dump;
2154 code = FinishDump (call, dump);
2155 osi_auditU (call, BUDB_FinDmpEvent, code, AUD_DATE, (dump ? dump->id : 0), AUD_END);
2159 afs_int32 FinishDump (call, dump)
2160 struct rx_call *call;
2161 struct budb_dumpEntry *dump;
2163 struct ubik_trans *ut;
2166 afs_int32 eval, code = 0;
2168 if ( !callPermitted(call) )
2169 return BUDB_NOTPERMITTED;
2171 eval = InitRPC(&ut, LOCKWRITE, 1);
2172 if (eval) return eval;
2174 eval = ht_LookupEntry (ut, &db.dumpIden, &dump->id, &a, &d);
2175 if (eval) ABORT(eval);
2176 if (!a) ABORT(BUDB_NODUMPID);
2178 if ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)
2179 ABORT(BUDB_DUMPNOTINUSE);
2181 d.flags = htonl(dump->flags & ~BUDB_DUMP_INPROGRESS);
2183 /* if creation time specified set it */
2184 if (dump->created) d.created = htonl(dump->created);
2185 dump->created = ntohl(d.created);
2187 /* Write the dump entry out */
2188 eval = dbwrite(ut, a, &d, sizeof(d));
2189 if (eval) ABORT(eval);
2191 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2192 if (eval) ABORT(eval);
2194 code = ubik_EndTrans(ut);
2198 ubik_AbortTrans(ut);
2202 afs_int32 SBUDB_FinishTape (call, tape)
2203 struct rx_call *call;
2204 struct budb_tapeEntry *tape;
2208 code = FinishTape (call, tape);
2209 osi_auditU (call, BUDB_FinTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
2213 afs_int32 FinishTape (call, tape)
2214 struct rx_call *call;
2215 struct budb_tapeEntry *tape;
2217 struct ubik_trans *ut;
2221 afs_int32 eval, code = 0;
2223 if ( !callPermitted(call) )
2224 return BUDB_NOTPERMITTED;
2226 eval = InitRPC (&ut, LOCKWRITE, 1);
2227 if (eval) return eval;
2229 /* find the tape struct in the tapename hash chain */
2230 eval = ht_LookupEntry (ut, &db.tapeName, tape->name, &a, &t);
2231 if (eval) ABORT(eval);
2232 if (!a) ABORT(BUDB_NOTAPENAME);
2234 /* Read the dump structure */
2235 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2236 if (eval) ABORT(eval);
2238 /* search for the right tape on the rest of the chain */
2239 while (ntohl(d.id) != tape->dump)
2241 a = ntohl(t.nameHashChain);
2242 if (!a) ABORT(BUDB_NOTAPENAME);
2244 eval = dbread(ut, a, &t, sizeof(t));
2245 if (eval) ABORT(eval);
2247 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2248 if (eval) ABORT(eval);
2251 if ( (ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0 )
2252 ABORT(BUDB_TAPENOTINUSE);
2254 /* t.nBytes = htonl(tape->nBytes); */
2255 t.nFiles = htonl(tape->nFiles);
2256 t.useKBytes = htonl(tape->useKBytes);
2257 t.flags = htonl(tape->flags & ~BUDB_TAPE_BEINGWRITTEN);
2259 eval = dbwrite(ut, a, &t, sizeof(t));
2260 if (eval) ABORT(BUDB_IO);
2262 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
2263 if (eval) ABORT(eval);
2265 code = ubik_EndTrans(ut);
2269 ubik_AbortTrans(ut);
2274 * return a set of dumps that match the specified criteria
2277 * majorVersion - version of interface structures. Permits compatibility
2279 * flags - for search and select operations. Broken down into flags
2280 * for name, start point, end point and time.
2281 * name - name to search for. Interpretation based on flags
2288 * dbTimeP - time at which the database was last modified. Up to
2289 * caller (client) to take appropriate action if database
2290 * modified between successive calls
2291 * dumps - list of matching dumps
2293 * currently supported are:
2298 afs_int32 SBUDB_GetDumps (call, majorVersion, flags, name, start, end,
2299 index, nextIndexP, dbTimeP, dumps)
2300 struct rx_call *call;
2301 afs_int32 majorVersion; /* version of interface structures */
2302 afs_int32 flags; /* search & select controls */
2303 char *name; /* s&s parameters */
2306 afs_int32 index; /* start index of returned entries */
2307 afs_int32 *nextIndexP; /* output index for next call */
2309 budb_dumpList *dumps; /* pointer to buffer */
2313 code = GetDumps (call, majorVersion, flags, name, start, end,
2314 index, nextIndexP, dbTimeP, dumps);
2315 osi_auditU (call, BUDB_GetDmpEvent, code, AUD_END);
2319 afs_int32 GetDumps (call, majorVersion, flags, name, start, end,
2320 index, nextIndexP, dbTimeP, dumps)
2321 struct rx_call *call;
2322 afs_int32 majorVersion; /* version of interface structures */
2323 afs_int32 flags; /* search & select controls */
2324 char *name; /* s&s parameters */
2327 afs_int32 index; /* start index of returned entries */
2328 afs_int32 *nextIndexP; /* output index for next call */
2330 budb_dumpList *dumps; /* pointer to buffer */
2332 struct ubik_trans *ut;
2335 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2336 afs_int32 eval, code = 0;
2338 struct returnList list;
2340 /* Don't check permissions when we look up a specific dump id */
2341 if ( ((flags & BUDB_OP_STARTS) != BUDB_OP_DUMPID) && !callPermitted(call) )
2342 return BUDB_NOTPERMITTED;
2344 if (majorVersion != BUDB_MAJORVERSION) return BUDB_OLDINTERFACE;
2345 if (index < 0) return BUDB_ENDOFLIST;
2347 eval = InitRPC (&ut, LOCKREAD, 1);
2348 if (eval) return eval;
2350 nameFlags = flags & BUDB_OP_NAMES;
2351 startFlags = flags & BUDB_OP_STARTS;
2352 endFlags = flags & BUDB_OP_ENDS;
2353 timeFlags = flags & BUDB_OP_TIMES;
2355 InitReturnList (&list);
2358 if (nameFlags == BUDB_OP_DUMPNAME)
2360 /* not yet implemented */
2361 if (startFlags || endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
2363 eval = ht_LookupEntry (ut, &db.dumpName, name, &da, &d);
2364 if (eval) ABORT(eval);
2365 if (!da) ABORT(BUDB_NODUMPNAME);
2369 if (strcmp (d.dumpName, name) == 0)
2371 eval = AddToReturnList (&list, da, &toskip);
2372 if (eval == BUDB_LIST2BIG) break;
2373 if (eval) ABORT(eval);
2376 da = ntohl(d.nameHashChain); /* get next dump w/ name */
2379 eval = dbread (ut, da, &d, sizeof(d));
2380 if (eval) ABORT(eval);
2384 if ( nameFlags == BUDB_OP_VOLUMENAME )
2389 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2390 ABORT(BUDB_BADFLAGS);
2393 if (startFlags != BUDB_OP_STARTTIME) ABORT(BUDB_BADFLAGS);
2395 /* lookup a dump by volumename and time stamp. Find the most recent
2396 * dump of the specified volumename, that occured before the supplied
2400 /* get us a volInfo for name */
2401 eval = ht_LookupEntry(ut, &db.volName, name, &da, &vi);
2402 if (eval) ABORT(eval);
2406 /* now iterate over all the entries of this name */
2407 for ( va = vi.firstFragment; va != 0; va = v.sameNameChain )
2410 eval = dbread(ut, va, &v, sizeof(v));
2411 if (eval) ABORT(eval);
2413 if date on fragment > date
2414 ignore it - too recent;
2416 if ( date on fragment < date && date on fragment > bestfound )
2417 bestfound = date on fragment;
2421 da = vi.sameNameChain;
2425 eval = dbread(ut, da, &vi, sizeof(vi));
2426 if (eval) ABORT(eval);
2433 from saved volfragment address, compute dump.
2434 otherwise, return dump found
2440 else if (startFlags == BUDB_OP_DUMPID)
2442 if (endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
2443 if (nameFlags) ABORT(BUDB_BADFLAGS); /* NYI */
2445 eval = ht_LookupEntry (ut, &db.dumpIden, &start, &da, &d);
2446 if (eval) ABORT(eval);
2447 if (!da) ABORT(BUDB_NODUMPID);
2449 eval = AddToReturnList (&list, da, &toskip);
2450 if (eval) ABORT(eval);
2452 else if (endFlags == BUDB_OP_NPREVIOUS)
2454 struct wantDumpRock rock;
2455 struct chosenDump *ptr, *nextPtr;
2457 extern wantDump(), rememberDump();
2459 /* no other flags should be set */
2461 /* end specifies how many dumps */
2462 if (!end) ABORT(BUDB_BADFLAGS);
2464 memset(&rock, 0, sizeof(rock));
2465 rock.maxDumps = end;
2467 scanHashTable(ut, &db.dumpName, wantDump, rememberDump, (char *) &rock);
2469 for (ptr=rock.chain; ptr; ptr=nextPtr)
2471 nextPtr = ptr->next;
2472 AddToReturnList (&list, ptr->addr, &toskip); /* ignore error for free */
2478 ABORT(BUDB_BADFLAGS);
2481 eval = SendReturnList (ut, &list, FillDumpEntry, sizeof(struct budb_dumpEntry),
2482 index, nextIndexP, dbTimeP, (returnList_t)dumps);
2483 if (eval) ABORT(eval);
2486 FreeReturnList(&list);
2487 code = ubik_EndTrans(ut);
2491 FreeReturnList(&list);
2492 ubik_AbortTrans(ut);
2497 * Get the expiration of a tape. Since the dump could have appended dumps,
2498 * we should use the most recent expiration date. Put the most recent
2499 * expiration tape into the given tape structure.
2501 afs_int32 getExpiration (ut, tapePtr)
2502 struct ubik_trans *ut;
2503 struct tape *tapePtr;
2509 afs_int32 eval, code = 0;
2511 if (!tapePtr) ERROR(0);
2513 /* Get the dump for this tape */
2514 ad = ntohl(tapePtr->dump);
2515 eval = dbread(ut,ad,&d,sizeof(d));
2516 if (eval) ERROR(eval);
2518 /* If not an initial dump, get the initial dump */
2519 if (d.initialDumpID)
2521 initDump = ntohl(d.initialDumpID);
2522 eval = ht_LookupEntry (ut, &db.dumpIden, &initDump, &ad, &d);
2523 if (eval) ERROR(eval);
2526 /* Cycle through the dumps and appended dumps */
2529 /* Get the first tape in this dump. No need to check the rest of the tapes */
2530 /* for this dump since they will all have the same expiration date */
2531 eval = dbread (ut, ntohl(d.firstTape), &t, sizeof(t));
2532 if (eval) ERROR(eval);
2534 /* Take the greater of the expiration dates */
2535 if ( ntohl(tapePtr->expires) < ntohl(t.expires) )
2536 tapePtr->expires = t.expires;
2538 /* Step to and read the next appended dump */
2539 if ( ad = ntohl(d.appendedDumpChain) )
2541 eval = dbread(ut,ad,&d,sizeof(d));
2542 if (eval) ERROR(eval);
2550 /* Mark the following dump as appended to another, intial dump */
2551 afs_int32 makeAppended (ut, appendedDumpID, initialDumpID, startTapeSeq)
2552 struct ubik_trans *ut;
2553 afs_int32 appendedDumpID;
2554 afs_int32 initialDumpID;
2555 afs_int32 startTapeSeq;
2557 dbadr ada, da, lastDumpAddr;
2559 afs_int32 eval, code = 0;
2563 if (appendedDumpID == initialDumpID)
2564 ERROR(BUDB_INTERNALERROR);
2566 /* If there is an initial dump, append this dump to it */
2567 /* Find the appended dump via its id */
2568 eval = ht_LookupEntry(ut,&db.dumpIden,&appendedDumpID,&ada,&ad);
2569 if (eval) ERROR(eval);
2571 /* If the dump is already marked as appended,
2572 * then we have an internal error.
2574 if (ad.initialDumpID) {
2575 if (ntohl(ad.initialDumpID) != initialDumpID)
2576 ERROR(BUDB_INTERNALERROR);
2579 /* Update the appended dump to point to the initial dump */
2580 ad.initialDumpID = htonl(initialDumpID);
2581 ad.tapes.b = htonl(startTapeSeq);
2583 /* find the initial dump via its id */
2584 eval = ht_LookupEntry(ut,&db.dumpIden,&initialDumpID,&da,&d);
2585 if (eval) ERROR(eval);
2587 /* Update the appended dump's tape format with that of the initial */
2588 strcpy(ad.tapes.format, d.tapes.format);
2590 /* starting with the initial dump step through its appended dumps till
2591 * we reach the last appended dump.
2594 while (d.appendedDumpChain) {
2595 lastDumpAddr = ntohl(d.appendedDumpChain);
2596 if (lastDumpAddr == ada) ERROR(0); /* Already appended */
2597 eval = dbread(ut, lastDumpAddr, &d, sizeof(d));
2598 if (eval) ERROR(eval);
2601 /* Update the last dump to point to our new appended dump.
2602 * The appended dump is the last one in the dump chain.
2604 d.appendedDumpChain = htonl(ada);
2605 ad.appendedDumpChain = 0;
2607 /* Write the appended dump and the initial dump */
2608 eval = dbwrite(ut,ada,(char *)&ad,sizeof(ad));
2609 if (eval) ERROR(eval);
2611 eval = dbwrite (ut, lastDumpAddr, (char *)&d, sizeof(d));
2612 if (eval) ERROR(eval);
2614 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
2615 if (eval) ERROR(eval);
2621 afs_int32 SBUDB_MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq)
2622 struct rx_call *call;
2623 afs_int32 appendedDumpID;
2624 afs_int32 initialDumpID;
2625 afs_int32 startTapeSeq;
2629 code = MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq);
2630 osi_auditU (call, BUDB_AppDmpEvent, code, AUD_LONG, appendedDumpID, AUD_END);
2634 afs_int32 MakeDumpAppended (call, appendedDumpID, initialDumpID, startTapeSeq)
2635 struct rx_call *call;
2636 afs_int32 appendedDumpID;
2637 afs_int32 initialDumpID;
2638 afs_int32 startTapeSeq;
2640 struct ubik_trans *ut;
2641 afs_int32 eval, code = 0;
2643 if ( !callPermitted(call) )
2644 return BUDB_NOTPERMITTED;
2646 eval = InitRPC (&ut, LOCKWRITE, 1);
2647 if (eval) return(eval);
2649 eval = makeAppended(ut,appendedDumpID,initialDumpID,startTapeSeq);
2650 if (eval) ABORT(eval);
2652 code = ubik_EndTrans(ut);
2656 ubik_AbortTrans(ut);
2660 /* Find the last tape of a dump-set. This includes any appended dumps */
2661 afs_int32 SBUDB_FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry)
2662 struct rx_call *call;
2664 struct budb_dumpEntry *dumpEntry;
2665 struct budb_tapeEntry *tapeEntry;
2666 struct budb_volumeEntry *volEntry;
2670 code = FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry);
2671 osi_auditU (call, BUDB_FndLTpeEvent, code, AUD_LONG, dumpID, AUD_END);
2675 afs_int32 FindLastTape (call, dumpID, dumpEntry, tapeEntry, volEntry)
2676 struct rx_call *call;
2678 struct budb_dumpEntry *dumpEntry;
2679 struct budb_tapeEntry *tapeEntry;
2680 struct budb_volumeEntry *volEntry;
2682 struct ubik_trans *ut;
2686 dbadr lastTape, thisTape;
2687 afs_int32 lastTapeSeq;
2688 struct volFragment vf;
2689 dbadr lastVol, thisVol;
2690 afs_int32 lastVolPos;
2691 afs_int32 eval, code = 0;
2693 if ( !callPermitted(call) )
2694 return BUDB_NOTPERMITTED;
2696 if (!dumpID) return(BUDB_BADARGUMENT);
2698 eval = InitRPC (&ut, LOCKREAD, 1);
2699 if (eval) return(eval);
2701 /* find and read its initial dump via its id */
2702 eval = ht_LookupEntry (ut, &db.dumpIden, &dumpID, &lastDump, &d);
2703 if (eval) ABORT(eval);
2704 if (!lastDump) ABORT(BUDB_NODUMPID);
2706 /* Follow the append dumps link chain until we reach the last dump */
2707 while (d.appendedDumpChain)
2709 lastDump = ntohl(d.appendedDumpChain);
2710 eval = dbread(ut,lastDump,&d,sizeof(d));
2711 if (eval) ABORT(eval);
2714 /* We now have the last dump of the last appended dump */
2715 /* Copy this into our return structure */
2716 eval = FillDumpEntry(ut,lastDump,dumpEntry);
2717 if (eval) ABORT(eval);
2719 /* Fail if the last dump has no tapes */
2720 if (!d.firstTape) ABORT(BUDB_NOTAPENAME);
2722 /* Follow the tapes in this dump until we reach the last tape */
2723 eval = dbread (ut, ntohl(d.firstTape), &t, sizeof(t));
2724 if (eval) ABORT(eval);
2726 lastTape = ntohl(d.firstTape);
2727 lastTapeSeq = ntohl(t.seq);
2728 lastVol = ntohl(t.firstVol);
2732 thisTape = ntohl(t.nextTape);
2733 eval = dbread(ut,thisTape,&t,sizeof(t));
2734 if (eval) ABORT(eval);
2736 if (ntohl(t.seq) > lastTapeSeq)
2738 lastTape = thisTape;
2739 lastTapeSeq = ntohl(t.seq);
2740 lastVol = ntohl(t.firstVol);
2744 /* We now have the last tape of the last appended dump */
2745 /* Copy this into our return structure */
2746 eval = FillTapeEntry(ut,lastTape,tapeEntry);
2747 if (eval) ABORT(eval);
2749 /* Zero volume entry if the last tape has no volumes */
2751 memset(volEntry, 0, sizeof(*volEntry));
2753 /* Follow the volumes until we reach the last volume */
2754 eval = dbread (ut,lastVol,&vf,sizeof(vf));
2755 if (eval) ABORT(eval);
2757 lastVolPos = vf.position;
2759 while (vf.sameTapeChain) {
2760 thisVol = ntohl(vf.sameTapeChain);
2761 eval = dbread(ut,thisVol,&vf,sizeof(vf));
2762 if (eval) ABORT(eval);
2764 if (vf.position > lastVolPos) {
2766 lastVolPos = vf.position;
2770 /* We now have the last volume of this tape */
2771 /* Copy this into our return structure */
2772 eval = FillVolEntry(ut,lastVol,volEntry);
2773 if (eval) ABORT(eval);
2776 eval = ubik_EndTrans(ut);
2777 if (!code) code = eval;
2781 ubik_AbortTrans(ut);
2786 afs_int32 SBUDB_GetTapes (call, majorVersion, flags, name, start, end, index, nextIndexP,
2788 struct rx_call *call;
2789 afs_int32 majorVersion; /* version of interface structures */
2790 afs_int32 flags; /* search & select controls */
2791 char *name; /* s&s parameters */
2793 afs_int32 end; /* reserved: MBZ */
2794 afs_int32 index; /* start index of returned entries */
2795 afs_int32 *nextIndexP; /* output index for next call */
2797 budb_tapeList *tapes; /* pointer to buffer */
2801 code = GetTapes (call, majorVersion, flags, name, start, end,
2802 index, nextIndexP, dbTimeP, tapes);
2803 osi_auditU (call, BUDB_GetTpeEvent, code, AUD_END);
2807 afs_int32 GetTapes (call, majorVersion, flags, name, start, end,
2808 index, nextIndexP, dbTimeP, tapes)
2809 struct rx_call *call;
2810 afs_int32 majorVersion; /* version of interface structures */
2811 afs_int32 flags; /* search & select controls */
2812 char *name; /* s&s parameters */
2814 afs_int32 end; /* reserved: MBZ */
2815 afs_int32 index; /* start index of returned entries */
2816 afs_int32 *nextIndexP; /* output index for next call */
2818 budb_tapeList *tapes; /* pointer to buffer */
2820 struct ubik_trans *ut;
2824 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2825 struct returnList list;
2826 afs_int32 eval, code = 0;
2829 if ( !callPermitted(call) )
2830 return BUDB_NOTPERMITTED;
2832 if (majorVersion != BUDB_MAJORVERSION)
2833 return BUDB_OLDINTERFACE;
2835 if (index < 0) return BUDB_ENDOFLIST;
2837 eval = InitRPC (&ut, LOCKREAD, 1);
2838 if (eval) return eval;
2840 nameFlags = flags & BUDB_OP_NAMES;
2841 startFlags = flags & BUDB_OP_STARTS;
2842 endFlags = flags & BUDB_OP_ENDS;
2843 timeFlags = flags & BUDB_OP_TIMES;
2845 InitReturnList (&list);
2848 if (nameFlags == BUDB_OP_TAPENAME)
2850 eval = ht_LookupEntry (ut, &db.tapeName, name, &ta, &t);
2851 if (eval) ABORT(eval);
2852 if (!ta) ABORT(BUDB_NOTAPENAME);
2855 if ( (startFlags & ~BUDB_OP_DUMPID) || endFlags || timeFlags ) ABORT(BUDB_BADFLAGS);
2857 /* follow the hash chain to the end */
2860 if (startFlags & BUDB_OP_DUMPID)
2862 /* read in the dump */
2863 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2864 if (eval) ABORT(eval);
2866 /* check if both name and dump id match */
2867 if ( (strcmp(name, t.name) == 0) && (ntohl(d.id) == start) )
2869 eval = AddToReturnList (&list, ta, &toskip);
2870 if (eval && (eval != BUDB_LIST2BIG)) ABORT(eval);
2876 /* Add to return list and continue search */
2877 if ( strcmp(name, t.name) == 0 )
2879 eval = AddToReturnList (&list, ta, &toskip);
2880 if (eval == BUDB_LIST2BIG) break;
2881 if (eval) ABORT(eval);
2885 ta = ntohl(t.nameHashChain);
2886 if (ta) dbread(ut, ta, &t, sizeof(t));
2889 else if (nameFlags == BUDB_OP_TAPESEQ)
2891 eval = ht_LookupEntry(ut,&db.dumpIden, &start, &da, &d);
2892 if (eval) ABORT(eval);
2893 if (!da) ABORT(BUDB_NODUMPNAME);
2895 /* search for the right tape */
2896 ta = ntohl(d.firstTape);
2897 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape))
2899 eval = dbread(ut, ta, &t, sizeof(t));
2900 if (eval) ABORT(eval);
2902 if (ntohl(t.seq) == end)
2904 eval = AddToReturnList (&list, ta, &toskip);
2905 if (eval && (eval != BUDB_LIST2BIG)) ABORT(eval);
2912 ABORT (BUDB_BADFLAGS);
2915 eval = SendReturnList (ut, &list, FillTapeEntry,
2916 sizeof(struct budb_tapeEntry),
2917 index, nextIndexP, dbTimeP, (returnList_t)tapes);
2918 if (eval) ABORT(eval);
2920 FreeReturnList(&list);
2921 code = ubik_EndTrans(ut);
2925 FreeReturnList(&list);
2926 ubik_AbortTrans(ut);
2931 * get a set of volumes according to the specified criteria.
2932 * See BUDB_GetDumps for general information on parameters
2933 * Currently supports:
2934 * 1) volume match - returns volumes based on volume name only.
2935 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
2936 * and start is a dumpid. Returns all volumes of the specified
2937 * name on the selected dumpid.
2940 afs_int32 SBUDB_GetVolumes (call, majorVersion, flags, name, start, end,
2941 index, nextIndexP, dbTimeP, volumes)
2942 struct rx_call *call;
2943 afs_int32 majorVersion; /* version of interface structures */
2944 afs_int32 flags; /* search & select controls */
2945 char *name; /* - parameters for search */
2946 afs_int32 start; /* - usage depends which BUDP_OP_* */
2947 afs_int32 end; /* - bits are set */
2948 afs_int32 index; /* start index of returned entries */
2949 afs_int32 *nextIndexP; /* output index for next call */
2951 budb_volumeList *volumes; /* pointer to buffer */
2955 code = GetVolumes (call, majorVersion, flags, name, start, end,
2956 index, nextIndexP, dbTimeP, volumes);
2957 osi_auditU (call, BUDB_GetVolEvent, code, AUD_END);
2961 afs_int32 GetVolumes (call, majorVersion, flags, name, start, end,
2962 index, nextIndexP, dbTimeP, volumes)
2963 struct rx_call *call;
2964 afs_int32 majorVersion; /* version of interface structures */
2965 afs_int32 flags; /* search & select controls */
2966 char *name; /* - parameters for search */
2967 afs_int32 start; /* - usage depends which BUDP_OP_* */
2968 afs_int32 end; /* - bits are set */
2969 afs_int32 index; /* start index of returned entries */
2970 afs_int32 *nextIndexP; /* output index for next call */
2972 budb_volumeList *volumes; /* pointer to buffer */
2974 struct ubik_trans *ut;
2977 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2978 afs_int32 eval, code = 0;
2979 struct returnList vollist;
2982 /* Don't check permissions when we look up a specific volume name */
2983 if ( ((flags & BUDB_OP_NAMES) != BUDB_OP_VOLUMENAME) && !callPermitted(call) )
2984 return BUDB_NOTPERMITTED;
2986 if (majorVersion != BUDB_MAJORVERSION) return BUDB_OLDINTERFACE;
2987 if (index < 0) return BUDB_ENDOFLIST;
2989 eval = InitRPC (&ut, LOCKREAD, 1);
2990 if (eval) return eval;
2992 nameFlags = flags & BUDB_OP_NAMES;
2993 startFlags = flags & BUDB_OP_STARTS;
2994 endFlags = flags & BUDB_OP_ENDS;
2995 timeFlags = flags & BUDB_OP_TIMES;
2997 InitReturnList (&vollist);
3000 /* lookup a the volume (specified by name) in the dump (specified by id) */
3001 if (nameFlags == BUDB_OP_VOLUMENAME)
3003 /* dumpid permissible, all others off */
3004 if ( ((startFlags & ~BUDB_OP_DUMPID) != 0) || endFlags || timeFlags )
3005 ABORT(BUDB_BADFLAGS);
3007 /* returns ptr to volinfo of requested name */
3008 eval = ht_LookupEntry (ut, &db.volName, name, &via, &vi);
3009 if (eval) ABORT(eval);
3010 if (!via) ABORT(BUDB_NOVOLUMENAME);
3012 /* Iterate over all volume fragments with this name */
3015 struct volFragment v;
3018 /* traverse all the volume fragments for this volume info structure */
3019 for (va=vi.firstFragment; va; va=v.sameNameChain)
3022 eval = dbread (ut, va, &v, sizeof(v));
3023 if (eval) ABORT(eval);
3025 if ( startFlags & BUDB_OP_DUMPID )
3030 /* get the dump id for this fragment */
3031 eval = dbread(ut, ntohl(v.tape), &atape, sizeof(atape));
3032 if (eval) ABORT(eval);
3034 eval = dbread(ut, ntohl(atape.dump), &adump, sizeof(adump));
3035 if (eval) ABORT(BUDB_IO);
3037 /* dump id does not match */
3038 if ( ntohl(adump.id) != start )
3042 eval = AddToReturnList (&vollist, va, &toskip);
3043 if (eval == BUDB_LIST2BIG) break;
3044 if (eval) ABORT(eval);
3046 if (eval == BUDB_LIST2BIG) break;
3048 via = vi.sameNameChain;
3049 if (via == 0) break;
3052 eval = dbread (ut, via, &vi, sizeof(vi));
3053 if (eval) ABORT(eval);
3056 else if ( ((nameFlags == 0) || (nameFlags == BUDB_OP_TAPENAME)) &&
3057 (startFlags == BUDB_OP_DUMPID) )
3063 struct volFragment volFrag;
3066 /* lookup all volumes for a specified dump id */
3068 /* no other flags should be set */
3069 if (endFlags || timeFlags) ABORT(BUDB_BADFLAGS);
3072 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &dumpAddr, &dump);
3073 if (eval) ABORT(eval);
3075 /* traverse all the tapes */
3076 for (tapeAddr=ntohl(dump.firstTape); tapeAddr; tapeAddr=ntohl(tape.nextTape))
3078 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
3079 if (eval) ABORT(eval);
3081 if ( ( nameFlags != BUDB_OP_TAPENAME ) ||
3082 ((nameFlags == BUDB_OP_TAPENAME) && (strcmp(tape.name,name) == 0)) )
3084 /* now return all the volumes */
3085 for (volFragAddr=ntohl(tape.firstVol); volFragAddr;
3086 volFragAddr=ntohl(volFrag.sameTapeChain))
3088 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
3089 if (eval) ABORT(eval);
3091 eval = AddToReturnList(&vollist, volFragAddr, &toskip);
3092 if (eval == BUDB_LIST2BIG) break;
3093 if (eval) ABORT(eval);
3096 if (eval == BUDB_LIST2BIG) break;
3101 ABORT(BUDB_BADFLAGS);
3104 eval = SendReturnList(ut, &vollist, FillVolEntry, sizeof(struct budb_volumeEntry),
3105 index, nextIndexP, dbTimeP, (returnList_t)volumes);
3106 if (eval) ABORT(eval);
3109 FreeReturnList(&vollist);
3110 code = ubik_EndTrans(ut);
3114 FreeReturnList(&vollist);
3115 ubik_AbortTrans(ut);
3119 afs_int32 SBUDB_UseTape (call, tape, new)
3120 struct rx_call *call;
3121 struct budb_tapeEntry *tape; /* tape info */
3122 afs_int32 *new; /* set if tape is new */
3126 code = UseTape (call, tape, new);
3127 osi_auditU (call, BUDB_UseTpeEvent, code, AUD_DATE, (tape ? tape->dump : 0), AUD_END);
3131 afs_int32 UseTape (call, tape, new)
3132 struct rx_call *call;
3133 struct budb_tapeEntry *tape; /* tape info */
3134 int *new; /* set if tape is new */
3136 struct ubik_trans *ut;
3140 afs_int32 eval, code;
3142 if ( !callPermitted(call) )
3143 return BUDB_NOTPERMITTED;
3145 if (strlen (tape->name) >= sizeof(t.name)) return BUDB_BADARGUMENT;
3147 eval = InitRPC (&ut, LOCKWRITE, 1);
3148 if (eval) return eval;
3152 memset(&t, 0, sizeof(t));
3153 eval = AllocStructure (ut, tape_BLOCK, 0, &a, &t);
3154 if (eval) ABORT(eval);
3156 strcpy (t.name, tape->name);
3158 eval = ht_HashIn (ut, &db.tapeName, a, &t);
3159 if (eval) ABORT(eval);
3163 /* Since deleting a tape may change the dump (if its the same one), read in
3164 the dump after the call to DeleteTape. */
3166 eval = ht_LookupEntry (ut, &db.dumpIden, &tape->dump, &da, &d);
3167 if (eval) ABORT(eval);
3168 if (!da) ABORT(BUDB_NODUMPID);
3170 if (!tape->written) tape->written = time(0); /* fill in tape struct */
3171 t.written = htonl(tape->written);
3172 t.expires = htonl(tape->expires);
3174 t.seq = htonl(tape->seq);
3175 t.useCount = htonl(tape->useCount);
3176 t.labelpos = htonl(tape->labelpos);
3178 t.flags = htonl(tape->flags | BUDB_TAPE_BEINGWRITTEN);
3180 t.nextTape = d.firstTape; /* Chain the tape to the dump */
3181 d.firstTape = htonl(a);
3183 if (tape->seq >= ntohl(d.tapes.maxTapes)) /* inc # tapes in the dump */
3184 d.tapes.maxTapes = htonl(tape->seq);
3186 eval = dbwrite (ut, a, &t, sizeof(t)); /* write tape struct */
3187 if (eval) ABORT(eval);
3189 eval = dbwrite (ut, da, &d, sizeof(d)); /* write the dump struct */
3190 if (eval) ABORT(eval);
3192 eval = set_header_word (ut, lastUpdate, htonl(time(0)));
3193 if (eval) ABORT(eval);
3195 LogDebug(5, "added tape %s\n", tape->name);
3197 code = ubik_EndTrans(ut);
3201 ubik_AbortTrans(ut);
3207 /* ---------------------------------------------
3208 * debug interface routines
3209 * ---------------------------------------------
3212 afs_int32 SBUDB_T_DumpHashTable (call, type, filename)
3213 struct rx_call *call;
3219 code = T_DumpHashTable (call, type, filename);
3220 osi_auditU (call, BUDB_TDmpHaEvent, code, AUD_STR, filename, AUD_END);
3224 afs_int32 T_DumpHashTable (call, type, filename)
3225 struct rx_call *call;
3229 struct ubik_trans *ut;
3230 struct memoryHashTable *mht;
3232 afs_int32 eval, code = 0;
3239 char e[sizeof(struct block)]; /* unnecessarily conservative */
3243 if ( !callPermitted(call) )
3244 return BUDB_NOTPERMITTED;
3246 if (strlen (filename) >= sizeof(path)-5) return BUDB_BADARGUMENT;
3248 eval = InitRPC (&ut, LOCKWRITE, 1);
3249 if (eval) return eval;
3251 if ((mht = ht_GetType (type, &e_size)) == 0) return BUDB_BADARGUMENT;
3253 sprintf(path, "%s/%s", gettmpdir(), filename);
3255 DUMP = fopen (path, "w");
3256 if (!DUMP) ABORT(BUDB_BADARGUMENT);
3259 for (old=0; ; old++)
3261 length = (old ? mht->oldLength : mht->length);
3262 if (length) fprintf (DUMP, "Dumping %sHash Table:\n", (old?"Old ":""));
3264 for (hash=0; hash<length; hash++)
3266 a = ht_LookupBucket (ut, mht, hash, old);
3270 eval = dbread (ut, a, e, e_size);
3271 if (eval) ABORT(eval);
3274 if (a == first_a) fprintf (DUMP, " in bucket %d at %d is ", hash, a);
3275 else fprintf (DUMP, " at %d is ", a);
3277 case HT_dumpIden_FUNCTION:
3278 fprintf (DUMP, "%d\n", ntohl(((struct dump *)e)->id));
3280 case HT_dumpName_FUNCTION:
3281 fprintf (DUMP, "%s\n", ((struct dump *)e)->dumpName);
3283 case HT_tapeName_FUNCTION:
3284 fprintf (DUMP, "%s\n", ((struct tape *)e)->name);
3286 case HT_volName_FUNCTION:
3287 fprintf (DUMP, "%s\n", ((struct volInfo *)e)->name);
3290 if ((ht_HashEntry(mht,e) % length) != hash) ABORT(BUDB_DATABASEINCONSISTENT);
3291 a = ntohl(*(dbadr *)(e + mht->threadOffset));
3297 fprintf (DUMP, "%d entries found\n", ent);
3298 if (ntohl(mht->ht->entries) != ent) ABORT(BUDB_DATABASEINCONSISTENT);
3300 code = ubik_EndTrans(ut);
3301 if (DUMP) fclose (DUMP);
3305 ubik_AbortTrans(ut);
3306 if (DUMP) fclose (DUMP);
3310 afs_int32 SBUDB_T_GetVersion (call, majorVersion)
3311 struct rx_call *call;
3312 afs_int32 *majorVersion;
3316 code = T_GetVersion (call, majorVersion);
3317 osi_auditU (call, BUDB_TGetVrEvent, code, AUD_END);
3321 afs_int32 T_GetVersion (call, majorVersion)
3322 struct rx_call *call;
3325 struct ubik_trans *ut;
3328 code = InitRPC (&ut, LOCKREAD, 0);
3329 if (code) return(code);
3331 *majorVersion = BUDB_MAJORVERSION;
3333 code = ubik_EndTrans(ut);
3337 /* BUDB_T_DumpDatabase
3338 * dump as much of the database as possible int /tmp/<filename>
3341 afs_int32 SBUDB_T_DumpDatabase (call, filename)
3342 struct rx_call *call;
3347 code = T_DumpDatabase (call, filename);
3348 osi_auditU (call, BUDB_TDmpDBEvent, code, AUD_STR, filename, AUD_END);
3352 afs_int32 T_DumpDatabase (call, filename)
3353 struct rx_call *call;
3358 struct ubik_trans *ut;
3361 int type, old, length, hash;
3363 struct memoryHashTable *mht;
3364 afs_int32 eval, code = 0;
3366 if ( !callPermitted(call) )
3367 return BUDB_NOTPERMITTED;
3369 path = (char *) malloc(strlen(gettmpdir())+1+strlen(filename)+1);
3370 if (!path) return(BUDB_INTERNALERROR);
3372 sprintf(path, "%s/%s", gettmpdir(), filename);
3374 dumpfid = fopen(path, "w");
3375 if (!dumpfid) return(BUDB_BADARGUMENT);
3377 eval = InitRPC (&ut, LOCKWRITE, 1);
3378 if (eval) return(eval);
3380 /* dump all items in the database */
3381 for ( type=1; type<=HT_MAX_FUNCTION; type++ )
3383 mht = ht_GetType (type, &entrySize);
3384 if (!mht) ERROR(BUDB_BADARGUMENT);
3386 for ( old =0; old <= 1; old++ )
3388 length = ( old ? mht->oldLength : mht->length);
3389 if (!length) continue;
3391 fprintf (dumpfid, "Dumping %s Hash Table:\n", (old ? "Old ":""));
3393 for ( hash = 0; hash < length; hash++ )
3395 dbAddr = ht_LookupBucket (ut, mht, hash, old);
3401 case HT_dumpIden_FUNCTION:
3403 struct dump hostDump, diskDump;
3405 eval = cdbread (ut, dump_BLOCK, dbAddr, &diskDump, sizeof(diskDump));
3406 if (eval) ERROR(eval);
3408 fprintf(dumpfid, "\ndumpId hash %d, entry at %u: block %d, index %d\n",
3409 hash, dbAddr, block, index);
3410 fprintf(dumpfid, "----------------------------\n");
3411 dump_ntoh(&diskDump, &hostDump);
3412 printDump(dumpfid, &hostDump);
3413 dbAddr = hostDump.idHashChain;
3417 case HT_dumpName_FUNCTION:
3419 struct dump hostDump, diskDump;
3421 eval = cdbread (ut, dump_BLOCK, dbAddr, &diskDump, sizeof(diskDump));
3422 if (eval) ERROR(eval);
3425 "\ndumpname hash %d, entry at %u: block %d, index %d\n",
3426 hash, dbAddr, block, index);
3427 fprintf(dumpfid, "----------------------------\n");
3428 dump_ntoh(&diskDump, &hostDump);
3429 printDump(dumpfid, &hostDump);
3430 dbAddr = hostDump.nameHashChain;
3434 case HT_tapeName_FUNCTION:
3436 struct tape hostTape, diskTape;
3438 eval = cdbread (ut, tape_BLOCK, dbAddr, &diskTape, sizeof(diskTape));
3439 if (eval) ERROR(eval);
3442 "\ntapename hash %d, entry at %u: block %d, index %d\n",
3443 hash, dbAddr, block, index);
3444 fprintf(dumpfid, "----------------------------\n");
3445 tape_ntoh(&diskTape, &hostTape);
3446 printTape(dumpfid, &hostTape);
3447 dbAddr = hostTape.nameHashChain;
3451 case HT_volName_FUNCTION:
3453 struct volInfo hostVolInfo, diskVolInfo;
3455 eval = cdbread (ut, volInfo_BLOCK, dbAddr, &diskVolInfo, sizeof(diskVolInfo));
3456 if (eval) ERROR(eval);
3459 "\nvolname hash %d, entry at %u: block %d, index %d\n",
3460 hash, dbAddr, block, index);
3461 fprintf(dumpfid, "----------------------------\n");
3462 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3463 printVolInfo(dumpfid, &hostVolInfo);
3464 dbAddr = hostVolInfo.nameHashChain;
3466 volFragsDump(ut, dumpfid,
3467 hostVolInfo.firstFragment);
3472 fprintf(dumpfid, "unknown type %d\n", type);
3482 code = ubik_EndTrans(ut); /* is this safe if no ut started ?*/
3483 if (dumpfid) fclose(dumpfid);
3484 if (path) free(path);
3488 volFragsDump(ut, dumpfid, dbAddr)
3489 struct ubik_trans *ut;
3493 struct volFragment hostVolFragment, diskVolFragment;
3499 code = cdbread (ut, volFragment_BLOCK, dbAddr, &diskVolFragment, sizeof(diskVolFragment));
3500 if (code) { /* don't be fussy about errors */
3501 fprintf(dumpfid, "volFragsDump: Error reading database\n");
3505 fprintf(dumpfid, "\nvolfragment entry at %u: block %d, index %d\n",
3506 dbAddr, block, index);
3507 fprintf(dumpfid, "----------------------------\n");
3508 volFragment_ntoh(&diskVolFragment, &hostVolFragment);
3509 printVolFragment(dumpfid, &hostVolFragment);
3510 dbAddr = hostVolFragment.sameNameChain;
3516 /* utilities - network to host conversion
3517 * currently used for debug only
3520 volFragmentDiskToHost(diskVfPtr, hostVfPtr)
3521 struct volFragment *diskVfPtr, *hostVfPtr;
3523 hostVfPtr->vol = ntohl(diskVfPtr->vol);
3524 hostVfPtr->sameNameChain = ntohl(diskVfPtr->sameNameChain);
3525 hostVfPtr->tape = ntohl(diskVfPtr->tape);
3526 hostVfPtr->sameTapeChain = ntohl(diskVfPtr->sameTapeChain);
3527 hostVfPtr->position = ntohl(diskVfPtr->position);
3528 hostVfPtr->clone = ntohl(diskVfPtr->clone);
3529 hostVfPtr->incTime = ntohl(diskVfPtr->incTime);
3530 hostVfPtr->startByte = ntohl(diskVfPtr->startByte);
3531 hostVfPtr->nBytes = ntohl(diskVfPtr->nBytes);
3532 hostVfPtr->flags = ntohs(diskVfPtr->flags);
3533 hostVfPtr->sequence = ntohs(diskVfPtr->sequence);
3536 volInfoDiskToHost(diskViPtr, hostViPtr)
3537 struct volInfo *diskViPtr, *hostViPtr;
3539 strcpy(hostViPtr->name, diskViPtr->name);
3540 hostViPtr->nameHashChain = ntohl(diskViPtr->nameHashChain);
3541 hostViPtr->id = ntohl(diskViPtr->id);
3542 strcpy(hostViPtr->server, diskViPtr->server);
3543 hostViPtr->partition = ntohl(diskViPtr->partition);
3544 hostViPtr->flags = ntohl(diskViPtr->flags);
3545 hostViPtr->sameNameHead = ntohl(diskViPtr->sameNameHead);
3546 hostViPtr->sameNameChain = ntohl(diskViPtr->sameNameChain);
3547 hostViPtr->firstFragment = ntohl(diskViPtr->firstFragment);
3548 hostViPtr->nFrags = ntohl(diskViPtr->nFrags);
3551 tapeDiskToHost(diskTapePtr, hostTapePtr)
3552 struct tape *diskTapePtr, *hostTapePtr;
3554 strcpy(hostTapePtr->name, diskTapePtr->name);
3555 hostTapePtr->nameHashChain = ntohl(diskTapePtr->nameHashChain);
3556 hostTapePtr->flags = ntohl(diskTapePtr->flags);
3558 /* tape id conversion here */
3559 hostTapePtr->written = ntohl(diskTapePtr->written);
3560 hostTapePtr->nBytes = ntohl(diskTapePtr->nBytes);
3561 hostTapePtr->nFiles = ntohl(diskTapePtr->nFiles);
3562 hostTapePtr->nVolumes = ntohl(diskTapePtr->nVolumes);
3563 hostTapePtr->seq = ntohl(diskTapePtr->seq);
3564 hostTapePtr->dump = ntohl(diskTapePtr->dump);
3565 hostTapePtr->nextTape = ntohl(diskTapePtr->nextTape);
3566 hostTapePtr->firstVol = ntohl(diskTapePtr->firstVol);
3567 hostTapePtr->useCount = ntohl(diskTapePtr->useCount);
3570 dumpDiskToHost(diskDumpPtr, hostDumpPtr)
3571 struct dump *diskDumpPtr, *hostDumpPtr;
3573 hostDumpPtr->id = ntohl(diskDumpPtr->id);
3574 hostDumpPtr->idHashChain = ntohl(diskDumpPtr->idHashChain);
3575 strcpy(hostDumpPtr->dumpName, diskDumpPtr->dumpName);
3576 strcpy(hostDumpPtr->dumpPath, diskDumpPtr->dumpPath);
3577 strcpy(hostDumpPtr->volumeSet, diskDumpPtr->volumeSet);
3578 hostDumpPtr->nameHashChain = ntohl(diskDumpPtr->nameHashChain);
3579 hostDumpPtr->flags = ntohl(diskDumpPtr->flags);
3580 hostDumpPtr->parent = ntohl(diskDumpPtr->parent);
3581 hostDumpPtr->created = ntohl(diskDumpPtr->created);
3582 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3583 hostDumpPtr->nVolumes = ntohl(diskDumpPtr->nVolumes);
3585 /* tapeset conversion here */
3587 hostDumpPtr->firstTape = ntohl(diskDumpPtr->firstTape);
3589 /* principal conversion here */
3594 checkHash(ut,hashType)
3595 struct ubik_trans *ut;
3598 struct memoryHashTable *mhtPtr;
3599 int entrySize, hashTableLength;
3604 mhtPtr = ht_GetType(hashType, &entrySize);
3608 for ( old = 0; old < 1; old++)
3610 LogDebug(5, "\nold = %d\n", old);
3611 printMemoryHashTable(stdout, mhtPtr);
3613 hashTableLength = ( old ? mhtPtr->oldLength : mhtPtr->length);
3615 for ( bucket = 0; bucket < hashTableLength; bucket++ )
3619 entryAddr = ht_LookupBucket (ut, mhtPtr, bucket, old);
3620 while (entryAddr != 0)
3622 LogDebug(6, "bucket %d has disk addr %d\n", bucket, entryAddr);
3625 case HT_dumpIden_FUNCTION:
3627 struct dump diskDump, hostDump;
3629 code = dbread(ut, entryAddr, &diskDump, entrySize);
3630 if (code) ERROR(-1);
3632 dump_ntoh(&diskDump, &hostDump);
3633 printDump(stdout, &hostDump);
3634 entryAddr = hostDump.idHashChain;
3638 case HT_dumpName_FUNCTION:
3641 case HT_tapeName_FUNCTION:
3644 case HT_volName_FUNCTION:
3646 struct volInfo diskVolInfo, hostVolInfo;
3648 code = dbread(ut, entryAddr, &diskVolInfo, entrySize);
3649 if (code) ERROR(-1);
3651 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3652 printVolInfo(stdout, &hostVolInfo);
3653 entryAddr = hostVolInfo.nameHashChain;