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 memset(dump
, 0, sizeof(*dump
));
428 if (dbread(ut
, da
, &d
, sizeof(d
)))
430 dump
->id
= ntohl(d
.id
);
431 dump
->flags
= ntohl(d
.flags
);
432 dump
->created
= ntohl(d
.created
);
433 strncpy(dump
->name
, d
.dumpName
, sizeof(dump
->name
));
434 strncpy(dump
->dumpPath
, d
.dumpPath
, sizeof(dump
->dumpPath
));
435 strncpy(dump
->volumeSetName
, d
.volumeSet
, sizeof(dump
->volumeSetName
));
437 dump
->parent
= ntohl(d
.parent
);
438 dump
->level
= ntohl(d
.level
);
439 dump
->nVolumes
= ntohl(d
.nVolumes
);
441 tapeSet_ntoh(&d
.tapes
, &dump
->tapes
);
443 if (strlen(d
.dumper
.name
) < sizeof(dump
->dumper
.name
))
444 strcpy(dump
->dumper
.name
, d
.dumper
.name
);
445 if (strlen(d
.dumper
.instance
) < sizeof(dump
->dumper
.instance
))
446 strcpy(dump
->dumper
.instance
, d
.dumper
.instance
);
447 if (strlen(d
.dumper
.cell
) < sizeof(dump
->dumper
.cell
))
448 strcpy(dump
->dumper
.cell
, d
.dumper
.cell
);
450 /* Get the initial dumpid and the appended dump id */
451 dump
->initialDumpID
= ntohl(d
.initialDumpID
);
452 if (d
.appendedDumpChain
) {
453 if (dbread(ut
, ntohl(d
.appendedDumpChain
), &ad
, sizeof(ad
)))
455 dump
->appendedDumpID
= ntohl(ad
.id
);
457 dump
->appendedDumpID
= 0;
459 /* printf("dump name %s, parent %d, level %d\n",
460 * d.dumpName, ntohl(d.parent), ntohl(d.level)); */
466 FillTapeEntry(struct ubik_trans
*ut
, dbadr ta
, void *rock
)
468 struct budb_tapeEntry
*tape
=(struct budb_tapeEntry
*) rock
;
473 if (dbread(ut
, ta
, &t
, sizeof(t
)))
476 /* Get the tape's expiration date */
477 if ((code
= getExpiration(ut
, &t
)))
480 strcpy(tape
->name
, t
.name
);
481 tape
->flags
= ntohl(t
.flags
);
482 tape
->written
= ntohl(t
.written
);
483 tape
->expires
= ntohl(t
.expires
);
484 tape
->nMBytes
= ntohl(t
.nMBytes
);
485 tape
->nBytes
= ntohl(t
.nBytes
);
486 tape
->nFiles
= ntohl(t
.nFiles
);
487 tape
->nVolumes
= ntohl(t
.nVolumes
);
488 tape
->seq
= ntohl(t
.seq
);
489 tape
->labelpos
= ntohl(t
.labelpos
);
490 tape
->useCount
= ntohl(t
.useCount
);
491 tape
->useKBytes
= ntohl(t
.useKBytes
);
493 if (dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
)))
495 tape
->dump
= ntohl(d
.id
);
499 #define returnList_t budb_dumpList *
502 * A list of elements of size e_size is in list, collected
503 * with AddToReturnList(). We will move this to a correspoding
504 * return list, eList, via FillProc(). nextInodeP tells us
505 * if there are more and how many to skip on the next request.
508 SendReturnList(struct ubik_trans
*ut
,
509 struct returnList
*list
, /* list of elements to return */
510 afs_int32(*FillProc
) (struct ubik_trans
*, dbadr da
,
512 /* proc to fill entry */
513 int e_size
, /* size of each element */
514 afs_int32 index
, /* index from previous call */
515 afs_int32
*nextIndexP
, /* if more elements are available */
516 afs_int32
*dbTimeP
, /* time of last db update */
517 budb_dumpList
*eList
) /* rxgen list structure (e.g.) */
525 *dbTimeP
= ntohl(db
.h
.lastUpdate
);
527 /* Calculate how many to return. Don't let if go over
528 * BUDB_MAX_RETURN_LIST nor the size of our return list.
530 to_return
= list
->nElements
;
531 if (to_return
> BUDB_MAX_RETURN_LIST
)
532 to_return
= BUDB_MAX_RETURN_LIST
;
533 if (eList
->budb_dumpList_len
&& (to_return
> eList
->budb_dumpList_len
))
534 to_return
= eList
->budb_dumpList_len
;
536 /* Allocate space for the return values if needed and zero it */
537 if (eList
->budb_dumpList_val
== 0) {
539 eList
->budb_dumpList_val
= calloc(to_return
, e_size
);
540 if (!eList
->budb_dumpList_val
)
543 eList
->budb_dumpList_val
= NULL
;
545 memset(eList
->budb_dumpList_val
, 0, e_size
* to_return
);
548 eList
->budb_dumpList_len
= to_return
;
550 e
= (char *)(eList
->budb_dumpList_val
);
551 for (i
= 0; i
< to_return
; i
++, e
+= e_size
) {
552 code
= (*FillProc
) (ut
, list
->elements
[i
], (budb_dumpEntry
*) e
);
557 if (list
->nElements
> i
)
558 *nextIndexP
= index
+ i
;
562 /* Come here to delete a volInfo structure. */
565 DeleteVolInfo(struct ubik_trans
*ut
, dbadr via
, struct volInfo
*vi
)
571 if (vi
->firstFragment
)
572 return 0; /* still some frags, don't free yet */
573 if (vi
->sameNameHead
== 0) { /* this is the head */
574 if (vi
->sameNameChain
)
575 return 0; /* empty head, some non-heads left */
577 code
= ht_HashOut(ut
, &db
.volName
, via
, vi
);
580 code
= FreeStructure(ut
, volInfo_BLOCK
, via
);
583 hvia
= ntohl(vi
->sameNameHead
);
584 if (dbread(ut
, hvia
, &hvi
, sizeof(hvi
)))
587 RemoveFromList(ut
, hvia
, &hvi
, &hvi
.sameNameChain
, via
, vi
,
590 return BUDB_DATABASEINCONSISTENT
;
592 code
= FreeStructure(ut
, volInfo_BLOCK
, via
);
596 /* Detach a volume fragment from its volInfo structure. Its tape chain is
597 already freed. This routine frees the structure and the caller must not
601 DeleteVolFragment(struct ubik_trans
*ut
, dbadr va
, struct volFragment
*v
)
608 if (dbread(ut
, via
, &vi
, sizeof(vi
)))
611 RemoveFromList(ut
, via
, &vi
, &vi
.firstFragment
, va
, v
,
614 return BUDB_DATABASEINCONSISTENT
;
617 if (vi
.firstFragment
== 0)
618 if ((code
= DeleteVolInfo(ut
, via
, &vi
)))
620 if ((code
= FreeStructure(ut
, volFragment_BLOCK
, va
)))
623 /* decrement frag counter */
625 set_word_addr(ut
, via
, &vi
, &vi
.nFrags
, htonl(ntohl(vi
.nFrags
) - 1));
631 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
632 * The caller will remove it from the hash table if necessary. The caller is
633 * also responsible for writing the tape out if necessary. */
636 DeleteTape(struct ubik_trans
*ut
, dbadr ta
, struct tape
*t
)
644 return BUDB_DATABASEINCONSISTENT
;
645 if (dbread(ut
, da
, &d
, sizeof(d
)))
647 if (d
.firstTape
== 0)
648 return BUDB_DATABASEINCONSISTENT
;
650 code
= RemoveFromList(ut
, da
, &d
, &d
.firstTape
, ta
, t
, &t
->nextTape
);
652 return BUDB_DATABASEINCONSISTENT
;
656 /* Since the tape should have been truncated there should never be any
657 * volumes in the tape. */
658 if (t
->firstVol
|| t
->nVolumes
)
659 return BUDB_DATABASEINCONSISTENT
;
665 DeleteDump(struct ubik_trans
*ut
, dbadr da
, struct dump
*d
)
669 code
= ht_HashOut(ut
, &db
.dumpIden
, da
, d
);
673 code
= ht_HashOut(ut
, &db
.dumpName
, da
, d
);
677 /* Since the tape should have been truncated this should never happen. */
678 if (d
->firstTape
|| d
->nVolumes
)
679 ERROR(BUDB_DATABASEINCONSISTENT
);
681 code
= FreeStructure(ut
, dump_BLOCK
, da
);
692 * This is called with a volumeEntry and a volInfo structure and compares
693 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
694 * search volInfo structures once it has the head volInfo structure from the
695 * volName hash table.
697 * When called from GetVolInfo the name compare is redundant.
698 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
702 VolInfoMatch(struct budb_volumeEntry
*vol
, struct volInfo
*vi
)
704 return ((strcmp(vol
->name
, vi
->name
) == 0) && /* same volume name */
705 (vol
->id
== ntohl(vi
->id
)) && /* same volume id */
706 ((vol
->flags
& VOLINFOFLAGS
) == (ntohl(vi
->flags
) & VOLINFOFLAGS
)) && /* same flags */
707 (vol
->partition
== ntohl(vi
->partition
)) && /* same partition (N/A) */
708 (strcmp(vol
->server
, vi
->server
) == 0)); /* same server (N/A) */
713 * This routine takes a volumeEntry structure from an RPC interface and
714 * returns the corresponding volInfo structure, creating it if necessary.
716 * The caller must write the entry out.
720 GetVolInfo(struct ubik_trans
*ut
, struct budb_volumeEntry
*volP
, dbadr
*viaP
,
725 afs_int32 eval
, code
= 0;
727 eval
= ht_LookupEntry(ut
, &db
.volName
, volP
->name
, &via
, viP
);
732 /* allocate a new volinfo structure */
733 eval
= AllocStructure(ut
, volInfo_BLOCK
, 0, &via
, viP
);
737 strcpy(viP
->name
, volP
->name
);
738 strcpy(viP
->server
, volP
->server
);
739 viP
->sameNameHead
= 0; /* The head of same name chain */
740 viP
->sameNameChain
= 0; /* Same name chain is empty */
741 viP
->firstFragment
= 0;
743 viP
->id
= htonl(volP
->id
);
744 viP
->partition
= htonl(volP
->partition
);
745 viP
->flags
= htonl(volP
->flags
& VOLINFOFLAGS
);
747 /* Chain onto volname hash table */
748 eval
= ht_HashIn(ut
, &db
.volName
, via
, viP
);
752 LogDebug(4, "volume Info for %s placed at %d\n", volP
->name
, via
);
755 else if (!VolInfoMatch(volP
, viP
)) { /* Not the head volinfo struct */
756 hvia
= via
; /* remember the head volinfo struct */
757 memcpy(&hvi
, viP
, sizeof(hvi
));
759 /* Search the same name chain for the correct volinfo structure */
760 for (via
= ntohl(viP
->sameNameChain
); via
;
761 via
= ntohl(viP
->sameNameChain
)) {
762 eval
= dbread(ut
, via
, viP
, sizeof(*viP
));
766 if (VolInfoMatch(volP
, viP
))
767 break; /* found the one */
770 /* if the correct volinfo struct isn't found, create one */
772 eval
= AllocStructure(ut
, volInfo_BLOCK
, 0, &via
, viP
);
776 strcpy(viP
->name
, volP
->name
);
777 strcpy(viP
->server
, volP
->server
);
778 viP
->nameHashChain
= 0; /* not in hash table */
779 viP
->sameNameHead
= htonl(hvia
); /* chain to head of sameNameChain */
780 viP
->sameNameChain
= hvi
.sameNameChain
;
781 viP
->firstFragment
= 0;
783 viP
->id
= htonl(volP
->id
);
784 viP
->partition
= htonl(volP
->partition
);
785 viP
->flags
= htonl(volP
->flags
& VOLINFOFLAGS
);
787 /* write the head entry's sameNameChain link */
789 set_word_addr(ut
, hvia
, &hvi
, &hvi
.sameNameChain
, htonl(via
));
801 /* deletesomevolumesfromtape
802 * Deletes a specified number of volumes from a tape. The tape
803 * and dump are modified to reflect the smaller number of volumes.
804 * The transaction is not terminated, it is up to the caller to
805 * finish the transaction and start a new one (if desired).
807 * maxvolumestodelete - don't delete more than this many volumes
811 deleteSomeVolumesFromTape(struct ubik_trans
*ut
, dbadr tapeAddr
,
812 struct tape
*tapePtr
, int maxVolumesToDelete
)
814 dbadr volFragAddr
, nextVolFragAddr
, dumpAddr
;
815 struct volFragment volFrag
;
817 int volumesDeleted
= 0;
818 afs_int32 eval
, code
= 0;
823 for (volFragAddr
= ntohl(tapePtr
->firstVol
);
824 (volFragAddr
&& (maxVolumesToDelete
> 0));
825 volFragAddr
= nextVolFragAddr
) {
826 eval
= dbread(ut
, volFragAddr
, &volFrag
, sizeof(volFrag
));
830 nextVolFragAddr
= ntohl(volFrag
.sameTapeChain
);
832 eval
= DeleteVolFragment(ut
, volFragAddr
, &volFrag
);
836 maxVolumesToDelete
--;
840 /* reset the volume fragment pointer in the tape */
841 tapePtr
->firstVol
= htonl(volFragAddr
);
843 /* diminish the tape's volume count */
844 tapePtr
->nVolumes
= htonl(ntohl(tapePtr
->nVolumes
) - volumesDeleted
);
846 eval
= dbwrite(ut
, tapeAddr
, tapePtr
, sizeof(*tapePtr
));
850 /* diminish the dump's volume count */
851 dumpAddr
= ntohl(tapePtr
->dump
);
852 eval
= dbread(ut
, dumpAddr
, &dump
, sizeof(dump
));
856 dump
.nVolumes
= htonl(ntohl(dump
.nVolumes
) - volumesDeleted
);
857 eval
= dbwrite(ut
, dumpAddr
, &dump
, sizeof(dump
));
866 * deletes a dump in stages, by repeatedly deleting a small number of
867 * volumes from the dump until none are left. The dump is then deleted.
869 * In the case where multiple calls are made to delete the same
870 * dump, the operation will succeed but contention for structures
871 * will result in someone getting back an error.
874 * id - id of dump to delete
878 deleteDump(struct rx_call
*call
, dumpId id
, budb_dumpsList
*dumps
)
880 struct ubik_trans
*ut
;
881 dbadr dumpAddr
, tapeAddr
, appendedDump
;
885 afs_int32 eval
, code
= 0;
888 /* iterate until the dump is truly deleted */
894 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
896 ERROR(eval
); /* can't start transaction */
899 ht_LookupEntry(ut
, &db
.dumpIden
, &dumpid
, &dumpAddr
, &dump
);
903 ABORT(BUDB_NOENT
); /* can't find dump */
905 if ((dumpid
== id
) && (dump
.initialDumpID
)) /* can't be an appended dump */
906 ABORT(BUDB_NOTINITIALDUMP
);
908 tapeAddr
= ntohl(dump
.firstTape
);
912 /* there is a tape to delete */
913 eval
= dbread(ut
, tapeAddr
, &tape
, sizeof(tape
));
917 if (ntohl(tape
.nVolumes
)) {
918 /* tape is not empty */
919 eval
= deleteSomeVolumesFromTape(ut
, tapeAddr
, &tape
, 10);
924 if (ntohl(tape
.nVolumes
) == 0) {
925 /* tape is now empty, delete it */
926 eval
= DeleteTape(ut
, tapeAddr
, &tape
);
929 eval
= ht_HashOut(ut
, &db
.tapeName
, tapeAddr
, &tape
);
932 eval
= FreeStructure(ut
, tape_BLOCK
, tapeAddr
);
937 eval
= ubik_EndTrans(ut
);
941 } /* next deletion portion */
943 /* Record the dump just deleted */
944 if (dumps
&& (dumps
->budb_dumpsList_len
< BUDB_MAX_RETURN_LIST
)) {
945 if (dumps
->budb_dumpsList_len
== 0)
946 dumps
->budb_dumpsList_val
= malloc(sizeof(afs_int32
));
948 dumps
->budb_dumpsList_val
=
949 realloc(dumps
->budb_dumpsList_val
,
950 (dumps
->budb_dumpsList_len
+ 1)
951 * sizeof(afs_int32
));
953 if (!dumps
->budb_dumpsList_val
)
956 dumps
->budb_dumpsList_val
[dumps
->budb_dumpsList_len
] = dumpid
;
957 dumps
->budb_dumpsList_len
++;
960 appendedDump
= ntohl(dump
.appendedDumpChain
);
962 /* finally done. No more tapes left in the dump. Delete the dump itself */
963 eval
= DeleteDump(ut
, dumpAddr
, &dump
);
967 /* Now delete the appended dump too */
969 eval
= dbread(ut
, appendedDump
, &dump
, sizeof(dump
));
973 dumpid
= ntohl(dump
.id
);
977 eval
= ubik_EndTrans(ut
);
981 Log("Delete dump %s (DumpID %u), path %s\n", dump
.dumpName
,
982 ntohl(dump
.id
), dump
.dumpPath
);
986 if (code
&& partialDel
) {
987 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
988 dump
.dumpName
, ntohl(dump
.id
), dump
.dumpPath
, code
);
998 * dump selection routines - used by BUDB_GetDumps
1002 /* most recent dump selection */
1005 struct chosenDump
*next
;
1010 struct wantDumpRock
{
1011 int maxDumps
; /* max wanted */
1012 int ndumps
; /* actual in chain */
1013 struct chosenDump
*chain
;
1018 wantDump(dbadr dumpAddr
, void *dumpParam
, void *dumpListPtrParam
)
1020 struct dump
*dumpPtr
;
1021 struct wantDumpRock
*rockPtr
;
1023 dumpPtr
= (struct dump
*)dumpParam
;
1024 rockPtr
= (struct wantDumpRock
*)dumpListPtrParam
;
1026 /* if we don't have our full complement, just add another */
1027 if (rockPtr
->ndumps
< rockPtr
->maxDumps
)
1030 /* got the number we need, select based on date */
1031 if ((afs_uint32
) ntohl(dumpPtr
->created
) > rockPtr
->chain
->date
)
1038 rememberDump(dbadr dumpAddr
, void *dumpParam
, void *dumpListPtrParam
)
1040 struct dump
*dumpPtr
;
1041 struct wantDumpRock
*rockPtr
;
1042 struct chosenDump
*ptr
, *deletedPtr
, **nextPtr
;
1044 dumpPtr
= (struct dump
*)dumpParam
;
1045 rockPtr
= (struct wantDumpRock
*)dumpListPtrParam
;
1047 ptr
= calloc(1, sizeof(*ptr
));
1050 ptr
->addr
= dumpAddr
;
1051 ptr
->date
= (afs_uint32
) ntohl(dumpPtr
->created
);
1053 /* Don't overflow the max */
1054 while (rockPtr
->ndumps
>= rockPtr
->maxDumps
) {
1055 /* have to drop one */
1056 deletedPtr
= rockPtr
->chain
;
1057 rockPtr
->chain
= deletedPtr
->next
;
1062 /* now insert in the right place */
1063 for (nextPtr
= &rockPtr
->chain
; *nextPtr
; nextPtr
= &((*nextPtr
)->next
)) {
1064 if (ptr
->date
< (*nextPtr
)->date
)
1067 ptr
->next
= *nextPtr
;
1075 /* ---------------------------------------------
1076 * general interface routines - alphabetic
1077 * ---------------------------------------------
1081 SBUDB_AddVolume(struct rx_call
*call
, struct budb_volumeEntry
*vol
)
1085 code
= AddVolume(call
, vol
);
1086 osi_auditU(call
, BUDB_AddVolEvent
, code
, AUD_LONG
, (vol
? vol
->id
: 0),
1092 AddVolume(struct rx_call
*call
, struct budb_volumeEntry
*vol
)
1094 struct ubik_trans
*ut
;
1095 dbadr da
, ta
, via
, va
;
1099 struct volFragment v
;
1101 afs_int32 eval
, code
= 0;
1103 if (!callPermitted(call
))
1104 return BUDB_NOTPERMITTED
;
1106 if ((strlen(vol
->name
) >= sizeof(vi
.name
))
1107 || (strlen(vol
->server
) >= sizeof(vi
.server
))
1108 || (strlen(vol
->tape
) >= sizeof(t
.name
)))
1109 return BUDB_BADARGUMENT
;
1111 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1115 /* Find the dump in dumpid hash table */
1116 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &vol
->dump
, &da
, &d
);
1120 ABORT(BUDB_NODUMPID
);
1122 /* search for the right tape in the dump */
1123 for (ta
= ntohl(d
.firstTape
); ta
; ta
= ntohl(t
.nextTape
)) {
1124 /* read the tape entry */
1125 eval
= dbread(ut
, ta
, &t
, sizeof(t
));
1129 /* Check if the right tape name */
1130 if (strcmp(t
.name
, vol
->tape
) == 0)
1134 ABORT(BUDB_NOTAPENAME
);
1136 if ((t
.dump
!= htonl(da
)) || /* tape must belong to dump */
1137 ((ntohl(t
.flags
) & BUDB_TAPE_BEINGWRITTEN
) == 0) || /* tape must be being written */
1138 ((ntohl(d
.flags
) & BUDB_DUMP_INPROGRESS
) == 0)) /* dump must be in progress */
1139 ABORT(BUDB_BADPROTOCOL
);
1141 /* find or create a volume info structure */
1142 eval
= GetVolInfo(ut
, vol
, &via
, &vi
);
1146 /* Create a volume fragment */
1147 eval
= AllocStructure(ut
, volFragment_BLOCK
, 0, &va
, &v
);
1151 v
.vol
= htonl(via
); /* vol frag points to vol info */
1152 v
.sameNameChain
= vi
.firstFragment
; /* vol frag is chained to vol info */
1153 vi
.firstFragment
= htonl(va
);
1154 vi
.nFrags
= htonl(ntohl(vi
.nFrags
) + 1);
1156 eval
= dbwrite(ut
, via
, &vi
, sizeof(vi
)); /* write the vol info struct */
1160 v
.tape
= htonl(ta
); /* vol frag points to tape */
1161 v
.sameTapeChain
= t
.firstVol
; /* vol frag is chained to tape info */
1162 t
.firstVol
= htonl(va
);
1163 t
.nVolumes
= htonl(ntohl(t
.nVolumes
) + 1);
1164 bytes
= ntohl(t
.nBytes
) + vol
->nBytes
; /* update bytes on tape */
1165 t
.nMBytes
= htonl(ntohl(t
.nMBytes
) + bytes
/ (1024 * 1024));
1166 t
.nBytes
= htonl(bytes
% (1024 * 1024));
1168 eval
= dbwrite(ut
, ta
, &t
, sizeof(t
)); /* write the tape structure */
1172 d
.nVolumes
= htonl(ntohl(d
.nVolumes
) + 1); /* one more volume on dump */
1174 eval
= dbwrite(ut
, da
, &d
, sizeof(d
)); /* write out the dump structure */
1178 v
.position
= htonl(vol
->position
); /* vol frag info */
1179 v
.clone
= htonl(vol
->clone
);
1180 v
.incTime
= htonl(vol
->incTime
);
1181 v
.startByte
= htonl(vol
->startByte
);
1182 v
.nBytes
= htonl(vol
->nBytes
);
1183 v
.flags
= htons(vol
->flags
& VOLFRAGMENTFLAGS
);
1184 v
.sequence
= htons(vol
->seq
);
1186 eval
= dbwrite(ut
, va
, &v
, sizeof(v
)); /* write out the vol frag struct */
1190 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1194 LogDebug(4, "added volume %s at %d\n", vol
->name
, va
);
1196 code
= ubik_EndTrans(ut
);
1200 ubik_AbortTrans(ut
);
1206 SBUDB_AddVolumes(struct rx_call
*call
, struct budb_volumeList
*vols
)
1210 code
= AddVolumes(call
, vols
);
1211 osi_auditU(call
, BUDB_AddVolEvent
, code
, AUD_LONG
, 0, AUD_END
);
1216 AddVolumes(struct rx_call
*call
, struct budb_volumeList
*vols
)
1218 struct budb_volumeEntry
*vol
, *vol1
;
1219 struct ubik_trans
*ut
;
1220 dbadr da
, ta
, via
, va
;
1224 struct volFragment v
;
1226 afs_int32 eval
, e
, code
= 0;
1228 if (!callPermitted(call
))
1229 return BUDB_NOTPERMITTED
;
1231 if (!vols
|| (vols
->budb_volumeList_len
<= 0)
1232 || !vols
->budb_volumeList_val
)
1233 return BUDB_BADARGUMENT
;
1235 /* The first volume in the list of volumes to add */
1236 vol1
= (struct budb_volumeEntry
*)vols
->budb_volumeList_val
;
1238 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1242 /* Find the dump in dumpid hash table */
1243 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &vol1
->dump
, &da
, &d
);
1247 ABORT(BUDB_NODUMPID
);
1249 /* search for the right tape in the dump */
1250 for (ta
= ntohl(d
.firstTape
); ta
; ta
= ntohl(t
.nextTape
)) {
1251 /* read the tape entry */
1252 eval
= dbread(ut
, ta
, &t
, sizeof(t
));
1256 /* Check if the right tape name */
1257 if (strcmp(t
.name
, vol1
->tape
) == 0)
1261 ABORT(BUDB_NOTAPENAME
);
1263 if ((t
.dump
!= htonl(da
)) || /* tape must belong to dump */
1264 ((ntohl(t
.flags
) & BUDB_TAPE_BEINGWRITTEN
) == 0) || /* tape must be being written */
1265 ((ntohl(d
.flags
) & BUDB_DUMP_INPROGRESS
) == 0)) /* dump must be in progress */
1266 ABORT(BUDB_BADPROTOCOL
);
1268 for (vol
= vol1
, e
= 0; e
< vols
->budb_volumeList_len
; vol
++, e
++) {
1270 if ((strlen(vol
->name
) >= sizeof(vi
.name
)) || (strcmp(vol
->name
, "") == 0) || /* no null volnames */
1271 (strlen(vol
->server
) >= sizeof(vi
.server
))
1272 || (strlen(vol
->tape
) >= sizeof(t
.name
))
1273 || (strcmp(vol
->tape
, vol1
->tape
) != 0)) {
1274 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n", vol
->name
, vol
->id
, vol
->tape
, vol
->dump
);
1278 /* find or create a volume info structure */
1279 eval
= GetVolInfo(ut
, vol
, &via
, &vi
);
1282 if (*(afs_int32
*) (&vi
) == 0) {
1283 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n", vol
->name
, vol
->tape
, vol
->dump
);
1284 ABORT(BUDB_BADARGUMENT
);
1287 /* Create a volume fragment */
1288 eval
= AllocStructure(ut
, volFragment_BLOCK
, 0, &va
, &v
);
1292 v
.vol
= htonl(via
); /* vol frag points to vol info */
1293 v
.sameNameChain
= vi
.firstFragment
; /* vol frag is chained to vol info */
1294 vi
.firstFragment
= htonl(va
);
1295 vi
.nFrags
= htonl(ntohl(vi
.nFrags
) + 1);
1296 eval
= dbwrite(ut
, via
, &vi
, sizeof(vi
)); /* write the vol info struct */
1300 v
.tape
= htonl(ta
); /* vol frag points to tape */
1301 v
.sameTapeChain
= t
.firstVol
; /* vol frag is chained to tape info */
1302 t
.firstVol
= htonl(va
);
1303 t
.nVolumes
= htonl(ntohl(t
.nVolumes
) + 1);
1304 bytes
= ntohl(t
.nBytes
) + vol
->nBytes
; /* update bytes on tape */
1305 t
.nMBytes
= htonl(ntohl(t
.nMBytes
) + bytes
/ (1024 * 1024));
1306 t
.nBytes
= htonl(bytes
% (1024 * 1024));
1308 d
.nVolumes
= htonl(ntohl(d
.nVolumes
) + 1); /* one more volume on dump */
1310 v
.position
= htonl(vol
->position
); /* vol frag info */
1311 v
.clone
= htonl(vol
->clone
);
1312 v
.incTime
= htonl(vol
->incTime
);
1313 v
.startByte
= htonl(vol
->startByte
);
1314 v
.nBytes
= htonl(vol
->nBytes
);
1315 v
.flags
= htons(vol
->flags
& VOLFRAGMENTFLAGS
);
1316 v
.sequence
= htons(vol
->seq
);
1318 eval
= dbwrite(ut
, va
, &v
, sizeof(v
)); /* write out the vol frag struct */
1322 LogDebug(4, "added volume %s at %d\n", vol
->name
, va
);
1325 eval
= dbwrite(ut
, ta
, &t
, sizeof(t
)); /* write the tape structure */
1329 eval
= dbwrite(ut
, da
, &d
, sizeof(d
)); /* write out the dump structure */
1333 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1337 code
= ubik_EndTrans(ut
);
1341 ubik_AbortTrans(ut
);
1347 * records the existence of a dump in the database. This creates only
1348 * the dump record, to which one must attach tape and volume records.
1350 * 1) record the volume set
1354 SBUDB_CreateDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
1358 code
= CreateDump(call
, dump
);
1359 osi_auditU(call
, BUDB_CrDmpEvent
, code
, AUD_DATE
, (dump
? dump
->id
: 0),
1361 if (dump
&& !code
) {
1362 Log("Create dump %s (DumpID %u), path %s\n", dump
->name
, dump
->id
,
1369 CreateDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
1371 struct ubik_trans
*ut
;
1372 dbadr findDumpAddr
, da
;
1373 struct dump findDump
, d
;
1374 afs_int32 eval
, code
= 0;
1378 Date expiration
; /* checked by Security Module */
1379 struct ktc_principal principal
;
1381 if (!callPermitted(call
))
1382 return BUDB_NOTPERMITTED
;
1384 if (strlen(dump
->name
) >= sizeof(d
.dumpName
))
1385 return BUDB_BADARGUMENT
;
1387 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1392 rxkad_GetServerInfo(rx_ConnectionOf(call
), &level
, &expiration
,
1393 principal
.name
, principal
.instance
,
1394 principal
.cell
, &kvno
);
1397 if (eval
!= RXKADNOAUTH
)
1400 strcpy(principal
.name
, "");
1401 strcpy(principal
.instance
, "");
1402 strcpy(principal
.cell
, "");
1405 /* authenticated. Take user supplied principal information */
1406 if (strcmp(dump
->dumper
.name
, "") != 0)
1407 strncpy(principal
.name
, dump
->dumper
.name
,
1408 sizeof(principal
.name
));
1410 if (strcmp(dump
->dumper
.instance
, "") != 0)
1411 strncpy(principal
.instance
, dump
->dumper
.instance
,
1412 sizeof(principal
.instance
));
1414 if (strcmp(dump
->dumper
.cell
, "") != 0)
1415 strncpy(principal
.cell
, dump
->dumper
.cell
,
1416 sizeof(principal
.cell
));
1419 /* dump id's are time stamps */
1421 while (1) { /* allocate a unique dump id *//*w */
1424 /* ensure it is unique - seach for dumpid in hash table */
1426 ht_LookupEntry(ut
, &db
.dumpIden
, &dump
->id
, &findDumpAddr
,
1431 if (!findDumpAddr
) { /* dumpid not in use */
1432 /* update the last dump id allocated */
1433 eval
= set_header_word(ut
, lastDumpId
, htonl(dump
->id
));
1439 /* dump id is in use - wait a while */
1440 #ifdef AFS_PTHREAD_ENV
1447 /* dump id supplied (e.g. for database restore) */
1449 ht_LookupEntry(ut
, &db
.dumpIden
, &dump
->id
, &findDumpAddr
,
1454 /* Dump id must not already exist */
1456 ABORT(BUDB_DUMPIDEXISTS
);
1459 /* Allocate a dump structure */
1460 memset(&d
, 0, sizeof(d
));
1461 eval
= AllocStructure(ut
, dump_BLOCK
, 0, &da
, &d
);
1465 strcpy(d
.dumpName
, dump
->name
); /* volset.dumpname */
1466 strcpy(d
.dumpPath
, dump
->dumpPath
); /* dump node path */
1467 strcpy(d
.volumeSet
, dump
->volumeSetName
); /* volume set */
1468 d
.id
= htonl(dump
->id
);
1469 d
.parent
= htonl(dump
->parent
); /* parent id */
1470 d
.level
= htonl(dump
->level
);
1472 LogDebug(4, "dump name %s, parent %d level %d\n", dump
->name
,
1473 dump
->parent
, dump
->level
);
1475 /* if creation time specified, use that. Else use the dumpid time */
1476 if (dump
->created
== 0)
1477 dump
->created
= dump
->id
;
1478 d
.created
= htonl(dump
->created
);
1480 d
.dumper
= principal
;
1481 tapeSet_hton(&dump
->tapes
, &d
.tapes
);
1483 d
.flags
= htonl(dump
->flags
| BUDB_DUMP_INPROGRESS
);
1485 eval
= ht_HashIn(ut
, &db
.dumpName
, da
, &d
); /* Into dump name hash table */
1489 eval
= ht_HashIn(ut
, &db
.dumpIden
, da
, &d
); /* Into dumpid hash table */
1493 eval
= dbwrite(ut
, da
, (char *)&d
, sizeof(d
)); /* Write the dump structure */
1497 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1501 /* If to append this dump, then append it - will write the appended dump */
1502 eval
= makeAppended(ut
, dump
->id
, dump
->initialDumpID
, dump
->tapes
.b
);
1506 code
= ubik_EndTrans(ut
);
1507 LogDebug(5, "made dump %s, path %s\n", d
.dumpName
, d
.dumpPath
);
1511 ubik_AbortTrans(ut
);
1516 SBUDB_DeleteDump(struct rx_call
*call
, dumpId id
, Date fromTime
, Date toTime
,
1517 budb_dumpsList
*dumps
)
1521 code
= DoDeleteDump(call
, id
, fromTime
, toTime
, dumps
);
1522 osi_auditU(call
, BUDB_DelDmpEvent
, code
, AUD_DATE
, id
, AUD_END
);
1529 DoDeleteDump(struct rx_call
*call
, dumpId id
, Date fromTime
, Date toTime
,
1530 budb_dumpsList
*dumps
)
1534 if (!callPermitted(call
))
1535 return BUDB_NOTPERMITTED
;
1538 code
= deleteDump(call
, id
, dumps
);
1543 SBUDB_ListDumps(struct rx_call
*call
, afs_int32 sflags
, char *name
,
1544 afs_int32 groupid
, Date fromTime
, Date toTime
,
1545 budb_dumpsList
*dumps
, budb_dumpsList
*flags
)
1549 code
= ListDumps(call
, sflags
, groupid
, fromTime
, toTime
, dumps
, flags
);
1550 osi_auditU(call
, BUDB_LstDmpEvent
, code
, AUD_LONG
, flags
, AUD_END
);
1555 ListDumps(struct rx_call
*call
, afs_int32 sflags
, afs_int32 groupid
,
1556 Date fromTime
, Date toTime
, budb_dumpsList
*dumps
,
1557 budb_dumpsList
*flags
)
1559 struct ubik_trans
*ut
;
1560 struct memoryHashTable
*mht
;
1561 struct dump diskDump
, appDiskDump
;
1562 dbadr dbAddr
, dbAppAddr
;
1564 afs_int32 eval
, code
= 0;
1565 int old
, hash
, length
, entrySize
, count
= 0;
1567 if (!callPermitted(call
))
1568 return BUDB_NOTPERMITTED
;
1570 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1574 /* Search the database */
1575 mht
= ht_GetType(HT_dumpIden_FUNCTION
, &entrySize
);
1577 return (BUDB_BADARGUMENT
);
1579 for (old
= 0; old
<= 1; old
++) { /*o *//* old and new hash tables */
1580 length
= (old
? mht
->oldLength
: mht
->length
);
1584 for (hash
= 0; hash
< length
; hash
++) { /*h *//* for each hash bucket */
1585 for (dbAddr
= ht_LookupBucket(ut
, mht
, hash
, old
); dbAddr
; dbAddr
= ntohl(diskDump
.idHashChain
)) { /*d */
1587 /* read the entry */
1588 eval
= dbread(ut
, dbAddr
, &diskDump
, sizeof(diskDump
));
1592 /* Skip appended dumps */
1593 if (ntohl(diskDump
.initialDumpID
) != 0) {
1597 /* Skip dumps with different goup id */
1598 if ((sflags
& BUDB_OP_GROUPID
)
1599 && (ntohl(diskDump
.tapes
.id
) != groupid
)) {
1603 /* Look at this dump to see if it meets the criteria for listing */
1604 if (sflags
& BUDB_OP_DATES
) {
1605 /* This and each appended dump should be in time */
1606 for (dbAppAddr
= dbAddr
; dbAppAddr
;
1607 dbAppAddr
= ntohl(appDiskDump
.appendedDumpChain
)) {
1609 dbread(ut
, dbAppAddr
, &appDiskDump
,
1610 sizeof(appDiskDump
));
1614 if ((ntohl(appDiskDump
.id
) < fromTime
)
1615 || (ntohl(appDiskDump
.id
) > toTime
))
1622 /* Add it and each of its appended dump to our list to return */
1623 for (dbAppAddr
= dbAddr
; dbAppAddr
;
1624 dbAppAddr
= ntohl(appDiskDump
.appendedDumpChain
)) {
1626 dbread(ut
, dbAppAddr
, &appDiskDump
,
1627 sizeof(appDiskDump
));
1631 /* Make sure we have space to list it */
1632 if (dumps
->budb_dumpsList_len
>= count
) {
1635 dumps
->budb_dumpsList_val
=
1636 malloc(count
* sizeof(afs_int32
));
1637 flags
->budb_dumpsList_val
=
1638 malloc(count
* sizeof(afs_int32
));
1640 dumps
->budb_dumpsList_val
=
1641 realloc(dumps
->budb_dumpsList_val
,
1642 count
* sizeof(afs_int32
));
1643 flags
->budb_dumpsList_val
=
1644 realloc(flags
->budb_dumpsList_val
,
1645 count
* sizeof(afs_int32
));
1647 if (!dumps
->budb_dumpsList_val
1648 || !dumps
->budb_dumpsList_val
)
1652 /* Add it to our list */
1653 dumps
->budb_dumpsList_val
[dumps
->budb_dumpsList_len
] =
1654 ntohl(appDiskDump
.id
);
1655 flags
->budb_dumpsList_val
[flags
->budb_dumpsList_len
] = 0;
1656 if (ntohl(appDiskDump
.initialDumpID
) != 0) {
1657 flags
->budb_dumpsList_val
[flags
->
1658 budb_dumpsList_len
] |=
1661 if (strcmp(appDiskDump
.dumpName
, DUMP_TAPE_NAME
) == 0) {
1662 flags
->budb_dumpsList_val
[flags
->
1663 budb_dumpsList_len
] |=
1666 dumps
->budb_dumpsList_len
++;
1667 flags
->budb_dumpsList_len
++;
1673 code
= ubik_EndTrans(ut
);
1677 ubik_AbortTrans(ut
);
1682 SBUDB_DeleteTape(struct rx_call
*call
,
1683 struct budb_tapeEntry
*tape
) /* tape info */
1687 code
= DoDeleteTape(call
, tape
);
1688 osi_auditU(call
, BUDB_DelTpeEvent
, code
, AUD_DATE
,
1689 (tape
? tape
->dump
: 0), AUD_END
);
1694 DoDeleteTape(struct rx_call
*call
,
1695 struct budb_tapeEntry
*tape
) /* tape info */
1697 struct ubik_trans
*ut
;
1700 afs_int32 eval
, code
;
1702 if (!callPermitted(call
))
1703 return BUDB_NOTPERMITTED
;
1705 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
1709 eval
= ht_LookupEntry(ut
, &db
.tapeName
, tape
->name
, &a
, &t
);
1713 eval
= DeleteTape(ut
, a
, &t
);
1717 eval
= FreeStructure(ut
, tape_BLOCK
, a
);
1721 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
1725 code
= ubik_EndTrans(ut
);
1729 ubik_AbortTrans(ut
);
1734 * Deletes old information from the database for a particular dump path
1735 * and volumset. This supercedes the old policy implemented in
1736 * UseTape, which simply matched on the volumeset.dump. Consequently
1737 * it was unable to handle name re-use.
1739 * dsname - dumpset name, i.e. volumeset.dumpname
1740 * dumpPath - full path of dump node
1741 * curDumpID - current dump in progress - so that is may be excluded
1744 * n - some error. May or may not have deleted information.
1748 SBUDB_DeleteVDP(struct rx_call
*call
, char *dsname
, char *dumpPath
,
1749 afs_int32 curDumpId
)
1753 code
= DeleteVDP(call
, dsname
, dumpPath
, curDumpId
);
1754 osi_auditU(call
, BUDB_DelVDPEvent
, code
, AUD_STR
, dsname
, AUD_END
);
1759 DeleteVDP(struct rx_call
*call
, char *dsname
, char *dumpPath
,
1760 afs_int32 curDumpId
)
1765 struct ubik_trans
*ut
;
1766 afs_int32 eval
, code
= 0;
1768 if (!callPermitted(call
))
1769 return BUDB_NOTPERMITTED
;
1772 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1776 eval
= ht_LookupEntry(ut
, &db
.dumpName
, dsname
, &dumpAddr
, &dump
);
1780 while (dumpAddr
!= 0) { /*wd */
1781 if ((strcmp(dump
.dumpName
, dsname
) == 0)
1782 && (strcmp(dump
.dumpPath
, dumpPath
) == 0)
1783 && (ntohl(dump
.id
) != curDumpId
)) {
1784 eval
= ubik_EndTrans(ut
);
1788 eval
= deleteDump(call
, ntohl(dump
.id
), 0);
1792 /* start the traversal over since the various chains may
1798 dumpAddr
= ntohl(dump
.nameHashChain
);
1800 eval
= dbread(ut
, dumpAddr
, &dump
, sizeof(dump
));
1806 /* check if all the dumps have been examined - can terminate */
1808 eval
= ubik_EndTrans(ut
);
1814 ubik_AbortTrans(ut
);
1820 * Given a volume name, and a dumpID, find the volume in that dump and
1821 * return the clone date of the volume (this is the clone date of the
1822 * volume at the time it was dumped).
1824 * Hashes on the volume name and traverses the fragments. Will need to read
1825 * the volumes tape entry to determine if it belongs to the dump. If the
1826 * volume is not found in the dump, then look for it in its parent dump.
1830 SBUDB_FindClone(struct rx_call
*call
, afs_int32 dumpID
, char *volName
,
1831 afs_int32
*clonetime
)
1835 code
= FindClone(call
, dumpID
, volName
, clonetime
);
1836 osi_auditU(call
, BUDB_FndClnEvent
, code
, AUD_STR
, volName
, AUD_END
);
1841 FindClone(struct rx_call
*call
, afs_int32 dumpID
, char *volName
,
1842 afs_int32
*clonetime
)
1844 struct ubik_trans
*ut
;
1845 dbadr da
, hvia
, via
, vfa
;
1848 struct volFragment vf
;
1850 int rvi
; /* read the volInfo struct */
1851 afs_int32 eval
, code
= 0;
1853 if (!callPermitted(call
))
1854 return BUDB_NOTPERMITTED
;
1856 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1862 /* Search for the volume by name */
1863 eval
= ht_LookupEntry(ut
, &db
.volName
, volName
, &hvia
, &vi
);
1867 ABORT(BUDB_NOVOLUMENAME
);
1870 /* Follw the dump levels up */
1871 for (; dumpID
; dumpID
= ntohl(d
.parent
)) { /*d */
1872 /* Get the dump entry */
1873 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dumpID
, &da
, &d
);
1877 ABORT(BUDB_NODUMPID
);
1879 /* seach all the volInfo entries on the sameNameChain */
1880 for (via
= hvia
; via
; via
= ntohl(vi
.sameNameChain
)) { /*via */
1881 if (rvi
) { /* Read the volInfo entry - except first time */
1882 eval
= dbread(ut
, via
, &vi
, sizeof(vi
));
1888 /* search all the volFrag entries on the volFrag */
1889 for (vfa
= ntohl(vi
.firstFragment
); vfa
; vfa
= ntohl(vf
.sameNameChain
)) { /*vfa */
1890 eval
= dbread(ut
, vfa
, &vf
, sizeof(vf
)); /* Read the volFrag entry */
1894 eval
= dbread(ut
, ntohl(vf
.tape
), &t
, sizeof(t
)); /* Read the tape */
1898 /* Now check to see if this fragment belongs to the dump we have */
1899 if (ntohl(t
.dump
) == da
) {
1900 *clonetime
= ntohl(vf
.clone
); /* return the clone */
1908 code
= ubik_EndTrans(ut
);
1918 * Searches each tape and each volume in the dump until the volume is found.
1919 * If the volume is not in the dump, then we search it's parent dump.
1921 * Re-write to do lookups by volume name.
1924 FindClone(struct rx_call
*call
, afs_int32 dumpID
, char *volName
,
1925 afs_int32
*clonetime
)
1927 struct ubik_trans
*ut
;
1928 dbadr diskAddr
, tapeAddr
, volFragmentAddr
;
1931 struct volFragment volFragment
;
1932 struct volInfo volInfo
;
1933 afs_int32 eval
, code
= 0;
1935 if (!callPermitted(call
))
1936 return BUDB_NOTPERMITTED
;
1938 eval
= InitRPC(&ut
, LOCKREAD
, 1);
1944 for (; dumpID
; dumpID
= ntohl(dump
.parent
)) { /*d */
1945 /* Get the dump entry */
1946 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dumpID
, &diskAddr
, &dump
);
1950 ABORT(BUDB_NODUMPID
);
1952 /* just to be sure */
1953 if (ntohl(dump
.id
) != dumpID
) {
1954 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID
,
1956 ABORT(BUDB_INTERNALERROR
);
1959 /* search all the tapes in this dump */
1960 for (tapeAddr
= ntohl(dump
.firstTape
); tapeAddr
; tapeAddr
= ntohl(tape
.nextTape
)) { /*t */
1961 /* Get the tape entry */
1962 eval
= dbread(ut
, tapeAddr
, &tape
, sizeof(tape
));
1966 /* search all the volume fragments on this tape */
1967 for (volFragmentAddr
= ntohl(tape
.firstVol
); volFragmentAddr
; volFragmentAddr
= ntohl(volFragment
.sameTapeChain
)) { /*vf */
1968 /* Get the volume fragment entry */
1970 dbread(ut
, volFragmentAddr
, &volFragment
,
1971 sizeof(volFragment
));
1975 /* Get the volume info entry */
1977 dbread(ut
, ntohl(volFragment
.vol
), &volInfo
,
1982 /* check if this volume is the one we want */
1983 if (strcmp(volInfo
.name
, volName
) == 0) {
1984 *clonetime
= ntohl(volFragment
.clone
);
1992 code
= ubik_EndTrans(ut
);
2002 * Find latest volume dump before adate.
2003 * Used by restore code when restoring a user requested volume(s)
2005 * volumeName - name of volume to match on
2006 * beforeDate - look for dumps older than this date
2008 * deptr - descriptor of most recent dump
2012 SBUDB_FindDump(struct rx_call
*call
, char *volumeName
, afs_int32 beforeDate
,
2013 struct budb_dumpEntry
*deptr
)
2017 code
= FindDump(call
, volumeName
, beforeDate
, deptr
);
2018 osi_auditU(call
, BUDB_FndDmpEvent
, code
, AUD_STR
, volumeName
, AUD_END
);
2023 FindDump(struct rx_call
*call
, char *volumeName
, afs_int32 beforeDate
,
2024 struct budb_dumpEntry
*deptr
)
2026 struct ubik_trans
*ut
;
2027 dbadr volInfoAddr
, volFragmentAddr
;
2029 struct volInfo volInfo
;
2030 struct volFragment volFragment
;
2032 dbadr selectedDumpAddr
= 0;
2033 afs_int32 selectedDate
= 0;
2034 afs_int32 volCloned
;
2036 afs_int32 eval
, code
= 0;
2038 if (!callPermitted(call
))
2039 return BUDB_NOTPERMITTED
;
2041 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2045 /* Find volinfo struct for volume name in hash table */
2047 ht_LookupEntry(ut
, &db
.volName
, volumeName
, &volInfoAddr
, &volInfo
);
2051 ABORT(BUDB_NOVOLUMENAME
);
2053 /* Step through all the volinfo structures on the same name chain.
2054 * No need to read the first - we read it above.
2056 for (rvoli
= 0; volInfoAddr
;
2057 rvoli
= 1, volInfoAddr
= ntohl(volInfo
.sameNameChain
)) {
2058 if (rvoli
) { /* read the volinfo structure */
2059 eval
= dbread(ut
, volInfoAddr
, &volInfo
, sizeof(volInfo
));
2064 /* step through the volfrag structures */
2065 for (volFragmentAddr
= ntohl(volInfo
.firstFragment
); volFragmentAddr
;
2066 volFragmentAddr
= ntohl(volFragment
.sameNameChain
)) {
2067 /* read the volfrag struct */
2069 dbread(ut
, volFragmentAddr
, &volFragment
,
2070 sizeof(volFragment
));
2074 volCloned
= ntohl(volFragment
.clone
);
2076 /* now we can examine the date for most recent dump */
2077 if ((volCloned
> selectedDate
) && (volCloned
< beforeDate
)) {
2078 /* from the volfrag struct, read the tape struct */
2080 dbread(ut
, ntohl(volFragment
.tape
), &tape
, sizeof(tape
));
2084 selectedDate
= volCloned
;
2085 selectedDumpAddr
= ntohl(tape
.dump
);
2090 if (!selectedDumpAddr
)
2093 eval
= FillDumpEntry(ut
, selectedDumpAddr
, deptr
);
2097 code
= ubik_EndTrans(ut
);
2105 /* BUDB_FindLatestDump
2106 * Find the latest dump of volumeset vsname with dump name dname.
2108 * vsname - volumeset name
2113 SBUDB_FindLatestDump(struct rx_call
*call
, char *vsname
, char *dumpPath
,
2114 struct budb_dumpEntry
*dumpentry
)
2118 code
= FindLatestDump(call
, vsname
, dumpPath
, dumpentry
);
2119 osi_auditU(call
, BUDB_FndLaDEvent
, code
, AUD_STR
, vsname
, AUD_END
);
2124 FindLatestDump(struct rx_call
*call
, char *vsname
, char *dumpPath
,
2125 struct budb_dumpEntry
*dumpentry
)
2127 struct ubik_trans
*ut
;
2128 dbadr curdbaddr
, retdbaddr
, firstdbaddr
;
2131 char dumpName
[BU_MAXNAMELEN
+ 2];
2132 afs_int32 eval
, code
= 0;
2134 if (!callPermitted(call
))
2135 return BUDB_NOTPERMITTED
;
2137 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2141 if ((strcmp(vsname
, "") == 0) && (strcmp(dumpPath
, "") == 0)) {
2142 /* Construct a database dump name */
2143 strcpy(dumpName
, DUMP_TAPE_NAME
);
2144 } else if (strchr(dumpPath
, '/') == 0) {
2145 int level
, old
, length
, hash
;
2146 struct dump hostDump
, diskDump
;
2147 struct memoryHashTable
*mht
;
2150 afs_uint32 bestDumpId
= 0;
2152 level
= atoi(dumpPath
);
2154 ABORT(BUDB_BADARGUMENT
);
2157 /* Brute force search of all the dumps in the database - yuck! */
2160 mht
= ht_GetType(HT_dumpIden_FUNCTION
, &entrySize
);
2162 ABORT(BUDB_BADARGUMENT
);
2164 for (old
= 0; old
<= 1; old
++) { /*fo */
2165 length
= (old
? mht
->oldLength
: mht
->length
);
2169 for (hash
= 0; hash
< length
; hash
++) {
2171 for (dbAddr
= ht_LookupBucket(ut
, mht
, hash
, old
); dbAddr
;
2172 dbAddr
= hostDump
.idHashChain
) {
2174 eval
= dbread(ut
, dbAddr
, &diskDump
, sizeof(diskDump
));
2177 dump_ntoh(&diskDump
, &hostDump
);
2179 if ((strcmp(hostDump
.volumeSet
, vsname
) == 0) && /* the volumeset */
2180 (hostDump
.level
== level
) && /* same level */
2181 (hostDump
.id
> bestDumpId
)) { /* more recent */
2182 bestDumpId
= hostDump
.id
;
2189 ABORT(BUDB_NODUMPNAME
);
2193 /* construct the name of the dump */
2194 if ((strlen(vsname
) + strlen(tailCompPtr(dumpPath
))) > BU_MAXNAMELEN
)
2195 ABORT(BUDB_NODUMPNAME
);
2197 strcpy(dumpName
, vsname
);
2198 strcat(dumpName
, ".");
2199 strcat(dumpName
, tailCompPtr(dumpPath
));
2202 LogDebug(5, "lookup on :%s:\n", dumpName
);
2204 /* Lookup on dumpname in hash table */
2205 eval
= ht_LookupEntry(ut
, &db
.dumpName
, dumpName
, &firstdbaddr
, &d
);
2212 /* folow remaining dumps in hash chain, looking for most latest dump */
2213 for (curdbaddr
= firstdbaddr
; curdbaddr
;
2214 curdbaddr
= ntohl(d
.nameHashChain
)) {
2215 if (curdbaddr
!= firstdbaddr
) {
2216 eval
= dbread(ut
, curdbaddr
, &d
, sizeof(d
));
2221 if ((strcmp(d
.dumpPath
, dumpPath
) == 0) && /* Same dumppath */
2222 (strcmp(d
.dumpName
, dumpName
) == 0) && /* Same dumpname */
2223 (ntohl(d
.created
) > latest
)) { /* most recent */
2224 latest
= ntohl(d
.created
);
2225 retdbaddr
= curdbaddr
;
2229 ABORT(BUDB_NODUMPNAME
);
2232 /* return the dump found */
2233 eval
= FillDumpEntry(ut
, retdbaddr
, dumpentry
);
2237 code
= ubik_EndTrans(ut
);
2241 ubik_AbortTrans(ut
);
2247 SBUDB_FinishDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
2251 code
= FinishDump(call
, dump
);
2252 osi_auditU(call
, BUDB_FinDmpEvent
, code
, AUD_DATE
, (dump
? dump
->id
: 0),
2258 FinishDump(struct rx_call
*call
, struct budb_dumpEntry
*dump
)
2260 struct ubik_trans
*ut
;
2263 afs_int32 eval
, code
= 0;
2265 if (!callPermitted(call
))
2266 return BUDB_NOTPERMITTED
;
2268 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
2272 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dump
->id
, &a
, &d
);
2276 ABORT(BUDB_NODUMPID
);
2278 if ((ntohl(d
.flags
) & BUDB_DUMP_INPROGRESS
) == 0)
2279 ABORT(BUDB_DUMPNOTINUSE
);
2281 d
.flags
= htonl(dump
->flags
& ~BUDB_DUMP_INPROGRESS
);
2283 /* if creation time specified set it */
2285 d
.created
= htonl(dump
->created
);
2286 dump
->created
= ntohl(d
.created
);
2288 /* Write the dump entry out */
2289 eval
= dbwrite(ut
, a
, &d
, sizeof(d
));
2293 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
2297 code
= ubik_EndTrans(ut
);
2301 ubik_AbortTrans(ut
);
2306 SBUDB_FinishTape(struct rx_call
*call
, struct budb_tapeEntry
*tape
)
2310 code
= FinishTape(call
, tape
);
2311 osi_auditU(call
, BUDB_FinTpeEvent
, code
, AUD_DATE
,
2312 (tape
? tape
->dump
: 0), AUD_END
);
2317 FinishTape(struct rx_call
*call
, struct budb_tapeEntry
*tape
)
2319 struct ubik_trans
*ut
;
2323 afs_int32 eval
, code
= 0;
2325 if (!callPermitted(call
))
2326 return BUDB_NOTPERMITTED
;
2328 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
2332 /* find the tape struct in the tapename hash chain */
2333 eval
= ht_LookupEntry(ut
, &db
.tapeName
, tape
->name
, &a
, &t
);
2337 ABORT(BUDB_NOTAPENAME
);
2339 /* Read the dump structure */
2340 eval
= dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
));
2344 /* search for the right tape on the rest of the chain */
2345 while (ntohl(d
.id
) != tape
->dump
) {
2346 a
= ntohl(t
.nameHashChain
);
2348 ABORT(BUDB_NOTAPENAME
);
2350 eval
= dbread(ut
, a
, &t
, sizeof(t
));
2354 eval
= dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
));
2359 if ((ntohl(t
.flags
) & BUDB_TAPE_BEINGWRITTEN
) == 0)
2360 ABORT(BUDB_TAPENOTINUSE
);
2362 /* t.nBytes = htonl(tape->nBytes); */
2363 t
.nFiles
= htonl(tape
->nFiles
);
2364 t
.useKBytes
= htonl(tape
->useKBytes
);
2365 t
.flags
= htonl(tape
->flags
& ~BUDB_TAPE_BEINGWRITTEN
);
2367 eval
= dbwrite(ut
, a
, &t
, sizeof(t
));
2371 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
2375 code
= ubik_EndTrans(ut
);
2379 ubik_AbortTrans(ut
);
2384 * return a set of dumps that match the specified criteria
2387 * majorVersion - version of interface structures. Permits compatibility
2389 * flags - for search and select operations. Broken down into flags
2390 * for name, start point, end point and time.
2391 * name - name to search for. Interpretation based on flags
2398 * dbTimeP - time at which the database was last modified. Up to
2399 * caller (client) to take appropriate action if database
2400 * modified between successive calls
2401 * dumps - list of matching dumps
2403 * currently supported are:
2409 SBUDB_GetDumps(struct rx_call
*call
,
2410 afs_int32 majorVersion
, /* version of interface structures */
2411 afs_int32 flags
, /* search & select controls */
2412 char *name
, /* s&s parameters */
2415 afs_int32 index
, /* start index of returned entries */
2416 afs_int32
*nextIndexP
, /* output index for next call */
2418 budb_dumpList
*dumps
) /* pointer to buffer */
2423 GetDumps(call
, majorVersion
, flags
, name
, start
, end
, index
,
2424 nextIndexP
, dbTimeP
, dumps
);
2425 osi_auditU(call
, BUDB_GetDmpEvent
, code
, AUD_END
);
2430 GetDumps(struct rx_call
*call
,
2431 afs_int32 majorVersion
, /* version of interface structures */
2432 afs_int32 flags
, /* search & select controls */
2433 char *name
, /* s&s parameters */
2436 afs_int32 index
, /* start index of returned entries */
2437 afs_int32
*nextIndexP
, /* output index for next call */
2439 budb_dumpList
*dumps
) /* pointer to buffer */
2441 struct ubik_trans
*ut
;
2444 afs_int32 nameFlags
, startFlags
, endFlags
, timeFlags
;
2445 afs_int32 eval
, code
= 0;
2447 struct returnList list
;
2449 /* Don't check permissions when we look up a specific dump id */
2450 if (((flags
& BUDB_OP_STARTS
) != BUDB_OP_DUMPID
) && !callPermitted(call
))
2451 return BUDB_NOTPERMITTED
;
2453 if (majorVersion
!= BUDB_MAJORVERSION
)
2454 return BUDB_OLDINTERFACE
;
2456 return BUDB_ENDOFLIST
;
2458 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2462 nameFlags
= flags
& BUDB_OP_NAMES
;
2463 startFlags
= flags
& BUDB_OP_STARTS
;
2464 endFlags
= flags
& BUDB_OP_ENDS
;
2465 timeFlags
= flags
& BUDB_OP_TIMES
;
2467 InitReturnList(&list
);
2470 if (nameFlags
== BUDB_OP_DUMPNAME
) {
2471 /* not yet implemented */
2472 if (startFlags
|| endFlags
|| timeFlags
)
2473 ABORT(BUDB_BADFLAGS
);
2475 eval
= ht_LookupEntry(ut
, &db
.dumpName
, name
, &da
, &d
);
2479 ABORT(BUDB_NODUMPNAME
);
2482 if (strcmp(d
.dumpName
, name
) == 0) {
2483 eval
= AddToReturnList(&list
, da
, &toskip
);
2484 if (eval
== BUDB_LIST2BIG
)
2490 da
= ntohl(d
.nameHashChain
); /* get next dump w/ name */
2494 eval
= dbread(ut
, da
, &d
, sizeof(d
));
2498 } else if (nameFlags
== BUDB_OP_VOLUMENAME
) {
2502 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2503 ABORT(BUDB_BADFLAGS
);
2506 if (startFlags
!= BUDB_OP_STARTTIME
)
2507 ABORT(BUDB_BADFLAGS
);
2509 /* lookup a dump by volumename and time stamp. Find the most recent
2510 * dump of the specified volumename, that occured before the supplied
2514 /* get us a volInfo for name */
2515 eval
= ht_LookupEntry(ut
, &db
.volName
, name
, &da
, &vi
);
2520 /* now iterate over all the entries of this name */
2521 for (va
= vi
.firstFragment
; va
!= 0; va
= v
.sameNameChain
) {
2523 eval
= dbread(ut
, va
, &v
, sizeof(v
));
2528 on fragment
> date ignore it
- too recent
;
2530 if (date on fragment
< date
&& date on fragment
> bestfound
)
2531 bestfound
= date on fragment
;
2535 da
= vi
.sameNameChain
;
2539 eval
= dbread(ut
, da
, &vi
, sizeof(vi
));
2548 from saved volfragment address, compute dump.
2549 otherwise, return dump found
2554 } else if (startFlags
== BUDB_OP_DUMPID
) {
2555 if (endFlags
|| timeFlags
)
2556 ABORT(BUDB_BADFLAGS
);
2558 ABORT(BUDB_BADFLAGS
); /* NYI */
2560 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &start
, &da
, &d
);
2564 ABORT(BUDB_NODUMPID
);
2566 eval
= AddToReturnList(&list
, da
, &toskip
);
2569 } else if (endFlags
== BUDB_OP_NPREVIOUS
) {
2570 struct wantDumpRock rock
;
2571 struct chosenDump
*ptr
, *nextPtr
;
2573 /* no other flags should be set */
2575 /* end specifies how many dumps */
2577 ABORT(BUDB_BADFLAGS
);
2579 memset(&rock
, 0, sizeof(rock
));
2580 rock
.maxDumps
= end
;
2582 scanHashTable(ut
, &db
.dumpName
, wantDump
, rememberDump
,
2585 for (ptr
= rock
.chain
; ptr
; ptr
= nextPtr
) {
2586 nextPtr
= ptr
->next
;
2587 AddToReturnList(&list
, ptr
->addr
, &toskip
); /* ignore error for free */
2591 ABORT(BUDB_BADFLAGS
);
2595 SendReturnList(ut
, &list
, FillDumpEntry
,
2596 sizeof(struct budb_dumpEntry
), index
, nextIndexP
,
2597 dbTimeP
, (returnList_t
) dumps
);
2601 FreeReturnList(&list
);
2602 code
= ubik_EndTrans(ut
);
2606 FreeReturnList(&list
);
2607 ubik_AbortTrans(ut
);
2612 * Get the expiration of a tape. Since the dump could have appended dumps,
2613 * we should use the most recent expiration date. Put the most recent
2614 * expiration tape into the given tape structure.
2617 getExpiration(struct ubik_trans
*ut
, struct tape
*tapePtr
)
2623 afs_int32 eval
, code
= 0;
2628 /* Get the dump for this tape */
2629 ad
= ntohl(tapePtr
->dump
);
2630 eval
= dbread(ut
, ad
, &d
, sizeof(d
));
2634 /* If not an initial dump, get the initial dump */
2635 if (d
.initialDumpID
) {
2636 initDump
= ntohl(d
.initialDumpID
);
2637 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &initDump
, &ad
, &d
);
2642 /* Cycle through the dumps and appended dumps */
2644 /* Get the first tape in this dump. No need to check the rest of the tapes */
2645 /* for this dump since they will all have the same expiration date */
2646 eval
= dbread(ut
, ntohl(d
.firstTape
), &t
, sizeof(t
));
2650 /* Take the greater of the expiration dates */
2651 if (ntohl(tapePtr
->expires
) < ntohl(t
.expires
))
2652 tapePtr
->expires
= t
.expires
;
2654 /* Step to and read the next appended dump */
2655 if ((ad
= ntohl(d
.appendedDumpChain
))) {
2656 eval
= dbread(ut
, ad
, &d
, sizeof(d
));
2666 /* Mark the following dump as appended to another, intial dump */
2668 makeAppended(struct ubik_trans
*ut
, afs_int32 appendedDumpID
,
2669 afs_int32 initialDumpID
, afs_int32 startTapeSeq
)
2671 dbadr ada
, da
, lastDumpAddr
;
2673 afs_int32 eval
, code
= 0;
2677 if (appendedDumpID
== initialDumpID
)
2678 ERROR(BUDB_INTERNALERROR
);
2680 /* If there is an initial dump, append this dump to it */
2681 /* Find the appended dump via its id */
2682 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &appendedDumpID
, &ada
, &ad
);
2686 /* If the dump is already marked as appended,
2687 * then we have an internal error.
2689 if (ad
.initialDumpID
) {
2690 if (ntohl(ad
.initialDumpID
) != initialDumpID
)
2691 ERROR(BUDB_INTERNALERROR
);
2694 /* Update the appended dump to point to the initial dump */
2695 ad
.initialDumpID
= htonl(initialDumpID
);
2696 ad
.tapes
.b
= htonl(startTapeSeq
);
2698 /* find the initial dump via its id */
2699 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &initialDumpID
, &da
, &d
);
2703 /* Update the appended dump's tape format with that of the initial */
2704 strcpy(ad
.tapes
.format
, d
.tapes
.format
);
2706 /* starting with the initial dump step through its appended dumps till
2707 * we reach the last appended dump.
2710 while (d
.appendedDumpChain
) {
2711 lastDumpAddr
= ntohl(d
.appendedDumpChain
);
2712 if (lastDumpAddr
== ada
)
2713 ERROR(0); /* Already appended */
2714 eval
= dbread(ut
, lastDumpAddr
, &d
, sizeof(d
));
2719 /* Update the last dump to point to our new appended dump.
2720 * The appended dump is the last one in the dump chain.
2722 d
.appendedDumpChain
= htonl(ada
);
2723 ad
.appendedDumpChain
= 0;
2725 /* Write the appended dump and the initial dump */
2726 eval
= dbwrite(ut
, ada
, (char *)&ad
, sizeof(ad
));
2730 eval
= dbwrite(ut
, lastDumpAddr
, (char *)&d
, sizeof(d
));
2734 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
2743 SBUDB_MakeDumpAppended(struct rx_call
*call
, afs_int32 appendedDumpID
,
2744 afs_int32 initialDumpID
, afs_int32 startTapeSeq
)
2749 MakeDumpAppended(call
, appendedDumpID
, initialDumpID
, startTapeSeq
);
2750 osi_auditU(call
, BUDB_AppDmpEvent
, code
, AUD_LONG
, appendedDumpID
,
2756 MakeDumpAppended(struct rx_call
*call
, afs_int32 appendedDumpID
,
2757 afs_int32 initialDumpID
, afs_int32 startTapeSeq
)
2759 struct ubik_trans
*ut
;
2760 afs_int32 eval
, code
= 0;
2762 if (!callPermitted(call
))
2763 return BUDB_NOTPERMITTED
;
2765 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
2769 eval
= makeAppended(ut
, appendedDumpID
, initialDumpID
, startTapeSeq
);
2773 code
= ubik_EndTrans(ut
);
2777 ubik_AbortTrans(ut
);
2781 /* Find the last tape of a dump-set. This includes any appended dumps */
2783 SBUDB_FindLastTape(struct rx_call
*call
, afs_int32 dumpID
,
2784 struct budb_dumpEntry
*dumpEntry
,
2785 struct budb_tapeEntry
*tapeEntry
,
2786 struct budb_volumeEntry
*volEntry
)
2790 code
= FindLastTape(call
, dumpID
, dumpEntry
, tapeEntry
, volEntry
);
2791 osi_auditU(call
, BUDB_FndLTpeEvent
, code
, AUD_LONG
, dumpID
, AUD_END
);
2796 FindLastTape(struct rx_call
*call
, afs_int32 dumpID
,
2797 struct budb_dumpEntry
*dumpEntry
,
2798 struct budb_tapeEntry
*tapeEntry
,
2799 struct budb_volumeEntry
*volEntry
)
2801 struct ubik_trans
*ut
;
2805 dbadr lastTape
, thisTape
;
2806 afs_int32 lastTapeSeq
;
2807 struct volFragment vf
;
2808 dbadr lastVol
, thisVol
;
2809 afs_int32 lastVolPos
;
2810 afs_int32 eval
, code
= 0;
2812 if (!callPermitted(call
))
2813 return BUDB_NOTPERMITTED
;
2816 return (BUDB_BADARGUMENT
);
2818 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2822 /* find and read its initial dump via its id */
2823 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &dumpID
, &lastDump
, &d
);
2827 ABORT(BUDB_NODUMPID
);
2829 /* Follow the append dumps link chain until we reach the last dump */
2830 while (d
.appendedDumpChain
) {
2831 lastDump
= ntohl(d
.appendedDumpChain
);
2832 eval
= dbread(ut
, lastDump
, &d
, sizeof(d
));
2837 /* We now have the last dump of the last appended dump */
2838 /* Copy this into our return structure */
2839 eval
= FillDumpEntry(ut
, lastDump
, dumpEntry
);
2843 /* Fail if the last dump has no tapes */
2845 ABORT(BUDB_NOTAPENAME
);
2847 /* Follow the tapes in this dump until we reach the last tape */
2848 eval
= dbread(ut
, ntohl(d
.firstTape
), &t
, sizeof(t
));
2852 lastTape
= ntohl(d
.firstTape
);
2853 lastTapeSeq
= ntohl(t
.seq
);
2854 lastVol
= ntohl(t
.firstVol
);
2856 while (t
.nextTape
) {
2857 thisTape
= ntohl(t
.nextTape
);
2858 eval
= dbread(ut
, thisTape
, &t
, sizeof(t
));
2862 if (ntohl(t
.seq
) > lastTapeSeq
) {
2863 lastTape
= thisTape
;
2864 lastTapeSeq
= ntohl(t
.seq
);
2865 lastVol
= ntohl(t
.firstVol
);
2869 /* We now have the last tape of the last appended dump */
2870 /* Copy this into our return structure */
2871 eval
= FillTapeEntry(ut
, lastTape
, tapeEntry
);
2875 /* Zero volume entry if the last tape has no volumes */
2877 memset(volEntry
, 0, sizeof(*volEntry
));
2879 /* Follow the volumes until we reach the last volume */
2880 eval
= dbread(ut
, lastVol
, &vf
, sizeof(vf
));
2884 lastVolPos
= vf
.position
;
2886 while (vf
.sameTapeChain
) {
2887 thisVol
= ntohl(vf
.sameTapeChain
);
2888 eval
= dbread(ut
, thisVol
, &vf
, sizeof(vf
));
2892 if (vf
.position
> lastVolPos
) {
2894 lastVolPos
= vf
.position
;
2898 /* We now have the last volume of this tape */
2899 /* Copy this into our return structure */
2900 eval
= FillVolEntry(ut
, lastVol
, volEntry
);
2905 eval
= ubik_EndTrans(ut
);
2911 ubik_AbortTrans(ut
);
2917 SBUDB_GetTapes(struct rx_call
*call
,
2918 afs_int32 majorVersion
, /* version of interface structures */
2919 afs_int32 flags
, /* search & select controls */
2920 char *name
, /* s&s parameters */
2922 afs_int32 end
, /* reserved: MBZ */
2923 afs_int32 index
, /* start index of returned entries */
2924 afs_int32
*nextIndexP
, /* output index for next call */
2926 budb_tapeList
*tapes
) /* pointer to buffer */
2931 GetTapes(call
, majorVersion
, flags
, name
, start
, end
, index
,
2932 nextIndexP
, dbTimeP
, tapes
);
2933 osi_auditU(call
, BUDB_GetTpeEvent
, code
, AUD_END
);
2938 GetTapes(struct rx_call
*call
,
2939 afs_int32 majorVersion
, /* version of interface structures */
2940 afs_int32 flags
, /* search & select controls */
2941 char *name
, /* s&s parameters */
2943 afs_int32 end
, /* reserved: MBZ */
2944 afs_int32 index
, /* start index of returned entries */
2945 afs_int32
*nextIndexP
, /* output index for next call */
2947 budb_tapeList
*tapes
) /* pointer to buffer */
2949 struct ubik_trans
*ut
;
2953 afs_int32 nameFlags
, startFlags
, endFlags
, timeFlags
;
2954 struct returnList list
;
2955 afs_int32 eval
, code
= 0;
2958 if (!callPermitted(call
))
2959 return BUDB_NOTPERMITTED
;
2961 if (majorVersion
!= BUDB_MAJORVERSION
)
2962 return BUDB_OLDINTERFACE
;
2965 return BUDB_ENDOFLIST
;
2967 eval
= InitRPC(&ut
, LOCKREAD
, 1);
2971 nameFlags
= flags
& BUDB_OP_NAMES
;
2972 startFlags
= flags
& BUDB_OP_STARTS
;
2973 endFlags
= flags
& BUDB_OP_ENDS
;
2974 timeFlags
= flags
& BUDB_OP_TIMES
;
2976 InitReturnList(&list
);
2979 if (nameFlags
== BUDB_OP_TAPENAME
) { /*it */
2980 eval
= ht_LookupEntry(ut
, &db
.tapeName
, name
, &ta
, &t
);
2984 ABORT(BUDB_NOTAPENAME
);
2987 if ((startFlags
& ~BUDB_OP_DUMPID
) || endFlags
|| timeFlags
)
2988 ABORT(BUDB_BADFLAGS
);
2990 /* follow the hash chain to the end */
2992 if (startFlags
& BUDB_OP_DUMPID
) {
2993 /* read in the dump */
2994 eval
= dbread(ut
, ntohl(t
.dump
), &d
, sizeof(d
));
2998 /* check if both name and dump id match */
2999 if ((strcmp(name
, t
.name
) == 0) && (ntohl(d
.id
) == start
)) {
3000 eval
= AddToReturnList(&list
, ta
, &toskip
);
3001 if (eval
&& (eval
!= BUDB_LIST2BIG
))
3006 /* Add to return list and continue search */
3007 if (strcmp(name
, t
.name
) == 0) {
3008 eval
= AddToReturnList(&list
, ta
, &toskip
);
3009 if (eval
== BUDB_LIST2BIG
)
3016 ta
= ntohl(t
.nameHashChain
);
3018 dbread(ut
, ta
, &t
, sizeof(t
));
3021 else if (nameFlags
== BUDB_OP_TAPESEQ
) {
3022 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &start
, &da
, &d
);
3026 ABORT(BUDB_NODUMPNAME
);
3028 /* search for the right tape */
3029 ta
= ntohl(d
.firstTape
);
3030 for (ta
= ntohl(d
.firstTape
); ta
; ta
= ntohl(t
.nextTape
)) {
3031 eval
= dbread(ut
, ta
, &t
, sizeof(t
));
3035 if (ntohl(t
.seq
) == end
) {
3036 eval
= AddToReturnList(&list
, ta
, &toskip
);
3037 if (eval
&& (eval
!= BUDB_LIST2BIG
))
3043 ABORT(BUDB_BADFLAGS
);
3047 SendReturnList(ut
, &list
, FillTapeEntry
,
3048 sizeof(struct budb_tapeEntry
), index
, nextIndexP
,
3049 dbTimeP
, (returnList_t
) tapes
);
3053 FreeReturnList(&list
);
3054 code
= ubik_EndTrans(ut
);
3058 FreeReturnList(&list
);
3059 ubik_AbortTrans(ut
);
3064 * get a set of volumes according to the specified criteria.
3065 * See BUDB_GetDumps for general information on parameters
3066 * Currently supports:
3067 * 1) volume match - returns volumes based on volume name only.
3068 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
3069 * and start is a dumpid. Returns all volumes of the specified
3070 * name on the selected dumpid.
3074 SBUDB_GetVolumes(struct rx_call
*call
,
3075 afs_int32 majorVersion
, /* version of interface structures */
3076 afs_int32 flags
, /* search & select controls */
3077 char *name
, /* - parameters for search */
3078 afs_int32 start
, /* - usage depends which BUDP_OP */
3079 afs_int32 end
, /* - bits are set */
3080 afs_int32 index
, /* start index of returned entries */
3081 afs_int32
*nextIndexP
, /* output index for next call */
3083 budb_volumeList
*volumes
) /* pointer to buffer */
3088 GetVolumes(call
, majorVersion
, flags
, name
, start
, end
, index
,
3089 nextIndexP
, dbTimeP
, volumes
);
3090 osi_auditU(call
, BUDB_GetVolEvent
, code
, AUD_END
);
3095 GetVolumes(struct rx_call
*call
,
3096 afs_int32 majorVersion
, /* version of interface structures */
3097 afs_int32 flags
, /* search & select controls */
3098 char *name
, /* - parameters for search */
3099 afs_int32 start
, /* - usage depends which BUDP_OP_* */
3100 afs_int32 end
, /* - bits are set */
3101 afs_int32 index
, /* start index of returned entries */
3102 afs_int32
*nextIndexP
, /* output index for next call */
3104 budb_volumeList
*volumes
) /* pointer to buffer */
3106 struct ubik_trans
*ut
;
3109 afs_int32 nameFlags
, startFlags
, endFlags
, timeFlags
;
3110 afs_int32 eval
, code
= 0;
3111 struct returnList vollist
;
3114 /* Don't check permissions when we look up a specific volume name */
3115 if (((flags
& BUDB_OP_NAMES
) != BUDB_OP_VOLUMENAME
)
3116 && !callPermitted(call
))
3117 return BUDB_NOTPERMITTED
;
3119 if (majorVersion
!= BUDB_MAJORVERSION
)
3120 return BUDB_OLDINTERFACE
;
3122 return BUDB_ENDOFLIST
;
3124 eval
= InitRPC(&ut
, LOCKREAD
, 1);
3128 nameFlags
= flags
& BUDB_OP_NAMES
;
3129 startFlags
= flags
& BUDB_OP_STARTS
;
3130 endFlags
= flags
& BUDB_OP_ENDS
;
3131 timeFlags
= flags
& BUDB_OP_TIMES
;
3133 InitReturnList(&vollist
);
3136 /* lookup a the volume (specified by name) in the dump (specified by id) */
3137 if (nameFlags
== BUDB_OP_VOLUMENAME
) {
3138 /* dumpid permissible, all others off */
3139 if (((startFlags
& ~BUDB_OP_DUMPID
) != 0) || endFlags
|| timeFlags
)
3140 ABORT(BUDB_BADFLAGS
);
3142 /* returns ptr to volinfo of requested name */
3143 eval
= ht_LookupEntry(ut
, &db
.volName
, name
, &via
, &vi
);
3147 ABORT(BUDB_NOVOLUMENAME
);
3149 /* Iterate over all volume fragments with this name */
3151 struct volFragment v
;
3154 /* traverse all the volume fragments for this volume info structure */
3155 for (va
= vi
.firstFragment
; va
; va
= v
.sameNameChain
) {
3157 eval
= dbread(ut
, va
, &v
, sizeof(v
));
3161 if (startFlags
& BUDB_OP_DUMPID
) {
3165 /* get the dump id for this fragment */
3166 eval
= dbread(ut
, ntohl(v
.tape
), &atape
, sizeof(atape
));
3171 dbread(ut
, ntohl(atape
.dump
), &adump
, sizeof(adump
));
3175 /* dump id does not match */
3176 if (ntohl(adump
.id
) != start
)
3180 eval
= AddToReturnList(&vollist
, va
, &toskip
);
3181 if (eval
== BUDB_LIST2BIG
)
3186 if (eval
== BUDB_LIST2BIG
)
3189 via
= vi
.sameNameChain
;
3194 eval
= dbread(ut
, via
, &vi
, sizeof(vi
));
3198 } else if (((nameFlags
== 0) || (nameFlags
== BUDB_OP_TAPENAME
))
3199 && (startFlags
== BUDB_OP_DUMPID
)) {
3204 struct volFragment volFrag
;
3207 /* lookup all volumes for a specified dump id */
3209 /* no other flags should be set */
3210 if (endFlags
|| timeFlags
)
3211 ABORT(BUDB_BADFLAGS
);
3214 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &start
, &dumpAddr
, &dump
);
3218 /* traverse all the tapes */
3219 for (tapeAddr
= ntohl(dump
.firstTape
); tapeAddr
; tapeAddr
= ntohl(tape
.nextTape
)) { /*w */
3220 eval
= dbread(ut
, tapeAddr
, &tape
, sizeof(tape
));
3224 if ((nameFlags
!= BUDB_OP_TAPENAME
)
3225 || ((nameFlags
== BUDB_OP_TAPENAME
)
3226 && (strcmp(tape
.name
, name
) == 0))) {
3227 /* now return all the volumes */
3228 for (volFragAddr
= ntohl(tape
.firstVol
); volFragAddr
;
3229 volFragAddr
= ntohl(volFrag
.sameTapeChain
)) {
3230 eval
= dbread(ut
, volFragAddr
, &volFrag
, sizeof(volFrag
));
3234 eval
= AddToReturnList(&vollist
, volFragAddr
, &toskip
);
3235 if (eval
== BUDB_LIST2BIG
)
3241 if (eval
== BUDB_LIST2BIG
)
3245 ABORT(BUDB_BADFLAGS
);
3249 SendReturnList(ut
, &vollist
, FillVolEntry
,
3250 sizeof(struct budb_volumeEntry
), index
, nextIndexP
,
3251 dbTimeP
, (returnList_t
) volumes
);
3256 FreeReturnList(&vollist
);
3257 code
= ubik_EndTrans(ut
);
3261 FreeReturnList(&vollist
);
3262 ubik_AbortTrans(ut
);
3267 SBUDB_UseTape(struct rx_call
*call
,
3268 struct budb_tapeEntry
*tape
, /* tape info */
3269 afs_int32
*new) /* set if tape is new */
3273 code
= UseTape(call
, tape
, new);
3274 osi_auditU(call
, BUDB_UseTpeEvent
, code
, AUD_DATE
,
3275 (tape
? tape
->dump
: 0), AUD_END
);
3280 UseTape(struct rx_call
*call
,
3281 struct budb_tapeEntry
*tape
, /* tape info */
3282 int *new) /* set if tape is new */
3284 struct ubik_trans
*ut
;
3288 afs_int32 eval
, code
;
3290 if (!callPermitted(call
))
3291 return BUDB_NOTPERMITTED
;
3293 if (strlen(tape
->name
) >= sizeof(t
.name
))
3294 return BUDB_BADARGUMENT
;
3296 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
3302 memset(&t
, 0, sizeof(t
));
3303 eval
= AllocStructure(ut
, tape_BLOCK
, 0, &a
, &t
);
3307 strcpy(t
.name
, tape
->name
);
3309 eval
= ht_HashIn(ut
, &db
.tapeName
, a
, &t
);
3315 /* Since deleting a tape may change the dump (if its the same one), read in
3316 * the dump after the call to DeleteTape. */
3318 eval
= ht_LookupEntry(ut
, &db
.dumpIden
, &tape
->dump
, &da
, &d
);
3322 ABORT(BUDB_NODUMPID
);
3325 tape
->written
= time(0); /* fill in tape struct */
3326 t
.written
= htonl(tape
->written
);
3327 t
.expires
= htonl(tape
->expires
);
3329 t
.seq
= htonl(tape
->seq
);
3330 t
.useCount
= htonl(tape
->useCount
);
3331 t
.labelpos
= htonl(tape
->labelpos
);
3333 t
.flags
= htonl(tape
->flags
| BUDB_TAPE_BEINGWRITTEN
);
3335 t
.nextTape
= d
.firstTape
; /* Chain the tape to the dump */
3336 d
.firstTape
= htonl(a
);
3338 if (tape
->seq
>= ntohl(d
.tapes
.maxTapes
)) /* inc # tapes in the dump */
3339 d
.tapes
.maxTapes
= htonl(tape
->seq
);
3341 eval
= dbwrite(ut
, a
, &t
, sizeof(t
)); /* write tape struct */
3345 eval
= dbwrite(ut
, da
, &d
, sizeof(d
)); /* write the dump struct */
3349 eval
= set_header_word(ut
, lastUpdate
, htonl(time(0)));
3353 LogDebug(5, "added tape %s\n", tape
->name
);
3355 code
= ubik_EndTrans(ut
);
3359 ubik_AbortTrans(ut
);
3365 /* ---------------------------------------------
3366 * debug interface routines
3367 * ---------------------------------------------
3371 SBUDB_T_DumpHashTable(struct rx_call
*call
, afs_int32 type
, char *filename
)
3375 code
= T_DumpHashTable(call
, type
, filename
);
3376 osi_auditU(call
, BUDB_TDmpHaEvent
, code
, AUD_STR
, filename
, AUD_END
);
3381 T_DumpHashTable(struct rx_call
*call
, int type
, char *filename
)
3383 struct ubik_trans
*ut
;
3384 struct memoryHashTable
*mht
;
3386 afs_int32 eval
, code
= 0;
3393 char e
[sizeof(struct block
)]; /* unnecessarily conservative */
3396 struct volInfo e_volinfo
;
3400 if (!callPermitted(call
))
3401 return BUDB_NOTPERMITTED
;
3403 if (strlen(filename
) >= sizeof(path
) - 5)
3404 return BUDB_BADARGUMENT
;
3406 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
3410 if ((mht
= ht_GetType(type
, &e_size
)) == 0)
3411 return BUDB_BADARGUMENT
;
3413 sprintf(path
, "%s/%s", gettmpdir(), filename
);
3415 DUMP
= fopen(path
, "w");
3417 ABORT(BUDB_BADARGUMENT
);
3420 for (old
= 0;; old
++) {
3421 length
= (old
? mht
->oldLength
: mht
->length
);
3423 fprintf(DUMP
, "Dumping %sHash Table:\n", (old
? "Old " : ""));
3425 for (hash
= 0; hash
< length
; hash
++) {
3426 a
= ht_LookupBucket(ut
, mht
, hash
, old
);
3429 eval
= dbread(ut
, a
, e
, e_size
);
3435 fprintf(DUMP
, " in bucket %d at %d is ", hash
, a
);
3437 fprintf(DUMP
, " at %d is ", a
);
3439 case HT_dumpIden_FUNCTION
:
3440 memcpy(&e_dump
, e
, sizeof(e_dump
));
3441 fprintf(DUMP
, "%d\n", ntohl(e_dump
.id
));
3443 case HT_dumpName_FUNCTION
:
3444 memcpy(&e_dump
, e
, sizeof(e_dump
));
3445 fprintf(DUMP
, "%s\n", e_dump
.dumpName
);
3447 case HT_tapeName_FUNCTION
:
3448 memcpy(&e_tape
, e
, sizeof(e_tape
));
3449 fprintf(DUMP
, "%s\n", e_tape
.name
);
3451 case HT_volName_FUNCTION
:
3452 memcpy(&e_volinfo
, e
, sizeof(e_volinfo
));
3453 fprintf(DUMP
, "%s\n", e_volinfo
.name
);
3456 if ((ht_HashEntry(mht
, e
) % length
) != hash
)
3457 ABORT(BUDB_DATABASEINCONSISTENT
);
3458 a
= ntohl(*(dbadr
*) (e
+ mht
->threadOffset
));
3465 fprintf(DUMP
, "%d entries found\n", ent
);
3466 if (ntohl(mht
->ht
->entries
) != ent
)
3467 ABORT(BUDB_DATABASEINCONSISTENT
);
3469 code
= ubik_EndTrans(ut
);
3475 ubik_AbortTrans(ut
);
3482 SBUDB_T_GetVersion(struct rx_call
*call
, afs_int32
*majorVersion
)
3486 code
= T_GetVersion(call
, majorVersion
);
3487 osi_auditU(call
, BUDB_TGetVrEvent
, code
, AUD_END
);
3492 T_GetVersion(struct rx_call
*call
, int *majorVersion
)
3494 struct ubik_trans
*ut
;
3497 code
= InitRPC(&ut
, LOCKREAD
, 0);
3501 *majorVersion
= BUDB_MAJORVERSION
;
3503 code
= ubik_EndTrans(ut
);
3507 /* BUDB_T_DumpDatabase
3508 * dump as much of the database as possible int /tmp/<filename>
3512 SBUDB_T_DumpDatabase(struct rx_call
*call
, char *filename
)
3516 code
= T_DumpDatabase(call
, filename
);
3517 osi_auditU(call
, BUDB_TDmpDBEvent
, code
, AUD_STR
, filename
, AUD_END
);
3522 T_DumpDatabase(struct rx_call
*call
, char *filename
)
3526 struct ubik_trans
*ut
;
3529 int type
, old
, length
, hash
;
3530 struct memoryHashTable
*mht
;
3531 afs_int32 eval
, code
= 0;
3533 if (!callPermitted(call
))
3534 return BUDB_NOTPERMITTED
;
3536 length
= asprintf(&path
, "%s/%s", gettmpdir(), filename
);
3537 if (length
< 0 || !path
)
3538 return (BUDB_INTERNALERROR
);
3540 dumpfid
= fopen(path
, "w");
3542 return (BUDB_BADARGUMENT
);
3544 eval
= InitRPC(&ut
, LOCKWRITE
, 1);
3548 /* dump all items in the database */
3549 for (type
= 1; type
<= HT_MAX_FUNCTION
; type
++) { /*ft */
3550 mht
= ht_GetType(type
, &entrySize
);
3552 ERROR(BUDB_BADARGUMENT
);
3554 for (old
= 0; old
<= 1; old
++) { /*fo */
3555 length
= (old
? mht
->oldLength
: mht
->length
);
3559 fprintf(dumpfid
, "Dumping %s Hash Table:\n", (old
? "Old " : ""));
3561 for (hash
= 0; hash
< length
; hash
++) { /*f */
3562 dbAddr
= ht_LookupBucket(ut
, mht
, hash
, old
);
3564 while (dbAddr
) { /*w */
3565 switch (type
) { /*s */
3566 case HT_dumpIden_FUNCTION
:
3568 struct dump hostDump
, diskDump
;
3571 cdbread(ut
, dump_BLOCK
, dbAddr
, &diskDump
,
3577 "\ndumpId hash %d, entry at %u\n",
3580 "----------------------------\n");
3581 dump_ntoh(&diskDump
, &hostDump
);
3582 printDump(dumpfid
, &hostDump
);
3583 dbAddr
= hostDump
.idHashChain
;
3587 case HT_dumpName_FUNCTION
:
3589 struct dump hostDump
, diskDump
;
3592 cdbread(ut
, dump_BLOCK
, dbAddr
, &diskDump
,
3598 "\ndumpname hash %d, entry at %u\n",
3601 "----------------------------\n");
3602 dump_ntoh(&diskDump
, &hostDump
);
3603 printDump(dumpfid
, &hostDump
);
3604 dbAddr
= hostDump
.nameHashChain
;
3608 case HT_tapeName_FUNCTION
:
3610 struct tape hostTape
, diskTape
;
3613 cdbread(ut
, tape_BLOCK
, dbAddr
, &diskTape
,
3619 "\ntapename hash %d, entry at %u\n",
3622 "----------------------------\n");
3623 tape_ntoh(&diskTape
, &hostTape
);
3624 printTape(dumpfid
, &hostTape
);
3625 dbAddr
= hostTape
.nameHashChain
;
3629 case HT_volName_FUNCTION
:
3631 struct volInfo hostVolInfo
, diskVolInfo
;
3634 cdbread(ut
, volInfo_BLOCK
, dbAddr
,
3635 &diskVolInfo
, sizeof(diskVolInfo
));
3640 "\nvolname hash %d, entry at %u\n",
3643 "----------------------------\n");
3644 volInfo_ntoh(&diskVolInfo
, &hostVolInfo
);
3645 printVolInfo(dumpfid
, &hostVolInfo
);
3646 dbAddr
= hostVolInfo
.nameHashChain
;
3648 volFragsDump(ut
, dumpfid
,
3649 hostVolInfo
.firstFragment
);
3654 fprintf(dumpfid
, "unknown type %d\n", type
);
3664 code
= ubik_EndTrans(ut
); /* is this safe if no ut started ? */
3673 volFragsDump(struct ubik_trans
*ut
, FILE *dumpfid
, dbadr dbAddr
)
3675 struct volFragment hostVolFragment
, diskVolFragment
;
3680 cdbread(ut
, volFragment_BLOCK
, dbAddr
, &diskVolFragment
,
3681 sizeof(diskVolFragment
));
3682 if (code
) { /* don't be fussy about errors */
3683 fprintf(dumpfid
, "volFragsDump: Error reading database\n");
3687 fprintf(dumpfid
, "\nvolfragment entry at %u\n", dbAddr
);
3688 fprintf(dumpfid
, "----------------------------\n");
3689 volFragment_ntoh(&diskVolFragment
, &hostVolFragment
);
3690 printVolFragment(dumpfid
, &hostVolFragment
);
3691 dbAddr
= hostVolFragment
.sameNameChain
;
3697 /* utilities - network to host conversion
3698 * currently used for debug only
3702 volFragmentDiskToHost(struct volFragment
*diskVfPtr
,
3703 struct volFragment
*hostVfPtr
)
3705 hostVfPtr
->vol
= ntohl(diskVfPtr
->vol
);
3706 hostVfPtr
->sameNameChain
= ntohl(diskVfPtr
->sameNameChain
);
3707 hostVfPtr
->tape
= ntohl(diskVfPtr
->tape
);
3708 hostVfPtr
->sameTapeChain
= ntohl(diskVfPtr
->sameTapeChain
);
3709 hostVfPtr
->position
= ntohl(diskVfPtr
->position
);
3710 hostVfPtr
->clone
= ntohl(diskVfPtr
->clone
);
3711 hostVfPtr
->incTime
= ntohl(diskVfPtr
->incTime
);
3712 hostVfPtr
->startByte
= ntohl(diskVfPtr
->startByte
);
3713 hostVfPtr
->nBytes
= ntohl(diskVfPtr
->nBytes
);
3714 hostVfPtr
->flags
= ntohs(diskVfPtr
->flags
);
3715 hostVfPtr
->sequence
= ntohs(diskVfPtr
->sequence
);
3719 volInfoDiskToHost(struct volInfo
*diskViPtr
, struct volInfo
*hostViPtr
)
3721 strcpy(hostViPtr
->name
, diskViPtr
->name
);
3722 hostViPtr
->nameHashChain
= ntohl(diskViPtr
->nameHashChain
);
3723 hostViPtr
->id
= ntohl(diskViPtr
->id
);
3724 strcpy(hostViPtr
->server
, diskViPtr
->server
);
3725 hostViPtr
->partition
= ntohl(diskViPtr
->partition
);
3726 hostViPtr
->flags
= ntohl(diskViPtr
->flags
);
3727 hostViPtr
->sameNameHead
= ntohl(diskViPtr
->sameNameHead
);
3728 hostViPtr
->sameNameChain
= ntohl(diskViPtr
->sameNameChain
);
3729 hostViPtr
->firstFragment
= ntohl(diskViPtr
->firstFragment
);
3730 hostViPtr
->nFrags
= ntohl(diskViPtr
->nFrags
);
3734 tapeDiskToHost(struct tape
*diskTapePtr
, struct tape
*hostTapePtr
)
3736 strcpy(hostTapePtr
->name
, diskTapePtr
->name
);
3737 hostTapePtr
->nameHashChain
= ntohl(diskTapePtr
->nameHashChain
);
3738 hostTapePtr
->flags
= ntohl(diskTapePtr
->flags
);
3740 /* tape id conversion here */
3741 hostTapePtr
->written
= ntohl(diskTapePtr
->written
);
3742 hostTapePtr
->nBytes
= ntohl(diskTapePtr
->nBytes
);
3743 hostTapePtr
->nFiles
= ntohl(diskTapePtr
->nFiles
);
3744 hostTapePtr
->nVolumes
= ntohl(diskTapePtr
->nVolumes
);
3745 hostTapePtr
->seq
= ntohl(diskTapePtr
->seq
);
3746 hostTapePtr
->dump
= ntohl(diskTapePtr
->dump
);
3747 hostTapePtr
->nextTape
= ntohl(diskTapePtr
->nextTape
);
3748 hostTapePtr
->firstVol
= ntohl(diskTapePtr
->firstVol
);
3749 hostTapePtr
->useCount
= ntohl(diskTapePtr
->useCount
);
3753 dumpDiskToHost(struct dump
*diskDumpPtr
, struct dump
*hostDumpPtr
)
3755 hostDumpPtr
->id
= ntohl(diskDumpPtr
->id
);
3756 hostDumpPtr
->idHashChain
= ntohl(diskDumpPtr
->idHashChain
);
3757 strcpy(hostDumpPtr
->dumpName
, diskDumpPtr
->dumpName
);
3758 strcpy(hostDumpPtr
->dumpPath
, diskDumpPtr
->dumpPath
);
3759 strcpy(hostDumpPtr
->volumeSet
, diskDumpPtr
->volumeSet
);
3760 hostDumpPtr
->nameHashChain
= ntohl(diskDumpPtr
->nameHashChain
);
3761 hostDumpPtr
->flags
= ntohl(diskDumpPtr
->flags
);
3762 hostDumpPtr
->parent
= ntohl(diskDumpPtr
->parent
);
3763 hostDumpPtr
->created
= ntohl(diskDumpPtr
->created
);
3764 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3765 hostDumpPtr
->nVolumes
= ntohl(diskDumpPtr
->nVolumes
);
3767 /* tapeset conversion here */
3769 hostDumpPtr
->firstTape
= ntohl(diskDumpPtr
->firstTape
);
3771 /* principal conversion here */
3777 checkHash(struct ubik_trans
*ut
, int hashType
)
3779 struct memoryHashTable
*mhtPtr
;
3780 int entrySize
, hashTableLength
;
3785 mhtPtr
= ht_GetType(hashType
, &entrySize
);
3789 for (old
= 0; old
< 1; old
++) {
3790 LogDebug(5, "\nold = %d\n", old
);
3791 printMemoryHashTable(stdout
, mhtPtr
);
3793 hashTableLength
= (old
? mhtPtr
->oldLength
: mhtPtr
->length
);
3795 for (bucket
= 0; bucket
< hashTableLength
; bucket
++) {
3798 entryAddr
= ht_LookupBucket(ut
, mhtPtr
, bucket
, old
);
3799 while (entryAddr
!= 0) {
3800 LogDebug(6, "bucket %d has disk addr %d\n", bucket
,
3803 case HT_dumpIden_FUNCTION
:
3805 struct dump diskDump
, hostDump
;
3807 code
= dbread(ut
, entryAddr
, &diskDump
, entrySize
);
3811 dump_ntoh(&diskDump
, &hostDump
);
3812 printDump(stdout
, &hostDump
);
3813 entryAddr
= hostDump
.idHashChain
;
3817 case HT_dumpName_FUNCTION
:
3820 case HT_tapeName_FUNCTION
:
3823 case HT_volName_FUNCTION
:
3825 struct volInfo diskVolInfo
, hostVolInfo
;
3827 code
= dbread(ut
, entryAddr
, &diskVolInfo
, entrySize
);
3831 volInfo_ntoh(&diskVolInfo
, &hostVolInfo
);
3832 printVolInfo(stdout
, &hostVolInfo
);
3833 entryAddr
= hostVolInfo
.nameHashChain
;