Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / budb / procs.c
CommitLineData
805e021f
CE
1/*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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 */
9
10/* TBD
11 * ht_lookupEntry - tape ids
12 * Truncate Tape - tape id's
13 * usetape - tape id's
14 */
15
16#include <afsconfig.h>
17#include <afs/param.h>
18
19#include <roken.h>
20
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>
33
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"
40
41#undef min
42#undef max
43
44
45extern struct ubik_dbase *BU_dbase;
46extern struct afsconf_dir *BU_conf; /* for getting cell info */
47
48afs_int32 AddVolume(struct rx_call *, struct budb_volumeEntry *);
49afs_int32 AddVolumes(struct rx_call *, struct budb_volumeList *);
50afs_int32 CreateDump(struct rx_call *, struct budb_dumpEntry *);
51afs_int32 DoDeleteDump(struct rx_call *, dumpId, Date, Date, budb_dumpsList *);
52afs_int32 DoDeleteTape(struct rx_call *, struct budb_tapeEntry *);
53afs_int32 ListDumps(struct rx_call *, afs_int32, afs_int32, Date, Date,
54 budb_dumpsList *, budb_dumpsList *);
55afs_int32 DeleteVDP(struct rx_call *, char *, char *, afs_int32);
56afs_int32 FindClone(struct rx_call *, afs_int32, char *, afs_int32 *);
57afs_int32 FindDump(struct rx_call *, char *, afs_int32,
58 struct budb_dumpEntry *);
59afs_int32 FindLatestDump(struct rx_call *, char *, char *,
60 struct budb_dumpEntry *);
61afs_int32 FinishDump(struct rx_call *, struct budb_dumpEntry *);
62afs_int32 FinishTape(struct rx_call *, struct budb_tapeEntry *);
63afs_int32 GetDumps(struct rx_call *, afs_int32, afs_int32, char *,
64 afs_int32, afs_int32, afs_int32, afs_int32 *,
65 afs_int32 *, budb_dumpList *);
66afs_int32 getExpiration(struct ubik_trans *ut, struct tape *);
67afs_int32 makeAppended(struct ubik_trans *ut, afs_int32, afs_int32,
68 afs_int32);
69afs_int32 MakeDumpAppended(struct rx_call *, afs_int32, afs_int32,
70 afs_int32);
71afs_int32 FindLastTape(struct rx_call *, afs_int32, struct budb_dumpEntry *,
72 struct budb_tapeEntry *, struct budb_volumeEntry *);
73afs_int32 GetTapes(struct rx_call *, afs_int32, afs_int32, char *, afs_int32,
74 afs_int32, afs_int32, afs_int32 *, afs_int32 *,
75 budb_tapeList *);
76afs_int32 GetVolumes(struct rx_call *, afs_int32, afs_int32, char *,
77 afs_int32, afs_int32, afs_int32, afs_int32 *,
78 afs_int32 *, budb_volumeList *);
79afs_int32 UseTape(struct rx_call *, struct budb_tapeEntry *, int *);
80afs_int32 T_DumpHashTable(struct rx_call *, int, char *);
81afs_int32 T_GetVersion(struct rx_call *, int *);
82afs_int32 T_DumpDatabase(struct rx_call *, char *);
83
84int volFragsDump(struct ubik_trans *, FILE *, dbadr);
85
86/* Text block management */
87
88struct 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 */
93};
94
95typedef struct memTextBlock memTextBlockT;
96typedef memTextBlockT *memTextBlockP;
97
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. */
101
102/* This is global so COUNT_REQ in krb_udp.c can refer to it. */
103char *lastOperation; /* name of last operation */
104static Date lastTrans; /* time of last transaction */
105
106/* procsInited is sort of a lock: during a transaction only one process runs
107 while procsInited is false. */
108
109static int procsInited = 0;
110
111/* This variable is protected by the procsInited flag. */
112
113static int (*rebuildDatabase) (struct ubik_trans *);
114
115/* AwaitInitialization
116 * Wait unitl budb has initialized (InitProcs). If it hasn't
117 * within 5 seconds, then return no quorum.
118 */
119afs_int32
120AwaitInitialization(void)
121{
122 afs_int32 start = 0;
123
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
134 }
135 return 0;
136}
137
138/* tailCompPtr
139 * name is a pathname style name, determine trailing name and return
140 * pointer to it
141 */
142
143char *
144tailCompPtr(char *pathNamePtr)
145{
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);
156}
157
158/* callPermitted
159 * Check to see if the caller is a SuperUser.
160 * exit:
161 * 0 - no
162 * 1 - yes
163 */
164
165int
166callPermitted(struct rx_call *call)
167{
168 int permitted = 0;
169 struct afsconf_dir *acdir;
170
171 acdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
172 if (!acdir)
173 return 0;
174
175 if (afsconf_SuperUser(acdir, call, NULL))
176 permitted = 1;
177
178 if (acdir)
179 afsconf_Close(acdir);
180 return (permitted);
181}
182
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.
193 */
194
195afs_int32
196InitRPC(struct ubik_trans **ut,
197 int lock, /* indicate read/write transaction */
198 int this_op) /* opcode of RCP, for COUNT_ABO */
199{
200 int code;
201 float wait = 0.91; /* start waiting for 1 second */
202
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;
208
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
225 }
226 }
227 if (code)
228 return code;
229 if (wait > 1)
230 Log("Have established quorum\n");
231
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;
236 }
237
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;
246 }
247 if ((code = ubik_EndTrans(*ut))) {
248 LogError(code, "InitRPC: ubik_EndTrans failed\n");
249 return code;
250 }
251 goto start; /* now redo the read transaction */
252 }
253 } else {
254 if ((code = CheckInit(*ut, rebuildDatabase))) {
255 ubik_AbortTrans(*ut);
256 return code;
257 }
258 }
259 lastTrans = time(0);
260 return 0;
261}
262
263/* This is called to initialize a newly created database */
264static int
265initialize_database(struct ubik_trans *ut)
266{
267 return 0;
268}
269
270static int noAuthenticationRequired; /* global state */
271static int recheckNoAuth; /* global state */
272
273afs_int32
274InitProcs(void)
275{
276 struct ubik_trans *ut;
277 afs_int32 code = 0;
278
279 procsInited = 0;
280
281 if ((globalConfPtr->myHost == 0) || (BU_conf == 0))
282 ERROR(BUDB_INTERNALERROR);
283
284 recheckNoAuth = 1;
285
286 if (globalConfPtr->debugFlags & DF_NOAUTH)
287 noAuthenticationRequired = 1;
288
289 if (globalConfPtr->debugFlags & DF_RECHECKNOAUTH)
290 recheckNoAuth = 0;
291
292 if (recheckNoAuth)
293 noAuthenticationRequired = afsconf_GetNoAuthFlag(BU_conf);
294
295 if (noAuthenticationRequired)
296 LogError(0, "Running server with security disabled\n");
297
298 InitDB();
299
300 rebuildDatabase = initialize_database;
301
302 if ((code = InitRPC(&ut, LOCKREAD, 0))) {
303 LogError(code, "InitProcs: InitRPC failed\n");
304 return code;
305 }
306 code = ubik_EndTrans(ut);
307 if (code) {
308 LogError(code, "InitProcs: ubik_EndTrans failed\n");
309 return code;
310 }
311
312 rebuildDatabase = 0; /* only do this during init */
313 procsInited = 1;
314
315 error_exit:
316 return (code);
317}
318
319struct returnList {
320 int nElements; /* number in list */
321 int allocSize; /* number of elements allocated */
322 dbadr *elements; /* array of addresses */
323};
324
325static void
326InitReturnList(struct returnList *list)
327{
328 list->nElements = 0;
329 list->allocSize = 0;
330 list->elements = (dbadr *) 0;
331}
332
333static void
334FreeReturnList(struct returnList *list)
335{
336 if (list->elements)
337 free(list->elements);
338 list->elements = (dbadr *) 0;
339 list->nElements = 0;
340}
341
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.
345 */
346static afs_int32
347AddToReturnList(struct returnList *list, dbadr a, afs_int32 *to_skipP)
348{
349 dbadr *tmp;
350 afs_int32 size;
351
352 if (a == 0)
353 return 0;
354 if (*to_skipP > 0) {
355 (*to_skipP)--;
356 return 0;
357 }
358
359 /* Up to 5 plus a maximum so SendReturnList() knows if we
360 * need to come back for more.
361 */
362 if (list->nElements >= BUDB_MAX_RETURN_LIST + 5)
363 return BUDB_LIST2BIG;
364
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);
372 }
373 if (!tmp)
374 return BUDB_NOMEM;
375 list->elements = tmp;
376 list->allocSize = size;
377 }
378
379 list->elements[list->nElements] = a;
380 list->nElements++;
381 return 0;
382}
383
384afs_int32
385FillVolEntry(struct ubik_trans *ut, dbadr va, void *rock)
386{
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;
392
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 */
401
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);
417
418 return 0;
419}
420
421afs_int32
422FillDumpEntry(struct ubik_trans *ut, dbadr da, void *rock)
423{
424 struct budb_dumpEntry *dump = (struct budb_dumpEntry *)rock;
425 struct dump d, ad;
426
427 memset(dump, 0, sizeof(*dump));
428 if (dbread(ut, da, &d, sizeof(d)))
429 return BUDB_IO;
430 dump->id = ntohl(d.id);
431 dump->flags = ntohl(d.flags);
432 dump->created = ntohl(d.created);
433 strncpy(dump->name, d.dumpName, sizeof(dump->name));
434 strncpy(dump->dumpPath, d.dumpPath, sizeof(dump->dumpPath));
435 strncpy(dump->volumeSetName, d.volumeSet, sizeof(dump->volumeSetName));
436
437 dump->parent = ntohl(d.parent);
438 dump->level = ntohl(d.level);
439 dump->nVolumes = ntohl(d.nVolumes);
440
441 tapeSet_ntoh(&d.tapes, &dump->tapes);
442
443 if (strlen(d.dumper.name) < sizeof(dump->dumper.name))
444 strcpy(dump->dumper.name, d.dumper.name);
445 if (strlen(d.dumper.instance) < sizeof(dump->dumper.instance))
446 strcpy(dump->dumper.instance, d.dumper.instance);
447 if (strlen(d.dumper.cell) < sizeof(dump->dumper.cell))
448 strcpy(dump->dumper.cell, d.dumper.cell);
449
450 /* Get the initial dumpid and the appended dump id */
451 dump->initialDumpID = ntohl(d.initialDumpID);
452 if (d.appendedDumpChain) {
453 if (dbread(ut, ntohl(d.appendedDumpChain), &ad, sizeof(ad)))
454 return BUDB_IO;
455 dump->appendedDumpID = ntohl(ad.id);
456 } else
457 dump->appendedDumpID = 0;
458
459 /* printf("dump name %s, parent %d, level %d\n",
460 * d.dumpName, ntohl(d.parent), ntohl(d.level)); */
461
462 return 0;
463}
464
465afs_int32
466FillTapeEntry(struct ubik_trans *ut, dbadr ta, void *rock)
467{
468 struct budb_tapeEntry *tape=(struct budb_tapeEntry *) rock;
469 struct tape t;
470 struct dump d;
471 afs_int32 code;
472
473 if (dbread(ut, ta, &t, sizeof(t)))
474 return BUDB_IO;
475
476 /* Get the tape's expiration date */
477 if ((code = getExpiration(ut, &t)))
478 return (code);
479
480 strcpy(tape->name, t.name);
481 tape->flags = ntohl(t.flags);
482 tape->written = ntohl(t.written);
483 tape->expires = ntohl(t.expires);
484 tape->nMBytes = ntohl(t.nMBytes);
485 tape->nBytes = ntohl(t.nBytes);
486 tape->nFiles = ntohl(t.nFiles);
487 tape->nVolumes = ntohl(t.nVolumes);
488 tape->seq = ntohl(t.seq);
489 tape->labelpos = ntohl(t.labelpos);
490 tape->useCount = ntohl(t.useCount);
491 tape->useKBytes = ntohl(t.useKBytes);
492
493 if (dbread(ut, ntohl(t.dump), &d, sizeof(d)))
494 return BUDB_IO;
495 tape->dump = ntohl(d.id);
496 return 0;
497}
498
499#define returnList_t budb_dumpList *
500
501/* SendReturnList
502 * A list of elements of size e_size is in list, collected
503 * with AddToReturnList(). We will move this to a correspoding
504 * return list, eList, via FillProc(). nextInodeP tells us
505 * if there are more and how many to skip on the next request.
506 */
507static afs_int32
508SendReturnList(struct ubik_trans *ut,
509 struct returnList *list, /* list of elements to return */
510 afs_int32(*FillProc) (struct ubik_trans *, dbadr da,
511 void *),
512 /* proc to fill entry */
513 int e_size, /* size of each element */
514 afs_int32 index, /* index from previous call */
515 afs_int32 *nextIndexP, /* if more elements are available */
516 afs_int32 *dbTimeP, /* time of last db update */
517 budb_dumpList *eList) /* rxgen list structure (e.g.) */
518{
519 afs_int32 code;
520 int to_return;
521 int i;
522 char *e;
523
524 *nextIndexP = -1;
525 *dbTimeP = ntohl(db.h.lastUpdate);
526
527 /* Calculate how many to return. Don't let if go over
528 * BUDB_MAX_RETURN_LIST nor the size of our return list.
529 */
530 to_return = list->nElements;
531 if (to_return > BUDB_MAX_RETURN_LIST)
532 to_return = BUDB_MAX_RETURN_LIST;
533 if (eList->budb_dumpList_len && (to_return > eList->budb_dumpList_len))
534 to_return = eList->budb_dumpList_len;
535
536 /* Allocate space for the return values if needed and zero it */
537 if (eList->budb_dumpList_val == 0) {
538 if (to_return > 0) {
539 eList->budb_dumpList_val = calloc(to_return, e_size);
540 if (!eList->budb_dumpList_val)
541 return (BUDB_NOMEM);
542 } else
543 eList->budb_dumpList_val = NULL;
544 } else {
545 memset(eList->budb_dumpList_val, 0, e_size * to_return);
546 }
547
548 eList->budb_dumpList_len = to_return;
549
550 e = (char *)(eList->budb_dumpList_val);
551 for (i = 0; i < to_return; i++, e += e_size) {
552 code = (*FillProc) (ut, list->elements[i], (budb_dumpEntry *) e);
553 if (code)
554 return code;
555 }
556
557 if (list->nElements > i)
558 *nextIndexP = index + i;
559 return 0;
560}
561
562/* Come here to delete a volInfo structure. */
563
564static afs_int32
565DeleteVolInfo(struct ubik_trans *ut, dbadr via, struct volInfo *vi)
566{
567 afs_int32 code;
568 dbadr hvia;
569 struct volInfo hvi;
570
571 if (vi->firstFragment)
572 return 0; /* still some frags, don't free yet */
573 if (vi->sameNameHead == 0) { /* this is the head */
574 if (vi->sameNameChain)
575 return 0; /* empty head, some non-heads left */
576
577 code = ht_HashOut(ut, &db.volName, via, vi);
578 if (code)
579 return code;
580 code = FreeStructure(ut, volInfo_BLOCK, via);
581 return code;
582 }
583 hvia = ntohl(vi->sameNameHead);
584 if (dbread(ut, hvia, &hvi, sizeof(hvi)))
585 return BUDB_IO;
586 code =
587 RemoveFromList(ut, hvia, &hvi, &hvi.sameNameChain, via, vi,
588 &vi->sameNameChain);
589 if (code == -1)
590 return BUDB_DATABASEINCONSISTENT;
591 if (code == 0)
592 code = FreeStructure(ut, volInfo_BLOCK, via);
593 return code;
594}
595
596/* Detach a volume fragment from its volInfo structure. Its tape chain is
597 already freed. This routine frees the structure and the caller must not
598 write it out. */
599
600static afs_int32
601DeleteVolFragment(struct ubik_trans *ut, dbadr va, struct volFragment *v)
602{
603 afs_int32 code;
604 struct volInfo vi;
605 dbadr via;
606
607 via = ntohl(v->vol);
608 if (dbread(ut, via, &vi, sizeof(vi)))
609 return BUDB_IO;
610 code =
611 RemoveFromList(ut, via, &vi, &vi.firstFragment, va, v,
612 &v->sameNameChain);
613 if (code == -1)
614 return BUDB_DATABASEINCONSISTENT;
615 if (code)
616 return code;
617 if (vi.firstFragment == 0)
618 if ((code = DeleteVolInfo(ut, via, &vi)))
619 return code;
620 if ((code = FreeStructure(ut, volFragment_BLOCK, va)))
621 return code;
622
623 /* decrement frag counter */
624 code =
625 set_word_addr(ut, via, &vi, &vi.nFrags, htonl(ntohl(vi.nFrags) - 1));
626 if (code)
627 return code;
628 return 0;
629}
630
631/* DeleteTape - by freeing all its volumes and removing it from its dump chain.
632 * The caller will remove it from the hash table if necessary. The caller is
633 * also responsible for writing the tape out if necessary. */
634
635static afs_int32
636DeleteTape(struct ubik_trans *ut, dbadr ta, struct tape *t)
637{
638 afs_int32 code;
639 struct dump d;
640 dbadr da;
641
642 da = ntohl(t->dump);
643 if (da == 0)
644 return BUDB_DATABASEINCONSISTENT;
645 if (dbread(ut, da, &d, sizeof(d)))
646 return BUDB_IO;
647 if (d.firstTape == 0)
648 return BUDB_DATABASEINCONSISTENT;
649
650 code = RemoveFromList(ut, da, &d, &d.firstTape, ta, t, &t->nextTape);
651 if (code == -1)
652 return BUDB_DATABASEINCONSISTENT;
653 if (code)
654 return code;
655
656 /* Since the tape should have been truncated there should never be any
657 * volumes in the tape. */
658 if (t->firstVol || t->nVolumes)
659 return BUDB_DATABASEINCONSISTENT;
660
661 return 0;
662}
663
664static afs_int32
665DeleteDump(struct ubik_trans *ut, dbadr da, struct dump *d)
666{
667 afs_int32 code = 0;
668
669 code = ht_HashOut(ut, &db.dumpIden, da, d);
670 if (code)
671 ERROR(code);
672
673 code = ht_HashOut(ut, &db.dumpName, da, d);
674 if (code)
675 ERROR(code);
676
677 /* Since the tape should have been truncated this should never happen. */
678 if (d->firstTape || d->nVolumes)
679 ERROR(BUDB_DATABASEINCONSISTENT);
680
681 code = FreeStructure(ut, dump_BLOCK, da);
682 if (code)
683 ERROR(code);
684
685 error_exit:
686 return code;
687}
688
689/*
690 * VolInfoMatch()
691 *
692 * This is called with a volumeEntry and a volInfo structure and compares
693 * them. It returns non-zero if they are equal. It is used by GetVolInfo to
694 * search volInfo structures once it has the head volInfo structure from the
695 * volName hash table.
696 *
697 * When called from GetVolInfo the name compare is redundant.
698 * Always AND the flags with VOLINFOFLAGS for backwards compatability (3.3).
699 */
700
701static int
702VolInfoMatch(struct budb_volumeEntry *vol, struct volInfo *vi)
703{
704 return ((strcmp(vol->name, vi->name) == 0) && /* same volume name */
705 (vol->id == ntohl(vi->id)) && /* same volume id */
706 ((vol->flags & VOLINFOFLAGS) == (ntohl(vi->flags) & VOLINFOFLAGS)) && /* same flags */
707 (vol->partition == ntohl(vi->partition)) && /* same partition (N/A) */
708 (strcmp(vol->server, vi->server) == 0)); /* same server (N/A) */
709}
710
711/*
712 * GetVolInfo()
713 * This routine takes a volumeEntry structure from an RPC interface and
714 * returns the corresponding volInfo structure, creating it if necessary.
715 *
716 * The caller must write the entry out.
717 */
718
719static afs_int32
720GetVolInfo(struct ubik_trans *ut, struct budb_volumeEntry *volP, dbadr *viaP,
721 struct volInfo *viP)
722{
723 dbadr hvia, via;
724 struct volInfo hvi;
725 afs_int32 eval, code = 0;
726
727 eval = ht_LookupEntry(ut, &db.volName, volP->name, &via, viP);
728 if (eval)
729 ERROR(eval);
730
731 if (!via) {
732 /* allocate a new volinfo structure */
733 eval = AllocStructure(ut, volInfo_BLOCK, 0, &via, viP);
734 if (eval)
735 ERROR(eval);
736
737 strcpy(viP->name, volP->name);
738 strcpy(viP->server, volP->server);
739 viP->sameNameHead = 0; /* The head of same name chain */
740 viP->sameNameChain = 0; /* Same name chain is empty */
741 viP->firstFragment = 0;
742 viP->nFrags = 0;
743 viP->id = htonl(volP->id);
744 viP->partition = htonl(volP->partition);
745 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
746
747 /* Chain onto volname hash table */
748 eval = ht_HashIn(ut, &db.volName, via, viP);
749 if (eval)
750 ERROR(eval);
751
752 LogDebug(4, "volume Info for %s placed at %d\n", volP->name, via);
753 }
754
755 else if (!VolInfoMatch(volP, viP)) { /* Not the head volinfo struct */
756 hvia = via; /* remember the head volinfo struct */
757 memcpy(&hvi, viP, sizeof(hvi));
758
759 /* Search the same name chain for the correct volinfo structure */
760 for (via = ntohl(viP->sameNameChain); via;
761 via = ntohl(viP->sameNameChain)) {
762 eval = dbread(ut, via, viP, sizeof(*viP));
763 if (eval)
764 ERROR(eval);
765
766 if (VolInfoMatch(volP, viP))
767 break; /* found the one */
768 }
769
770 /* if the correct volinfo struct isn't found, create one */
771 if (!via) {
772 eval = AllocStructure(ut, volInfo_BLOCK, 0, &via, viP);
773 if (eval)
774 ERROR(eval);
775
776 strcpy(viP->name, volP->name);
777 strcpy(viP->server, volP->server);
778 viP->nameHashChain = 0; /* not in hash table */
779 viP->sameNameHead = htonl(hvia); /* chain to head of sameNameChain */
780 viP->sameNameChain = hvi.sameNameChain;
781 viP->firstFragment = 0;
782 viP->nFrags = 0;
783 viP->id = htonl(volP->id);
784 viP->partition = htonl(volP->partition);
785 viP->flags = htonl(volP->flags & VOLINFOFLAGS);
786
787 /* write the head entry's sameNameChain link */
788 eval =
789 set_word_addr(ut, hvia, &hvi, &hvi.sameNameChain, htonl(via));
790 if (eval)
791 ERROR(eval);
792 }
793 }
794
795 *viaP = via;
796
797 error_exit:
798 return code;
799}
800
801/* deletesomevolumesfromtape
802 * Deletes a specified number of volumes from a tape. The tape
803 * and dump are modified to reflect the smaller number of volumes.
804 * The transaction is not terminated, it is up to the caller to
805 * finish the transaction and start a new one (if desired).
806 * entry:
807 * maxvolumestodelete - don't delete more than this many volumes
808 */
809
810afs_int32
811deleteSomeVolumesFromTape(struct ubik_trans *ut, dbadr tapeAddr,
812 struct tape *tapePtr, int maxVolumesToDelete)
813{
814 dbadr volFragAddr, nextVolFragAddr, dumpAddr;
815 struct volFragment volFrag;
816 struct dump dump;
817 int volumesDeleted = 0;
818 afs_int32 eval, code = 0;
819
820 if (!tapePtr)
821 ERROR(0);
822
823 for (volFragAddr = ntohl(tapePtr->firstVol);
824 (volFragAddr && (maxVolumesToDelete > 0));
825 volFragAddr = nextVolFragAddr) {
826 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
827 if (eval)
828 ERROR(eval);
829
830 nextVolFragAddr = ntohl(volFrag.sameTapeChain);
831
832 eval = DeleteVolFragment(ut, volFragAddr, &volFrag);
833 if (eval)
834 ERROR(eval);
835
836 maxVolumesToDelete--;
837 volumesDeleted++;
838 }
839
840 /* reset the volume fragment pointer in the tape */
841 tapePtr->firstVol = htonl(volFragAddr);
842
843 /* diminish the tape's volume count */
844 tapePtr->nVolumes = htonl(ntohl(tapePtr->nVolumes) - volumesDeleted);
845
846 eval = dbwrite(ut, tapeAddr, tapePtr, sizeof(*tapePtr));
847 if (eval)
848 ERROR(eval);
849
850 /* diminish the dump's volume count */
851 dumpAddr = ntohl(tapePtr->dump);
852 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
853 if (eval)
854 ERROR(eval);
855
856 dump.nVolumes = htonl(ntohl(dump.nVolumes) - volumesDeleted);
857 eval = dbwrite(ut, dumpAddr, &dump, sizeof(dump));
858 if (eval)
859 ERROR(eval);
860
861 error_exit:
862 return (code);
863}
864
865/* deleteDump
866 * deletes a dump in stages, by repeatedly deleting a small number of
867 * volumes from the dump until none are left. The dump is then deleted.
868 *
869 * In the case where multiple calls are made to delete the same
870 * dump, the operation will succeed but contention for structures
871 * will result in someone getting back an error.
872 *
873 * entry:
874 * id - id of dump to delete
875 */
876
877afs_int32
878deleteDump(struct rx_call *call, dumpId id, budb_dumpsList *dumps)
879{
880 struct ubik_trans *ut;
881 dbadr dumpAddr, tapeAddr, appendedDump;
882 struct dump dump;
883 struct tape tape;
884 dumpId dumpid;
885 afs_int32 eval, code = 0;
886 int partialDel = 0;
887
888 /* iterate until the dump is truly deleted */
889
890 dumpid = id;
891 while (dumpid) {
892 partialDel = 0;
893 while (1) {
894 eval = InitRPC(&ut, LOCKWRITE, 1);
895 if (eval)
896 ERROR(eval); /* can't start transaction */
897
898 eval =
899 ht_LookupEntry(ut, &db.dumpIden, &dumpid, &dumpAddr, &dump);
900 if (eval)
901 ABORT(eval);
902 if (!dumpAddr)
903 ABORT(BUDB_NOENT); /* can't find dump */
904
905 if ((dumpid == id) && (dump.initialDumpID)) /* can't be an appended dump */
906 ABORT(BUDB_NOTINITIALDUMP);
907
908 tapeAddr = ntohl(dump.firstTape);
909 if (tapeAddr == 0)
910 break;
911
912 /* there is a tape to delete */
913 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
914 if (eval)
915 ABORT(eval);
916
917 if (ntohl(tape.nVolumes)) {
918 /* tape is not empty */
919 eval = deleteSomeVolumesFromTape(ut, tapeAddr, &tape, 10);
920 if (eval)
921 ABORT(eval);
922 }
923
924 if (ntohl(tape.nVolumes) == 0) {
925 /* tape is now empty, delete it */
926 eval = DeleteTape(ut, tapeAddr, &tape);
927 if (eval)
928 ABORT(eval);
929 eval = ht_HashOut(ut, &db.tapeName, tapeAddr, &tape);
930 if (eval)
931 ABORT(eval);
932 eval = FreeStructure(ut, tape_BLOCK, tapeAddr);
933 if (eval)
934 ABORT(eval);
935 }
936
937 eval = ubik_EndTrans(ut);
938 if (eval)
939 ERROR(eval);
940 partialDel = 1;
941 } /* next deletion portion */
942
943 /* Record the dump just deleted */
944 if (dumps && (dumps->budb_dumpsList_len < BUDB_MAX_RETURN_LIST)) {
945 if (dumps->budb_dumpsList_len == 0)
946 dumps->budb_dumpsList_val = malloc(sizeof(afs_int32));
947 else
948 dumps->budb_dumpsList_val =
949 realloc(dumps->budb_dumpsList_val,
950 (dumps->budb_dumpsList_len + 1)
951 * sizeof(afs_int32));
952
953 if (!dumps->budb_dumpsList_val)
954 ABORT(BUDB_NOMEM);
955
956 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] = dumpid;
957 dumps->budb_dumpsList_len++;
958 }
959
960 appendedDump = ntohl(dump.appendedDumpChain);
961
962 /* finally done. No more tapes left in the dump. Delete the dump itself */
963 eval = DeleteDump(ut, dumpAddr, &dump);
964 if (eval)
965 ABORT(eval);
966
967 /* Now delete the appended dump too */
968 if (appendedDump) {
969 eval = dbread(ut, appendedDump, &dump, sizeof(dump));
970 if (eval)
971 ABORT(eval);
972
973 dumpid = ntohl(dump.id);
974 } else
975 dumpid = 0;
976
977 eval = ubik_EndTrans(ut);
978 if (eval)
979 ERROR(eval);
980
981 Log("Delete dump %s (DumpID %u), path %s\n", dump.dumpName,
982 ntohl(dump.id), dump.dumpPath);
983 }
984
985 error_exit:
986 if (code && partialDel) {
987 Log("Delete dump %s (DumpID %u), path %s - INCOMPLETE (code = %u)\n",
988 dump.dumpName, ntohl(dump.id), dump.dumpPath, code);
989 }
990 return (code);
991
992 abort_exit:
993 ubik_AbortTrans(ut);
994 goto error_exit;
995}
996
997/* --------------
998 * dump selection routines - used by BUDB_GetDumps
999 * --------------
1000 */
1001
1002/* most recent dump selection */
1003
1004struct chosenDump {
1005 struct chosenDump *next;
1006 dbadr addr;
1007 afs_uint32 date;
1008};
1009
1010struct wantDumpRock {
1011 int maxDumps; /* max wanted */
1012 int ndumps; /* actual in chain */
1013 struct chosenDump *chain;
1014};
1015
1016
1017int
1018wantDump(dbadr dumpAddr, void *dumpParam, void *dumpListPtrParam)
1019{
1020 struct dump *dumpPtr;
1021 struct wantDumpRock *rockPtr;
1022
1023 dumpPtr = (struct dump *)dumpParam;
1024 rockPtr = (struct wantDumpRock *)dumpListPtrParam;
1025
1026 /* if we don't have our full complement, just add another */
1027 if (rockPtr->ndumps < rockPtr->maxDumps)
1028 return (1);
1029
1030 /* got the number we need, select based on date */
1031 if ((afs_uint32) ntohl(dumpPtr->created) > rockPtr->chain->date)
1032 return (1);
1033
1034 return (0);
1035}
1036
1037int
1038rememberDump(dbadr dumpAddr, void *dumpParam, void *dumpListPtrParam)
1039{
1040 struct dump *dumpPtr;
1041 struct wantDumpRock *rockPtr;
1042 struct chosenDump *ptr, *deletedPtr, **nextPtr;
1043
1044 dumpPtr = (struct dump *)dumpParam;
1045 rockPtr = (struct wantDumpRock *)dumpListPtrParam;
1046
1047 ptr = calloc(1, sizeof(*ptr));
1048 if (!ptr)
1049 return (0);
1050 ptr->addr = dumpAddr;
1051 ptr->date = (afs_uint32) ntohl(dumpPtr->created);
1052
1053 /* Don't overflow the max */
1054 while (rockPtr->ndumps >= rockPtr->maxDumps) {
1055 /* have to drop one */
1056 deletedPtr = rockPtr->chain;
1057 rockPtr->chain = deletedPtr->next;
1058 free(deletedPtr);
1059 rockPtr->ndumps--;
1060 }
1061
1062 /* now insert in the right place */
1063 for (nextPtr = &rockPtr->chain; *nextPtr; nextPtr = &((*nextPtr)->next)) {
1064 if (ptr->date < (*nextPtr)->date)
1065 break;
1066 }
1067 ptr->next = *nextPtr;
1068 *nextPtr = ptr;
1069 rockPtr->ndumps++;
1070
1071 return (0);
1072}
1073
1074
1075/* ---------------------------------------------
1076 * general interface routines - alphabetic
1077 * ---------------------------------------------
1078 */
1079
1080afs_int32
1081SBUDB_AddVolume(struct rx_call *call, struct budb_volumeEntry *vol)
1082{
1083 afs_int32 code;
1084
1085 code = AddVolume(call, vol);
1086 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, (vol ? vol->id : 0),
1087 AUD_END);
1088 return code;
1089}
1090
1091afs_int32
1092AddVolume(struct rx_call *call, struct budb_volumeEntry *vol)
1093{
1094 struct ubik_trans *ut;
1095 dbadr da, ta, via, va;
1096 struct dump d;
1097 struct tape t;
1098 struct volInfo vi;
1099 struct volFragment v;
1100 afs_uint32 bytes;
1101 afs_int32 eval, code = 0;
1102
1103 if (!callPermitted(call))
1104 return BUDB_NOTPERMITTED;
1105
1106 if ((strlen(vol->name) >= sizeof(vi.name))
1107 || (strlen(vol->server) >= sizeof(vi.server))
1108 || (strlen(vol->tape) >= sizeof(t.name)))
1109 return BUDB_BADARGUMENT;
1110
1111 eval = InitRPC(&ut, LOCKWRITE, 1);
1112 if (eval)
1113 return eval;
1114
1115 /* Find the dump in dumpid hash table */
1116 eval = ht_LookupEntry(ut, &db.dumpIden, &vol->dump, &da, &d);
1117 if (eval)
1118 ABORT(eval);
1119 if (!da)
1120 ABORT(BUDB_NODUMPID);
1121
1122 /* search for the right tape in the dump */
1123 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
1124 /* read the tape entry */
1125 eval = dbread(ut, ta, &t, sizeof(t));
1126 if (eval)
1127 ABORT(eval);
1128
1129 /* Check if the right tape name */
1130 if (strcmp(t.name, vol->tape) == 0)
1131 break;
1132 }
1133 if (!ta)
1134 ABORT(BUDB_NOTAPENAME);
1135
1136 if ((t.dump != htonl(da)) || /* tape must belong to dump */
1137 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1138 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)) /* dump must be in progress */
1139 ABORT(BUDB_BADPROTOCOL);
1140
1141 /* find or create a volume info structure */
1142 eval = GetVolInfo(ut, vol, &via, &vi);
1143 if (eval)
1144 ABORT(eval);
1145
1146 /* Create a volume fragment */
1147 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1148 if (eval)
1149 ABORT(eval);
1150
1151 v.vol = htonl(via); /* vol frag points to vol info */
1152 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1153 vi.firstFragment = htonl(va);
1154 vi.nFrags = htonl(ntohl(vi.nFrags) + 1);
1155
1156 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1157 if (eval)
1158 ABORT(eval);
1159
1160 v.tape = htonl(ta); /* vol frag points to tape */
1161 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1162 t.firstVol = htonl(va);
1163 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1164 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1165 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes / (1024 * 1024));
1166 t.nBytes = htonl(bytes % (1024 * 1024));
1167
1168 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1169 if (eval)
1170 ABORT(eval);
1171
1172 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1173
1174 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1175 if (eval)
1176 ABORT(eval);
1177
1178 v.position = htonl(vol->position); /* vol frag info */
1179 v.clone = htonl(vol->clone);
1180 v.incTime = htonl(vol->incTime);
1181 v.startByte = htonl(vol->startByte);
1182 v.nBytes = htonl(vol->nBytes);
1183 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1184 v.sequence = htons(vol->seq);
1185
1186 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1187 if (eval)
1188 ABORT(eval);
1189
1190 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1191 if (eval)
1192 ABORT(eval);
1193
1194 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1195
1196 code = ubik_EndTrans(ut);
1197 return code;
1198
1199 abort_exit:
1200 ubik_AbortTrans(ut);
1201 return code;
1202}
1203
1204
1205afs_int32
1206SBUDB_AddVolumes(struct rx_call *call, struct budb_volumeList *vols)
1207{
1208 afs_int32 code;
1209
1210 code = AddVolumes(call, vols);
1211 osi_auditU(call, BUDB_AddVolEvent, code, AUD_LONG, 0, AUD_END);
1212 return code;
1213}
1214
1215afs_int32
1216AddVolumes(struct rx_call *call, struct budb_volumeList *vols)
1217{
1218 struct budb_volumeEntry *vol, *vol1;
1219 struct ubik_trans *ut;
1220 dbadr da, ta, via, va;
1221 struct dump d;
1222 struct tape t;
1223 struct volInfo vi;
1224 struct volFragment v;
1225 afs_uint32 bytes;
1226 afs_int32 eval, e, code = 0;
1227
1228 if (!callPermitted(call))
1229 return BUDB_NOTPERMITTED;
1230
1231 if (!vols || (vols->budb_volumeList_len <= 0)
1232 || !vols->budb_volumeList_val)
1233 return BUDB_BADARGUMENT;
1234
1235 /* The first volume in the list of volumes to add */
1236 vol1 = (struct budb_volumeEntry *)vols->budb_volumeList_val;
1237
1238 eval = InitRPC(&ut, LOCKWRITE, 1);
1239 if (eval)
1240 return eval;
1241
1242 /* Find the dump in dumpid hash table */
1243 eval = ht_LookupEntry(ut, &db.dumpIden, &vol1->dump, &da, &d);
1244 if (eval)
1245 ABORT(eval);
1246 if (!da)
1247 ABORT(BUDB_NODUMPID);
1248
1249 /* search for the right tape in the dump */
1250 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
1251 /* read the tape entry */
1252 eval = dbread(ut, ta, &t, sizeof(t));
1253 if (eval)
1254 ABORT(eval);
1255
1256 /* Check if the right tape name */
1257 if (strcmp(t.name, vol1->tape) == 0)
1258 break;
1259 }
1260 if (!ta)
1261 ABORT(BUDB_NOTAPENAME);
1262
1263 if ((t.dump != htonl(da)) || /* tape must belong to dump */
1264 ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0) || /* tape must be being written */
1265 ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)) /* dump must be in progress */
1266 ABORT(BUDB_BADPROTOCOL);
1267
1268 for (vol = vol1, e = 0; e < vols->budb_volumeList_len; vol++, e++) {
1269 /*v */
1270 if ((strlen(vol->name) >= sizeof(vi.name)) || (strcmp(vol->name, "") == 0) || /* no null volnames */
1271 (strlen(vol->server) >= sizeof(vi.server))
1272 || (strlen(vol->tape) >= sizeof(t.name))
1273 || (strcmp(vol->tape, vol1->tape) != 0)) {
1274 Log("Volume '%s' %u, tape '%s', dumpID %u is an invalid entry - not added\n", vol->name, vol->id, vol->tape, vol->dump);
1275 continue;
1276 }
1277
1278 /* find or create a volume info structure */
1279 eval = GetVolInfo(ut, vol, &via, &vi);
1280 if (eval)
1281 ABORT(eval);
1282 if (*(afs_int32 *) (&vi) == 0) {
1283 Log("Volume '%s', tape '%s', dumpID %u is an invalid entry - aborted\n", vol->name, vol->tape, vol->dump);
1284 ABORT(BUDB_BADARGUMENT);
1285 }
1286
1287 /* Create a volume fragment */
1288 eval = AllocStructure(ut, volFragment_BLOCK, 0, &va, &v);
1289 if (eval)
1290 ABORT(eval);
1291
1292 v.vol = htonl(via); /* vol frag points to vol info */
1293 v.sameNameChain = vi.firstFragment; /* vol frag is chained to vol info */
1294 vi.firstFragment = htonl(va);
1295 vi.nFrags = htonl(ntohl(vi.nFrags) + 1);
1296 eval = dbwrite(ut, via, &vi, sizeof(vi)); /* write the vol info struct */
1297 if (eval)
1298 ABORT(eval);
1299
1300 v.tape = htonl(ta); /* vol frag points to tape */
1301 v.sameTapeChain = t.firstVol; /* vol frag is chained to tape info */
1302 t.firstVol = htonl(va);
1303 t.nVolumes = htonl(ntohl(t.nVolumes) + 1);
1304 bytes = ntohl(t.nBytes) + vol->nBytes; /* update bytes on tape */
1305 t.nMBytes = htonl(ntohl(t.nMBytes) + bytes / (1024 * 1024));
1306 t.nBytes = htonl(bytes % (1024 * 1024));
1307
1308 d.nVolumes = htonl(ntohl(d.nVolumes) + 1); /* one more volume on dump */
1309
1310 v.position = htonl(vol->position); /* vol frag info */
1311 v.clone = htonl(vol->clone);
1312 v.incTime = htonl(vol->incTime);
1313 v.startByte = htonl(vol->startByte);
1314 v.nBytes = htonl(vol->nBytes);
1315 v.flags = htons(vol->flags & VOLFRAGMENTFLAGS);
1316 v.sequence = htons(vol->seq);
1317
1318 eval = dbwrite(ut, va, &v, sizeof(v)); /* write out the vol frag struct */
1319 if (eval)
1320 ABORT(eval);
1321
1322 LogDebug(4, "added volume %s at %d\n", vol->name, va);
1323 } /*v */
1324
1325 eval = dbwrite(ut, ta, &t, sizeof(t)); /* write the tape structure */
1326 if (eval)
1327 ABORT(eval);
1328
1329 eval = dbwrite(ut, da, &d, sizeof(d)); /* write out the dump structure */
1330 if (eval)
1331 ABORT(eval);
1332
1333 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1334 if (eval)
1335 ABORT(eval);
1336
1337 code = ubik_EndTrans(ut);
1338 return code;
1339
1340 abort_exit:
1341 ubik_AbortTrans(ut);
1342 return code;
1343}
1344
1345
1346/* BUDB_CreateDump
1347 * records the existence of a dump in the database. This creates only
1348 * the dump record, to which one must attach tape and volume records.
1349 * TBD
1350 * 1) record the volume set
1351 */
1352
1353afs_int32
1354SBUDB_CreateDump(struct rx_call *call, struct budb_dumpEntry *dump)
1355{
1356 afs_int32 code;
1357
1358 code = CreateDump(call, dump);
1359 osi_auditU(call, BUDB_CrDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
1360 AUD_END);
1361 if (dump && !code) {
1362 Log("Create dump %s (DumpID %u), path %s\n", dump->name, dump->id,
1363 dump->dumpPath);
1364 }
1365 return code;
1366}
1367
1368afs_int32
1369CreateDump(struct rx_call *call, struct budb_dumpEntry *dump)
1370{
1371 struct ubik_trans *ut;
1372 dbadr findDumpAddr, da;
1373 struct dump findDump, d;
1374 afs_int32 eval, code = 0;
1375
1376 rxkad_level level;
1377 afs_int32 kvno;
1378 Date expiration; /* checked by Security Module */
1379 struct ktc_principal principal;
1380
1381 if (!callPermitted(call))
1382 return BUDB_NOTPERMITTED;
1383
1384 if (strlen(dump->name) >= sizeof(d.dumpName))
1385 return BUDB_BADARGUMENT;
1386
1387 eval = InitRPC(&ut, LOCKWRITE, 1);
1388 if (eval)
1389 return eval;
1390
1391 eval =
1392 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration,
1393 principal.name, principal.instance,
1394 principal.cell, &kvno);
1395
1396 if (eval) {
1397 if (eval != RXKADNOAUTH)
1398 ABORT(eval);
1399
1400 strcpy(principal.name, "");
1401 strcpy(principal.instance, "");
1402 strcpy(principal.cell, "");
1403 expiration = 0;
1404 } else {
1405 /* authenticated. Take user supplied principal information */
1406 if (strcmp(dump->dumper.name, "") != 0)
1407 strncpy(principal.name, dump->dumper.name,
1408 sizeof(principal.name));
1409
1410 if (strcmp(dump->dumper.instance, "") != 0)
1411 strncpy(principal.instance, dump->dumper.instance,
1412 sizeof(principal.instance));
1413
1414 if (strcmp(dump->dumper.cell, "") != 0)
1415 strncpy(principal.cell, dump->dumper.cell,
1416 sizeof(principal.cell));
1417 }
1418
1419 /* dump id's are time stamps */
1420 if (!dump->id) {
1421 while (1) { /* allocate a unique dump id *//*w */
1422 dump->id = time(0);
1423
1424 /* ensure it is unique - seach for dumpid in hash table */
1425 eval =
1426 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1427 &findDump);
1428 if (eval)
1429 ABORT(eval);
1430
1431 if (!findDumpAddr) { /* dumpid not in use */
1432 /* update the last dump id allocated */
1433 eval = set_header_word(ut, lastDumpId, htonl(dump->id));
1434 if (eval)
1435 ABORT(eval);
1436 break;
1437 }
1438
1439 /* dump id is in use - wait a while */
1440#ifdef AFS_PTHREAD_ENV
1441 sleep(1);
1442#else
1443 IOMGR_Sleep(1);
1444#endif
1445 } /*w */
1446 } else {
1447 /* dump id supplied (e.g. for database restore) */
1448 eval =
1449 ht_LookupEntry(ut, &db.dumpIden, &dump->id, &findDumpAddr,
1450 &findDump);
1451 if (eval)
1452 ABORT(eval);
1453
1454 /* Dump id must not already exist */
1455 if (findDumpAddr)
1456 ABORT(BUDB_DUMPIDEXISTS);
1457 }
1458
1459 /* Allocate a dump structure */
1460 memset(&d, 0, sizeof(d));
1461 eval = AllocStructure(ut, dump_BLOCK, 0, &da, &d);
1462 if (eval)
1463 ABORT(eval);
1464
1465 strcpy(d.dumpName, dump->name); /* volset.dumpname */
1466 strcpy(d.dumpPath, dump->dumpPath); /* dump node path */
1467 strcpy(d.volumeSet, dump->volumeSetName); /* volume set */
1468 d.id = htonl(dump->id);
1469 d.parent = htonl(dump->parent); /* parent id */
1470 d.level = htonl(dump->level);
1471
1472 LogDebug(4, "dump name %s, parent %d level %d\n", dump->name,
1473 dump->parent, dump->level);
1474
1475 /* if creation time specified, use that. Else use the dumpid time */
1476 if (dump->created == 0)
1477 dump->created = dump->id;
1478 d.created = htonl(dump->created);
1479
1480 d.dumper = principal;
1481 tapeSet_hton(&dump->tapes, &d.tapes);
1482
1483 d.flags = htonl(dump->flags | BUDB_DUMP_INPROGRESS);
1484
1485 eval = ht_HashIn(ut, &db.dumpName, da, &d); /* Into dump name hash table */
1486 if (eval)
1487 ABORT(eval);
1488
1489 eval = ht_HashIn(ut, &db.dumpIden, da, &d); /* Into dumpid hash table */
1490 if (eval)
1491 ABORT(eval);
1492
1493 eval = dbwrite(ut, da, (char *)&d, sizeof(d)); /* Write the dump structure */
1494 if (eval)
1495 ABORT(eval);
1496
1497 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1498 if (eval)
1499 ABORT(eval);
1500
1501 /* If to append this dump, then append it - will write the appended dump */
1502 eval = makeAppended(ut, dump->id, dump->initialDumpID, dump->tapes.b);
1503 if (eval)
1504 ABORT(eval);
1505
1506 code = ubik_EndTrans(ut);
1507 LogDebug(5, "made dump %s, path %s\n", d.dumpName, d.dumpPath);
1508 return code;
1509
1510 abort_exit:
1511 ubik_AbortTrans(ut);
1512 return code;
1513}
1514
1515afs_int32
1516SBUDB_DeleteDump(struct rx_call *call, dumpId id, Date fromTime, Date toTime,
1517 budb_dumpsList *dumps)
1518{
1519 afs_int32 code;
1520
1521 code = DoDeleteDump(call, id, fromTime, toTime, dumps);
1522 osi_auditU(call, BUDB_DelDmpEvent, code, AUD_DATE, id, AUD_END);
1523 return code;
1524}
1525
1526#define MAXOFFS 30
1527
1528afs_int32
1529DoDeleteDump(struct rx_call *call, dumpId id, Date fromTime, Date toTime,
1530 budb_dumpsList *dumps)
1531{
1532 afs_int32 code = 0;
1533
1534 if (!callPermitted(call))
1535 return BUDB_NOTPERMITTED;
1536
1537 if (id)
1538 code = deleteDump(call, id, dumps);
1539 return (code);
1540}
1541
1542afs_int32
1543SBUDB_ListDumps(struct rx_call *call, afs_int32 sflags, char *name,
1544 afs_int32 groupid, Date fromTime, Date toTime,
1545 budb_dumpsList *dumps, budb_dumpsList *flags)
1546{
1547 afs_int32 code;
1548
1549 code = ListDumps(call, sflags, groupid, fromTime, toTime, dumps, flags);
1550 osi_auditU(call, BUDB_LstDmpEvent, code, AUD_LONG, flags, AUD_END);
1551 return code;
1552}
1553
1554afs_int32
1555ListDumps(struct rx_call *call, afs_int32 sflags, afs_int32 groupid,
1556 Date fromTime, Date toTime, budb_dumpsList *dumps,
1557 budb_dumpsList *flags)
1558{
1559 struct ubik_trans *ut;
1560 struct memoryHashTable *mht;
1561 struct dump diskDump, appDiskDump;
1562 dbadr dbAddr, dbAppAddr;
1563
1564 afs_int32 eval, code = 0;
1565 int old, hash, length, entrySize, count = 0;
1566
1567 if (!callPermitted(call))
1568 return BUDB_NOTPERMITTED;
1569
1570 eval = InitRPC(&ut, LOCKREAD, 1);
1571 if (eval)
1572 return (eval);
1573
1574 /* Search the database */
1575 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
1576 if (!mht)
1577 return (BUDB_BADARGUMENT);
1578
1579 for (old = 0; old <= 1; old++) { /*o *//* old and new hash tables */
1580 length = (old ? mht->oldLength : mht->length);
1581 if (length == 0)
1582 continue;
1583
1584 for (hash = 0; hash < length; hash++) { /*h *//* for each hash bucket */
1585 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) { /*d */
1586
1587 /* read the entry */
1588 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
1589 if (eval)
1590 ABORT(eval);
1591
1592 /* Skip appended dumps */
1593 if (ntohl(diskDump.initialDumpID) != 0) {
1594 continue;
1595 }
1596
1597 /* Skip dumps with different goup id */
1598 if ((sflags & BUDB_OP_GROUPID)
1599 && (ntohl(diskDump.tapes.id) != groupid)) {
1600 continue; /*nope */
1601 }
1602
1603 /* Look at this dump to see if it meets the criteria for listing */
1604 if (sflags & BUDB_OP_DATES) {
1605 /* This and each appended dump should be in time */
1606 for (dbAppAddr = dbAddr; dbAppAddr;
1607 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1608 eval =
1609 dbread(ut, dbAppAddr, &appDiskDump,
1610 sizeof(appDiskDump));
1611 if (eval)
1612 ABORT(eval);
1613
1614 if ((ntohl(appDiskDump.id) < fromTime)
1615 || (ntohl(appDiskDump.id) > toTime))
1616 break; /*nope */
1617 }
1618 if (dbAppAddr)
1619 continue; /*nope */
1620 }
1621
1622 /* Add it and each of its appended dump to our list to return */
1623 for (dbAppAddr = dbAddr; dbAppAddr;
1624 dbAppAddr = ntohl(appDiskDump.appendedDumpChain)) {
1625 eval =
1626 dbread(ut, dbAppAddr, &appDiskDump,
1627 sizeof(appDiskDump));
1628 if (eval)
1629 ABORT(eval);
1630
1631 /* Make sure we have space to list it */
1632 if (dumps->budb_dumpsList_len >= count) {
1633 count += 10;
1634 if (count == 10) {
1635 dumps->budb_dumpsList_val =
1636 malloc(count * sizeof(afs_int32));
1637 flags->budb_dumpsList_val =
1638 malloc(count * sizeof(afs_int32));
1639 } else {
1640 dumps->budb_dumpsList_val =
1641 realloc(dumps->budb_dumpsList_val,
1642 count * sizeof(afs_int32));
1643 flags->budb_dumpsList_val =
1644 realloc(flags->budb_dumpsList_val,
1645 count * sizeof(afs_int32));
1646 }
1647 if (!dumps->budb_dumpsList_val
1648 || !dumps->budb_dumpsList_val)
1649 ABORT(BUDB_NOMEM);
1650 }
1651
1652 /* Add it to our list */
1653 dumps->budb_dumpsList_val[dumps->budb_dumpsList_len] =
1654 ntohl(appDiskDump.id);
1655 flags->budb_dumpsList_val[flags->budb_dumpsList_len] = 0;
1656 if (ntohl(appDiskDump.initialDumpID) != 0) {
1657 flags->budb_dumpsList_val[flags->
1658 budb_dumpsList_len] |=
1659 BUDB_OP_APPDUMP;
1660 }
1661 if (strcmp(appDiskDump.dumpName, DUMP_TAPE_NAME) == 0) {
1662 flags->budb_dumpsList_val[flags->
1663 budb_dumpsList_len] |=
1664 BUDB_OP_DBDUMP;
1665 }
1666 dumps->budb_dumpsList_len++;
1667 flags->budb_dumpsList_len++;
1668 }
1669 } /*d */
1670 } /*h */
1671 } /*o */
1672
1673 code = ubik_EndTrans(ut);
1674 return (code);
1675
1676 abort_exit:
1677 ubik_AbortTrans(ut);
1678 return (code);
1679}
1680
1681afs_int32
1682SBUDB_DeleteTape(struct rx_call *call,
1683 struct budb_tapeEntry *tape) /* tape info */
1684{
1685 afs_int32 code;
1686
1687 code = DoDeleteTape(call, tape);
1688 osi_auditU(call, BUDB_DelTpeEvent, code, AUD_DATE,
1689 (tape ? tape->dump : 0), AUD_END);
1690 return code;
1691}
1692
1693afs_int32
1694DoDeleteTape(struct rx_call *call,
1695 struct budb_tapeEntry *tape) /* tape info */
1696{
1697 struct ubik_trans *ut;
1698 struct tape t;
1699 dbadr a;
1700 afs_int32 eval, code;
1701
1702 if (!callPermitted(call))
1703 return BUDB_NOTPERMITTED;
1704
1705 eval = InitRPC(&ut, LOCKWRITE, 1);
1706 if (eval)
1707 return eval;
1708
1709 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
1710 if (eval)
1711 ABORT(eval);
1712
1713 eval = DeleteTape(ut, a, &t);
1714 if (eval)
1715 ABORT(eval);
1716
1717 eval = FreeStructure(ut, tape_BLOCK, a);
1718 if (eval)
1719 ABORT(eval);
1720
1721 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
1722 if (eval)
1723 ABORT(eval);
1724
1725 code = ubik_EndTrans(ut);
1726 return code;
1727
1728 abort_exit:
1729 ubik_AbortTrans(ut);
1730 return code;
1731}
1732
1733/* BUDB_DeleteVDP
1734 * Deletes old information from the database for a particular dump path
1735 * and volumset. This supercedes the old policy implemented in
1736 * UseTape, which simply matched on the volumeset.dump. Consequently
1737 * it was unable to handle name re-use.
1738 * entry:
1739 * dsname - dumpset name, i.e. volumeset.dumpname
1740 * dumpPath - full path of dump node
1741 * curDumpID - current dump in progress - so that is may be excluded
1742 * exit:
1743 * 0 - ok
1744 * n - some error. May or may not have deleted information.
1745 */
1746
1747afs_int32
1748SBUDB_DeleteVDP(struct rx_call *call, char *dsname, char *dumpPath,
1749 afs_int32 curDumpId)
1750{
1751 afs_int32 code;
1752
1753 code = DeleteVDP(call, dsname, dumpPath, curDumpId);
1754 osi_auditU(call, BUDB_DelVDPEvent, code, AUD_STR, dsname, AUD_END);
1755 return code;
1756}
1757
1758afs_int32
1759DeleteVDP(struct rx_call *call, char *dsname, char *dumpPath,
1760 afs_int32 curDumpId)
1761{
1762 struct dump dump;
1763 dbadr dumpAddr;
1764
1765 struct ubik_trans *ut;
1766 afs_int32 eval, code = 0;
1767
1768 if (!callPermitted(call))
1769 return BUDB_NOTPERMITTED;
1770
1771 while (1) {
1772 eval = InitRPC(&ut, LOCKREAD, 1);
1773 if (eval)
1774 return (eval);
1775
1776 eval = ht_LookupEntry(ut, &db.dumpName, dsname, &dumpAddr, &dump);
1777 if (eval)
1778 ABORT(eval);
1779
1780 while (dumpAddr != 0) { /*wd */
1781 if ((strcmp(dump.dumpName, dsname) == 0)
1782 && (strcmp(dump.dumpPath, dumpPath) == 0)
1783 && (ntohl(dump.id) != curDumpId)) {
1784 eval = ubik_EndTrans(ut);
1785 if (eval)
1786 return (eval);
1787
1788 eval = deleteDump(call, ntohl(dump.id), 0);
1789 if (eval)
1790 return (eval);
1791
1792 /* start the traversal over since the various chains may
1793 * have changed
1794 */
1795 break;
1796 }
1797
1798 dumpAddr = ntohl(dump.nameHashChain);
1799 if (dumpAddr) {
1800 eval = dbread(ut, dumpAddr, &dump, sizeof(dump));
1801 if (eval)
1802 ABORT(eval);
1803 }
1804 } /*wd */
1805
1806 /* check if all the dumps have been examined - can terminate */
1807 if (!dumpAddr) {
1808 eval = ubik_EndTrans(ut);
1809 return (eval);
1810 }
1811 }
1812
1813 abort_exit:
1814 ubik_AbortTrans(ut);
1815 return (code);
1816}
1817
1818/* BUDB_FindClone
1819 * notes:
1820 * Given a volume name, and a dumpID, find the volume in that dump and
1821 * return the clone date of the volume (this is the clone date of the
1822 * volume at the time it was dumped).
1823 *
1824 * Hashes on the volume name and traverses the fragments. Will need to read
1825 * the volumes tape entry to determine if it belongs to the dump. If the
1826 * volume is not found in the dump, then look for it in its parent dump.
1827 */
1828
1829afs_int32
1830SBUDB_FindClone(struct rx_call *call, afs_int32 dumpID, char *volName,
1831 afs_int32 *clonetime)
1832{
1833 afs_int32 code;
1834
1835 code = FindClone(call, dumpID, volName, clonetime);
1836 osi_auditU(call, BUDB_FndClnEvent, code, AUD_STR, volName, AUD_END);
1837 return code;
1838}
1839
1840afs_int32
1841FindClone(struct rx_call *call, afs_int32 dumpID, char *volName,
1842 afs_int32 *clonetime)
1843{
1844 struct ubik_trans *ut;
1845 dbadr da, hvia, via, vfa;
1846 struct dump d;
1847 struct tape t;
1848 struct volFragment vf;
1849 struct volInfo vi;
1850 int rvi; /* read the volInfo struct */
1851 afs_int32 eval, code = 0;
1852
1853 if (!callPermitted(call))
1854 return BUDB_NOTPERMITTED;
1855
1856 eval = InitRPC(&ut, LOCKREAD, 1);
1857 if (eval)
1858 return (eval);
1859
1860 *clonetime = 0;
1861
1862 /* Search for the volume by name */
1863 eval = ht_LookupEntry(ut, &db.volName, volName, &hvia, &vi);
1864 if (eval)
1865 ABORT(eval);
1866 if (!hvia)
1867 ABORT(BUDB_NOVOLUMENAME);
1868 rvi = 0;
1869
1870 /* Follw the dump levels up */
1871 for (; dumpID; dumpID = ntohl(d.parent)) { /*d */
1872 /* Get the dump entry */
1873 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &da, &d);
1874 if (eval)
1875 ABORT(eval);
1876 if (!da)
1877 ABORT(BUDB_NODUMPID);
1878
1879 /* seach all the volInfo entries on the sameNameChain */
1880 for (via = hvia; via; via = ntohl(vi.sameNameChain)) { /*via */
1881 if (rvi) { /* Read the volInfo entry - except first time */
1882 eval = dbread(ut, via, &vi, sizeof(vi));
1883 if (eval)
1884 ABORT(eval);
1885 }
1886 rvi = 1;
1887
1888 /* search all the volFrag entries on the volFrag */
1889 for (vfa = ntohl(vi.firstFragment); vfa; vfa = ntohl(vf.sameNameChain)) { /*vfa */
1890 eval = dbread(ut, vfa, &vf, sizeof(vf)); /* Read the volFrag entry */
1891 if (eval)
1892 ABORT(eval);
1893
1894 eval = dbread(ut, ntohl(vf.tape), &t, sizeof(t)); /* Read the tape */
1895 if (eval)
1896 ABORT(eval);
1897
1898 /* Now check to see if this fragment belongs to the dump we have */
1899 if (ntohl(t.dump) == da) {
1900 *clonetime = ntohl(vf.clone); /* return the clone */
1901 ERROR(0);
1902 }
1903 } /*vfa */
1904 } /*via */
1905 } /*d */
1906
1907 error_exit:
1908 code = ubik_EndTrans(ut);
1909 return (code);
1910
1911 abort_exit:
1912 ubik_EndTrans(ut);
1913 return (code);
1914}
1915
1916#ifdef notdef
1917/*
1918 * Searches each tape and each volume in the dump until the volume is found.
1919 * If the volume is not in the dump, then we search it's parent dump.
1920 *
1921 * Re-write to do lookups by volume name.
1922 */
1923afs_int32
1924FindClone(struct rx_call *call, afs_int32 dumpID, char *volName,
1925 afs_int32 *clonetime)
1926{
1927 struct ubik_trans *ut;
1928 dbadr diskAddr, tapeAddr, volFragmentAddr;
1929 struct dump dump;
1930 struct tape tape;
1931 struct volFragment volFragment;
1932 struct volInfo volInfo;
1933 afs_int32 eval, code = 0;
1934
1935 if (!callPermitted(call))
1936 return BUDB_NOTPERMITTED;
1937
1938 eval = InitRPC(&ut, LOCKREAD, 1);
1939 if (eval)
1940 return (eval);
1941
1942 *clonetime = 0;
1943
1944 for (; dumpID; dumpID = ntohl(dump.parent)) { /*d */
1945 /* Get the dump entry */
1946 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &diskAddr, &dump);
1947 if (eval)
1948 ABORT(eval);
1949 if (!diskAddr)
1950 ABORT(BUDB_NODUMPID);
1951
1952 /* just to be sure */
1953 if (ntohl(dump.id) != dumpID) {
1954 LogDebug(4, "BUDB_FindClone: requested %d, found %d\n", dumpID,
1955 ntohl(dump.id));
1956 ABORT(BUDB_INTERNALERROR);
1957 }
1958
1959 /* search all the tapes in this dump */
1960 for (tapeAddr = ntohl(dump.firstTape); tapeAddr; tapeAddr = ntohl(tape.nextTape)) { /*t */
1961 /* Get the tape entry */
1962 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
1963 if (eval)
1964 ABORT(eval);
1965
1966 /* search all the volume fragments on this tape */
1967 for (volFragmentAddr = ntohl(tape.firstVol); volFragmentAddr; volFragmentAddr = ntohl(volFragment.sameTapeChain)) { /*vf */
1968 /* Get the volume fragment entry */
1969 eval =
1970 dbread(ut, volFragmentAddr, &volFragment,
1971 sizeof(volFragment));
1972 if (eval)
1973 ABORT(eval);
1974
1975 /* Get the volume info entry */
1976 eval =
1977 dbread(ut, ntohl(volFragment.vol), &volInfo,
1978 sizeof(volInfo));
1979 if (eval)
1980 ABORT(eval);
1981
1982 /* check if this volume is the one we want */
1983 if (strcmp(volInfo.name, volName) == 0) {
1984 *clonetime = ntohl(volFragment.clone);
1985 ERROR(0);
1986 }
1987 } /*vf */
1988 } /*t */
1989 } /*d */
1990
1991 error_exit:
1992 code = ubik_EndTrans(ut);
1993 return (code);
1994
1995 abort_exit:
1996 ubik_EndTrans(ut);
1997 return (code);
1998}
1999#endif
2000
2001/* BUDB_FindDump
2002 * Find latest volume dump before adate.
2003 * Used by restore code when restoring a user requested volume(s)
2004 * entry:
2005 * volumeName - name of volume to match on
2006 * beforeDate - look for dumps older than this date
2007 * exit:
2008 * deptr - descriptor of most recent dump
2009 */
2010
2011afs_int32
2012SBUDB_FindDump(struct rx_call *call, char *volumeName, afs_int32 beforeDate,
2013 struct budb_dumpEntry *deptr)
2014{
2015 afs_int32 code;
2016
2017 code = FindDump(call, volumeName, beforeDate, deptr);
2018 osi_auditU(call, BUDB_FndDmpEvent, code, AUD_STR, volumeName, AUD_END);
2019 return code;
2020}
2021
2022afs_int32
2023FindDump(struct rx_call *call, char *volumeName, afs_int32 beforeDate,
2024 struct budb_dumpEntry *deptr)
2025{
2026 struct ubik_trans *ut;
2027 dbadr volInfoAddr, volFragmentAddr;
2028 struct tape tape;
2029 struct volInfo volInfo;
2030 struct volFragment volFragment;
2031
2032 dbadr selectedDumpAddr = 0;
2033 afs_int32 selectedDate = 0;
2034 afs_int32 volCloned;
2035 int rvoli;
2036 afs_int32 eval, code = 0;
2037
2038 if (!callPermitted(call))
2039 return BUDB_NOTPERMITTED;
2040
2041 eval = InitRPC(&ut, LOCKREAD, 1);
2042 if (eval)
2043 return eval;
2044
2045 /* Find volinfo struct for volume name in hash table */
2046 eval =
2047 ht_LookupEntry(ut, &db.volName, volumeName, &volInfoAddr, &volInfo);
2048 if (eval)
2049 ABORT(eval);
2050 if (!volInfoAddr)
2051 ABORT(BUDB_NOVOLUMENAME);
2052
2053 /* Step through all the volinfo structures on the same name chain.
2054 * No need to read the first - we read it above.
2055 */
2056 for (rvoli = 0; volInfoAddr;
2057 rvoli = 1, volInfoAddr = ntohl(volInfo.sameNameChain)) {
2058 if (rvoli) { /* read the volinfo structure */
2059 eval = dbread(ut, volInfoAddr, &volInfo, sizeof(volInfo));
2060 if (eval)
2061 ABORT(eval);
2062 }
2063
2064 /* step through the volfrag structures */
2065 for (volFragmentAddr = ntohl(volInfo.firstFragment); volFragmentAddr;
2066 volFragmentAddr = ntohl(volFragment.sameNameChain)) {
2067 /* read the volfrag struct */
2068 eval =
2069 dbread(ut, volFragmentAddr, &volFragment,
2070 sizeof(volFragment));
2071 if (eval)
2072 ABORT(eval);
2073
2074 volCloned = ntohl(volFragment.clone);
2075
2076 /* now we can examine the date for most recent dump */
2077 if ((volCloned > selectedDate) && (volCloned < beforeDate)) {
2078 /* from the volfrag struct, read the tape struct */
2079 eval =
2080 dbread(ut, ntohl(volFragment.tape), &tape, sizeof(tape));
2081 if (eval)
2082 ABORT(eval);
2083
2084 selectedDate = volCloned;
2085 selectedDumpAddr = ntohl(tape.dump);
2086 }
2087 }
2088 }
2089
2090 if (!selectedDumpAddr)
2091 ABORT(BUDB_NOENT);
2092
2093 eval = FillDumpEntry(ut, selectedDumpAddr, deptr);
2094 if (eval)
2095 ABORT(eval);
2096
2097 code = ubik_EndTrans(ut);
2098 return (code);
2099
2100 abort_exit:
2101 ubik_EndTrans(ut);
2102 return (code);
2103}
2104
2105/* BUDB_FindLatestDump
2106 * Find the latest dump of volumeset vsname with dump name dname.
2107 * entry:
2108 * vsname - volumeset name
2109 * dname - dumpname
2110 */
2111
2112afs_int32
2113SBUDB_FindLatestDump(struct rx_call *call, char *vsname, char *dumpPath,
2114 struct budb_dumpEntry *dumpentry)
2115{
2116 afs_int32 code;
2117
2118 code = FindLatestDump(call, vsname, dumpPath, dumpentry);
2119 osi_auditU(call, BUDB_FndLaDEvent, code, AUD_STR, vsname, AUD_END);
2120 return code;
2121}
2122
2123afs_int32
2124FindLatestDump(struct rx_call *call, char *vsname, char *dumpPath,
2125 struct budb_dumpEntry *dumpentry)
2126{
2127 struct ubik_trans *ut;
2128 dbadr curdbaddr, retdbaddr, firstdbaddr;
2129 struct dump d;
2130 Date latest;
2131 char dumpName[BU_MAXNAMELEN + 2];
2132 afs_int32 eval, code = 0;
2133
2134 if (!callPermitted(call))
2135 return BUDB_NOTPERMITTED;
2136
2137 eval = InitRPC(&ut, LOCKREAD, 1);
2138 if (eval)
2139 return (eval);
2140
2141 if ((strcmp(vsname, "") == 0) && (strcmp(dumpPath, "") == 0)) {
2142 /* Construct a database dump name */
2143 strcpy(dumpName, DUMP_TAPE_NAME);
2144 } else if (strchr(dumpPath, '/') == 0) {
2145 int level, old, length, hash;
2146 struct dump hostDump, diskDump;
2147 struct memoryHashTable *mht;
2148 int entrySize;
2149 dbadr dbAddr;
2150 afs_uint32 bestDumpId = 0;
2151
2152 level = atoi(dumpPath);
2153 if (level < 0) {
2154 ABORT(BUDB_BADARGUMENT);
2155 }
2156
2157 /* Brute force search of all the dumps in the database - yuck! */
2158
2159 retdbaddr = 0;
2160 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
2161 if (!mht)
2162 ABORT(BUDB_BADARGUMENT);
2163
2164 for (old = 0; old <= 1; old++) { /*fo */
2165 length = (old ? mht->oldLength : mht->length);
2166 if (!length)
2167 continue;
2168
2169 for (hash = 0; hash < length; hash++) {
2170 /*f */
2171 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr;
2172 dbAddr = hostDump.idHashChain) {
2173 /*w */
2174 eval = dbread(ut, dbAddr, &diskDump, sizeof(diskDump));
2175 if (eval)
2176 ABORT(eval);
2177 dump_ntoh(&diskDump, &hostDump);
2178
2179 if ((strcmp(hostDump.volumeSet, vsname) == 0) && /* the volumeset */
2180 (hostDump.level == level) && /* same level */
2181 (hostDump.id > bestDumpId)) { /* more recent */
2182 bestDumpId = hostDump.id;
2183 retdbaddr = dbAddr;
2184 }
2185 } /*w */
2186 } /*f */
2187 } /*fo */
2188 if (!retdbaddr)
2189 ABORT(BUDB_NODUMPNAME);
2190
2191 goto finished;
2192 } else {
2193 /* construct the name of the dump */
2194 if ((strlen(vsname) + strlen(tailCompPtr(dumpPath))) > BU_MAXNAMELEN)
2195 ABORT(BUDB_NODUMPNAME);
2196
2197 strcpy(dumpName, vsname);
2198 strcat(dumpName, ".");
2199 strcat(dumpName, tailCompPtr(dumpPath));
2200 }
2201
2202 LogDebug(5, "lookup on :%s:\n", dumpName);
2203
2204 /* Lookup on dumpname in hash table */
2205 eval = ht_LookupEntry(ut, &db.dumpName, dumpName, &firstdbaddr, &d);
2206 if (eval)
2207 ABORT(eval);
2208
2209 latest = 0;
2210 retdbaddr = 0;
2211
2212 /* folow remaining dumps in hash chain, looking for most latest dump */
2213 for (curdbaddr = firstdbaddr; curdbaddr;
2214 curdbaddr = ntohl(d.nameHashChain)) {
2215 if (curdbaddr != firstdbaddr) {
2216 eval = dbread(ut, curdbaddr, &d, sizeof(d));
2217 if (eval)
2218 ABORT(eval);
2219 }
2220
2221 if ((strcmp(d.dumpPath, dumpPath) == 0) && /* Same dumppath */
2222 (strcmp(d.dumpName, dumpName) == 0) && /* Same dumpname */
2223 (ntohl(d.created) > latest)) { /* most recent */
2224 latest = ntohl(d.created);
2225 retdbaddr = curdbaddr;
2226 }
2227 }
2228 if (!retdbaddr)
2229 ABORT(BUDB_NODUMPNAME);
2230
2231 finished:
2232 /* return the dump found */
2233 eval = FillDumpEntry(ut, retdbaddr, dumpentry);
2234 if (eval)
2235 ABORT(eval);
2236
2237 code = ubik_EndTrans(ut);
2238 return (code);
2239
2240 abort_exit:
2241 ubik_AbortTrans(ut);
2242 return (code);
2243}
2244
2245
2246afs_int32
2247SBUDB_FinishDump(struct rx_call *call, struct budb_dumpEntry *dump)
2248{
2249 afs_int32 code;
2250
2251 code = FinishDump(call, dump);
2252 osi_auditU(call, BUDB_FinDmpEvent, code, AUD_DATE, (dump ? dump->id : 0),
2253 AUD_END);
2254 return code;
2255}
2256
2257afs_int32
2258FinishDump(struct rx_call *call, struct budb_dumpEntry *dump)
2259{
2260 struct ubik_trans *ut;
2261 dbadr a;
2262 struct dump d;
2263 afs_int32 eval, code = 0;
2264
2265 if (!callPermitted(call))
2266 return BUDB_NOTPERMITTED;
2267
2268 eval = InitRPC(&ut, LOCKWRITE, 1);
2269 if (eval)
2270 return eval;
2271
2272 eval = ht_LookupEntry(ut, &db.dumpIden, &dump->id, &a, &d);
2273 if (eval)
2274 ABORT(eval);
2275 if (!a)
2276 ABORT(BUDB_NODUMPID);
2277
2278 if ((ntohl(d.flags) & BUDB_DUMP_INPROGRESS) == 0)
2279 ABORT(BUDB_DUMPNOTINUSE);
2280
2281 d.flags = htonl(dump->flags & ~BUDB_DUMP_INPROGRESS);
2282
2283 /* if creation time specified set it */
2284 if (dump->created)
2285 d.created = htonl(dump->created);
2286 dump->created = ntohl(d.created);
2287
2288 /* Write the dump entry out */
2289 eval = dbwrite(ut, a, &d, sizeof(d));
2290 if (eval)
2291 ABORT(eval);
2292
2293 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2294 if (eval)
2295 ABORT(eval);
2296
2297 code = ubik_EndTrans(ut);
2298 return code;
2299
2300 abort_exit:
2301 ubik_AbortTrans(ut);
2302 return code;
2303}
2304
2305afs_int32
2306SBUDB_FinishTape(struct rx_call *call, struct budb_tapeEntry *tape)
2307{
2308 afs_int32 code;
2309
2310 code = FinishTape(call, tape);
2311 osi_auditU(call, BUDB_FinTpeEvent, code, AUD_DATE,
2312 (tape ? tape->dump : 0), AUD_END);
2313 return code;
2314}
2315
2316afs_int32
2317FinishTape(struct rx_call *call, struct budb_tapeEntry *tape)
2318{
2319 struct ubik_trans *ut;
2320 dbadr a;
2321 struct tape t;
2322 struct dump d;
2323 afs_int32 eval, code = 0;
2324
2325 if (!callPermitted(call))
2326 return BUDB_NOTPERMITTED;
2327
2328 eval = InitRPC(&ut, LOCKWRITE, 1);
2329 if (eval)
2330 return eval;
2331
2332 /* find the tape struct in the tapename hash chain */
2333 eval = ht_LookupEntry(ut, &db.tapeName, tape->name, &a, &t);
2334 if (eval)
2335 ABORT(eval);
2336 if (!a)
2337 ABORT(BUDB_NOTAPENAME);
2338
2339 /* Read the dump structure */
2340 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2341 if (eval)
2342 ABORT(eval);
2343
2344 /* search for the right tape on the rest of the chain */
2345 while (ntohl(d.id) != tape->dump) {
2346 a = ntohl(t.nameHashChain);
2347 if (!a)
2348 ABORT(BUDB_NOTAPENAME);
2349
2350 eval = dbread(ut, a, &t, sizeof(t));
2351 if (eval)
2352 ABORT(eval);
2353
2354 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2355 if (eval)
2356 ABORT(eval);
2357 }
2358
2359 if ((ntohl(t.flags) & BUDB_TAPE_BEINGWRITTEN) == 0)
2360 ABORT(BUDB_TAPENOTINUSE);
2361
2362 /* t.nBytes = htonl(tape->nBytes); */
2363 t.nFiles = htonl(tape->nFiles);
2364 t.useKBytes = htonl(tape->useKBytes);
2365 t.flags = htonl(tape->flags & ~BUDB_TAPE_BEINGWRITTEN);
2366
2367 eval = dbwrite(ut, a, &t, sizeof(t));
2368 if (eval)
2369 ABORT(BUDB_IO);
2370
2371 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2372 if (eval)
2373 ABORT(eval);
2374
2375 code = ubik_EndTrans(ut);
2376 return code;
2377
2378 abort_exit:
2379 ubik_AbortTrans(ut);
2380 return code;
2381}
2382
2383/* BUDB_GetDumps
2384 * return a set of dumps that match the specified criteria
2385 * entry:
2386 * call - rx call
2387 * majorVersion - version of interface structures. Permits compatibility
2388 * checks to be made
2389 * flags - for search and select operations. Broken down into flags
2390 * for name, start point, end point and time.
2391 * name - name to search for. Interpretation based on flags
2392 * end
2393 * index
2394 * nextIndexP
2395 * dbTimeP
2396 * exit:
2397 * nextIndexP
2398 * dbTimeP - time at which the database was last modified. Up to
2399 * caller (client) to take appropriate action if database
2400 * modified between successive calls
2401 * dumps - list of matching dumps
2402 * notes:
2403 * currently supported are:
2404 * BUDB_OP_DUMPNAME
2405 * BUDB_OP_DUMPID
2406 */
2407
2408afs_int32
2409SBUDB_GetDumps(struct rx_call *call,
2410 afs_int32 majorVersion, /* version of interface structures */
2411 afs_int32 flags, /* search & select controls */
2412 char *name, /* s&s parameters */
2413 afs_int32 start,
2414 afs_int32 end,
2415 afs_int32 index, /* start index of returned entries */
2416 afs_int32 *nextIndexP, /* output index for next call */
2417 afs_int32 *dbTimeP,
2418 budb_dumpList *dumps) /* pointer to buffer */
2419{
2420 afs_int32 code;
2421
2422 code =
2423 GetDumps(call, majorVersion, flags, name, start, end, index,
2424 nextIndexP, dbTimeP, dumps);
2425 osi_auditU(call, BUDB_GetDmpEvent, code, AUD_END);
2426 return code;
2427}
2428
2429afs_int32
2430GetDumps(struct rx_call *call,
2431 afs_int32 majorVersion, /* version of interface structures */
2432 afs_int32 flags, /* search & select controls */
2433 char *name, /* s&s parameters */
2434 afs_int32 start,
2435 afs_int32 end,
2436 afs_int32 index, /* start index of returned entries */
2437 afs_int32 *nextIndexP, /* output index for next call */
2438 afs_int32 *dbTimeP,
2439 budb_dumpList *dumps) /* pointer to buffer */
2440{
2441 struct ubik_trans *ut;
2442 dbadr da;
2443 struct dump d;
2444 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2445 afs_int32 eval, code = 0;
2446 afs_int32 toskip;
2447 struct returnList list;
2448
2449 /* Don't check permissions when we look up a specific dump id */
2450 if (((flags & BUDB_OP_STARTS) != BUDB_OP_DUMPID) && !callPermitted(call))
2451 return BUDB_NOTPERMITTED;
2452
2453 if (majorVersion != BUDB_MAJORVERSION)
2454 return BUDB_OLDINTERFACE;
2455 if (index < 0)
2456 return BUDB_ENDOFLIST;
2457
2458 eval = InitRPC(&ut, LOCKREAD, 1);
2459 if (eval)
2460 return eval;
2461
2462 nameFlags = flags & BUDB_OP_NAMES;
2463 startFlags = flags & BUDB_OP_STARTS;
2464 endFlags = flags & BUDB_OP_ENDS;
2465 timeFlags = flags & BUDB_OP_TIMES;
2466
2467 InitReturnList(&list);
2468 toskip = index;
2469
2470 if (nameFlags == BUDB_OP_DUMPNAME) {
2471 /* not yet implemented */
2472 if (startFlags || endFlags || timeFlags)
2473 ABORT(BUDB_BADFLAGS);
2474
2475 eval = ht_LookupEntry(ut, &db.dumpName, name, &da, &d);
2476 if (eval)
2477 ABORT(eval);
2478 if (!da)
2479 ABORT(BUDB_NODUMPNAME);
2480
2481 while (1) {
2482 if (strcmp(d.dumpName, name) == 0) {
2483 eval = AddToReturnList(&list, da, &toskip);
2484 if (eval == BUDB_LIST2BIG)
2485 break;
2486 if (eval)
2487 ABORT(eval);
2488 }
2489
2490 da = ntohl(d.nameHashChain); /* get next dump w/ name */
2491 if (!da)
2492 break;
2493
2494 eval = dbread(ut, da, &d, sizeof(d));
2495 if (eval)
2496 ABORT(eval);
2497 }
2498 } else if (nameFlags == BUDB_OP_VOLUMENAME) {
2499#ifdef PA
2500 struct volInfo vi;
2501
2502 LogError(0, "NYI, BUDB_OP_VOLUMENAME\n");
2503 ABORT(BUDB_BADFLAGS);
2504
2505
2506 if (startFlags != BUDB_OP_STARTTIME)
2507 ABORT(BUDB_BADFLAGS);
2508
2509 /* lookup a dump by volumename and time stamp. Find the most recent
2510 * dump of the specified volumename, that occured before the supplied
2511 * time
2512 */
2513
2514 /* get us a volInfo for name */
2515 eval = ht_LookupEntry(ut, &db.volName, name, &da, &vi);
2516 if (eval)
2517 ABORT(eval);
2518
2519 while (1) {
2520 /* now iterate over all the entries of this name */
2521 for (va = vi.firstFragment; va != 0; va = v.sameNameChain) {
2522 va = ntohl(va);
2523 eval = dbread(ut, va, &v, sizeof(v));
2524 if (eval)
2525 ABORT(eval);
2526
2527 if date
2528 on fragment > date ignore it - too recent;
2529
2530 if (date on fragment < date && date on fragment > bestfound)
2531 bestfound = date on fragment;
2532
2533 } /* for va */
2534
2535 da = vi.sameNameChain;
2536 if (da == 0)
2537 break;
2538 da = ntohl(da);
2539 eval = dbread(ut, da, &vi, sizeof(vi));
2540 if (eval)
2541 ABORT(eval);
2542 }
2543
2544/*
2545 if nothing found
2546 return error
2547
2548 from saved volfragment address, compute dump.
2549 otherwise, return dump found
2550*/
2551
2552#endif /* PA */
2553
2554 } else if (startFlags == BUDB_OP_DUMPID) {
2555 if (endFlags || timeFlags)
2556 ABORT(BUDB_BADFLAGS);
2557 if (nameFlags)
2558 ABORT(BUDB_BADFLAGS); /* NYI */
2559
2560 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
2561 if (eval)
2562 ABORT(eval);
2563 if (!da)
2564 ABORT(BUDB_NODUMPID);
2565
2566 eval = AddToReturnList(&list, da, &toskip);
2567 if (eval)
2568 ABORT(eval);
2569 } else if (endFlags == BUDB_OP_NPREVIOUS) {
2570 struct wantDumpRock rock;
2571 struct chosenDump *ptr, *nextPtr;
2572
2573 /* no other flags should be set */
2574
2575 /* end specifies how many dumps */
2576 if (!end)
2577 ABORT(BUDB_BADFLAGS);
2578
2579 memset(&rock, 0, sizeof(rock));
2580 rock.maxDumps = end;
2581
2582 scanHashTable(ut, &db.dumpName, wantDump, rememberDump,
2583 (char *)&rock);
2584
2585 for (ptr = rock.chain; ptr; ptr = nextPtr) {
2586 nextPtr = ptr->next;
2587 AddToReturnList(&list, ptr->addr, &toskip); /* ignore error for free */
2588 free(ptr);
2589 }
2590 } else {
2591 ABORT(BUDB_BADFLAGS);
2592 }
2593
2594 eval =
2595 SendReturnList(ut, &list, FillDumpEntry,
2596 sizeof(struct budb_dumpEntry), index, nextIndexP,
2597 dbTimeP, (returnList_t) dumps);
2598 if (eval)
2599 ABORT(eval);
2600
2601 FreeReturnList(&list);
2602 code = ubik_EndTrans(ut);
2603 return code;
2604
2605 abort_exit:
2606 FreeReturnList(&list);
2607 ubik_AbortTrans(ut);
2608 return code;
2609}
2610
2611/*
2612 * Get the expiration of a tape. Since the dump could have appended dumps,
2613 * we should use the most recent expiration date. Put the most recent
2614 * expiration tape into the given tape structure.
2615 */
2616afs_int32
2617getExpiration(struct ubik_trans *ut, struct tape *tapePtr)
2618{
2619 dbadr ad;
2620 struct dump d;
2621 struct tape t;
2622 afs_int32 initDump;
2623 afs_int32 eval, code = 0;
2624
2625 if (!tapePtr)
2626 ERROR(0);
2627
2628 /* Get the dump for this tape */
2629 ad = ntohl(tapePtr->dump);
2630 eval = dbread(ut, ad, &d, sizeof(d));
2631 if (eval)
2632 ERROR(eval);
2633
2634 /* If not an initial dump, get the initial dump */
2635 if (d.initialDumpID) {
2636 initDump = ntohl(d.initialDumpID);
2637 eval = ht_LookupEntry(ut, &db.dumpIden, &initDump, &ad, &d);
2638 if (eval)
2639 ERROR(eval);
2640 }
2641
2642 /* Cycle through the dumps and appended dumps */
2643 while (ad) {
2644 /* Get the first tape in this dump. No need to check the rest of the tapes */
2645 /* for this dump since they will all have the same expiration date */
2646 eval = dbread(ut, ntohl(d.firstTape), &t, sizeof(t));
2647 if (eval)
2648 ERROR(eval);
2649
2650 /* Take the greater of the expiration dates */
2651 if (ntohl(tapePtr->expires) < ntohl(t.expires))
2652 tapePtr->expires = t.expires;
2653
2654 /* Step to and read the next appended dump */
2655 if ((ad = ntohl(d.appendedDumpChain))) {
2656 eval = dbread(ut, ad, &d, sizeof(d));
2657 if (eval)
2658 ERROR(eval);
2659 }
2660 }
2661
2662 error_exit:
2663 return (code);
2664}
2665
2666/* Mark the following dump as appended to another, intial dump */
2667afs_int32
2668makeAppended(struct ubik_trans *ut, afs_int32 appendedDumpID,
2669 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2670{
2671 dbadr ada, da, lastDumpAddr;
2672 struct dump ad, d;
2673 afs_int32 eval, code = 0;
2674
2675 if (!initialDumpID)
2676 ERROR(0);
2677 if (appendedDumpID == initialDumpID)
2678 ERROR(BUDB_INTERNALERROR);
2679
2680 /* If there is an initial dump, append this dump to it */
2681 /* Find the appended dump via its id */
2682 eval = ht_LookupEntry(ut, &db.dumpIden, &appendedDumpID, &ada, &ad);
2683 if (eval)
2684 ERROR(eval);
2685
2686 /* If the dump is already marked as appended,
2687 * then we have an internal error.
2688 */
2689 if (ad.initialDumpID) {
2690 if (ntohl(ad.initialDumpID) != initialDumpID)
2691 ERROR(BUDB_INTERNALERROR);
2692 }
2693
2694 /* Update the appended dump to point to the initial dump */
2695 ad.initialDumpID = htonl(initialDumpID);
2696 ad.tapes.b = htonl(startTapeSeq);
2697
2698 /* find the initial dump via its id */
2699 eval = ht_LookupEntry(ut, &db.dumpIden, &initialDumpID, &da, &d);
2700 if (eval)
2701 ERROR(eval);
2702
2703 /* Update the appended dump's tape format with that of the initial */
2704 strcpy(ad.tapes.format, d.tapes.format);
2705
2706 /* starting with the initial dump step through its appended dumps till
2707 * we reach the last appended dump.
2708 */
2709 lastDumpAddr = da;
2710 while (d.appendedDumpChain) {
2711 lastDumpAddr = ntohl(d.appendedDumpChain);
2712 if (lastDumpAddr == ada)
2713 ERROR(0); /* Already appended */
2714 eval = dbread(ut, lastDumpAddr, &d, sizeof(d));
2715 if (eval)
2716 ERROR(eval);
2717 }
2718
2719 /* Update the last dump to point to our new appended dump.
2720 * The appended dump is the last one in the dump chain.
2721 */
2722 d.appendedDumpChain = htonl(ada);
2723 ad.appendedDumpChain = 0;
2724
2725 /* Write the appended dump and the initial dump */
2726 eval = dbwrite(ut, ada, (char *)&ad, sizeof(ad));
2727 if (eval)
2728 ERROR(eval);
2729
2730 eval = dbwrite(ut, lastDumpAddr, (char *)&d, sizeof(d));
2731 if (eval)
2732 ERROR(eval);
2733
2734 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
2735 if (eval)
2736 ERROR(eval);
2737
2738 error_exit:
2739 return (code);
2740}
2741
2742afs_int32
2743SBUDB_MakeDumpAppended(struct rx_call *call, afs_int32 appendedDumpID,
2744 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2745{
2746 afs_int32 code;
2747
2748 code =
2749 MakeDumpAppended(call, appendedDumpID, initialDumpID, startTapeSeq);
2750 osi_auditU(call, BUDB_AppDmpEvent, code, AUD_LONG, appendedDumpID,
2751 AUD_END);
2752 return code;
2753}
2754
2755afs_int32
2756MakeDumpAppended(struct rx_call *call, afs_int32 appendedDumpID,
2757 afs_int32 initialDumpID, afs_int32 startTapeSeq)
2758{
2759 struct ubik_trans *ut;
2760 afs_int32 eval, code = 0;
2761
2762 if (!callPermitted(call))
2763 return BUDB_NOTPERMITTED;
2764
2765 eval = InitRPC(&ut, LOCKWRITE, 1);
2766 if (eval)
2767 return (eval);
2768
2769 eval = makeAppended(ut, appendedDumpID, initialDumpID, startTapeSeq);
2770 if (eval)
2771 ABORT(eval);
2772
2773 code = ubik_EndTrans(ut);
2774 return (code);
2775
2776 abort_exit:
2777 ubik_AbortTrans(ut);
2778 return (code);
2779}
2780
2781/* Find the last tape of a dump-set. This includes any appended dumps */
2782afs_int32
2783SBUDB_FindLastTape(struct rx_call *call, afs_int32 dumpID,
2784 struct budb_dumpEntry *dumpEntry,
2785 struct budb_tapeEntry *tapeEntry,
2786 struct budb_volumeEntry *volEntry)
2787{
2788 afs_int32 code;
2789
2790 code = FindLastTape(call, dumpID, dumpEntry, tapeEntry, volEntry);
2791 osi_auditU(call, BUDB_FndLTpeEvent, code, AUD_LONG, dumpID, AUD_END);
2792 return code;
2793}
2794
2795afs_int32
2796FindLastTape(struct rx_call *call, afs_int32 dumpID,
2797 struct budb_dumpEntry *dumpEntry,
2798 struct budb_tapeEntry *tapeEntry,
2799 struct budb_volumeEntry *volEntry)
2800{
2801 struct ubik_trans *ut;
2802 struct dump d;
2803 dbadr lastDump;
2804 struct tape t;
2805 dbadr lastTape, thisTape;
2806 afs_int32 lastTapeSeq;
2807 struct volFragment vf;
2808 dbadr lastVol, thisVol;
2809 afs_int32 lastVolPos;
2810 afs_int32 eval, code = 0;
2811
2812 if (!callPermitted(call))
2813 return BUDB_NOTPERMITTED;
2814
2815 if (!dumpID)
2816 return (BUDB_BADARGUMENT);
2817
2818 eval = InitRPC(&ut, LOCKREAD, 1);
2819 if (eval)
2820 return (eval);
2821
2822 /* find and read its initial dump via its id */
2823 eval = ht_LookupEntry(ut, &db.dumpIden, &dumpID, &lastDump, &d);
2824 if (eval)
2825 ABORT(eval);
2826 if (!lastDump)
2827 ABORT(BUDB_NODUMPID);
2828
2829 /* Follow the append dumps link chain until we reach the last dump */
2830 while (d.appendedDumpChain) {
2831 lastDump = ntohl(d.appendedDumpChain);
2832 eval = dbread(ut, lastDump, &d, sizeof(d));
2833 if (eval)
2834 ABORT(eval);
2835 }
2836
2837 /* We now have the last dump of the last appended dump */
2838 /* Copy this into our return structure */
2839 eval = FillDumpEntry(ut, lastDump, dumpEntry);
2840 if (eval)
2841 ABORT(eval);
2842
2843 /* Fail if the last dump has no tapes */
2844 if (!d.firstTape)
2845 ABORT(BUDB_NOTAPENAME);
2846
2847 /* Follow the tapes in this dump until we reach the last tape */
2848 eval = dbread(ut, ntohl(d.firstTape), &t, sizeof(t));
2849 if (eval)
2850 ABORT(eval);
2851
2852 lastTape = ntohl(d.firstTape);
2853 lastTapeSeq = ntohl(t.seq);
2854 lastVol = ntohl(t.firstVol);
2855
2856 while (t.nextTape) {
2857 thisTape = ntohl(t.nextTape);
2858 eval = dbread(ut, thisTape, &t, sizeof(t));
2859 if (eval)
2860 ABORT(eval);
2861
2862 if (ntohl(t.seq) > lastTapeSeq) {
2863 lastTape = thisTape;
2864 lastTapeSeq = ntohl(t.seq);
2865 lastVol = ntohl(t.firstVol);
2866 }
2867 }
2868
2869 /* We now have the last tape of the last appended dump */
2870 /* Copy this into our return structure */
2871 eval = FillTapeEntry(ut, lastTape, tapeEntry);
2872 if (eval)
2873 ABORT(eval);
2874
2875 /* Zero volume entry if the last tape has no volumes */
2876 if (!lastVol) {
2877 memset(volEntry, 0, sizeof(*volEntry));
2878 } else {
2879 /* Follow the volumes until we reach the last volume */
2880 eval = dbread(ut, lastVol, &vf, sizeof(vf));
2881 if (eval)
2882 ABORT(eval);
2883
2884 lastVolPos = vf.position;
2885
2886 while (vf.sameTapeChain) {
2887 thisVol = ntohl(vf.sameTapeChain);
2888 eval = dbread(ut, thisVol, &vf, sizeof(vf));
2889 if (eval)
2890 ABORT(eval);
2891
2892 if (vf.position > lastVolPos) {
2893 lastVol = thisVol;
2894 lastVolPos = vf.position;
2895 }
2896 }
2897
2898 /* We now have the last volume of this tape */
2899 /* Copy this into our return structure */
2900 eval = FillVolEntry(ut, lastVol, volEntry);
2901 if (eval)
2902 ABORT(eval);
2903 }
2904
2905 eval = ubik_EndTrans(ut);
2906 if (!code)
2907 code = eval;
2908 return (code);
2909
2910 abort_exit:
2911 ubik_AbortTrans(ut);
2912 return (code);
2913}
2914
2915
2916afs_int32
2917SBUDB_GetTapes(struct rx_call *call,
2918 afs_int32 majorVersion, /* version of interface structures */
2919 afs_int32 flags, /* search & select controls */
2920 char *name, /* s&s parameters */
2921 afs_int32 start,
2922 afs_int32 end, /* reserved: MBZ */
2923 afs_int32 index, /* start index of returned entries */
2924 afs_int32 *nextIndexP, /* output index for next call */
2925 afs_int32 *dbTimeP,
2926 budb_tapeList *tapes) /* pointer to buffer */
2927{
2928 afs_int32 code;
2929
2930 code =
2931 GetTapes(call, majorVersion, flags, name, start, end, index,
2932 nextIndexP, dbTimeP, tapes);
2933 osi_auditU(call, BUDB_GetTpeEvent, code, AUD_END);
2934 return code;
2935}
2936
2937afs_int32
2938GetTapes(struct rx_call *call,
2939 afs_int32 majorVersion, /* version of interface structures */
2940 afs_int32 flags, /* search & select controls */
2941 char *name, /* s&s parameters */
2942 afs_int32 start,
2943 afs_int32 end, /* reserved: MBZ */
2944 afs_int32 index, /* start index of returned entries */
2945 afs_int32 *nextIndexP, /* output index for next call */
2946 afs_int32 *dbTimeP,
2947 budb_tapeList *tapes) /* pointer to buffer */
2948{
2949 struct ubik_trans *ut;
2950 dbadr da, ta;
2951 struct dump d;
2952 struct tape t;
2953 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
2954 struct returnList list;
2955 afs_int32 eval, code = 0;
2956 afs_int32 toskip;
2957
2958 if (!callPermitted(call))
2959 return BUDB_NOTPERMITTED;
2960
2961 if (majorVersion != BUDB_MAJORVERSION)
2962 return BUDB_OLDINTERFACE;
2963
2964 if (index < 0)
2965 return BUDB_ENDOFLIST;
2966
2967 eval = InitRPC(&ut, LOCKREAD, 1);
2968 if (eval)
2969 return eval;
2970
2971 nameFlags = flags & BUDB_OP_NAMES;
2972 startFlags = flags & BUDB_OP_STARTS;
2973 endFlags = flags & BUDB_OP_ENDS;
2974 timeFlags = flags & BUDB_OP_TIMES;
2975
2976 InitReturnList(&list);
2977 toskip = index;
2978
2979 if (nameFlags == BUDB_OP_TAPENAME) { /*it */
2980 eval = ht_LookupEntry(ut, &db.tapeName, name, &ta, &t);
2981 if (eval)
2982 ABORT(eval);
2983 if (!ta)
2984 ABORT(BUDB_NOTAPENAME);
2985
2986 /* NYI */
2987 if ((startFlags & ~BUDB_OP_DUMPID) || endFlags || timeFlags)
2988 ABORT(BUDB_BADFLAGS);
2989
2990 /* follow the hash chain to the end */
2991 while (ta) { /*w */
2992 if (startFlags & BUDB_OP_DUMPID) {
2993 /* read in the dump */
2994 eval = dbread(ut, ntohl(t.dump), &d, sizeof(d));
2995 if (eval)
2996 ABORT(eval);
2997
2998 /* check if both name and dump id match */
2999 if ((strcmp(name, t.name) == 0) && (ntohl(d.id) == start)) {
3000 eval = AddToReturnList(&list, ta, &toskip);
3001 if (eval && (eval != BUDB_LIST2BIG))
3002 ABORT(eval);
3003 break;
3004 }
3005 } else {
3006 /* Add to return list and continue search */
3007 if (strcmp(name, t.name) == 0) {
3008 eval = AddToReturnList(&list, ta, &toskip);
3009 if (eval == BUDB_LIST2BIG)
3010 break;
3011 if (eval)
3012 ABORT(eval);
3013 }
3014 }
3015
3016 ta = ntohl(t.nameHashChain);
3017 if (ta)
3018 dbread(ut, ta, &t, sizeof(t));
3019 } /*w */
3020 } /*it */
3021 else if (nameFlags == BUDB_OP_TAPESEQ) {
3022 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &da, &d);
3023 if (eval)
3024 ABORT(eval);
3025 if (!da)
3026 ABORT(BUDB_NODUMPNAME);
3027
3028 /* search for the right tape */
3029 ta = ntohl(d.firstTape);
3030 for (ta = ntohl(d.firstTape); ta; ta = ntohl(t.nextTape)) {
3031 eval = dbread(ut, ta, &t, sizeof(t));
3032 if (eval)
3033 ABORT(eval);
3034
3035 if (ntohl(t.seq) == end) {
3036 eval = AddToReturnList(&list, ta, &toskip);
3037 if (eval && (eval != BUDB_LIST2BIG))
3038 ABORT(eval);
3039 break;
3040 }
3041 }
3042 } else {
3043 ABORT(BUDB_BADFLAGS);
3044 }
3045
3046 eval =
3047 SendReturnList(ut, &list, FillTapeEntry,
3048 sizeof(struct budb_tapeEntry), index, nextIndexP,
3049 dbTimeP, (returnList_t) tapes);
3050 if (eval)
3051 ABORT(eval);
3052
3053 FreeReturnList(&list);
3054 code = ubik_EndTrans(ut);
3055 return code;
3056
3057 abort_exit:
3058 FreeReturnList(&list);
3059 ubik_AbortTrans(ut);
3060 return (code);
3061}
3062
3063/* BUDB_GetVolumes
3064 * get a set of volumes according to the specified criteria.
3065 * See BUDB_GetDumps for general information on parameters
3066 * Currently supports:
3067 * 1) volume match - returns volumes based on volume name only.
3068 * 2) flags = BUDB_OP_DUMPID in which case name is a volume name
3069 * and start is a dumpid. Returns all volumes of the specified
3070 * name on the selected dumpid.
3071 */
3072
3073afs_int32
3074SBUDB_GetVolumes(struct rx_call *call,
3075 afs_int32 majorVersion, /* version of interface structures */
3076 afs_int32 flags, /* search & select controls */
3077 char *name, /* - parameters for search */
3078 afs_int32 start, /* - usage depends which BUDP_OP */
3079 afs_int32 end, /* - bits are set */
3080 afs_int32 index, /* start index of returned entries */
3081 afs_int32 *nextIndexP, /* output index for next call */
3082 afs_int32 *dbTimeP,
3083 budb_volumeList *volumes) /* pointer to buffer */
3084{
3085 afs_int32 code;
3086
3087 code =
3088 GetVolumes(call, majorVersion, flags, name, start, end, index,
3089 nextIndexP, dbTimeP, volumes);
3090 osi_auditU(call, BUDB_GetVolEvent, code, AUD_END);
3091 return code;
3092}
3093
3094afs_int32
3095GetVolumes(struct rx_call *call,
3096 afs_int32 majorVersion, /* version of interface structures */
3097 afs_int32 flags, /* search & select controls */
3098 char *name, /* - parameters for search */
3099 afs_int32 start, /* - usage depends which BUDP_OP_* */
3100 afs_int32 end, /* - bits are set */
3101 afs_int32 index, /* start index of returned entries */
3102 afs_int32 *nextIndexP, /* output index for next call */
3103 afs_int32 *dbTimeP,
3104 budb_volumeList *volumes) /* pointer to buffer */
3105{
3106 struct ubik_trans *ut;
3107 dbadr via;
3108 struct volInfo vi;
3109 afs_int32 nameFlags, startFlags, endFlags, timeFlags;
3110 afs_int32 eval, code = 0;
3111 struct returnList vollist;
3112 afs_int32 toskip;
3113
3114 /* Don't check permissions when we look up a specific volume name */
3115 if (((flags & BUDB_OP_NAMES) != BUDB_OP_VOLUMENAME)
3116 && !callPermitted(call))
3117 return BUDB_NOTPERMITTED;
3118
3119 if (majorVersion != BUDB_MAJORVERSION)
3120 return BUDB_OLDINTERFACE;
3121 if (index < 0)
3122 return BUDB_ENDOFLIST;
3123
3124 eval = InitRPC(&ut, LOCKREAD, 1);
3125 if (eval)
3126 return eval;
3127
3128 nameFlags = flags & BUDB_OP_NAMES;
3129 startFlags = flags & BUDB_OP_STARTS;
3130 endFlags = flags & BUDB_OP_ENDS;
3131 timeFlags = flags & BUDB_OP_TIMES;
3132
3133 InitReturnList(&vollist);
3134 toskip = index;
3135
3136 /* lookup a the volume (specified by name) in the dump (specified by id) */
3137 if (nameFlags == BUDB_OP_VOLUMENAME) {
3138 /* dumpid permissible, all others off */
3139 if (((startFlags & ~BUDB_OP_DUMPID) != 0) || endFlags || timeFlags)
3140 ABORT(BUDB_BADFLAGS);
3141
3142 /* returns ptr to volinfo of requested name */
3143 eval = ht_LookupEntry(ut, &db.volName, name, &via, &vi);
3144 if (eval)
3145 ABORT(eval);
3146 if (!via)
3147 ABORT(BUDB_NOVOLUMENAME);
3148
3149 /* Iterate over all volume fragments with this name */
3150 while (1) {
3151 struct volFragment v;
3152 afs_int32 va;
3153
3154 /* traverse all the volume fragments for this volume info structure */
3155 for (va = vi.firstFragment; va; va = v.sameNameChain) {
3156 va = ntohl(va);
3157 eval = dbread(ut, va, &v, sizeof(v));
3158 if (eval)
3159 ABORT(eval);
3160
3161 if (startFlags & BUDB_OP_DUMPID) {
3162 struct tape atape;
3163 struct dump adump;
3164
3165 /* get the dump id for this fragment */
3166 eval = dbread(ut, ntohl(v.tape), &atape, sizeof(atape));
3167 if (eval)
3168 ABORT(eval);
3169
3170 eval =
3171 dbread(ut, ntohl(atape.dump), &adump, sizeof(adump));
3172 if (eval)
3173 ABORT(BUDB_IO);
3174
3175 /* dump id does not match */
3176 if (ntohl(adump.id) != start)
3177 continue;
3178 }
3179
3180 eval = AddToReturnList(&vollist, va, &toskip);
3181 if (eval == BUDB_LIST2BIG)
3182 break;
3183 if (eval)
3184 ABORT(eval);
3185 }
3186 if (eval == BUDB_LIST2BIG)
3187 break;
3188
3189 via = vi.sameNameChain;
3190 if (via == 0)
3191 break;
3192 via = ntohl(via);
3193
3194 eval = dbread(ut, via, &vi, sizeof(vi));
3195 if (eval)
3196 ABORT(eval);
3197 }
3198 } else if (((nameFlags == 0) || (nameFlags == BUDB_OP_TAPENAME))
3199 && (startFlags == BUDB_OP_DUMPID)) {
3200 struct dump dump;
3201 dbadr dumpAddr;
3202 struct tape tape;
3203 dbadr tapeAddr;
3204 struct volFragment volFrag;
3205 dbadr volFragAddr;
3206
3207 /* lookup all volumes for a specified dump id */
3208
3209 /* no other flags should be set */
3210 if (endFlags || timeFlags)
3211 ABORT(BUDB_BADFLAGS);
3212
3213 /* find the dump */
3214 eval = ht_LookupEntry(ut, &db.dumpIden, &start, &dumpAddr, &dump);
3215 if (eval)
3216 ABORT(eval);
3217
3218 /* traverse all the tapes */
3219 for (tapeAddr = ntohl(dump.firstTape); tapeAddr; tapeAddr = ntohl(tape.nextTape)) { /*w */
3220 eval = dbread(ut, tapeAddr, &tape, sizeof(tape));
3221 if (eval)
3222 ABORT(eval);
3223
3224 if ((nameFlags != BUDB_OP_TAPENAME)
3225 || ((nameFlags == BUDB_OP_TAPENAME)
3226 && (strcmp(tape.name, name) == 0))) {
3227 /* now return all the volumes */
3228 for (volFragAddr = ntohl(tape.firstVol); volFragAddr;
3229 volFragAddr = ntohl(volFrag.sameTapeChain)) {
3230 eval = dbread(ut, volFragAddr, &volFrag, sizeof(volFrag));
3231 if (eval)
3232 ABORT(eval);
3233
3234 eval = AddToReturnList(&vollist, volFragAddr, &toskip);
3235 if (eval == BUDB_LIST2BIG)
3236 break;
3237 if (eval)
3238 ABORT(eval);
3239 }
3240 }
3241 if (eval == BUDB_LIST2BIG)
3242 break;
3243 } /*w */
3244 } else {
3245 ABORT(BUDB_BADFLAGS);
3246 }
3247
3248 eval =
3249 SendReturnList(ut, &vollist, FillVolEntry,
3250 sizeof(struct budb_volumeEntry), index, nextIndexP,
3251 dbTimeP, (returnList_t) volumes);
3252 if (eval)
3253 ABORT(eval);
3254
3255 /* error_exit: */
3256 FreeReturnList(&vollist);
3257 code = ubik_EndTrans(ut);
3258 return code;
3259
3260 abort_exit:
3261 FreeReturnList(&vollist);
3262 ubik_AbortTrans(ut);
3263 return code;
3264}
3265
3266afs_int32
3267SBUDB_UseTape(struct rx_call *call,
3268 struct budb_tapeEntry *tape, /* tape info */
3269 afs_int32 *new) /* set if tape is new */
3270{
3271 afs_int32 code;
3272
3273 code = UseTape(call, tape, new);
3274 osi_auditU(call, BUDB_UseTpeEvent, code, AUD_DATE,
3275 (tape ? tape->dump : 0), AUD_END);
3276 return code;
3277}
3278
3279afs_int32
3280UseTape(struct rx_call *call,
3281 struct budb_tapeEntry *tape, /* tape info */
3282 int *new) /* set if tape is new */
3283{
3284 struct ubik_trans *ut;
3285 dbadr da, a;
3286 struct dump d;
3287 struct tape t;
3288 afs_int32 eval, code;
3289
3290 if (!callPermitted(call))
3291 return BUDB_NOTPERMITTED;
3292
3293 if (strlen(tape->name) >= sizeof(t.name))
3294 return BUDB_BADARGUMENT;
3295
3296 eval = InitRPC(&ut, LOCKWRITE, 1);
3297 if (eval)
3298 return eval;
3299
3300 *new = 0;
3301
3302 memset(&t, 0, sizeof(t));
3303 eval = AllocStructure(ut, tape_BLOCK, 0, &a, &t);
3304 if (eval)
3305 ABORT(eval);
3306
3307 strcpy(t.name, tape->name);
3308
3309 eval = ht_HashIn(ut, &db.tapeName, a, &t);
3310 if (eval)
3311 ABORT(eval);
3312
3313 *new = 1;
3314
3315 /* Since deleting a tape may change the dump (if its the same one), read in
3316 * the dump after the call to DeleteTape. */
3317
3318 eval = ht_LookupEntry(ut, &db.dumpIden, &tape->dump, &da, &d);
3319 if (eval)
3320 ABORT(eval);
3321 if (!da)
3322 ABORT(BUDB_NODUMPID);
3323
3324 if (!tape->written)
3325 tape->written = time(0); /* fill in tape struct */
3326 t.written = htonl(tape->written);
3327 t.expires = htonl(tape->expires);
3328 t.dump = htonl(da);
3329 t.seq = htonl(tape->seq);
3330 t.useCount = htonl(tape->useCount);
3331 t.labelpos = htonl(tape->labelpos);
3332 t.useKBytes = 0;
3333 t.flags = htonl(tape->flags | BUDB_TAPE_BEINGWRITTEN);
3334
3335 t.nextTape = d.firstTape; /* Chain the tape to the dump */
3336 d.firstTape = htonl(a);
3337
3338 if (tape->seq >= ntohl(d.tapes.maxTapes)) /* inc # tapes in the dump */
3339 d.tapes.maxTapes = htonl(tape->seq);
3340
3341 eval = dbwrite(ut, a, &t, sizeof(t)); /* write tape struct */
3342 if (eval)
3343 ABORT(eval);
3344
3345 eval = dbwrite(ut, da, &d, sizeof(d)); /* write the dump struct */
3346 if (eval)
3347 ABORT(eval);
3348
3349 eval = set_header_word(ut, lastUpdate, htonl(time(0)));
3350 if (eval)
3351 ABORT(eval);
3352
3353 LogDebug(5, "added tape %s\n", tape->name);
3354
3355 code = ubik_EndTrans(ut);
3356 return code;
3357
3358 abort_exit:
3359 ubik_AbortTrans(ut);
3360 return code;
3361
3362}
3363
3364
3365/* ---------------------------------------------
3366 * debug interface routines
3367 * ---------------------------------------------
3368 */
3369
3370afs_int32
3371SBUDB_T_DumpHashTable(struct rx_call *call, afs_int32 type, char *filename)
3372{
3373 afs_int32 code;
3374
3375 code = T_DumpHashTable(call, type, filename);
3376 osi_auditU(call, BUDB_TDmpHaEvent, code, AUD_STR, filename, AUD_END);
3377 return code;
3378}
3379
3380afs_int32
3381T_DumpHashTable(struct rx_call *call, int type, char *filename)
3382{
3383 struct ubik_trans *ut;
3384 struct memoryHashTable *mht;
3385 int ent;
3386 afs_int32 eval, code = 0;
3387 char path[64];
3388 FILE *DUMP;
3389
3390 int length;
3391 afs_uint32 hash;
3392 dbadr a, first_a;
3393 char e[sizeof(struct block)]; /* unnecessarily conservative */
3394 struct dump e_dump;
3395 struct tape e_tape;
3396 struct volInfo e_volinfo;
3397 int e_size;
3398 int old;
3399
3400 if (!callPermitted(call))
3401 return BUDB_NOTPERMITTED;
3402
3403 if (strlen(filename) >= sizeof(path) - 5)
3404 return BUDB_BADARGUMENT;
3405
3406 eval = InitRPC(&ut, LOCKWRITE, 1);
3407 if (eval)
3408 return eval;
3409
3410 if ((mht = ht_GetType(type, &e_size)) == 0)
3411 return BUDB_BADARGUMENT;
3412
3413 sprintf(path, "%s/%s", gettmpdir(), filename);
3414
3415 DUMP = fopen(path, "w");
3416 if (!DUMP)
3417 ABORT(BUDB_BADARGUMENT);
3418
3419 ent = 0;
3420 for (old = 0;; old++) {
3421 length = (old ? mht->oldLength : mht->length);
3422 if (length)
3423 fprintf(DUMP, "Dumping %sHash Table:\n", (old ? "Old " : ""));
3424
3425 for (hash = 0; hash < length; hash++) {
3426 a = ht_LookupBucket(ut, mht, hash, old);
3427 first_a = a;
3428 while (a) {
3429 eval = dbread(ut, a, e, e_size);
3430 if (eval)
3431 ABORT(eval);
3432
3433 ent++;
3434 if (a == first_a)
3435 fprintf(DUMP, " in bucket %d at %d is ", hash, a);
3436 else
3437 fprintf(DUMP, " at %d is ", a);
3438 switch (type) {
3439 case HT_dumpIden_FUNCTION:
3440 memcpy(&e_dump, e, sizeof(e_dump));
3441 fprintf(DUMP, "%d\n", ntohl(e_dump.id));
3442 break;
3443 case HT_dumpName_FUNCTION:
3444 memcpy(&e_dump, e, sizeof(e_dump));
3445 fprintf(DUMP, "%s\n", e_dump.dumpName);
3446 break;
3447 case HT_tapeName_FUNCTION:
3448 memcpy(&e_tape, e, sizeof(e_tape));
3449 fprintf(DUMP, "%s\n", e_tape.name);
3450 break;
3451 case HT_volName_FUNCTION:
3452 memcpy(&e_volinfo, e, sizeof(e_volinfo));
3453 fprintf(DUMP, "%s\n", e_volinfo.name);
3454 break;
3455 }
3456 if ((ht_HashEntry(mht, e) % length) != hash)
3457 ABORT(BUDB_DATABASEINCONSISTENT);
3458 a = ntohl(*(dbadr *) (e + mht->threadOffset));
3459 }
3460 }
3461 if (old)
3462 break;
3463 }
3464
3465 fprintf(DUMP, "%d entries found\n", ent);
3466 if (ntohl(mht->ht->entries) != ent)
3467 ABORT(BUDB_DATABASEINCONSISTENT);
3468
3469 code = ubik_EndTrans(ut);
3470 if (DUMP)
3471 fclose(DUMP);
3472 return code;
3473
3474 abort_exit:
3475 ubik_AbortTrans(ut);
3476 if (DUMP)
3477 fclose(DUMP);
3478 return code;
3479}
3480
3481afs_int32
3482SBUDB_T_GetVersion(struct rx_call *call, afs_int32 *majorVersion)
3483{
3484 afs_int32 code;
3485
3486 code = T_GetVersion(call, majorVersion);
3487 osi_auditU(call, BUDB_TGetVrEvent, code, AUD_END);
3488 return code;
3489}
3490
3491afs_int32
3492T_GetVersion(struct rx_call *call, int *majorVersion)
3493{
3494 struct ubik_trans *ut;
3495 afs_int32 code;
3496
3497 code = InitRPC(&ut, LOCKREAD, 0);
3498 if (code)
3499 return (code);
3500
3501 *majorVersion = BUDB_MAJORVERSION;
3502
3503 code = ubik_EndTrans(ut);
3504 return (code);
3505}
3506
3507/* BUDB_T_DumpDatabase
3508 * dump as much of the database as possible int /tmp/<filename>
3509 */
3510
3511afs_int32
3512SBUDB_T_DumpDatabase(struct rx_call *call, char *filename)
3513{
3514 afs_int32 code;
3515
3516 code = T_DumpDatabase(call, filename);
3517 osi_auditU(call, BUDB_TDmpDBEvent, code, AUD_STR, filename, AUD_END);
3518 return code;
3519}
3520
3521afs_int32
3522T_DumpDatabase(struct rx_call *call, char *filename)
3523{
3524 FILE *dumpfid;
3525 int entrySize;
3526 struct ubik_trans *ut;
3527 char *path = 0;
3528 dbadr dbAddr;
3529 int type, old, length, hash;
3530 struct memoryHashTable *mht;
3531 afs_int32 eval, code = 0;
3532
3533 if (!callPermitted(call))
3534 return BUDB_NOTPERMITTED;
3535
3536 length = asprintf(&path, "%s/%s", gettmpdir(), filename);
3537 if (length < 0 || !path)
3538 return (BUDB_INTERNALERROR);
3539
3540 dumpfid = fopen(path, "w");
3541 if (!dumpfid)
3542 return (BUDB_BADARGUMENT);
3543
3544 eval = InitRPC(&ut, LOCKWRITE, 1);
3545 if (eval)
3546 return (eval);
3547
3548 /* dump all items in the database */
3549 for (type = 1; type <= HT_MAX_FUNCTION; type++) { /*ft */
3550 mht = ht_GetType(type, &entrySize);
3551 if (!mht)
3552 ERROR(BUDB_BADARGUMENT);
3553
3554 for (old = 0; old <= 1; old++) { /*fo */
3555 length = (old ? mht->oldLength : mht->length);
3556 if (!length)
3557 continue;
3558
3559 fprintf(dumpfid, "Dumping %s Hash Table:\n", (old ? "Old " : ""));
3560
3561 for (hash = 0; hash < length; hash++) { /*f */
3562 dbAddr = ht_LookupBucket(ut, mht, hash, old);
3563
3564 while (dbAddr) { /*w */
3565 switch (type) { /*s */
3566 case HT_dumpIden_FUNCTION:
3567 {
3568 struct dump hostDump, diskDump;
3569
3570 eval =
3571 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3572 sizeof(diskDump));
3573 if (eval)
3574 ERROR(eval);
3575
3576 fprintf(dumpfid,
3577 "\ndumpId hash %d, entry at %u\n",
3578 hash, dbAddr);
3579 fprintf(dumpfid,
3580 "----------------------------\n");
3581 dump_ntoh(&diskDump, &hostDump);
3582 printDump(dumpfid, &hostDump);
3583 dbAddr = hostDump.idHashChain;
3584 }
3585 break;
3586
3587 case HT_dumpName_FUNCTION:
3588 {
3589 struct dump hostDump, diskDump;
3590
3591 eval =
3592 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
3593 sizeof(diskDump));
3594 if (eval)
3595 ERROR(eval);
3596
3597 fprintf(dumpfid,
3598 "\ndumpname hash %d, entry at %u\n",
3599 hash, dbAddr);
3600 fprintf(dumpfid,
3601 "----------------------------\n");
3602 dump_ntoh(&diskDump, &hostDump);
3603 printDump(dumpfid, &hostDump);
3604 dbAddr = hostDump.nameHashChain;
3605 }
3606 break;
3607
3608 case HT_tapeName_FUNCTION:
3609 {
3610 struct tape hostTape, diskTape;
3611
3612 eval =
3613 cdbread(ut, tape_BLOCK, dbAddr, &diskTape,
3614 sizeof(diskTape));
3615 if (eval)
3616 ERROR(eval);
3617
3618 fprintf(dumpfid,
3619 "\ntapename hash %d, entry at %u\n",
3620 hash, dbAddr);
3621 fprintf(dumpfid,
3622 "----------------------------\n");
3623 tape_ntoh(&diskTape, &hostTape);
3624 printTape(dumpfid, &hostTape);
3625 dbAddr = hostTape.nameHashChain;
3626 }
3627 break;
3628
3629 case HT_volName_FUNCTION:
3630 {
3631 struct volInfo hostVolInfo, diskVolInfo;
3632
3633 eval =
3634 cdbread(ut, volInfo_BLOCK, dbAddr,
3635 &diskVolInfo, sizeof(diskVolInfo));
3636 if (eval)
3637 ERROR(eval);
3638
3639 fprintf(dumpfid,
3640 "\nvolname hash %d, entry at %u\n",
3641 hash, dbAddr);
3642 fprintf(dumpfid,
3643 "----------------------------\n");
3644 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3645 printVolInfo(dumpfid, &hostVolInfo);
3646 dbAddr = hostVolInfo.nameHashChain;
3647
3648 volFragsDump(ut, dumpfid,
3649 hostVolInfo.firstFragment);
3650 }
3651 break;
3652
3653 default:
3654 fprintf(dumpfid, "unknown type %d\n", type);
3655 break;
3656
3657 } /*s */
3658 } /*w */
3659 } /*f */
3660 } /*fo */
3661 } /*ft */
3662
3663 error_exit:
3664 code = ubik_EndTrans(ut); /* is this safe if no ut started ? */
3665 if (dumpfid)
3666 fclose(dumpfid);
3667 if (path)
3668 free(path);
3669 return (code);
3670}
3671
3672int
3673volFragsDump(struct ubik_trans *ut, FILE *dumpfid, dbadr dbAddr)
3674{
3675 struct volFragment hostVolFragment, diskVolFragment;
3676 afs_int32 code;
3677
3678 while (dbAddr) {
3679 code =
3680 cdbread(ut, volFragment_BLOCK, dbAddr, &diskVolFragment,
3681 sizeof(diskVolFragment));
3682 if (code) { /* don't be fussy about errors */
3683 fprintf(dumpfid, "volFragsDump: Error reading database\n");
3684 return (0);
3685 }
3686
3687 fprintf(dumpfid, "\nvolfragment entry at %u\n", dbAddr);
3688 fprintf(dumpfid, "----------------------------\n");
3689 volFragment_ntoh(&diskVolFragment, &hostVolFragment);
3690 printVolFragment(dumpfid, &hostVolFragment);
3691 dbAddr = hostVolFragment.sameNameChain;
3692 }
3693 return (0);
3694}
3695
3696#ifdef notdef
3697/* utilities - network to host conversion
3698 * currently used for debug only
3699 */
3700
3701void
3702volFragmentDiskToHost(struct volFragment *diskVfPtr,
3703 struct volFragment *hostVfPtr)
3704{
3705 hostVfPtr->vol = ntohl(diskVfPtr->vol);
3706 hostVfPtr->sameNameChain = ntohl(diskVfPtr->sameNameChain);
3707 hostVfPtr->tape = ntohl(diskVfPtr->tape);
3708 hostVfPtr->sameTapeChain = ntohl(diskVfPtr->sameTapeChain);
3709 hostVfPtr->position = ntohl(diskVfPtr->position);
3710 hostVfPtr->clone = ntohl(diskVfPtr->clone);
3711 hostVfPtr->incTime = ntohl(diskVfPtr->incTime);
3712 hostVfPtr->startByte = ntohl(diskVfPtr->startByte);
3713 hostVfPtr->nBytes = ntohl(diskVfPtr->nBytes);
3714 hostVfPtr->flags = ntohs(diskVfPtr->flags);
3715 hostVfPtr->sequence = ntohs(diskVfPtr->sequence);
3716}
3717
3718void
3719volInfoDiskToHost(struct volInfo *diskViPtr, struct volInfo *hostViPtr)
3720{
3721 strcpy(hostViPtr->name, diskViPtr->name);
3722 hostViPtr->nameHashChain = ntohl(diskViPtr->nameHashChain);
3723 hostViPtr->id = ntohl(diskViPtr->id);
3724 strcpy(hostViPtr->server, diskViPtr->server);
3725 hostViPtr->partition = ntohl(diskViPtr->partition);
3726 hostViPtr->flags = ntohl(diskViPtr->flags);
3727 hostViPtr->sameNameHead = ntohl(diskViPtr->sameNameHead);
3728 hostViPtr->sameNameChain = ntohl(diskViPtr->sameNameChain);
3729 hostViPtr->firstFragment = ntohl(diskViPtr->firstFragment);
3730 hostViPtr->nFrags = ntohl(diskViPtr->nFrags);
3731}
3732
3733void
3734tapeDiskToHost(struct tape *diskTapePtr, struct tape *hostTapePtr)
3735{
3736 strcpy(hostTapePtr->name, diskTapePtr->name);
3737 hostTapePtr->nameHashChain = ntohl(diskTapePtr->nameHashChain);
3738 hostTapePtr->flags = ntohl(diskTapePtr->flags);
3739
3740 /* tape id conversion here */
3741 hostTapePtr->written = ntohl(diskTapePtr->written);
3742 hostTapePtr->nBytes = ntohl(diskTapePtr->nBytes);
3743 hostTapePtr->nFiles = ntohl(diskTapePtr->nFiles);
3744 hostTapePtr->nVolumes = ntohl(diskTapePtr->nVolumes);
3745 hostTapePtr->seq = ntohl(diskTapePtr->seq);
3746 hostTapePtr->dump = ntohl(diskTapePtr->dump);
3747 hostTapePtr->nextTape = ntohl(diskTapePtr->nextTape);
3748 hostTapePtr->firstVol = ntohl(diskTapePtr->firstVol);
3749 hostTapePtr->useCount = ntohl(diskTapePtr->useCount);
3750}
3751
3752void
3753dumpDiskToHost(struct dump *diskDumpPtr, struct dump *hostDumpPtr)
3754{
3755 hostDumpPtr->id = ntohl(diskDumpPtr->id);
3756 hostDumpPtr->idHashChain = ntohl(diskDumpPtr->idHashChain);
3757 strcpy(hostDumpPtr->dumpName, diskDumpPtr->dumpName);
3758 strcpy(hostDumpPtr->dumpPath, diskDumpPtr->dumpPath);
3759 strcpy(hostDumpPtr->volumeSet, diskDumpPtr->volumeSet);
3760 hostDumpPtr->nameHashChain = ntohl(diskDumpPtr->nameHashChain);
3761 hostDumpPtr->flags = ntohl(diskDumpPtr->flags);
3762 hostDumpPtr->parent = ntohl(diskDumpPtr->parent);
3763 hostDumpPtr->created = ntohl(diskDumpPtr->created);
3764/* hostDumpPtr->incTime = ntohl(diskDumpPtr->incTime); */
3765 hostDumpPtr->nVolumes = ntohl(diskDumpPtr->nVolumes);
3766
3767 /* tapeset conversion here */
3768
3769 hostDumpPtr->firstTape = ntohl(diskDumpPtr->firstTape);
3770
3771 /* principal conversion here */
3772}
3773
3774#endif /* notdef */
3775
3776int
3777checkHash(struct ubik_trans *ut, int hashType)
3778{
3779 struct memoryHashTable *mhtPtr;
3780 int entrySize, hashTableLength;
3781 int bucket;
3782 int old;
3783 afs_int32 code = 0;
3784
3785 mhtPtr = ht_GetType(hashType, &entrySize);
3786 if (mhtPtr == 0)
3787 ERROR(-1);
3788
3789 for (old = 0; old < 1; old++) {
3790 LogDebug(5, "\nold = %d\n", old);
3791 printMemoryHashTable(stdout, mhtPtr);
3792 LogDebug(5, "\n");
3793 hashTableLength = (old ? mhtPtr->oldLength : mhtPtr->length);
3794
3795 for (bucket = 0; bucket < hashTableLength; bucket++) {
3796 dbadr entryAddr;
3797
3798 entryAddr = ht_LookupBucket(ut, mhtPtr, bucket, old);
3799 while (entryAddr != 0) {
3800 LogDebug(6, "bucket %d has disk addr %d\n", bucket,
3801 entryAddr);
3802 switch (hashType) {
3803 case HT_dumpIden_FUNCTION:
3804 {
3805 struct dump diskDump, hostDump;
3806
3807 code = dbread(ut, entryAddr, &diskDump, entrySize);
3808 if (code)
3809 ERROR(-1);
3810
3811 dump_ntoh(&diskDump, &hostDump);
3812 printDump(stdout, &hostDump);
3813 entryAddr = hostDump.idHashChain;
3814 }
3815 break;
3816
3817 case HT_dumpName_FUNCTION:
3818 break;
3819
3820 case HT_tapeName_FUNCTION:
3821 break;
3822
3823 case HT_volName_FUNCTION:
3824 {
3825 struct volInfo diskVolInfo, hostVolInfo;
3826
3827 code = dbread(ut, entryAddr, &diskVolInfo, entrySize);
3828 if (code)
3829 ERROR(-1);
3830
3831 volInfo_ntoh(&diskVolInfo, &hostVolInfo);
3832 printVolInfo(stdout, &hostVolInfo);
3833 entryAddr = hostVolInfo.nameHashChain;
3834 break;
3835 }
3836 }
3837 }
3838 }
3839 }
3840 error_exit:
3841 return (code);
3842}