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>
23 #include <netinet/in.h>
25 #include <sys/param.h>
27 #include <sys/resource.h>
31 #include <sys/types.h>
33 #include <afs/bubasics.h>
42 #include <afs/cellconfig.h>
46 #include "budb_errs.h"
48 #include "budb_internal.h"
49 #include "error_macros.h"
51 #include "afs/audit.h"
52 #include <afs/afsutil.h>
58 extern struct ubik_dbase
*BU_dbase
;
59 extern struct afsconf_dir
*BU_conf
; /* for getting cell info */
61 afs_int32
AddVolume(struct rx_call
*, struct budb_volumeEntry
*);
62 afs_int32
AddVolumes(struct rx_call
*, struct budb_volumeList
*);
63 afs_int32
CreateDump(struct rx_call
*, struct budb_dumpEntry
*);
64 afs_int32
DoDeleteDump(struct rx_call
*, dumpId
, Date
, Date
, budb_dumpsList
*);
65 afs_int32
DoDeleteTape(struct rx_call
*, struct budb_tapeEntry
*);
66 afs_int32
ListDumps(struct rx_call
*, afs_int32
, afs_int32
, Date
, Date
,
67 budb_dumpsList
*, budb_dumpsList
*);
68 afs_int32
DeleteVDP(struct rx_call
*, char *, char *, afs_int32
);
69 afs_int32
FindClone(struct rx_call
*, afs_int32
, char *, afs_int32
*);
70 afs_int32
FindDump(struct rx_call
*, char *, afs_int32
,
71 struct budb_dumpEntry
*);
72 afs_int32
FindLatestDump(struct rx_call
*, char *, char *,
73 struct budb_dumpEntry
*);
74 afs_int32
FinishDump(struct rx_call
*, struct budb_dumpEntry
*);
75 afs_int32
FinishTape(struct rx_call
*, struct budb_tapeEntry
*);
76 afs_int32
GetDumps(struct rx_call
*, afs_int32
, afs_int32
, char *,
77 afs_int32
, afs_int32
, afs_int32
, afs_int32
*,
78 afs_int32
*, budb_dumpList
*);
79 afs_int32
getExpiration(struct ubik_trans
*ut
, struct tape
*);
80 afs_int32
makeAppended(struct ubik_trans
*ut
, afs_int32
, afs_int32
,
82 afs_int32
MakeDumpAppended(struct rx_call
*, afs_int32
, afs_int32
,
84 afs_int32
FindLastTape(struct rx_call
*, afs_int32
, struct budb_dumpEntry
*,
85 struct budb_tapeEntry
*, struct budb_volumeEntry
*);
86 afs_int32
GetTapes(struct rx_call
*, afs_int32
, afs_int32
, char *, afs_int32
,
87 afs_int32
, afs_int32
, afs_int32
*, afs_int32
*,
89 afs_int32
GetVolumes(struct rx_call
*, afs_int32
, afs_int32
, char *,
90 afs_int32
, afs_int32
, afs_int32
, afs_int32
*,
91 afs_int32
*, budb_volumeList
*);
92 afs_int32
UseTape(struct rx_call
*, struct budb_tapeEntry
*, int *);
93 afs_int32
T_DumpHashTable(struct rx_call
*, int, char *);
94 afs_int32
T_GetVersion(struct rx_call
*, int *);
95 afs_int32
T_DumpDatabase(struct rx_call
*, char *);
97 int volFragsDump(struct ubik_trans
*, FILE *, dbadr
);
99 /* Text block management */
101 struct memTextBlock
{
102 struct memTextBlock
*mtb_next
; /* next in chain */
103 afs_int32 mtb_nbytes
; /* # of bytes in this block */
104 struct blockHeader mtb_blkHeader
; /* in memory header */
105 dbadr mtb_addr
; /* disk address of block */
108 typedef struct memTextBlock memTextBlockT
;
109 typedef memTextBlockT
*memTextBlockP
;
111 /* These variable are for returning debugging info about the state of the
112 server. If they get trashed during multi-threaded operation it doesn't
115 /* This is global so COUNT_REQ in krb_udp.c can refer to it. */
116 char *lastOperation
; /* name of last operation */
117 static Date lastTrans
; /* time of last transaction */
119 /* procsInited is sort of a lock: during a transaction only one process runs
120 while procsInited is false. */
122 static int procsInited
= 0;
124 /* This variable is protected by the procsInited flag. */
126 static int (*rebuildDatabase
) (struct ubik_trans
*);
128 /* AwaitInitialization
129 * Wait unitl budb has initialized (InitProcs). If it hasn't
130 * within 5 seconds, then return no quorum.
133 AwaitInitialization(void)
137 while (!procsInited
) {
140 else if (time(0) - start
> 5)
142 #ifdef AFS_PTHREAD_ENV
152 * name is a pathname style name, determine trailing name and return
157 tailCompPtr(char *pathNamePtr
)
160 ptr
= strrchr(pathNamePtr
, '/');
162 /* this should never happen */
163 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
165 return (pathNamePtr
);
167 ptr
++; /* skip the / */
172 * Check to see if the caller is a SuperUser.
179 callPermitted(struct rx_call
*call
)
182 struct afsconf_dir
*acdir
;
184 acdir
= afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH
);
188 if (afsconf_SuperUser(acdir
, call
, NULL
))
192 afsconf_Close(acdir
);
197 * This is called by every RPC interface to create a Ubik transaction
198 * and read the database header into core
204 * sets a lock on byte 1 of the database. Looks like it enforces
205 * single threading by use of the lock.
209 InitRPC(struct ubik_trans
**ut
,
210 int lock
, /* indicate read/write transaction */
211 int this_op
) /* opcode of RCP, for COUNT_ABO */
214 float wait
= 0.91; /* start waiting for 1 second */
217 /* wait for server initialization to finish if this is not InitProcs calling */
219 if ((code
= AwaitInitialization()))
222 for (code
= UNOQUORUM
; code
== UNOQUORUM
;) {
224 ubik_BeginTrans(BU_dbase
,
226 LOCKREAD
) ? UBIK_READTRANS
: UBIK_WRITETRANS
),
228 if (code
== UNOQUORUM
) { /* no quorum elected */
230 Log("Waiting for quorum election\n");
233 #ifdef AFS_PTHREAD_ENV
236 IOMGR_Sleep((int)wait
);
243 Log("Have established quorum\n");
245 /* set lock at posiion 1, for 1 byte of type lock */
246 if ((code
= ubik_SetLock(*ut
, 1, 1, lock
))) {
247 ubik_AbortTrans(*ut
);
251 /* check that dbase is initialized and setup cheader */
252 if (lock
== LOCKREAD
) {
253 /* init but don't fix because this is read only */
254 if ((code
= CheckInit(*ut
, 0))) {
255 ubik_AbortTrans(*ut
);
256 if ((code
= InitRPC(ut
, LOCKWRITE
, 0))) { /* Now fix the database */
257 LogError(code
, "InitRPC: InitRPC failed\n");
260 if ((code
= ubik_EndTrans(*ut
))) {
261 LogError(code
, "InitRPC: ubik_EndTrans failed\n");
264 goto start
; /* now redo the read transaction */
267 if ((code
= CheckInit(*ut
, rebuildDatabase
))) {
268 ubik_AbortTrans(*ut
);
276 /* This is called to initialize a newly created database */
278 initialize_database(struct ubik_trans
*ut
)
283 static int noAuthenticationRequired
; /* global state */
284 static int recheckNoAuth
; /* global state */
289 struct ubik_trans
*ut
;
294 if ((globalConfPtr
->myHost
== 0) || (BU_conf
== 0))
295 ERROR(BUDB_INTERNALERROR
);
299 if (globalConfPtr
->debugFlags
& DF_NOAUTH
)
300 noAuthenticationRequired
= 1;
302 if (globalConfPtr
->debugFlags
& DF_RECHECKNOAUTH
)
306 noAuthenticationRequired
= afsconf_GetNoAuthFlag(BU_conf
);
308 if (noAuthenticationRequired
)
309 LogError(0, "Running server with security disabled\n");
313 rebuildDatabase
= initialize_database
;
315 if ((code
= InitRPC(&ut
, LOCKREAD
, 0))) {
316 LogError(code
, "InitProcs: InitRPC failed\n");
319 code
= ubik_EndTrans(ut
);
321 LogError(code
, "InitProcs: ubik_EndTrans failed\n");
325 rebuildDatabase
= 0; /* only do this during init */
333 int nElements
; /* number in list */
334 int allocSize
; /* number of elements allocated */
335 dbadr
*elements
; /* array of addresses */
339 InitReturnList(struct returnList
*list
)
343 list
->elements
= (dbadr
*) 0;
347 FreeReturnList(struct returnList
*list
)
350 free(list
->elements
);
351 list
->elements
= (dbadr
*) 0;
355 /* As entries are collected, they are added to a return list. Once all
356 * entries have been collected, it is then placed in the return buffer
357 * with SendReturnList(). The first *to_skipP are not recorded.
360 AddToReturnList(struct returnList
*list
, dbadr a
, afs_int32
*to_skipP
)
372 /* Up to 5 plus a maximum so SendReturnList() knows if we
373 * need to come back for more.
375 if (list
->nElements
>= BUDB_MAX_RETURN_LIST
+ 5)
376 return BUDB_LIST2BIG
;
378 if (list
->nElements
>= list
->allocSize
) {
379 if (list
->elements
== 0) {
381 tmp
= (char *)malloc(sizeof(dbadr
) * size
);
383 size
= list
->allocSize
+ 10;
384 tmp
= (char *)realloc(list
->elements
, sizeof(dbadr
) * size
);
388 list
->elements
= (dbadr
*) tmp
;
389 list
->allocSize
= size
;
392 list
->elements
[list
->nElements
] = a
;
398 FillVolEntry(struct ubik_trans
*ut
, dbadr va
, void *rock
)
400 struct budb_volumeEntry
*vol
= (struct budb_volumeEntry
*) rock
;
404 struct volFragment vf
;
406 if (dbread(ut
, va
, &vf
, sizeof(vf
)))
407 return BUDB_IO
; /* The volFrag */
408 if (dbread(ut
, ntohl(vf
.vol
), &vi
, sizeof(vi
)))
409 return BUDB_IO
; /* The volInfo */
410 if (dbread(ut
, ntohl(vf
.tape
), &t
, sizeof(t
)))
411 return BUDB_IO
; /* The tape */
412 if (dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
)))
413 return BUDB_IO
; /* The dump */
415 strcpy(vol
->name
, vi
.name
);
416 strcpy(vol
->server
, vi
.server
);
417 strcpy(vol
->tape
, t
.name
);
418 vol
->tapeSeq
= ntohl(t
.seq
);
419 vol
->dump
= ntohl(d
.id
);
420 vol
->position
= ntohl(vf
.position
);
421 vol
->clone
= ntohl(vf
.clone
);
422 vol
->incTime
= ntohl(vf
.incTime
);
423 vol
->nBytes
= ntohl(vf
.nBytes
);
424 vol
->startByte
= ntohl(vf
.startByte
);
425 vol
->flags
= (ntohs(vf
.flags
) & VOLFRAGMENTFLAGS
); /* low 16 bits here */
426 vol
->flags
|= (ntohl(vi
.flags
) & VOLINFOFLAGS
); /* high 16 bits here */
427 vol
->seq
= ntohs(vf
.sequence
);
428 vol
->id
= ntohl(vi
.id
);
429 vol
->partition
= ntohl(vi
.partition
);
435 FillDumpEntry(struct ubik_trans
*ut
, dbadr da
, void *rock
)
437 struct budb_dumpEntry
*dump
= (struct budb_dumpEntry
*)rock
;
440 if (dbread(ut
, da
, &d
, sizeof(d
)))
442 dump
->id
= ntohl(d
.id
);
443 dump
->flags
= ntohl(d
.flags
);
444 dump
->created
= ntohl(d
.created
);
445 strncpy(dump
->name
, d
.dumpName
, sizeof(dump
->name
));
446 strncpy(dump
->dumpPath
, d
.dumpPath
, sizeof(dump
->dumpPath
));
447 strncpy(dump
->volumeSetName
, d
.volumeSet
, sizeof(dump
->volumeSetName
));
449 dump
->parent
= ntohl(d
.parent
);
450 dump
->level
= ntohl(d
.level
);
451 dump
->nVolumes
= ntohl(d
.nVolumes
);
453 tapeSet_ntoh(&d
.tapes
, &dump
->tapes
);
455 if (strlen(d
.dumper
.name
) < sizeof(dump
->dumper
.name
))
456 strcpy(dump
->dumper
.name
, d
.dumper
.name
);
457 if (strlen(d
.dumper
.instance
) < sizeof(dump
->dumper
.instance
))
458 strcpy(dump
->dumper
.instance
, d
.dumper
.instance
);
459 if (strlen(d
.dumper
.cell
) < sizeof(dump
->dumper
.cell
))
460 strcpy(dump
->dumper
.cell
, d
.dumper
.cell
);
462 /* Get the initial dumpid and the appended dump id */
463 dump
->initialDumpID
= ntohl(d
.initialDumpID
);
464 if (d
.appendedDumpChain
) {
465 if (dbread(ut
, ntohl(d
.appendedDumpChain
), &ad
, sizeof(ad
)))
467 dump
->appendedDumpID
= ntohl(ad
.id
);
469 dump
->appendedDumpID
= 0;
471 /* printf("dump name %s, parent %d, level %d\n",
472 * d.dumpName, ntohl(d.parent), ntohl(d.level)); */
478 FillTapeEntry(struct ubik_trans
*ut
, dbadr ta
, void *rock
)
480 struct budb_tapeEntry
*tape
=(struct budb_tapeEntry
*) rock
;
485 if (dbread(ut
, ta
, &t
, sizeof(t
)))
488 /* Get the tape's expiration date */
489 if ((code
= getExpiration(ut
, &t
)))
492 strcpy(tape
->name
, t
.name
);
493 tape
->flags
= ntohl(t
.flags
);
494 tape
->written
= ntohl(t
.written
);
495 tape
->expires
= ntohl(t
.expires
);
496 tape
->nMBytes
= ntohl(t
.nMBytes
);
497 tape
->nBytes
= ntohl(t
.nBytes
);
498 tape
->nFiles
= ntohl(t
.nFiles
);
499 tape
->nVolumes
= ntohl(t
.nVolumes
);
500 tape
->seq
= ntohl(t
.seq
);
501 tape
->labelpos
= ntohl(t
.labelpos
);
502 tape
->useCount
= ntohl(t
.useCount
);
503 tape
->useKBytes
= ntohl(t
.useKBytes
);
505 if (dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
)))
507 tape
->dump
= ntohl(d
.id
);
511 #define returnList_t budb_dumpList *
514 * A list of elements of size e_size is in list, collected
515 * with AddToReturnList(). We will move this to a correspoding
516 * return list, eList, via FillProc(). nextInodeP tells us
517 * if there are more and how many to skip on the next request.
520 SendReturnList(struct ubik_trans
*ut
,
521 struct returnList
*list
, /* list of elements to return */
522 afs_int32(*FillProc
) (struct ubik_trans
*, dbadr da
,
524 /* proc to fill entry */
525 int e_size
, /* size of each element */
526 afs_int32 index
, /* index from previous call */
527 afs_int32
*nextIndexP
, /* if more elements are available */
528 afs_int32
*dbTimeP
, /* time of last db update */
529 budb_dumpList
*eList
) /* rxgen list structure (e.g.) */
537 *dbTimeP
= ntohl(db
.h
.lastUpdate
);
539 /* Calculate how many to return. Don't let if go over
540 * BUDB_MAX_RETURN_LIST nor the size of our return list.
542 to_return
= list
->nElements
;
543 if (to_return
> BUDB_MAX_RETURN_LIST
)
544 to_return
= BUDB_MAX_RETURN_LIST
;
545 if (eList
->budb_dumpList_len
&& (to_return
> eList
->budb_dumpList_len
))
546 to_return
= eList
->budb_dumpList_len
;
548 /* Allocate space for the return values if needed and zero it */
549 if (eList
->budb_dumpList_val
== 0) {
550 eList
->budb_dumpList_val
=
551 (struct budb_dumpEntry
*)malloc(e_size
* to_return
);
552 if (!eList
->budb_dumpList_val
)
555 memset(eList
->budb_dumpList_val
, 0, e_size
* to_return
);
556 eList
->budb_dumpList_len
= to_return
;
558 e
= (char *)(eList
->budb_dumpList_val
);
559 for (i
= 0; i
< to_return
; i
++, e
+= e_size
) {
560 code
= (*FillProc
) (ut
, list
->elements
[i
], (budb_dumpEntry
*) e
);
565 if (list
->nElements
> i
)
566 *nextIndexP
= index
+ i
;
570 /* Come here to delete a volInfo structure. */
573 DeleteVolInfo(struct ubik_trans
*ut
, dbadr via
, struct volInfo
*vi
)
579 if (vi
->firstFragment
)
580 return 0; /* still some frags, don't free yet */
581 if (vi
->sameNameHead
== 0) { /* this is the head */
582 if (vi
->sameNameChain
)
583 return 0; /* empty head, some non-heads left */
585 code
= ht_HashOut(ut
, &db
.volName
, via
, vi
);
588 code
= FreeStructure(ut
, volInfo_BLOCK
, via
);
591 hvia
= ntohl(vi
->sameNameHead
);
592 if (dbread(ut
, hvia
, &hvi
, sizeof(hvi
)))
595 RemoveFromList(ut
, hvia
, &hvi
, &hvi
.sameNameChain
, via
, vi
,
598 return BUDB_DATABASEINCONSISTENT
;
600 code
= FreeStructure(ut
, volInfo_BLOCK
, via
);
604 /* Detach a volume fragment from its volInfo structure. Its tape chain is
605 already freed. This routine frees the structure and the caller must not
609 DeleteVolFragment(struct ubik_trans
*ut
, dbadr va
, struct volFragment
*v
)
616 if (dbread(ut
, via
, &vi
, sizeof(vi
)))
619 RemoveFromList(ut
, via
, &vi
, &vi
.firstFragment
, va
, v
,
622 return BUDB_DATABASEINCONSISTENT
;
625 if (vi
.firstFragment
== 0)
626 if ((code
= DeleteVolInfo(ut
, via
, &vi
)))
628 if ((code
= FreeStructure(ut
, volFragment_BLOCK
, va
)))
631 /* decrement frag counter */
633 set_word_addr(ut
, via
, &vi
, &vi
.nFrags
, htonl(ntohl(vi
.nFrags
) - 1));
639 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
640 * The caller will remove it from the hash table if necessary. The caller is
641 * also responsible for writing the tape out if necessary. */
644 DeleteTape(struct ubik_trans
*ut
, dbadr ta
, struct tape
*t
)
652 return BUDB_DATABASEINCONSISTENT
;
653 if (dbread(ut
, da
, &d
, sizeof(d
)))
655 if (d
.firstTape
== 0)
656 return BUDB_DATABASEINCONSISTENT
;
658 code
= RemoveFromList(ut
, da
, &d
, &d
.firstTape
, ta
, t
, &t
->nextTape
);
660 return BUDB_DATABASEINCONSISTENT
;
664 /* Since the tape should have been truncated there should never be any
665 * volumes in the tape. */
666 if (t
->firstVol
|| t
->nVolumes
)
667 return BUDB_DATABASEINCONSISTENT
;
673 DeleteDump(struct ubik_trans
*ut
, dbadr da
, struct dump
*d
)
677 code
= ht_HashOut(ut
, &db
.dumpIden
, da
, d
);
681 code
= ht_HashOut(ut
, &db
.dumpName
, da
, d
);
685 /* Since the tape should have been truncated this should never happen. */
686 if (d
->firstTape
|| d
->nVolumes
)
687 ERROR(BUDB_DATABASEINCONSISTENT
);
689 code
= FreeStructure(ut
, dump_BLOCK
, da
);
700 * This is called with a volumeEntry and a volInfo structure and compares
701 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
702 * search volInfo structures once it has the head volInfo structure from the
703 * volName hash table.
705 * When called from GetVolInfo the name compare is redundant.
706 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
710 VolInfoMatch(struct budb_volumeEntry
*vol
, struct volInfo
*vi
)
712 return ((strcmp(vol
->name
, vi
->name
) == 0) && /* same volume name */
713 (vol
->id
== ntohl(vi
->id
)) && /* same volume id */
714 ((vol
->flags
& VOLINFOFLAGS
) == (ntohl(vi
->flags
) & VOLINFOFLAGS
)) && /* same flags */
715 (vol
->partition
== ntohl(vi
->partition
)) && /* same partition (N/A) */
716 (strcmp(vol
->server
, vi
->server
) == 0)); /* same server (N/A) */
721 * This routine takes a volumeEntry structure from an RPC interface and
722 * returns the corresponding volInfo structure, creating it if necessary.
724 * The caller must write the entry out.
728 GetVolInfo(struct ubik_trans
*ut
, struct budb_volumeEntry
*volP
, dbadr
*viaP
,
733 afs_int32 eval
, code
= 0;
735 eval
= ht_LookupEntry(ut
, &db
.volName
, volP
->name
, &via
, viP
);
740 /* allocate a new volinfo structure */
741 eval
= AllocStructure(ut
, volInfo_BLOCK
, 0, &via
, viP
);
745 strcpy(viP
->name
, volP
->name
);
746 strcpy(viP
->server
, volP
->server
);
747 viP
->sameNameHead
= 0; /* The head of same name chain */
748 viP
->sameNameChain
= 0; /* Same name chain is empty */
749 viP
->firstFragment
= 0;
751 viP
->id
= htonl(volP
->id
);
752 viP
->partition
= htonl(volP
->partition
);
753 viP
->flags
= htonl(volP
->flags
& VOLINFOFLAGS
);
755 /* Chain onto volname hash table */
756 eval
= ht_HashIn(ut
, &db
.volName
, via
, viP
);
760 LogDebug(4, "volume Info for %s placed at %d\n", volP
->name
, via
);
763 else if (!VolInfoMatch(volP
, viP
)) { /* Not the head volinfo struct */
764 hvia
= via
; /* remember the head volinfo struct */
765 memcpy(&hvi
, viP
, sizeof(hvi
));
767 /* Search the same name chain for the correct volinfo structure */
768 for (via
= ntohl(viP
->sameNameChain
); via
;
769 via
= ntohl(viP
->sameNameChain
)) {
770 eval
= dbread(ut
, via
, viP
, sizeof(*viP
));
774 if (VolInfoMatch(volP
, viP
))
775 break; /* found the one */
778 /* if the correct volinfo struct isn't found, create one */
780 eval
= AllocStructure(ut
, volInfo_BLOCK
, 0, &via
, viP
);
784 strcpy(viP
->name
, volP
->name
);
785 strcpy(viP
->server
, volP
->server
);
786 viP
->nameHashChain
= 0; /* not in hash table */
787 viP
->sameNameHead
= htonl(hvia
); /* chain to head of sameNameChain */
788 viP
->sameNameChain
= hvi
.sameNameChain
;
789 viP
->firstFragment
= 0;
791 viP
->id
= htonl(volP
->id
);
792 viP
->partition
= htonl(volP
->partition
);
793 viP
->flags
= htonl(volP
->flags
& VOLINFOFLAGS
);
795 /* write the head entry's sameNameChain link */
797 set_word_addr(ut
, hvia
, &hvi
, &hvi
.sameNameChain
, htonl(via
));
809 /* deletesomevolumesfromtape
810 * Deletes a specified number of volumes from a tape. The tape
811 * and dump are modified to reflect the smaller number of volumes.
812 * The transaction is not terminated, it is up to the caller to
813 * finish the transaction and start a new one (if desired).
815 * maxvolumestodelete - don't delete more than this many volumes
819 deleteSomeVolumesFromTape(struct ubik_trans
*ut
, dbadr tapeAddr
,
820 struct tape
*tapePtr
, int maxVolumesToDelete
)
822 dbadr volFragAddr
, nextVolFragAddr
, dumpAddr
;
823 struct volFragment volFrag
;
825 int volumesDeleted
= 0;
826 afs_int32 eval
, code
= 0;
831 for (volFragAddr
= ntohl(tapePtr
->firstVol
);
832 (volFragAddr
&& (maxVolumesToDelete
> 0));
833 volFragAddr
= nextVolFragAddr
) {
834 eval
= dbread(ut
, volFragAddr
, &volFrag
, sizeof(volFrag
));
838 nextVolFragAddr
= ntohl(volFrag
.sameTapeChain
);
840 eval
= DeleteVolFragment(ut
, volFragAddr
, &volFrag
);
844 maxVolumesToDelete
--;
848 /* reset the volume fragment pointer in the tape */
849 tapePtr
->firstVol
= htonl(volFragAddr
);
851 /* diminish the tape's volume count */
852 tapePtr
->nVolumes
= htonl(ntohl(tapePtr
->nVolumes
) - volumesDeleted
);
854 eval
= dbwrite(ut
, tapeAddr
, tapePtr
, sizeof(*tapePtr
));
858 /* diminish the dump's volume count */
859 dumpAddr
= ntohl(tapePtr
->dump
);
860 eval
= dbread(ut
, dumpAddr
, &dump
, sizeof(dump
));
864 dump
.nVolumes
= htonl(ntohl(dump
.nVolumes
) - volumesDeleted
);
865 eval
= dbwrite(ut
, dumpAddr
, &dump
, sizeof(dump
));
874 * deletes a dump in stages, by repeatedly deleting a small number of
875 * volumes from the dump until none are left. The dump is then deleted.
877 * In the case where multiple calls are made to delete the same
878 * dump, the operation will succeed but contention for structures
879 * will result in someone getting back an error.
882 * id - id of dump to delete
886 deleteDump(struct rx_call
*call
, dumpId id
, budb_dumpsList
*dumps
)
888 struct ubik_trans
*ut
;
889 dbadr dumpAddr
, tapeAddr
, appendedDump
;
893 afs_int32 eval
, code
= 0;
896 /* iterate until the dump is truly deleted */
902 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
904 ERROR(eval
); /* can't start transaction */
907 ht_LookupEntry(ut
, &db
.dumpIden
, &dumpid
, &dumpAddr
, &dump
);
911 ABORT(BUDB_NOENT
); /* can't find dump */
913 if ((dumpid
== id
) && (dump
.initialDumpID
)) /* can't be an appended dump */
914 ABORT(BUDB_NOTINITIALDUMP
);
916 tapeAddr
= ntohl(dump
.firstTape
);
920 /* there is a tape to delete */
921 eval
= dbread(ut
, tapeAddr
, &tape
, sizeof(tape
));
925 if (ntohl(tape
.nVolumes
)) {
926 /* tape is not empty */
927 eval
= deleteSomeVolumesFromTape(ut
, tapeAddr
, &tape
, 10);
932 if (ntohl(tape
.nVolumes
) == 0) {
933 /* tape is now empty, delete it */
934 eval
= DeleteTape(ut
, tapeAddr
, &tape
);
937 eval
= ht_HashOut(ut
, &db
.tapeName
, tapeAddr
, &tape
);
940 eval
= FreeStructure(ut
, tape_BLOCK
, tapeAddr
);
945 eval
= ubik_EndTrans(ut
);
949 } /* next deletion portion */
951 /* Record the dump just deleted */
952 if (dumps
&& (dumps
->budb_dumpsList_len
< BUDB_MAX_RETURN_LIST
)) {
953 if (dumps
->budb_dumpsList_len
== 0)
954 dumps
->budb_dumpsList_val
=
955 (afs_int32
*) malloc(sizeof(afs_int32
));
957 dumps
->budb_dumpsList_val
=
958 (afs_int32
*) realloc(dumps
->budb_dumpsList_val
,
959 (dumps
->budb_dumpsList_len
+
960 1) * sizeof(afs_int32
));
962 if (!dumps
->budb_dumpsList_val
)
965 dumps
->budb_dumpsList_val
[dumps
->budb_dumpsList_len
] = dumpid
;
966 dumps
->budb_dumpsList_len
++;
969 appendedDump
= ntohl(dump
.appendedDumpChain
);
971 /* finally done. No more tapes left in the dump. Delete the dump itself */
972 eval
= DeleteDump(ut
, dumpAddr
, &dump
);
976 /* Now delete the appended dump too */
978 eval
= dbread(ut
, appendedDump
, &dump
, sizeof(dump
));
982 dumpid
= ntohl(dump
.id
);
986 eval
= ubik_EndTrans(ut
);
990 Log("Delete dump %s (DumpID %u), path %s\n", dump
.dumpName
,
991 ntohl(dump
.id
), dump
.dumpPath
);
995 if (code
&& partialDel
) {
996 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
997 dump
.dumpName
, ntohl(dump
.id
), dump
.dumpPath
, code
);
1002 ubik_AbortTrans(ut
);
1007 * dump selection routines - used by BUDB_GetDumps
1011 /* most recent dump selection */
1014 struct chosenDump
*next
;
1019 struct wantDumpRock
{
1020 int maxDumps
; /* max wanted */
1021 int ndumps
; /* actual in chain */
1022 struct chosenDump
*chain
;
1027 wantDump(dbadr dumpAddr
, void *dumpParam
, void *dumpListPtrParam
)
1029 struct dump
*dumpPtr
;
1030 struct wantDumpRock
*rockPtr
;
1032 dumpPtr
= (struct dump
*)dumpParam
;
1033 rockPtr
= (struct wantDumpRock
*)dumpListPtrParam
;
1035 /* if we don't have our full complement, just add another */
1036 if (rockPtr
->ndumps
< rockPtr
->maxDumps
)
1039 /* got the number we need, select based on date */
1040 if ((afs_uint32
) ntohl(dumpPtr
->created
) > rockPtr
->chain
->date
)
1047 rememberDump(dbadr dumpAddr
, void *dumpParam
, void *dumpListPtrParam
)
1049 struct dump
*dumpPtr
;
1050 struct wantDumpRock
*rockPtr
;
1051 struct chosenDump
*ptr
, *deletedPtr
, **nextPtr
;
1053 dumpPtr
= (struct dump
*)dumpParam
;
1054 rockPtr
= (struct wantDumpRock
*)dumpListPtrParam
;
1056 ptr
= (struct chosenDump
*)malloc(sizeof(*ptr
));
1059 memset(ptr
, 0, sizeof(*ptr
));
1060 ptr
->addr
= dumpAddr
;
1061 ptr
->date
= (afs_uint32
) ntohl(dumpPtr
->created
);
1063 /* Don't overflow the max */
1064 while (rockPtr
->ndumps
>= rockPtr
->maxDumps
) {
1065 /* have to drop one */
1066 deletedPtr
= rockPtr
->chain
;
1067 rockPtr
->chain
= deletedPtr
->next
;
1072 /* now insert in the right place */
1073 for (nextPtr
= &rockPtr
->chain
; *nextPtr
; nextPtr
= &((*nextPtr
)->next
)) {
1074 if (ptr
->date
< (*nextPtr
)->date
)
1077 ptr
->next
= *nextPtr
;
1085 /* ---------------------------------------------
1086 * general interface routines - alphabetic
1087 * ---------------------------------------------
1091 SBUDB_AddVolume(struct rx_call
*call
, struct budb_volumeEntry
*vol
)
1095 code
= AddVolume(call
, vol
);
1096 osi_auditU(call
, BUDB_AddVolEvent
, code
, AUD_LONG
, (vol
? vol
->id
: 0),
1102 AddVolume(struct rx_call
*call
, struct budb_volumeEntry
*vol
)
1104 struct ubik_trans
*ut
;
1105 dbadr da
, ta
, via
, va
;
1109 struct volFragment v
;
1111 afs_int32 eval
, code
= 0;
1113 if (!callPermitted(call
))
1114 return BUDB_NOTPERMITTED
;
1116 if ((strlen(vol
->name
) >= sizeof(vi
.name
))
1117 || (strlen(vol
->server
) >= sizeof(vi
.server
))
1118 || (strlen(vol
->tape
) >= sizeof(t
.name
)))
1119 return BUDB_BADARGUMENT
;
1121 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1125 /* Find the dump in dumpid hash table */
1126 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &vol
->dump
, &da
, &d
);
1130 ABORT(BUDB_NODUMPID
);
1132 /* search for the right tape in the dump */
1133 for (ta
= ntohl(d
.firstTape
); ta
; ta
= ntohl(t
.nextTape
)) {
1134 /* read the tape entry */
1135 eval
= dbread(ut
, ta
, &t
, sizeof(t
));
1139 /* Check if the right tape name */
1140 if (strcmp(t
.name
, vol
->tape
) == 0)
1144 ABORT(BUDB_NOTAPENAME
);
1146 if ((t
.dump
!= htonl(da
)) || /* tape must belong to dump */
1147 ((ntohl(t
.flags
) & BUDB_TAPE_BEINGWRITTEN
) == 0) || /* tape must be being written */
1148 ((ntohl(d
.flags
) & BUDB_DUMP_INPROGRESS
) == 0)) /* dump must be in progress */
1149 ABORT(BUDB_BADPROTOCOL
);
1151 /* find or create a volume info structure */
1152 eval
= GetVolInfo(ut
, vol
, &via
, &vi
);
1156 /* Create a volume fragment */
1157 eval
= AllocStructure(ut
, volFragment_BLOCK
, 0, &va
, &v
);
1161 v
.vol
= htonl(via
); /* vol frag points to vol info */
1162 v
.sameNameChain
= vi
.firstFragment
; /* vol frag is chained to vol info */
1163 vi
.firstFragment
= htonl(va
);
1164 vi
.nFrags
= htonl(ntohl(vi
.nFrags
) + 1);
1166 eval
= dbwrite(ut
, via
, &vi
, sizeof(vi
)); /* write the vol info struct */
1170 v
.tape
= htonl(ta
); /* vol frag points to tape */
1171 v
.sameTapeChain
= t
.firstVol
; /* vol frag is chained to tape info */
1172 t
.firstVol
= htonl(va
);
1173 t
.nVolumes
= htonl(ntohl(t
.nVolumes
) + 1);
1174 bytes
= ntohl(t
.nBytes
) + vol
->nBytes
; /* update bytes on tape */
1175 t
.nMBytes
= htonl(ntohl(t
.nMBytes
) + bytes
/ (1024 * 1024));
1176 t
.nBytes
= htonl(bytes
% (1024 * 1024));
1178 eval
= dbwrite(ut
, ta
, &t
, sizeof(t
)); /* write the tape structure */
1182 d
.nVolumes
= htonl(ntohl(d
.nVolumes
) + 1); /* one more volume on dump */
1184 eval
= dbwrite(ut
, da
, &d
, sizeof(d
)); /* write out the dump structure */
1188 v
.position
= htonl(vol
->position
); /* vol frag info */
1189 v
.clone
= htonl(vol
->clone
);
1190 v
.incTime
= htonl(vol
->incTime
);
1191 v
.startByte
= htonl(vol
->startByte
);
1192 v
.nBytes
= htonl(vol
->nBytes
);
1193 v
.flags
= htons(vol
->flags
& VOLFRAGMENTFLAGS
);
1194 v
.sequence
= htons(vol
->seq
);
1196 eval
= dbwrite(ut
, va
, &v
, sizeof(v
)); /* write out the vol frag struct */
1200 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1204 LogDebug(4, "added volume %s at %d\n", vol
->name
, va
);
1206 code
= ubik_EndTrans(ut
);
1210 ubik_AbortTrans(ut
);
1216 SBUDB_AddVolumes(struct rx_call
*call
, struct budb_volumeList
*vols
)
1220 code
= AddVolumes(call
, vols
);
1221 osi_auditU(call
, BUDB_AddVolEvent
, code
, AUD_LONG
, 0, AUD_END
);
1226 AddVolumes(struct rx_call
*call
, struct budb_volumeList
*vols
)
1228 struct budb_volumeEntry
*vol
, *vol1
;
1229 struct ubik_trans
*ut
;
1230 dbadr da
, ta
, via
, va
;
1234 struct volFragment v
;
1236 afs_int32 eval
, e
, code
= 0;
1238 if (!callPermitted(call
))
1239 return BUDB_NOTPERMITTED
;
1241 if (!vols
|| (vols
->budb_volumeList_len
<= 0)
1242 || !vols
->budb_volumeList_val
)
1243 return BUDB_BADARGUMENT
;
1245 /* The first volume in the list of volumes to add */
1246 vol1
= (struct budb_volumeEntry
*)vols
->budb_volumeList_val
;
1248 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1252 /* Find the dump in dumpid hash table */
1253 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &vol1
->dump
, &da
, &d
);
1257 ABORT(BUDB_NODUMPID
);
1259 /* search for the right tape in the dump */
1260 for (ta
= ntohl(d
.firstTape
); ta
; ta
= ntohl(t
.nextTape
)) {
1261 /* read the tape entry */
1262 eval
= dbread(ut
, ta
, &t
, sizeof(t
));
1266 /* Check if the right tape name */
1267 if (strcmp(t
.name
, vol1
->tape
) == 0)
1271 ABORT(BUDB_NOTAPENAME
);
1273 if ((t
.dump
!= htonl(da
)) || /* tape must belong to dump */
1274 ((ntohl(t
.flags
) & BUDB_TAPE_BEINGWRITTEN
) == 0) || /* tape must be being written */
1275 ((ntohl(d
.flags
) & BUDB_DUMP_INPROGRESS
) == 0)) /* dump must be in progress */
1276 ABORT(BUDB_BADPROTOCOL
);
1278 for (vol
= vol1
, e
= 0; e
< vols
->budb_volumeList_len
; vol
++, e
++) {
1280 if ((strlen(vol
->name
) >= sizeof(vi
.name
)) || (strcmp(vol
->name
, "") == 0) || /* no null volnames */
1281 (strlen(vol
->server
) >= sizeof(vi
.server
))
1282 || (strlen(vol
->tape
) >= sizeof(t
.name
))
1283 || (strcmp(vol
->tape
, vol1
->tape
) != 0)) {
1284 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n", vol
->name
, vol
->id
, vol
->tape
, vol
->dump
);
1288 /* find or create a volume info structure */
1289 eval
= GetVolInfo(ut
, vol
, &via
, &vi
);
1292 if (*(afs_int32
*) (&vi
) == 0) {
1293 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n", vol
->name
, vol
->tape
, vol
->dump
);
1294 ABORT(BUDB_BADARGUMENT
);
1297 /* Create a volume fragment */
1298 eval
= AllocStructure(ut
, volFragment_BLOCK
, 0, &va
, &v
);
1302 v
.vol
= htonl(via
); /* vol frag points to vol info */
1303 v
.sameNameChain
= vi
.firstFragment
; /* vol frag is chained to vol info */
1304 vi
.firstFragment
= htonl(va
);
1305 vi
.nFrags
= htonl(ntohl(vi
.nFrags
) + 1);
1306 eval
= dbwrite(ut
, via
, &vi
, sizeof(vi
)); /* write the vol info struct */
1310 v
.tape
= htonl(ta
); /* vol frag points to tape */
1311 v
.sameTapeChain
= t
.firstVol
; /* vol frag is chained to tape info */
1312 t
.firstVol
= htonl(va
);
1313 t
.nVolumes
= htonl(ntohl(t
.nVolumes
) + 1);
1314 bytes
= ntohl(t
.nBytes
) + vol
->nBytes
; /* update bytes on tape */
1315 t
.nMBytes
= htonl(ntohl(t
.nMBytes
) + bytes
/ (1024 * 1024));
1316 t
.nBytes
= htonl(bytes
% (1024 * 1024));
1318 d
.nVolumes
= htonl(ntohl(d
.nVolumes
) + 1); /* one more volume on dump */
1320 v
.position
= htonl(vol
->position
); /* vol frag info */
1321 v
.clone
= htonl(vol
->clone
);
1322 v
.incTime
= htonl(vol
->incTime
);
1323 v
.startByte
= htonl(vol
->startByte
);
1324 v
.nBytes
= htonl(vol
->nBytes
);
1325 v
.flags
= htons(vol
->flags
& VOLFRAGMENTFLAGS
);
1326 v
.sequence
= htons(vol
->seq
);
1328 eval
= dbwrite(ut
, va
, &v
, sizeof(v
)); /* write out the vol frag struct */
1332 LogDebug(4, "added volume %s at %d\n", vol
->name
, va
);
1335 eval
= dbwrite(ut
, ta
, &t
, sizeof(t
)); /* write the tape structure */
1339 eval
= dbwrite(ut
, da
, &d
, sizeof(d
)); /* write out the dump structure */
1343 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1347 code
= ubik_EndTrans(ut
);
1351 ubik_AbortTrans(ut
);
1357 * records the existence of a dump in the database. This creates only
1358 * the dump record, to which one must attach tape and volume records.
1360 * 1) record the volume set
1364 SBUDB_CreateDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
1368 code
= CreateDump(call
, dump
);
1369 osi_auditU(call
, BUDB_CrDmpEvent
, code
, AUD_DATE
, (dump
? dump
->id
: 0),
1371 if (dump
&& !code
) {
1372 Log("Create dump %s (DumpID %u), path %s\n", dump
->name
, dump
->id
,
1379 CreateDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
1381 struct ubik_trans
*ut
;
1382 dbadr findDumpAddr
, da
;
1383 struct dump findDump
, d
;
1384 afs_int32 eval
, code
= 0;
1388 Date expiration
; /* checked by Security Module */
1389 struct ktc_principal principal
;
1391 if (!callPermitted(call
))
1392 return BUDB_NOTPERMITTED
;
1394 if (strlen(dump
->name
) >= sizeof(d
.dumpName
))
1395 return BUDB_BADARGUMENT
;
1397 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1402 rxkad_GetServerInfo(rx_ConnectionOf(call
), &level
, &expiration
,
1403 principal
.name
, principal
.instance
,
1404 principal
.cell
, &kvno
);
1407 if (eval
!= RXKADNOAUTH
)
1410 strcpy(principal
.name
, "");
1411 strcpy(principal
.instance
, "");
1412 strcpy(principal
.cell
, "");
1415 /* authenticated. Take user supplied principal information */
1416 if (strcmp(dump
->dumper
.name
, "") != 0)
1417 strncpy(principal
.name
, dump
->dumper
.name
,
1418 sizeof(principal
.name
));
1420 if (strcmp(dump
->dumper
.instance
, "") != 0)
1421 strncpy(principal
.instance
, dump
->dumper
.instance
,
1422 sizeof(principal
.instance
));
1424 if (strcmp(dump
->dumper
.cell
, "") != 0)
1425 strncpy(principal
.cell
, dump
->dumper
.cell
,
1426 sizeof(principal
.cell
));
1429 /* dump id's are time stamps */
1431 while (1) { /* allocate a unique dump id *//*w */
1434 /* ensure it is unique - seach for dumpid in hash table */
1436 ht_LookupEntry(ut
, &db
.dumpIden
, &dump
->id
, &findDumpAddr
,
1441 if (!findDumpAddr
) { /* dumpid not in use */
1442 /* update the last dump id allocated */
1443 eval
= set_header_word(ut
, lastDumpId
, htonl(dump
->id
));
1449 /* dump id is in use - wait a while */
1450 #ifdef AFS_PTHREAD_ENV
1457 /* dump id supplied (e.g. for database restore) */
1459 ht_LookupEntry(ut
, &db
.dumpIden
, &dump
->id
, &findDumpAddr
,
1464 /* Dump id must not already exist */
1466 ABORT(BUDB_DUMPIDEXISTS
);
1469 /* Allocate a dump structure */
1470 memset(&d
, 0, sizeof(d
));
1471 eval
= AllocStructure(ut
, dump_BLOCK
, 0, &da
, &d
);
1475 strcpy(d
.dumpName
, dump
->name
); /* volset.dumpname */
1476 strcpy(d
.dumpPath
, dump
->dumpPath
); /* dump node path */
1477 strcpy(d
.volumeSet
, dump
->volumeSetName
); /* volume set */
1478 d
.id
= htonl(dump
->id
);
1479 d
.parent
= htonl(dump
->parent
); /* parent id */
1480 d
.level
= htonl(dump
->level
);
1482 LogDebug(4, "dump name %s, parent %d level %d\n", dump
->name
,
1483 dump
->parent
, dump
->level
);
1485 /* if creation time specified, use that. Else use the dumpid time */
1486 if (dump
->created
== 0)
1487 dump
->created
= dump
->id
;
1488 d
.created
= htonl(dump
->created
);
1490 d
.dumper
= principal
;
1491 tapeSet_hton(&dump
->tapes
, &d
.tapes
);
1493 d
.flags
= htonl(dump
->flags
| BUDB_DUMP_INPROGRESS
);
1495 eval
= ht_HashIn(ut
, &db
.dumpName
, da
, &d
); /* Into dump name hash table */
1499 eval
= ht_HashIn(ut
, &db
.dumpIden
, da
, &d
); /* Into dumpid hash table */
1503 eval
= dbwrite(ut
, da
, (char *)&d
, sizeof(d
)); /* Write the dump structure */
1507 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1511 /* If to append this dump, then append it - will write the appended dump */
1512 eval
= makeAppended(ut
, dump
->id
, dump
->initialDumpID
, dump
->tapes
.b
);
1516 code
= ubik_EndTrans(ut
);
1517 LogDebug(5, "made dump %s, path %s\n", d
.dumpName
, d
.dumpPath
);
1521 ubik_AbortTrans(ut
);
1526 SBUDB_DeleteDump(struct rx_call
*call
, dumpId id
, Date fromTime
, Date toTime
,
1527 budb_dumpsList
*dumps
)
1531 code
= DoDeleteDump(call
, id
, fromTime
, toTime
, dumps
);
1532 osi_auditU(call
, BUDB_DelDmpEvent
, code
, AUD_DATE
, id
, AUD_END
);
1539 DoDeleteDump(struct rx_call
*call
, dumpId id
, Date fromTime
, Date toTime
,
1540 budb_dumpsList
*dumps
)
1544 if (!callPermitted(call
))
1545 return BUDB_NOTPERMITTED
;
1548 code
= deleteDump(call
, id
, dumps
);
1553 SBUDB_ListDumps(struct rx_call
*call
, afs_int32 sflags
, char *name
,
1554 afs_int32 groupid
, Date fromTime
, Date toTime
,
1555 budb_dumpsList
*dumps
, budb_dumpsList
*flags
)
1559 code
= ListDumps(call
, sflags
, groupid
, fromTime
, toTime
, dumps
, flags
);
1560 osi_auditU(call
, BUDB_LstDmpEvent
, code
, AUD_LONG
, flags
, AUD_END
);
1565 ListDumps(struct rx_call
*call
, afs_int32 sflags
, afs_int32 groupid
,
1566 Date fromTime
, Date toTime
, budb_dumpsList
*dumps
,
1567 budb_dumpsList
*flags
)
1569 struct ubik_trans
*ut
;
1570 struct memoryHashTable
*mht
;
1571 struct dump diskDump
, appDiskDump
;
1572 dbadr dbAddr
, dbAppAddr
;
1574 afs_int32 eval
, code
= 0;
1575 int old
, hash
, length
, entrySize
, count
= 0;
1577 if (!callPermitted(call
))
1578 return BUDB_NOTPERMITTED
;
1580 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1584 /* Search the database */
1585 mht
= ht_GetType(HT_dumpIden_FUNCTION
, &entrySize
);
1587 return (BUDB_BADARGUMENT
);
1589 for (old
= 0; old
<= 1; old
++) { /*o *//* old and new hash tables */
1590 length
= (old
? mht
->oldLength
: mht
->length
);
1594 for (hash
= 0; hash
< length
; hash
++) { /*h *//* for each hash bucket */
1595 for (dbAddr
= ht_LookupBucket(ut
, mht
, hash
, old
); dbAddr
; dbAddr
= ntohl(diskDump
.idHashChain
)) { /*d */
1597 /* read the entry */
1598 eval
= dbread(ut
, dbAddr
, &diskDump
, sizeof(diskDump
));
1602 /* Skip appended dumps */
1603 if (ntohl(diskDump
.initialDumpID
) != 0) {
1607 /* Skip dumps with different goup id */
1608 if ((sflags
& BUDB_OP_GROUPID
)
1609 && (ntohl(diskDump
.tapes
.id
) != groupid
)) {
1613 /* Look at this dump to see if it meets the criteria for listing */
1614 if (sflags
& BUDB_OP_DATES
) {
1615 /* This and each appended dump should be in time */
1616 for (dbAppAddr
= dbAddr
; dbAppAddr
;
1617 dbAppAddr
= ntohl(appDiskDump
.appendedDumpChain
)) {
1619 dbread(ut
, dbAppAddr
, &appDiskDump
,
1620 sizeof(appDiskDump
));
1624 if ((ntohl(appDiskDump
.id
) < fromTime
)
1625 || (ntohl(appDiskDump
.id
) > toTime
))
1632 /* Add it and each of its appended dump to our list to return */
1633 for (dbAppAddr
= dbAddr
; dbAppAddr
;
1634 dbAppAddr
= ntohl(appDiskDump
.appendedDumpChain
)) {
1636 dbread(ut
, dbAppAddr
, &appDiskDump
,
1637 sizeof(appDiskDump
));
1641 /* Make sure we have space to list it */
1642 if (dumps
->budb_dumpsList_len
>= count
) {
1645 dumps
->budb_dumpsList_val
=
1646 (afs_int32
*) malloc(count
*
1648 flags
->budb_dumpsList_val
=
1649 (afs_int32
*) malloc(count
*
1652 dumps
->budb_dumpsList_val
=
1653 (afs_int32
*) realloc(dumps
->
1657 flags
->budb_dumpsList_val
=
1658 (afs_int32
*) realloc(flags
->
1663 if (!dumps
->budb_dumpsList_val
1664 || !dumps
->budb_dumpsList_val
)
1668 /* Add it to our list */
1669 dumps
->budb_dumpsList_val
[dumps
->budb_dumpsList_len
] =
1670 ntohl(appDiskDump
.id
);
1671 flags
->budb_dumpsList_val
[flags
->budb_dumpsList_len
] = 0;
1672 if (ntohl(appDiskDump
.initialDumpID
) != 0) {
1673 flags
->budb_dumpsList_val
[flags
->
1674 budb_dumpsList_len
] |=
1677 if (strcmp(appDiskDump
.dumpName
, DUMP_TAPE_NAME
) == 0) {
1678 flags
->budb_dumpsList_val
[flags
->
1679 budb_dumpsList_len
] |=
1682 dumps
->budb_dumpsList_len
++;
1683 flags
->budb_dumpsList_len
++;
1689 code
= ubik_EndTrans(ut
);
1693 ubik_AbortTrans(ut
);
1698 SBUDB_DeleteTape(struct rx_call
*call
,
1699 struct budb_tapeEntry
*tape
) /* tape info */
1703 code
= DoDeleteTape(call
, tape
);
1704 osi_auditU(call
, BUDB_DelTpeEvent
, code
, AUD_DATE
,
1705 (tape
? tape
->dump
: 0), AUD_END
);
1710 DoDeleteTape(struct rx_call
*call
,
1711 struct budb_tapeEntry
*tape
) /* tape info */
1713 struct ubik_trans
*ut
;
1716 afs_int32 eval
, code
;
1718 if (!callPermitted(call
))
1719 return BUDB_NOTPERMITTED
;
1721 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1725 eval
= ht_LookupEntry(ut
, &db
.tapeName
, tape
->name
, &a
, &t
);
1729 eval
= DeleteTape(ut
, a
, &t
);
1733 eval
= FreeStructure(ut
, tape_BLOCK
, a
);
1737 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1741 code
= ubik_EndTrans(ut
);
1745 ubik_AbortTrans(ut
);
1750 * Deletes old information from the database for a particular dump path
1751 * and volumset. This supercedes the old policy implemented in
1752 * UseTape, which simply matched on the volumeset.dump. Consequently
1753 * it was unable to handle name re-use.
1755 * dsname - dumpset name, i.e. volumeset.dumpname
1756 * dumpPath - full path of dump node
1757 * curDumpID - current dump in progress - so that is may be excluded
1760 * n - some error. May or may not have deleted information.
1764 SBUDB_DeleteVDP(struct rx_call
*call
, char *dsname
, char *dumpPath
,
1765 afs_int32 curDumpId
)
1769 code
= DeleteVDP(call
, dsname
, dumpPath
, curDumpId
);
1770 osi_auditU(call
, BUDB_DelVDPEvent
, code
, AUD_STR
, dsname
, AUD_END
);
1775 DeleteVDP(struct rx_call
*call
, char *dsname
, char *dumpPath
,
1776 afs_int32 curDumpId
)
1781 struct ubik_trans
*ut
;
1782 afs_int32 eval
, code
= 0;
1784 if (!callPermitted(call
))
1785 return BUDB_NOTPERMITTED
;
1788 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1792 eval
= ht_LookupEntry(ut
, &db
.dumpName
, dsname
, &dumpAddr
, &dump
);
1796 while (dumpAddr
!= 0) { /*wd */
1797 if ((strcmp(dump
.dumpName
, dsname
) == 0)
1798 && (strcmp(dump
.dumpPath
, dumpPath
) == 0)
1799 && (ntohl(dump
.id
) != curDumpId
)) {
1800 eval
= ubik_EndTrans(ut
);
1804 eval
= deleteDump(call
, ntohl(dump
.id
), 0);
1808 /* start the traversal over since the various chains may
1814 dumpAddr
= ntohl(dump
.nameHashChain
);
1816 eval
= dbread(ut
, dumpAddr
, &dump
, sizeof(dump
));
1822 /* check if all the dumps have been examined - can terminate */
1824 eval
= ubik_EndTrans(ut
);
1830 ubik_AbortTrans(ut
);
1836 * Given a volume name, and a dumpID, find the volume in that dump and
1837 * return the clone date of the volume (this is the clone date of the
1838 * volume at the time it was dumped).
1840 * Hashes on the volume name and traverses the fragments. Will need to read
1841 * the volumes tape entry to determine if it belongs to the dump. If the
1842 * volume is not found in the dump, then look for it in its parent dump.
1846 SBUDB_FindClone(struct rx_call
*call
, afs_int32 dumpID
, char *volName
,
1847 afs_int32
*clonetime
)
1851 code
= FindClone(call
, dumpID
, volName
, clonetime
);
1852 osi_auditU(call
, BUDB_FndClnEvent
, code
, AUD_STR
, volName
, AUD_END
);
1857 FindClone(struct rx_call
*call
, afs_int32 dumpID
, char *volName
,
1858 afs_int32
*clonetime
)
1860 struct ubik_trans
*ut
;
1861 dbadr da
, hvia
, via
, vfa
;
1864 struct volFragment vf
;
1866 int rvi
; /* read the volInfo struct */
1867 afs_int32 eval
, code
= 0;
1869 if (!callPermitted(call
))
1870 return BUDB_NOTPERMITTED
;
1872 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1878 /* Search for the volume by name */
1879 eval
= ht_LookupEntry(ut
, &db
.volName
, volName
, &hvia
, &vi
);
1883 ABORT(BUDB_NOVOLUMENAME
);
1886 /* Follw the dump levels up */
1887 for (; dumpID
; dumpID
= ntohl(d
.parent
)) { /*d */
1888 /* Get the dump entry */
1889 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dumpID
, &da
, &d
);
1893 ABORT(BUDB_NODUMPID
);
1895 /* seach all the volInfo entries on the sameNameChain */
1896 for (via
= hvia
; via
; via
= ntohl(vi
.sameNameChain
)) { /*via */
1897 if (rvi
) { /* Read the volInfo entry - except first time */
1898 eval
= dbread(ut
, via
, &vi
, sizeof(vi
));
1904 /* search all the volFrag entries on the volFrag */
1905 for (vfa
= ntohl(vi
.firstFragment
); vfa
; vfa
= ntohl(vf
.sameNameChain
)) { /*vfa */
1906 eval
= dbread(ut
, vfa
, &vf
, sizeof(vf
)); /* Read the volFrag entry */
1910 eval
= dbread(ut
, ntohl(vf
.tape
), &t
, sizeof(t
)); /* Read the tape */
1914 /* Now check to see if this fragment belongs to the dump we have */
1915 if (ntohl(t
.dump
) == da
) {
1916 *clonetime
= ntohl(vf
.clone
); /* return the clone */
1924 code
= ubik_EndTrans(ut
);
1934 * Searches each tape and each volume in the dump until the volume is found.
1935 * If the volume is not in the dump, then we search it's parent dump.
1937 * Re-write to do lookups by volume name.
1940 FindClone(struct rx_call
*call
, afs_int32 dumpID
, char *volName
,
1941 afs_int32
*clonetime
)
1943 struct ubik_trans
*ut
;
1944 dbadr diskAddr
, tapeAddr
, volFragmentAddr
;
1947 struct volFragment volFragment
;
1948 struct volInfo volInfo
;
1949 afs_int32 eval
, code
= 0;
1951 if (!callPermitted(call
))
1952 return BUDB_NOTPERMITTED
;
1954 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1960 for (; dumpID
; dumpID
= ntohl(dump
.parent
)) { /*d */
1961 /* Get the dump entry */
1962 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dumpID
, &diskAddr
, &dump
);
1966 ABORT(BUDB_NODUMPID
);
1968 /* just to be sure */
1969 if (ntohl(dump
.id
) != dumpID
) {
1970 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID
,
1972 ABORT(BUDB_INTERNALERROR
);
1975 /* search all the tapes in this dump */
1976 for (tapeAddr
= ntohl(dump
.firstTape
); tapeAddr
; tapeAddr
= ntohl(tape
.nextTape
)) { /*t */
1977 /* Get the tape entry */
1978 eval
= dbread(ut
, tapeAddr
, &tape
, sizeof(tape
));
1982 /* search all the volume fragments on this tape */
1983 for (volFragmentAddr
= ntohl(tape
.firstVol
); volFragmentAddr
; volFragmentAddr
= ntohl(volFragment
.sameTapeChain
)) { /*vf */
1984 /* Get the volume fragment entry */
1986 dbread(ut
, volFragmentAddr
, &volFragment
,
1987 sizeof(volFragment
));
1991 /* Get the volume info entry */
1993 dbread(ut
, ntohl(volFragment
.vol
), &volInfo
,
1998 /* check if this volume is the one we want */
1999 if (strcmp(volInfo
.name
, volName
) == 0) {
2000 *clonetime
= ntohl(volFragment
.clone
);
2008 code
= ubik_EndTrans(ut
);
2018 * Find latest volume dump before adate.
2019 * Used by restore code when restoring a user requested volume(s)
2021 * volumeName - name of volume to match on
2022 * beforeDate - look for dumps older than this date
2024 * deptr - descriptor of most recent dump
2028 SBUDB_FindDump(struct rx_call
*call
, char *volumeName
, afs_int32 beforeDate
,
2029 struct budb_dumpEntry
*deptr
)
2033 code
= FindDump(call
, volumeName
, beforeDate
, deptr
);
2034 osi_auditU(call
, BUDB_FndDmpEvent
, code
, AUD_STR
, volumeName
, AUD_END
);
2039 FindDump(struct rx_call
*call
, char *volumeName
, afs_int32 beforeDate
,
2040 struct budb_dumpEntry
*deptr
)
2042 struct ubik_trans
*ut
;
2043 dbadr volInfoAddr
, volFragmentAddr
;
2045 struct volInfo volInfo
;
2046 struct volFragment volFragment
;
2048 dbadr selectedDumpAddr
= 0;
2049 afs_int32 selectedDate
= 0;
2050 afs_int32 volCloned
;
2052 afs_int32 eval
, code
= 0;
2054 if (!callPermitted(call
))
2055 return BUDB_NOTPERMITTED
;
2057 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2061 /* Find volinfo struct for volume name in hash table */
2063 ht_LookupEntry(ut
, &db
.volName
, volumeName
, &volInfoAddr
, &volInfo
);
2067 ABORT(BUDB_NOVOLUMENAME
);
2069 /* Step through all the volinfo structures on the same name chain.
2070 * No need to read the first - we read it above.
2072 for (rvoli
= 0; volInfoAddr
;
2073 rvoli
= 1, volInfoAddr
= ntohl(volInfo
.sameNameChain
)) {
2074 if (rvoli
) { /* read the volinfo structure */
2075 eval
= dbread(ut
, volInfoAddr
, &volInfo
, sizeof(volInfo
));
2080 /* step through the volfrag structures */
2081 for (volFragmentAddr
= ntohl(volInfo
.firstFragment
); volFragmentAddr
;
2082 volFragmentAddr
= ntohl(volFragment
.sameNameChain
)) {
2083 /* read the volfrag struct */
2085 dbread(ut
, volFragmentAddr
, &volFragment
,
2086 sizeof(volFragment
));
2090 volCloned
= ntohl(volFragment
.clone
);
2092 /* now we can examine the date for most recent dump */
2093 if ((volCloned
> selectedDate
) && (volCloned
< beforeDate
)) {
2094 /* from the volfrag struct, read the tape struct */
2096 dbread(ut
, ntohl(volFragment
.tape
), &tape
, sizeof(tape
));
2100 selectedDate
= volCloned
;
2101 selectedDumpAddr
= ntohl(tape
.dump
);
2106 if (!selectedDumpAddr
)
2109 eval
= FillDumpEntry(ut
, selectedDumpAddr
, deptr
);
2113 code
= ubik_EndTrans(ut
);
2121 /* BUDB_FindLatestDump
2122 * Find the latest dump of volumeset vsname with dump name dname.
2124 * vsname - volumeset name
2129 SBUDB_FindLatestDump(struct rx_call
*call
, char *vsname
, char *dumpPath
,
2130 struct budb_dumpEntry
*dumpentry
)
2134 code
= FindLatestDump(call
, vsname
, dumpPath
, dumpentry
);
2135 osi_auditU(call
, BUDB_FndLaDEvent
, code
, AUD_STR
, vsname
, AUD_END
);
2140 FindLatestDump(struct rx_call
*call
, char *vsname
, char *dumpPath
,
2141 struct budb_dumpEntry
*dumpentry
)
2143 struct ubik_trans
*ut
;
2144 dbadr curdbaddr
, retdbaddr
, firstdbaddr
;
2147 char dumpName
[BU_MAXNAMELEN
+ 2];
2148 afs_int32 eval
, code
= 0;
2150 if (!callPermitted(call
))
2151 return BUDB_NOTPERMITTED
;
2153 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2157 if ((strcmp(vsname
, "") == 0) && (strcmp(dumpPath
, "") == 0)) {
2158 /* Construct a database dump name */
2159 strcpy(dumpName
, DUMP_TAPE_NAME
);
2160 } else if (strchr(dumpPath
, '/') == 0) {
2161 int level
, old
, length
, hash
;
2162 struct dump hostDump
, diskDump
;
2163 struct memoryHashTable
*mht
;
2166 afs_uint32 bestDumpId
= 0;
2168 level
= atoi(dumpPath
);
2170 ABORT(BUDB_BADARGUMENT
);
2173 /* Brute force search of all the dumps in the database - yuck! */
2176 mht
= ht_GetType(HT_dumpIden_FUNCTION
, &entrySize
);
2178 ABORT(BUDB_BADARGUMENT
);
2180 for (old
= 0; old
<= 1; old
++) { /*fo */
2181 length
= (old
? mht
->oldLength
: mht
->length
);
2185 for (hash
= 0; hash
< length
; hash
++) {
2187 for (dbAddr
= ht_LookupBucket(ut
, mht
, hash
, old
); dbAddr
;
2188 dbAddr
= hostDump
.idHashChain
) {
2190 eval
= dbread(ut
, dbAddr
, &diskDump
, sizeof(diskDump
));
2193 dump_ntoh(&diskDump
, &hostDump
);
2195 if ((strcmp(hostDump
.volumeSet
, vsname
) == 0) && /* the volumeset */
2196 (hostDump
.level
== level
) && /* same level */
2197 (hostDump
.id
> bestDumpId
)) { /* more recent */
2198 bestDumpId
= hostDump
.id
;
2205 ABORT(BUDB_NODUMPNAME
);
2209 /* construct the name of the dump */
2210 if ((strlen(vsname
) + strlen(tailCompPtr(dumpPath
))) > BU_MAXNAMELEN
)
2211 ABORT(BUDB_NODUMPNAME
);
2213 strcpy(dumpName
, vsname
);
2214 strcat(dumpName
, ".");
2215 strcat(dumpName
, tailCompPtr(dumpPath
));
2218 LogDebug(5, "lookup on :%s:\n", dumpName
);
2220 /* Lookup on dumpname in hash table */
2221 eval
= ht_LookupEntry(ut
, &db
.dumpName
, dumpName
, &firstdbaddr
, &d
);
2228 /* folow remaining dumps in hash chain, looking for most latest dump */
2229 for (curdbaddr
= firstdbaddr
; curdbaddr
;
2230 curdbaddr
= ntohl(d
.nameHashChain
)) {
2231 if (curdbaddr
!= firstdbaddr
) {
2232 eval
= dbread(ut
, curdbaddr
, &d
, sizeof(d
));
2237 if ((strcmp(d
.dumpPath
, dumpPath
) == 0) && /* Same dumppath */
2238 (strcmp(d
.dumpName
, dumpName
) == 0) && /* Same dumpname */
2239 (ntohl(d
.created
) > latest
)) { /* most recent */
2240 latest
= ntohl(d
.created
);
2241 retdbaddr
= curdbaddr
;
2245 ABORT(BUDB_NODUMPNAME
);
2248 /* return the dump found */
2249 FillDumpEntry(ut
, retdbaddr
, dumpentry
);
2251 code
= ubik_EndTrans(ut
);
2255 ubik_AbortTrans(ut
);
2261 SBUDB_FinishDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
2265 code
= FinishDump(call
, dump
);
2266 osi_auditU(call
, BUDB_FinDmpEvent
, code
, AUD_DATE
, (dump
? dump
->id
: 0),
2272 FinishDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
2274 struct ubik_trans
*ut
;
2277 afs_int32 eval
, code
= 0;
2279 if (!callPermitted(call
))
2280 return BUDB_NOTPERMITTED
;
2282 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
2286 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dump
->id
, &a
, &d
);
2290 ABORT(BUDB_NODUMPID
);
2292 if ((ntohl(d
.flags
) & BUDB_DUMP_INPROGRESS
) == 0)
2293 ABORT(BUDB_DUMPNOTINUSE
);
2295 d
.flags
= htonl(dump
->flags
& ~BUDB_DUMP_INPROGRESS
);
2297 /* if creation time specified set it */
2299 d
.created
= htonl(dump
->created
);
2300 dump
->created
= ntohl(d
.created
);
2302 /* Write the dump entry out */
2303 eval
= dbwrite(ut
, a
, &d
, sizeof(d
));
2307 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
2311 code
= ubik_EndTrans(ut
);
2315 ubik_AbortTrans(ut
);
2320 SBUDB_FinishTape(struct rx_call
*call
, struct budb_tapeEntry
*tape
)
2324 code
= FinishTape(call
, tape
);
2325 osi_auditU(call
, BUDB_FinTpeEvent
, code
, AUD_DATE
,
2326 (tape
? tape
->dump
: 0), AUD_END
);
2331 FinishTape(struct rx_call
*call
, struct budb_tapeEntry
*tape
)
2333 struct ubik_trans
*ut
;
2337 afs_int32 eval
, code
= 0;
2339 if (!callPermitted(call
))
2340 return BUDB_NOTPERMITTED
;
2342 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
2346 /* find the tape struct in the tapename hash chain */
2347 eval
= ht_LookupEntry(ut
, &db
.tapeName
, tape
->name
, &a
, &t
);
2351 ABORT(BUDB_NOTAPENAME
);
2353 /* Read the dump structure */
2354 eval
= dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
));
2358 /* search for the right tape on the rest of the chain */
2359 while (ntohl(d
.id
) != tape
->dump
) {
2360 a
= ntohl(t
.nameHashChain
);
2362 ABORT(BUDB_NOTAPENAME
);
2364 eval
= dbread(ut
, a
, &t
, sizeof(t
));
2368 eval
= dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
));
2373 if ((ntohl(t
.flags
) & BUDB_TAPE_BEINGWRITTEN
) == 0)
2374 ABORT(BUDB_TAPENOTINUSE
);
2376 /* t.nBytes = htonl(tape->nBytes); */
2377 t
.nFiles
= htonl(tape
->nFiles
);
2378 t
.useKBytes
= htonl(tape
->useKBytes
);
2379 t
.flags
= htonl(tape
->flags
& ~BUDB_TAPE_BEINGWRITTEN
);
2381 eval
= dbwrite(ut
, a
, &t
, sizeof(t
));
2385 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
2389 code
= ubik_EndTrans(ut
);
2393 ubik_AbortTrans(ut
);
2398 * return a set of dumps that match the specified criteria
2401 * majorVersion - version of interface structures. Permits compatibility
2403 * flags - for search and select operations. Broken down into flags
2404 * for name, start point, end point and time.
2405 * name - name to search for. Interpretation based on flags
2412 * dbTimeP - time at which the database was last modified. Up to
2413 * caller (client) to take appropriate action if database
2414 * modified between successive calls
2415 * dumps - list of matching dumps
2417 * currently supported are:
2423 SBUDB_GetDumps(struct rx_call
*call
,
2424 afs_int32 majorVersion
, /* version of interface structures */
2425 afs_int32 flags
, /* search & select controls */
2426 char *name
, /* s&s parameters */
2429 afs_int32 index
, /* start index of returned entries */
2430 afs_int32
*nextIndexP
, /* output index for next call */
2432 budb_dumpList
*dumps
) /* pointer to buffer */
2437 GetDumps(call
, majorVersion
, flags
, name
, start
, end
, index
,
2438 nextIndexP
, dbTimeP
, dumps
);
2439 osi_auditU(call
, BUDB_GetDmpEvent
, code
, AUD_END
);
2444 GetDumps(struct rx_call
*call
,
2445 afs_int32 majorVersion
, /* version of interface structures */
2446 afs_int32 flags
, /* search & select controls */
2447 char *name
, /* s&s parameters */
2450 afs_int32 index
, /* start index of returned entries */
2451 afs_int32
*nextIndexP
, /* output index for next call */
2453 budb_dumpList
*dumps
) /* pointer to buffer */
2455 struct ubik_trans
*ut
;
2458 afs_int32 nameFlags
, startFlags
, endFlags
, timeFlags
;
2459 afs_int32 eval
, code
= 0;
2461 struct returnList list
;
2463 /* Don't check permissions when we look up a specific dump id */
2464 if (((flags
& BUDB_OP_STARTS
) != BUDB_OP_DUMPID
) && !callPermitted(call
))
2465 return BUDB_NOTPERMITTED
;
2467 if (majorVersion
!= BUDB_MAJORVERSION
)
2468 return BUDB_OLDINTERFACE
;
2470 return BUDB_ENDOFLIST
;
2472 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2476 nameFlags
= flags
& BUDB_OP_NAMES
;
2477 startFlags
= flags
& BUDB_OP_STARTS
;
2478 endFlags
= flags
& BUDB_OP_ENDS
;
2479 timeFlags
= flags
& BUDB_OP_TIMES
;
2481 InitReturnList(&list
);
2484 if (nameFlags
== BUDB_OP_DUMPNAME
) {
2485 /* not yet implemented */
2486 if (startFlags
|| endFlags
|| timeFlags
)
2487 ABORT(BUDB_BADFLAGS
);
2489 eval
= ht_LookupEntry(ut
, &db
.dumpName
, name
, &da
, &d
);
2493 ABORT(BUDB_NODUMPNAME
);
2496 if (strcmp(d
.dumpName
, name
) == 0) {
2497 eval
= AddToReturnList(&list
, da
, &toskip
);
2498 if (eval
== BUDB_LIST2BIG
)
2504 da
= ntohl(d
.nameHashChain
); /* get next dump w/ name */
2508 eval
= dbread(ut
, da
, &d
, sizeof(d
));
2512 } else if (nameFlags
== BUDB_OP_VOLUMENAME
) {
2516 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2517 ABORT(BUDB_BADFLAGS
);
2520 if (startFlags
!= BUDB_OP_STARTTIME
)
2521 ABORT(BUDB_BADFLAGS
);
2523 /* lookup a dump by volumename and time stamp. Find the most recent
2524 * dump of the specified volumename, that occured before the supplied
2528 /* get us a volInfo for name */
2529 eval
= ht_LookupEntry(ut
, &db
.volName
, name
, &da
, &vi
);
2534 /* now iterate over all the entries of this name */
2535 for (va
= vi
.firstFragment
; va
!= 0; va
= v
.sameNameChain
) {
2537 eval
= dbread(ut
, va
, &v
, sizeof(v
));
2542 on fragment
> date ignore it
- too recent
;
2544 if (date on fragment
< date
&& date on fragment
> bestfound
)
2545 bestfound
= date on fragment
;
2549 da
= vi
.sameNameChain
;
2553 eval
= dbread(ut
, da
, &vi
, sizeof(vi
));
2562 from saved volfragment address, compute dump.
2563 otherwise, return dump found
2568 } else if (startFlags
== BUDB_OP_DUMPID
) {
2569 if (endFlags
|| timeFlags
)
2570 ABORT(BUDB_BADFLAGS
);
2572 ABORT(BUDB_BADFLAGS
); /* NYI */
2574 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &start
, &da
, &d
);
2578 ABORT(BUDB_NODUMPID
);
2580 eval
= AddToReturnList(&list
, da
, &toskip
);
2583 } else if (endFlags
== BUDB_OP_NPREVIOUS
) {
2584 struct wantDumpRock rock
;
2585 struct chosenDump
*ptr
, *nextPtr
;
2587 /* no other flags should be set */
2589 /* end specifies how many dumps */
2591 ABORT(BUDB_BADFLAGS
);
2593 memset(&rock
, 0, sizeof(rock
));
2594 rock
.maxDumps
= end
;
2596 scanHashTable(ut
, &db
.dumpName
, wantDump
, rememberDump
,
2599 for (ptr
= rock
.chain
; ptr
; ptr
= nextPtr
) {
2600 nextPtr
= ptr
->next
;
2601 AddToReturnList(&list
, ptr
->addr
, &toskip
); /* ignore error for free */
2605 ABORT(BUDB_BADFLAGS
);
2609 SendReturnList(ut
, &list
, FillDumpEntry
,
2610 sizeof(struct budb_dumpEntry
), index
, nextIndexP
,
2611 dbTimeP
, (returnList_t
) dumps
);
2615 FreeReturnList(&list
);
2616 code
= ubik_EndTrans(ut
);
2620 FreeReturnList(&list
);
2621 ubik_AbortTrans(ut
);
2626 * Get the expiration of a tape. Since the dump could have appended dumps,
2627 * we should use the most recent expiration date. Put the most recent
2628 * expiration tape into the given tape structure.
2631 getExpiration(struct ubik_trans
*ut
, struct tape
*tapePtr
)
2637 afs_int32 eval
, code
= 0;
2642 /* Get the dump for this tape */
2643 ad
= ntohl(tapePtr
->dump
);
2644 eval
= dbread(ut
, ad
, &d
, sizeof(d
));
2648 /* If not an initial dump, get the initial dump */
2649 if (d
.initialDumpID
) {
2650 initDump
= ntohl(d
.initialDumpID
);
2651 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &initDump
, &ad
, &d
);
2656 /* Cycle through the dumps and appended dumps */
2658 /* Get the first tape in this dump. No need to check the rest of the tapes */
2659 /* for this dump since they will all have the same expiration date */
2660 eval
= dbread(ut
, ntohl(d
.firstTape
), &t
, sizeof(t
));
2664 /* Take the greater of the expiration dates */
2665 if (ntohl(tapePtr
->expires
) < ntohl(t
.expires
))
2666 tapePtr
->expires
= t
.expires
;
2668 /* Step to and read the next appended dump */
2669 if ((ad
= ntohl(d
.appendedDumpChain
))) {
2670 eval
= dbread(ut
, ad
, &d
, sizeof(d
));
2680 /* Mark the following dump as appended to another, intial dump */
2682 makeAppended(struct ubik_trans
*ut
, afs_int32 appendedDumpID
,
2683 afs_int32 initialDumpID
, afs_int32 startTapeSeq
)
2685 dbadr ada
, da
, lastDumpAddr
;
2687 afs_int32 eval
, code
= 0;
2691 if (appendedDumpID
== initialDumpID
)
2692 ERROR(BUDB_INTERNALERROR
);
2694 /* If there is an initial dump, append this dump to it */
2695 /* Find the appended dump via its id */
2696 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &appendedDumpID
, &ada
, &ad
);
2700 /* If the dump is already marked as appended,
2701 * then we have an internal error.
2703 if (ad
.initialDumpID
) {
2704 if (ntohl(ad
.initialDumpID
) != initialDumpID
)
2705 ERROR(BUDB_INTERNALERROR
);
2708 /* Update the appended dump to point to the initial dump */
2709 ad
.initialDumpID
= htonl(initialDumpID
);
2710 ad
.tapes
.b
= htonl(startTapeSeq
);
2712 /* find the initial dump via its id */
2713 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &initialDumpID
, &da
, &d
);
2717 /* Update the appended dump's tape format with that of the initial */
2718 strcpy(ad
.tapes
.format
, d
.tapes
.format
);
2720 /* starting with the initial dump step through its appended dumps till
2721 * we reach the last appended dump.
2724 while (d
.appendedDumpChain
) {
2725 lastDumpAddr
= ntohl(d
.appendedDumpChain
);
2726 if (lastDumpAddr
== ada
)
2727 ERROR(0); /* Already appended */
2728 eval
= dbread(ut
, lastDumpAddr
, &d
, sizeof(d
));
2733 /* Update the last dump to point to our new appended dump.
2734 * The appended dump is the last one in the dump chain.
2736 d
.appendedDumpChain
= htonl(ada
);
2737 ad
.appendedDumpChain
= 0;
2739 /* Write the appended dump and the initial dump */
2740 eval
= dbwrite(ut
, ada
, (char *)&ad
, sizeof(ad
));
2744 eval
= dbwrite(ut
, lastDumpAddr
, (char *)&d
, sizeof(d
));
2748 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
2757 SBUDB_MakeDumpAppended(struct rx_call
*call
, afs_int32 appendedDumpID
,
2758 afs_int32 initialDumpID
, afs_int32 startTapeSeq
)
2763 MakeDumpAppended(call
, appendedDumpID
, initialDumpID
, startTapeSeq
);
2764 osi_auditU(call
, BUDB_AppDmpEvent
, code
, AUD_LONG
, appendedDumpID
,
2770 MakeDumpAppended(struct rx_call
*call
, afs_int32 appendedDumpID
,
2771 afs_int32 initialDumpID
, afs_int32 startTapeSeq
)
2773 struct ubik_trans
*ut
;
2774 afs_int32 eval
, code
= 0;
2776 if (!callPermitted(call
))
2777 return BUDB_NOTPERMITTED
;
2779 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
2783 eval
= makeAppended(ut
, appendedDumpID
, initialDumpID
, startTapeSeq
);
2787 code
= ubik_EndTrans(ut
);
2791 ubik_AbortTrans(ut
);
2795 /* Find the last tape of a dump-set. This includes any appended dumps */
2797 SBUDB_FindLastTape(struct rx_call
*call
, afs_int32 dumpID
,
2798 struct budb_dumpEntry
*dumpEntry
,
2799 struct budb_tapeEntry
*tapeEntry
,
2800 struct budb_volumeEntry
*volEntry
)
2804 code
= FindLastTape(call
, dumpID
, dumpEntry
, tapeEntry
, volEntry
);
2805 osi_auditU(call
, BUDB_FndLTpeEvent
, code
, AUD_LONG
, dumpID
, AUD_END
);
2810 FindLastTape(struct rx_call
*call
, afs_int32 dumpID
,
2811 struct budb_dumpEntry
*dumpEntry
,
2812 struct budb_tapeEntry
*tapeEntry
,
2813 struct budb_volumeEntry
*volEntry
)
2815 struct ubik_trans
*ut
;
2819 dbadr lastTape
, thisTape
;
2820 afs_int32 lastTapeSeq
;
2821 struct volFragment vf
;
2822 dbadr lastVol
, thisVol
;
2823 afs_int32 lastVolPos
;
2824 afs_int32 eval
, code
= 0;
2826 if (!callPermitted(call
))
2827 return BUDB_NOTPERMITTED
;
2830 return (BUDB_BADARGUMENT
);
2832 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2836 /* find and read its initial dump via its id */
2837 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dumpID
, &lastDump
, &d
);
2841 ABORT(BUDB_NODUMPID
);
2843 /* Follow the append dumps link chain until we reach the last dump */
2844 while (d
.appendedDumpChain
) {
2845 lastDump
= ntohl(d
.appendedDumpChain
);
2846 eval
= dbread(ut
, lastDump
, &d
, sizeof(d
));
2851 /* We now have the last dump of the last appended dump */
2852 /* Copy this into our return structure */
2853 eval
= FillDumpEntry(ut
, lastDump
, dumpEntry
);
2857 /* Fail if the last dump has no tapes */
2859 ABORT(BUDB_NOTAPENAME
);
2861 /* Follow the tapes in this dump until we reach the last tape */
2862 eval
= dbread(ut
, ntohl(d
.firstTape
), &t
, sizeof(t
));
2866 lastTape
= ntohl(d
.firstTape
);
2867 lastTapeSeq
= ntohl(t
.seq
);
2868 lastVol
= ntohl(t
.firstVol
);
2870 while (t
.nextTape
) {
2871 thisTape
= ntohl(t
.nextTape
);
2872 eval
= dbread(ut
, thisTape
, &t
, sizeof(t
));
2876 if (ntohl(t
.seq
) > lastTapeSeq
) {
2877 lastTape
= thisTape
;
2878 lastTapeSeq
= ntohl(t
.seq
);
2879 lastVol
= ntohl(t
.firstVol
);
2883 /* We now have the last tape of the last appended dump */
2884 /* Copy this into our return structure */
2885 eval
= FillTapeEntry(ut
, lastTape
, tapeEntry
);
2889 /* Zero volume entry if the last tape has no volumes */
2891 memset(volEntry
, 0, sizeof(*volEntry
));
2893 /* Follow the volumes until we reach the last volume */
2894 eval
= dbread(ut
, lastVol
, &vf
, sizeof(vf
));
2898 lastVolPos
= vf
.position
;
2900 while (vf
.sameTapeChain
) {
2901 thisVol
= ntohl(vf
.sameTapeChain
);
2902 eval
= dbread(ut
, thisVol
, &vf
, sizeof(vf
));
2906 if (vf
.position
> lastVolPos
) {
2908 lastVolPos
= vf
.position
;
2912 /* We now have the last volume of this tape */
2913 /* Copy this into our return structure */
2914 eval
= FillVolEntry(ut
, lastVol
, volEntry
);
2919 eval
= ubik_EndTrans(ut
);
2925 ubik_AbortTrans(ut
);
2931 SBUDB_GetTapes(struct rx_call
*call
,
2932 afs_int32 majorVersion
, /* version of interface structures */
2933 afs_int32 flags
, /* search & select controls */
2934 char *name
, /* s&s parameters */
2936 afs_int32 end
, /* reserved: MBZ */
2937 afs_int32 index
, /* start index of returned entries */
2938 afs_int32
*nextIndexP
, /* output index for next call */
2940 budb_tapeList
*tapes
) /* pointer to buffer */
2945 GetTapes(call
, majorVersion
, flags
, name
, start
, end
, index
,
2946 nextIndexP
, dbTimeP
, tapes
);
2947 osi_auditU(call
, BUDB_GetTpeEvent
, code
, AUD_END
);
2952 GetTapes(struct rx_call
*call
,
2953 afs_int32 majorVersion
, /* version of interface structures */
2954 afs_int32 flags
, /* search & select controls */
2955 char *name
, /* s&s parameters */
2957 afs_int32 end
, /* reserved: MBZ */
2958 afs_int32 index
, /* start index of returned entries */
2959 afs_int32
*nextIndexP
, /* output index for next call */
2961 budb_tapeList
*tapes
) /* pointer to buffer */
2963 struct ubik_trans
*ut
;
2967 afs_int32 nameFlags
, startFlags
, endFlags
, timeFlags
;
2968 struct returnList list
;
2969 afs_int32 eval
, code
= 0;
2972 if (!callPermitted(call
))
2973 return BUDB_NOTPERMITTED
;
2975 if (majorVersion
!= BUDB_MAJORVERSION
)
2976 return BUDB_OLDINTERFACE
;
2979 return BUDB_ENDOFLIST
;
2981 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2985 nameFlags
= flags
& BUDB_OP_NAMES
;
2986 startFlags
= flags
& BUDB_OP_STARTS
;
2987 endFlags
= flags
& BUDB_OP_ENDS
;
2988 timeFlags
= flags
& BUDB_OP_TIMES
;
2990 InitReturnList(&list
);
2993 if (nameFlags
== BUDB_OP_TAPENAME
) { /*it */
2994 eval
= ht_LookupEntry(ut
, &db
.tapeName
, name
, &ta
, &t
);
2998 ABORT(BUDB_NOTAPENAME
);
3001 if ((startFlags
& ~BUDB_OP_DUMPID
) || endFlags
|| timeFlags
)
3002 ABORT(BUDB_BADFLAGS
);
3004 /* follow the hash chain to the end */
3006 if (startFlags
& BUDB_OP_DUMPID
) {
3007 /* read in the dump */
3008 eval
= dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
));
3012 /* check if both name and dump id match */
3013 if ((strcmp(name
, t
.name
) == 0) && (ntohl(d
.id
) == start
)) {
3014 eval
= AddToReturnList(&list
, ta
, &toskip
);
3015 if (eval
&& (eval
!= BUDB_LIST2BIG
))
3020 /* Add to return list and continue search */
3021 if (strcmp(name
, t
.name
) == 0) {
3022 eval
= AddToReturnList(&list
, ta
, &toskip
);
3023 if (eval
== BUDB_LIST2BIG
)
3030 ta
= ntohl(t
.nameHashChain
);
3032 dbread(ut
, ta
, &t
, sizeof(t
));
3035 else if (nameFlags
== BUDB_OP_TAPESEQ
) {
3036 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &start
, &da
, &d
);
3040 ABORT(BUDB_NODUMPNAME
);
3042 /* search for the right tape */
3043 ta
= ntohl(d
.firstTape
);
3044 for (ta
= ntohl(d
.firstTape
); ta
; ta
= ntohl(t
.nextTape
)) {
3045 eval
= dbread(ut
, ta
, &t
, sizeof(t
));
3049 if (ntohl(t
.seq
) == end
) {
3050 eval
= AddToReturnList(&list
, ta
, &toskip
);
3051 if (eval
&& (eval
!= BUDB_LIST2BIG
))
3057 ABORT(BUDB_BADFLAGS
);
3061 SendReturnList(ut
, &list
, FillTapeEntry
,
3062 sizeof(struct budb_tapeEntry
), index
, nextIndexP
,
3063 dbTimeP
, (returnList_t
) tapes
);
3067 FreeReturnList(&list
);
3068 code
= ubik_EndTrans(ut
);
3072 FreeReturnList(&list
);
3073 ubik_AbortTrans(ut
);
3078 * get a set of volumes according to the specified criteria.
3079 * See BUDB_GetDumps for general information on parameters
3080 * Currently supports:
3081 * 1) volume match - returns volumes based on volume name only.
3082 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
3083 * and start is a dumpid. Returns all volumes of the specified
3084 * name on the selected dumpid.
3088 SBUDB_GetVolumes(struct rx_call
*call
,
3089 afs_int32 majorVersion
, /* version of interface structures */
3090 afs_int32 flags
, /* search & select controls */
3091 char *name
, /* - parameters for search */
3092 afs_int32 start
, /* - usage depends which BUDP_OP */
3093 afs_int32 end
, /* - bits are set */
3094 afs_int32 index
, /* start index of returned entries */
3095 afs_int32
*nextIndexP
, /* output index for next call */
3097 budb_volumeList
*volumes
) /* pointer to buffer */
3102 GetVolumes(call
, majorVersion
, flags
, name
, start
, end
, index
,
3103 nextIndexP
, dbTimeP
, volumes
);
3104 osi_auditU(call
, BUDB_GetVolEvent
, code
, AUD_END
);
3109 GetVolumes(struct rx_call
*call
,
3110 afs_int32 majorVersion
, /* version of interface structures */
3111 afs_int32 flags
, /* search & select controls */
3112 char *name
, /* - parameters for search */
3113 afs_int32 start
, /* - usage depends which BUDP_OP_* */
3114 afs_int32 end
, /* - bits are set */
3115 afs_int32 index
, /* start index of returned entries */
3116 afs_int32
*nextIndexP
, /* output index for next call */
3118 budb_volumeList
*volumes
) /* pointer to buffer */
3120 struct ubik_trans
*ut
;
3123 afs_int32 nameFlags
, startFlags
, endFlags
, timeFlags
;
3124 afs_int32 eval
, code
= 0;
3125 struct returnList vollist
;
3128 /* Don't check permissions when we look up a specific volume name */
3129 if (((flags
& BUDB_OP_NAMES
) != BUDB_OP_VOLUMENAME
)
3130 && !callPermitted(call
))
3131 return BUDB_NOTPERMITTED
;
3133 if (majorVersion
!= BUDB_MAJORVERSION
)
3134 return BUDB_OLDINTERFACE
;
3136 return BUDB_ENDOFLIST
;
3138 eval
= InitRPC(&ut
, LOCKREAD
, 1);
3142 nameFlags
= flags
& BUDB_OP_NAMES
;
3143 startFlags
= flags
& BUDB_OP_STARTS
;
3144 endFlags
= flags
& BUDB_OP_ENDS
;
3145 timeFlags
= flags
& BUDB_OP_TIMES
;
3147 InitReturnList(&vollist
);
3150 /* lookup a the volume (specified by name) in the dump (specified by id) */
3151 if (nameFlags
== BUDB_OP_VOLUMENAME
) {
3152 /* dumpid permissible, all others off */
3153 if (((startFlags
& ~BUDB_OP_DUMPID
) != 0) || endFlags
|| timeFlags
)
3154 ABORT(BUDB_BADFLAGS
);
3156 /* returns ptr to volinfo of requested name */
3157 eval
= ht_LookupEntry(ut
, &db
.volName
, name
, &via
, &vi
);
3161 ABORT(BUDB_NOVOLUMENAME
);
3163 /* Iterate over all volume fragments with this name */
3165 struct volFragment v
;
3168 /* traverse all the volume fragments for this volume info structure */
3169 for (va
= vi
.firstFragment
; va
; va
= v
.sameNameChain
) {
3171 eval
= dbread(ut
, va
, &v
, sizeof(v
));
3175 if (startFlags
& BUDB_OP_DUMPID
) {
3179 /* get the dump id for this fragment */
3180 eval
= dbread(ut
, ntohl(v
.tape
), &atape
, sizeof(atape
));
3185 dbread(ut
, ntohl(atape
.dump
), &adump
, sizeof(adump
));
3189 /* dump id does not match */
3190 if (ntohl(adump
.id
) != start
)
3194 eval
= AddToReturnList(&vollist
, va
, &toskip
);
3195 if (eval
== BUDB_LIST2BIG
)
3200 if (eval
== BUDB_LIST2BIG
)
3203 via
= vi
.sameNameChain
;
3208 eval
= dbread(ut
, via
, &vi
, sizeof(vi
));
3212 } else if (((nameFlags
== 0) || (nameFlags
== BUDB_OP_TAPENAME
))
3213 && (startFlags
== BUDB_OP_DUMPID
)) {
3218 struct volFragment volFrag
;
3221 /* lookup all volumes for a specified dump id */
3223 /* no other flags should be set */
3224 if (endFlags
|| timeFlags
)
3225 ABORT(BUDB_BADFLAGS
);
3228 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &start
, &dumpAddr
, &dump
);
3232 /* traverse all the tapes */
3233 for (tapeAddr
= ntohl(dump
.firstTape
); tapeAddr
; tapeAddr
= ntohl(tape
.nextTape
)) { /*w */
3234 eval
= dbread(ut
, tapeAddr
, &tape
, sizeof(tape
));
3238 if ((nameFlags
!= BUDB_OP_TAPENAME
)
3239 || ((nameFlags
== BUDB_OP_TAPENAME
)
3240 && (strcmp(tape
.name
, name
) == 0))) {
3241 /* now return all the volumes */
3242 for (volFragAddr
= ntohl(tape
.firstVol
); volFragAddr
;
3243 volFragAddr
= ntohl(volFrag
.sameTapeChain
)) {
3244 eval
= dbread(ut
, volFragAddr
, &volFrag
, sizeof(volFrag
));
3248 eval
= AddToReturnList(&vollist
, volFragAddr
, &toskip
);
3249 if (eval
== BUDB_LIST2BIG
)
3255 if (eval
== BUDB_LIST2BIG
)
3259 ABORT(BUDB_BADFLAGS
);
3263 SendReturnList(ut
, &vollist
, FillVolEntry
,
3264 sizeof(struct budb_volumeEntry
), index
, nextIndexP
,
3265 dbTimeP
, (returnList_t
) volumes
);
3270 FreeReturnList(&vollist
);
3271 code
= ubik_EndTrans(ut
);
3275 FreeReturnList(&vollist
);
3276 ubik_AbortTrans(ut
);
3281 SBUDB_UseTape(struct rx_call
*call
,
3282 struct budb_tapeEntry
*tape
, /* tape info */
3283 afs_int32
*new) /* set if tape is new */
3287 code
= UseTape(call
, tape
, new);
3288 osi_auditU(call
, BUDB_UseTpeEvent
, code
, AUD_DATE
,
3289 (tape
? tape
->dump
: 0), AUD_END
);
3294 UseTape(struct rx_call
*call
,
3295 struct budb_tapeEntry
*tape
, /* tape info */
3296 int *new) /* set if tape is new */
3298 struct ubik_trans
*ut
;
3302 afs_int32 eval
, code
;
3304 if (!callPermitted(call
))
3305 return BUDB_NOTPERMITTED
;
3307 if (strlen(tape
->name
) >= sizeof(t
.name
))
3308 return BUDB_BADARGUMENT
;
3310 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
3316 memset(&t
, 0, sizeof(t
));
3317 eval
= AllocStructure(ut
, tape_BLOCK
, 0, &a
, &t
);
3321 strcpy(t
.name
, tape
->name
);
3323 eval
= ht_HashIn(ut
, &db
.tapeName
, a
, &t
);
3329 /* Since deleting a tape may change the dump (if its the same one), read in
3330 * the dump after the call to DeleteTape. */
3332 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &tape
->dump
, &da
, &d
);
3336 ABORT(BUDB_NODUMPID
);
3339 tape
->written
= time(0); /* fill in tape struct */
3340 t
.written
= htonl(tape
->written
);
3341 t
.expires
= htonl(tape
->expires
);
3343 t
.seq
= htonl(tape
->seq
);
3344 t
.useCount
= htonl(tape
->useCount
);
3345 t
.labelpos
= htonl(tape
->labelpos
);
3347 t
.flags
= htonl(tape
->flags
| BUDB_TAPE_BEINGWRITTEN
);
3349 t
.nextTape
= d
.firstTape
; /* Chain the tape to the dump */
3350 d
.firstTape
= htonl(a
);
3352 if (tape
->seq
>= ntohl(d
.tapes
.maxTapes
)) /* inc # tapes in the dump */
3353 d
.tapes
.maxTapes
= htonl(tape
->seq
);
3355 eval
= dbwrite(ut
, a
, &t
, sizeof(t
)); /* write tape struct */
3359 eval
= dbwrite(ut
, da
, &d
, sizeof(d
)); /* write the dump struct */
3363 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
3367 LogDebug(5, "added tape %s\n", tape
->name
);
3369 code
= ubik_EndTrans(ut
);
3373 ubik_AbortTrans(ut
);
3379 /* ---------------------------------------------
3380 * debug interface routines
3381 * ---------------------------------------------
3385 SBUDB_T_DumpHashTable(struct rx_call
*call
, afs_int32 type
, char *filename
)
3389 code
= T_DumpHashTable(call
, type
, filename
);
3390 osi_auditU(call
, BUDB_TDmpHaEvent
, code
, AUD_STR
, filename
, AUD_END
);
3395 T_DumpHashTable(struct rx_call
*call
, int type
, char *filename
)
3397 struct ubik_trans
*ut
;
3398 struct memoryHashTable
*mht
;
3400 afs_int32 eval
, code
= 0;
3407 char e
[sizeof(struct block
)]; /* unnecessarily conservative */
3410 struct volInfo e_volinfo
;
3414 if (!callPermitted(call
))
3415 return BUDB_NOTPERMITTED
;
3417 if (strlen(filename
) >= sizeof(path
) - 5)
3418 return BUDB_BADARGUMENT
;
3420 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
3424 if ((mht
= ht_GetType(type
, &e_size
)) == 0)
3425 return BUDB_BADARGUMENT
;
3427 sprintf(path
, "%s/%s", gettmpdir(), filename
);
3429 DUMP
= fopen(path
, "w");
3431 ABORT(BUDB_BADARGUMENT
);
3434 for (old
= 0;; old
++) {
3435 length
= (old
? mht
->oldLength
: mht
->length
);
3437 fprintf(DUMP
, "Dumping %sHash Table:\n", (old
? "Old " : ""));
3439 for (hash
= 0; hash
< length
; hash
++) {
3440 a
= ht_LookupBucket(ut
, mht
, hash
, old
);
3443 eval
= dbread(ut
, a
, e
, e_size
);
3449 fprintf(DUMP
, " in bucket %d at %d is ", hash
, a
);
3451 fprintf(DUMP
, " at %d is ", a
);
3453 case HT_dumpIden_FUNCTION
:
3454 memcpy(&e_dump
, e
, sizeof(e_dump
));
3455 fprintf(DUMP
, "%d\n", ntohl(e_dump
.id
));
3457 case HT_dumpName_FUNCTION
:
3458 memcpy(&e_dump
, e
, sizeof(e_dump
));
3459 fprintf(DUMP
, "%s\n", e_dump
.dumpName
);
3461 case HT_tapeName_FUNCTION
:
3462 memcpy(&e_tape
, e
, sizeof(e_tape
));
3463 fprintf(DUMP
, "%s\n", e_tape
.name
);
3465 case HT_volName_FUNCTION
:
3466 memcpy(&e_volinfo
, e
, sizeof(e_volinfo
));
3467 fprintf(DUMP
, "%s\n", e_volinfo
.name
);
3470 if ((ht_HashEntry(mht
, e
) % length
) != hash
)
3471 ABORT(BUDB_DATABASEINCONSISTENT
);
3472 a
= ntohl(*(dbadr
*) (e
+ mht
->threadOffset
));
3479 fprintf(DUMP
, "%d entries found\n", ent
);
3480 if (ntohl(mht
->ht
->entries
) != ent
)
3481 ABORT(BUDB_DATABASEINCONSISTENT
);
3483 code
= ubik_EndTrans(ut
);
3489 ubik_AbortTrans(ut
);
3496 SBUDB_T_GetVersion(struct rx_call
*call
, afs_int32
*majorVersion
)
3500 code
= T_GetVersion(call
, majorVersion
);
3501 osi_auditU(call
, BUDB_TGetVrEvent
, code
, AUD_END
);
3506 T_GetVersion(struct rx_call
*call
, int *majorVersion
)
3508 struct ubik_trans
*ut
;
3511 code
= InitRPC(&ut
, LOCKREAD
, 0);
3515 *majorVersion
= BUDB_MAJORVERSION
;
3517 code
= ubik_EndTrans(ut
);
3521 /* BUDB_T_DumpDatabase
3522 * dump as much of the database as possible int /tmp/<filename>
3526 SBUDB_T_DumpDatabase(struct rx_call
*call
, char *filename
)
3530 code
= T_DumpDatabase(call
, filename
);
3531 osi_auditU(call
, BUDB_TDmpDBEvent
, code
, AUD_STR
, filename
, AUD_END
);
3536 T_DumpDatabase(struct rx_call
*call
, char *filename
)
3540 struct ubik_trans
*ut
;
3543 int type
, old
, length
, hash
;
3544 struct memoryHashTable
*mht
;
3545 afs_int32 eval
, code
= 0;
3547 if (!callPermitted(call
))
3548 return BUDB_NOTPERMITTED
;
3550 path
= (char *)malloc(strlen(gettmpdir()) + 1 + strlen(filename
) + 1);
3552 return (BUDB_INTERNALERROR
);
3554 sprintf(path
, "%s/%s", gettmpdir(), filename
);
3556 dumpfid
= fopen(path
, "w");
3558 return (BUDB_BADARGUMENT
);
3560 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
3564 /* dump all items in the database */
3565 for (type
= 1; type
<= HT_MAX_FUNCTION
; type
++) { /*ft */
3566 mht
= ht_GetType(type
, &entrySize
);
3568 ERROR(BUDB_BADARGUMENT
);
3570 for (old
= 0; old
<= 1; old
++) { /*fo */
3571 length
= (old
? mht
->oldLength
: mht
->length
);
3575 fprintf(dumpfid
, "Dumping %s Hash Table:\n", (old
? "Old " : ""));
3577 for (hash
= 0; hash
< length
; hash
++) { /*f */
3578 dbAddr
= ht_LookupBucket(ut
, mht
, hash
, old
);
3580 while (dbAddr
) { /*w */
3581 switch (type
) { /*s */
3582 case HT_dumpIden_FUNCTION
:
3584 struct dump hostDump
, diskDump
;
3587 cdbread(ut
, dump_BLOCK
, dbAddr
, &diskDump
,
3593 "\ndumpId hash %d, entry at %u\n",
3596 "----------------------------\n");
3597 dump_ntoh(&diskDump
, &hostDump
);
3598 printDump(dumpfid
, &hostDump
);
3599 dbAddr
= hostDump
.idHashChain
;
3603 case HT_dumpName_FUNCTION
:
3605 struct dump hostDump
, diskDump
;
3608 cdbread(ut
, dump_BLOCK
, dbAddr
, &diskDump
,
3614 "\ndumpname hash %d, entry at %u\n",
3617 "----------------------------\n");
3618 dump_ntoh(&diskDump
, &hostDump
);
3619 printDump(dumpfid
, &hostDump
);
3620 dbAddr
= hostDump
.nameHashChain
;
3624 case HT_tapeName_FUNCTION
:
3626 struct tape hostTape
, diskTape
;
3629 cdbread(ut
, tape_BLOCK
, dbAddr
, &diskTape
,
3635 "\ntapename hash %d, entry at %u\n",
3638 "----------------------------\n");
3639 tape_ntoh(&diskTape
, &hostTape
);
3640 printTape(dumpfid
, &hostTape
);
3641 dbAddr
= hostTape
.nameHashChain
;
3645 case HT_volName_FUNCTION
:
3647 struct volInfo hostVolInfo
, diskVolInfo
;
3650 cdbread(ut
, volInfo_BLOCK
, dbAddr
,
3651 &diskVolInfo
, sizeof(diskVolInfo
));
3656 "\nvolname hash %d, entry at %u\n",
3659 "----------------------------\n");
3660 volInfo_ntoh(&diskVolInfo
, &hostVolInfo
);
3661 printVolInfo(dumpfid
, &hostVolInfo
);
3662 dbAddr
= hostVolInfo
.nameHashChain
;
3664 volFragsDump(ut
, dumpfid
,
3665 hostVolInfo
.firstFragment
);
3670 fprintf(dumpfid
, "unknown type %d\n", type
);
3680 code
= ubik_EndTrans(ut
); /* is this safe if no ut started ? */
3689 volFragsDump(struct ubik_trans
*ut
, FILE *dumpfid
, dbadr dbAddr
)
3691 struct volFragment hostVolFragment
, diskVolFragment
;
3696 cdbread(ut
, volFragment_BLOCK
, dbAddr
, &diskVolFragment
,
3697 sizeof(diskVolFragment
));
3698 if (code
) { /* don't be fussy about errors */
3699 fprintf(dumpfid
, "volFragsDump: Error reading database\n");
3703 fprintf(dumpfid
, "\nvolfragment entry at %u\n", dbAddr
);
3704 fprintf(dumpfid
, "----------------------------\n");
3705 volFragment_ntoh(&diskVolFragment
, &hostVolFragment
);
3706 printVolFragment(dumpfid
, &hostVolFragment
);
3707 dbAddr
= hostVolFragment
.sameNameChain
;
3713 /* utilities - network to host conversion
3714 * currently used for debug only
3718 volFragmentDiskToHost(struct volFragment
*diskVfPtr
,
3719 struct volFragment
*hostVfPtr
)
3721 hostVfPtr
->vol
= ntohl(diskVfPtr
->vol
);
3722 hostVfPtr
->sameNameChain
= ntohl(diskVfPtr
->sameNameChain
);
3723 hostVfPtr
->tape
= ntohl(diskVfPtr
->tape
);
3724 hostVfPtr
->sameTapeChain
= ntohl(diskVfPtr
->sameTapeChain
);
3725 hostVfPtr
->position
= ntohl(diskVfPtr
->position
);
3726 hostVfPtr
->clone
= ntohl(diskVfPtr
->clone
);
3727 hostVfPtr
->incTime
= ntohl(diskVfPtr
->incTime
);
3728 hostVfPtr
->startByte
= ntohl(diskVfPtr
->startByte
);
3729 hostVfPtr
->nBytes
= ntohl(diskVfPtr
->nBytes
);
3730 hostVfPtr
->flags
= ntohs(diskVfPtr
->flags
);
3731 hostVfPtr
->sequence
= ntohs(diskVfPtr
->sequence
);
3735 volInfoDiskToHost(struct volInfo
*diskViPtr
, struct volInfo
*hostViPtr
)
3737 strcpy(hostViPtr
->name
, diskViPtr
->name
);
3738 hostViPtr
->nameHashChain
= ntohl(diskViPtr
->nameHashChain
);
3739 hostViPtr
->id
= ntohl(diskViPtr
->id
);
3740 strcpy(hostViPtr
->server
, diskViPtr
->server
);
3741 hostViPtr
->partition
= ntohl(diskViPtr
->partition
);
3742 hostViPtr
->flags
= ntohl(diskViPtr
->flags
);
3743 hostViPtr
->sameNameHead
= ntohl(diskViPtr
->sameNameHead
);
3744 hostViPtr
->sameNameChain
= ntohl(diskViPtr
->sameNameChain
);
3745 hostViPtr
->firstFragment
= ntohl(diskViPtr
->firstFragment
);
3746 hostViPtr
->nFrags
= ntohl(diskViPtr
->nFrags
);
3750 tapeDiskToHost(struct tape
*diskTapePtr
, struct tape
*hostTapePtr
)
3752 strcpy(hostTapePtr
->name
, diskTapePtr
->name
);
3753 hostTapePtr
->nameHashChain
= ntohl(diskTapePtr
->nameHashChain
);
3754 hostTapePtr
->flags
= ntohl(diskTapePtr
->flags
);
3756 /* tape id conversion here */
3757 hostTapePtr
->written
= ntohl(diskTapePtr
->written
);
3758 hostTapePtr
->nBytes
= ntohl(diskTapePtr
->nBytes
);
3759 hostTapePtr
->nFiles
= ntohl(diskTapePtr
->nFiles
);
3760 hostTapePtr
->nVolumes
= ntohl(diskTapePtr
->nVolumes
);
3761 hostTapePtr
->seq
= ntohl(diskTapePtr
->seq
);
3762 hostTapePtr
->dump
= ntohl(diskTapePtr
->dump
);
3763 hostTapePtr
->nextTape
= ntohl(diskTapePtr
->nextTape
);
3764 hostTapePtr
->firstVol
= ntohl(diskTapePtr
->firstVol
);
3765 hostTapePtr
->useCount
= ntohl(diskTapePtr
->useCount
);
3769 dumpDiskToHost(struct dump
*diskDumpPtr
, struct dump
*hostDumpPtr
)
3771 hostDumpPtr
->id
= ntohl(diskDumpPtr
->id
);
3772 hostDumpPtr
->idHashChain
= ntohl(diskDumpPtr
->idHashChain
);
3773 strcpy(hostDumpPtr
->dumpName
, diskDumpPtr
->dumpName
);
3774 strcpy(hostDumpPtr
->dumpPath
, diskDumpPtr
->dumpPath
);
3775 strcpy(hostDumpPtr
->volumeSet
, diskDumpPtr
->volumeSet
);
3776 hostDumpPtr
->nameHashChain
= ntohl(diskDumpPtr
->nameHashChain
);
3777 hostDumpPtr
->flags
= ntohl(diskDumpPtr
->flags
);
3778 hostDumpPtr
->parent
= ntohl(diskDumpPtr
->parent
);
3779 hostDumpPtr
->created
= ntohl(diskDumpPtr
->created
);
3780 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3781 hostDumpPtr
->nVolumes
= ntohl(diskDumpPtr
->nVolumes
);
3783 /* tapeset conversion here */
3785 hostDumpPtr
->firstTape
= ntohl(diskDumpPtr
->firstTape
);
3787 /* principal conversion here */
3793 checkHash(struct ubik_trans
*ut
, int hashType
)
3795 struct memoryHashTable
*mhtPtr
;
3796 int entrySize
, hashTableLength
;
3801 mhtPtr
= ht_GetType(hashType
, &entrySize
);
3805 for (old
= 0; old
< 1; old
++) {
3806 LogDebug(5, "\nold = %d\n", old
);
3807 printMemoryHashTable(stdout
, mhtPtr
);
3809 hashTableLength
= (old
? mhtPtr
->oldLength
: mhtPtr
->length
);
3811 for (bucket
= 0; bucket
< hashTableLength
; bucket
++) {
3814 entryAddr
= ht_LookupBucket(ut
, mhtPtr
, bucket
, old
);
3815 while (entryAddr
!= 0) {
3816 LogDebug(6, "bucket %d has disk addr %d\n", bucket
,
3819 case HT_dumpIden_FUNCTION
:
3821 struct dump diskDump
, hostDump
;
3823 code
= dbread(ut
, entryAddr
, &diskDump
, entrySize
);
3827 dump_ntoh(&diskDump
, &hostDump
);
3828 printDump(stdout
, &hostDump
);
3829 entryAddr
= hostDump
.idHashChain
;
3833 case HT_dumpName_FUNCTION
:
3836 case HT_tapeName_FUNCTION
:
3839 case HT_volName_FUNCTION
:
3841 struct volInfo diskVolInfo
, hostVolInfo
;
3843 code
= dbread(ut
, entryAddr
, &diskVolInfo
, entrySize
);
3847 volInfo_ntoh(&diskVolInfo
, &hostVolInfo
);
3848 printVolInfo(stdout
, &hostVolInfo
);
3849 entryAddr
= hostVolInfo
.nameHashChain
;