Merge 1.8.0~pre4 packaging into master
[pkg-k5-afs_openafs.git] / src / budb / procs.c
blobf2987d3115cfb07ad08d37bd744ea686d66355c1
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>
19 #include <roken.h>
21 #include <afs/stds.h>
22 #include <afs/bubasics.h>
23 #include <lock.h>
24 #include <ubik.h>
25 #include <lwp.h>
26 #include <rx/xdr.h>
27 #include <rx/rx.h>
28 #include <rx/rxkad.h>
29 #include <afs/cellconfig.h>
30 #include <afs/auth.h>
31 #include <afs/audit.h>
32 #include <afs/afsutil.h>
34 #include "budb.h"
35 #include "budb_errs.h"
36 #include "database.h"
37 #include "budb_internal.h"
38 #include "error_macros.h"
39 #include "globals.h"
41 #undef min
42 #undef max
45 extern struct ubik_dbase *BU_dbase;
46 extern struct afsconf_dir *BU_conf; /* for getting cell info */
48 afs_int32 AddVolume(struct rx_call *, struct budb_volumeEntry *);
49 afs_int32 AddVolumes(struct rx_call *, struct budb_volumeList *);
50 afs_int32 CreateDump(struct rx_call *, struct budb_dumpEntry *);
51 afs_int32 DoDeleteDump(struct rx_call *, dumpId, Date, Date, budb_dumpsList *);
52 afs_int32 DoDeleteTape(struct rx_call *, struct budb_tapeEntry *);
53 afs_int32 ListDumps(struct rx_call *, afs_int32, afs_int32, Date, Date,
54 budb_dumpsList *, budb_dumpsList *);
55 afs_int32 DeleteVDP(struct rx_call *, char *, char *, afs_int32);
56 afs_int32 FindClone(struct rx_call *, afs_int32, char *, afs_int32 *);
57 afs_int32 FindDump(struct rx_call *, char *, afs_int32,
58 struct budb_dumpEntry *);
59 afs_int32 FindLatestDump(struct rx_call *, char *, char *,
60 struct budb_dumpEntry *);
61 afs_int32 FinishDump(struct rx_call *, struct budb_dumpEntry *);
62 afs_int32 FinishTape(struct rx_call *, struct budb_tapeEntry *);
63 afs_int32 GetDumps(struct rx_call *, afs_int32, afs_int32, char *,
64 afs_int32, afs_int32, afs_int32, afs_int32 *,
65 afs_int32 *, budb_dumpList *);
66 afs_int32 getExpiration(struct ubik_trans *ut, struct tape *);
67 afs_int32 makeAppended(struct ubik_trans *ut, afs_int32, afs_int32,
68 afs_int32);
69 afs_int32 MakeDumpAppended(struct rx_call *, afs_int32, afs_int32,
70 afs_int32);
71 afs_int32 FindLastTape(struct rx_call *, afs_int32, struct budb_dumpEntry *,
72 struct budb_tapeEntry *, struct budb_volumeEntry *);
73 afs_int32 GetTapes(struct rx_call *, afs_int32, afs_int32, char *, afs_int32,
74 afs_int32, afs_int32, afs_int32 *, afs_int32 *,
75 budb_tapeList *);
76 afs_int32 GetVolumes(struct rx_call *, afs_int32, afs_int32, char *,
77 afs_int32, afs_int32, afs_int32, afs_int32 *,
78 afs_int32 *, budb_volumeList *);
79 afs_int32 UseTape(struct rx_call *, struct budb_tapeEntry *, int *);
80 afs_int32 T_DumpHashTable(struct rx_call *, int, char *);
81 afs_int32 T_GetVersion(struct rx_call *, int *);
82 afs_int32 T_DumpDatabase(struct rx_call *, char *);
84 int volFragsDump(struct ubik_trans *, FILE *, dbadr);
86 /* Text block management */
88 struct memTextBlock {
89 struct memTextBlock *mtb_next; /* next in chain */
90 afs_int32 mtb_nbytes; /* # of bytes in this block */
91 struct blockHeader mtb_blkHeader; /* in memory header */
92 dbadr mtb_addr; /* disk address of block */
95 typedef struct memTextBlock memTextBlockT;
96 typedef memTextBlockT *memTextBlockP;
98 /* These variable are for returning debugging info about the state of the
99 server. If they get trashed during multi-threaded operation it doesn't
100 matter. */
102 /* This is global so COUNT_REQ in krb_udp.c can refer to it. */
103 char *lastOperation; /* name of last operation */
104 static Date lastTrans; /* time of last transaction */
106 /* procsInited is sort of a lock: during a transaction only one process runs
107 while procsInited is false. */
109 static int procsInited = 0;
111 /* This variable is protected by the procsInited flag. */
113 static int (*rebuildDatabase) (struct ubik_trans *);
115 /* AwaitInitialization
116 * Wait unitl budb has initialized (InitProcs). If it hasn't
117 * within 5 seconds, then return no quorum.
119 afs_int32
120 AwaitInitialization(void)
122 afs_int32 start = 0;
124 while (!procsInited) {
125 if (!start)
126 start = time(0);
127 else if (time(0) - start > 5)
128 return UNOQUORUM;
129 #ifdef AFS_PTHREAD_ENV
130 sleep(1);
131 #else
132 IOMGR_Sleep(1);
133 #endif
135 return 0;
138 /* tailCompPtr
139 * name is a pathname style name, determine trailing name and return
140 * pointer to it
143 char *
144 tailCompPtr(char *pathNamePtr)
146 char *ptr;
147 ptr = strrchr(pathNamePtr, '/');
148 if (ptr == 0) {
149 /* this should never happen */
150 LogError(0, "tailCompPtr: could not find / in name(%s)\n",
151 pathNamePtr);
152 return (pathNamePtr);
153 } else
154 ptr++; /* skip the / */
155 return (ptr);
158 /* callPermitted
159 * Check to see if the caller is a SuperUser.
160 * exit:
161 * 0 - no
162 * 1 - yes
166 callPermitted(struct rx_call *call)
168 int permitted = 0;
169 struct afsconf_dir *acdir;
171 acdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
172 if (!acdir)
173 return 0;
175 if (afsconf_SuperUser(acdir, call, NULL))
176 permitted = 1;
178 if (acdir)
179 afsconf_Close(acdir);
180 return (permitted);
183 /* InitRPC
184 * This is called by every RPC interface to create a Ubik transaction
185 * and read the database header into core
186 * entry:
187 * ut
188 * lock
189 * this_op
190 * notes:
191 * sets a lock on byte 1 of the database. Looks like it enforces
192 * single threading by use of the lock.
195 afs_int32
196 InitRPC(struct ubik_trans **ut,
197 int lock, /* indicate read/write transaction */
198 int this_op) /* opcode of RCP, for COUNT_ABO */
200 int code;
201 float wait = 0.91; /* start waiting for 1 second */
203 start:
204 /* wait for server initialization to finish if this is not InitProcs calling */
205 if (this_op)
206 if ((code = AwaitInitialization()))
207 return code;
209 for (code = UNOQUORUM; code == UNOQUORUM;) {
210 code =
211 ubik_BeginTrans(BU_dbase,
212 ((lock ==
213 LOCKREAD) ? UBIK_READTRANS : UBIK_WRITETRANS),
214 ut);
215 if (code == UNOQUORUM) { /* no quorum elected */
216 if (wait < 1)
217 Log("Waiting for quorum election\n");
218 if (wait < 15.0)
219 wait *= 1.1;
220 #ifdef AFS_PTHREAD_ENV
221 sleep((int)wait);
222 #else
223 IOMGR_Sleep((int)wait);
224 #endif
227 if (code)
228 return code;
229 if (wait > 1)
230 Log("Have established quorum\n");
232 /* set lock at posiion 1, for 1 byte of type lock */
233 if ((code = ubik_SetLock(*ut, 1, 1, lock))) {
234 ubik_AbortTrans(*ut);
235 return code;
238 /* check that dbase is initialized and setup cheader */
239 if (lock == LOCKREAD) {
240 /* init but don't fix because this is read only */
241 if ((code = CheckInit(*ut, 0))) {
242 ubik_AbortTrans(*ut);
243 if ((code = InitRPC(ut, LOCKWRITE, 0))) { /* Now fix the database */
244 LogError(code, "InitRPC: InitRPC failed\n");
245 return code;
247 if ((code = ubik_EndTrans(*ut))) {
248 LogError(code, "InitRPC: ubik_EndTrans failed\n");
249 return code;
251 goto start; /* now redo the read transaction */
253 } else {
254 if ((code = CheckInit(*ut, rebuildDatabase))) {
255 ubik_AbortTrans(*ut);
256 return code;
259 lastTrans = time(0);
260 return 0;
263 /* This is called to initialize a newly created database */
264 static int
265 initialize_database(struct ubik_trans *ut)
267 return 0;
270 static int noAuthenticationRequired; /* global state */
271 static int recheckNoAuth; /* global state */
273 afs_int32
274 InitProcs(void)
276 struct ubik_trans *ut;
277 afs_int32 code = 0;
279 procsInited = 0;
281 if ((globalConfPtr->myHost == 0) || (BU_conf == 0))
282 ERROR(BUDB_INTERNALERROR);
284 recheckNoAuth = 1;
286 if (globalConfPtr->debugFlags & DF_NOAUTH)
287 noAuthenticationRequired = 1;
289 if (globalConfPtr->debugFlags & DF_RECHECKNOAUTH)
290 recheckNoAuth = 0;
292 if (recheckNoAuth)
293 noAuthenticationRequired = afsconf_GetNoAuthFlag(BU_conf);
295 if (noAuthenticationRequired)
296 LogError(0, "Running server with security disabled\n");
298 InitDB();
300 rebuildDatabase = initialize_database;
302 if ((code = InitRPC(&ut, LOCKREAD, 0))) {
303 LogError(code, "InitProcs: InitRPC failed\n");
304 return code;
306 code = ubik_EndTrans(ut);
307 if (code) {
308 LogError(code, "InitProcs: ubik_EndTrans failed\n");
309 return code;
312 rebuildDatabase = 0; /* only do this during init */
313 procsInited = 1;
315 error_exit:
316 return (code);
319 struct returnList {
320 int nElements; /* number in list */
321 int allocSize; /* number of elements allocated */
322 dbadr *elements; /* array of addresses */
325 static void
326 InitReturnList(struct returnList *list)
328 list->nElements = 0;
329 list->allocSize = 0;
330 list->elements = (dbadr *) 0;
333 static void
334 FreeReturnList(struct returnList *list)
336 if (list->elements)
337 free(list->elements);
338 list->elements = (dbadr *) 0;
339 list->nElements = 0;
342 /* As entries are collected, they are added to a return list. Once all
343 * entries have been collected, it is then placed in the return buffer
344 * with SendReturnList(). The first *to_skipP are not recorded.
346 static afs_int32
347 AddToReturnList(struct returnList *list, dbadr a, afs_int32 *to_skipP)
349 dbadr *tmp;
350 afs_int32 size;
352 if (a == 0)
353 return 0;
354 if (*to_skipP > 0) {
355 (*to_skipP)--;
356 return 0;
359 /* Up to 5 plus a maximum so SendReturnList() knows if we
360 * need to come back for more.
362 if (list->nElements >= BUDB_MAX_RETURN_LIST + 5)
363 return BUDB_LIST2BIG;
365 if (list->nElements >= list->allocSize) {
366 if (list->elements == 0) {
367 size = 10;
368 tmp = malloc(sizeof(dbadr) * size);
369 } else {
370 size = list->allocSize + 10;
371 tmp = realloc(list->elements, sizeof(dbadr) * size);
373 if (!tmp)
374 return BUDB_NOMEM;
375 list->elements = tmp;
376 list->allocSize = size;
379 list->elements[list->nElements] = a;
380 list->nElements++;
381 return 0;
384 afs_int32
385 FillVolEntry(struct ubik_trans *ut, dbadr va, void *rock)
387 struct budb_volumeEntry *vol = (struct budb_volumeEntry *) rock;
388 struct dump d;
389 struct tape t;
390 struct volInfo vi;
391 struct volFragment vf;
393 if (dbread(ut, va, &vf, sizeof(vf)))
394 return BUDB_IO; /* The volFrag */
395 if (dbread(ut, ntohl(vf.vol), &vi, sizeof(vi)))
396 return BUDB_IO; /* The volInfo */
397 if (dbread(ut, ntohl(vf.tape), &t, sizeof(t)))
398 return BUDB_IO; /* The tape */
399 if (dbread(ut, ntohl(t.dump), &d, sizeof(d)))
400 return BUDB_IO; /* The dump */
402 strcpy(vol->name, vi.name);
403 strcpy(vol->server, vi.server);
404 strcpy(vol->tape, t.name);
405 vol->tapeSeq = ntohl(t.seq);
406 vol->dump = ntohl(d.id);
407 vol->position = ntohl(vf.position);
408 vol->clone = ntohl(vf.clone);
409 vol->incTime = ntohl(vf.incTime);
410 vol->nBytes = ntohl(vf.nBytes);
411 vol->startByte = ntohl(vf.startByte);
412 vol->flags = (ntohs(vf.flags) & VOLFRAGMENTFLAGS); /* low 16 bits here */
413 vol->flags |= (ntohl(vi.flags) & VOLINFOFLAGS); /* high 16 bits here */
414 vol->seq = ntohs(vf.sequence);
415 vol->id = ntohl(vi.id);
416 vol->partition = ntohl(vi.partition);
418 return 0;
421 afs_int32
422 FillDumpEntry(struct ubik_trans *ut, dbadr da, void *rock)
424 struct budb_dumpEntry *dump = (struct budb_dumpEntry *)rock;
425 struct dump d, ad;
427 if (dbread(ut, da, &d, sizeof(d)))
428 return BUDB_IO;
429 dump->id = ntohl(d.id);
430 dump->flags = ntohl(d.flags);
431 dump->created = ntohl(d.created);
432 strncpy(dump->name, d.dumpName, sizeof(dump->name));
433 strncpy(dump->dumpPath, d.dumpPath, sizeof(dump->dumpPath));
434 strncpy(dump->volumeSetName, d.volumeSet, sizeof(dump->volumeSetName));
436 dump->parent = ntohl(d.parent);
437 dump->level = ntohl(d.level);
438 dump->nVolumes = ntohl(d.nVolumes);
440 tapeSet_ntoh(&d.tapes, &dump->tapes);
442 if (strlen(d.dumper.name) < sizeof(dump->dumper.name))
443 strcpy(dump->dumper.name, d.dumper.name);
444 if (strlen(d.dumper.instance) < sizeof(dump->dumper.instance))
445 strcpy(dump->dumper.instance, d.dumper.instance);
446 if (strlen(d.dumper.cell) < sizeof(dump->dumper.cell))
447 strcpy(dump->dumper.cell, d.dumper.cell);
449 /* Get the initial dumpid and the appended dump id */
450 dump->initialDumpID = ntohl(d.initialDumpID);
451 if (d.appendedDumpChain) {
452 if (dbread(ut, ntohl(d.appendedDumpChain), &ad, sizeof(ad)))
453 return BUDB_IO;
454 dump->appendedDumpID = ntohl(ad.id);
455 } else
456 dump->appendedDumpID = 0;
458 /* printf("dump name %s, parent %d, level %d\n",
459 * d.dumpName, ntohl(d.parent), ntohl(d.level)); */
461 return 0;
464 afs_int32
465 FillTapeEntry(struct ubik_trans *ut, dbadr ta, void *rock)
467 struct budb_tapeEntry *tape=(struct budb_tapeEntry *) rock;
468 struct tape t;
469 struct dump d;
470 afs_int32 code;
472 if (dbread(ut, ta, &t, sizeof(t)))
473 return BUDB_IO;
475 /* Get the tape's expiration date */
476 if ((code = getExpiration(ut, &t)))
477 return (code);
479 strcpy(tape->name, t.name);
480 tape->flags = ntohl(t.flags);
481 tape->written = ntohl(t.written);
482 tape->expires = ntohl(t.expires);
483 tape->nMBytes = ntohl(t.nMBytes);
484 tape->nBytes = ntohl(t.nBytes);
485 tape->nFiles = ntohl(t.nFiles);
486 tape->nVolumes = ntohl(t.nVolumes);
487 tape->seq = ntohl(t.seq);
488 tape->labelpos = ntohl(t.labelpos);
489 tape->useCount = ntohl(t.useCount);
490 tape->useKBytes = ntohl(t.useKBytes);
492 if (dbread(ut, ntohl(t.dump), &d, sizeof(d)))
493 return BUDB_IO;
494 tape->dump = ntohl(d.id);
495 return 0;
498 #define returnList_t budb_dumpList *
500 /* SendReturnList
501 * A list of elements of size e_size is in list, collected
502 * with AddToReturnList(). We will move this to a correspoding
503 * return list, eList, via FillProc(). nextInodeP tells us
504 * if there are more and how many to skip on the next request.
506 static afs_int32
507 SendReturnList(struct ubik_trans *ut,
508 struct returnList *list, /* list of elements to return */
509 afs_int32(*FillProc) (struct ubik_trans *, dbadr da,
510 void *),
511 /* proc to fill entry */
512 int e_size, /* size of each element */
513 afs_int32 index, /* index from previous call */
514 afs_int32 *nextIndexP, /* if more elements are available */
515 afs_int32 *dbTimeP, /* time of last db update */
516 budb_dumpList *eList) /* rxgen list structure (e.g.) */
518 afs_int32 code;
519 int to_return;
520 int i;
521 char *e;
523 *nextIndexP = -1;
524 *dbTimeP = ntohl(db.h.lastUpdate);
526 /* Calculate how many to return. Don't let if go over
527 * BUDB_MAX_RETURN_LIST nor the size of our return list.
529 to_return = list->nElements;
530 if (to_return > BUDB_MAX_RETURN_LIST)
531 to_return = BUDB_MAX_RETURN_LIST;
532 if (eList->budb_dumpList_len && (to_return > eList->budb_dumpList_len))
533 to_return = eList->budb_dumpList_len;
535 /* Allocate space for the return values if needed and zero it */
536 if (eList->budb_dumpList_val == 0) {
537 if (to_return > 0) {
538 eList->budb_dumpList_val = calloc(to_return, e_size);
539 if (!eList->budb_dumpList_val)
540 return (BUDB_NOMEM);
541 } else
542 eList->budb_dumpList_val = NULL;
543 } else {
544 memset(eList->budb_dumpList_val, 0, e_size * to_return);
547 eList->budb_dumpList_len = to_return;
549 e = (char *)(eList->budb_dumpList_val);
550 for (i = 0; i < to_return; i++, e += e_size) {
551 code = (*FillProc) (ut, list->elements[i], (budb_dumpEntry *) e);
552 if (code)
553 return code;
556 if (list->nElements > i)
557 *nextIndexP = index + i;
558 return 0;
561 /* Come here to delete a volInfo structure. */
563 static afs_int32
564 DeleteVolInfo(struct ubik_trans *ut, dbadr via, struct volInfo *vi)
566 afs_int32 code;
567 dbadr hvia;
568 struct volInfo hvi;
570 if (vi->firstFragment)
571 return 0; /* still some frags, don't free yet */
572 if (vi->sameNameHead == 0) { /* this is the head */
573 if (vi->sameNameChain)
574 return 0; /* empty head, some non-heads left */
576 code = ht_HashOut(ut, &db.volName, via, vi);
577 if (code)
578 return code;
579 code = FreeStructure(ut, volInfo_BLOCK, via);
580 return code;
582 hvia = ntohl(vi->sameNameHead);
583 if (dbread(ut, hvia, &hvi, sizeof(hvi)))
584 return BUDB_IO;
585 code =
586 RemoveFromList(ut, hvia, &hvi, &hvi.sameNameChain, via, vi,
587 &vi->sameNameChain);
588 if (code == -1)
589 return BUDB_DATABASEINCONSISTENT;
590 if (code == 0)
591 code = FreeStructure(ut, volInfo_BLOCK, via);
592 return code;
595 /* Detach a volume fragment from its volInfo structure. Its tape chain is
596 already freed. This routine frees the structure and the caller must not
597 write it out. */
599 static afs_int32
600 DeleteVolFragment(struct ubik_trans *ut, dbadr va, struct volFragment *v)
602 afs_int32 code;
603 struct volInfo vi;
604 dbadr via;
606 via = ntohl(v->vol);
607 if (dbread(ut, via, &vi, sizeof(vi)))
608 return BUDB_IO;
609 code =
610 RemoveFromList(ut, via, &vi, &vi.firstFragment, va, v,
611 &v->sameNameChain);
612 if (code == -1)
613 return BUDB_DATABASEINCONSISTENT;
614 if (code)
615 return code;
616 if (vi.firstFragment == 0)
617 if ((code = DeleteVolInfo(ut, via, &vi)))
618 return code;
619 if ((code = FreeStructure(ut, volFragment_BLOCK, va)))
620 return code;
622 /* decrement frag counter */
623 code =
624 set_word_addr(ut, via, &vi, &vi.nFrags, htonl(ntohl(vi.nFrags) - 1));
625 if (code)
626 return code;
627 return 0;
630 /* DeleteTape - by freeing all its volumes and removing it from its dump chain.
631 * The caller will remove it from the hash table if necessary. The caller is
632 * also responsible for writing the tape out if necessary. */
634 static afs_int32
635 DeleteTape(struct ubik_trans *ut, dbadr ta, struct tape *t)
637 afs_int32 code;
638 struct dump d;
639 dbadr da;
641 da = ntohl(t->dump);
642 if (da == 0)
643 return BUDB_DATABASEINCONSISTENT;
644 if (dbread(ut, da, &d, sizeof(d)))
645 return BUDB_IO;
646 if (d.firstTape == 0)
647 return BUDB_DATABASEINCONSISTENT;
649 code = RemoveFromList(ut, da, &d, &d.firstTape, ta, t, &t->nextTape);
650 if (code == -1)
651 return BUDB_DATABASEINCONSISTENT;
652 if (code)
653 return code;
655 /* Since the tape should have been truncated there should never be any
656 * volumes in the tape. */
657 if (t->firstVol || t->nVolumes)
658 return BUDB_DATABASEINCONSISTENT;
660 return 0;
663 static afs_int32
664 DeleteDump(struct ubik_trans *ut, dbadr da, struct dump *d)
666 afs_int32 code = 0;
668 code = ht_HashOut(ut, &db.dumpIden, da, d);
669 if (code)
670 ERROR(code);
672 code = ht_HashOut(ut, &db.dumpName, da, d);
673 if (code)
674 ERROR(code);
676 /* Since the tape should have been truncated this should never happen. */
677 if (d->firstTape || d->nVolumes)
678 ERROR(BUDB_DATABASEINCONSISTENT);
680 code = FreeStructure(ut, dump_BLOCK, da);
681 if (code)
682 ERROR(code);
684 error_exit:
685 return code;
689 * VolInfoMatch()
691 * This is called with a volumeEntry and a volInfo structure and compares
692 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
693 * search volInfo structures once it has the head volInfo structure from the
694 * volName hash table.
696 * When called from GetVolInfo the name compare is redundant.
697 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
700 static int
701 VolInfoMatch(struct budb_volumeEntry *vol, struct volInfo *vi)
703 return ((strcmp(vol->name, vi->name) == 0) && /* same volume name */
704 (vol->id == ntohl(vi->id)) && /* same volume id */
705 ((vol->flags & VOLINFOFLAGS) == (ntohl(vi->flags) & VOLINFOFLAGS)) && /* same flags */
706 (vol->partition == ntohl(vi->partition)) && /* same partition (N/A) */
707 (strcmp(vol->server, vi->server) == 0)); /* same server (N/A) */
711 * GetVolInfo()
712 * This routine takes a volumeEntry structure from an RPC interface and
713 * returns the corresponding volInfo structure, creating it if necessary.
715 * The caller must write the entry out.
718 static afs_int32
719 GetVolInfo(struct ubik_trans *ut, struct budb_volumeEntry *volP, dbadr *viaP,
720 struct volInfo *viP)
722 dbadr hvia, via;
723 struct volInfo hvi;
724 afs_int32 eval, code = 0;
726 eval = ht_LookupEntry(ut, &db.volName, volP->name, &via, viP);
727 if (eval)
728 ERROR(eval);
730 if (!via) {
731 /* allocate a new volinfo structure */
732 eval = AllocStructure(ut, volInfo_BLOCK, 0, &via, viP);
733 if (eval)
734 ERROR(eval);
736 strcpy(viP->name, volP->name);
737 strcpy(viP->server, volP->server);
738 viP->sameNameHead = 0; /* The head of same name chain */
739 viP->sameNameChain = 0; /* Same name chain is empty */
740 viP->firstFragment = 0;
741 viP->nFrags = 0;
742 viP->id = htonl(volP->id);
743 viP->partition = htonl(volP->partition);
744 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
746 /* Chain onto volname hash table */
747 eval = ht_HashIn(ut, &db.volName, via, viP);
748 if (eval)
749 ERROR(eval);
751 LogDebug(4, "volume Info for %s placed at %d\n", volP->name, via);
754 else if (!VolInfoMatch(volP, viP)) { /* Not the head volinfo struct */
755 hvia = via; /* remember the head volinfo struct */
756 memcpy(&hvi, viP, sizeof(hvi));
758 /* Search the same name chain for the correct volinfo structure */
759 for (via = ntohl(viP->sameNameChain); via;
760 via = ntohl(viP->sameNameChain)) {
761 eval = dbread(ut, via, viP, sizeof(*viP));
762 if (eval)
763 ERROR(eval);
765 if (VolInfoMatch(volP, viP))
766 break; /* found the one */
769 /* if the correct volinfo struct isn't found, create one */
770 if (!via) {
771 eval = AllocStructure(ut, volInfo_BLOCK, 0, &via, viP);
772 if (eval)
773 ERROR(eval);
775 strcpy(viP->name, volP->name);
776 strcpy(viP->server, volP->server);
777 viP->nameHashChain = 0; /* not in hash table */
778 viP->sameNameHead = htonl(hvia); /* chain to head of sameNameChain */
779 viP->sameNameChain = hvi.sameNameChain;
780 viP->firstFragment = 0;
781 viP->nFrags = 0;
782 viP->id = htonl(volP->id);
783 viP->partition = htonl(volP->partition);
784 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
786 /* write the head entry's sameNameChain link */
787 eval =
788 set_word_addr(ut, hvia, &hvi, &hvi.sameNameChain, htonl(via));
789 if (eval)
790 ERROR(eval);
794 *viaP = via;
796 error_exit:
797 return code;
800 /* deletesomevolumesfromtape
801 * Deletes a specified number of volumes from a tape. The tape
802 * and dump are modified to reflect the smaller number of volumes.
803 * The transaction is not terminated, it is up to the caller to
804 * finish the transaction and start a new one (if desired).
805 * entry:
806 * maxvolumestodelete - don't delete more than this many volumes
809 afs_int32
810 deleteSomeVolumesFromTape(struct ubik_trans *ut, dbadr tapeAddr,
811 struct tape *tapePtr, int maxVolumesToDelete)
813 dbadr volFragAddr, nextVolFragAddr, dumpAddr;
814 struct volFragment volFrag;
815 struct dump dump;
816 int volumesDeleted = 0;
817 afs_int32 eval, code = 0;
819 if (!tapePtr)
820 ERROR(0);
822 for (volFragAddr = ntohl(tapePtr->firstVol);
823 (volFragAddr && (maxVolumesToDelete > 0));
824 volFragAddr = nextVolFragAddr) {
825 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
826 if (eval)
827 ERROR(eval);
829 nextVolFragAddr = ntohl(volFrag.sameTapeChain);
831 eval = DeleteVolFragment(ut, volFragAddr, &volFrag);
832 if (eval)
833 ERROR(eval);
835 maxVolumesToDelete--;
836 volumesDeleted++;
839 /* reset the volume fragment pointer in the tape */
840 tapePtr->firstVol = htonl(volFragAddr);
842 /* diminish the tape's volume count */
843 tapePtr->nVolumes = htonl(ntohl(tapePtr->nVolumes) - volumesDeleted);
845 eval = dbwrite(ut, tapeAddr, tapePtr, sizeof(*tapePtr));
846 if (eval)
847 ERROR(eval);
849 /* diminish the dump's volume count */
850 dumpAddr = ntohl(tapePtr->dump);
851 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
852 if (eval)
853 ERROR(eval);
855 dump.nVolumes = htonl(ntohl(dump.nVolumes) - volumesDeleted);
856 eval = dbwrite(ut, dumpAddr, &dump, sizeof(dump));
857 if (eval)
858 ERROR(eval);
860 error_exit:
861 return (code);
864 /* deleteDump
865 * deletes a dump in stages, by repeatedly deleting a small number of
866 * volumes from the dump until none are left. The dump is then deleted.
868 * In the case where multiple calls are made to delete the same
869 * dump, the operation will succeed but contention for structures
870 * will result in someone getting back an error.
872 * entry:
873 * id - id of dump to delete
876 afs_int32
877 deleteDump(struct rx_call *call, dumpId id, budb_dumpsList *dumps)
879 struct ubik_trans *ut;
880 dbadr dumpAddr, tapeAddr, appendedDump;
881 struct dump dump;
882 struct tape tape;
883 dumpId dumpid;
884 afs_int32 eval, code = 0;
885 int partialDel = 0;
887 /* iterate until the dump is truly deleted */
889 dumpid = id;
890 while (dumpid) {
891 partialDel = 0;
892 while (1) {
893 eval = InitRPC(&ut, LOCKWRITE, 1);
894 if (eval)
895 ERROR(eval); /* can't start transaction */
897 eval =
898 ht_LookupEntry(ut, &db.dumpIden, &dumpid, &dumpAddr, &dump);
899 if (eval)
900 ABORT(eval);
901 if (!dumpAddr)
902 ABORT(BUDB_NOENT); /* can't find dump */
904 if ((dumpid == id) && (dump.initialDumpID)) /* can't be an appended dump */
905 ABORT(BUDB_NOTINITIALDUMP);
907 tapeAddr = ntohl(dump.firstTape);
908 if (tapeAddr == 0)
909 break;
911 /* there is a tape to delete */
912 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
913 if (eval)
914 ABORT(eval);
916 if (ntohl(tape.nVolumes)) {
917 /* tape is not empty */
918 eval = deleteSomeVolumesFromTape(ut, tapeAddr, &tape, 10);
919 if (eval)
920 ABORT(eval);
923 if (ntohl(tape.nVolumes) == 0) {
924 /* tape is now empty, delete it */
925 eval = DeleteTape(ut, tapeAddr, &tape);
926 if (eval)
927 ABORT(eval);
928 eval = ht_HashOut(ut, &db.tapeName, tapeAddr, &tape);
929 if (eval)
930 ABORT(eval);
931 eval = FreeStructure(ut, tape_BLOCK, tapeAddr);
932 if (eval)
933 ABORT(eval);
936 eval = ubik_EndTrans(ut);
937 if (eval)
938 ERROR(eval);
939 partialDel = 1;
940 } /* next deletion portion */
942 /* Record the dump just deleted */
943 if (dumps && (dumps->budb_dumpsList_len < BUDB_MAX_RETURN_LIST)) {
944 if (dumps->budb_dumpsList_len == 0)
945 dumps->budb_dumpsList_val = malloc(sizeof(afs_int32));
946 else
947 dumps->budb_dumpsList_val =
948 realloc(dumps->budb_dumpsList_val,
949 (dumps->budb_dumpsList_len + 1)
950 * sizeof(afs_int32));
952 if (!dumps->budb_dumpsList_val)
953 ABORT(BUDB_NOMEM);
955 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = dumpid;
956 dumps->budb_dumpsList_len++;
959 appendedDump = ntohl(dump.appendedDumpChain);
961 /* finally done. No more tapes left in the dump. Delete the dump itself */
962 eval = DeleteDump(ut, dumpAddr, &dump);
963 if (eval)
964 ABORT(eval);
966 /* Now delete the appended dump too */
967 if (appendedDump) {
968 eval = dbread(ut, appendedDump, &dump, sizeof(dump));
969 if (eval)
970 ABORT(eval);
972 dumpid = ntohl(dump.id);
973 } else
974 dumpid = 0;
976 eval = ubik_EndTrans(ut);
977 if (eval)
978 ERROR(eval);
980 Log("Delete dump %s (DumpID %u), path %s\n", dump.dumpName,
981 ntohl(dump.id), dump.dumpPath);
984 error_exit:
985 if (code && partialDel) {
986 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
987 dump.dumpName, ntohl(dump.id), dump.dumpPath, code);
989 return (code);
991 abort_exit:
992 ubik_AbortTrans(ut);
993 goto error_exit;
996 /* --------------
997 * dump selection routines - used by BUDB_GetDumps
998 * --------------
1001 /* most recent dump selection */
1003 struct chosenDump {
1004 struct chosenDump *next;
1005 dbadr addr;
1006 afs_uint32 date;
1009 struct wantDumpRock {
1010 int maxDumps; /* max wanted */
1011 int ndumps; /* actual in chain */
1012 struct chosenDump *chain;
1017 wantDump(dbadr dumpAddr, void *dumpParam, void *dumpListPtrParam)
1019 struct dump *dumpPtr;
1020 struct wantDumpRock *rockPtr;
1022 dumpPtr = (struct dump *)dumpParam;
1023 rockPtr = (struct wantDumpRock *)dumpListPtrParam;
1025 /* if we don't have our full complement, just add another */
1026 if (rockPtr->ndumps < rockPtr->maxDumps)
1027 return (1);
1029 /* got the number we need, select based on date */
1030 if ((afs_uint32) ntohl(dumpPtr->created) > rockPtr->chain->date)
1031 return (1);
1033 return (0);
1037 rememberDump(dbadr dumpAddr, void *dumpParam, void *dumpListPtrParam)
1039 struct dump *dumpPtr;
1040 struct wantDumpRock *rockPtr;
1041 struct chosenDump *ptr, *deletedPtr, **nextPtr;
1043 dumpPtr = (struct dump *)dumpParam;
1044 rockPtr = (struct wantDumpRock *)dumpListPtrParam;
1046 ptr = calloc(1, sizeof(*ptr));
1047 if (!ptr)
1048 return (0);
1049 ptr->addr = dumpAddr;
1050 ptr->date = (afs_uint32) ntohl(dumpPtr->created);
1052 /* Don't overflow the max */
1053 while (rockPtr->ndumps >= rockPtr->maxDumps) {
1054 /* have to drop one */
1055 deletedPtr = rockPtr->chain;
1056 rockPtr->chain = deletedPtr->next;
1057 free(deletedPtr);
1058 rockPtr->ndumps--;
1061 /* now insert in the right place */
1062 for (nextPtr = &rockPtr->chain; *nextPtr; nextPtr = &((*nextPtr)->next)) {
1063 if (ptr->date < (*nextPtr)->date)
1064 break;
1066 ptr->next = *nextPtr;
1067 *nextPtr = ptr;
1068 rockPtr->ndumps++;
1070 return (0);
1074 /* ---------------------------------------------
1075 * general interface routines - alphabetic
1076 * ---------------------------------------------
1079 afs_int32
1080 SBUDB_AddVolume(struct rx_call *call, struct budb_volumeEntry *vol)
1082 afs_int32 code;
1084 code = AddVolume(call, vol);
1085 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, (vol ? vol->id : 0),
1086 AUD_END);
1087 return code;
1090 afs_int32
1091 AddVolume(struct rx_call *call, struct budb_volumeEntry *vol)
1093 struct ubik_trans *ut;
1094 dbadr da, ta, via, va;
1095 struct dump d;
1096 struct tape t;
1097 struct volInfo vi;
1098 struct volFragment v;
1099 afs_uint32 bytes;
1100 afs_int32 eval, code = 0;
1102 if (!callPermitted(call))
1103 return BUDB_NOTPERMITTED;
1105 if ((strlen(vol->name) >= sizeof(vi.name))
1106 || (strlen(vol->server) >= sizeof(vi.server))
1107 || (strlen(vol->tape) >= sizeof(t.name)))
1108 return BUDB_BADARGUMENT;
1110 eval = InitRPC(&ut, LOCKWRITE, 1);
1111 if (eval)
1112 return eval;
1114 /* Find the dump in dumpid hash table */
1115 eval = ht_LookupEntry(ut, &db.dumpIden, &vol->dump, &da, &d);
1116 if (eval)
1117 ABORT(eval);
1118 if (!da)
1119 ABORT(BUDB_NODUMPID);
1121 /* search for the right tape in the dump */
1122 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
1123 /* read the tape entry */
1124 eval = dbread(ut, ta, &t, sizeof(t));
1125 if (eval)
1126 ABORT(eval);
1128 /* Check if the right tape name */
1129 if (strcmp(t.name, vol->tape) == 0)
1130 break;
1132 if (!ta)
1133 ABORT(BUDB_NOTAPENAME);
1135 if ((t.dump != htonl(da)) || /* tape must belong to dump */
1136 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1137 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)) /* dump must be in progress */
1138 ABORT(BUDB_BADPROTOCOL);
1140 /* find or create a volume info structure */
1141 eval = GetVolInfo(ut, vol, &via, &vi);
1142 if (eval)
1143 ABORT(eval);
1145 /* Create a volume fragment */
1146 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1147 if (eval)
1148 ABORT(eval);
1150 v.vol = htonl(via); /* vol frag points to vol info */
1151 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1152 vi.firstFragment = htonl(va);
1153 vi.nFrags = htonl(ntohl(vi.nFrags) + 1);
1155 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1156 if (eval)
1157 ABORT(eval);
1159 v.tape = htonl(ta); /* vol frag points to tape */
1160 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1161 t.firstVol = htonl(va);
1162 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1163 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1164 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes / (1024 * 1024));
1165 t.nBytes = htonl(bytes % (1024 * 1024));
1167 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1168 if (eval)
1169 ABORT(eval);
1171 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1173 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1174 if (eval)
1175 ABORT(eval);
1177 v.position = htonl(vol->position); /* vol frag info */
1178 v.clone = htonl(vol->clone);
1179 v.incTime = htonl(vol->incTime);
1180 v.startByte = htonl(vol->startByte);
1181 v.nBytes = htonl(vol->nBytes);
1182 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1183 v.sequence = htons(vol->seq);
1185 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1186 if (eval)
1187 ABORT(eval);
1189 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1190 if (eval)
1191 ABORT(eval);
1193 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1195 code = ubik_EndTrans(ut);
1196 return code;
1198 abort_exit:
1199 ubik_AbortTrans(ut);
1200 return code;
1204 afs_int32
1205 SBUDB_AddVolumes(struct rx_call *call, struct budb_volumeList *vols)
1207 afs_int32 code;
1209 code = AddVolumes(call, vols);
1210 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, 0, AUD_END);
1211 return code;
1214 afs_int32
1215 AddVolumes(struct rx_call *call, struct budb_volumeList *vols)
1217 struct budb_volumeEntry *vol, *vol1;
1218 struct ubik_trans *ut;
1219 dbadr da, ta, via, va;
1220 struct dump d;
1221 struct tape t;
1222 struct volInfo vi;
1223 struct volFragment v;
1224 afs_uint32 bytes;
1225 afs_int32 eval, e, code = 0;
1227 if (!callPermitted(call))
1228 return BUDB_NOTPERMITTED;
1230 if (!vols || (vols->budb_volumeList_len <= 0)
1231 || !vols->budb_volumeList_val)
1232 return BUDB_BADARGUMENT;
1234 /* The first volume in the list of volumes to add */
1235 vol1 = (struct budb_volumeEntry *)vols->budb_volumeList_val;
1237 eval = InitRPC(&ut, LOCKWRITE, 1);
1238 if (eval)
1239 return eval;
1241 /* Find the dump in dumpid hash table */
1242 eval = ht_LookupEntry(ut, &db.dumpIden, &vol1->dump, &da, &d);
1243 if (eval)
1244 ABORT(eval);
1245 if (!da)
1246 ABORT(BUDB_NODUMPID);
1248 /* search for the right tape in the dump */
1249 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
1250 /* read the tape entry */
1251 eval = dbread(ut, ta, &t, sizeof(t));
1252 if (eval)
1253 ABORT(eval);
1255 /* Check if the right tape name */
1256 if (strcmp(t.name, vol1->tape) == 0)
1257 break;
1259 if (!ta)
1260 ABORT(BUDB_NOTAPENAME);
1262 if ((t.dump != htonl(da)) || /* tape must belong to dump */
1263 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1264 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)) /* dump must be in progress */
1265 ABORT(BUDB_BADPROTOCOL);
1267 for (vol = vol1, e = 0; e < vols->budb_volumeList_len; vol++, e++) {
1268 /*v */
1269 if ((strlen(vol->name) >= sizeof(vi.name)) || (strcmp(vol->name, "") == 0) || /* no null volnames */
1270 (strlen(vol->server) >= sizeof(vi.server))
1271 || (strlen(vol->tape) >= sizeof(t.name))
1272 || (strcmp(vol->tape, vol1->tape) != 0)) {
1273 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n", vol->name, vol->id, vol->tape, vol->dump);
1274 continue;
1277 /* find or create a volume info structure */
1278 eval = GetVolInfo(ut, vol, &via, &vi);
1279 if (eval)
1280 ABORT(eval);
1281 if (*(afs_int32 *) (&vi) == 0) {
1282 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n", vol->name, vol->tape, vol->dump);
1283 ABORT(BUDB_BADARGUMENT);
1286 /* Create a volume fragment */
1287 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1288 if (eval)
1289 ABORT(eval);
1291 v.vol = htonl(via); /* vol frag points to vol info */
1292 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1293 vi.firstFragment = htonl(va);
1294 vi.nFrags = htonl(ntohl(vi.nFrags) + 1);
1295 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1296 if (eval)
1297 ABORT(eval);
1299 v.tape = htonl(ta); /* vol frag points to tape */
1300 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1301 t.firstVol = htonl(va);
1302 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1303 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1304 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes / (1024 * 1024));
1305 t.nBytes = htonl(bytes % (1024 * 1024));
1307 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1309 v.position = htonl(vol->position); /* vol frag info */
1310 v.clone = htonl(vol->clone);
1311 v.incTime = htonl(vol->incTime);
1312 v.startByte = htonl(vol->startByte);
1313 v.nBytes = htonl(vol->nBytes);
1314 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1315 v.sequence = htons(vol->seq);
1317 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1318 if (eval)
1319 ABORT(eval);
1321 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1322 } /*v */
1324 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1325 if (eval)
1326 ABORT(eval);
1328 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1329 if (eval)
1330 ABORT(eval);
1332 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1333 if (eval)
1334 ABORT(eval);
1336 code = ubik_EndTrans(ut);
1337 return code;
1339 abort_exit:
1340 ubik_AbortTrans(ut);
1341 return code;
1345 /* BUDB_CreateDump
1346 * records the existence of a dump in the database. This creates only
1347 * the dump record, to which one must attach tape and volume records.
1348 * TBD
1349 * 1) record the volume set
1352 afs_int32
1353 SBUDB_CreateDump(struct rx_call *call, struct budb_dumpEntry *dump)
1355 afs_int32 code;
1357 code = CreateDump(call, dump);
1358 osi_auditU(call, BUDB_CrDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
1359 AUD_END);
1360 if (dump && !code) {
1361 Log("Create dump %s (DumpID %u), path %s\n", dump->name, dump->id,
1362 dump->dumpPath);
1364 return code;
1367 afs_int32
1368 CreateDump(struct rx_call *call, struct budb_dumpEntry *dump)
1370 struct ubik_trans *ut;
1371 dbadr findDumpAddr, da;
1372 struct dump findDump, d;
1373 afs_int32 eval, code = 0;
1375 rxkad_level level;
1376 afs_int32 kvno;
1377 Date expiration; /* checked by Security Module */
1378 struct ktc_principal principal;
1380 if (!callPermitted(call))
1381 return BUDB_NOTPERMITTED;
1383 if (strlen(dump->name) >= sizeof(d.dumpName))
1384 return BUDB_BADARGUMENT;
1386 eval = InitRPC(&ut, LOCKWRITE, 1);
1387 if (eval)
1388 return eval;
1390 eval =
1391 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration,
1392 principal.name, principal.instance,
1393 principal.cell, &kvno);
1395 if (eval) {
1396 if (eval != RXKADNOAUTH)
1397 ABORT(eval);
1399 strcpy(principal.name, "");
1400 strcpy(principal.instance, "");
1401 strcpy(principal.cell, "");
1402 expiration = 0;
1403 } else {
1404 /* authenticated. Take user supplied principal information */
1405 if (strcmp(dump->dumper.name, "") != 0)
1406 strncpy(principal.name, dump->dumper.name,
1407 sizeof(principal.name));
1409 if (strcmp(dump->dumper.instance, "") != 0)
1410 strncpy(principal.instance, dump->dumper.instance,
1411 sizeof(principal.instance));
1413 if (strcmp(dump->dumper.cell, "") != 0)
1414 strncpy(principal.cell, dump->dumper.cell,
1415 sizeof(principal.cell));
1418 /* dump id's are time stamps */
1419 if (!dump->id) {
1420 while (1) { /* allocate a unique dump id *//*w */
1421 dump->id = time(0);
1423 /* ensure it is unique - seach for dumpid in hash table */
1424 eval =
1425 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1426 &findDump);
1427 if (eval)
1428 ABORT(eval);
1430 if (!findDumpAddr) { /* dumpid not in use */
1431 /* update the last dump id allocated */
1432 eval = set_header_word(ut, lastDumpId, htonl(dump->id));
1433 if (eval)
1434 ABORT(eval);
1435 break;
1438 /* dump id is in use - wait a while */
1439 #ifdef AFS_PTHREAD_ENV
1440 sleep(1);
1441 #else
1442 IOMGR_Sleep(1);
1443 #endif
1444 } /*w */
1445 } else {
1446 /* dump id supplied (e.g. for database restore) */
1447 eval =
1448 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1449 &findDump);
1450 if (eval)
1451 ABORT(eval);
1453 /* Dump id must not already exist */
1454 if (findDumpAddr)
1455 ABORT(BUDB_DUMPIDEXISTS);
1458 /* Allocate a dump structure */
1459 memset(&d, 0, sizeof(d));
1460 eval = AllocStructure(ut, dump_BLOCK, 0, &da, &d);
1461 if (eval)
1462 ABORT(eval);
1464 strcpy(d.dumpName, dump->name); /* volset.dumpname */
1465 strcpy(d.dumpPath, dump->dumpPath); /* dump node path */
1466 strcpy(d.volumeSet, dump->volumeSetName); /* volume set */
1467 d.id = htonl(dump->id);
1468 d.parent = htonl(dump->parent); /* parent id */
1469 d.level = htonl(dump->level);
1471 LogDebug(4, "dump name %s, parent %d level %d\n", dump->name,
1472 dump->parent, dump->level);
1474 /* if creation time specified, use that. Else use the dumpid time */
1475 if (dump->created == 0)
1476 dump->created = dump->id;
1477 d.created = htonl(dump->created);
1479 d.dumper = principal;
1480 tapeSet_hton(&dump->tapes, &d.tapes);
1482 d.flags = htonl(dump->flags | BUDB_DUMP_INPROGRESS);
1484 eval = ht_HashIn(ut, &db.dumpName, da, &d); /* Into dump name hash table */
1485 if (eval)
1486 ABORT(eval);
1488 eval = ht_HashIn(ut, &db.dumpIden, da, &d); /* Into dumpid hash table */
1489 if (eval)
1490 ABORT(eval);
1492 eval = dbwrite(ut, da, (char *)&d, sizeof(d)); /* Write the dump structure */
1493 if (eval)
1494 ABORT(eval);
1496 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1497 if (eval)
1498 ABORT(eval);
1500 /* If to append this dump, then append it - will write the appended dump */
1501 eval = makeAppended(ut, dump->id, dump->initialDumpID, dump->tapes.b);
1502 if (eval)
1503 ABORT(eval);
1505 code = ubik_EndTrans(ut);
1506 LogDebug(5, "made dump %s, path %s\n", d.dumpName, d.dumpPath);
1507 return code;
1509 abort_exit:
1510 ubik_AbortTrans(ut);
1511 return code;
1514 afs_int32
1515 SBUDB_DeleteDump(struct rx_call *call, dumpId id, Date fromTime, Date toTime,
1516 budb_dumpsList *dumps)
1518 afs_int32 code;
1520 code = DoDeleteDump(call, id, fromTime, toTime, dumps);
1521 osi_auditU(call, BUDB_DelDmpEvent, code, AUD_DATE, id, AUD_END);
1522 return code;
1525 #define MAXOFFS 30
1527 afs_int32
1528 DoDeleteDump(struct rx_call *call, dumpId id, Date fromTime, Date toTime,
1529 budb_dumpsList *dumps)
1531 afs_int32 code = 0;
1533 if (!callPermitted(call))
1534 return BUDB_NOTPERMITTED;
1536 if (id)
1537 code = deleteDump(call, id, dumps);
1538 return (code);
1541 afs_int32
1542 SBUDB_ListDumps(struct rx_call *call, afs_int32 sflags, char *name,
1543 afs_int32 groupid, Date fromTime, Date toTime,
1544 budb_dumpsList *dumps, budb_dumpsList *flags)
1546 afs_int32 code;
1548 code = ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags);
1549 osi_auditU(call, BUDB_LstDmpEvent, code, AUD_LONG, flags, AUD_END);
1550 return code;
1553 afs_int32
1554 ListDumps(struct rx_call *call, afs_int32 sflags, afs_int32 groupid,
1555 Date fromTime, Date toTime, budb_dumpsList *dumps,
1556 budb_dumpsList *flags)
1558 struct ubik_trans *ut;
1559 struct memoryHashTable *mht;
1560 struct dump diskDump, appDiskDump;
1561 dbadr dbAddr, dbAppAddr;
1563 afs_int32 eval, code = 0;
1564 int old, hash, length, entrySize, count = 0;
1566 if (!callPermitted(call))
1567 return BUDB_NOTPERMITTED;
1569 eval = InitRPC(&ut, LOCKREAD, 1);
1570 if (eval)
1571 return (eval);
1573 /* Search the database */
1574 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
1575 if (!mht)
1576 return (BUDB_BADARGUMENT);
1578 for (old = 0; old <= 1; old++) { /*o *//* old and new hash tables */
1579 length = (old ? mht->oldLength : mht->length);
1580 if (length == 0)
1581 continue;
1583 for (hash = 0; hash < length; hash++) { /*h *//* for each hash bucket */
1584 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) { /*d */
1586 /* read the entry */
1587 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
1588 if (eval)
1589 ABORT(eval);
1591 /* Skip appended dumps */
1592 if (ntohl(diskDump.initialDumpID) != 0) {
1593 continue;
1596 /* Skip dumps with different goup id */
1597 if ((sflags & BUDB_OP_GROUPID)
1598 && (ntohl(diskDump.tapes.id) != groupid)) {
1599 continue; /*nope */
1602 /* Look at this dump to see if it meets the criteria for listing */
1603 if (sflags & BUDB_OP_DATES) {
1604 /* This and each appended dump should be in time */
1605 for (dbAppAddr = dbAddr; dbAppAddr;
1606 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1607 eval =
1608 dbread(ut, dbAppAddr, &appDiskDump,
1609 sizeof(appDiskDump));
1610 if (eval)
1611 ABORT(eval);
1613 if ((ntohl(appDiskDump.id) < fromTime)
1614 || (ntohl(appDiskDump.id) > toTime))
1615 break; /*nope */
1617 if (dbAppAddr)
1618 continue; /*nope */
1621 /* Add it and each of its appended dump to our list to return */
1622 for (dbAppAddr = dbAddr; dbAppAddr;
1623 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1624 eval =
1625 dbread(ut, dbAppAddr, &appDiskDump,
1626 sizeof(appDiskDump));
1627 if (eval)
1628 ABORT(eval);
1630 /* Make sure we have space to list it */
1631 if (dumps->budb_dumpsList_len >= count) {
1632 count += 10;
1633 if (count == 10) {
1634 dumps->budb_dumpsList_val =
1635 malloc(count * sizeof(afs_int32));
1636 flags->budb_dumpsList_val =
1637 malloc(count * sizeof(afs_int32));
1638 } else {
1639 dumps->budb_dumpsList_val =
1640 realloc(dumps->budb_dumpsList_val,
1641 count * sizeof(afs_int32));
1642 flags->budb_dumpsList_val =
1643 realloc(flags->budb_dumpsList_val,
1644 count * sizeof(afs_int32));
1646 if (!dumps->budb_dumpsList_val
1647 || !dumps->budb_dumpsList_val)
1648 ABORT(BUDB_NOMEM);
1651 /* Add it to our list */
1652 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] =
1653 ntohl(appDiskDump.id);
1654 flags->budb_dumpsList_val[flags->budb_dumpsList_len] = 0;
1655 if (ntohl(appDiskDump.initialDumpID) != 0) {
1656 flags->budb_dumpsList_val[flags->
1657 budb_dumpsList_len] |=
1658 BUDB_OP_APPDUMP;
1660 if (strcmp(appDiskDump.dumpName, DUMP_TAPE_NAME) == 0) {
1661 flags->budb_dumpsList_val[flags->
1662 budb_dumpsList_len] |=
1663 BUDB_OP_DBDUMP;
1665 dumps->budb_dumpsList_len++;
1666 flags->budb_dumpsList_len++;
1668 } /*d */
1669 } /*h */
1670 } /*o */
1672 code = ubik_EndTrans(ut);
1673 return (code);
1675 abort_exit:
1676 ubik_AbortTrans(ut);
1677 return (code);
1680 afs_int32
1681 SBUDB_DeleteTape(struct rx_call *call,
1682 struct budb_tapeEntry *tape) /* tape info */
1684 afs_int32 code;
1686 code = DoDeleteTape(call, tape);
1687 osi_auditU(call, BUDB_DelTpeEvent, code, AUD_DATE,
1688 (tape ? tape->dump : 0), AUD_END);
1689 return code;
1692 afs_int32
1693 DoDeleteTape(struct rx_call *call,
1694 struct budb_tapeEntry *tape) /* tape info */
1696 struct ubik_trans *ut;
1697 struct tape t;
1698 dbadr a;
1699 afs_int32 eval, code;
1701 if (!callPermitted(call))
1702 return BUDB_NOTPERMITTED;
1704 eval = InitRPC(&ut, LOCKWRITE, 1);
1705 if (eval)
1706 return eval;
1708 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
1709 if (eval)
1710 ABORT(eval);
1712 eval = DeleteTape(ut, a, &t);
1713 if (eval)
1714 ABORT(eval);
1716 eval = FreeStructure(ut, tape_BLOCK, a);
1717 if (eval)
1718 ABORT(eval);
1720 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1721 if (eval)
1722 ABORT(eval);
1724 code = ubik_EndTrans(ut);
1725 return code;
1727 abort_exit:
1728 ubik_AbortTrans(ut);
1729 return code;
1732 /* BUDB_DeleteVDP
1733 * Deletes old information from the database for a particular dump path
1734 * and volumset. This supercedes the old policy implemented in
1735 * UseTape, which simply matched on the volumeset.dump. Consequently
1736 * it was unable to handle name re-use.
1737 * entry:
1738 * dsname - dumpset name, i.e. volumeset.dumpname
1739 * dumpPath - full path of dump node
1740 * curDumpID - current dump in progress - so that is may be excluded
1741 * exit:
1742 * 0 - ok
1743 * n - some error. May or may not have deleted information.
1746 afs_int32
1747 SBUDB_DeleteVDP(struct rx_call *call, char *dsname, char *dumpPath,
1748 afs_int32 curDumpId)
1750 afs_int32 code;
1752 code = DeleteVDP(call, dsname, dumpPath, curDumpId);
1753 osi_auditU(call, BUDB_DelVDPEvent, code, AUD_STR, dsname, AUD_END);
1754 return code;
1757 afs_int32
1758 DeleteVDP(struct rx_call *call, char *dsname, char *dumpPath,
1759 afs_int32 curDumpId)
1761 struct dump dump;
1762 dbadr dumpAddr;
1764 struct ubik_trans *ut;
1765 afs_int32 eval, code = 0;
1767 if (!callPermitted(call))
1768 return BUDB_NOTPERMITTED;
1770 while (1) {
1771 eval = InitRPC(&ut, LOCKREAD, 1);
1772 if (eval)
1773 return (eval);
1775 eval = ht_LookupEntry(ut, &db.dumpName, dsname, &dumpAddr, &dump);
1776 if (eval)
1777 ABORT(eval);
1779 while (dumpAddr != 0) { /*wd */
1780 if ((strcmp(dump.dumpName, dsname) == 0)
1781 && (strcmp(dump.dumpPath, dumpPath) == 0)
1782 && (ntohl(dump.id) != curDumpId)) {
1783 eval = ubik_EndTrans(ut);
1784 if (eval)
1785 return (eval);
1787 eval = deleteDump(call, ntohl(dump.id), 0);
1788 if (eval)
1789 return (eval);
1791 /* start the traversal over since the various chains may
1792 * have changed
1794 break;
1797 dumpAddr = ntohl(dump.nameHashChain);
1798 if (dumpAddr) {
1799 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
1800 if (eval)
1801 ABORT(eval);
1803 } /*wd */
1805 /* check if all the dumps have been examined - can terminate */
1806 if (!dumpAddr) {
1807 eval = ubik_EndTrans(ut);
1808 return (eval);
1812 abort_exit:
1813 ubik_AbortTrans(ut);
1814 return (code);
1817 /* BUDB_FindClone
1818 * notes:
1819 * Given a volume name, and a dumpID, find the volume in that dump and
1820 * return the clone date of the volume (this is the clone date of the
1821 * volume at the time it was dumped).
1823 * Hashes on the volume name and traverses the fragments. Will need to read
1824 * the volumes tape entry to determine if it belongs to the dump. If the
1825 * volume is not found in the dump, then look for it in its parent dump.
1828 afs_int32
1829 SBUDB_FindClone(struct rx_call *call, afs_int32 dumpID, char *volName,
1830 afs_int32 *clonetime)
1832 afs_int32 code;
1834 code = FindClone(call, dumpID, volName, clonetime);
1835 osi_auditU(call, BUDB_FndClnEvent, code, AUD_STR, volName, AUD_END);
1836 return code;
1839 afs_int32
1840 FindClone(struct rx_call *call, afs_int32 dumpID, char *volName,
1841 afs_int32 *clonetime)
1843 struct ubik_trans *ut;
1844 dbadr da, hvia, via, vfa;
1845 struct dump d;
1846 struct tape t;
1847 struct volFragment vf;
1848 struct volInfo vi;
1849 int rvi; /* read the volInfo struct */
1850 afs_int32 eval, code = 0;
1852 if (!callPermitted(call))
1853 return BUDB_NOTPERMITTED;
1855 eval = InitRPC(&ut, LOCKREAD, 1);
1856 if (eval)
1857 return (eval);
1859 *clonetime = 0;
1861 /* Search for the volume by name */
1862 eval = ht_LookupEntry(ut, &db.volName, volName, &hvia, &vi);
1863 if (eval)
1864 ABORT(eval);
1865 if (!hvia)
1866 ABORT(BUDB_NOVOLUMENAME);
1867 rvi = 0;
1869 /* Follw the dump levels up */
1870 for (; dumpID; dumpID = ntohl(d.parent)) { /*d */
1871 /* Get the dump entry */
1872 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &da, &d);
1873 if (eval)
1874 ABORT(eval);
1875 if (!da)
1876 ABORT(BUDB_NODUMPID);
1878 /* seach all the volInfo entries on the sameNameChain */
1879 for (via = hvia; via; via = ntohl(vi.sameNameChain)) { /*via */
1880 if (rvi) { /* Read the volInfo entry - except first time */
1881 eval = dbread(ut, via, &vi, sizeof(vi));
1882 if (eval)
1883 ABORT(eval);
1885 rvi = 1;
1887 /* search all the volFrag entries on the volFrag */
1888 for (vfa = ntohl(vi.firstFragment); vfa; vfa = ntohl(vf.sameNameChain)) { /*vfa */
1889 eval = dbread(ut, vfa, &vf, sizeof(vf)); /* Read the volFrag entry */
1890 if (eval)
1891 ABORT(eval);
1893 eval = dbread(ut, ntohl(vf.tape), &t, sizeof(t)); /* Read the tape */
1894 if (eval)
1895 ABORT(eval);
1897 /* Now check to see if this fragment belongs to the dump we have */
1898 if (ntohl(t.dump) == da) {
1899 *clonetime = ntohl(vf.clone); /* return the clone */
1900 ERROR(0);
1902 } /*vfa */
1903 } /*via */
1904 } /*d */
1906 error_exit:
1907 code = ubik_EndTrans(ut);
1908 return (code);
1910 abort_exit:
1911 ubik_EndTrans(ut);
1912 return (code);
1915 #ifdef notdef
1917 * Searches each tape and each volume in the dump until the volume is found.
1918 * If the volume is not in the dump, then we search it's parent dump.
1920 * Re-write to do lookups by volume name.
1922 afs_int32
1923 FindClone(struct rx_call *call, afs_int32 dumpID, char *volName,
1924 afs_int32 *clonetime)
1926 struct ubik_trans *ut;
1927 dbadr diskAddr, tapeAddr, volFragmentAddr;
1928 struct dump dump;
1929 struct tape tape;
1930 struct volFragment volFragment;
1931 struct volInfo volInfo;
1932 afs_int32 eval, code = 0;
1934 if (!callPermitted(call))
1935 return BUDB_NOTPERMITTED;
1937 eval = InitRPC(&ut, LOCKREAD, 1);
1938 if (eval)
1939 return (eval);
1941 *clonetime = 0;
1943 for (; dumpID; dumpID = ntohl(dump.parent)) { /*d */
1944 /* Get the dump entry */
1945 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &diskAddr, &dump);
1946 if (eval)
1947 ABORT(eval);
1948 if (!diskAddr)
1949 ABORT(BUDB_NODUMPID);
1951 /* just to be sure */
1952 if (ntohl(dump.id) != dumpID) {
1953 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID,
1954 ntohl(dump.id));
1955 ABORT(BUDB_INTERNALERROR);
1958 /* search all the tapes in this dump */
1959 for (tapeAddr = ntohl(dump.firstTape); tapeAddr; tapeAddr = ntohl(tape.nextTape)) { /*t */
1960 /* Get the tape entry */
1961 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
1962 if (eval)
1963 ABORT(eval);
1965 /* search all the volume fragments on this tape */
1966 for (volFragmentAddr = ntohl(tape.firstVol); volFragmentAddr; volFragmentAddr = ntohl(volFragment.sameTapeChain)) { /*vf */
1967 /* Get the volume fragment entry */
1968 eval =
1969 dbread(ut, volFragmentAddr, &volFragment,
1970 sizeof(volFragment));
1971 if (eval)
1972 ABORT(eval);
1974 /* Get the volume info entry */
1975 eval =
1976 dbread(ut, ntohl(volFragment.vol), &volInfo,
1977 sizeof(volInfo));
1978 if (eval)
1979 ABORT(eval);
1981 /* check if this volume is the one we want */
1982 if (strcmp(volInfo.name, volName) == 0) {
1983 *clonetime = ntohl(volFragment.clone);
1984 ERROR(0);
1986 } /*vf */
1987 } /*t */
1988 } /*d */
1990 error_exit:
1991 code = ubik_EndTrans(ut);
1992 return (code);
1994 abort_exit:
1995 ubik_EndTrans(ut);
1996 return (code);
1998 #endif
2000 /* BUDB_FindDump
2001 * Find latest volume dump before adate.
2002 * Used by restore code when restoring a user requested volume(s)
2003 * entry:
2004 * volumeName - name of volume to match on
2005 * beforeDate - look for dumps older than this date
2006 * exit:
2007 * deptr - descriptor of most recent dump
2010 afs_int32
2011 SBUDB_FindDump(struct rx_call *call, char *volumeName, afs_int32 beforeDate,
2012 struct budb_dumpEntry *deptr)
2014 afs_int32 code;
2016 code = FindDump(call, volumeName, beforeDate, deptr);
2017 osi_auditU(call, BUDB_FndDmpEvent, code, AUD_STR, volumeName, AUD_END);
2018 return code;
2021 afs_int32
2022 FindDump(struct rx_call *call, char *volumeName, afs_int32 beforeDate,
2023 struct budb_dumpEntry *deptr)
2025 struct ubik_trans *ut;
2026 dbadr volInfoAddr, volFragmentAddr;
2027 struct tape tape;
2028 struct volInfo volInfo;
2029 struct volFragment volFragment;
2031 dbadr selectedDumpAddr = 0;
2032 afs_int32 selectedDate = 0;
2033 afs_int32 volCloned;
2034 int rvoli;
2035 afs_int32 eval, code = 0;
2037 if (!callPermitted(call))
2038 return BUDB_NOTPERMITTED;
2040 eval = InitRPC(&ut, LOCKREAD, 1);
2041 if (eval)
2042 return eval;
2044 /* Find volinfo struct for volume name in hash table */
2045 eval =
2046 ht_LookupEntry(ut, &db.volName, volumeName, &volInfoAddr, &volInfo);
2047 if (eval)
2048 ABORT(eval);
2049 if (!volInfoAddr)
2050 ABORT(BUDB_NOVOLUMENAME);
2052 /* Step through all the volinfo structures on the same name chain.
2053 * No need to read the first - we read it above.
2055 for (rvoli = 0; volInfoAddr;
2056 rvoli = 1, volInfoAddr = ntohl(volInfo.sameNameChain)) {
2057 if (rvoli) { /* read the volinfo structure */
2058 eval = dbread(ut, volInfoAddr, &volInfo, sizeof(volInfo));
2059 if (eval)
2060 ABORT(eval);
2063 /* step through the volfrag structures */
2064 for (volFragmentAddr = ntohl(volInfo.firstFragment); volFragmentAddr;
2065 volFragmentAddr = ntohl(volFragment.sameNameChain)) {
2066 /* read the volfrag struct */
2067 eval =
2068 dbread(ut, volFragmentAddr, &volFragment,
2069 sizeof(volFragment));
2070 if (eval)
2071 ABORT(eval);
2073 volCloned = ntohl(volFragment.clone);
2075 /* now we can examine the date for most recent dump */
2076 if ((volCloned > selectedDate) && (volCloned < beforeDate)) {
2077 /* from the volfrag struct, read the tape struct */
2078 eval =
2079 dbread(ut, ntohl(volFragment.tape), &tape, sizeof(tape));
2080 if (eval)
2081 ABORT(eval);
2083 selectedDate = volCloned;
2084 selectedDumpAddr = ntohl(tape.dump);
2089 if (!selectedDumpAddr)
2090 ABORT(BUDB_NOENT);
2092 eval = FillDumpEntry(ut, selectedDumpAddr, deptr);
2093 if (eval)
2094 ABORT(eval);
2096 code = ubik_EndTrans(ut);
2097 return (code);
2099 abort_exit:
2100 ubik_EndTrans(ut);
2101 return (code);
2104 /* BUDB_FindLatestDump
2105 * Find the latest dump of volumeset vsname with dump name dname.
2106 * entry:
2107 * vsname - volumeset name
2108 * dname - dumpname
2111 afs_int32
2112 SBUDB_FindLatestDump(struct rx_call *call, char *vsname, char *dumpPath,
2113 struct budb_dumpEntry *dumpentry)
2115 afs_int32 code;
2117 code = FindLatestDump(call, vsname, dumpPath, dumpentry);
2118 osi_auditU(call, BUDB_FndLaDEvent, code, AUD_STR, vsname, AUD_END);
2119 return code;
2122 afs_int32
2123 FindLatestDump(struct rx_call *call, char *vsname, char *dumpPath,
2124 struct budb_dumpEntry *dumpentry)
2126 struct ubik_trans *ut;
2127 dbadr curdbaddr, retdbaddr, firstdbaddr;
2128 struct dump d;
2129 Date latest;
2130 char dumpName[BU_MAXNAMELEN + 2];
2131 afs_int32 eval, code = 0;
2133 if (!callPermitted(call))
2134 return BUDB_NOTPERMITTED;
2136 eval = InitRPC(&ut, LOCKREAD, 1);
2137 if (eval)
2138 return (eval);
2140 if ((strcmp(vsname, "") == 0) && (strcmp(dumpPath, "") == 0)) {
2141 /* Construct a database dump name */
2142 strcpy(dumpName, DUMP_TAPE_NAME);
2143 } else if (strchr(dumpPath, '/') == 0) {
2144 int level, old, length, hash;
2145 struct dump hostDump, diskDump;
2146 struct memoryHashTable *mht;
2147 int entrySize;
2148 dbadr dbAddr;
2149 afs_uint32 bestDumpId = 0;
2151 level = atoi(dumpPath);
2152 if (level < 0) {
2153 ABORT(BUDB_BADARGUMENT);
2156 /* Brute force search of all the dumps in the database - yuck! */
2158 retdbaddr = 0;
2159 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
2160 if (!mht)
2161 ABORT(BUDB_BADARGUMENT);
2163 for (old = 0; old <= 1; old++) { /*fo */
2164 length = (old ? mht->oldLength : mht->length);
2165 if (!length)
2166 continue;
2168 for (hash = 0; hash < length; hash++) {
2169 /*f */
2170 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr;
2171 dbAddr = hostDump.idHashChain) {
2172 /*w */
2173 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
2174 if (eval)
2175 ABORT(eval);
2176 dump_ntoh(&diskDump, &hostDump);
2178 if ((strcmp(hostDump.volumeSet, vsname) == 0) && /* the volumeset */
2179 (hostDump.level == level) && /* same level */
2180 (hostDump.id > bestDumpId)) { /* more recent */
2181 bestDumpId = hostDump.id;
2182 retdbaddr = dbAddr;
2184 } /*w */
2185 } /*f */
2186 } /*fo */
2187 if (!retdbaddr)
2188 ABORT(BUDB_NODUMPNAME);
2190 goto finished;
2191 } else {
2192 /* construct the name of the dump */
2193 if ((strlen(vsname) + strlen(tailCompPtr(dumpPath))) > BU_MAXNAMELEN)
2194 ABORT(BUDB_NODUMPNAME);
2196 strcpy(dumpName, vsname);
2197 strcat(dumpName, ".");
2198 strcat(dumpName, tailCompPtr(dumpPath));
2201 LogDebug(5, "lookup on :%s:\n", dumpName);
2203 /* Lookup on dumpname in hash table */
2204 eval = ht_LookupEntry(ut, &db.dumpName, dumpName, &firstdbaddr, &d);
2205 if (eval)
2206 ABORT(eval);
2208 latest = 0;
2209 retdbaddr = 0;
2211 /* folow remaining dumps in hash chain, looking for most latest dump */
2212 for (curdbaddr = firstdbaddr; curdbaddr;
2213 curdbaddr = ntohl(d.nameHashChain)) {
2214 if (curdbaddr != firstdbaddr) {
2215 eval = dbread(ut, curdbaddr, &d, sizeof(d));
2216 if (eval)
2217 ABORT(eval);
2220 if ((strcmp(d.dumpPath, dumpPath) == 0) && /* Same dumppath */
2221 (strcmp(d.dumpName, dumpName) == 0) && /* Same dumpname */
2222 (ntohl(d.created) > latest)) { /* most recent */
2223 latest = ntohl(d.created);
2224 retdbaddr = curdbaddr;
2227 if (!retdbaddr)
2228 ABORT(BUDB_NODUMPNAME);
2230 finished:
2231 /* return the dump found */
2232 FillDumpEntry(ut, retdbaddr, dumpentry);
2234 code = ubik_EndTrans(ut);
2235 return (code);
2237 abort_exit:
2238 ubik_AbortTrans(ut);
2239 return (code);
2243 afs_int32
2244 SBUDB_FinishDump(struct rx_call *call, struct budb_dumpEntry *dump)
2246 afs_int32 code;
2248 code = FinishDump(call, dump);
2249 osi_auditU(call, BUDB_FinDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
2250 AUD_END);
2251 return code;
2254 afs_int32
2255 FinishDump(struct rx_call *call, struct budb_dumpEntry *dump)
2257 struct ubik_trans *ut;
2258 dbadr a;
2259 struct dump d;
2260 afs_int32 eval, code = 0;
2262 if (!callPermitted(call))
2263 return BUDB_NOTPERMITTED;
2265 eval = InitRPC(&ut, LOCKWRITE, 1);
2266 if (eval)
2267 return eval;
2269 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &a, &d);
2270 if (eval)
2271 ABORT(eval);
2272 if (!a)
2273 ABORT(BUDB_NODUMPID);
2275 if ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)
2276 ABORT(BUDB_DUMPNOTINUSE);
2278 d.flags = htonl(dump->flags & ~BUDB_DUMP_INPROGRESS);
2280 /* if creation time specified set it */
2281 if (dump->created)
2282 d.created = htonl(dump->created);
2283 dump->created = ntohl(d.created);
2285 /* Write the dump entry out */
2286 eval = dbwrite(ut, a, &d, sizeof(d));
2287 if (eval)
2288 ABORT(eval);
2290 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2291 if (eval)
2292 ABORT(eval);
2294 code = ubik_EndTrans(ut);
2295 return code;
2297 abort_exit:
2298 ubik_AbortTrans(ut);
2299 return code;
2302 afs_int32
2303 SBUDB_FinishTape(struct rx_call *call, struct budb_tapeEntry *tape)
2305 afs_int32 code;
2307 code = FinishTape(call, tape);
2308 osi_auditU(call, BUDB_FinTpeEvent, code, AUD_DATE,
2309 (tape ? tape->dump : 0), AUD_END);
2310 return code;
2313 afs_int32
2314 FinishTape(struct rx_call *call, struct budb_tapeEntry *tape)
2316 struct ubik_trans *ut;
2317 dbadr a;
2318 struct tape t;
2319 struct dump d;
2320 afs_int32 eval, code = 0;
2322 if (!callPermitted(call))
2323 return BUDB_NOTPERMITTED;
2325 eval = InitRPC(&ut, LOCKWRITE, 1);
2326 if (eval)
2327 return eval;
2329 /* find the tape struct in the tapename hash chain */
2330 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
2331 if (eval)
2332 ABORT(eval);
2333 if (!a)
2334 ABORT(BUDB_NOTAPENAME);
2336 /* Read the dump structure */
2337 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2338 if (eval)
2339 ABORT(eval);
2341 /* search for the right tape on the rest of the chain */
2342 while (ntohl(d.id) != tape->dump) {
2343 a = ntohl(t.nameHashChain);
2344 if (!a)
2345 ABORT(BUDB_NOTAPENAME);
2347 eval = dbread(ut, a, &t, sizeof(t));
2348 if (eval)
2349 ABORT(eval);
2351 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2352 if (eval)
2353 ABORT(eval);
2356 if ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0)
2357 ABORT(BUDB_TAPENOTINUSE);
2359 /* t.nBytes = htonl(tape->nBytes); */
2360 t.nFiles = htonl(tape->nFiles);
2361 t.useKBytes = htonl(tape->useKBytes);
2362 t.flags = htonl(tape->flags & ~BUDB_TAPE_BEINGWRITTEN);
2364 eval = dbwrite(ut, a, &t, sizeof(t));
2365 if (eval)
2366 ABORT(BUDB_IO);
2368 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2369 if (eval)
2370 ABORT(eval);
2372 code = ubik_EndTrans(ut);
2373 return code;
2375 abort_exit:
2376 ubik_AbortTrans(ut);
2377 return code;
2380 /* BUDB_GetDumps
2381 * return a set of dumps that match the specified criteria
2382 * entry:
2383 * call - rx call
2384 * majorVersion - version of interface structures. Permits compatibility
2385 * checks to be made
2386 * flags - for search and select operations. Broken down into flags
2387 * for name, start point, end point and time.
2388 * name - name to search for. Interpretation based on flags
2389 * end
2390 * index
2391 * nextIndexP
2392 * dbTimeP
2393 * exit:
2394 * nextIndexP
2395 * dbTimeP - time at which the database was last modified. Up to
2396 * caller (client) to take appropriate action if database
2397 * modified between successive calls
2398 * dumps - list of matching dumps
2399 * notes:
2400 * currently supported are:
2401 * BUDB_OP_DUMPNAME
2402 * BUDB_OP_DUMPID
2405 afs_int32
2406 SBUDB_GetDumps(struct rx_call *call,
2407 afs_int32 majorVersion, /* version of interface structures */
2408 afs_int32 flags, /* search & select controls */
2409 char *name, /* s&s parameters */
2410 afs_int32 start,
2411 afs_int32 end,
2412 afs_int32 index, /* start index of returned entries */
2413 afs_int32 *nextIndexP, /* output index for next call */
2414 afs_int32 *dbTimeP,
2415 budb_dumpList *dumps) /* pointer to buffer */
2417 afs_int32 code;
2419 code =
2420 GetDumps(call, majorVersion, flags, name, start, end, index,
2421 nextIndexP, dbTimeP, dumps);
2422 osi_auditU(call, BUDB_GetDmpEvent, code, AUD_END);
2423 return code;
2426 afs_int32
2427 GetDumps(struct rx_call *call,
2428 afs_int32 majorVersion, /* version of interface structures */
2429 afs_int32 flags, /* search & select controls */
2430 char *name, /* s&s parameters */
2431 afs_int32 start,
2432 afs_int32 end,
2433 afs_int32 index, /* start index of returned entries */
2434 afs_int32 *nextIndexP, /* output index for next call */
2435 afs_int32 *dbTimeP,
2436 budb_dumpList *dumps) /* pointer to buffer */
2438 struct ubik_trans *ut;
2439 dbadr da;
2440 struct dump d;
2441 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2442 afs_int32 eval, code = 0;
2443 afs_int32 toskip;
2444 struct returnList list;
2446 /* Don't check permissions when we look up a specific dump id */
2447 if (((flags & BUDB_OP_STARTS) != BUDB_OP_DUMPID) && !callPermitted(call))
2448 return BUDB_NOTPERMITTED;
2450 if (majorVersion != BUDB_MAJORVERSION)
2451 return BUDB_OLDINTERFACE;
2452 if (index < 0)
2453 return BUDB_ENDOFLIST;
2455 eval = InitRPC(&ut, LOCKREAD, 1);
2456 if (eval)
2457 return eval;
2459 nameFlags = flags & BUDB_OP_NAMES;
2460 startFlags = flags & BUDB_OP_STARTS;
2461 endFlags = flags & BUDB_OP_ENDS;
2462 timeFlags = flags & BUDB_OP_TIMES;
2464 InitReturnList(&list);
2465 toskip = index;
2467 if (nameFlags == BUDB_OP_DUMPNAME) {
2468 /* not yet implemented */
2469 if (startFlags || endFlags || timeFlags)
2470 ABORT(BUDB_BADFLAGS);
2472 eval = ht_LookupEntry(ut, &db.dumpName, name, &da, &d);
2473 if (eval)
2474 ABORT(eval);
2475 if (!da)
2476 ABORT(BUDB_NODUMPNAME);
2478 while (1) {
2479 if (strcmp(d.dumpName, name) == 0) {
2480 eval = AddToReturnList(&list, da, &toskip);
2481 if (eval == BUDB_LIST2BIG)
2482 break;
2483 if (eval)
2484 ABORT(eval);
2487 da = ntohl(d.nameHashChain); /* get next dump w/ name */
2488 if (!da)
2489 break;
2491 eval = dbread(ut, da, &d, sizeof(d));
2492 if (eval)
2493 ABORT(eval);
2495 } else if (nameFlags == BUDB_OP_VOLUMENAME) {
2496 #ifdef PA
2497 struct volInfo vi;
2499 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2500 ABORT(BUDB_BADFLAGS);
2503 if (startFlags != BUDB_OP_STARTTIME)
2504 ABORT(BUDB_BADFLAGS);
2506 /* lookup a dump by volumename and time stamp. Find the most recent
2507 * dump of the specified volumename, that occured before the supplied
2508 * time
2511 /* get us a volInfo for name */
2512 eval = ht_LookupEntry(ut, &db.volName, name, &da, &vi);
2513 if (eval)
2514 ABORT(eval);
2516 while (1) {
2517 /* now iterate over all the entries of this name */
2518 for (va = vi.firstFragment; va != 0; va = v.sameNameChain) {
2519 va = ntohl(va);
2520 eval = dbread(ut, va, &v, sizeof(v));
2521 if (eval)
2522 ABORT(eval);
2524 if date
2525 on fragment > date ignore it - too recent;
2527 if (date on fragment < date && date on fragment > bestfound)
2528 bestfound = date on fragment;
2530 } /* for va */
2532 da = vi.sameNameChain;
2533 if (da == 0)
2534 break;
2535 da = ntohl(da);
2536 eval = dbread(ut, da, &vi, sizeof(vi));
2537 if (eval)
2538 ABORT(eval);
2542 if nothing found
2543 return error
2545 from saved volfragment address, compute dump.
2546 otherwise, return dump found
2549 #endif /* PA */
2551 } else if (startFlags == BUDB_OP_DUMPID) {
2552 if (endFlags || timeFlags)
2553 ABORT(BUDB_BADFLAGS);
2554 if (nameFlags)
2555 ABORT(BUDB_BADFLAGS); /* NYI */
2557 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
2558 if (eval)
2559 ABORT(eval);
2560 if (!da)
2561 ABORT(BUDB_NODUMPID);
2563 eval = AddToReturnList(&list, da, &toskip);
2564 if (eval)
2565 ABORT(eval);
2566 } else if (endFlags == BUDB_OP_NPREVIOUS) {
2567 struct wantDumpRock rock;
2568 struct chosenDump *ptr, *nextPtr;
2570 /* no other flags should be set */
2572 /* end specifies how many dumps */
2573 if (!end)
2574 ABORT(BUDB_BADFLAGS);
2576 memset(&rock, 0, sizeof(rock));
2577 rock.maxDumps = end;
2579 scanHashTable(ut, &db.dumpName, wantDump, rememberDump,
2580 (char *)&rock);
2582 for (ptr = rock.chain; ptr; ptr = nextPtr) {
2583 nextPtr = ptr->next;
2584 AddToReturnList(&list, ptr->addr, &toskip); /* ignore error for free */
2585 free(ptr);
2587 } else {
2588 ABORT(BUDB_BADFLAGS);
2591 eval =
2592 SendReturnList(ut, &list, FillDumpEntry,
2593 sizeof(struct budb_dumpEntry), index, nextIndexP,
2594 dbTimeP, (returnList_t) dumps);
2595 if (eval)
2596 ABORT(eval);
2598 FreeReturnList(&list);
2599 code = ubik_EndTrans(ut);
2600 return code;
2602 abort_exit:
2603 FreeReturnList(&list);
2604 ubik_AbortTrans(ut);
2605 return code;
2609 * Get the expiration of a tape. Since the dump could have appended dumps,
2610 * we should use the most recent expiration date. Put the most recent
2611 * expiration tape into the given tape structure.
2613 afs_int32
2614 getExpiration(struct ubik_trans *ut, struct tape *tapePtr)
2616 dbadr ad;
2617 struct dump d;
2618 struct tape t;
2619 afs_int32 initDump;
2620 afs_int32 eval, code = 0;
2622 if (!tapePtr)
2623 ERROR(0);
2625 /* Get the dump for this tape */
2626 ad = ntohl(tapePtr->dump);
2627 eval = dbread(ut, ad, &d, sizeof(d));
2628 if (eval)
2629 ERROR(eval);
2631 /* If not an initial dump, get the initial dump */
2632 if (d.initialDumpID) {
2633 initDump = ntohl(d.initialDumpID);
2634 eval = ht_LookupEntry(ut, &db.dumpIden, &initDump, &ad, &d);
2635 if (eval)
2636 ERROR(eval);
2639 /* Cycle through the dumps and appended dumps */
2640 while (ad) {
2641 /* Get the first tape in this dump. No need to check the rest of the tapes */
2642 /* for this dump since they will all have the same expiration date */
2643 eval = dbread(ut, ntohl(d.firstTape), &t, sizeof(t));
2644 if (eval)
2645 ERROR(eval);
2647 /* Take the greater of the expiration dates */
2648 if (ntohl(tapePtr->expires) < ntohl(t.expires))
2649 tapePtr->expires = t.expires;
2651 /* Step to and read the next appended dump */
2652 if ((ad = ntohl(d.appendedDumpChain))) {
2653 eval = dbread(ut, ad, &d, sizeof(d));
2654 if (eval)
2655 ERROR(eval);
2659 error_exit:
2660 return (code);
2663 /* Mark the following dump as appended to another, intial dump */
2664 afs_int32
2665 makeAppended(struct ubik_trans *ut, afs_int32 appendedDumpID,
2666 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2668 dbadr ada, da, lastDumpAddr;
2669 struct dump ad, d;
2670 afs_int32 eval, code = 0;
2672 if (!initialDumpID)
2673 ERROR(0);
2674 if (appendedDumpID == initialDumpID)
2675 ERROR(BUDB_INTERNALERROR);
2677 /* If there is an initial dump, append this dump to it */
2678 /* Find the appended dump via its id */
2679 eval = ht_LookupEntry(ut, &db.dumpIden, &appendedDumpID, &ada, &ad);
2680 if (eval)
2681 ERROR(eval);
2683 /* If the dump is already marked as appended,
2684 * then we have an internal error.
2686 if (ad.initialDumpID) {
2687 if (ntohl(ad.initialDumpID) != initialDumpID)
2688 ERROR(BUDB_INTERNALERROR);
2691 /* Update the appended dump to point to the initial dump */
2692 ad.initialDumpID = htonl(initialDumpID);
2693 ad.tapes.b = htonl(startTapeSeq);
2695 /* find the initial dump via its id */
2696 eval = ht_LookupEntry(ut, &db.dumpIden, &initialDumpID, &da, &d);
2697 if (eval)
2698 ERROR(eval);
2700 /* Update the appended dump's tape format with that of the initial */
2701 strcpy(ad.tapes.format, d.tapes.format);
2703 /* starting with the initial dump step through its appended dumps till
2704 * we reach the last appended dump.
2706 lastDumpAddr = da;
2707 while (d.appendedDumpChain) {
2708 lastDumpAddr = ntohl(d.appendedDumpChain);
2709 if (lastDumpAddr == ada)
2710 ERROR(0); /* Already appended */
2711 eval = dbread(ut, lastDumpAddr, &d, sizeof(d));
2712 if (eval)
2713 ERROR(eval);
2716 /* Update the last dump to point to our new appended dump.
2717 * The appended dump is the last one in the dump chain.
2719 d.appendedDumpChain = htonl(ada);
2720 ad.appendedDumpChain = 0;
2722 /* Write the appended dump and the initial dump */
2723 eval = dbwrite(ut, ada, (char *)&ad, sizeof(ad));
2724 if (eval)
2725 ERROR(eval);
2727 eval = dbwrite(ut, lastDumpAddr, (char *)&d, sizeof(d));
2728 if (eval)
2729 ERROR(eval);
2731 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2732 if (eval)
2733 ERROR(eval);
2735 error_exit:
2736 return (code);
2739 afs_int32
2740 SBUDB_MakeDumpAppended(struct rx_call *call, afs_int32 appendedDumpID,
2741 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2743 afs_int32 code;
2745 code =
2746 MakeDumpAppended(call, appendedDumpID, initialDumpID, startTapeSeq);
2747 osi_auditU(call, BUDB_AppDmpEvent, code, AUD_LONG, appendedDumpID,
2748 AUD_END);
2749 return code;
2752 afs_int32
2753 MakeDumpAppended(struct rx_call *call, afs_int32 appendedDumpID,
2754 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2756 struct ubik_trans *ut;
2757 afs_int32 eval, code = 0;
2759 if (!callPermitted(call))
2760 return BUDB_NOTPERMITTED;
2762 eval = InitRPC(&ut, LOCKWRITE, 1);
2763 if (eval)
2764 return (eval);
2766 eval = makeAppended(ut, appendedDumpID, initialDumpID, startTapeSeq);
2767 if (eval)
2768 ABORT(eval);
2770 code = ubik_EndTrans(ut);
2771 return (code);
2773 abort_exit:
2774 ubik_AbortTrans(ut);
2775 return (code);
2778 /* Find the last tape of a dump-set. This includes any appended dumps */
2779 afs_int32
2780 SBUDB_FindLastTape(struct rx_call *call, afs_int32 dumpID,
2781 struct budb_dumpEntry *dumpEntry,
2782 struct budb_tapeEntry *tapeEntry,
2783 struct budb_volumeEntry *volEntry)
2785 afs_int32 code;
2787 code = FindLastTape(call, dumpID, dumpEntry, tapeEntry, volEntry);
2788 osi_auditU(call, BUDB_FndLTpeEvent, code, AUD_LONG, dumpID, AUD_END);
2789 return code;
2792 afs_int32
2793 FindLastTape(struct rx_call *call, afs_int32 dumpID,
2794 struct budb_dumpEntry *dumpEntry,
2795 struct budb_tapeEntry *tapeEntry,
2796 struct budb_volumeEntry *volEntry)
2798 struct ubik_trans *ut;
2799 struct dump d;
2800 dbadr lastDump;
2801 struct tape t;
2802 dbadr lastTape, thisTape;
2803 afs_int32 lastTapeSeq;
2804 struct volFragment vf;
2805 dbadr lastVol, thisVol;
2806 afs_int32 lastVolPos;
2807 afs_int32 eval, code = 0;
2809 if (!callPermitted(call))
2810 return BUDB_NOTPERMITTED;
2812 if (!dumpID)
2813 return (BUDB_BADARGUMENT);
2815 eval = InitRPC(&ut, LOCKREAD, 1);
2816 if (eval)
2817 return (eval);
2819 /* find and read its initial dump via its id */
2820 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &lastDump, &d);
2821 if (eval)
2822 ABORT(eval);
2823 if (!lastDump)
2824 ABORT(BUDB_NODUMPID);
2826 /* Follow the append dumps link chain until we reach the last dump */
2827 while (d.appendedDumpChain) {
2828 lastDump = ntohl(d.appendedDumpChain);
2829 eval = dbread(ut, lastDump, &d, sizeof(d));
2830 if (eval)
2831 ABORT(eval);
2834 /* We now have the last dump of the last appended dump */
2835 /* Copy this into our return structure */
2836 eval = FillDumpEntry(ut, lastDump, dumpEntry);
2837 if (eval)
2838 ABORT(eval);
2840 /* Fail if the last dump has no tapes */
2841 if (!d.firstTape)
2842 ABORT(BUDB_NOTAPENAME);
2844 /* Follow the tapes in this dump until we reach the last tape */
2845 eval = dbread(ut, ntohl(d.firstTape), &t, sizeof(t));
2846 if (eval)
2847 ABORT(eval);
2849 lastTape = ntohl(d.firstTape);
2850 lastTapeSeq = ntohl(t.seq);
2851 lastVol = ntohl(t.firstVol);
2853 while (t.nextTape) {
2854 thisTape = ntohl(t.nextTape);
2855 eval = dbread(ut, thisTape, &t, sizeof(t));
2856 if (eval)
2857 ABORT(eval);
2859 if (ntohl(t.seq) > lastTapeSeq) {
2860 lastTape = thisTape;
2861 lastTapeSeq = ntohl(t.seq);
2862 lastVol = ntohl(t.firstVol);
2866 /* We now have the last tape of the last appended dump */
2867 /* Copy this into our return structure */
2868 eval = FillTapeEntry(ut, lastTape, tapeEntry);
2869 if (eval)
2870 ABORT(eval);
2872 /* Zero volume entry if the last tape has no volumes */
2873 if (!lastVol) {
2874 memset(volEntry, 0, sizeof(*volEntry));
2875 } else {
2876 /* Follow the volumes until we reach the last volume */
2877 eval = dbread(ut, lastVol, &vf, sizeof(vf));
2878 if (eval)
2879 ABORT(eval);
2881 lastVolPos = vf.position;
2883 while (vf.sameTapeChain) {
2884 thisVol = ntohl(vf.sameTapeChain);
2885 eval = dbread(ut, thisVol, &vf, sizeof(vf));
2886 if (eval)
2887 ABORT(eval);
2889 if (vf.position > lastVolPos) {
2890 lastVol = thisVol;
2891 lastVolPos = vf.position;
2895 /* We now have the last volume of this tape */
2896 /* Copy this into our return structure */
2897 eval = FillVolEntry(ut, lastVol, volEntry);
2898 if (eval)
2899 ABORT(eval);
2902 eval = ubik_EndTrans(ut);
2903 if (!code)
2904 code = eval;
2905 return (code);
2907 abort_exit:
2908 ubik_AbortTrans(ut);
2909 return (code);
2913 afs_int32
2914 SBUDB_GetTapes(struct rx_call *call,
2915 afs_int32 majorVersion, /* version of interface structures */
2916 afs_int32 flags, /* search & select controls */
2917 char *name, /* s&s parameters */
2918 afs_int32 start,
2919 afs_int32 end, /* reserved: MBZ */
2920 afs_int32 index, /* start index of returned entries */
2921 afs_int32 *nextIndexP, /* output index for next call */
2922 afs_int32 *dbTimeP,
2923 budb_tapeList *tapes) /* pointer to buffer */
2925 afs_int32 code;
2927 code =
2928 GetTapes(call, majorVersion, flags, name, start, end, index,
2929 nextIndexP, dbTimeP, tapes);
2930 osi_auditU(call, BUDB_GetTpeEvent, code, AUD_END);
2931 return code;
2934 afs_int32
2935 GetTapes(struct rx_call *call,
2936 afs_int32 majorVersion, /* version of interface structures */
2937 afs_int32 flags, /* search & select controls */
2938 char *name, /* s&s parameters */
2939 afs_int32 start,
2940 afs_int32 end, /* reserved: MBZ */
2941 afs_int32 index, /* start index of returned entries */
2942 afs_int32 *nextIndexP, /* output index for next call */
2943 afs_int32 *dbTimeP,
2944 budb_tapeList *tapes) /* pointer to buffer */
2946 struct ubik_trans *ut;
2947 dbadr da, ta;
2948 struct dump d;
2949 struct tape t;
2950 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2951 struct returnList list;
2952 afs_int32 eval, code = 0;
2953 afs_int32 toskip;
2955 if (!callPermitted(call))
2956 return BUDB_NOTPERMITTED;
2958 if (majorVersion != BUDB_MAJORVERSION)
2959 return BUDB_OLDINTERFACE;
2961 if (index < 0)
2962 return BUDB_ENDOFLIST;
2964 eval = InitRPC(&ut, LOCKREAD, 1);
2965 if (eval)
2966 return eval;
2968 nameFlags = flags & BUDB_OP_NAMES;
2969 startFlags = flags & BUDB_OP_STARTS;
2970 endFlags = flags & BUDB_OP_ENDS;
2971 timeFlags = flags & BUDB_OP_TIMES;
2973 InitReturnList(&list);
2974 toskip = index;
2976 if (nameFlags == BUDB_OP_TAPENAME) { /*it */
2977 eval = ht_LookupEntry(ut, &db.tapeName, name, &ta, &t);
2978 if (eval)
2979 ABORT(eval);
2980 if (!ta)
2981 ABORT(BUDB_NOTAPENAME);
2983 /* NYI */
2984 if ((startFlags & ~BUDB_OP_DUMPID) || endFlags || timeFlags)
2985 ABORT(BUDB_BADFLAGS);
2987 /* follow the hash chain to the end */
2988 while (ta) { /*w */
2989 if (startFlags & BUDB_OP_DUMPID) {
2990 /* read in the dump */
2991 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2992 if (eval)
2993 ABORT(eval);
2995 /* check if both name and dump id match */
2996 if ((strcmp(name, t.name) == 0) && (ntohl(d.id) == start)) {
2997 eval = AddToReturnList(&list, ta, &toskip);
2998 if (eval && (eval != BUDB_LIST2BIG))
2999 ABORT(eval);
3000 break;
3002 } else {
3003 /* Add to return list and continue search */
3004 if (strcmp(name, t.name) == 0) {
3005 eval = AddToReturnList(&list, ta, &toskip);
3006 if (eval == BUDB_LIST2BIG)
3007 break;
3008 if (eval)
3009 ABORT(eval);
3013 ta = ntohl(t.nameHashChain);
3014 if (ta)
3015 dbread(ut, ta, &t, sizeof(t));
3016 } /*w */
3017 } /*it */
3018 else if (nameFlags == BUDB_OP_TAPESEQ) {
3019 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
3020 if (eval)
3021 ABORT(eval);
3022 if (!da)
3023 ABORT(BUDB_NODUMPNAME);
3025 /* search for the right tape */
3026 ta = ntohl(d.firstTape);
3027 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
3028 eval = dbread(ut, ta, &t, sizeof(t));
3029 if (eval)
3030 ABORT(eval);
3032 if (ntohl(t.seq) == end) {
3033 eval = AddToReturnList(&list, ta, &toskip);
3034 if (eval && (eval != BUDB_LIST2BIG))
3035 ABORT(eval);
3036 break;
3039 } else {
3040 ABORT(BUDB_BADFLAGS);
3043 eval =
3044 SendReturnList(ut, &list, FillTapeEntry,
3045 sizeof(struct budb_tapeEntry), index, nextIndexP,
3046 dbTimeP, (returnList_t) tapes);
3047 if (eval)
3048 ABORT(eval);
3050 FreeReturnList(&list);
3051 code = ubik_EndTrans(ut);
3052 return code;
3054 abort_exit:
3055 FreeReturnList(&list);
3056 ubik_AbortTrans(ut);
3057 return (code);
3060 /* BUDB_GetVolumes
3061 * get a set of volumes according to the specified criteria.
3062 * See BUDB_GetDumps for general information on parameters
3063 * Currently supports:
3064 * 1) volume match - returns volumes based on volume name only.
3065 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
3066 * and start is a dumpid. Returns all volumes of the specified
3067 * name on the selected dumpid.
3070 afs_int32
3071 SBUDB_GetVolumes(struct rx_call *call,
3072 afs_int32 majorVersion, /* version of interface structures */
3073 afs_int32 flags, /* search & select controls */
3074 char *name, /* - parameters for search */
3075 afs_int32 start, /* - usage depends which BUDP_OP */
3076 afs_int32 end, /* - bits are set */
3077 afs_int32 index, /* start index of returned entries */
3078 afs_int32 *nextIndexP, /* output index for next call */
3079 afs_int32 *dbTimeP,
3080 budb_volumeList *volumes) /* pointer to buffer */
3082 afs_int32 code;
3084 code =
3085 GetVolumes(call, majorVersion, flags, name, start, end, index,
3086 nextIndexP, dbTimeP, volumes);
3087 osi_auditU(call, BUDB_GetVolEvent, code, AUD_END);
3088 return code;
3091 afs_int32
3092 GetVolumes(struct rx_call *call,
3093 afs_int32 majorVersion, /* version of interface structures */
3094 afs_int32 flags, /* search & select controls */
3095 char *name, /* - parameters for search */
3096 afs_int32 start, /* - usage depends which BUDP_OP_* */
3097 afs_int32 end, /* - bits are set */
3098 afs_int32 index, /* start index of returned entries */
3099 afs_int32 *nextIndexP, /* output index for next call */
3100 afs_int32 *dbTimeP,
3101 budb_volumeList *volumes) /* pointer to buffer */
3103 struct ubik_trans *ut;
3104 dbadr via;
3105 struct volInfo vi;
3106 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
3107 afs_int32 eval, code = 0;
3108 struct returnList vollist;
3109 afs_int32 toskip;
3111 /* Don't check permissions when we look up a specific volume name */
3112 if (((flags & BUDB_OP_NAMES) != BUDB_OP_VOLUMENAME)
3113 && !callPermitted(call))
3114 return BUDB_NOTPERMITTED;
3116 if (majorVersion != BUDB_MAJORVERSION)
3117 return BUDB_OLDINTERFACE;
3118 if (index < 0)
3119 return BUDB_ENDOFLIST;
3121 eval = InitRPC(&ut, LOCKREAD, 1);
3122 if (eval)
3123 return eval;
3125 nameFlags = flags & BUDB_OP_NAMES;
3126 startFlags = flags & BUDB_OP_STARTS;
3127 endFlags = flags & BUDB_OP_ENDS;
3128 timeFlags = flags & BUDB_OP_TIMES;
3130 InitReturnList(&vollist);
3131 toskip = index;
3133 /* lookup a the volume (specified by name) in the dump (specified by id) */
3134 if (nameFlags == BUDB_OP_VOLUMENAME) {
3135 /* dumpid permissible, all others off */
3136 if (((startFlags & ~BUDB_OP_DUMPID) != 0) || endFlags || timeFlags)
3137 ABORT(BUDB_BADFLAGS);
3139 /* returns ptr to volinfo of requested name */
3140 eval = ht_LookupEntry(ut, &db.volName, name, &via, &vi);
3141 if (eval)
3142 ABORT(eval);
3143 if (!via)
3144 ABORT(BUDB_NOVOLUMENAME);
3146 /* Iterate over all volume fragments with this name */
3147 while (1) {
3148 struct volFragment v;
3149 afs_int32 va;
3151 /* traverse all the volume fragments for this volume info structure */
3152 for (va = vi.firstFragment; va; va = v.sameNameChain) {
3153 va = ntohl(va);
3154 eval = dbread(ut, va, &v, sizeof(v));
3155 if (eval)
3156 ABORT(eval);
3158 if (startFlags & BUDB_OP_DUMPID) {
3159 struct tape atape;
3160 struct dump adump;
3162 /* get the dump id for this fragment */
3163 eval = dbread(ut, ntohl(v.tape), &atape, sizeof(atape));
3164 if (eval)
3165 ABORT(eval);
3167 eval =
3168 dbread(ut, ntohl(atape.dump), &adump, sizeof(adump));
3169 if (eval)
3170 ABORT(BUDB_IO);
3172 /* dump id does not match */
3173 if (ntohl(adump.id) != start)
3174 continue;
3177 eval = AddToReturnList(&vollist, va, &toskip);
3178 if (eval == BUDB_LIST2BIG)
3179 break;
3180 if (eval)
3181 ABORT(eval);
3183 if (eval == BUDB_LIST2BIG)
3184 break;
3186 via = vi.sameNameChain;
3187 if (via == 0)
3188 break;
3189 via = ntohl(via);
3191 eval = dbread(ut, via, &vi, sizeof(vi));
3192 if (eval)
3193 ABORT(eval);
3195 } else if (((nameFlags == 0) || (nameFlags == BUDB_OP_TAPENAME))
3196 && (startFlags == BUDB_OP_DUMPID)) {
3197 struct dump dump;
3198 dbadr dumpAddr;
3199 struct tape tape;
3200 dbadr tapeAddr;
3201 struct volFragment volFrag;
3202 dbadr volFragAddr;
3204 /* lookup all volumes for a specified dump id */
3206 /* no other flags should be set */
3207 if (endFlags || timeFlags)
3208 ABORT(BUDB_BADFLAGS);
3210 /* find the dump */
3211 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &dumpAddr, &dump);
3212 if (eval)
3213 ABORT(eval);
3215 /* traverse all the tapes */
3216 for (tapeAddr = ntohl(dump.firstTape); tapeAddr; tapeAddr = ntohl(tape.nextTape)) { /*w */
3217 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
3218 if (eval)
3219 ABORT(eval);
3221 if ((nameFlags != BUDB_OP_TAPENAME)
3222 || ((nameFlags == BUDB_OP_TAPENAME)
3223 && (strcmp(tape.name, name) == 0))) {
3224 /* now return all the volumes */
3225 for (volFragAddr = ntohl(tape.firstVol); volFragAddr;
3226 volFragAddr = ntohl(volFrag.sameTapeChain)) {
3227 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
3228 if (eval)
3229 ABORT(eval);
3231 eval = AddToReturnList(&vollist, volFragAddr, &toskip);
3232 if (eval == BUDB_LIST2BIG)
3233 break;
3234 if (eval)
3235 ABORT(eval);
3238 if (eval == BUDB_LIST2BIG)
3239 break;
3240 } /*w */
3241 } else {
3242 ABORT(BUDB_BADFLAGS);
3245 eval =
3246 SendReturnList(ut, &vollist, FillVolEntry,
3247 sizeof(struct budb_volumeEntry), index, nextIndexP,
3248 dbTimeP, (returnList_t) volumes);
3249 if (eval)
3250 ABORT(eval);
3252 /* error_exit: */
3253 FreeReturnList(&vollist);
3254 code = ubik_EndTrans(ut);
3255 return code;
3257 abort_exit:
3258 FreeReturnList(&vollist);
3259 ubik_AbortTrans(ut);
3260 return code;
3263 afs_int32
3264 SBUDB_UseTape(struct rx_call *call,
3265 struct budb_tapeEntry *tape, /* tape info */
3266 afs_int32 *new) /* set if tape is new */
3268 afs_int32 code;
3270 code = UseTape(call, tape, new);
3271 osi_auditU(call, BUDB_UseTpeEvent, code, AUD_DATE,
3272 (tape ? tape->dump : 0), AUD_END);
3273 return code;
3276 afs_int32
3277 UseTape(struct rx_call *call,
3278 struct budb_tapeEntry *tape, /* tape info */
3279 int *new) /* set if tape is new */
3281 struct ubik_trans *ut;
3282 dbadr da, a;
3283 struct dump d;
3284 struct tape t;
3285 afs_int32 eval, code;
3287 if (!callPermitted(call))
3288 return BUDB_NOTPERMITTED;
3290 if (strlen(tape->name) >= sizeof(t.name))
3291 return BUDB_BADARGUMENT;
3293 eval = InitRPC(&ut, LOCKWRITE, 1);
3294 if (eval)
3295 return eval;
3297 *new = 0;
3299 memset(&t, 0, sizeof(t));
3300 eval = AllocStructure(ut, tape_BLOCK, 0, &a, &t);
3301 if (eval)
3302 ABORT(eval);
3304 strcpy(t.name, tape->name);
3306 eval = ht_HashIn(ut, &db.tapeName, a, &t);
3307 if (eval)
3308 ABORT(eval);
3310 *new = 1;
3312 /* Since deleting a tape may change the dump (if its the same one), read in
3313 * the dump after the call to DeleteTape. */
3315 eval = ht_LookupEntry(ut, &db.dumpIden, &tape->dump, &da, &d);
3316 if (eval)
3317 ABORT(eval);
3318 if (!da)
3319 ABORT(BUDB_NODUMPID);
3321 if (!tape->written)
3322 tape->written = time(0); /* fill in tape struct */
3323 t.written = htonl(tape->written);
3324 t.expires = htonl(tape->expires);
3325 t.dump = htonl(da);
3326 t.seq = htonl(tape->seq);
3327 t.useCount = htonl(tape->useCount);
3328 t.labelpos = htonl(tape->labelpos);
3329 t.useKBytes = 0;
3330 t.flags = htonl(tape->flags | BUDB_TAPE_BEINGWRITTEN);
3332 t.nextTape = d.firstTape; /* Chain the tape to the dump */
3333 d.firstTape = htonl(a);
3335 if (tape->seq >= ntohl(d.tapes.maxTapes)) /* inc # tapes in the dump */
3336 d.tapes.maxTapes = htonl(tape->seq);
3338 eval = dbwrite(ut, a, &t, sizeof(t)); /* write tape struct */
3339 if (eval)
3340 ABORT(eval);
3342 eval = dbwrite(ut, da, &d, sizeof(d)); /* write the dump struct */
3343 if (eval)
3344 ABORT(eval);
3346 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
3347 if (eval)
3348 ABORT(eval);
3350 LogDebug(5, "added tape %s\n", tape->name);
3352 code = ubik_EndTrans(ut);
3353 return code;
3355 abort_exit:
3356 ubik_AbortTrans(ut);
3357 return code;
3362 /* ---------------------------------------------
3363 * debug interface routines
3364 * ---------------------------------------------
3367 afs_int32
3368 SBUDB_T_DumpHashTable(struct rx_call *call, afs_int32 type, char *filename)
3370 afs_int32 code;
3372 code = T_DumpHashTable(call, type, filename);
3373 osi_auditU(call, BUDB_TDmpHaEvent, code, AUD_STR, filename, AUD_END);
3374 return code;
3377 afs_int32
3378 T_DumpHashTable(struct rx_call *call, int type, char *filename)
3380 struct ubik_trans *ut;
3381 struct memoryHashTable *mht;
3382 int ent;
3383 afs_int32 eval, code = 0;
3384 char path[64];
3385 FILE *DUMP;
3387 int length;
3388 afs_uint32 hash;
3389 dbadr a, first_a;
3390 char e[sizeof(struct block)]; /* unnecessarily conservative */
3391 struct dump e_dump;
3392 struct tape e_tape;
3393 struct volInfo e_volinfo;
3394 int e_size;
3395 int old;
3397 if (!callPermitted(call))
3398 return BUDB_NOTPERMITTED;
3400 if (strlen(filename) >= sizeof(path) - 5)
3401 return BUDB_BADARGUMENT;
3403 eval = InitRPC(&ut, LOCKWRITE, 1);
3404 if (eval)
3405 return eval;
3407 if ((mht = ht_GetType(type, &e_size)) == 0)
3408 return BUDB_BADARGUMENT;
3410 sprintf(path, "%s/%s", gettmpdir(), filename);
3412 DUMP = fopen(path, "w");
3413 if (!DUMP)
3414 ABORT(BUDB_BADARGUMENT);
3416 ent = 0;
3417 for (old = 0;; old++) {
3418 length = (old ? mht->oldLength : mht->length);
3419 if (length)
3420 fprintf(DUMP, "Dumping %sHash Table:\n", (old ? "Old " : ""));
3422 for (hash = 0; hash < length; hash++) {
3423 a = ht_LookupBucket(ut, mht, hash, old);
3424 first_a = a;
3425 while (a) {
3426 eval = dbread(ut, a, e, e_size);
3427 if (eval)
3428 ABORT(eval);
3430 ent++;
3431 if (a == first_a)
3432 fprintf(DUMP, " in bucket %d at %d is ", hash, a);
3433 else
3434 fprintf(DUMP, " at %d is ", a);
3435 switch (type) {
3436 case HT_dumpIden_FUNCTION:
3437 memcpy(&e_dump, e, sizeof(e_dump));
3438 fprintf(DUMP, "%d\n", ntohl(e_dump.id));
3439 break;
3440 case HT_dumpName_FUNCTION:
3441 memcpy(&e_dump, e, sizeof(e_dump));
3442 fprintf(DUMP, "%s\n", e_dump.dumpName);
3443 break;
3444 case HT_tapeName_FUNCTION:
3445 memcpy(&e_tape, e, sizeof(e_tape));
3446 fprintf(DUMP, "%s\n", e_tape.name);
3447 break;
3448 case HT_volName_FUNCTION:
3449 memcpy(&e_volinfo, e, sizeof(e_volinfo));
3450 fprintf(DUMP, "%s\n", e_volinfo.name);
3451 break;
3453 if ((ht_HashEntry(mht, e) % length) != hash)
3454 ABORT(BUDB_DATABASEINCONSISTENT);
3455 a = ntohl(*(dbadr *) (e + mht->threadOffset));
3458 if (old)
3459 break;
3462 fprintf(DUMP, "%d entries found\n", ent);
3463 if (ntohl(mht->ht->entries) != ent)
3464 ABORT(BUDB_DATABASEINCONSISTENT);
3466 code = ubik_EndTrans(ut);
3467 if (DUMP)
3468 fclose(DUMP);
3469 return code;
3471 abort_exit:
3472 ubik_AbortTrans(ut);
3473 if (DUMP)
3474 fclose(DUMP);
3475 return code;
3478 afs_int32
3479 SBUDB_T_GetVersion(struct rx_call *call, afs_int32 *majorVersion)
3481 afs_int32 code;
3483 code = T_GetVersion(call, majorVersion);
3484 osi_auditU(call, BUDB_TGetVrEvent, code, AUD_END);
3485 return code;
3488 afs_int32
3489 T_GetVersion(struct rx_call *call, int *majorVersion)
3491 struct ubik_trans *ut;
3492 afs_int32 code;
3494 code = InitRPC(&ut, LOCKREAD, 0);
3495 if (code)
3496 return (code);
3498 *majorVersion = BUDB_MAJORVERSION;
3500 code = ubik_EndTrans(ut);
3501 return (code);
3504 /* BUDB_T_DumpDatabase
3505 * dump as much of the database as possible int /tmp/<filename>
3508 afs_int32
3509 SBUDB_T_DumpDatabase(struct rx_call *call, char *filename)
3511 afs_int32 code;
3513 code = T_DumpDatabase(call, filename);
3514 osi_auditU(call, BUDB_TDmpDBEvent, code, AUD_STR, filename, AUD_END);
3515 return code;
3518 afs_int32
3519 T_DumpDatabase(struct rx_call *call, char *filename)
3521 FILE *dumpfid;
3522 int entrySize;
3523 struct ubik_trans *ut;
3524 char *path = 0;
3525 dbadr dbAddr;
3526 int type, old, length, hash;
3527 struct memoryHashTable *mht;
3528 afs_int32 eval, code = 0;
3530 if (!callPermitted(call))
3531 return BUDB_NOTPERMITTED;
3533 length = asprintf(&path, "%s/%s", gettmpdir(), filename);
3534 if (length < 0 || !path)
3535 return (BUDB_INTERNALERROR);
3537 dumpfid = fopen(path, "w");
3538 if (!dumpfid)
3539 return (BUDB_BADARGUMENT);
3541 eval = InitRPC(&ut, LOCKWRITE, 1);
3542 if (eval)
3543 return (eval);
3545 /* dump all items in the database */
3546 for (type = 1; type <= HT_MAX_FUNCTION; type++) { /*ft */
3547 mht = ht_GetType(type, &entrySize);
3548 if (!mht)
3549 ERROR(BUDB_BADARGUMENT);
3551 for (old = 0; old <= 1; old++) { /*fo */
3552 length = (old ? mht->oldLength : mht->length);
3553 if (!length)
3554 continue;
3556 fprintf(dumpfid, "Dumping %s Hash Table:\n", (old ? "Old " : ""));
3558 for (hash = 0; hash < length; hash++) { /*f */
3559 dbAddr = ht_LookupBucket(ut, mht, hash, old);
3561 while (dbAddr) { /*w */
3562 switch (type) { /*s */
3563 case HT_dumpIden_FUNCTION:
3565 struct dump hostDump, diskDump;
3567 eval =
3568 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3569 sizeof(diskDump));
3570 if (eval)
3571 ERROR(eval);
3573 fprintf(dumpfid,
3574 "\ndumpId hash %d, entry at %u\n",
3575 hash, dbAddr);
3576 fprintf(dumpfid,
3577 "----------------------------\n");
3578 dump_ntoh(&diskDump, &hostDump);
3579 printDump(dumpfid, &hostDump);
3580 dbAddr = hostDump.idHashChain;
3582 break;
3584 case HT_dumpName_FUNCTION:
3586 struct dump hostDump, diskDump;
3588 eval =
3589 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3590 sizeof(diskDump));
3591 if (eval)
3592 ERROR(eval);
3594 fprintf(dumpfid,
3595 "\ndumpname hash %d, entry at %u\n",
3596 hash, dbAddr);
3597 fprintf(dumpfid,
3598 "----------------------------\n");
3599 dump_ntoh(&diskDump, &hostDump);
3600 printDump(dumpfid, &hostDump);
3601 dbAddr = hostDump.nameHashChain;
3603 break;
3605 case HT_tapeName_FUNCTION:
3607 struct tape hostTape, diskTape;
3609 eval =
3610 cdbread(ut, tape_BLOCK, dbAddr, &diskTape,
3611 sizeof(diskTape));
3612 if (eval)
3613 ERROR(eval);
3615 fprintf(dumpfid,
3616 "\ntapename hash %d, entry at %u\n",
3617 hash, dbAddr);
3618 fprintf(dumpfid,
3619 "----------------------------\n");
3620 tape_ntoh(&diskTape, &hostTape);
3621 printTape(dumpfid, &hostTape);
3622 dbAddr = hostTape.nameHashChain;
3624 break;
3626 case HT_volName_FUNCTION:
3628 struct volInfo hostVolInfo, diskVolInfo;
3630 eval =
3631 cdbread(ut, volInfo_BLOCK, dbAddr,
3632 &diskVolInfo, sizeof(diskVolInfo));
3633 if (eval)
3634 ERROR(eval);
3636 fprintf(dumpfid,
3637 "\nvolname hash %d, entry at %u\n",
3638 hash, dbAddr);
3639 fprintf(dumpfid,
3640 "----------------------------\n");
3641 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3642 printVolInfo(dumpfid, &hostVolInfo);
3643 dbAddr = hostVolInfo.nameHashChain;
3645 volFragsDump(ut, dumpfid,
3646 hostVolInfo.firstFragment);
3648 break;
3650 default:
3651 fprintf(dumpfid, "unknown type %d\n", type);
3652 break;
3654 } /*s */
3655 } /*w */
3656 } /*f */
3657 } /*fo */
3658 } /*ft */
3660 error_exit:
3661 code = ubik_EndTrans(ut); /* is this safe if no ut started ? */
3662 if (dumpfid)
3663 fclose(dumpfid);
3664 if (path)
3665 free(path);
3666 return (code);
3670 volFragsDump(struct ubik_trans *ut, FILE *dumpfid, dbadr dbAddr)
3672 struct volFragment hostVolFragment, diskVolFragment;
3673 afs_int32 code;
3675 while (dbAddr) {
3676 code =
3677 cdbread(ut, volFragment_BLOCK, dbAddr, &diskVolFragment,
3678 sizeof(diskVolFragment));
3679 if (code) { /* don't be fussy about errors */
3680 fprintf(dumpfid, "volFragsDump: Error reading database\n");
3681 return (0);
3684 fprintf(dumpfid, "\nvolfragment entry at %u\n", dbAddr);
3685 fprintf(dumpfid, "----------------------------\n");
3686 volFragment_ntoh(&diskVolFragment, &hostVolFragment);
3687 printVolFragment(dumpfid, &hostVolFragment);
3688 dbAddr = hostVolFragment.sameNameChain;
3690 return (0);
3693 #ifdef notdef
3694 /* utilities - network to host conversion
3695 * currently used for debug only
3698 void
3699 volFragmentDiskToHost(struct volFragment *diskVfPtr,
3700 struct volFragment *hostVfPtr)
3702 hostVfPtr->vol = ntohl(diskVfPtr->vol);
3703 hostVfPtr->sameNameChain = ntohl(diskVfPtr->sameNameChain);
3704 hostVfPtr->tape = ntohl(diskVfPtr->tape);
3705 hostVfPtr->sameTapeChain = ntohl(diskVfPtr->sameTapeChain);
3706 hostVfPtr->position = ntohl(diskVfPtr->position);
3707 hostVfPtr->clone = ntohl(diskVfPtr->clone);
3708 hostVfPtr->incTime = ntohl(diskVfPtr->incTime);
3709 hostVfPtr->startByte = ntohl(diskVfPtr->startByte);
3710 hostVfPtr->nBytes = ntohl(diskVfPtr->nBytes);
3711 hostVfPtr->flags = ntohs(diskVfPtr->flags);
3712 hostVfPtr->sequence = ntohs(diskVfPtr->sequence);
3715 void
3716 volInfoDiskToHost(struct volInfo *diskViPtr, struct volInfo *hostViPtr)
3718 strcpy(hostViPtr->name, diskViPtr->name);
3719 hostViPtr->nameHashChain = ntohl(diskViPtr->nameHashChain);
3720 hostViPtr->id = ntohl(diskViPtr->id);
3721 strcpy(hostViPtr->server, diskViPtr->server);
3722 hostViPtr->partition = ntohl(diskViPtr->partition);
3723 hostViPtr->flags = ntohl(diskViPtr->flags);
3724 hostViPtr->sameNameHead = ntohl(diskViPtr->sameNameHead);
3725 hostViPtr->sameNameChain = ntohl(diskViPtr->sameNameChain);
3726 hostViPtr->firstFragment = ntohl(diskViPtr->firstFragment);
3727 hostViPtr->nFrags = ntohl(diskViPtr->nFrags);
3730 void
3731 tapeDiskToHost(struct tape *diskTapePtr, struct tape *hostTapePtr)
3733 strcpy(hostTapePtr->name, diskTapePtr->name);
3734 hostTapePtr->nameHashChain = ntohl(diskTapePtr->nameHashChain);
3735 hostTapePtr->flags = ntohl(diskTapePtr->flags);
3737 /* tape id conversion here */
3738 hostTapePtr->written = ntohl(diskTapePtr->written);
3739 hostTapePtr->nBytes = ntohl(diskTapePtr->nBytes);
3740 hostTapePtr->nFiles = ntohl(diskTapePtr->nFiles);
3741 hostTapePtr->nVolumes = ntohl(diskTapePtr->nVolumes);
3742 hostTapePtr->seq = ntohl(diskTapePtr->seq);
3743 hostTapePtr->dump = ntohl(diskTapePtr->dump);
3744 hostTapePtr->nextTape = ntohl(diskTapePtr->nextTape);
3745 hostTapePtr->firstVol = ntohl(diskTapePtr->firstVol);
3746 hostTapePtr->useCount = ntohl(diskTapePtr->useCount);
3749 void
3750 dumpDiskToHost(struct dump *diskDumpPtr, struct dump *hostDumpPtr)
3752 hostDumpPtr->id = ntohl(diskDumpPtr->id);
3753 hostDumpPtr->idHashChain = ntohl(diskDumpPtr->idHashChain);
3754 strcpy(hostDumpPtr->dumpName, diskDumpPtr->dumpName);
3755 strcpy(hostDumpPtr->dumpPath, diskDumpPtr->dumpPath);
3756 strcpy(hostDumpPtr->volumeSet, diskDumpPtr->volumeSet);
3757 hostDumpPtr->nameHashChain = ntohl(diskDumpPtr->nameHashChain);
3758 hostDumpPtr->flags = ntohl(diskDumpPtr->flags);
3759 hostDumpPtr->parent = ntohl(diskDumpPtr->parent);
3760 hostDumpPtr->created = ntohl(diskDumpPtr->created);
3761 /* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3762 hostDumpPtr->nVolumes = ntohl(diskDumpPtr->nVolumes);
3764 /* tapeset conversion here */
3766 hostDumpPtr->firstTape = ntohl(diskDumpPtr->firstTape);
3768 /* principal conversion here */
3771 #endif /* notdef */
3774 checkHash(struct ubik_trans *ut, int hashType)
3776 struct memoryHashTable *mhtPtr;
3777 int entrySize, hashTableLength;
3778 int bucket;
3779 int old;
3780 afs_int32 code = 0;
3782 mhtPtr = ht_GetType(hashType, &entrySize);
3783 if (mhtPtr == 0)
3784 ERROR(-1);
3786 for (old = 0; old < 1; old++) {
3787 LogDebug(5, "\nold = %d\n", old);
3788 printMemoryHashTable(stdout, mhtPtr);
3789 LogDebug(5, "\n");
3790 hashTableLength = (old ? mhtPtr->oldLength : mhtPtr->length);
3792 for (bucket = 0; bucket < hashTableLength; bucket++) {
3793 dbadr entryAddr;
3795 entryAddr = ht_LookupBucket(ut, mhtPtr, bucket, old);
3796 while (entryAddr != 0) {
3797 LogDebug(6, "bucket %d has disk addr %d\n", bucket,
3798 entryAddr);
3799 switch (hashType) {
3800 case HT_dumpIden_FUNCTION:
3802 struct dump diskDump, hostDump;
3804 code = dbread(ut, entryAddr, &diskDump, entrySize);
3805 if (code)
3806 ERROR(-1);
3808 dump_ntoh(&diskDump, &hostDump);
3809 printDump(stdout, &hostDump);
3810 entryAddr = hostDump.idHashChain;
3812 break;
3814 case HT_dumpName_FUNCTION:
3815 break;
3817 case HT_tapeName_FUNCTION:
3818 break;
3820 case HT_volName_FUNCTION:
3822 struct volInfo diskVolInfo, hostVolInfo;
3824 code = dbread(ut, entryAddr, &diskVolInfo, entrySize);
3825 if (code)
3826 ERROR(-1);
3828 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3829 printVolInfo(stdout, &hostVolInfo);
3830 entryAddr = hostVolInfo.nameHashChain;
3831 break;
3837 error_exit:
3838 return (code);