Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / budb / procs.c
blob51f31026366395a15bf192b4527db323fdf79595
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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
8 */
10 /* TBD
11 * ht_lookupEntry - tape ids
12 * Truncate Tape - tape id's
13 * usetape - tape id's
16 #include <afsconfig.h>
17 #include <afs/param.h>
20 #ifdef AFS_NT40_ENV
21 #include <winsock2.h>
22 #else
23 #include <netinet/in.h>
24 #include <sys/file.h>
25 #include <sys/param.h>
26 #include <sys/time.h>
27 #include <sys/resource.h>
28 #endif
30 #include <string.h>
31 #include <sys/types.h>
32 #include <afs/stds.h>
33 #include <afs/bubasics.h>
34 #include <stdio.h>
35 #include <lock.h>
36 #include <ubik.h>
37 #include <lwp.h>
38 #include <rx/xdr.h>
39 #include <rx/rx.h>
40 #include <rx/rxkad.h>
41 #include <des.h>
42 #include <afs/cellconfig.h>
43 #include <afs/auth.h>
44 #include <errno.h>
45 #include "budb.h"
46 #include "budb_errs.h"
47 #include "database.h"
48 #include "budb_internal.h"
49 #include "error_macros.h"
50 #include "globals.h"
51 #include "afs/audit.h"
52 #include <afs/afsutil.h>
54 #undef min
55 #undef max
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,
81 afs_int32);
82 afs_int32 MakeDumpAppended(struct rx_call *, afs_int32, afs_int32,
83 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 *,
88 budb_tapeList *);
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
113 matter. */
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.
132 afs_int32
133 AwaitInitialization(void)
135 afs_int32 start = 0;
137 while (!procsInited) {
138 if (!start)
139 start = time(0);
140 else if (time(0) - start > 5)
141 return UNOQUORUM;
142 #ifdef AFS_PTHREAD_ENV
143 sleep(1);
144 #else
145 IOMGR_Sleep(1);
146 #endif
148 return 0;
151 /* tailCompPtr
152 * name is a pathname style name, determine trailing name and return
153 * pointer to it
156 char *
157 tailCompPtr(char *pathNamePtr)
159 char *ptr;
160 ptr = strrchr(pathNamePtr, '/');
161 if (ptr == 0) {
162 /* this should never happen */
163 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
164 pathNamePtr);
165 return (pathNamePtr);
166 } else
167 ptr++; /* skip the / */
168 return (ptr);
171 /* callPermitted
172 * Check to see if the caller is a SuperUser.
173 * exit:
174 * 0 - no
175 * 1 - yes
179 callPermitted(struct rx_call *call)
181 int permitted = 0;
182 struct afsconf_dir *acdir;
184 acdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
185 if (!acdir)
186 return 0;
188 if (afsconf_SuperUser(acdir, call, NULL))
189 permitted = 1;
191 if (acdir)
192 afsconf_Close(acdir);
193 return (permitted);
196 /* InitRPC
197 * This is called by every RPC interface to create a Ubik transaction
198 * and read the database header into core
199 * entry:
200 * ut
201 * lock
202 * this_op
203 * notes:
204 * sets a lock on byte 1 of the database. Looks like it enforces
205 * single threading by use of the lock.
208 afs_int32
209 InitRPC(struct ubik_trans **ut,
210 int lock, /* indicate read/write transaction */
211 int this_op) /* opcode of RCP, for COUNT_ABO */
213 int code;
214 float wait = 0.91; /* start waiting for 1 second */
216 start:
217 /* wait for server initialization to finish if this is not InitProcs calling */
218 if (this_op)
219 if ((code = AwaitInitialization()))
220 return code;
222 for (code = UNOQUORUM; code == UNOQUORUM;) {
223 code =
224 ubik_BeginTrans(BU_dbase,
225 ((lock ==
226 LOCKREAD) ? UBIK_READTRANS : UBIK_WRITETRANS),
227 ut);
228 if (code == UNOQUORUM) { /* no quorum elected */
229 if (wait < 1)
230 Log("Waiting for quorum election\n");
231 if (wait < 15.0)
232 wait *= 1.1;
233 #ifdef AFS_PTHREAD_ENV
234 sleep((int)wait);
235 #else
236 IOMGR_Sleep((int)wait);
237 #endif
240 if (code)
241 return code;
242 if (wait > 1)
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);
248 return code;
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");
258 return code;
260 if ((code = ubik_EndTrans(*ut))) {
261 LogError(code, "InitRPC: ubik_EndTrans failed\n");
262 return code;
264 goto start; /* now redo the read transaction */
266 } else {
267 if ((code = CheckInit(*ut, rebuildDatabase))) {
268 ubik_AbortTrans(*ut);
269 return code;
272 lastTrans = time(0);
273 return 0;
276 /* This is called to initialize a newly created database */
277 static int
278 initialize_database(struct ubik_trans *ut)
280 return 0;
283 static int noAuthenticationRequired; /* global state */
284 static int recheckNoAuth; /* global state */
286 afs_int32
287 InitProcs(void)
289 struct ubik_trans *ut;
290 afs_int32 code = 0;
292 procsInited = 0;
294 if ((globalConfPtr->myHost == 0) || (BU_conf == 0))
295 ERROR(BUDB_INTERNALERROR);
297 recheckNoAuth = 1;
299 if (globalConfPtr->debugFlags & DF_NOAUTH)
300 noAuthenticationRequired = 1;
302 if (globalConfPtr->debugFlags & DF_RECHECKNOAUTH)
303 recheckNoAuth = 0;
305 if (recheckNoAuth)
306 noAuthenticationRequired = afsconf_GetNoAuthFlag(BU_conf);
308 if (noAuthenticationRequired)
309 LogError(0, "Running server with security disabled\n");
311 InitDB();
313 rebuildDatabase = initialize_database;
315 if ((code = InitRPC(&ut, LOCKREAD, 0))) {
316 LogError(code, "InitProcs: InitRPC failed\n");
317 return code;
319 code = ubik_EndTrans(ut);
320 if (code) {
321 LogError(code, "InitProcs: ubik_EndTrans failed\n");
322 return code;
325 rebuildDatabase = 0; /* only do this during init */
326 procsInited = 1;
328 error_exit:
329 return (code);
332 struct returnList {
333 int nElements; /* number in list */
334 int allocSize; /* number of elements allocated */
335 dbadr *elements; /* array of addresses */
338 static void
339 InitReturnList(struct returnList *list)
341 list->nElements = 0;
342 list->allocSize = 0;
343 list->elements = (dbadr *) 0;
346 static void
347 FreeReturnList(struct returnList *list)
349 if (list->elements)
350 free(list->elements);
351 list->elements = (dbadr *) 0;
352 list->nElements = 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.
359 static afs_int32
360 AddToReturnList(struct returnList *list, dbadr a, afs_int32 *to_skipP)
362 char *tmp;
363 afs_int32 size;
365 if (a == 0)
366 return 0;
367 if (*to_skipP > 0) {
368 (*to_skipP)--;
369 return 0;
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) {
380 size = 10;
381 tmp = (char *)malloc(sizeof(dbadr) * size);
382 } else {
383 size = list->allocSize + 10;
384 tmp = (char *)realloc(list->elements, sizeof(dbadr) * size);
386 if (!tmp)
387 return BUDB_NOMEM;
388 list->elements = (dbadr *) tmp;
389 list->allocSize = size;
392 list->elements[list->nElements] = a;
393 list->nElements++;
394 return 0;
397 afs_int32
398 FillVolEntry(struct ubik_trans *ut, dbadr va, void *rock)
400 struct budb_volumeEntry *vol = (struct budb_volumeEntry *) rock;
401 struct dump d;
402 struct tape t;
403 struct volInfo vi;
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);
431 return 0;
434 afs_int32
435 FillDumpEntry(struct ubik_trans *ut, dbadr da, void *rock)
437 struct budb_dumpEntry *dump = (struct budb_dumpEntry *)rock;
438 struct dump d, ad;
440 if (dbread(ut, da, &d, sizeof(d)))
441 return BUDB_IO;
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)))
466 return BUDB_IO;
467 dump->appendedDumpID = ntohl(ad.id);
468 } else
469 dump->appendedDumpID = 0;
471 /* printf("dump name %s, parent %d, level %d\n",
472 * d.dumpName, ntohl(d.parent), ntohl(d.level)); */
474 return 0;
477 afs_int32
478 FillTapeEntry(struct ubik_trans *ut, dbadr ta, void *rock)
480 struct budb_tapeEntry *tape=(struct budb_tapeEntry *) rock;
481 struct tape t;
482 struct dump d;
483 afs_int32 code;
485 if (dbread(ut, ta, &t, sizeof(t)))
486 return BUDB_IO;
488 /* Get the tape's expiration date */
489 if ((code = getExpiration(ut, &t)))
490 return (code);
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)))
506 return BUDB_IO;
507 tape->dump = ntohl(d.id);
508 return 0;
511 #define returnList_t budb_dumpList *
513 /* SendReturnList
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.
519 static afs_int32
520 SendReturnList(struct ubik_trans *ut,
521 struct returnList *list, /* list of elements to return */
522 afs_int32(*FillProc) (struct ubik_trans *, dbadr da,
523 void *),
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.) */
531 afs_int32 code;
532 int to_return;
533 int i;
534 char *e;
536 *nextIndexP = -1;
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)
553 return (BUDB_NOMEM);
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);
561 if (code)
562 return code;
565 if (list->nElements > i)
566 *nextIndexP = index + i;
567 return 0;
570 /* Come here to delete a volInfo structure. */
572 static afs_int32
573 DeleteVolInfo(struct ubik_trans *ut, dbadr via, struct volInfo *vi)
575 afs_int32 code;
576 dbadr hvia;
577 struct volInfo hvi;
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);
586 if (code)
587 return code;
588 code = FreeStructure(ut, volInfo_BLOCK, via);
589 return code;
591 hvia = ntohl(vi->sameNameHead);
592 if (dbread(ut, hvia, &hvi, sizeof(hvi)))
593 return BUDB_IO;
594 code =
595 RemoveFromList(ut, hvia, &hvi, &hvi.sameNameChain, via, vi,
596 &vi->sameNameChain);
597 if (code == -1)
598 return BUDB_DATABASEINCONSISTENT;
599 if (code == 0)
600 code = FreeStructure(ut, volInfo_BLOCK, via);
601 return code;
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
606 write it out. */
608 static afs_int32
609 DeleteVolFragment(struct ubik_trans *ut, dbadr va, struct volFragment *v)
611 afs_int32 code;
612 struct volInfo vi;
613 dbadr via;
615 via = ntohl(v->vol);
616 if (dbread(ut, via, &vi, sizeof(vi)))
617 return BUDB_IO;
618 code =
619 RemoveFromList(ut, via, &vi, &vi.firstFragment, va, v,
620 &v->sameNameChain);
621 if (code == -1)
622 return BUDB_DATABASEINCONSISTENT;
623 if (code)
624 return code;
625 if (vi.firstFragment == 0)
626 if ((code = DeleteVolInfo(ut, via, &vi)))
627 return code;
628 if ((code = FreeStructure(ut, volFragment_BLOCK, va)))
629 return code;
631 /* decrement frag counter */
632 code =
633 set_word_addr(ut, via, &vi, &vi.nFrags, htonl(ntohl(vi.nFrags) - 1));
634 if (code)
635 return code;
636 return 0;
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. */
643 static afs_int32
644 DeleteTape(struct ubik_trans *ut, dbadr ta, struct tape *t)
646 afs_int32 code;
647 struct dump d;
648 dbadr da;
650 da = ntohl(t->dump);
651 if (da == 0)
652 return BUDB_DATABASEINCONSISTENT;
653 if (dbread(ut, da, &d, sizeof(d)))
654 return BUDB_IO;
655 if (d.firstTape == 0)
656 return BUDB_DATABASEINCONSISTENT;
658 code = RemoveFromList(ut, da, &d, &d.firstTape, ta, t, &t->nextTape);
659 if (code == -1)
660 return BUDB_DATABASEINCONSISTENT;
661 if (code)
662 return code;
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;
669 return 0;
672 static afs_int32
673 DeleteDump(struct ubik_trans *ut, dbadr da, struct dump *d)
675 afs_int32 code = 0;
677 code = ht_HashOut(ut, &db.dumpIden, da, d);
678 if (code)
679 ERROR(code);
681 code = ht_HashOut(ut, &db.dumpName, da, d);
682 if (code)
683 ERROR(code);
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);
690 if (code)
691 ERROR(code);
693 error_exit:
694 return code;
698 * VolInfoMatch()
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).
709 static int
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) */
720 * GetVolInfo()
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.
727 static afs_int32
728 GetVolInfo(struct ubik_trans *ut, struct budb_volumeEntry *volP, dbadr *viaP,
729 struct volInfo *viP)
731 dbadr hvia, via;
732 struct volInfo hvi;
733 afs_int32 eval, code = 0;
735 eval = ht_LookupEntry(ut, &db.volName, volP->name, &via, viP);
736 if (eval)
737 ERROR(eval);
739 if (!via) {
740 /* allocate a new volinfo structure */
741 eval = AllocStructure(ut, volInfo_BLOCK, 0, &via, viP);
742 if (eval)
743 ERROR(eval);
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;
750 viP->nFrags = 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);
757 if (eval)
758 ERROR(eval);
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));
771 if (eval)
772 ERROR(eval);
774 if (VolInfoMatch(volP, viP))
775 break; /* found the one */
778 /* if the correct volinfo struct isn't found, create one */
779 if (!via) {
780 eval = AllocStructure(ut, volInfo_BLOCK, 0, &via, viP);
781 if (eval)
782 ERROR(eval);
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;
790 viP->nFrags = 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 */
796 eval =
797 set_word_addr(ut, hvia, &hvi, &hvi.sameNameChain, htonl(via));
798 if (eval)
799 ERROR(eval);
803 *viaP = via;
805 error_exit:
806 return code;
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).
814 * entry:
815 * maxvolumestodelete - don't delete more than this many volumes
818 afs_int32
819 deleteSomeVolumesFromTape(struct ubik_trans *ut, dbadr tapeAddr,
820 struct tape *tapePtr, int maxVolumesToDelete)
822 dbadr volFragAddr, nextVolFragAddr, dumpAddr;
823 struct volFragment volFrag;
824 struct dump dump;
825 int volumesDeleted = 0;
826 afs_int32 eval, code = 0;
828 if (!tapePtr)
829 ERROR(0);
831 for (volFragAddr = ntohl(tapePtr->firstVol);
832 (volFragAddr && (maxVolumesToDelete > 0));
833 volFragAddr = nextVolFragAddr) {
834 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
835 if (eval)
836 ERROR(eval);
838 nextVolFragAddr = ntohl(volFrag.sameTapeChain);
840 eval = DeleteVolFragment(ut, volFragAddr, &volFrag);
841 if (eval)
842 ERROR(eval);
844 maxVolumesToDelete--;
845 volumesDeleted++;
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));
855 if (eval)
856 ERROR(eval);
858 /* diminish the dump's volume count */
859 dumpAddr = ntohl(tapePtr->dump);
860 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
861 if (eval)
862 ERROR(eval);
864 dump.nVolumes = htonl(ntohl(dump.nVolumes) - volumesDeleted);
865 eval = dbwrite(ut, dumpAddr, &dump, sizeof(dump));
866 if (eval)
867 ERROR(eval);
869 error_exit:
870 return (code);
873 /* deleteDump
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.
881 * entry:
882 * id - id of dump to delete
885 afs_int32
886 deleteDump(struct rx_call *call, dumpId id, budb_dumpsList *dumps)
888 struct ubik_trans *ut;
889 dbadr dumpAddr, tapeAddr, appendedDump;
890 struct dump dump;
891 struct tape tape;
892 dumpId dumpid;
893 afs_int32 eval, code = 0;
894 int partialDel = 0;
896 /* iterate until the dump is truly deleted */
898 dumpid = id;
899 while (dumpid) {
900 partialDel = 0;
901 while (1) {
902 eval = InitRPC(&ut, LOCKWRITE, 1);
903 if (eval)
904 ERROR(eval); /* can't start transaction */
906 eval =
907 ht_LookupEntry(ut, &db.dumpIden, &dumpid, &dumpAddr, &dump);
908 if (eval)
909 ABORT(eval);
910 if (!dumpAddr)
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);
917 if (tapeAddr == 0)
918 break;
920 /* there is a tape to delete */
921 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
922 if (eval)
923 ABORT(eval);
925 if (ntohl(tape.nVolumes)) {
926 /* tape is not empty */
927 eval = deleteSomeVolumesFromTape(ut, tapeAddr, &tape, 10);
928 if (eval)
929 ABORT(eval);
932 if (ntohl(tape.nVolumes) == 0) {
933 /* tape is now empty, delete it */
934 eval = DeleteTape(ut, tapeAddr, &tape);
935 if (eval)
936 ABORT(eval);
937 eval = ht_HashOut(ut, &db.tapeName, tapeAddr, &tape);
938 if (eval)
939 ABORT(eval);
940 eval = FreeStructure(ut, tape_BLOCK, tapeAddr);
941 if (eval)
942 ABORT(eval);
945 eval = ubik_EndTrans(ut);
946 if (eval)
947 ERROR(eval);
948 partialDel = 1;
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));
956 else
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)
963 ABORT(BUDB_NOMEM);
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);
973 if (eval)
974 ABORT(eval);
976 /* Now delete the appended dump too */
977 if (appendedDump) {
978 eval = dbread(ut, appendedDump, &dump, sizeof(dump));
979 if (eval)
980 ABORT(eval);
982 dumpid = ntohl(dump.id);
983 } else
984 dumpid = 0;
986 eval = ubik_EndTrans(ut);
987 if (eval)
988 ERROR(eval);
990 Log("Delete dump %s (DumpID %u), path %s\n", dump.dumpName,
991 ntohl(dump.id), dump.dumpPath);
994 error_exit:
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);
999 return (code);
1001 abort_exit:
1002 ubik_AbortTrans(ut);
1003 goto error_exit;
1006 /* --------------
1007 * dump selection routines - used by BUDB_GetDumps
1008 * --------------
1011 /* most recent dump selection */
1013 struct chosenDump {
1014 struct chosenDump *next;
1015 dbadr addr;
1016 afs_uint32 date;
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)
1037 return (1);
1039 /* got the number we need, select based on date */
1040 if ((afs_uint32) ntohl(dumpPtr->created) > rockPtr->chain->date)
1041 return (1);
1043 return (0);
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));
1057 if (!ptr)
1058 return (0);
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;
1068 free(deletedPtr);
1069 rockPtr->ndumps--;
1072 /* now insert in the right place */
1073 for (nextPtr = &rockPtr->chain; *nextPtr; nextPtr = &((*nextPtr)->next)) {
1074 if (ptr->date < (*nextPtr)->date)
1075 break;
1077 ptr->next = *nextPtr;
1078 *nextPtr = ptr;
1079 rockPtr->ndumps++;
1081 return (0);
1085 /* ---------------------------------------------
1086 * general interface routines - alphabetic
1087 * ---------------------------------------------
1090 afs_int32
1091 SBUDB_AddVolume(struct rx_call *call, struct budb_volumeEntry *vol)
1093 afs_int32 code;
1095 code = AddVolume(call, vol);
1096 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, (vol ? vol->id : 0),
1097 AUD_END);
1098 return code;
1101 afs_int32
1102 AddVolume(struct rx_call *call, struct budb_volumeEntry *vol)
1104 struct ubik_trans *ut;
1105 dbadr da, ta, via, va;
1106 struct dump d;
1107 struct tape t;
1108 struct volInfo vi;
1109 struct volFragment v;
1110 afs_uint32 bytes;
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);
1122 if (eval)
1123 return eval;
1125 /* Find the dump in dumpid hash table */
1126 eval = ht_LookupEntry(ut, &db.dumpIden, &vol->dump, &da, &d);
1127 if (eval)
1128 ABORT(eval);
1129 if (!da)
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));
1136 if (eval)
1137 ABORT(eval);
1139 /* Check if the right tape name */
1140 if (strcmp(t.name, vol->tape) == 0)
1141 break;
1143 if (!ta)
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);
1153 if (eval)
1154 ABORT(eval);
1156 /* Create a volume fragment */
1157 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1158 if (eval)
1159 ABORT(eval);
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 */
1167 if (eval)
1168 ABORT(eval);
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 */
1179 if (eval)
1180 ABORT(eval);
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 */
1185 if (eval)
1186 ABORT(eval);
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 */
1197 if (eval)
1198 ABORT(eval);
1200 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1201 if (eval)
1202 ABORT(eval);
1204 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1206 code = ubik_EndTrans(ut);
1207 return code;
1209 abort_exit:
1210 ubik_AbortTrans(ut);
1211 return code;
1215 afs_int32
1216 SBUDB_AddVolumes(struct rx_call *call, struct budb_volumeList *vols)
1218 afs_int32 code;
1220 code = AddVolumes(call, vols);
1221 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, 0, AUD_END);
1222 return code;
1225 afs_int32
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;
1231 struct dump d;
1232 struct tape t;
1233 struct volInfo vi;
1234 struct volFragment v;
1235 afs_uint32 bytes;
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);
1249 if (eval)
1250 return eval;
1252 /* Find the dump in dumpid hash table */
1253 eval = ht_LookupEntry(ut, &db.dumpIden, &vol1->dump, &da, &d);
1254 if (eval)
1255 ABORT(eval);
1256 if (!da)
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));
1263 if (eval)
1264 ABORT(eval);
1266 /* Check if the right tape name */
1267 if (strcmp(t.name, vol1->tape) == 0)
1268 break;
1270 if (!ta)
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++) {
1279 /*v */
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);
1285 continue;
1288 /* find or create a volume info structure */
1289 eval = GetVolInfo(ut, vol, &via, &vi);
1290 if (eval)
1291 ABORT(eval);
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);
1299 if (eval)
1300 ABORT(eval);
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 */
1307 if (eval)
1308 ABORT(eval);
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 */
1329 if (eval)
1330 ABORT(eval);
1332 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1333 } /*v */
1335 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1336 if (eval)
1337 ABORT(eval);
1339 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1340 if (eval)
1341 ABORT(eval);
1343 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1344 if (eval)
1345 ABORT(eval);
1347 code = ubik_EndTrans(ut);
1348 return code;
1350 abort_exit:
1351 ubik_AbortTrans(ut);
1352 return code;
1356 /* BUDB_CreateDump
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.
1359 * TBD
1360 * 1) record the volume set
1363 afs_int32
1364 SBUDB_CreateDump(struct rx_call *call, struct budb_dumpEntry *dump)
1366 afs_int32 code;
1368 code = CreateDump(call, dump);
1369 osi_auditU(call, BUDB_CrDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
1370 AUD_END);
1371 if (dump && !code) {
1372 Log("Create dump %s (DumpID %u), path %s\n", dump->name, dump->id,
1373 dump->dumpPath);
1375 return code;
1378 afs_int32
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;
1386 rxkad_level level;
1387 afs_int32 kvno;
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);
1398 if (eval)
1399 return eval;
1401 eval =
1402 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration,
1403 principal.name, principal.instance,
1404 principal.cell, &kvno);
1406 if (eval) {
1407 if (eval != RXKADNOAUTH)
1408 ABORT(eval);
1410 strcpy(principal.name, "");
1411 strcpy(principal.instance, "");
1412 strcpy(principal.cell, "");
1413 expiration = 0;
1414 } else {
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 */
1430 if (!dump->id) {
1431 while (1) { /* allocate a unique dump id *//*w */
1432 dump->id = time(0);
1434 /* ensure it is unique - seach for dumpid in hash table */
1435 eval =
1436 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1437 &findDump);
1438 if (eval)
1439 ABORT(eval);
1441 if (!findDumpAddr) { /* dumpid not in use */
1442 /* update the last dump id allocated */
1443 eval = set_header_word(ut, lastDumpId, htonl(dump->id));
1444 if (eval)
1445 ABORT(eval);
1446 break;
1449 /* dump id is in use - wait a while */
1450 #ifdef AFS_PTHREAD_ENV
1451 sleep(1);
1452 #else
1453 IOMGR_Sleep(1);
1454 #endif
1455 } /*w */
1456 } else {
1457 /* dump id supplied (e.g. for database restore) */
1458 eval =
1459 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1460 &findDump);
1461 if (eval)
1462 ABORT(eval);
1464 /* Dump id must not already exist */
1465 if (findDumpAddr)
1466 ABORT(BUDB_DUMPIDEXISTS);
1469 /* Allocate a dump structure */
1470 memset(&d, 0, sizeof(d));
1471 eval = AllocStructure(ut, dump_BLOCK, 0, &da, &d);
1472 if (eval)
1473 ABORT(eval);
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 */
1496 if (eval)
1497 ABORT(eval);
1499 eval = ht_HashIn(ut, &db.dumpIden, da, &d); /* Into dumpid hash table */
1500 if (eval)
1501 ABORT(eval);
1503 eval = dbwrite(ut, da, (char *)&d, sizeof(d)); /* Write the dump structure */
1504 if (eval)
1505 ABORT(eval);
1507 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1508 if (eval)
1509 ABORT(eval);
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);
1513 if (eval)
1514 ABORT(eval);
1516 code = ubik_EndTrans(ut);
1517 LogDebug(5, "made dump %s, path %s\n", d.dumpName, d.dumpPath);
1518 return code;
1520 abort_exit:
1521 ubik_AbortTrans(ut);
1522 return code;
1525 afs_int32
1526 SBUDB_DeleteDump(struct rx_call *call, dumpId id, Date fromTime, Date toTime,
1527 budb_dumpsList *dumps)
1529 afs_int32 code;
1531 code = DoDeleteDump(call, id, fromTime, toTime, dumps);
1532 osi_auditU(call, BUDB_DelDmpEvent, code, AUD_DATE, id, AUD_END);
1533 return code;
1536 #define MAXOFFS 30
1538 afs_int32
1539 DoDeleteDump(struct rx_call *call, dumpId id, Date fromTime, Date toTime,
1540 budb_dumpsList *dumps)
1542 afs_int32 code = 0;
1544 if (!callPermitted(call))
1545 return BUDB_NOTPERMITTED;
1547 if (id)
1548 code = deleteDump(call, id, dumps);
1549 return (code);
1552 afs_int32
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)
1557 afs_int32 code;
1559 code = ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags);
1560 osi_auditU(call, BUDB_LstDmpEvent, code, AUD_LONG, flags, AUD_END);
1561 return code;
1564 afs_int32
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);
1581 if (eval)
1582 return (eval);
1584 /* Search the database */
1585 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
1586 if (!mht)
1587 return (BUDB_BADARGUMENT);
1589 for (old = 0; old <= 1; old++) { /*o *//* old and new hash tables */
1590 length = (old ? mht->oldLength : mht->length);
1591 if (length == 0)
1592 continue;
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));
1599 if (eval)
1600 ABORT(eval);
1602 /* Skip appended dumps */
1603 if (ntohl(diskDump.initialDumpID) != 0) {
1604 continue;
1607 /* Skip dumps with different goup id */
1608 if ((sflags & BUDB_OP_GROUPID)
1609 && (ntohl(diskDump.tapes.id) != groupid)) {
1610 continue; /*nope */
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)) {
1618 eval =
1619 dbread(ut, dbAppAddr, &appDiskDump,
1620 sizeof(appDiskDump));
1621 if (eval)
1622 ABORT(eval);
1624 if ((ntohl(appDiskDump.id) < fromTime)
1625 || (ntohl(appDiskDump.id) > toTime))
1626 break; /*nope */
1628 if (dbAppAddr)
1629 continue; /*nope */
1632 /* Add it and each of its appended dump to our list to return */
1633 for (dbAppAddr = dbAddr; dbAppAddr;
1634 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1635 eval =
1636 dbread(ut, dbAppAddr, &appDiskDump,
1637 sizeof(appDiskDump));
1638 if (eval)
1639 ABORT(eval);
1641 /* Make sure we have space to list it */
1642 if (dumps->budb_dumpsList_len >= count) {
1643 count += 10;
1644 if (count == 10) {
1645 dumps->budb_dumpsList_val =
1646 (afs_int32 *) malloc(count *
1647 sizeof(afs_int32));
1648 flags->budb_dumpsList_val =
1649 (afs_int32 *) malloc(count *
1650 sizeof(afs_int32));
1651 } else {
1652 dumps->budb_dumpsList_val =
1653 (afs_int32 *) realloc(dumps->
1654 budb_dumpsList_val,
1655 count *
1656 sizeof(afs_int32));
1657 flags->budb_dumpsList_val =
1658 (afs_int32 *) realloc(flags->
1659 budb_dumpsList_val,
1660 count *
1661 sizeof(afs_int32));
1663 if (!dumps->budb_dumpsList_val
1664 || !dumps->budb_dumpsList_val)
1665 ABORT(BUDB_NOMEM);
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] |=
1675 BUDB_OP_APPDUMP;
1677 if (strcmp(appDiskDump.dumpName, DUMP_TAPE_NAME) == 0) {
1678 flags->budb_dumpsList_val[flags->
1679 budb_dumpsList_len] |=
1680 BUDB_OP_DBDUMP;
1682 dumps->budb_dumpsList_len++;
1683 flags->budb_dumpsList_len++;
1685 } /*d */
1686 } /*h */
1687 } /*o */
1689 code = ubik_EndTrans(ut);
1690 return (code);
1692 abort_exit:
1693 ubik_AbortTrans(ut);
1694 return (code);
1697 afs_int32
1698 SBUDB_DeleteTape(struct rx_call *call,
1699 struct budb_tapeEntry *tape) /* tape info */
1701 afs_int32 code;
1703 code = DoDeleteTape(call, tape);
1704 osi_auditU(call, BUDB_DelTpeEvent, code, AUD_DATE,
1705 (tape ? tape->dump : 0), AUD_END);
1706 return code;
1709 afs_int32
1710 DoDeleteTape(struct rx_call *call,
1711 struct budb_tapeEntry *tape) /* tape info */
1713 struct ubik_trans *ut;
1714 struct tape t;
1715 dbadr a;
1716 afs_int32 eval, code;
1718 if (!callPermitted(call))
1719 return BUDB_NOTPERMITTED;
1721 eval = InitRPC(&ut, LOCKWRITE, 1);
1722 if (eval)
1723 return eval;
1725 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
1726 if (eval)
1727 ABORT(eval);
1729 eval = DeleteTape(ut, a, &t);
1730 if (eval)
1731 ABORT(eval);
1733 eval = FreeStructure(ut, tape_BLOCK, a);
1734 if (eval)
1735 ABORT(eval);
1737 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1738 if (eval)
1739 ABORT(eval);
1741 code = ubik_EndTrans(ut);
1742 return code;
1744 abort_exit:
1745 ubik_AbortTrans(ut);
1746 return code;
1749 /* BUDB_DeleteVDP
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.
1754 * entry:
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
1758 * exit:
1759 * 0 - ok
1760 * n - some error. May or may not have deleted information.
1763 afs_int32
1764 SBUDB_DeleteVDP(struct rx_call *call, char *dsname, char *dumpPath,
1765 afs_int32 curDumpId)
1767 afs_int32 code;
1769 code = DeleteVDP(call, dsname, dumpPath, curDumpId);
1770 osi_auditU(call, BUDB_DelVDPEvent, code, AUD_STR, dsname, AUD_END);
1771 return code;
1774 afs_int32
1775 DeleteVDP(struct rx_call *call, char *dsname, char *dumpPath,
1776 afs_int32 curDumpId)
1778 struct dump dump;
1779 dbadr dumpAddr;
1781 struct ubik_trans *ut;
1782 afs_int32 eval, code = 0;
1784 if (!callPermitted(call))
1785 return BUDB_NOTPERMITTED;
1787 while (1) {
1788 eval = InitRPC(&ut, LOCKREAD, 1);
1789 if (eval)
1790 return (eval);
1792 eval = ht_LookupEntry(ut, &db.dumpName, dsname, &dumpAddr, &dump);
1793 if (eval)
1794 ABORT(eval);
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);
1801 if (eval)
1802 return (eval);
1804 eval = deleteDump(call, ntohl(dump.id), 0);
1805 if (eval)
1806 return (eval);
1808 /* start the traversal over since the various chains may
1809 * have changed
1811 break;
1814 dumpAddr = ntohl(dump.nameHashChain);
1815 if (dumpAddr) {
1816 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
1817 if (eval)
1818 ABORT(eval);
1820 } /*wd */
1822 /* check if all the dumps have been examined - can terminate */
1823 if (!dumpAddr) {
1824 eval = ubik_EndTrans(ut);
1825 return (eval);
1829 abort_exit:
1830 ubik_AbortTrans(ut);
1831 return (code);
1834 /* BUDB_FindClone
1835 * notes:
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.
1845 afs_int32
1846 SBUDB_FindClone(struct rx_call *call, afs_int32 dumpID, char *volName,
1847 afs_int32 *clonetime)
1849 afs_int32 code;
1851 code = FindClone(call, dumpID, volName, clonetime);
1852 osi_auditU(call, BUDB_FndClnEvent, code, AUD_STR, volName, AUD_END);
1853 return code;
1856 afs_int32
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;
1862 struct dump d;
1863 struct tape t;
1864 struct volFragment vf;
1865 struct volInfo vi;
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);
1873 if (eval)
1874 return (eval);
1876 *clonetime = 0;
1878 /* Search for the volume by name */
1879 eval = ht_LookupEntry(ut, &db.volName, volName, &hvia, &vi);
1880 if (eval)
1881 ABORT(eval);
1882 if (!hvia)
1883 ABORT(BUDB_NOVOLUMENAME);
1884 rvi = 0;
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);
1890 if (eval)
1891 ABORT(eval);
1892 if (!da)
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));
1899 if (eval)
1900 ABORT(eval);
1902 rvi = 1;
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 */
1907 if (eval)
1908 ABORT(eval);
1910 eval = dbread(ut, ntohl(vf.tape), &t, sizeof(t)); /* Read the tape */
1911 if (eval)
1912 ABORT(eval);
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 */
1917 ERROR(0);
1919 } /*vfa */
1920 } /*via */
1921 } /*d */
1923 error_exit:
1924 code = ubik_EndTrans(ut);
1925 return (code);
1927 abort_exit:
1928 ubik_EndTrans(ut);
1929 return (code);
1932 #ifdef notdef
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.
1939 afs_int32
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;
1945 struct dump dump;
1946 struct tape tape;
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);
1955 if (eval)
1956 return (eval);
1958 *clonetime = 0;
1960 for (; dumpID; dumpID = ntohl(dump.parent)) { /*d */
1961 /* Get the dump entry */
1962 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &diskAddr, &dump);
1963 if (eval)
1964 ABORT(eval);
1965 if (!diskAddr)
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,
1971 ntohl(dump.id));
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));
1979 if (eval)
1980 ABORT(eval);
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 */
1985 eval =
1986 dbread(ut, volFragmentAddr, &volFragment,
1987 sizeof(volFragment));
1988 if (eval)
1989 ABORT(eval);
1991 /* Get the volume info entry */
1992 eval =
1993 dbread(ut, ntohl(volFragment.vol), &volInfo,
1994 sizeof(volInfo));
1995 if (eval)
1996 ABORT(eval);
1998 /* check if this volume is the one we want */
1999 if (strcmp(volInfo.name, volName) == 0) {
2000 *clonetime = ntohl(volFragment.clone);
2001 ERROR(0);
2003 } /*vf */
2004 } /*t */
2005 } /*d */
2007 error_exit:
2008 code = ubik_EndTrans(ut);
2009 return (code);
2011 abort_exit:
2012 ubik_EndTrans(ut);
2013 return (code);
2015 #endif
2017 /* BUDB_FindDump
2018 * Find latest volume dump before adate.
2019 * Used by restore code when restoring a user requested volume(s)
2020 * entry:
2021 * volumeName - name of volume to match on
2022 * beforeDate - look for dumps older than this date
2023 * exit:
2024 * deptr - descriptor of most recent dump
2027 afs_int32
2028 SBUDB_FindDump(struct rx_call *call, char *volumeName, afs_int32 beforeDate,
2029 struct budb_dumpEntry *deptr)
2031 afs_int32 code;
2033 code = FindDump(call, volumeName, beforeDate, deptr);
2034 osi_auditU(call, BUDB_FndDmpEvent, code, AUD_STR, volumeName, AUD_END);
2035 return code;
2038 afs_int32
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;
2044 struct tape tape;
2045 struct volInfo volInfo;
2046 struct volFragment volFragment;
2048 dbadr selectedDumpAddr = 0;
2049 afs_int32 selectedDate = 0;
2050 afs_int32 volCloned;
2051 int rvoli;
2052 afs_int32 eval, code = 0;
2054 if (!callPermitted(call))
2055 return BUDB_NOTPERMITTED;
2057 eval = InitRPC(&ut, LOCKREAD, 1);
2058 if (eval)
2059 return eval;
2061 /* Find volinfo struct for volume name in hash table */
2062 eval =
2063 ht_LookupEntry(ut, &db.volName, volumeName, &volInfoAddr, &volInfo);
2064 if (eval)
2065 ABORT(eval);
2066 if (!volInfoAddr)
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));
2076 if (eval)
2077 ABORT(eval);
2080 /* step through the volfrag structures */
2081 for (volFragmentAddr = ntohl(volInfo.firstFragment); volFragmentAddr;
2082 volFragmentAddr = ntohl(volFragment.sameNameChain)) {
2083 /* read the volfrag struct */
2084 eval =
2085 dbread(ut, volFragmentAddr, &volFragment,
2086 sizeof(volFragment));
2087 if (eval)
2088 ABORT(eval);
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 */
2095 eval =
2096 dbread(ut, ntohl(volFragment.tape), &tape, sizeof(tape));
2097 if (eval)
2098 ABORT(eval);
2100 selectedDate = volCloned;
2101 selectedDumpAddr = ntohl(tape.dump);
2106 if (!selectedDumpAddr)
2107 ABORT(BUDB_NOENT);
2109 eval = FillDumpEntry(ut, selectedDumpAddr, deptr);
2110 if (eval)
2111 ABORT(eval);
2113 code = ubik_EndTrans(ut);
2114 return (code);
2116 abort_exit:
2117 ubik_EndTrans(ut);
2118 return (code);
2121 /* BUDB_FindLatestDump
2122 * Find the latest dump of volumeset vsname with dump name dname.
2123 * entry:
2124 * vsname - volumeset name
2125 * dname - dumpname
2128 afs_int32
2129 SBUDB_FindLatestDump(struct rx_call *call, char *vsname, char *dumpPath,
2130 struct budb_dumpEntry *dumpentry)
2132 afs_int32 code;
2134 code = FindLatestDump(call, vsname, dumpPath, dumpentry);
2135 osi_auditU(call, BUDB_FndLaDEvent, code, AUD_STR, vsname, AUD_END);
2136 return code;
2139 afs_int32
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;
2145 struct dump d;
2146 Date latest;
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);
2154 if (eval)
2155 return (eval);
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;
2164 int entrySize;
2165 dbadr dbAddr;
2166 afs_uint32 bestDumpId = 0;
2168 level = atoi(dumpPath);
2169 if (level < 0) {
2170 ABORT(BUDB_BADARGUMENT);
2173 /* Brute force search of all the dumps in the database - yuck! */
2175 retdbaddr = 0;
2176 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
2177 if (!mht)
2178 ABORT(BUDB_BADARGUMENT);
2180 for (old = 0; old <= 1; old++) { /*fo */
2181 length = (old ? mht->oldLength : mht->length);
2182 if (!length)
2183 continue;
2185 for (hash = 0; hash < length; hash++) {
2186 /*f */
2187 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr;
2188 dbAddr = hostDump.idHashChain) {
2189 /*w */
2190 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
2191 if (eval)
2192 ABORT(eval);
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;
2199 retdbaddr = dbAddr;
2201 } /*w */
2202 } /*f */
2203 } /*fo */
2204 if (!retdbaddr)
2205 ABORT(BUDB_NODUMPNAME);
2207 goto finished;
2208 } else {
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);
2222 if (eval)
2223 ABORT(eval);
2225 latest = 0;
2226 retdbaddr = 0;
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));
2233 if (eval)
2234 ABORT(eval);
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;
2244 if (!retdbaddr)
2245 ABORT(BUDB_NODUMPNAME);
2247 finished:
2248 /* return the dump found */
2249 FillDumpEntry(ut, retdbaddr, dumpentry);
2251 code = ubik_EndTrans(ut);
2252 return (code);
2254 abort_exit:
2255 ubik_AbortTrans(ut);
2256 return (code);
2260 afs_int32
2261 SBUDB_FinishDump(struct rx_call *call, struct budb_dumpEntry *dump)
2263 afs_int32 code;
2265 code = FinishDump(call, dump);
2266 osi_auditU(call, BUDB_FinDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
2267 AUD_END);
2268 return code;
2271 afs_int32
2272 FinishDump(struct rx_call *call, struct budb_dumpEntry *dump)
2274 struct ubik_trans *ut;
2275 dbadr a;
2276 struct dump d;
2277 afs_int32 eval, code = 0;
2279 if (!callPermitted(call))
2280 return BUDB_NOTPERMITTED;
2282 eval = InitRPC(&ut, LOCKWRITE, 1);
2283 if (eval)
2284 return eval;
2286 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &a, &d);
2287 if (eval)
2288 ABORT(eval);
2289 if (!a)
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 */
2298 if (dump->created)
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));
2304 if (eval)
2305 ABORT(eval);
2307 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2308 if (eval)
2309 ABORT(eval);
2311 code = ubik_EndTrans(ut);
2312 return code;
2314 abort_exit:
2315 ubik_AbortTrans(ut);
2316 return code;
2319 afs_int32
2320 SBUDB_FinishTape(struct rx_call *call, struct budb_tapeEntry *tape)
2322 afs_int32 code;
2324 code = FinishTape(call, tape);
2325 osi_auditU(call, BUDB_FinTpeEvent, code, AUD_DATE,
2326 (tape ? tape->dump : 0), AUD_END);
2327 return code;
2330 afs_int32
2331 FinishTape(struct rx_call *call, struct budb_tapeEntry *tape)
2333 struct ubik_trans *ut;
2334 dbadr a;
2335 struct tape t;
2336 struct dump d;
2337 afs_int32 eval, code = 0;
2339 if (!callPermitted(call))
2340 return BUDB_NOTPERMITTED;
2342 eval = InitRPC(&ut, LOCKWRITE, 1);
2343 if (eval)
2344 return eval;
2346 /* find the tape struct in the tapename hash chain */
2347 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
2348 if (eval)
2349 ABORT(eval);
2350 if (!a)
2351 ABORT(BUDB_NOTAPENAME);
2353 /* Read the dump structure */
2354 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2355 if (eval)
2356 ABORT(eval);
2358 /* search for the right tape on the rest of the chain */
2359 while (ntohl(d.id) != tape->dump) {
2360 a = ntohl(t.nameHashChain);
2361 if (!a)
2362 ABORT(BUDB_NOTAPENAME);
2364 eval = dbread(ut, a, &t, sizeof(t));
2365 if (eval)
2366 ABORT(eval);
2368 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2369 if (eval)
2370 ABORT(eval);
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));
2382 if (eval)
2383 ABORT(BUDB_IO);
2385 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2386 if (eval)
2387 ABORT(eval);
2389 code = ubik_EndTrans(ut);
2390 return code;
2392 abort_exit:
2393 ubik_AbortTrans(ut);
2394 return code;
2397 /* BUDB_GetDumps
2398 * return a set of dumps that match the specified criteria
2399 * entry:
2400 * call - rx call
2401 * majorVersion - version of interface structures. Permits compatibility
2402 * checks to be made
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
2406 * end
2407 * index
2408 * nextIndexP
2409 * dbTimeP
2410 * exit:
2411 * nextIndexP
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
2416 * notes:
2417 * currently supported are:
2418 * BUDB_OP_DUMPNAME
2419 * BUDB_OP_DUMPID
2422 afs_int32
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 */
2427 afs_int32 start,
2428 afs_int32 end,
2429 afs_int32 index, /* start index of returned entries */
2430 afs_int32 *nextIndexP, /* output index for next call */
2431 afs_int32 *dbTimeP,
2432 budb_dumpList *dumps) /* pointer to buffer */
2434 afs_int32 code;
2436 code =
2437 GetDumps(call, majorVersion, flags, name, start, end, index,
2438 nextIndexP, dbTimeP, dumps);
2439 osi_auditU(call, BUDB_GetDmpEvent, code, AUD_END);
2440 return code;
2443 afs_int32
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 */
2448 afs_int32 start,
2449 afs_int32 end,
2450 afs_int32 index, /* start index of returned entries */
2451 afs_int32 *nextIndexP, /* output index for next call */
2452 afs_int32 *dbTimeP,
2453 budb_dumpList *dumps) /* pointer to buffer */
2455 struct ubik_trans *ut;
2456 dbadr da;
2457 struct dump d;
2458 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2459 afs_int32 eval, code = 0;
2460 afs_int32 toskip;
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;
2469 if (index < 0)
2470 return BUDB_ENDOFLIST;
2472 eval = InitRPC(&ut, LOCKREAD, 1);
2473 if (eval)
2474 return eval;
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);
2482 toskip = index;
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);
2490 if (eval)
2491 ABORT(eval);
2492 if (!da)
2493 ABORT(BUDB_NODUMPNAME);
2495 while (1) {
2496 if (strcmp(d.dumpName, name) == 0) {
2497 eval = AddToReturnList(&list, da, &toskip);
2498 if (eval == BUDB_LIST2BIG)
2499 break;
2500 if (eval)
2501 ABORT(eval);
2504 da = ntohl(d.nameHashChain); /* get next dump w/ name */
2505 if (!da)
2506 break;
2508 eval = dbread(ut, da, &d, sizeof(d));
2509 if (eval)
2510 ABORT(eval);
2512 } else if (nameFlags == BUDB_OP_VOLUMENAME) {
2513 #ifdef PA
2514 struct volInfo vi;
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
2525 * time
2528 /* get us a volInfo for name */
2529 eval = ht_LookupEntry(ut, &db.volName, name, &da, &vi);
2530 if (eval)
2531 ABORT(eval);
2533 while (1) {
2534 /* now iterate over all the entries of this name */
2535 for (va = vi.firstFragment; va != 0; va = v.sameNameChain) {
2536 va = ntohl(va);
2537 eval = dbread(ut, va, &v, sizeof(v));
2538 if (eval)
2539 ABORT(eval);
2541 if date
2542 on fragment > date ignore it - too recent;
2544 if (date on fragment < date && date on fragment > bestfound)
2545 bestfound = date on fragment;
2547 } /* for va */
2549 da = vi.sameNameChain;
2550 if (da == 0)
2551 break;
2552 da = ntohl(da);
2553 eval = dbread(ut, da, &vi, sizeof(vi));
2554 if (eval)
2555 ABORT(eval);
2559 if nothing found
2560 return error
2562 from saved volfragment address, compute dump.
2563 otherwise, return dump found
2566 #endif /* PA */
2568 } else if (startFlags == BUDB_OP_DUMPID) {
2569 if (endFlags || timeFlags)
2570 ABORT(BUDB_BADFLAGS);
2571 if (nameFlags)
2572 ABORT(BUDB_BADFLAGS); /* NYI */
2574 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
2575 if (eval)
2576 ABORT(eval);
2577 if (!da)
2578 ABORT(BUDB_NODUMPID);
2580 eval = AddToReturnList(&list, da, &toskip);
2581 if (eval)
2582 ABORT(eval);
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 */
2590 if (!end)
2591 ABORT(BUDB_BADFLAGS);
2593 memset(&rock, 0, sizeof(rock));
2594 rock.maxDumps = end;
2596 scanHashTable(ut, &db.dumpName, wantDump, rememberDump,
2597 (char *)&rock);
2599 for (ptr = rock.chain; ptr; ptr = nextPtr) {
2600 nextPtr = ptr->next;
2601 AddToReturnList(&list, ptr->addr, &toskip); /* ignore error for free */
2602 free(ptr);
2604 } else {
2605 ABORT(BUDB_BADFLAGS);
2608 eval =
2609 SendReturnList(ut, &list, FillDumpEntry,
2610 sizeof(struct budb_dumpEntry), index, nextIndexP,
2611 dbTimeP, (returnList_t) dumps);
2612 if (eval)
2613 ABORT(eval);
2615 FreeReturnList(&list);
2616 code = ubik_EndTrans(ut);
2617 return code;
2619 abort_exit:
2620 FreeReturnList(&list);
2621 ubik_AbortTrans(ut);
2622 return code;
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.
2630 afs_int32
2631 getExpiration(struct ubik_trans *ut, struct tape *tapePtr)
2633 dbadr ad;
2634 struct dump d;
2635 struct tape t;
2636 afs_int32 initDump;
2637 afs_int32 eval, code = 0;
2639 if (!tapePtr)
2640 ERROR(0);
2642 /* Get the dump for this tape */
2643 ad = ntohl(tapePtr->dump);
2644 eval = dbread(ut, ad, &d, sizeof(d));
2645 if (eval)
2646 ERROR(eval);
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);
2652 if (eval)
2653 ERROR(eval);
2656 /* Cycle through the dumps and appended dumps */
2657 while (ad) {
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));
2661 if (eval)
2662 ERROR(eval);
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));
2671 if (eval)
2672 ERROR(eval);
2676 error_exit:
2677 return (code);
2680 /* Mark the following dump as appended to another, intial dump */
2681 afs_int32
2682 makeAppended(struct ubik_trans *ut, afs_int32 appendedDumpID,
2683 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2685 dbadr ada, da, lastDumpAddr;
2686 struct dump ad, d;
2687 afs_int32 eval, code = 0;
2689 if (!initialDumpID)
2690 ERROR(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);
2697 if (eval)
2698 ERROR(eval);
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);
2714 if (eval)
2715 ERROR(eval);
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.
2723 lastDumpAddr = da;
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));
2729 if (eval)
2730 ERROR(eval);
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));
2741 if (eval)
2742 ERROR(eval);
2744 eval = dbwrite(ut, lastDumpAddr, (char *)&d, sizeof(d));
2745 if (eval)
2746 ERROR(eval);
2748 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2749 if (eval)
2750 ERROR(eval);
2752 error_exit:
2753 return (code);
2756 afs_int32
2757 SBUDB_MakeDumpAppended(struct rx_call *call, afs_int32 appendedDumpID,
2758 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2760 afs_int32 code;
2762 code =
2763 MakeDumpAppended(call, appendedDumpID, initialDumpID, startTapeSeq);
2764 osi_auditU(call, BUDB_AppDmpEvent, code, AUD_LONG, appendedDumpID,
2765 AUD_END);
2766 return code;
2769 afs_int32
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);
2780 if (eval)
2781 return (eval);
2783 eval = makeAppended(ut, appendedDumpID, initialDumpID, startTapeSeq);
2784 if (eval)
2785 ABORT(eval);
2787 code = ubik_EndTrans(ut);
2788 return (code);
2790 abort_exit:
2791 ubik_AbortTrans(ut);
2792 return (code);
2795 /* Find the last tape of a dump-set. This includes any appended dumps */
2796 afs_int32
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)
2802 afs_int32 code;
2804 code = FindLastTape(call, dumpID, dumpEntry, tapeEntry, volEntry);
2805 osi_auditU(call, BUDB_FndLTpeEvent, code, AUD_LONG, dumpID, AUD_END);
2806 return code;
2809 afs_int32
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;
2816 struct dump d;
2817 dbadr lastDump;
2818 struct tape t;
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;
2829 if (!dumpID)
2830 return (BUDB_BADARGUMENT);
2832 eval = InitRPC(&ut, LOCKREAD, 1);
2833 if (eval)
2834 return (eval);
2836 /* find and read its initial dump via its id */
2837 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &lastDump, &d);
2838 if (eval)
2839 ABORT(eval);
2840 if (!lastDump)
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));
2847 if (eval)
2848 ABORT(eval);
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);
2854 if (eval)
2855 ABORT(eval);
2857 /* Fail if the last dump has no tapes */
2858 if (!d.firstTape)
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));
2863 if (eval)
2864 ABORT(eval);
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));
2873 if (eval)
2874 ABORT(eval);
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);
2886 if (eval)
2887 ABORT(eval);
2889 /* Zero volume entry if the last tape has no volumes */
2890 if (!lastVol) {
2891 memset(volEntry, 0, sizeof(*volEntry));
2892 } else {
2893 /* Follow the volumes until we reach the last volume */
2894 eval = dbread(ut, lastVol, &vf, sizeof(vf));
2895 if (eval)
2896 ABORT(eval);
2898 lastVolPos = vf.position;
2900 while (vf.sameTapeChain) {
2901 thisVol = ntohl(vf.sameTapeChain);
2902 eval = dbread(ut, thisVol, &vf, sizeof(vf));
2903 if (eval)
2904 ABORT(eval);
2906 if (vf.position > lastVolPos) {
2907 lastVol = thisVol;
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);
2915 if (eval)
2916 ABORT(eval);
2919 eval = ubik_EndTrans(ut);
2920 if (!code)
2921 code = eval;
2922 return (code);
2924 abort_exit:
2925 ubik_AbortTrans(ut);
2926 return (code);
2930 afs_int32
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 */
2935 afs_int32 start,
2936 afs_int32 end, /* reserved: MBZ */
2937 afs_int32 index, /* start index of returned entries */
2938 afs_int32 *nextIndexP, /* output index for next call */
2939 afs_int32 *dbTimeP,
2940 budb_tapeList *tapes) /* pointer to buffer */
2942 afs_int32 code;
2944 code =
2945 GetTapes(call, majorVersion, flags, name, start, end, index,
2946 nextIndexP, dbTimeP, tapes);
2947 osi_auditU(call, BUDB_GetTpeEvent, code, AUD_END);
2948 return code;
2951 afs_int32
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 */
2956 afs_int32 start,
2957 afs_int32 end, /* reserved: MBZ */
2958 afs_int32 index, /* start index of returned entries */
2959 afs_int32 *nextIndexP, /* output index for next call */
2960 afs_int32 *dbTimeP,
2961 budb_tapeList *tapes) /* pointer to buffer */
2963 struct ubik_trans *ut;
2964 dbadr da, ta;
2965 struct dump d;
2966 struct tape t;
2967 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2968 struct returnList list;
2969 afs_int32 eval, code = 0;
2970 afs_int32 toskip;
2972 if (!callPermitted(call))
2973 return BUDB_NOTPERMITTED;
2975 if (majorVersion != BUDB_MAJORVERSION)
2976 return BUDB_OLDINTERFACE;
2978 if (index < 0)
2979 return BUDB_ENDOFLIST;
2981 eval = InitRPC(&ut, LOCKREAD, 1);
2982 if (eval)
2983 return eval;
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);
2991 toskip = index;
2993 if (nameFlags == BUDB_OP_TAPENAME) { /*it */
2994 eval = ht_LookupEntry(ut, &db.tapeName, name, &ta, &t);
2995 if (eval)
2996 ABORT(eval);
2997 if (!ta)
2998 ABORT(BUDB_NOTAPENAME);
3000 /* NYI */
3001 if ((startFlags & ~BUDB_OP_DUMPID) || endFlags || timeFlags)
3002 ABORT(BUDB_BADFLAGS);
3004 /* follow the hash chain to the end */
3005 while (ta) { /*w */
3006 if (startFlags & BUDB_OP_DUMPID) {
3007 /* read in the dump */
3008 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
3009 if (eval)
3010 ABORT(eval);
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))
3016 ABORT(eval);
3017 break;
3019 } else {
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)
3024 break;
3025 if (eval)
3026 ABORT(eval);
3030 ta = ntohl(t.nameHashChain);
3031 if (ta)
3032 dbread(ut, ta, &t, sizeof(t));
3033 } /*w */
3034 } /*it */
3035 else if (nameFlags == BUDB_OP_TAPESEQ) {
3036 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
3037 if (eval)
3038 ABORT(eval);
3039 if (!da)
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));
3046 if (eval)
3047 ABORT(eval);
3049 if (ntohl(t.seq) == end) {
3050 eval = AddToReturnList(&list, ta, &toskip);
3051 if (eval && (eval != BUDB_LIST2BIG))
3052 ABORT(eval);
3053 break;
3056 } else {
3057 ABORT(BUDB_BADFLAGS);
3060 eval =
3061 SendReturnList(ut, &list, FillTapeEntry,
3062 sizeof(struct budb_tapeEntry), index, nextIndexP,
3063 dbTimeP, (returnList_t) tapes);
3064 if (eval)
3065 ABORT(eval);
3067 FreeReturnList(&list);
3068 code = ubik_EndTrans(ut);
3069 return code;
3071 abort_exit:
3072 FreeReturnList(&list);
3073 ubik_AbortTrans(ut);
3074 return (code);
3077 /* BUDB_GetVolumes
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.
3087 afs_int32
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 */
3096 afs_int32 *dbTimeP,
3097 budb_volumeList *volumes) /* pointer to buffer */
3099 afs_int32 code;
3101 code =
3102 GetVolumes(call, majorVersion, flags, name, start, end, index,
3103 nextIndexP, dbTimeP, volumes);
3104 osi_auditU(call, BUDB_GetVolEvent, code, AUD_END);
3105 return code;
3108 afs_int32
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 */
3117 afs_int32 *dbTimeP,
3118 budb_volumeList *volumes) /* pointer to buffer */
3120 struct ubik_trans *ut;
3121 dbadr via;
3122 struct volInfo vi;
3123 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
3124 afs_int32 eval, code = 0;
3125 struct returnList vollist;
3126 afs_int32 toskip;
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;
3135 if (index < 0)
3136 return BUDB_ENDOFLIST;
3138 eval = InitRPC(&ut, LOCKREAD, 1);
3139 if (eval)
3140 return eval;
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);
3148 toskip = index;
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);
3158 if (eval)
3159 ABORT(eval);
3160 if (!via)
3161 ABORT(BUDB_NOVOLUMENAME);
3163 /* Iterate over all volume fragments with this name */
3164 while (1) {
3165 struct volFragment v;
3166 afs_int32 va;
3168 /* traverse all the volume fragments for this volume info structure */
3169 for (va = vi.firstFragment; va; va = v.sameNameChain) {
3170 va = ntohl(va);
3171 eval = dbread(ut, va, &v, sizeof(v));
3172 if (eval)
3173 ABORT(eval);
3175 if (startFlags & BUDB_OP_DUMPID) {
3176 struct tape atape;
3177 struct dump adump;
3179 /* get the dump id for this fragment */
3180 eval = dbread(ut, ntohl(v.tape), &atape, sizeof(atape));
3181 if (eval)
3182 ABORT(eval);
3184 eval =
3185 dbread(ut, ntohl(atape.dump), &adump, sizeof(adump));
3186 if (eval)
3187 ABORT(BUDB_IO);
3189 /* dump id does not match */
3190 if (ntohl(adump.id) != start)
3191 continue;
3194 eval = AddToReturnList(&vollist, va, &toskip);
3195 if (eval == BUDB_LIST2BIG)
3196 break;
3197 if (eval)
3198 ABORT(eval);
3200 if (eval == BUDB_LIST2BIG)
3201 break;
3203 via = vi.sameNameChain;
3204 if (via == 0)
3205 break;
3206 via = ntohl(via);
3208 eval = dbread(ut, via, &vi, sizeof(vi));
3209 if (eval)
3210 ABORT(eval);
3212 } else if (((nameFlags == 0) || (nameFlags == BUDB_OP_TAPENAME))
3213 && (startFlags == BUDB_OP_DUMPID)) {
3214 struct dump dump;
3215 dbadr dumpAddr;
3216 struct tape tape;
3217 dbadr tapeAddr;
3218 struct volFragment volFrag;
3219 dbadr volFragAddr;
3221 /* lookup all volumes for a specified dump id */
3223 /* no other flags should be set */
3224 if (endFlags || timeFlags)
3225 ABORT(BUDB_BADFLAGS);
3227 /* find the dump */
3228 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &dumpAddr, &dump);
3229 if (eval)
3230 ABORT(eval);
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));
3235 if (eval)
3236 ABORT(eval);
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));
3245 if (eval)
3246 ABORT(eval);
3248 eval = AddToReturnList(&vollist, volFragAddr, &toskip);
3249 if (eval == BUDB_LIST2BIG)
3250 break;
3251 if (eval)
3252 ABORT(eval);
3255 if (eval == BUDB_LIST2BIG)
3256 break;
3257 } /*w */
3258 } else {
3259 ABORT(BUDB_BADFLAGS);
3262 eval =
3263 SendReturnList(ut, &vollist, FillVolEntry,
3264 sizeof(struct budb_volumeEntry), index, nextIndexP,
3265 dbTimeP, (returnList_t) volumes);
3266 if (eval)
3267 ABORT(eval);
3269 /* error_exit: */
3270 FreeReturnList(&vollist);
3271 code = ubik_EndTrans(ut);
3272 return code;
3274 abort_exit:
3275 FreeReturnList(&vollist);
3276 ubik_AbortTrans(ut);
3277 return code;
3280 afs_int32
3281 SBUDB_UseTape(struct rx_call *call,
3282 struct budb_tapeEntry *tape, /* tape info */
3283 afs_int32 *new) /* set if tape is new */
3285 afs_int32 code;
3287 code = UseTape(call, tape, new);
3288 osi_auditU(call, BUDB_UseTpeEvent, code, AUD_DATE,
3289 (tape ? tape->dump : 0), AUD_END);
3290 return code;
3293 afs_int32
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;
3299 dbadr da, a;
3300 struct dump d;
3301 struct tape t;
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);
3311 if (eval)
3312 return eval;
3314 *new = 0;
3316 memset(&t, 0, sizeof(t));
3317 eval = AllocStructure(ut, tape_BLOCK, 0, &a, &t);
3318 if (eval)
3319 ABORT(eval);
3321 strcpy(t.name, tape->name);
3323 eval = ht_HashIn(ut, &db.tapeName, a, &t);
3324 if (eval)
3325 ABORT(eval);
3327 *new = 1;
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);
3333 if (eval)
3334 ABORT(eval);
3335 if (!da)
3336 ABORT(BUDB_NODUMPID);
3338 if (!tape->written)
3339 tape->written = time(0); /* fill in tape struct */
3340 t.written = htonl(tape->written);
3341 t.expires = htonl(tape->expires);
3342 t.dump = htonl(da);
3343 t.seq = htonl(tape->seq);
3344 t.useCount = htonl(tape->useCount);
3345 t.labelpos = htonl(tape->labelpos);
3346 t.useKBytes = 0;
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 */
3356 if (eval)
3357 ABORT(eval);
3359 eval = dbwrite(ut, da, &d, sizeof(d)); /* write the dump struct */
3360 if (eval)
3361 ABORT(eval);
3363 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
3364 if (eval)
3365 ABORT(eval);
3367 LogDebug(5, "added tape %s\n", tape->name);
3369 code = ubik_EndTrans(ut);
3370 return code;
3372 abort_exit:
3373 ubik_AbortTrans(ut);
3374 return code;
3379 /* ---------------------------------------------
3380 * debug interface routines
3381 * ---------------------------------------------
3384 afs_int32
3385 SBUDB_T_DumpHashTable(struct rx_call *call, afs_int32 type, char *filename)
3387 afs_int32 code;
3389 code = T_DumpHashTable(call, type, filename);
3390 osi_auditU(call, BUDB_TDmpHaEvent, code, AUD_STR, filename, AUD_END);
3391 return code;
3394 afs_int32
3395 T_DumpHashTable(struct rx_call *call, int type, char *filename)
3397 struct ubik_trans *ut;
3398 struct memoryHashTable *mht;
3399 int ent;
3400 afs_int32 eval, code = 0;
3401 char path[64];
3402 FILE *DUMP;
3404 int length;
3405 afs_uint32 hash;
3406 dbadr a, first_a;
3407 char e[sizeof(struct block)]; /* unnecessarily conservative */
3408 struct dump e_dump;
3409 struct tape e_tape;
3410 struct volInfo e_volinfo;
3411 int e_size;
3412 int old;
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);
3421 if (eval)
3422 return eval;
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");
3430 if (!DUMP)
3431 ABORT(BUDB_BADARGUMENT);
3433 ent = 0;
3434 for (old = 0;; old++) {
3435 length = (old ? mht->oldLength : mht->length);
3436 if (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);
3441 first_a = a;
3442 while (a) {
3443 eval = dbread(ut, a, e, e_size);
3444 if (eval)
3445 ABORT(eval);
3447 ent++;
3448 if (a == first_a)
3449 fprintf(DUMP, " in bucket %d at %d is ", hash, a);
3450 else
3451 fprintf(DUMP, " at %d is ", a);
3452 switch (type) {
3453 case HT_dumpIden_FUNCTION:
3454 memcpy(&e_dump, e, sizeof(e_dump));
3455 fprintf(DUMP, "%d\n", ntohl(e_dump.id));
3456 break;
3457 case HT_dumpName_FUNCTION:
3458 memcpy(&e_dump, e, sizeof(e_dump));
3459 fprintf(DUMP, "%s\n", e_dump.dumpName);
3460 break;
3461 case HT_tapeName_FUNCTION:
3462 memcpy(&e_tape, e, sizeof(e_tape));
3463 fprintf(DUMP, "%s\n", e_tape.name);
3464 break;
3465 case HT_volName_FUNCTION:
3466 memcpy(&e_volinfo, e, sizeof(e_volinfo));
3467 fprintf(DUMP, "%s\n", e_volinfo.name);
3468 break;
3470 if ((ht_HashEntry(mht, e) % length) != hash)
3471 ABORT(BUDB_DATABASEINCONSISTENT);
3472 a = ntohl(*(dbadr *) (e + mht->threadOffset));
3475 if (old)
3476 break;
3479 fprintf(DUMP, "%d entries found\n", ent);
3480 if (ntohl(mht->ht->entries) != ent)
3481 ABORT(BUDB_DATABASEINCONSISTENT);
3483 code = ubik_EndTrans(ut);
3484 if (DUMP)
3485 fclose(DUMP);
3486 return code;
3488 abort_exit:
3489 ubik_AbortTrans(ut);
3490 if (DUMP)
3491 fclose(DUMP);
3492 return code;
3495 afs_int32
3496 SBUDB_T_GetVersion(struct rx_call *call, afs_int32 *majorVersion)
3498 afs_int32 code;
3500 code = T_GetVersion(call, majorVersion);
3501 osi_auditU(call, BUDB_TGetVrEvent, code, AUD_END);
3502 return code;
3505 afs_int32
3506 T_GetVersion(struct rx_call *call, int *majorVersion)
3508 struct ubik_trans *ut;
3509 afs_int32 code;
3511 code = InitRPC(&ut, LOCKREAD, 0);
3512 if (code)
3513 return (code);
3515 *majorVersion = BUDB_MAJORVERSION;
3517 code = ubik_EndTrans(ut);
3518 return (code);
3521 /* BUDB_T_DumpDatabase
3522 * dump as much of the database as possible int /tmp/<filename>
3525 afs_int32
3526 SBUDB_T_DumpDatabase(struct rx_call *call, char *filename)
3528 afs_int32 code;
3530 code = T_DumpDatabase(call, filename);
3531 osi_auditU(call, BUDB_TDmpDBEvent, code, AUD_STR, filename, AUD_END);
3532 return code;
3535 afs_int32
3536 T_DumpDatabase(struct rx_call *call, char *filename)
3538 FILE *dumpfid;
3539 int entrySize;
3540 struct ubik_trans *ut;
3541 char *path = 0;
3542 dbadr dbAddr;
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);
3551 if (!path)
3552 return (BUDB_INTERNALERROR);
3554 sprintf(path, "%s/%s", gettmpdir(), filename);
3556 dumpfid = fopen(path, "w");
3557 if (!dumpfid)
3558 return (BUDB_BADARGUMENT);
3560 eval = InitRPC(&ut, LOCKWRITE, 1);
3561 if (eval)
3562 return (eval);
3564 /* dump all items in the database */
3565 for (type = 1; type <= HT_MAX_FUNCTION; type++) { /*ft */
3566 mht = ht_GetType(type, &entrySize);
3567 if (!mht)
3568 ERROR(BUDB_BADARGUMENT);
3570 for (old = 0; old <= 1; old++) { /*fo */
3571 length = (old ? mht->oldLength : mht->length);
3572 if (!length)
3573 continue;
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;
3586 eval =
3587 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3588 sizeof(diskDump));
3589 if (eval)
3590 ERROR(eval);
3592 fprintf(dumpfid,
3593 "\ndumpId hash %d, entry at %u\n",
3594 hash, dbAddr);
3595 fprintf(dumpfid,
3596 "----------------------------\n");
3597 dump_ntoh(&diskDump, &hostDump);
3598 printDump(dumpfid, &hostDump);
3599 dbAddr = hostDump.idHashChain;
3601 break;
3603 case HT_dumpName_FUNCTION:
3605 struct dump hostDump, diskDump;
3607 eval =
3608 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3609 sizeof(diskDump));
3610 if (eval)
3611 ERROR(eval);
3613 fprintf(dumpfid,
3614 "\ndumpname hash %d, entry at %u\n",
3615 hash, dbAddr);
3616 fprintf(dumpfid,
3617 "----------------------------\n");
3618 dump_ntoh(&diskDump, &hostDump);
3619 printDump(dumpfid, &hostDump);
3620 dbAddr = hostDump.nameHashChain;
3622 break;
3624 case HT_tapeName_FUNCTION:
3626 struct tape hostTape, diskTape;
3628 eval =
3629 cdbread(ut, tape_BLOCK, dbAddr, &diskTape,
3630 sizeof(diskTape));
3631 if (eval)
3632 ERROR(eval);
3634 fprintf(dumpfid,
3635 "\ntapename hash %d, entry at %u\n",
3636 hash, dbAddr);
3637 fprintf(dumpfid,
3638 "----------------------------\n");
3639 tape_ntoh(&diskTape, &hostTape);
3640 printTape(dumpfid, &hostTape);
3641 dbAddr = hostTape.nameHashChain;
3643 break;
3645 case HT_volName_FUNCTION:
3647 struct volInfo hostVolInfo, diskVolInfo;
3649 eval =
3650 cdbread(ut, volInfo_BLOCK, dbAddr,
3651 &diskVolInfo, sizeof(diskVolInfo));
3652 if (eval)
3653 ERROR(eval);
3655 fprintf(dumpfid,
3656 "\nvolname hash %d, entry at %u\n",
3657 hash, dbAddr);
3658 fprintf(dumpfid,
3659 "----------------------------\n");
3660 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3661 printVolInfo(dumpfid, &hostVolInfo);
3662 dbAddr = hostVolInfo.nameHashChain;
3664 volFragsDump(ut, dumpfid,
3665 hostVolInfo.firstFragment);
3667 break;
3669 default:
3670 fprintf(dumpfid, "unknown type %d\n", type);
3671 break;
3673 } /*s */
3674 } /*w */
3675 } /*f */
3676 } /*fo */
3677 } /*ft */
3679 error_exit:
3680 code = ubik_EndTrans(ut); /* is this safe if no ut started ? */
3681 if (dumpfid)
3682 fclose(dumpfid);
3683 if (path)
3684 free(path);
3685 return (code);
3689 volFragsDump(struct ubik_trans *ut, FILE *dumpfid, dbadr dbAddr)
3691 struct volFragment hostVolFragment, diskVolFragment;
3692 afs_int32 code;
3694 while (dbAddr) {
3695 code =
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");
3700 return (0);
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;
3709 return (0);
3712 #ifdef notdef
3713 /* utilities - network to host conversion
3714 * currently used for debug only
3717 void
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);
3734 void
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);
3749 void
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);
3768 void
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 */
3790 #endif /* notdef */
3793 checkHash(struct ubik_trans *ut, int hashType)
3795 struct memoryHashTable *mhtPtr;
3796 int entrySize, hashTableLength;
3797 int bucket;
3798 int old;
3799 afs_int32 code = 0;
3801 mhtPtr = ht_GetType(hashType, &entrySize);
3802 if (mhtPtr == 0)
3803 ERROR(-1);
3805 for (old = 0; old < 1; old++) {
3806 LogDebug(5, "\nold = %d\n", old);
3807 printMemoryHashTable(stdout, mhtPtr);
3808 LogDebug(5, "\n");
3809 hashTableLength = (old ? mhtPtr->oldLength : mhtPtr->length);
3811 for (bucket = 0; bucket < hashTableLength; bucket++) {
3812 dbadr entryAddr;
3814 entryAddr = ht_LookupBucket(ut, mhtPtr, bucket, old);
3815 while (entryAddr != 0) {
3816 LogDebug(6, "bucket %d has disk addr %d\n", bucket,
3817 entryAddr);
3818 switch (hashType) {
3819 case HT_dumpIden_FUNCTION:
3821 struct dump diskDump, hostDump;
3823 code = dbread(ut, entryAddr, &diskDump, entrySize);
3824 if (code)
3825 ERROR(-1);
3827 dump_ntoh(&diskDump, &hostDump);
3828 printDump(stdout, &hostDump);
3829 entryAddr = hostDump.idHashChain;
3831 break;
3833 case HT_dumpName_FUNCTION:
3834 break;
3836 case HT_tapeName_FUNCTION:
3837 break;
3839 case HT_volName_FUNCTION:
3841 struct volInfo diskVolInfo, hostVolInfo;
3843 code = dbread(ut, entryAddr, &diskVolInfo, entrySize);
3844 if (code)
3845 ERROR(-1);
3847 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3848 printVolInfo(stdout, &hostVolInfo);
3849 entryAddr = hostVolInfo.nameHashChain;
3850 break;
3856 error_exit:
3857 return (code);