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>
22 #include <afs/bubasics.h>
29 #include <afs/cellconfig.h>
31 #include <afs/audit.h>
32 #include <afs/afsutil.h>
35 #include "budb_errs.h"
37 #include "budb_internal.h"
38 #include "error_macros.h"
45 extern struct ubik_dbase
*BU_dbase
;
46 extern struct afsconf_dir
*BU_conf
; /* for getting cell info */
48 afs_int32
AddVolume(struct rx_call
*, struct budb_volumeEntry
*);
49 afs_int32
AddVolumes(struct rx_call
*, struct budb_volumeList
*);
50 afs_int32
CreateDump(struct rx_call
*, struct budb_dumpEntry
*);
51 afs_int32
DoDeleteDump(struct rx_call
*, dumpId
, Date
, Date
, budb_dumpsList
*);
52 afs_int32
DoDeleteTape(struct rx_call
*, struct budb_tapeEntry
*);
53 afs_int32
ListDumps(struct rx_call
*, afs_int32
, afs_int32
, Date
, Date
,
54 budb_dumpsList
*, budb_dumpsList
*);
55 afs_int32
DeleteVDP(struct rx_call
*, char *, char *, afs_int32
);
56 afs_int32
FindClone(struct rx_call
*, afs_int32
, char *, afs_int32
*);
57 afs_int32
FindDump(struct rx_call
*, char *, afs_int32
,
58 struct budb_dumpEntry
*);
59 afs_int32
FindLatestDump(struct rx_call
*, char *, char *,
60 struct budb_dumpEntry
*);
61 afs_int32
FinishDump(struct rx_call
*, struct budb_dumpEntry
*);
62 afs_int32
FinishTape(struct rx_call
*, struct budb_tapeEntry
*);
63 afs_int32
GetDumps(struct rx_call
*, afs_int32
, afs_int32
, char *,
64 afs_int32
, afs_int32
, afs_int32
, afs_int32
*,
65 afs_int32
*, budb_dumpList
*);
66 afs_int32
getExpiration(struct ubik_trans
*ut
, struct tape
*);
67 afs_int32
makeAppended(struct ubik_trans
*ut
, afs_int32
, afs_int32
,
69 afs_int32
MakeDumpAppended(struct rx_call
*, afs_int32
, afs_int32
,
71 afs_int32
FindLastTape(struct rx_call
*, afs_int32
, struct budb_dumpEntry
*,
72 struct budb_tapeEntry
*, struct budb_volumeEntry
*);
73 afs_int32
GetTapes(struct rx_call
*, afs_int32
, afs_int32
, char *, afs_int32
,
74 afs_int32
, afs_int32
, afs_int32
*, afs_int32
*,
76 afs_int32
GetVolumes(struct rx_call
*, afs_int32
, afs_int32
, char *,
77 afs_int32
, afs_int32
, afs_int32
, afs_int32
*,
78 afs_int32
*, budb_volumeList
*);
79 afs_int32
UseTape(struct rx_call
*, struct budb_tapeEntry
*, int *);
80 afs_int32
T_DumpHashTable(struct rx_call
*, int, char *);
81 afs_int32
T_GetVersion(struct rx_call
*, int *);
82 afs_int32
T_DumpDatabase(struct rx_call
*, char *);
84 int volFragsDump(struct ubik_trans
*, FILE *, dbadr
);
86 /* Text block management */
89 struct memTextBlock
*mtb_next
; /* next in chain */
90 afs_int32 mtb_nbytes
; /* # of bytes in this block */
91 struct blockHeader mtb_blkHeader
; /* in memory header */
92 dbadr mtb_addr
; /* disk address of block */
95 typedef struct memTextBlock memTextBlockT
;
96 typedef memTextBlockT
*memTextBlockP
;
98 /* These variable are for returning debugging info about the state of the
99 server. If they get trashed during multi-threaded operation it doesn't
102 /* This is global so COUNT_REQ in krb_udp.c can refer to it. */
103 char *lastOperation
; /* name of last operation */
104 static Date lastTrans
; /* time of last transaction */
106 /* procsInited is sort of a lock: during a transaction only one process runs
107 while procsInited is false. */
109 static int procsInited
= 0;
111 /* This variable is protected by the procsInited flag. */
113 static int (*rebuildDatabase
) (struct ubik_trans
*);
115 /* AwaitInitialization
116 * Wait unitl budb has initialized (InitProcs). If it hasn't
117 * within 5 seconds, then return no quorum.
120 AwaitInitialization(void)
124 while (!procsInited
) {
127 else if (time(0) - start
> 5)
129 #ifdef AFS_PTHREAD_ENV
139 * name is a pathname style name, determine trailing name and return
144 tailCompPtr(char *pathNamePtr
)
147 ptr
= strrchr(pathNamePtr
, '/');
149 /* this should never happen */
150 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
152 return (pathNamePtr
);
154 ptr
++; /* skip the / */
159 * Check to see if the caller is a SuperUser.
166 callPermitted(struct rx_call
*call
)
169 struct afsconf_dir
*acdir
;
171 acdir
= afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH
);
175 if (afsconf_SuperUser(acdir
, call
, NULL
))
179 afsconf_Close(acdir
);
184 * This is called by every RPC interface to create a Ubik transaction
185 * and read the database header into core
191 * sets a lock on byte 1 of the database. Looks like it enforces
192 * single threading by use of the lock.
196 InitRPC(struct ubik_trans
**ut
,
197 int lock
, /* indicate read/write transaction */
198 int this_op
) /* opcode of RCP, for COUNT_ABO */
201 float wait
= 0.91; /* start waiting for 1 second */
204 /* wait for server initialization to finish if this is not InitProcs calling */
206 if ((code
= AwaitInitialization()))
209 for (code
= UNOQUORUM
; code
== UNOQUORUM
;) {
211 ubik_BeginTrans(BU_dbase
,
213 LOCKREAD
) ? UBIK_READTRANS
: UBIK_WRITETRANS
),
215 if (code
== UNOQUORUM
) { /* no quorum elected */
217 Log("Waiting for quorum election\n");
220 #ifdef AFS_PTHREAD_ENV
223 IOMGR_Sleep((int)wait
);
230 Log("Have established quorum\n");
232 /* set lock at posiion 1, for 1 byte of type lock */
233 if ((code
= ubik_SetLock(*ut
, 1, 1, lock
))) {
234 ubik_AbortTrans(*ut
);
238 /* check that dbase is initialized and setup cheader */
239 if (lock
== LOCKREAD
) {
240 /* init but don't fix because this is read only */
241 if ((code
= CheckInit(*ut
, 0))) {
242 ubik_AbortTrans(*ut
);
243 if ((code
= InitRPC(ut
, LOCKWRITE
, 0))) { /* Now fix the database */
244 LogError(code
, "InitRPC: InitRPC failed\n");
247 if ((code
= ubik_EndTrans(*ut
))) {
248 LogError(code
, "InitRPC: ubik_EndTrans failed\n");
251 goto start
; /* now redo the read transaction */
254 if ((code
= CheckInit(*ut
, rebuildDatabase
))) {
255 ubik_AbortTrans(*ut
);
263 /* This is called to initialize a newly created database */
265 initialize_database(struct ubik_trans
*ut
)
270 static int noAuthenticationRequired
; /* global state */
271 static int recheckNoAuth
; /* global state */
276 struct ubik_trans
*ut
;
281 if ((globalConfPtr
->myHost
== 0) || (BU_conf
== 0))
282 ERROR(BUDB_INTERNALERROR
);
286 if (globalConfPtr
->debugFlags
& DF_NOAUTH
)
287 noAuthenticationRequired
= 1;
289 if (globalConfPtr
->debugFlags
& DF_RECHECKNOAUTH
)
293 noAuthenticationRequired
= afsconf_GetNoAuthFlag(BU_conf
);
295 if (noAuthenticationRequired
)
296 LogError(0, "Running server with security disabled\n");
300 rebuildDatabase
= initialize_database
;
302 if ((code
= InitRPC(&ut
, LOCKREAD
, 0))) {
303 LogError(code
, "InitProcs: InitRPC failed\n");
306 code
= ubik_EndTrans(ut
);
308 LogError(code
, "InitProcs: ubik_EndTrans failed\n");
312 rebuildDatabase
= 0; /* only do this during init */
320 int nElements
; /* number in list */
321 int allocSize
; /* number of elements allocated */
322 dbadr
*elements
; /* array of addresses */
326 InitReturnList(struct returnList
*list
)
330 list
->elements
= (dbadr
*) 0;
334 FreeReturnList(struct returnList
*list
)
337 free(list
->elements
);
338 list
->elements
= (dbadr
*) 0;
342 /* As entries are collected, they are added to a return list. Once all
343 * entries have been collected, it is then placed in the return buffer
344 * with SendReturnList(). The first *to_skipP are not recorded.
347 AddToReturnList(struct returnList
*list
, dbadr a
, afs_int32
*to_skipP
)
359 /* Up to 5 plus a maximum so SendReturnList() knows if we
360 * need to come back for more.
362 if (list
->nElements
>= BUDB_MAX_RETURN_LIST
+ 5)
363 return BUDB_LIST2BIG
;
365 if (list
->nElements
>= list
->allocSize
) {
366 if (list
->elements
== 0) {
368 tmp
= malloc(sizeof(dbadr
) * size
);
370 size
= list
->allocSize
+ 10;
371 tmp
= realloc(list
->elements
, sizeof(dbadr
) * size
);
375 list
->elements
= tmp
;
376 list
->allocSize
= size
;
379 list
->elements
[list
->nElements
] = a
;
385 FillVolEntry(struct ubik_trans
*ut
, dbadr va
, void *rock
)
387 struct budb_volumeEntry
*vol
= (struct budb_volumeEntry
*) rock
;
391 struct volFragment vf
;
393 if (dbread(ut
, va
, &vf
, sizeof(vf
)))
394 return BUDB_IO
; /* The volFrag */
395 if (dbread(ut
, ntohl(vf
.vol
), &vi
, sizeof(vi
)))
396 return BUDB_IO
; /* The volInfo */
397 if (dbread(ut
, ntohl(vf
.tape
), &t
, sizeof(t
)))
398 return BUDB_IO
; /* The tape */
399 if (dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
)))
400 return BUDB_IO
; /* The dump */
402 strcpy(vol
->name
, vi
.name
);
403 strcpy(vol
->server
, vi
.server
);
404 strcpy(vol
->tape
, t
.name
);
405 vol
->tapeSeq
= ntohl(t
.seq
);
406 vol
->dump
= ntohl(d
.id
);
407 vol
->position
= ntohl(vf
.position
);
408 vol
->clone
= ntohl(vf
.clone
);
409 vol
->incTime
= ntohl(vf
.incTime
);
410 vol
->nBytes
= ntohl(vf
.nBytes
);
411 vol
->startByte
= ntohl(vf
.startByte
);
412 vol
->flags
= (ntohs(vf
.flags
) & VOLFRAGMENTFLAGS
); /* low 16 bits here */
413 vol
->flags
|= (ntohl(vi
.flags
) & VOLINFOFLAGS
); /* high 16 bits here */
414 vol
->seq
= ntohs(vf
.sequence
);
415 vol
->id
= ntohl(vi
.id
);
416 vol
->partition
= ntohl(vi
.partition
);
422 FillDumpEntry(struct ubik_trans
*ut
, dbadr da
, void *rock
)
424 struct budb_dumpEntry
*dump
= (struct budb_dumpEntry
*)rock
;
427 if (dbread(ut
, da
, &d
, sizeof(d
)))
429 dump
->id
= ntohl(d
.id
);
430 dump
->flags
= ntohl(d
.flags
);
431 dump
->created
= ntohl(d
.created
);
432 strncpy(dump
->name
, d
.dumpName
, sizeof(dump
->name
));
433 strncpy(dump
->dumpPath
, d
.dumpPath
, sizeof(dump
->dumpPath
));
434 strncpy(dump
->volumeSetName
, d
.volumeSet
, sizeof(dump
->volumeSetName
));
436 dump
->parent
= ntohl(d
.parent
);
437 dump
->level
= ntohl(d
.level
);
438 dump
->nVolumes
= ntohl(d
.nVolumes
);
440 tapeSet_ntoh(&d
.tapes
, &dump
->tapes
);
442 if (strlen(d
.dumper
.name
) < sizeof(dump
->dumper
.name
))
443 strcpy(dump
->dumper
.name
, d
.dumper
.name
);
444 if (strlen(d
.dumper
.instance
) < sizeof(dump
->dumper
.instance
))
445 strcpy(dump
->dumper
.instance
, d
.dumper
.instance
);
446 if (strlen(d
.dumper
.cell
) < sizeof(dump
->dumper
.cell
))
447 strcpy(dump
->dumper
.cell
, d
.dumper
.cell
);
449 /* Get the initial dumpid and the appended dump id */
450 dump
->initialDumpID
= ntohl(d
.initialDumpID
);
451 if (d
.appendedDumpChain
) {
452 if (dbread(ut
, ntohl(d
.appendedDumpChain
), &ad
, sizeof(ad
)))
454 dump
->appendedDumpID
= ntohl(ad
.id
);
456 dump
->appendedDumpID
= 0;
458 /* printf("dump name %s, parent %d, level %d\n",
459 * d.dumpName, ntohl(d.parent), ntohl(d.level)); */
465 FillTapeEntry(struct ubik_trans
*ut
, dbadr ta
, void *rock
)
467 struct budb_tapeEntry
*tape
=(struct budb_tapeEntry
*) rock
;
472 if (dbread(ut
, ta
, &t
, sizeof(t
)))
475 /* Get the tape's expiration date */
476 if ((code
= getExpiration(ut
, &t
)))
479 strcpy(tape
->name
, t
.name
);
480 tape
->flags
= ntohl(t
.flags
);
481 tape
->written
= ntohl(t
.written
);
482 tape
->expires
= ntohl(t
.expires
);
483 tape
->nMBytes
= ntohl(t
.nMBytes
);
484 tape
->nBytes
= ntohl(t
.nBytes
);
485 tape
->nFiles
= ntohl(t
.nFiles
);
486 tape
->nVolumes
= ntohl(t
.nVolumes
);
487 tape
->seq
= ntohl(t
.seq
);
488 tape
->labelpos
= ntohl(t
.labelpos
);
489 tape
->useCount
= ntohl(t
.useCount
);
490 tape
->useKBytes
= ntohl(t
.useKBytes
);
492 if (dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
)))
494 tape
->dump
= ntohl(d
.id
);
498 #define returnList_t budb_dumpList *
501 * A list of elements of size e_size is in list, collected
502 * with AddToReturnList(). We will move this to a correspoding
503 * return list, eList, via FillProc(). nextInodeP tells us
504 * if there are more and how many to skip on the next request.
507 SendReturnList(struct ubik_trans
*ut
,
508 struct returnList
*list
, /* list of elements to return */
509 afs_int32(*FillProc
) (struct ubik_trans
*, dbadr da
,
511 /* proc to fill entry */
512 int e_size
, /* size of each element */
513 afs_int32 index
, /* index from previous call */
514 afs_int32
*nextIndexP
, /* if more elements are available */
515 afs_int32
*dbTimeP
, /* time of last db update */
516 budb_dumpList
*eList
) /* rxgen list structure (e.g.) */
524 *dbTimeP
= ntohl(db
.h
.lastUpdate
);
526 /* Calculate how many to return. Don't let if go over
527 * BUDB_MAX_RETURN_LIST nor the size of our return list.
529 to_return
= list
->nElements
;
530 if (to_return
> BUDB_MAX_RETURN_LIST
)
531 to_return
= BUDB_MAX_RETURN_LIST
;
532 if (eList
->budb_dumpList_len
&& (to_return
> eList
->budb_dumpList_len
))
533 to_return
= eList
->budb_dumpList_len
;
535 /* Allocate space for the return values if needed and zero it */
536 if (eList
->budb_dumpList_val
== 0) {
538 eList
->budb_dumpList_val
= calloc(to_return
, e_size
);
539 if (!eList
->budb_dumpList_val
)
542 eList
->budb_dumpList_val
= NULL
;
544 memset(eList
->budb_dumpList_val
, 0, e_size
* to_return
);
547 eList
->budb_dumpList_len
= to_return
;
549 e
= (char *)(eList
->budb_dumpList_val
);
550 for (i
= 0; i
< to_return
; i
++, e
+= e_size
) {
551 code
= (*FillProc
) (ut
, list
->elements
[i
], (budb_dumpEntry
*) e
);
556 if (list
->nElements
> i
)
557 *nextIndexP
= index
+ i
;
561 /* Come here to delete a volInfo structure. */
564 DeleteVolInfo(struct ubik_trans
*ut
, dbadr via
, struct volInfo
*vi
)
570 if (vi
->firstFragment
)
571 return 0; /* still some frags, don't free yet */
572 if (vi
->sameNameHead
== 0) { /* this is the head */
573 if (vi
->sameNameChain
)
574 return 0; /* empty head, some non-heads left */
576 code
= ht_HashOut(ut
, &db
.volName
, via
, vi
);
579 code
= FreeStructure(ut
, volInfo_BLOCK
, via
);
582 hvia
= ntohl(vi
->sameNameHead
);
583 if (dbread(ut
, hvia
, &hvi
, sizeof(hvi
)))
586 RemoveFromList(ut
, hvia
, &hvi
, &hvi
.sameNameChain
, via
, vi
,
589 return BUDB_DATABASEINCONSISTENT
;
591 code
= FreeStructure(ut
, volInfo_BLOCK
, via
);
595 /* Detach a volume fragment from its volInfo structure. Its tape chain is
596 already freed. This routine frees the structure and the caller must not
600 DeleteVolFragment(struct ubik_trans
*ut
, dbadr va
, struct volFragment
*v
)
607 if (dbread(ut
, via
, &vi
, sizeof(vi
)))
610 RemoveFromList(ut
, via
, &vi
, &vi
.firstFragment
, va
, v
,
613 return BUDB_DATABASEINCONSISTENT
;
616 if (vi
.firstFragment
== 0)
617 if ((code
= DeleteVolInfo(ut
, via
, &vi
)))
619 if ((code
= FreeStructure(ut
, volFragment_BLOCK
, va
)))
622 /* decrement frag counter */
624 set_word_addr(ut
, via
, &vi
, &vi
.nFrags
, htonl(ntohl(vi
.nFrags
) - 1));
630 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
631 * The caller will remove it from the hash table if necessary. The caller is
632 * also responsible for writing the tape out if necessary. */
635 DeleteTape(struct ubik_trans
*ut
, dbadr ta
, struct tape
*t
)
643 return BUDB_DATABASEINCONSISTENT
;
644 if (dbread(ut
, da
, &d
, sizeof(d
)))
646 if (d
.firstTape
== 0)
647 return BUDB_DATABASEINCONSISTENT
;
649 code
= RemoveFromList(ut
, da
, &d
, &d
.firstTape
, ta
, t
, &t
->nextTape
);
651 return BUDB_DATABASEINCONSISTENT
;
655 /* Since the tape should have been truncated there should never be any
656 * volumes in the tape. */
657 if (t
->firstVol
|| t
->nVolumes
)
658 return BUDB_DATABASEINCONSISTENT
;
664 DeleteDump(struct ubik_trans
*ut
, dbadr da
, struct dump
*d
)
668 code
= ht_HashOut(ut
, &db
.dumpIden
, da
, d
);
672 code
= ht_HashOut(ut
, &db
.dumpName
, da
, d
);
676 /* Since the tape should have been truncated this should never happen. */
677 if (d
->firstTape
|| d
->nVolumes
)
678 ERROR(BUDB_DATABASEINCONSISTENT
);
680 code
= FreeStructure(ut
, dump_BLOCK
, da
);
691 * This is called with a volumeEntry and a volInfo structure and compares
692 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
693 * search volInfo structures once it has the head volInfo structure from the
694 * volName hash table.
696 * When called from GetVolInfo the name compare is redundant.
697 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
701 VolInfoMatch(struct budb_volumeEntry
*vol
, struct volInfo
*vi
)
703 return ((strcmp(vol
->name
, vi
->name
) == 0) && /* same volume name */
704 (vol
->id
== ntohl(vi
->id
)) && /* same volume id */
705 ((vol
->flags
& VOLINFOFLAGS
) == (ntohl(vi
->flags
) & VOLINFOFLAGS
)) && /* same flags */
706 (vol
->partition
== ntohl(vi
->partition
)) && /* same partition (N/A) */
707 (strcmp(vol
->server
, vi
->server
) == 0)); /* same server (N/A) */
712 * This routine takes a volumeEntry structure from an RPC interface and
713 * returns the corresponding volInfo structure, creating it if necessary.
715 * The caller must write the entry out.
719 GetVolInfo(struct ubik_trans
*ut
, struct budb_volumeEntry
*volP
, dbadr
*viaP
,
724 afs_int32 eval
, code
= 0;
726 eval
= ht_LookupEntry(ut
, &db
.volName
, volP
->name
, &via
, viP
);
731 /* allocate a new volinfo structure */
732 eval
= AllocStructure(ut
, volInfo_BLOCK
, 0, &via
, viP
);
736 strcpy(viP
->name
, volP
->name
);
737 strcpy(viP
->server
, volP
->server
);
738 viP
->sameNameHead
= 0; /* The head of same name chain */
739 viP
->sameNameChain
= 0; /* Same name chain is empty */
740 viP
->firstFragment
= 0;
742 viP
->id
= htonl(volP
->id
);
743 viP
->partition
= htonl(volP
->partition
);
744 viP
->flags
= htonl(volP
->flags
& VOLINFOFLAGS
);
746 /* Chain onto volname hash table */
747 eval
= ht_HashIn(ut
, &db
.volName
, via
, viP
);
751 LogDebug(4, "volume Info for %s placed at %d\n", volP
->name
, via
);
754 else if (!VolInfoMatch(volP
, viP
)) { /* Not the head volinfo struct */
755 hvia
= via
; /* remember the head volinfo struct */
756 memcpy(&hvi
, viP
, sizeof(hvi
));
758 /* Search the same name chain for the correct volinfo structure */
759 for (via
= ntohl(viP
->sameNameChain
); via
;
760 via
= ntohl(viP
->sameNameChain
)) {
761 eval
= dbread(ut
, via
, viP
, sizeof(*viP
));
765 if (VolInfoMatch(volP
, viP
))
766 break; /* found the one */
769 /* if the correct volinfo struct isn't found, create one */
771 eval
= AllocStructure(ut
, volInfo_BLOCK
, 0, &via
, viP
);
775 strcpy(viP
->name
, volP
->name
);
776 strcpy(viP
->server
, volP
->server
);
777 viP
->nameHashChain
= 0; /* not in hash table */
778 viP
->sameNameHead
= htonl(hvia
); /* chain to head of sameNameChain */
779 viP
->sameNameChain
= hvi
.sameNameChain
;
780 viP
->firstFragment
= 0;
782 viP
->id
= htonl(volP
->id
);
783 viP
->partition
= htonl(volP
->partition
);
784 viP
->flags
= htonl(volP
->flags
& VOLINFOFLAGS
);
786 /* write the head entry's sameNameChain link */
788 set_word_addr(ut
, hvia
, &hvi
, &hvi
.sameNameChain
, htonl(via
));
800 /* deletesomevolumesfromtape
801 * Deletes a specified number of volumes from a tape. The tape
802 * and dump are modified to reflect the smaller number of volumes.
803 * The transaction is not terminated, it is up to the caller to
804 * finish the transaction and start a new one (if desired).
806 * maxvolumestodelete - don't delete more than this many volumes
810 deleteSomeVolumesFromTape(struct ubik_trans
*ut
, dbadr tapeAddr
,
811 struct tape
*tapePtr
, int maxVolumesToDelete
)
813 dbadr volFragAddr
, nextVolFragAddr
, dumpAddr
;
814 struct volFragment volFrag
;
816 int volumesDeleted
= 0;
817 afs_int32 eval
, code
= 0;
822 for (volFragAddr
= ntohl(tapePtr
->firstVol
);
823 (volFragAddr
&& (maxVolumesToDelete
> 0));
824 volFragAddr
= nextVolFragAddr
) {
825 eval
= dbread(ut
, volFragAddr
, &volFrag
, sizeof(volFrag
));
829 nextVolFragAddr
= ntohl(volFrag
.sameTapeChain
);
831 eval
= DeleteVolFragment(ut
, volFragAddr
, &volFrag
);
835 maxVolumesToDelete
--;
839 /* reset the volume fragment pointer in the tape */
840 tapePtr
->firstVol
= htonl(volFragAddr
);
842 /* diminish the tape's volume count */
843 tapePtr
->nVolumes
= htonl(ntohl(tapePtr
->nVolumes
) - volumesDeleted
);
845 eval
= dbwrite(ut
, tapeAddr
, tapePtr
, sizeof(*tapePtr
));
849 /* diminish the dump's volume count */
850 dumpAddr
= ntohl(tapePtr
->dump
);
851 eval
= dbread(ut
, dumpAddr
, &dump
, sizeof(dump
));
855 dump
.nVolumes
= htonl(ntohl(dump
.nVolumes
) - volumesDeleted
);
856 eval
= dbwrite(ut
, dumpAddr
, &dump
, sizeof(dump
));
865 * deletes a dump in stages, by repeatedly deleting a small number of
866 * volumes from the dump until none are left. The dump is then deleted.
868 * In the case where multiple calls are made to delete the same
869 * dump, the operation will succeed but contention for structures
870 * will result in someone getting back an error.
873 * id - id of dump to delete
877 deleteDump(struct rx_call
*call
, dumpId id
, budb_dumpsList
*dumps
)
879 struct ubik_trans
*ut
;
880 dbadr dumpAddr
, tapeAddr
, appendedDump
;
884 afs_int32 eval
, code
= 0;
887 /* iterate until the dump is truly deleted */
893 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
895 ERROR(eval
); /* can't start transaction */
898 ht_LookupEntry(ut
, &db
.dumpIden
, &dumpid
, &dumpAddr
, &dump
);
902 ABORT(BUDB_NOENT
); /* can't find dump */
904 if ((dumpid
== id
) && (dump
.initialDumpID
)) /* can't be an appended dump */
905 ABORT(BUDB_NOTINITIALDUMP
);
907 tapeAddr
= ntohl(dump
.firstTape
);
911 /* there is a tape to delete */
912 eval
= dbread(ut
, tapeAddr
, &tape
, sizeof(tape
));
916 if (ntohl(tape
.nVolumes
)) {
917 /* tape is not empty */
918 eval
= deleteSomeVolumesFromTape(ut
, tapeAddr
, &tape
, 10);
923 if (ntohl(tape
.nVolumes
) == 0) {
924 /* tape is now empty, delete it */
925 eval
= DeleteTape(ut
, tapeAddr
, &tape
);
928 eval
= ht_HashOut(ut
, &db
.tapeName
, tapeAddr
, &tape
);
931 eval
= FreeStructure(ut
, tape_BLOCK
, tapeAddr
);
936 eval
= ubik_EndTrans(ut
);
940 } /* next deletion portion */
942 /* Record the dump just deleted */
943 if (dumps
&& (dumps
->budb_dumpsList_len
< BUDB_MAX_RETURN_LIST
)) {
944 if (dumps
->budb_dumpsList_len
== 0)
945 dumps
->budb_dumpsList_val
= malloc(sizeof(afs_int32
));
947 dumps
->budb_dumpsList_val
=
948 realloc(dumps
->budb_dumpsList_val
,
949 (dumps
->budb_dumpsList_len
+ 1)
950 * sizeof(afs_int32
));
952 if (!dumps
->budb_dumpsList_val
)
955 dumps
->budb_dumpsList_val
[dumps
->budb_dumpsList_len
] = dumpid
;
956 dumps
->budb_dumpsList_len
++;
959 appendedDump
= ntohl(dump
.appendedDumpChain
);
961 /* finally done. No more tapes left in the dump. Delete the dump itself */
962 eval
= DeleteDump(ut
, dumpAddr
, &dump
);
966 /* Now delete the appended dump too */
968 eval
= dbread(ut
, appendedDump
, &dump
, sizeof(dump
));
972 dumpid
= ntohl(dump
.id
);
976 eval
= ubik_EndTrans(ut
);
980 Log("Delete dump %s (DumpID %u), path %s\n", dump
.dumpName
,
981 ntohl(dump
.id
), dump
.dumpPath
);
985 if (code
&& partialDel
) {
986 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
987 dump
.dumpName
, ntohl(dump
.id
), dump
.dumpPath
, code
);
997 * dump selection routines - used by BUDB_GetDumps
1001 /* most recent dump selection */
1004 struct chosenDump
*next
;
1009 struct wantDumpRock
{
1010 int maxDumps
; /* max wanted */
1011 int ndumps
; /* actual in chain */
1012 struct chosenDump
*chain
;
1017 wantDump(dbadr dumpAddr
, void *dumpParam
, void *dumpListPtrParam
)
1019 struct dump
*dumpPtr
;
1020 struct wantDumpRock
*rockPtr
;
1022 dumpPtr
= (struct dump
*)dumpParam
;
1023 rockPtr
= (struct wantDumpRock
*)dumpListPtrParam
;
1025 /* if we don't have our full complement, just add another */
1026 if (rockPtr
->ndumps
< rockPtr
->maxDumps
)
1029 /* got the number we need, select based on date */
1030 if ((afs_uint32
) ntohl(dumpPtr
->created
) > rockPtr
->chain
->date
)
1037 rememberDump(dbadr dumpAddr
, void *dumpParam
, void *dumpListPtrParam
)
1039 struct dump
*dumpPtr
;
1040 struct wantDumpRock
*rockPtr
;
1041 struct chosenDump
*ptr
, *deletedPtr
, **nextPtr
;
1043 dumpPtr
= (struct dump
*)dumpParam
;
1044 rockPtr
= (struct wantDumpRock
*)dumpListPtrParam
;
1046 ptr
= calloc(1, sizeof(*ptr
));
1049 ptr
->addr
= dumpAddr
;
1050 ptr
->date
= (afs_uint32
) ntohl(dumpPtr
->created
);
1052 /* Don't overflow the max */
1053 while (rockPtr
->ndumps
>= rockPtr
->maxDumps
) {
1054 /* have to drop one */
1055 deletedPtr
= rockPtr
->chain
;
1056 rockPtr
->chain
= deletedPtr
->next
;
1061 /* now insert in the right place */
1062 for (nextPtr
= &rockPtr
->chain
; *nextPtr
; nextPtr
= &((*nextPtr
)->next
)) {
1063 if (ptr
->date
< (*nextPtr
)->date
)
1066 ptr
->next
= *nextPtr
;
1074 /* ---------------------------------------------
1075 * general interface routines - alphabetic
1076 * ---------------------------------------------
1080 SBUDB_AddVolume(struct rx_call
*call
, struct budb_volumeEntry
*vol
)
1084 code
= AddVolume(call
, vol
);
1085 osi_auditU(call
, BUDB_AddVolEvent
, code
, AUD_LONG
, (vol
? vol
->id
: 0),
1091 AddVolume(struct rx_call
*call
, struct budb_volumeEntry
*vol
)
1093 struct ubik_trans
*ut
;
1094 dbadr da
, ta
, via
, va
;
1098 struct volFragment v
;
1100 afs_int32 eval
, code
= 0;
1102 if (!callPermitted(call
))
1103 return BUDB_NOTPERMITTED
;
1105 if ((strlen(vol
->name
) >= sizeof(vi
.name
))
1106 || (strlen(vol
->server
) >= sizeof(vi
.server
))
1107 || (strlen(vol
->tape
) >= sizeof(t
.name
)))
1108 return BUDB_BADARGUMENT
;
1110 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1114 /* Find the dump in dumpid hash table */
1115 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &vol
->dump
, &da
, &d
);
1119 ABORT(BUDB_NODUMPID
);
1121 /* search for the right tape in the dump */
1122 for (ta
= ntohl(d
.firstTape
); ta
; ta
= ntohl(t
.nextTape
)) {
1123 /* read the tape entry */
1124 eval
= dbread(ut
, ta
, &t
, sizeof(t
));
1128 /* Check if the right tape name */
1129 if (strcmp(t
.name
, vol
->tape
) == 0)
1133 ABORT(BUDB_NOTAPENAME
);
1135 if ((t
.dump
!= htonl(da
)) || /* tape must belong to dump */
1136 ((ntohl(t
.flags
) & BUDB_TAPE_BEINGWRITTEN
) == 0) || /* tape must be being written */
1137 ((ntohl(d
.flags
) & BUDB_DUMP_INPROGRESS
) == 0)) /* dump must be in progress */
1138 ABORT(BUDB_BADPROTOCOL
);
1140 /* find or create a volume info structure */
1141 eval
= GetVolInfo(ut
, vol
, &via
, &vi
);
1145 /* Create a volume fragment */
1146 eval
= AllocStructure(ut
, volFragment_BLOCK
, 0, &va
, &v
);
1150 v
.vol
= htonl(via
); /* vol frag points to vol info */
1151 v
.sameNameChain
= vi
.firstFragment
; /* vol frag is chained to vol info */
1152 vi
.firstFragment
= htonl(va
);
1153 vi
.nFrags
= htonl(ntohl(vi
.nFrags
) + 1);
1155 eval
= dbwrite(ut
, via
, &vi
, sizeof(vi
)); /* write the vol info struct */
1159 v
.tape
= htonl(ta
); /* vol frag points to tape */
1160 v
.sameTapeChain
= t
.firstVol
; /* vol frag is chained to tape info */
1161 t
.firstVol
= htonl(va
);
1162 t
.nVolumes
= htonl(ntohl(t
.nVolumes
) + 1);
1163 bytes
= ntohl(t
.nBytes
) + vol
->nBytes
; /* update bytes on tape */
1164 t
.nMBytes
= htonl(ntohl(t
.nMBytes
) + bytes
/ (1024 * 1024));
1165 t
.nBytes
= htonl(bytes
% (1024 * 1024));
1167 eval
= dbwrite(ut
, ta
, &t
, sizeof(t
)); /* write the tape structure */
1171 d
.nVolumes
= htonl(ntohl(d
.nVolumes
) + 1); /* one more volume on dump */
1173 eval
= dbwrite(ut
, da
, &d
, sizeof(d
)); /* write out the dump structure */
1177 v
.position
= htonl(vol
->position
); /* vol frag info */
1178 v
.clone
= htonl(vol
->clone
);
1179 v
.incTime
= htonl(vol
->incTime
);
1180 v
.startByte
= htonl(vol
->startByte
);
1181 v
.nBytes
= htonl(vol
->nBytes
);
1182 v
.flags
= htons(vol
->flags
& VOLFRAGMENTFLAGS
);
1183 v
.sequence
= htons(vol
->seq
);
1185 eval
= dbwrite(ut
, va
, &v
, sizeof(v
)); /* write out the vol frag struct */
1189 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1193 LogDebug(4, "added volume %s at %d\n", vol
->name
, va
);
1195 code
= ubik_EndTrans(ut
);
1199 ubik_AbortTrans(ut
);
1205 SBUDB_AddVolumes(struct rx_call
*call
, struct budb_volumeList
*vols
)
1209 code
= AddVolumes(call
, vols
);
1210 osi_auditU(call
, BUDB_AddVolEvent
, code
, AUD_LONG
, 0, AUD_END
);
1215 AddVolumes(struct rx_call
*call
, struct budb_volumeList
*vols
)
1217 struct budb_volumeEntry
*vol
, *vol1
;
1218 struct ubik_trans
*ut
;
1219 dbadr da
, ta
, via
, va
;
1223 struct volFragment v
;
1225 afs_int32 eval
, e
, code
= 0;
1227 if (!callPermitted(call
))
1228 return BUDB_NOTPERMITTED
;
1230 if (!vols
|| (vols
->budb_volumeList_len
<= 0)
1231 || !vols
->budb_volumeList_val
)
1232 return BUDB_BADARGUMENT
;
1234 /* The first volume in the list of volumes to add */
1235 vol1
= (struct budb_volumeEntry
*)vols
->budb_volumeList_val
;
1237 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1241 /* Find the dump in dumpid hash table */
1242 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &vol1
->dump
, &da
, &d
);
1246 ABORT(BUDB_NODUMPID
);
1248 /* search for the right tape in the dump */
1249 for (ta
= ntohl(d
.firstTape
); ta
; ta
= ntohl(t
.nextTape
)) {
1250 /* read the tape entry */
1251 eval
= dbread(ut
, ta
, &t
, sizeof(t
));
1255 /* Check if the right tape name */
1256 if (strcmp(t
.name
, vol1
->tape
) == 0)
1260 ABORT(BUDB_NOTAPENAME
);
1262 if ((t
.dump
!= htonl(da
)) || /* tape must belong to dump */
1263 ((ntohl(t
.flags
) & BUDB_TAPE_BEINGWRITTEN
) == 0) || /* tape must be being written */
1264 ((ntohl(d
.flags
) & BUDB_DUMP_INPROGRESS
) == 0)) /* dump must be in progress */
1265 ABORT(BUDB_BADPROTOCOL
);
1267 for (vol
= vol1
, e
= 0; e
< vols
->budb_volumeList_len
; vol
++, e
++) {
1269 if ((strlen(vol
->name
) >= sizeof(vi
.name
)) || (strcmp(vol
->name
, "") == 0) || /* no null volnames */
1270 (strlen(vol
->server
) >= sizeof(vi
.server
))
1271 || (strlen(vol
->tape
) >= sizeof(t
.name
))
1272 || (strcmp(vol
->tape
, vol1
->tape
) != 0)) {
1273 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n", vol
->name
, vol
->id
, vol
->tape
, vol
->dump
);
1277 /* find or create a volume info structure */
1278 eval
= GetVolInfo(ut
, vol
, &via
, &vi
);
1281 if (*(afs_int32
*) (&vi
) == 0) {
1282 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n", vol
->name
, vol
->tape
, vol
->dump
);
1283 ABORT(BUDB_BADARGUMENT
);
1286 /* Create a volume fragment */
1287 eval
= AllocStructure(ut
, volFragment_BLOCK
, 0, &va
, &v
);
1291 v
.vol
= htonl(via
); /* vol frag points to vol info */
1292 v
.sameNameChain
= vi
.firstFragment
; /* vol frag is chained to vol info */
1293 vi
.firstFragment
= htonl(va
);
1294 vi
.nFrags
= htonl(ntohl(vi
.nFrags
) + 1);
1295 eval
= dbwrite(ut
, via
, &vi
, sizeof(vi
)); /* write the vol info struct */
1299 v
.tape
= htonl(ta
); /* vol frag points to tape */
1300 v
.sameTapeChain
= t
.firstVol
; /* vol frag is chained to tape info */
1301 t
.firstVol
= htonl(va
);
1302 t
.nVolumes
= htonl(ntohl(t
.nVolumes
) + 1);
1303 bytes
= ntohl(t
.nBytes
) + vol
->nBytes
; /* update bytes on tape */
1304 t
.nMBytes
= htonl(ntohl(t
.nMBytes
) + bytes
/ (1024 * 1024));
1305 t
.nBytes
= htonl(bytes
% (1024 * 1024));
1307 d
.nVolumes
= htonl(ntohl(d
.nVolumes
) + 1); /* one more volume on dump */
1309 v
.position
= htonl(vol
->position
); /* vol frag info */
1310 v
.clone
= htonl(vol
->clone
);
1311 v
.incTime
= htonl(vol
->incTime
);
1312 v
.startByte
= htonl(vol
->startByte
);
1313 v
.nBytes
= htonl(vol
->nBytes
);
1314 v
.flags
= htons(vol
->flags
& VOLFRAGMENTFLAGS
);
1315 v
.sequence
= htons(vol
->seq
);
1317 eval
= dbwrite(ut
, va
, &v
, sizeof(v
)); /* write out the vol frag struct */
1321 LogDebug(4, "added volume %s at %d\n", vol
->name
, va
);
1324 eval
= dbwrite(ut
, ta
, &t
, sizeof(t
)); /* write the tape structure */
1328 eval
= dbwrite(ut
, da
, &d
, sizeof(d
)); /* write out the dump structure */
1332 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1336 code
= ubik_EndTrans(ut
);
1340 ubik_AbortTrans(ut
);
1346 * records the existence of a dump in the database. This creates only
1347 * the dump record, to which one must attach tape and volume records.
1349 * 1) record the volume set
1353 SBUDB_CreateDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
1357 code
= CreateDump(call
, dump
);
1358 osi_auditU(call
, BUDB_CrDmpEvent
, code
, AUD_DATE
, (dump
? dump
->id
: 0),
1360 if (dump
&& !code
) {
1361 Log("Create dump %s (DumpID %u), path %s\n", dump
->name
, dump
->id
,
1368 CreateDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
1370 struct ubik_trans
*ut
;
1371 dbadr findDumpAddr
, da
;
1372 struct dump findDump
, d
;
1373 afs_int32 eval
, code
= 0;
1377 Date expiration
; /* checked by Security Module */
1378 struct ktc_principal principal
;
1380 if (!callPermitted(call
))
1381 return BUDB_NOTPERMITTED
;
1383 if (strlen(dump
->name
) >= sizeof(d
.dumpName
))
1384 return BUDB_BADARGUMENT
;
1386 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1391 rxkad_GetServerInfo(rx_ConnectionOf(call
), &level
, &expiration
,
1392 principal
.name
, principal
.instance
,
1393 principal
.cell
, &kvno
);
1396 if (eval
!= RXKADNOAUTH
)
1399 strcpy(principal
.name
, "");
1400 strcpy(principal
.instance
, "");
1401 strcpy(principal
.cell
, "");
1404 /* authenticated. Take user supplied principal information */
1405 if (strcmp(dump
->dumper
.name
, "") != 0)
1406 strncpy(principal
.name
, dump
->dumper
.name
,
1407 sizeof(principal
.name
));
1409 if (strcmp(dump
->dumper
.instance
, "") != 0)
1410 strncpy(principal
.instance
, dump
->dumper
.instance
,
1411 sizeof(principal
.instance
));
1413 if (strcmp(dump
->dumper
.cell
, "") != 0)
1414 strncpy(principal
.cell
, dump
->dumper
.cell
,
1415 sizeof(principal
.cell
));
1418 /* dump id's are time stamps */
1420 while (1) { /* allocate a unique dump id *//*w */
1423 /* ensure it is unique - seach for dumpid in hash table */
1425 ht_LookupEntry(ut
, &db
.dumpIden
, &dump
->id
, &findDumpAddr
,
1430 if (!findDumpAddr
) { /* dumpid not in use */
1431 /* update the last dump id allocated */
1432 eval
= set_header_word(ut
, lastDumpId
, htonl(dump
->id
));
1438 /* dump id is in use - wait a while */
1439 #ifdef AFS_PTHREAD_ENV
1446 /* dump id supplied (e.g. for database restore) */
1448 ht_LookupEntry(ut
, &db
.dumpIden
, &dump
->id
, &findDumpAddr
,
1453 /* Dump id must not already exist */
1455 ABORT(BUDB_DUMPIDEXISTS
);
1458 /* Allocate a dump structure */
1459 memset(&d
, 0, sizeof(d
));
1460 eval
= AllocStructure(ut
, dump_BLOCK
, 0, &da
, &d
);
1464 strcpy(d
.dumpName
, dump
->name
); /* volset.dumpname */
1465 strcpy(d
.dumpPath
, dump
->dumpPath
); /* dump node path */
1466 strcpy(d
.volumeSet
, dump
->volumeSetName
); /* volume set */
1467 d
.id
= htonl(dump
->id
);
1468 d
.parent
= htonl(dump
->parent
); /* parent id */
1469 d
.level
= htonl(dump
->level
);
1471 LogDebug(4, "dump name %s, parent %d level %d\n", dump
->name
,
1472 dump
->parent
, dump
->level
);
1474 /* if creation time specified, use that. Else use the dumpid time */
1475 if (dump
->created
== 0)
1476 dump
->created
= dump
->id
;
1477 d
.created
= htonl(dump
->created
);
1479 d
.dumper
= principal
;
1480 tapeSet_hton(&dump
->tapes
, &d
.tapes
);
1482 d
.flags
= htonl(dump
->flags
| BUDB_DUMP_INPROGRESS
);
1484 eval
= ht_HashIn(ut
, &db
.dumpName
, da
, &d
); /* Into dump name hash table */
1488 eval
= ht_HashIn(ut
, &db
.dumpIden
, da
, &d
); /* Into dumpid hash table */
1492 eval
= dbwrite(ut
, da
, (char *)&d
, sizeof(d
)); /* Write the dump structure */
1496 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1500 /* If to append this dump, then append it - will write the appended dump */
1501 eval
= makeAppended(ut
, dump
->id
, dump
->initialDumpID
, dump
->tapes
.b
);
1505 code
= ubik_EndTrans(ut
);
1506 LogDebug(5, "made dump %s, path %s\n", d
.dumpName
, d
.dumpPath
);
1510 ubik_AbortTrans(ut
);
1515 SBUDB_DeleteDump(struct rx_call
*call
, dumpId id
, Date fromTime
, Date toTime
,
1516 budb_dumpsList
*dumps
)
1520 code
= DoDeleteDump(call
, id
, fromTime
, toTime
, dumps
);
1521 osi_auditU(call
, BUDB_DelDmpEvent
, code
, AUD_DATE
, id
, AUD_END
);
1528 DoDeleteDump(struct rx_call
*call
, dumpId id
, Date fromTime
, Date toTime
,
1529 budb_dumpsList
*dumps
)
1533 if (!callPermitted(call
))
1534 return BUDB_NOTPERMITTED
;
1537 code
= deleteDump(call
, id
, dumps
);
1542 SBUDB_ListDumps(struct rx_call
*call
, afs_int32 sflags
, char *name
,
1543 afs_int32 groupid
, Date fromTime
, Date toTime
,
1544 budb_dumpsList
*dumps
, budb_dumpsList
*flags
)
1548 code
= ListDumps(call
, sflags
, groupid
, fromTime
, toTime
, dumps
, flags
);
1549 osi_auditU(call
, BUDB_LstDmpEvent
, code
, AUD_LONG
, flags
, AUD_END
);
1554 ListDumps(struct rx_call
*call
, afs_int32 sflags
, afs_int32 groupid
,
1555 Date fromTime
, Date toTime
, budb_dumpsList
*dumps
,
1556 budb_dumpsList
*flags
)
1558 struct ubik_trans
*ut
;
1559 struct memoryHashTable
*mht
;
1560 struct dump diskDump
, appDiskDump
;
1561 dbadr dbAddr
, dbAppAddr
;
1563 afs_int32 eval
, code
= 0;
1564 int old
, hash
, length
, entrySize
, count
= 0;
1566 if (!callPermitted(call
))
1567 return BUDB_NOTPERMITTED
;
1569 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1573 /* Search the database */
1574 mht
= ht_GetType(HT_dumpIden_FUNCTION
, &entrySize
);
1576 return (BUDB_BADARGUMENT
);
1578 for (old
= 0; old
<= 1; old
++) { /*o *//* old and new hash tables */
1579 length
= (old
? mht
->oldLength
: mht
->length
);
1583 for (hash
= 0; hash
< length
; hash
++) { /*h *//* for each hash bucket */
1584 for (dbAddr
= ht_LookupBucket(ut
, mht
, hash
, old
); dbAddr
; dbAddr
= ntohl(diskDump
.idHashChain
)) { /*d */
1586 /* read the entry */
1587 eval
= dbread(ut
, dbAddr
, &diskDump
, sizeof(diskDump
));
1591 /* Skip appended dumps */
1592 if (ntohl(diskDump
.initialDumpID
) != 0) {
1596 /* Skip dumps with different goup id */
1597 if ((sflags
& BUDB_OP_GROUPID
)
1598 && (ntohl(diskDump
.tapes
.id
) != groupid
)) {
1602 /* Look at this dump to see if it meets the criteria for listing */
1603 if (sflags
& BUDB_OP_DATES
) {
1604 /* This and each appended dump should be in time */
1605 for (dbAppAddr
= dbAddr
; dbAppAddr
;
1606 dbAppAddr
= ntohl(appDiskDump
.appendedDumpChain
)) {
1608 dbread(ut
, dbAppAddr
, &appDiskDump
,
1609 sizeof(appDiskDump
));
1613 if ((ntohl(appDiskDump
.id
) < fromTime
)
1614 || (ntohl(appDiskDump
.id
) > toTime
))
1621 /* Add it and each of its appended dump to our list to return */
1622 for (dbAppAddr
= dbAddr
; dbAppAddr
;
1623 dbAppAddr
= ntohl(appDiskDump
.appendedDumpChain
)) {
1625 dbread(ut
, dbAppAddr
, &appDiskDump
,
1626 sizeof(appDiskDump
));
1630 /* Make sure we have space to list it */
1631 if (dumps
->budb_dumpsList_len
>= count
) {
1634 dumps
->budb_dumpsList_val
=
1635 malloc(count
* sizeof(afs_int32
));
1636 flags
->budb_dumpsList_val
=
1637 malloc(count
* sizeof(afs_int32
));
1639 dumps
->budb_dumpsList_val
=
1640 realloc(dumps
->budb_dumpsList_val
,
1641 count
* sizeof(afs_int32
));
1642 flags
->budb_dumpsList_val
=
1643 realloc(flags
->budb_dumpsList_val
,
1644 count
* sizeof(afs_int32
));
1646 if (!dumps
->budb_dumpsList_val
1647 || !dumps
->budb_dumpsList_val
)
1651 /* Add it to our list */
1652 dumps
->budb_dumpsList_val
[dumps
->budb_dumpsList_len
] =
1653 ntohl(appDiskDump
.id
);
1654 flags
->budb_dumpsList_val
[flags
->budb_dumpsList_len
] = 0;
1655 if (ntohl(appDiskDump
.initialDumpID
) != 0) {
1656 flags
->budb_dumpsList_val
[flags
->
1657 budb_dumpsList_len
] |=
1660 if (strcmp(appDiskDump
.dumpName
, DUMP_TAPE_NAME
) == 0) {
1661 flags
->budb_dumpsList_val
[flags
->
1662 budb_dumpsList_len
] |=
1665 dumps
->budb_dumpsList_len
++;
1666 flags
->budb_dumpsList_len
++;
1672 code
= ubik_EndTrans(ut
);
1676 ubik_AbortTrans(ut
);
1681 SBUDB_DeleteTape(struct rx_call
*call
,
1682 struct budb_tapeEntry
*tape
) /* tape info */
1686 code
= DoDeleteTape(call
, tape
);
1687 osi_auditU(call
, BUDB_DelTpeEvent
, code
, AUD_DATE
,
1688 (tape
? tape
->dump
: 0), AUD_END
);
1693 DoDeleteTape(struct rx_call
*call
,
1694 struct budb_tapeEntry
*tape
) /* tape info */
1696 struct ubik_trans
*ut
;
1699 afs_int32 eval
, code
;
1701 if (!callPermitted(call
))
1702 return BUDB_NOTPERMITTED
;
1704 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1708 eval
= ht_LookupEntry(ut
, &db
.tapeName
, tape
->name
, &a
, &t
);
1712 eval
= DeleteTape(ut
, a
, &t
);
1716 eval
= FreeStructure(ut
, tape_BLOCK
, a
);
1720 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1724 code
= ubik_EndTrans(ut
);
1728 ubik_AbortTrans(ut
);
1733 * Deletes old information from the database for a particular dump path
1734 * and volumset. This supercedes the old policy implemented in
1735 * UseTape, which simply matched on the volumeset.dump. Consequently
1736 * it was unable to handle name re-use.
1738 * dsname - dumpset name, i.e. volumeset.dumpname
1739 * dumpPath - full path of dump node
1740 * curDumpID - current dump in progress - so that is may be excluded
1743 * n - some error. May or may not have deleted information.
1747 SBUDB_DeleteVDP(struct rx_call
*call
, char *dsname
, char *dumpPath
,
1748 afs_int32 curDumpId
)
1752 code
= DeleteVDP(call
, dsname
, dumpPath
, curDumpId
);
1753 osi_auditU(call
, BUDB_DelVDPEvent
, code
, AUD_STR
, dsname
, AUD_END
);
1758 DeleteVDP(struct rx_call
*call
, char *dsname
, char *dumpPath
,
1759 afs_int32 curDumpId
)
1764 struct ubik_trans
*ut
;
1765 afs_int32 eval
, code
= 0;
1767 if (!callPermitted(call
))
1768 return BUDB_NOTPERMITTED
;
1771 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1775 eval
= ht_LookupEntry(ut
, &db
.dumpName
, dsname
, &dumpAddr
, &dump
);
1779 while (dumpAddr
!= 0) { /*wd */
1780 if ((strcmp(dump
.dumpName
, dsname
) == 0)
1781 && (strcmp(dump
.dumpPath
, dumpPath
) == 0)
1782 && (ntohl(dump
.id
) != curDumpId
)) {
1783 eval
= ubik_EndTrans(ut
);
1787 eval
= deleteDump(call
, ntohl(dump
.id
), 0);
1791 /* start the traversal over since the various chains may
1797 dumpAddr
= ntohl(dump
.nameHashChain
);
1799 eval
= dbread(ut
, dumpAddr
, &dump
, sizeof(dump
));
1805 /* check if all the dumps have been examined - can terminate */
1807 eval
= ubik_EndTrans(ut
);
1813 ubik_AbortTrans(ut
);
1819 * Given a volume name, and a dumpID, find the volume in that dump and
1820 * return the clone date of the volume (this is the clone date of the
1821 * volume at the time it was dumped).
1823 * Hashes on the volume name and traverses the fragments. Will need to read
1824 * the volumes tape entry to determine if it belongs to the dump. If the
1825 * volume is not found in the dump, then look for it in its parent dump.
1829 SBUDB_FindClone(struct rx_call
*call
, afs_int32 dumpID
, char *volName
,
1830 afs_int32
*clonetime
)
1834 code
= FindClone(call
, dumpID
, volName
, clonetime
);
1835 osi_auditU(call
, BUDB_FndClnEvent
, code
, AUD_STR
, volName
, AUD_END
);
1840 FindClone(struct rx_call
*call
, afs_int32 dumpID
, char *volName
,
1841 afs_int32
*clonetime
)
1843 struct ubik_trans
*ut
;
1844 dbadr da
, hvia
, via
, vfa
;
1847 struct volFragment vf
;
1849 int rvi
; /* read the volInfo struct */
1850 afs_int32 eval
, code
= 0;
1852 if (!callPermitted(call
))
1853 return BUDB_NOTPERMITTED
;
1855 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1861 /* Search for the volume by name */
1862 eval
= ht_LookupEntry(ut
, &db
.volName
, volName
, &hvia
, &vi
);
1866 ABORT(BUDB_NOVOLUMENAME
);
1869 /* Follw the dump levels up */
1870 for (; dumpID
; dumpID
= ntohl(d
.parent
)) { /*d */
1871 /* Get the dump entry */
1872 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dumpID
, &da
, &d
);
1876 ABORT(BUDB_NODUMPID
);
1878 /* seach all the volInfo entries on the sameNameChain */
1879 for (via
= hvia
; via
; via
= ntohl(vi
.sameNameChain
)) { /*via */
1880 if (rvi
) { /* Read the volInfo entry - except first time */
1881 eval
= dbread(ut
, via
, &vi
, sizeof(vi
));
1887 /* search all the volFrag entries on the volFrag */
1888 for (vfa
= ntohl(vi
.firstFragment
); vfa
; vfa
= ntohl(vf
.sameNameChain
)) { /*vfa */
1889 eval
= dbread(ut
, vfa
, &vf
, sizeof(vf
)); /* Read the volFrag entry */
1893 eval
= dbread(ut
, ntohl(vf
.tape
), &t
, sizeof(t
)); /* Read the tape */
1897 /* Now check to see if this fragment belongs to the dump we have */
1898 if (ntohl(t
.dump
) == da
) {
1899 *clonetime
= ntohl(vf
.clone
); /* return the clone */
1907 code
= ubik_EndTrans(ut
);
1917 * Searches each tape and each volume in the dump until the volume is found.
1918 * If the volume is not in the dump, then we search it's parent dump.
1920 * Re-write to do lookups by volume name.
1923 FindClone(struct rx_call
*call
, afs_int32 dumpID
, char *volName
,
1924 afs_int32
*clonetime
)
1926 struct ubik_trans
*ut
;
1927 dbadr diskAddr
, tapeAddr
, volFragmentAddr
;
1930 struct volFragment volFragment
;
1931 struct volInfo volInfo
;
1932 afs_int32 eval
, code
= 0;
1934 if (!callPermitted(call
))
1935 return BUDB_NOTPERMITTED
;
1937 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1943 for (; dumpID
; dumpID
= ntohl(dump
.parent
)) { /*d */
1944 /* Get the dump entry */
1945 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dumpID
, &diskAddr
, &dump
);
1949 ABORT(BUDB_NODUMPID
);
1951 /* just to be sure */
1952 if (ntohl(dump
.id
) != dumpID
) {
1953 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID
,
1955 ABORT(BUDB_INTERNALERROR
);
1958 /* search all the tapes in this dump */
1959 for (tapeAddr
= ntohl(dump
.firstTape
); tapeAddr
; tapeAddr
= ntohl(tape
.nextTape
)) { /*t */
1960 /* Get the tape entry */
1961 eval
= dbread(ut
, tapeAddr
, &tape
, sizeof(tape
));
1965 /* search all the volume fragments on this tape */
1966 for (volFragmentAddr
= ntohl(tape
.firstVol
); volFragmentAddr
; volFragmentAddr
= ntohl(volFragment
.sameTapeChain
)) { /*vf */
1967 /* Get the volume fragment entry */
1969 dbread(ut
, volFragmentAddr
, &volFragment
,
1970 sizeof(volFragment
));
1974 /* Get the volume info entry */
1976 dbread(ut
, ntohl(volFragment
.vol
), &volInfo
,
1981 /* check if this volume is the one we want */
1982 if (strcmp(volInfo
.name
, volName
) == 0) {
1983 *clonetime
= ntohl(volFragment
.clone
);
1991 code
= ubik_EndTrans(ut
);
2001 * Find latest volume dump before adate.
2002 * Used by restore code when restoring a user requested volume(s)
2004 * volumeName - name of volume to match on
2005 * beforeDate - look for dumps older than this date
2007 * deptr - descriptor of most recent dump
2011 SBUDB_FindDump(struct rx_call
*call
, char *volumeName
, afs_int32 beforeDate
,
2012 struct budb_dumpEntry
*deptr
)
2016 code
= FindDump(call
, volumeName
, beforeDate
, deptr
);
2017 osi_auditU(call
, BUDB_FndDmpEvent
, code
, AUD_STR
, volumeName
, AUD_END
);
2022 FindDump(struct rx_call
*call
, char *volumeName
, afs_int32 beforeDate
,
2023 struct budb_dumpEntry
*deptr
)
2025 struct ubik_trans
*ut
;
2026 dbadr volInfoAddr
, volFragmentAddr
;
2028 struct volInfo volInfo
;
2029 struct volFragment volFragment
;
2031 dbadr selectedDumpAddr
= 0;
2032 afs_int32 selectedDate
= 0;
2033 afs_int32 volCloned
;
2035 afs_int32 eval
, code
= 0;
2037 if (!callPermitted(call
))
2038 return BUDB_NOTPERMITTED
;
2040 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2044 /* Find volinfo struct for volume name in hash table */
2046 ht_LookupEntry(ut
, &db
.volName
, volumeName
, &volInfoAddr
, &volInfo
);
2050 ABORT(BUDB_NOVOLUMENAME
);
2052 /* Step through all the volinfo structures on the same name chain.
2053 * No need to read the first - we read it above.
2055 for (rvoli
= 0; volInfoAddr
;
2056 rvoli
= 1, volInfoAddr
= ntohl(volInfo
.sameNameChain
)) {
2057 if (rvoli
) { /* read the volinfo structure */
2058 eval
= dbread(ut
, volInfoAddr
, &volInfo
, sizeof(volInfo
));
2063 /* step through the volfrag structures */
2064 for (volFragmentAddr
= ntohl(volInfo
.firstFragment
); volFragmentAddr
;
2065 volFragmentAddr
= ntohl(volFragment
.sameNameChain
)) {
2066 /* read the volfrag struct */
2068 dbread(ut
, volFragmentAddr
, &volFragment
,
2069 sizeof(volFragment
));
2073 volCloned
= ntohl(volFragment
.clone
);
2075 /* now we can examine the date for most recent dump */
2076 if ((volCloned
> selectedDate
) && (volCloned
< beforeDate
)) {
2077 /* from the volfrag struct, read the tape struct */
2079 dbread(ut
, ntohl(volFragment
.tape
), &tape
, sizeof(tape
));
2083 selectedDate
= volCloned
;
2084 selectedDumpAddr
= ntohl(tape
.dump
);
2089 if (!selectedDumpAddr
)
2092 eval
= FillDumpEntry(ut
, selectedDumpAddr
, deptr
);
2096 code
= ubik_EndTrans(ut
);
2104 /* BUDB_FindLatestDump
2105 * Find the latest dump of volumeset vsname with dump name dname.
2107 * vsname - volumeset name
2112 SBUDB_FindLatestDump(struct rx_call
*call
, char *vsname
, char *dumpPath
,
2113 struct budb_dumpEntry
*dumpentry
)
2117 code
= FindLatestDump(call
, vsname
, dumpPath
, dumpentry
);
2118 osi_auditU(call
, BUDB_FndLaDEvent
, code
, AUD_STR
, vsname
, AUD_END
);
2123 FindLatestDump(struct rx_call
*call
, char *vsname
, char *dumpPath
,
2124 struct budb_dumpEntry
*dumpentry
)
2126 struct ubik_trans
*ut
;
2127 dbadr curdbaddr
, retdbaddr
, firstdbaddr
;
2130 char dumpName
[BU_MAXNAMELEN
+ 2];
2131 afs_int32 eval
, code
= 0;
2133 if (!callPermitted(call
))
2134 return BUDB_NOTPERMITTED
;
2136 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2140 if ((strcmp(vsname
, "") == 0) && (strcmp(dumpPath
, "") == 0)) {
2141 /* Construct a database dump name */
2142 strcpy(dumpName
, DUMP_TAPE_NAME
);
2143 } else if (strchr(dumpPath
, '/') == 0) {
2144 int level
, old
, length
, hash
;
2145 struct dump hostDump
, diskDump
;
2146 struct memoryHashTable
*mht
;
2149 afs_uint32 bestDumpId
= 0;
2151 level
= atoi(dumpPath
);
2153 ABORT(BUDB_BADARGUMENT
);
2156 /* Brute force search of all the dumps in the database - yuck! */
2159 mht
= ht_GetType(HT_dumpIden_FUNCTION
, &entrySize
);
2161 ABORT(BUDB_BADARGUMENT
);
2163 for (old
= 0; old
<= 1; old
++) { /*fo */
2164 length
= (old
? mht
->oldLength
: mht
->length
);
2168 for (hash
= 0; hash
< length
; hash
++) {
2170 for (dbAddr
= ht_LookupBucket(ut
, mht
, hash
, old
); dbAddr
;
2171 dbAddr
= hostDump
.idHashChain
) {
2173 eval
= dbread(ut
, dbAddr
, &diskDump
, sizeof(diskDump
));
2176 dump_ntoh(&diskDump
, &hostDump
);
2178 if ((strcmp(hostDump
.volumeSet
, vsname
) == 0) && /* the volumeset */
2179 (hostDump
.level
== level
) && /* same level */
2180 (hostDump
.id
> bestDumpId
)) { /* more recent */
2181 bestDumpId
= hostDump
.id
;
2188 ABORT(BUDB_NODUMPNAME
);
2192 /* construct the name of the dump */
2193 if ((strlen(vsname
) + strlen(tailCompPtr(dumpPath
))) > BU_MAXNAMELEN
)
2194 ABORT(BUDB_NODUMPNAME
);
2196 strcpy(dumpName
, vsname
);
2197 strcat(dumpName
, ".");
2198 strcat(dumpName
, tailCompPtr(dumpPath
));
2201 LogDebug(5, "lookup on :%s:\n", dumpName
);
2203 /* Lookup on dumpname in hash table */
2204 eval
= ht_LookupEntry(ut
, &db
.dumpName
, dumpName
, &firstdbaddr
, &d
);
2211 /* folow remaining dumps in hash chain, looking for most latest dump */
2212 for (curdbaddr
= firstdbaddr
; curdbaddr
;
2213 curdbaddr
= ntohl(d
.nameHashChain
)) {
2214 if (curdbaddr
!= firstdbaddr
) {
2215 eval
= dbread(ut
, curdbaddr
, &d
, sizeof(d
));
2220 if ((strcmp(d
.dumpPath
, dumpPath
) == 0) && /* Same dumppath */
2221 (strcmp(d
.dumpName
, dumpName
) == 0) && /* Same dumpname */
2222 (ntohl(d
.created
) > latest
)) { /* most recent */
2223 latest
= ntohl(d
.created
);
2224 retdbaddr
= curdbaddr
;
2228 ABORT(BUDB_NODUMPNAME
);
2231 /* return the dump found */
2232 FillDumpEntry(ut
, retdbaddr
, dumpentry
);
2234 code
= ubik_EndTrans(ut
);
2238 ubik_AbortTrans(ut
);
2244 SBUDB_FinishDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
2248 code
= FinishDump(call
, dump
);
2249 osi_auditU(call
, BUDB_FinDmpEvent
, code
, AUD_DATE
, (dump
? dump
->id
: 0),
2255 FinishDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
2257 struct ubik_trans
*ut
;
2260 afs_int32 eval
, code
= 0;
2262 if (!callPermitted(call
))
2263 return BUDB_NOTPERMITTED
;
2265 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
2269 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dump
->id
, &a
, &d
);
2273 ABORT(BUDB_NODUMPID
);
2275 if ((ntohl(d
.flags
) & BUDB_DUMP_INPROGRESS
) == 0)
2276 ABORT(BUDB_DUMPNOTINUSE
);
2278 d
.flags
= htonl(dump
->flags
& ~BUDB_DUMP_INPROGRESS
);
2280 /* if creation time specified set it */
2282 d
.created
= htonl(dump
->created
);
2283 dump
->created
= ntohl(d
.created
);
2285 /* Write the dump entry out */
2286 eval
= dbwrite(ut
, a
, &d
, sizeof(d
));
2290 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
2294 code
= ubik_EndTrans(ut
);
2298 ubik_AbortTrans(ut
);
2303 SBUDB_FinishTape(struct rx_call
*call
, struct budb_tapeEntry
*tape
)
2307 code
= FinishTape(call
, tape
);
2308 osi_auditU(call
, BUDB_FinTpeEvent
, code
, AUD_DATE
,
2309 (tape
? tape
->dump
: 0), AUD_END
);
2314 FinishTape(struct rx_call
*call
, struct budb_tapeEntry
*tape
)
2316 struct ubik_trans
*ut
;
2320 afs_int32 eval
, code
= 0;
2322 if (!callPermitted(call
))
2323 return BUDB_NOTPERMITTED
;
2325 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
2329 /* find the tape struct in the tapename hash chain */
2330 eval
= ht_LookupEntry(ut
, &db
.tapeName
, tape
->name
, &a
, &t
);
2334 ABORT(BUDB_NOTAPENAME
);
2336 /* Read the dump structure */
2337 eval
= dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
));
2341 /* search for the right tape on the rest of the chain */
2342 while (ntohl(d
.id
) != tape
->dump
) {
2343 a
= ntohl(t
.nameHashChain
);
2345 ABORT(BUDB_NOTAPENAME
);
2347 eval
= dbread(ut
, a
, &t
, sizeof(t
));
2351 eval
= dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
));
2356 if ((ntohl(t
.flags
) & BUDB_TAPE_BEINGWRITTEN
) == 0)
2357 ABORT(BUDB_TAPENOTINUSE
);
2359 /* t.nBytes = htonl(tape->nBytes); */
2360 t
.nFiles
= htonl(tape
->nFiles
);
2361 t
.useKBytes
= htonl(tape
->useKBytes
);
2362 t
.flags
= htonl(tape
->flags
& ~BUDB_TAPE_BEINGWRITTEN
);
2364 eval
= dbwrite(ut
, a
, &t
, sizeof(t
));
2368 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
2372 code
= ubik_EndTrans(ut
);
2376 ubik_AbortTrans(ut
);
2381 * return a set of dumps that match the specified criteria
2384 * majorVersion - version of interface structures. Permits compatibility
2386 * flags - for search and select operations. Broken down into flags
2387 * for name, start point, end point and time.
2388 * name - name to search for. Interpretation based on flags
2395 * dbTimeP - time at which the database was last modified. Up to
2396 * caller (client) to take appropriate action if database
2397 * modified between successive calls
2398 * dumps - list of matching dumps
2400 * currently supported are:
2406 SBUDB_GetDumps(struct rx_call
*call
,
2407 afs_int32 majorVersion
, /* version of interface structures */
2408 afs_int32 flags
, /* search & select controls */
2409 char *name
, /* s&s parameters */
2412 afs_int32 index
, /* start index of returned entries */
2413 afs_int32
*nextIndexP
, /* output index for next call */
2415 budb_dumpList
*dumps
) /* pointer to buffer */
2420 GetDumps(call
, majorVersion
, flags
, name
, start
, end
, index
,
2421 nextIndexP
, dbTimeP
, dumps
);
2422 osi_auditU(call
, BUDB_GetDmpEvent
, code
, AUD_END
);
2427 GetDumps(struct rx_call
*call
,
2428 afs_int32 majorVersion
, /* version of interface structures */
2429 afs_int32 flags
, /* search & select controls */
2430 char *name
, /* s&s parameters */
2433 afs_int32 index
, /* start index of returned entries */
2434 afs_int32
*nextIndexP
, /* output index for next call */
2436 budb_dumpList
*dumps
) /* pointer to buffer */
2438 struct ubik_trans
*ut
;
2441 afs_int32 nameFlags
, startFlags
, endFlags
, timeFlags
;
2442 afs_int32 eval
, code
= 0;
2444 struct returnList list
;
2446 /* Don't check permissions when we look up a specific dump id */
2447 if (((flags
& BUDB_OP_STARTS
) != BUDB_OP_DUMPID
) && !callPermitted(call
))
2448 return BUDB_NOTPERMITTED
;
2450 if (majorVersion
!= BUDB_MAJORVERSION
)
2451 return BUDB_OLDINTERFACE
;
2453 return BUDB_ENDOFLIST
;
2455 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2459 nameFlags
= flags
& BUDB_OP_NAMES
;
2460 startFlags
= flags
& BUDB_OP_STARTS
;
2461 endFlags
= flags
& BUDB_OP_ENDS
;
2462 timeFlags
= flags
& BUDB_OP_TIMES
;
2464 InitReturnList(&list
);
2467 if (nameFlags
== BUDB_OP_DUMPNAME
) {
2468 /* not yet implemented */
2469 if (startFlags
|| endFlags
|| timeFlags
)
2470 ABORT(BUDB_BADFLAGS
);
2472 eval
= ht_LookupEntry(ut
, &db
.dumpName
, name
, &da
, &d
);
2476 ABORT(BUDB_NODUMPNAME
);
2479 if (strcmp(d
.dumpName
, name
) == 0) {
2480 eval
= AddToReturnList(&list
, da
, &toskip
);
2481 if (eval
== BUDB_LIST2BIG
)
2487 da
= ntohl(d
.nameHashChain
); /* get next dump w/ name */
2491 eval
= dbread(ut
, da
, &d
, sizeof(d
));
2495 } else if (nameFlags
== BUDB_OP_VOLUMENAME
) {
2499 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2500 ABORT(BUDB_BADFLAGS
);
2503 if (startFlags
!= BUDB_OP_STARTTIME
)
2504 ABORT(BUDB_BADFLAGS
);
2506 /* lookup a dump by volumename and time stamp. Find the most recent
2507 * dump of the specified volumename, that occured before the supplied
2511 /* get us a volInfo for name */
2512 eval
= ht_LookupEntry(ut
, &db
.volName
, name
, &da
, &vi
);
2517 /* now iterate over all the entries of this name */
2518 for (va
= vi
.firstFragment
; va
!= 0; va
= v
.sameNameChain
) {
2520 eval
= dbread(ut
, va
, &v
, sizeof(v
));
2525 on fragment
> date ignore it
- too recent
;
2527 if (date on fragment
< date
&& date on fragment
> bestfound
)
2528 bestfound
= date on fragment
;
2532 da
= vi
.sameNameChain
;
2536 eval
= dbread(ut
, da
, &vi
, sizeof(vi
));
2545 from saved volfragment address, compute dump.
2546 otherwise, return dump found
2551 } else if (startFlags
== BUDB_OP_DUMPID
) {
2552 if (endFlags
|| timeFlags
)
2553 ABORT(BUDB_BADFLAGS
);
2555 ABORT(BUDB_BADFLAGS
); /* NYI */
2557 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &start
, &da
, &d
);
2561 ABORT(BUDB_NODUMPID
);
2563 eval
= AddToReturnList(&list
, da
, &toskip
);
2566 } else if (endFlags
== BUDB_OP_NPREVIOUS
) {
2567 struct wantDumpRock rock
;
2568 struct chosenDump
*ptr
, *nextPtr
;
2570 /* no other flags should be set */
2572 /* end specifies how many dumps */
2574 ABORT(BUDB_BADFLAGS
);
2576 memset(&rock
, 0, sizeof(rock
));
2577 rock
.maxDumps
= end
;
2579 scanHashTable(ut
, &db
.dumpName
, wantDump
, rememberDump
,
2582 for (ptr
= rock
.chain
; ptr
; ptr
= nextPtr
) {
2583 nextPtr
= ptr
->next
;
2584 AddToReturnList(&list
, ptr
->addr
, &toskip
); /* ignore error for free */
2588 ABORT(BUDB_BADFLAGS
);
2592 SendReturnList(ut
, &list
, FillDumpEntry
,
2593 sizeof(struct budb_dumpEntry
), index
, nextIndexP
,
2594 dbTimeP
, (returnList_t
) dumps
);
2598 FreeReturnList(&list
);
2599 code
= ubik_EndTrans(ut
);
2603 FreeReturnList(&list
);
2604 ubik_AbortTrans(ut
);
2609 * Get the expiration of a tape. Since the dump could have appended dumps,
2610 * we should use the most recent expiration date. Put the most recent
2611 * expiration tape into the given tape structure.
2614 getExpiration(struct ubik_trans
*ut
, struct tape
*tapePtr
)
2620 afs_int32 eval
, code
= 0;
2625 /* Get the dump for this tape */
2626 ad
= ntohl(tapePtr
->dump
);
2627 eval
= dbread(ut
, ad
, &d
, sizeof(d
));
2631 /* If not an initial dump, get the initial dump */
2632 if (d
.initialDumpID
) {
2633 initDump
= ntohl(d
.initialDumpID
);
2634 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &initDump
, &ad
, &d
);
2639 /* Cycle through the dumps and appended dumps */
2641 /* Get the first tape in this dump. No need to check the rest of the tapes */
2642 /* for this dump since they will all have the same expiration date */
2643 eval
= dbread(ut
, ntohl(d
.firstTape
), &t
, sizeof(t
));
2647 /* Take the greater of the expiration dates */
2648 if (ntohl(tapePtr
->expires
) < ntohl(t
.expires
))
2649 tapePtr
->expires
= t
.expires
;
2651 /* Step to and read the next appended dump */
2652 if ((ad
= ntohl(d
.appendedDumpChain
))) {
2653 eval
= dbread(ut
, ad
, &d
, sizeof(d
));
2663 /* Mark the following dump as appended to another, intial dump */
2665 makeAppended(struct ubik_trans
*ut
, afs_int32 appendedDumpID
,
2666 afs_int32 initialDumpID
, afs_int32 startTapeSeq
)
2668 dbadr ada
, da
, lastDumpAddr
;
2670 afs_int32 eval
, code
= 0;
2674 if (appendedDumpID
== initialDumpID
)
2675 ERROR(BUDB_INTERNALERROR
);
2677 /* If there is an initial dump, append this dump to it */
2678 /* Find the appended dump via its id */
2679 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &appendedDumpID
, &ada
, &ad
);
2683 /* If the dump is already marked as appended,
2684 * then we have an internal error.
2686 if (ad
.initialDumpID
) {
2687 if (ntohl(ad
.initialDumpID
) != initialDumpID
)
2688 ERROR(BUDB_INTERNALERROR
);
2691 /* Update the appended dump to point to the initial dump */
2692 ad
.initialDumpID
= htonl(initialDumpID
);
2693 ad
.tapes
.b
= htonl(startTapeSeq
);
2695 /* find the initial dump via its id */
2696 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &initialDumpID
, &da
, &d
);
2700 /* Update the appended dump's tape format with that of the initial */
2701 strcpy(ad
.tapes
.format
, d
.tapes
.format
);
2703 /* starting with the initial dump step through its appended dumps till
2704 * we reach the last appended dump.
2707 while (d
.appendedDumpChain
) {
2708 lastDumpAddr
= ntohl(d
.appendedDumpChain
);
2709 if (lastDumpAddr
== ada
)
2710 ERROR(0); /* Already appended */
2711 eval
= dbread(ut
, lastDumpAddr
, &d
, sizeof(d
));
2716 /* Update the last dump to point to our new appended dump.
2717 * The appended dump is the last one in the dump chain.
2719 d
.appendedDumpChain
= htonl(ada
);
2720 ad
.appendedDumpChain
= 0;
2722 /* Write the appended dump and the initial dump */
2723 eval
= dbwrite(ut
, ada
, (char *)&ad
, sizeof(ad
));
2727 eval
= dbwrite(ut
, lastDumpAddr
, (char *)&d
, sizeof(d
));
2731 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
2740 SBUDB_MakeDumpAppended(struct rx_call
*call
, afs_int32 appendedDumpID
,
2741 afs_int32 initialDumpID
, afs_int32 startTapeSeq
)
2746 MakeDumpAppended(call
, appendedDumpID
, initialDumpID
, startTapeSeq
);
2747 osi_auditU(call
, BUDB_AppDmpEvent
, code
, AUD_LONG
, appendedDumpID
,
2753 MakeDumpAppended(struct rx_call
*call
, afs_int32 appendedDumpID
,
2754 afs_int32 initialDumpID
, afs_int32 startTapeSeq
)
2756 struct ubik_trans
*ut
;
2757 afs_int32 eval
, code
= 0;
2759 if (!callPermitted(call
))
2760 return BUDB_NOTPERMITTED
;
2762 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
2766 eval
= makeAppended(ut
, appendedDumpID
, initialDumpID
, startTapeSeq
);
2770 code
= ubik_EndTrans(ut
);
2774 ubik_AbortTrans(ut
);
2778 /* Find the last tape of a dump-set. This includes any appended dumps */
2780 SBUDB_FindLastTape(struct rx_call
*call
, afs_int32 dumpID
,
2781 struct budb_dumpEntry
*dumpEntry
,
2782 struct budb_tapeEntry
*tapeEntry
,
2783 struct budb_volumeEntry
*volEntry
)
2787 code
= FindLastTape(call
, dumpID
, dumpEntry
, tapeEntry
, volEntry
);
2788 osi_auditU(call
, BUDB_FndLTpeEvent
, code
, AUD_LONG
, dumpID
, AUD_END
);
2793 FindLastTape(struct rx_call
*call
, afs_int32 dumpID
,
2794 struct budb_dumpEntry
*dumpEntry
,
2795 struct budb_tapeEntry
*tapeEntry
,
2796 struct budb_volumeEntry
*volEntry
)
2798 struct ubik_trans
*ut
;
2802 dbadr lastTape
, thisTape
;
2803 afs_int32 lastTapeSeq
;
2804 struct volFragment vf
;
2805 dbadr lastVol
, thisVol
;
2806 afs_int32 lastVolPos
;
2807 afs_int32 eval
, code
= 0;
2809 if (!callPermitted(call
))
2810 return BUDB_NOTPERMITTED
;
2813 return (BUDB_BADARGUMENT
);
2815 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2819 /* find and read its initial dump via its id */
2820 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dumpID
, &lastDump
, &d
);
2824 ABORT(BUDB_NODUMPID
);
2826 /* Follow the append dumps link chain until we reach the last dump */
2827 while (d
.appendedDumpChain
) {
2828 lastDump
= ntohl(d
.appendedDumpChain
);
2829 eval
= dbread(ut
, lastDump
, &d
, sizeof(d
));
2834 /* We now have the last dump of the last appended dump */
2835 /* Copy this into our return structure */
2836 eval
= FillDumpEntry(ut
, lastDump
, dumpEntry
);
2840 /* Fail if the last dump has no tapes */
2842 ABORT(BUDB_NOTAPENAME
);
2844 /* Follow the tapes in this dump until we reach the last tape */
2845 eval
= dbread(ut
, ntohl(d
.firstTape
), &t
, sizeof(t
));
2849 lastTape
= ntohl(d
.firstTape
);
2850 lastTapeSeq
= ntohl(t
.seq
);
2851 lastVol
= ntohl(t
.firstVol
);
2853 while (t
.nextTape
) {
2854 thisTape
= ntohl(t
.nextTape
);
2855 eval
= dbread(ut
, thisTape
, &t
, sizeof(t
));
2859 if (ntohl(t
.seq
) > lastTapeSeq
) {
2860 lastTape
= thisTape
;
2861 lastTapeSeq
= ntohl(t
.seq
);
2862 lastVol
= ntohl(t
.firstVol
);
2866 /* We now have the last tape of the last appended dump */
2867 /* Copy this into our return structure */
2868 eval
= FillTapeEntry(ut
, lastTape
, tapeEntry
);
2872 /* Zero volume entry if the last tape has no volumes */
2874 memset(volEntry
, 0, sizeof(*volEntry
));
2876 /* Follow the volumes until we reach the last volume */
2877 eval
= dbread(ut
, lastVol
, &vf
, sizeof(vf
));
2881 lastVolPos
= vf
.position
;
2883 while (vf
.sameTapeChain
) {
2884 thisVol
= ntohl(vf
.sameTapeChain
);
2885 eval
= dbread(ut
, thisVol
, &vf
, sizeof(vf
));
2889 if (vf
.position
> lastVolPos
) {
2891 lastVolPos
= vf
.position
;
2895 /* We now have the last volume of this tape */
2896 /* Copy this into our return structure */
2897 eval
= FillVolEntry(ut
, lastVol
, volEntry
);
2902 eval
= ubik_EndTrans(ut
);
2908 ubik_AbortTrans(ut
);
2914 SBUDB_GetTapes(struct rx_call
*call
,
2915 afs_int32 majorVersion
, /* version of interface structures */
2916 afs_int32 flags
, /* search & select controls */
2917 char *name
, /* s&s parameters */
2919 afs_int32 end
, /* reserved: MBZ */
2920 afs_int32 index
, /* start index of returned entries */
2921 afs_int32
*nextIndexP
, /* output index for next call */
2923 budb_tapeList
*tapes
) /* pointer to buffer */
2928 GetTapes(call
, majorVersion
, flags
, name
, start
, end
, index
,
2929 nextIndexP
, dbTimeP
, tapes
);
2930 osi_auditU(call
, BUDB_GetTpeEvent
, code
, AUD_END
);
2935 GetTapes(struct rx_call
*call
,
2936 afs_int32 majorVersion
, /* version of interface structures */
2937 afs_int32 flags
, /* search & select controls */
2938 char *name
, /* s&s parameters */
2940 afs_int32 end
, /* reserved: MBZ */
2941 afs_int32 index
, /* start index of returned entries */
2942 afs_int32
*nextIndexP
, /* output index for next call */
2944 budb_tapeList
*tapes
) /* pointer to buffer */
2946 struct ubik_trans
*ut
;
2950 afs_int32 nameFlags
, startFlags
, endFlags
, timeFlags
;
2951 struct returnList list
;
2952 afs_int32 eval
, code
= 0;
2955 if (!callPermitted(call
))
2956 return BUDB_NOTPERMITTED
;
2958 if (majorVersion
!= BUDB_MAJORVERSION
)
2959 return BUDB_OLDINTERFACE
;
2962 return BUDB_ENDOFLIST
;
2964 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2968 nameFlags
= flags
& BUDB_OP_NAMES
;
2969 startFlags
= flags
& BUDB_OP_STARTS
;
2970 endFlags
= flags
& BUDB_OP_ENDS
;
2971 timeFlags
= flags
& BUDB_OP_TIMES
;
2973 InitReturnList(&list
);
2976 if (nameFlags
== BUDB_OP_TAPENAME
) { /*it */
2977 eval
= ht_LookupEntry(ut
, &db
.tapeName
, name
, &ta
, &t
);
2981 ABORT(BUDB_NOTAPENAME
);
2984 if ((startFlags
& ~BUDB_OP_DUMPID
) || endFlags
|| timeFlags
)
2985 ABORT(BUDB_BADFLAGS
);
2987 /* follow the hash chain to the end */
2989 if (startFlags
& BUDB_OP_DUMPID
) {
2990 /* read in the dump */
2991 eval
= dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
));
2995 /* check if both name and dump id match */
2996 if ((strcmp(name
, t
.name
) == 0) && (ntohl(d
.id
) == start
)) {
2997 eval
= AddToReturnList(&list
, ta
, &toskip
);
2998 if (eval
&& (eval
!= BUDB_LIST2BIG
))
3003 /* Add to return list and continue search */
3004 if (strcmp(name
, t
.name
) == 0) {
3005 eval
= AddToReturnList(&list
, ta
, &toskip
);
3006 if (eval
== BUDB_LIST2BIG
)
3013 ta
= ntohl(t
.nameHashChain
);
3015 dbread(ut
, ta
, &t
, sizeof(t
));
3018 else if (nameFlags
== BUDB_OP_TAPESEQ
) {
3019 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &start
, &da
, &d
);
3023 ABORT(BUDB_NODUMPNAME
);
3025 /* search for the right tape */
3026 ta
= ntohl(d
.firstTape
);
3027 for (ta
= ntohl(d
.firstTape
); ta
; ta
= ntohl(t
.nextTape
)) {
3028 eval
= dbread(ut
, ta
, &t
, sizeof(t
));
3032 if (ntohl(t
.seq
) == end
) {
3033 eval
= AddToReturnList(&list
, ta
, &toskip
);
3034 if (eval
&& (eval
!= BUDB_LIST2BIG
))
3040 ABORT(BUDB_BADFLAGS
);
3044 SendReturnList(ut
, &list
, FillTapeEntry
,
3045 sizeof(struct budb_tapeEntry
), index
, nextIndexP
,
3046 dbTimeP
, (returnList_t
) tapes
);
3050 FreeReturnList(&list
);
3051 code
= ubik_EndTrans(ut
);
3055 FreeReturnList(&list
);
3056 ubik_AbortTrans(ut
);
3061 * get a set of volumes according to the specified criteria.
3062 * See BUDB_GetDumps for general information on parameters
3063 * Currently supports:
3064 * 1) volume match - returns volumes based on volume name only.
3065 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
3066 * and start is a dumpid. Returns all volumes of the specified
3067 * name on the selected dumpid.
3071 SBUDB_GetVolumes(struct rx_call
*call
,
3072 afs_int32 majorVersion
, /* version of interface structures */
3073 afs_int32 flags
, /* search & select controls */
3074 char *name
, /* - parameters for search */
3075 afs_int32 start
, /* - usage depends which BUDP_OP */
3076 afs_int32 end
, /* - bits are set */
3077 afs_int32 index
, /* start index of returned entries */
3078 afs_int32
*nextIndexP
, /* output index for next call */
3080 budb_volumeList
*volumes
) /* pointer to buffer */
3085 GetVolumes(call
, majorVersion
, flags
, name
, start
, end
, index
,
3086 nextIndexP
, dbTimeP
, volumes
);
3087 osi_auditU(call
, BUDB_GetVolEvent
, code
, AUD_END
);
3092 GetVolumes(struct rx_call
*call
,
3093 afs_int32 majorVersion
, /* version of interface structures */
3094 afs_int32 flags
, /* search & select controls */
3095 char *name
, /* - parameters for search */
3096 afs_int32 start
, /* - usage depends which BUDP_OP_* */
3097 afs_int32 end
, /* - bits are set */
3098 afs_int32 index
, /* start index of returned entries */
3099 afs_int32
*nextIndexP
, /* output index for next call */
3101 budb_volumeList
*volumes
) /* pointer to buffer */
3103 struct ubik_trans
*ut
;
3106 afs_int32 nameFlags
, startFlags
, endFlags
, timeFlags
;
3107 afs_int32 eval
, code
= 0;
3108 struct returnList vollist
;
3111 /* Don't check permissions when we look up a specific volume name */
3112 if (((flags
& BUDB_OP_NAMES
) != BUDB_OP_VOLUMENAME
)
3113 && !callPermitted(call
))
3114 return BUDB_NOTPERMITTED
;
3116 if (majorVersion
!= BUDB_MAJORVERSION
)
3117 return BUDB_OLDINTERFACE
;
3119 return BUDB_ENDOFLIST
;
3121 eval
= InitRPC(&ut
, LOCKREAD
, 1);
3125 nameFlags
= flags
& BUDB_OP_NAMES
;
3126 startFlags
= flags
& BUDB_OP_STARTS
;
3127 endFlags
= flags
& BUDB_OP_ENDS
;
3128 timeFlags
= flags
& BUDB_OP_TIMES
;
3130 InitReturnList(&vollist
);
3133 /* lookup a the volume (specified by name) in the dump (specified by id) */
3134 if (nameFlags
== BUDB_OP_VOLUMENAME
) {
3135 /* dumpid permissible, all others off */
3136 if (((startFlags
& ~BUDB_OP_DUMPID
) != 0) || endFlags
|| timeFlags
)
3137 ABORT(BUDB_BADFLAGS
);
3139 /* returns ptr to volinfo of requested name */
3140 eval
= ht_LookupEntry(ut
, &db
.volName
, name
, &via
, &vi
);
3144 ABORT(BUDB_NOVOLUMENAME
);
3146 /* Iterate over all volume fragments with this name */
3148 struct volFragment v
;
3151 /* traverse all the volume fragments for this volume info structure */
3152 for (va
= vi
.firstFragment
; va
; va
= v
.sameNameChain
) {
3154 eval
= dbread(ut
, va
, &v
, sizeof(v
));
3158 if (startFlags
& BUDB_OP_DUMPID
) {
3162 /* get the dump id for this fragment */
3163 eval
= dbread(ut
, ntohl(v
.tape
), &atape
, sizeof(atape
));
3168 dbread(ut
, ntohl(atape
.dump
), &adump
, sizeof(adump
));
3172 /* dump id does not match */
3173 if (ntohl(adump
.id
) != start
)
3177 eval
= AddToReturnList(&vollist
, va
, &toskip
);
3178 if (eval
== BUDB_LIST2BIG
)
3183 if (eval
== BUDB_LIST2BIG
)
3186 via
= vi
.sameNameChain
;
3191 eval
= dbread(ut
, via
, &vi
, sizeof(vi
));
3195 } else if (((nameFlags
== 0) || (nameFlags
== BUDB_OP_TAPENAME
))
3196 && (startFlags
== BUDB_OP_DUMPID
)) {
3201 struct volFragment volFrag
;
3204 /* lookup all volumes for a specified dump id */
3206 /* no other flags should be set */
3207 if (endFlags
|| timeFlags
)
3208 ABORT(BUDB_BADFLAGS
);
3211 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &start
, &dumpAddr
, &dump
);
3215 /* traverse all the tapes */
3216 for (tapeAddr
= ntohl(dump
.firstTape
); tapeAddr
; tapeAddr
= ntohl(tape
.nextTape
)) { /*w */
3217 eval
= dbread(ut
, tapeAddr
, &tape
, sizeof(tape
));
3221 if ((nameFlags
!= BUDB_OP_TAPENAME
)
3222 || ((nameFlags
== BUDB_OP_TAPENAME
)
3223 && (strcmp(tape
.name
, name
) == 0))) {
3224 /* now return all the volumes */
3225 for (volFragAddr
= ntohl(tape
.firstVol
); volFragAddr
;
3226 volFragAddr
= ntohl(volFrag
.sameTapeChain
)) {
3227 eval
= dbread(ut
, volFragAddr
, &volFrag
, sizeof(volFrag
));
3231 eval
= AddToReturnList(&vollist
, volFragAddr
, &toskip
);
3232 if (eval
== BUDB_LIST2BIG
)
3238 if (eval
== BUDB_LIST2BIG
)
3242 ABORT(BUDB_BADFLAGS
);
3246 SendReturnList(ut
, &vollist
, FillVolEntry
,
3247 sizeof(struct budb_volumeEntry
), index
, nextIndexP
,
3248 dbTimeP
, (returnList_t
) volumes
);
3253 FreeReturnList(&vollist
);
3254 code
= ubik_EndTrans(ut
);
3258 FreeReturnList(&vollist
);
3259 ubik_AbortTrans(ut
);
3264 SBUDB_UseTape(struct rx_call
*call
,
3265 struct budb_tapeEntry
*tape
, /* tape info */
3266 afs_int32
*new) /* set if tape is new */
3270 code
= UseTape(call
, tape
, new);
3271 osi_auditU(call
, BUDB_UseTpeEvent
, code
, AUD_DATE
,
3272 (tape
? tape
->dump
: 0), AUD_END
);
3277 UseTape(struct rx_call
*call
,
3278 struct budb_tapeEntry
*tape
, /* tape info */
3279 int *new) /* set if tape is new */
3281 struct ubik_trans
*ut
;
3285 afs_int32 eval
, code
;
3287 if (!callPermitted(call
))
3288 return BUDB_NOTPERMITTED
;
3290 if (strlen(tape
->name
) >= sizeof(t
.name
))
3291 return BUDB_BADARGUMENT
;
3293 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
3299 memset(&t
, 0, sizeof(t
));
3300 eval
= AllocStructure(ut
, tape_BLOCK
, 0, &a
, &t
);
3304 strcpy(t
.name
, tape
->name
);
3306 eval
= ht_HashIn(ut
, &db
.tapeName
, a
, &t
);
3312 /* Since deleting a tape may change the dump (if its the same one), read in
3313 * the dump after the call to DeleteTape. */
3315 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &tape
->dump
, &da
, &d
);
3319 ABORT(BUDB_NODUMPID
);
3322 tape
->written
= time(0); /* fill in tape struct */
3323 t
.written
= htonl(tape
->written
);
3324 t
.expires
= htonl(tape
->expires
);
3326 t
.seq
= htonl(tape
->seq
);
3327 t
.useCount
= htonl(tape
->useCount
);
3328 t
.labelpos
= htonl(tape
->labelpos
);
3330 t
.flags
= htonl(tape
->flags
| BUDB_TAPE_BEINGWRITTEN
);
3332 t
.nextTape
= d
.firstTape
; /* Chain the tape to the dump */
3333 d
.firstTape
= htonl(a
);
3335 if (tape
->seq
>= ntohl(d
.tapes
.maxTapes
)) /* inc # tapes in the dump */
3336 d
.tapes
.maxTapes
= htonl(tape
->seq
);
3338 eval
= dbwrite(ut
, a
, &t
, sizeof(t
)); /* write tape struct */
3342 eval
= dbwrite(ut
, da
, &d
, sizeof(d
)); /* write the dump struct */
3346 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
3350 LogDebug(5, "added tape %s\n", tape
->name
);
3352 code
= ubik_EndTrans(ut
);
3356 ubik_AbortTrans(ut
);
3362 /* ---------------------------------------------
3363 * debug interface routines
3364 * ---------------------------------------------
3368 SBUDB_T_DumpHashTable(struct rx_call
*call
, afs_int32 type
, char *filename
)
3372 code
= T_DumpHashTable(call
, type
, filename
);
3373 osi_auditU(call
, BUDB_TDmpHaEvent
, code
, AUD_STR
, filename
, AUD_END
);
3378 T_DumpHashTable(struct rx_call
*call
, int type
, char *filename
)
3380 struct ubik_trans
*ut
;
3381 struct memoryHashTable
*mht
;
3383 afs_int32 eval
, code
= 0;
3390 char e
[sizeof(struct block
)]; /* unnecessarily conservative */
3393 struct volInfo e_volinfo
;
3397 if (!callPermitted(call
))
3398 return BUDB_NOTPERMITTED
;
3400 if (strlen(filename
) >= sizeof(path
) - 5)
3401 return BUDB_BADARGUMENT
;
3403 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
3407 if ((mht
= ht_GetType(type
, &e_size
)) == 0)
3408 return BUDB_BADARGUMENT
;
3410 sprintf(path
, "%s/%s", gettmpdir(), filename
);
3412 DUMP
= fopen(path
, "w");
3414 ABORT(BUDB_BADARGUMENT
);
3417 for (old
= 0;; old
++) {
3418 length
= (old
? mht
->oldLength
: mht
->length
);
3420 fprintf(DUMP
, "Dumping %sHash Table:\n", (old
? "Old " : ""));
3422 for (hash
= 0; hash
< length
; hash
++) {
3423 a
= ht_LookupBucket(ut
, mht
, hash
, old
);
3426 eval
= dbread(ut
, a
, e
, e_size
);
3432 fprintf(DUMP
, " in bucket %d at %d is ", hash
, a
);
3434 fprintf(DUMP
, " at %d is ", a
);
3436 case HT_dumpIden_FUNCTION
:
3437 memcpy(&e_dump
, e
, sizeof(e_dump
));
3438 fprintf(DUMP
, "%d\n", ntohl(e_dump
.id
));
3440 case HT_dumpName_FUNCTION
:
3441 memcpy(&e_dump
, e
, sizeof(e_dump
));
3442 fprintf(DUMP
, "%s\n", e_dump
.dumpName
);
3444 case HT_tapeName_FUNCTION
:
3445 memcpy(&e_tape
, e
, sizeof(e_tape
));
3446 fprintf(DUMP
, "%s\n", e_tape
.name
);
3448 case HT_volName_FUNCTION
:
3449 memcpy(&e_volinfo
, e
, sizeof(e_volinfo
));
3450 fprintf(DUMP
, "%s\n", e_volinfo
.name
);
3453 if ((ht_HashEntry(mht
, e
) % length
) != hash
)
3454 ABORT(BUDB_DATABASEINCONSISTENT
);
3455 a
= ntohl(*(dbadr
*) (e
+ mht
->threadOffset
));
3462 fprintf(DUMP
, "%d entries found\n", ent
);
3463 if (ntohl(mht
->ht
->entries
) != ent
)
3464 ABORT(BUDB_DATABASEINCONSISTENT
);
3466 code
= ubik_EndTrans(ut
);
3472 ubik_AbortTrans(ut
);
3479 SBUDB_T_GetVersion(struct rx_call
*call
, afs_int32
*majorVersion
)
3483 code
= T_GetVersion(call
, majorVersion
);
3484 osi_auditU(call
, BUDB_TGetVrEvent
, code
, AUD_END
);
3489 T_GetVersion(struct rx_call
*call
, int *majorVersion
)
3491 struct ubik_trans
*ut
;
3494 code
= InitRPC(&ut
, LOCKREAD
, 0);
3498 *majorVersion
= BUDB_MAJORVERSION
;
3500 code
= ubik_EndTrans(ut
);
3504 /* BUDB_T_DumpDatabase
3505 * dump as much of the database as possible int /tmp/<filename>
3509 SBUDB_T_DumpDatabase(struct rx_call
*call
, char *filename
)
3513 code
= T_DumpDatabase(call
, filename
);
3514 osi_auditU(call
, BUDB_TDmpDBEvent
, code
, AUD_STR
, filename
, AUD_END
);
3519 T_DumpDatabase(struct rx_call
*call
, char *filename
)
3523 struct ubik_trans
*ut
;
3526 int type
, old
, length
, hash
;
3527 struct memoryHashTable
*mht
;
3528 afs_int32 eval
, code
= 0;
3530 if (!callPermitted(call
))
3531 return BUDB_NOTPERMITTED
;
3533 length
= asprintf(&path
, "%s/%s", gettmpdir(), filename
);
3534 if (length
< 0 || !path
)
3535 return (BUDB_INTERNALERROR
);
3537 dumpfid
= fopen(path
, "w");
3539 return (BUDB_BADARGUMENT
);
3541 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
3545 /* dump all items in the database */
3546 for (type
= 1; type
<= HT_MAX_FUNCTION
; type
++) { /*ft */
3547 mht
= ht_GetType(type
, &entrySize
);
3549 ERROR(BUDB_BADARGUMENT
);
3551 for (old
= 0; old
<= 1; old
++) { /*fo */
3552 length
= (old
? mht
->oldLength
: mht
->length
);
3556 fprintf(dumpfid
, "Dumping %s Hash Table:\n", (old
? "Old " : ""));
3558 for (hash
= 0; hash
< length
; hash
++) { /*f */
3559 dbAddr
= ht_LookupBucket(ut
, mht
, hash
, old
);
3561 while (dbAddr
) { /*w */
3562 switch (type
) { /*s */
3563 case HT_dumpIden_FUNCTION
:
3565 struct dump hostDump
, diskDump
;
3568 cdbread(ut
, dump_BLOCK
, dbAddr
, &diskDump
,
3574 "\ndumpId hash %d, entry at %u\n",
3577 "----------------------------\n");
3578 dump_ntoh(&diskDump
, &hostDump
);
3579 printDump(dumpfid
, &hostDump
);
3580 dbAddr
= hostDump
.idHashChain
;
3584 case HT_dumpName_FUNCTION
:
3586 struct dump hostDump
, diskDump
;
3589 cdbread(ut
, dump_BLOCK
, dbAddr
, &diskDump
,
3595 "\ndumpname hash %d, entry at %u\n",
3598 "----------------------------\n");
3599 dump_ntoh(&diskDump
, &hostDump
);
3600 printDump(dumpfid
, &hostDump
);
3601 dbAddr
= hostDump
.nameHashChain
;
3605 case HT_tapeName_FUNCTION
:
3607 struct tape hostTape
, diskTape
;
3610 cdbread(ut
, tape_BLOCK
, dbAddr
, &diskTape
,
3616 "\ntapename hash %d, entry at %u\n",
3619 "----------------------------\n");
3620 tape_ntoh(&diskTape
, &hostTape
);
3621 printTape(dumpfid
, &hostTape
);
3622 dbAddr
= hostTape
.nameHashChain
;
3626 case HT_volName_FUNCTION
:
3628 struct volInfo hostVolInfo
, diskVolInfo
;
3631 cdbread(ut
, volInfo_BLOCK
, dbAddr
,
3632 &diskVolInfo
, sizeof(diskVolInfo
));
3637 "\nvolname hash %d, entry at %u\n",
3640 "----------------------------\n");
3641 volInfo_ntoh(&diskVolInfo
, &hostVolInfo
);
3642 printVolInfo(dumpfid
, &hostVolInfo
);
3643 dbAddr
= hostVolInfo
.nameHashChain
;
3645 volFragsDump(ut
, dumpfid
,
3646 hostVolInfo
.firstFragment
);
3651 fprintf(dumpfid
, "unknown type %d\n", type
);
3661 code
= ubik_EndTrans(ut
); /* is this safe if no ut started ? */
3670 volFragsDump(struct ubik_trans
*ut
, FILE *dumpfid
, dbadr dbAddr
)
3672 struct volFragment hostVolFragment
, diskVolFragment
;
3677 cdbread(ut
, volFragment_BLOCK
, dbAddr
, &diskVolFragment
,
3678 sizeof(diskVolFragment
));
3679 if (code
) { /* don't be fussy about errors */
3680 fprintf(dumpfid
, "volFragsDump: Error reading database\n");
3684 fprintf(dumpfid
, "\nvolfragment entry at %u\n", dbAddr
);
3685 fprintf(dumpfid
, "----------------------------\n");
3686 volFragment_ntoh(&diskVolFragment
, &hostVolFragment
);
3687 printVolFragment(dumpfid
, &hostVolFragment
);
3688 dbAddr
= hostVolFragment
.sameNameChain
;
3694 /* utilities - network to host conversion
3695 * currently used for debug only
3699 volFragmentDiskToHost(struct volFragment
*diskVfPtr
,
3700 struct volFragment
*hostVfPtr
)
3702 hostVfPtr
->vol
= ntohl(diskVfPtr
->vol
);
3703 hostVfPtr
->sameNameChain
= ntohl(diskVfPtr
->sameNameChain
);
3704 hostVfPtr
->tape
= ntohl(diskVfPtr
->tape
);
3705 hostVfPtr
->sameTapeChain
= ntohl(diskVfPtr
->sameTapeChain
);
3706 hostVfPtr
->position
= ntohl(diskVfPtr
->position
);
3707 hostVfPtr
->clone
= ntohl(diskVfPtr
->clone
);
3708 hostVfPtr
->incTime
= ntohl(diskVfPtr
->incTime
);
3709 hostVfPtr
->startByte
= ntohl(diskVfPtr
->startByte
);
3710 hostVfPtr
->nBytes
= ntohl(diskVfPtr
->nBytes
);
3711 hostVfPtr
->flags
= ntohs(diskVfPtr
->flags
);
3712 hostVfPtr
->sequence
= ntohs(diskVfPtr
->sequence
);
3716 volInfoDiskToHost(struct volInfo
*diskViPtr
, struct volInfo
*hostViPtr
)
3718 strcpy(hostViPtr
->name
, diskViPtr
->name
);
3719 hostViPtr
->nameHashChain
= ntohl(diskViPtr
->nameHashChain
);
3720 hostViPtr
->id
= ntohl(diskViPtr
->id
);
3721 strcpy(hostViPtr
->server
, diskViPtr
->server
);
3722 hostViPtr
->partition
= ntohl(diskViPtr
->partition
);
3723 hostViPtr
->flags
= ntohl(diskViPtr
->flags
);
3724 hostViPtr
->sameNameHead
= ntohl(diskViPtr
->sameNameHead
);
3725 hostViPtr
->sameNameChain
= ntohl(diskViPtr
->sameNameChain
);
3726 hostViPtr
->firstFragment
= ntohl(diskViPtr
->firstFragment
);
3727 hostViPtr
->nFrags
= ntohl(diskViPtr
->nFrags
);
3731 tapeDiskToHost(struct tape
*diskTapePtr
, struct tape
*hostTapePtr
)
3733 strcpy(hostTapePtr
->name
, diskTapePtr
->name
);
3734 hostTapePtr
->nameHashChain
= ntohl(diskTapePtr
->nameHashChain
);
3735 hostTapePtr
->flags
= ntohl(diskTapePtr
->flags
);
3737 /* tape id conversion here */
3738 hostTapePtr
->written
= ntohl(diskTapePtr
->written
);
3739 hostTapePtr
->nBytes
= ntohl(diskTapePtr
->nBytes
);
3740 hostTapePtr
->nFiles
= ntohl(diskTapePtr
->nFiles
);
3741 hostTapePtr
->nVolumes
= ntohl(diskTapePtr
->nVolumes
);
3742 hostTapePtr
->seq
= ntohl(diskTapePtr
->seq
);
3743 hostTapePtr
->dump
= ntohl(diskTapePtr
->dump
);
3744 hostTapePtr
->nextTape
= ntohl(diskTapePtr
->nextTape
);
3745 hostTapePtr
->firstVol
= ntohl(diskTapePtr
->firstVol
);
3746 hostTapePtr
->useCount
= ntohl(diskTapePtr
->useCount
);
3750 dumpDiskToHost(struct dump
*diskDumpPtr
, struct dump
*hostDumpPtr
)
3752 hostDumpPtr
->id
= ntohl(diskDumpPtr
->id
);
3753 hostDumpPtr
->idHashChain
= ntohl(diskDumpPtr
->idHashChain
);
3754 strcpy(hostDumpPtr
->dumpName
, diskDumpPtr
->dumpName
);
3755 strcpy(hostDumpPtr
->dumpPath
, diskDumpPtr
->dumpPath
);
3756 strcpy(hostDumpPtr
->volumeSet
, diskDumpPtr
->volumeSet
);
3757 hostDumpPtr
->nameHashChain
= ntohl(diskDumpPtr
->nameHashChain
);
3758 hostDumpPtr
->flags
= ntohl(diskDumpPtr
->flags
);
3759 hostDumpPtr
->parent
= ntohl(diskDumpPtr
->parent
);
3760 hostDumpPtr
->created
= ntohl(diskDumpPtr
->created
);
3761 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3762 hostDumpPtr
->nVolumes
= ntohl(diskDumpPtr
->nVolumes
);
3764 /* tapeset conversion here */
3766 hostDumpPtr
->firstTape
= ntohl(diskDumpPtr
->firstTape
);
3768 /* principal conversion here */
3774 checkHash(struct ubik_trans
*ut
, int hashType
)
3776 struct memoryHashTable
*mhtPtr
;
3777 int entrySize
, hashTableLength
;
3782 mhtPtr
= ht_GetType(hashType
, &entrySize
);
3786 for (old
= 0; old
< 1; old
++) {
3787 LogDebug(5, "\nold = %d\n", old
);
3788 printMemoryHashTable(stdout
, mhtPtr
);
3790 hashTableLength
= (old
? mhtPtr
->oldLength
: mhtPtr
->length
);
3792 for (bucket
= 0; bucket
< hashTableLength
; bucket
++) {
3795 entryAddr
= ht_LookupBucket(ut
, mhtPtr
, bucket
, old
);
3796 while (entryAddr
!= 0) {
3797 LogDebug(6, "bucket %d has disk addr %d\n", bucket
,
3800 case HT_dumpIden_FUNCTION
:
3802 struct dump diskDump
, hostDump
;
3804 code
= dbread(ut
, entryAddr
, &diskDump
, entrySize
);
3808 dump_ntoh(&diskDump
, &hostDump
);
3809 printDump(stdout
, &hostDump
);
3810 entryAddr
= hostDump
.idHashChain
;
3814 case HT_dumpName_FUNCTION
:
3817 case HT_tapeName_FUNCTION
:
3820 case HT_volName_FUNCTION
:
3822 struct volInfo diskVolInfo
, hostVolInfo
;
3824 code
= dbread(ut
, entryAddr
, &diskVolInfo
, entrySize
);
3828 volInfo_ntoh(&diskVolInfo
, &hostVolInfo
);
3829 printVolInfo(stdout
, &hostVolInfo
);
3830 entryAddr
= hostVolInfo
.nameHashChain
;