Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / butc / tcudbprocs.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#include <afsconfig.h>
11#include <afs/param.h>
12
13#include <afs/procmgmt.h>
14#include <roken.h>
15
16#ifdef IGNORE_SOME_GCC_WARNINGS
17# pragma GCC diagnostic warning "-Wimplicit-function-declaration"
18#endif
19
20#include <afs/opr.h>
21#include <rx/rx.h>
22#include <afs/afsint.h>
23#include <afs/prs_fs.h>
24#include <afs/nfs.h>
25#include <lwp.h>
26#include <lock.h>
27#include <afs/cellconfig.h>
28#include <afs/keys.h>
29#include <ubik.h>
30#include <afs/acl.h>
31#include <afs/volser.h>
32#include <afs/vlserver.h>
33#include <afs/tcdata.h>
34#include <afs/budb.h>
35#include <afs/budb_client.h>
36#include <afs/bubasics.h>
37#include <afs/bucoord_prototypes.h>
38#include <afs/butm_prototypes.h>
39#include <afs/budb_prototypes.h>
40#include <afs/afsutil.h>
41
42#include "butc_internal.h"
43#include "error_macros.h"
44
45/* GLOBAL CONFIGURATION PARAMETERS */
46#define BIGCHUNK 102400
47
48extern int dump_namecheck;
49extern int autoQuery;
50
51struct rstTapeInfo {
52 afs_int32 taskId;
53 afs_int32 tapeSeq;
54 afs_uint32 dumpid;
55};
56
57static void initTapeBuffering(void);
58static int writeDbDump(struct butm_tapeInfo *, afs_uint32, Date, afs_uint32);
59static int restoreDbEntries(struct butm_tapeInfo *, struct rstTapeInfo *);
60
61int getTapeData(struct butm_tapeInfo *, struct rstTapeInfo *, void *,
62 afs_int32);
63int restoreDbHeader(struct butm_tapeInfo *, struct rstTapeInfo *,
64 struct structDumpHeader *);
65int restoreDbDump(struct butm_tapeInfo *, struct rstTapeInfo *,
66 struct structDumpHeader *);
67int restoreText(struct butm_tapeInfo *, struct rstTapeInfo *,
68 struct structDumpHeader *);
69
70
71
72void * KeepAlive(void *);
73/* CreateDBDump
74 * create a dump entry for a saved database
75 */
76
77afs_int32
78CreateDBDump(struct budb_dumpEntry *dumpEntryPtr)
79{
80 afs_int32 code = 0;
81
82 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
83
84 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
85 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
86 strcat(dumpEntryPtr->tapes.format, ".%d");
87 strcpy(dumpEntryPtr->volumeSetName, "");
88 strcpy(dumpEntryPtr->dumpPath, "");
89 dumpEntryPtr->created = 0; /* let database assign it */
90 dumpEntryPtr->incTime = 0;
91 dumpEntryPtr->nVolumes = 0;
92 dumpEntryPtr->initialDumpID = 0;
93 dumpEntryPtr->parent = 0;
94 dumpEntryPtr->level = 0;
95 dumpEntryPtr->tapes.maxTapes = 0;
96 dumpEntryPtr->tapes.b = 1;
97
98 /* now call the database to create the entry */
99 code = bcdb_CreateDump(dumpEntryPtr);
100 return (code);
101}
102
103struct tapeEntryList {
104 struct tapeEntryList *next;
105 afs_uint32 oldDumpId;
106 struct budb_tapeEntry tapeEnt;
107};
108struct tapeEntryList *listEntryHead;
109struct tapeEntryList *listEntryPtr;
110#define tapeEntryPtr (&listEntryPtr->tapeEnt)
111struct budb_dumpEntry lastDump; /* the last dump of this volset */
112
113/* GetDBTape
114 * Load a DB tape, read and over write its label.
115 * Leave the tape mounted.
116 */
117afs_int32
118GetDBTape(afs_int32 taskId, Date expires, struct butm_tapeInfo *tapeInfoPtr,
119 afs_uint32 dumpid, afs_int32 sequence, int queryFlag,
120 int *wroteLabel)
121{
122 afs_int32 code = 0;
123 int interactiveFlag;
124 char tapeName[BU_MAXTAPELEN];
125 char strlevel[5];
126 struct timeval tp;
127 afs_int32 curTime;
128 int tapecount = 1;
129
130 struct butm_tapeLabel oldTapeLabel, newLabel;
131 struct tapeEntryList *endList;
132
133 /* construct the name of the tape */
134 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
135
136 interactiveFlag = queryFlag;
137 *wroteLabel = 0;
138
139 while (!*wroteLabel) { /*w */
140 if (interactiveFlag) { /* need a tape to write */
141 code =
142 PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
143 tapecount);
144 if (code)
145 ERROR_EXIT(code);
146 }
147 interactiveFlag = 1;
148 tapecount++;
149
150 code = butm_Mount(tapeInfoPtr, tapeName);
151 if (code) {
152 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
153 goto getNewTape;
154 }
155
156 memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
157 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
158 if (code) {
159 oldTapeLabel.useCount = 0; /* no label exists */
160 oldTapeLabel.structVersion = 0;
161 strcpy(oldTapeLabel.pName, "");
162 } else {
163 /* If tape has a name, it must be null or database tape name */
164 if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
165 && !databaseTape(oldTapeLabel.AFSName)) {
166 char gotName[BU_MAXTAPELEN + 32];
167
168 LABELNAME(gotName, &oldTapeLabel);
169 TLog(taskId,
170 "This tape %s must be a database tape or NULL tape\n",
171 gotName);
172
173 getNewTape:
174 unmountTape(taskId, tapeInfoPtr);
175 continue;
176 }
177
178 /* Do not overwrite a tape that belongs to this dump */
179 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
180 ErrorLog(0, taskId, 0, 0,
181 "Can't overwrite tape containing the dump in progress\n");
182 goto getNewTape;
183 }
184
185 /* On first tape, the savedb has not started yet, so the database is not locked
186 * and we can therefore, access information from it. This is easier to do because
187 * database dumps don't have appended dumps (nor appended).
188 */
189 if (sequence == 1) {
190 afs_uint32 dmp;
191 struct budb_dumpEntry de, de2;
192
193 /* Verify the tape has not expired
194 * Early database dumps don't have a dumpid
195 */
196 if (!tapeExpired(&oldTapeLabel)) {
197 TLog(taskId, "This tape has not expired\n");
198 goto getNewTape;
199 }
200
201 /* Since the dumpset on this tape will be deleted from database, check if
202 * any of the dumps in this dumpset are most-recent-dumps.
203 */
204 for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
205 if (dmp == lastDump.id) {
206 memcpy(&de, &lastDump, sizeof(de));
207 memcpy(&de2, &lastDump, sizeof(de2));
208 } else {
209 code = bcdb_FindDumpByID(dmp, &de);
210 if (code)
211 break;
212 sprintf(strlevel, "%d", de.level);
213 code =
214 bcdb_FindLatestDump(de.volumeSetName, strlevel,
215 &de2);
216 if (code)
217 continue;
218 }
219
220 if (de.id == de2.id) {
221 if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
222 ErrorLog(0, taskId, 0, 0,
223 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
224 de.name, de.id);
225 } else {
226 ErrorLog(0, taskId, 0, 0,
227 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
228 de.volumeSetName, de.name, de.id);
229 }
230 }
231 }
232 }
233
234 /* Otherwise, the savedb is in progress and we can't
235 * access the database (it's locked). So we rely on the
236 * information available (and not the backup database).
237 */
238 else {
239 /* Check the tape's expiration date. Use the expiration on the label */
240 gettimeofday(&tp, NULL);
241 curTime = tp.tv_sec;
242 if (curTime < oldTapeLabel.expirationDate) {
243 TLog(taskId, "This tape has not expired\n");
244 goto getNewTape;
245 }
246
247 /* Check if this previous-dump of the dump-in-progress is on this tape */
248 if (oldTapeLabel.dumpid
249 && (oldTapeLabel.dumpid == lastDump.id)) {
250 ErrorLog(0, taskId, 0, 0,
251 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
252 lastDump.name, lastDump.id);
253 }
254
255 }
256 }
257
258 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
259 newLabel.expirationDate = expires;
260 newLabel.useCount = oldTapeLabel.useCount + 1;
261 newLabel.dumpid = dumpid;
262 newLabel.size = tapeInfoPtr->tapeSize;
263
264 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
265 if (code) {
266 TapeLog(0, taskId, code, tapeInfoPtr->error,
267 "Can't label tape\n");
268 goto getNewTape;
269 }
270
271 *wroteLabel = 1;
272
273 /* Initialize a tapeEntry for later inclusion into the database */
274 listEntryPtr = calloc(1, sizeof(struct tapeEntryList));
275 if (!listEntryPtr)
276 ERROR_EXIT(TC_NOMEMORY);
277
278 /* Remember dumpid so we can delete it later */
279 if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
280 && oldTapeLabel.dumpid)
281 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
282
283 /* Fill in tape entry so we can save it later */
284 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
285 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
286 tapeEntryPtr->written = newLabel.creationTime;
287 tapeEntryPtr->expires = expires;
288 tapeEntryPtr->seq = sequence;
289 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
290 tapeEntryPtr->dump = dumpid;
291 tapeEntryPtr->useKBytes = 0;
292 tapeEntryPtr->labelpos = 0;
293
294 /* Thread onto end of single-linked list */
295 if (listEntryHead) {
296 endList = listEntryHead;
297 while (endList->next)
298 endList = endList->next;
299 endList->next = listEntryPtr;
300 } else
301 listEntryHead = listEntryPtr;
302 } /*w */
303
304 error_exit:
305 return (code);
306}
307
308/* freeTapeList
309 * With the list of tapes, free the structures.
310 */
311
312afs_int32
313freeTapeList(void)
314{
315 struct tapeEntryList *next;
316
317 listEntryPtr = listEntryHead;
318 while (listEntryPtr) {
319 next = listEntryPtr->next;
320 free(listEntryPtr);
321 listEntryPtr = next;
322 }
323
324 listEntryHead = NULL;
325 return (0);
326}
327
328/* addTapesToDb
329 * With the list of tapes, add them to the database.
330 * Also delete any olddumpids that are around.
331 */
332
333afs_int32
334addTapesToDb(afs_int32 taskId)
335{
336 afs_int32 code = 0;
337 afs_int32 i, new;
338 struct tapeEntryList *next;
339
340 listEntryPtr = listEntryHead;
341 while (listEntryPtr) {
342 next = listEntryPtr->next;
343
344 /* Remove the old database entry */
345 if (listEntryPtr->oldDumpId) {
346 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
347 if (i && (i != BUDB_NOENT)) {
348 ErrorLog(0, taskId, i, 0,
349 "Unable to delete old DB entry %u.\n",
350 listEntryPtr->oldDumpId);
351 }
352 }
353
354 /* Add the tape to the database */
355 code = bcdb_UseTape(tapeEntryPtr, &new);
356 if (code) {
357 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n",
358 tapeEntryPtr->name);
359 ERROR_EXIT(code);
360 }
361
362 code = bcdb_FinishTape(tapeEntryPtr);
363 if (code) {
364 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n",
365 tapeEntryPtr->name);
366 ERROR_EXIT(code);
367 }
368
369 listEntryPtr = next;
370 }
371
372 error_exit:
373 return (code);
374}
375
376/* writeDbDump
377 * notes:
378 * this code assumes that the blocksize on reads is smaller than
379 * the blocksize on writes
380 */
381
382static int
383writeDbDump(struct butm_tapeInfo *tapeInfoPtr, afs_uint32 taskId,
384 Date expires, afs_uint32 dumpid)
385{
386 afs_int32 blockSize;
387 afs_int32 writeBufNbytes = 0;
388 char *writeBlock = 0;
389 char *writeBuffer = 0;
390 char *writeBufPtr;
391 afs_int32 transferSize;
392
393 char *readBufPtr = NULL;
394 afs_int32 maxReadSize;
395
396 charListT charList;
397 afs_int32 done;
398 afs_int32 code;
399 afs_int32 chunksize = 0;
400 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
401 int sequence;
402 int wroteLabel;
403 int firstcall;
404#ifdef AFS_PTHREAD_ENV
405 pthread_t alivePid;
406 pthread_attr_t tattr;
407 AFS_SIGSET_DECL;
408#else
409 PROCESS alivePid;
410#endif
411
412 extern struct tapeConfig globalTapeConfig;
413 extern struct udbHandleS udbHandle;
414
415 charList.charListT_val = 0;
416 charList.charListT_len = 0;
417 blockSize = BUTM_BLKSIZE;
418 writeBlock = malloc(BUTM_BLOCKSIZE);
419 if (!writeBlock)
420 ERROR_EXIT(TC_NOMEMORY);
421
422 writeBuffer = writeBlock + sizeof(struct blockMark);
423 memset(writeBuffer, 0, BUTM_BLKSIZE);
424 maxReadSize = 1024;
425
426 /*
427 * The margin of space to check for end of tape is set to the
428 * amount of space used to write an end-of-tape multiplied by 2.
429 * The amount of space is size of a 16K EODump marker, its EOF
430 * marker, and up to two EOF markers done on close (1 16K blocks +
431 * 3 EOF * markers).
432 */
433 tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
434 tc_KEndMargin = tc_EndMargin / 1024;
435
436 /* have to write enclose the dump in file marks */
437 code = butm_WriteFileBegin(tapeInfoPtr);
438 if (code) {
439 ErrorLog(0, taskId, code, tapeInfoPtr->error,
440 "Can't write FileBegin on tape\n");
441 ERROR_EXIT(code);
442 }
443
444 writeBufPtr = &writeBuffer[0];
445 firstcall = 1;
446 sequence = 1;
447
448 while (1) { /*w */
449 /* When no data in buffer, read data from the budb_server */
450 if (charList.charListT_len == 0) {
451 /* get more data. let rx allocate space */
452 if (charList.charListT_val) {
453 free(charList.charListT_val);
454 charList.charListT_val = 0;
455 }
456
457 /* get the data */
458 code =
459 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
460 UF_SINGLESERVER, firstcall,
461 maxReadSize, &charList, &done);
462 if (code) {
463 ErrorLog(0, taskId, code, 0, "Can't read database\n");
464 ERROR_EXIT(code);
465 }
466
467 /* If this if the first call to the budb server, create a thread
468 * that will keep the connection alive (during tape changes).
469 */
470 if (firstcall) {
471#ifdef AFS_PTHREAD_ENV
472 code = pthread_attr_init(&tattr);
473 if (code) {
474 ErrorLog(0, taskId, code, 0,
475 "Can't pthread_attr_init Keep-alive process\n");
476 ERROR_EXIT(code);
477 }
478
479 code =
480 pthread_attr_setdetachstate(&tattr,
481 PTHREAD_CREATE_DETACHED);
482 if (code) {
483 ErrorLog(0, taskId, code, 0,
484 "Can't pthread_attr_setdetachstate Keep-alive process\n");
485 ERROR_EXIT(code);
486 }
487
488 AFS_SIGSET_CLEAR();
489 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
490 AFS_SIGSET_RESTORE();
491#else
492 code =
493 LWP_CreateProcess(KeepAlive, 16384, 1, NULL,
494 "Keep-alive process", &alivePid);
495#endif
496 if (code) {
497 ErrorLog(0, taskId, code, 0,
498 "Failed to create keep alive process\n");
499 ERROR_EXIT(code);
500 }
501 }
502 firstcall = 0;
503
504 readBufPtr = charList.charListT_val;
505 }
506
507 if ((charList.charListT_len == 0) && done)
508 break;
509
510 /* compute how many bytes and transfer to the write Buffer */
511 transferSize =
512 (charList.charListT_len <
513 (blockSize -
514 writeBufNbytes)) ? charList.charListT_len : (blockSize -
515 writeBufNbytes);
516
517 memcpy(writeBufPtr, readBufPtr, transferSize);
518 charList.charListT_len -= transferSize;
519 writeBufPtr += transferSize;
520 readBufPtr += transferSize;
521 writeBufNbytes += transferSize;
522
523 /* If filled the write buffer, then write it to tape */
524 if (writeBufNbytes == blockSize) {
525 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
526 if (code) {
527 ErrorLog(0, taskId, code, tapeInfoPtr->error,
528 "Can't write data on tape\n");
529 ERROR_EXIT(code);
530 }
531
532 memset(writeBuffer, 0, blockSize);
533 writeBufPtr = &writeBuffer[0];
534 writeBufNbytes = 0;
535
536 /* Every BIGCHUNK bytes check if aborted */
537 chunksize += blockSize;
538 if (chunksize > BIGCHUNK) {
539 chunksize = 0;
540 if (checkAbortByTaskId(taskId))
541 ERROR_EXIT(TC_ABORTEDBYREQUEST);
542 }
543
544 /*
545 * check if tape is full - since we filled a blockSize worth of data
546 * assume that there is more data.
547 */
548 kRemaining = butm_remainingKSpace(tapeInfoPtr);
549 if (kRemaining < tc_KEndMargin) {
550 code = butm_WriteFileEnd(tapeInfoPtr);
551 if (code) {
552 ErrorLog(0, taskId, code, tapeInfoPtr->error,
553 "Can't write FileEnd on tape\n");
554 ERROR_EXIT(code);
555 }
556
557 code = butm_WriteEOT(tapeInfoPtr);
558 if (code) {
559 ErrorLog(0, taskId, code, tapeInfoPtr->error,
560 "Can't write end-of-dump on tape\n");
561 ERROR_EXIT(code);
562 }
563
564 /* Mark tape as having been written */
565 tapeEntryPtr->useKBytes =
566 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
567 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
568
569 unmountTape(taskId, tapeInfoPtr);
570
571 /* Get next tape and writes its label */
572 sequence++;
573 code =
574 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
575 1, &wroteLabel);
576 if (code)
577 ERROR_EXIT(code);
578
579 code = butm_WriteFileBegin(tapeInfoPtr);
580 if (code) {
581 ErrorLog(0, taskId, code, tapeInfoPtr->error,
582 "Can't write FileBegin on tape\n");
583 ERROR_EXIT(code);
584 }
585 }
586 }
587 } /*w */
588
589 /* no more data to be read - if necessary, flush out the last buffer */
590 if (writeBufNbytes > 0) {
591 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
592 if (code) {
593 ErrorLog(1, taskId, code, tapeInfoPtr->error,
594 "Can't write data on tape\n");
595 ERROR_EXIT(code);
596 }
597 }
598
599 code = butm_WriteFileEnd(tapeInfoPtr);
600 if (code) {
601 ErrorLog(0, taskId, code, tapeInfoPtr->error,
602 "Can't write FileEnd on tape\n");
603 ERROR_EXIT(code);
604 }
605
606 /* Mark tape as having been written */
607 tapeEntryPtr->useKBytes =
608 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
609 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
610
611 error_exit:
612 /* Let the KeepAlive process stop on its own */
613 code =
614 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
615 UF_END_SINGLESERVER, 0);
616
617 if (writeBlock)
618 free(writeBlock);
619 if (charList.charListT_val)
620 free(charList.charListT_val);
621 return (code);
622}
623
624/* saveDbToTape
625 * dump backup database to tape
626 */
627
628void *
629saveDbToTape(void *param)
630{
631 struct saveDbIf *saveDbIfPtr = (struct saveDbIf *)param;
632 afs_int32 code;
633 afs_int32 i;
634 int wroteLabel;
635 afs_uint32 taskId;
636 Date expires;
637
638 struct butm_tapeInfo tapeInfo;
639 struct budb_dumpEntry dumpEntry;
640
641 extern struct deviceSyncNode *deviceLatch;
642 extern struct tapeConfig globalTapeConfig;
643
644 afs_pthread_setname_self("Db save");
645 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
646 taskId = saveDbIfPtr->taskId;
647 dumpEntry.id = 0;
648
649 setStatus(taskId, DRIVE_WAIT);
650 EnterDeviceQueue(deviceLatch); /* lock tape device */
651 clearStatus(taskId, DRIVE_WAIT);
652
653 printf("\n\n");
654 TLog(taskId, "SaveDb\n");
655
656 tapeInfo.structVersion = BUTM_MAJORVERSION;
657 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
658 if (code) {
659 ErrorLog(0, taskId, code, tapeInfo.error,
660 "Can't initialize tape module\n");
661 ERROR_EXIT(code);
662 }
663
664 /* Determine what the last database dump was */
665 memset(&lastDump, 0, sizeof(lastDump));
666 code = bcdb_FindLatestDump("", "", &lastDump);
667 if (code) {
668 if (code != BUDB_NODUMPNAME) {
669 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
670 ERROR_EXIT(code);
671 }
672 memset(&lastDump, 0, sizeof(lastDump));
673 }
674
675 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
676 if (code) {
677 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
678 ERROR_EXIT(code);
679 }
680
681
682 listEntryHead = NULL;
683
684 /* Get the tape and write a new label to it */
685 code =
686 GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
687 &wroteLabel);
688
689 /*
690 * If did not write the label, remove created dump
691 * Else if wrote the label, remove old dump from db so it's not saved.
692 */
693 if (!wroteLabel) {
694 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
695 dumpEntry.id = 0;
696 if (i && (i != BUDB_NOENT))
697 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
698 dumpEntry.id);
699 } else if (listEntryHead->oldDumpId) {
700 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
701 listEntryHead->oldDumpId = 0;
702 if (i && (i != BUDB_NOENT)) {
703 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
704 listEntryHead->oldDumpId);
705 ERROR_EXIT(i);
706 }
707 }
708 if (code)
709 ERROR_EXIT(code);
710
711 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
712
713 /* we have a writable tape */
714 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
715 if (code)
716 ERROR_EXIT(code);
717
718 /* Now delete the entries between time 0 and archive-time */
719 if (saveDbIfPtr->archiveTime)
720 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
721
722 error_exit:
723 unmountTape(taskId, &tapeInfo);
724
725 /* Add this dump's tapes to the database and mark it finished */
726 if (dumpEntry.id) {
727 i = addTapesToDb(taskId);
728 if (!code)
729 code = i;
730
731 i = bcdb_FinishDump(&dumpEntry);
732 if (!code)
733 code = i;
734 }
735 freeTapeList();
736
737 if (code == TC_ABORTEDBYREQUEST) {
738 TLog(taskId, "SaveDb: Aborted by request\n");
739 clearStatus(taskId, ABORT_REQUEST);
740 setStatus(taskId, ABORT_DONE);
741 } else if (code) {
742 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
743 setStatus(taskId, TASK_ERROR);
744 } else {
745 TLog(taskId, "SaveDb: Finished\n");
746 }
747 setStatus(taskId, TASK_DONE);
748
749 free(saveDbIfPtr);
750 LeaveDeviceQueue(deviceLatch);
751 return (void *)(intptr_t)(code);
752}
753
754
755/* makeDbDumpEntry()
756 * Make a database dump entry given a tape label.
757 */
758
759afs_int32
760makeDbDumpEntry(struct budb_tapeEntry *tapeEntPtr,
761 struct budb_dumpEntry *dumpEntryPtr)
762{
763 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
764
765 dumpEntryPtr->id = tapeEntPtr->dump;
766 dumpEntryPtr->initialDumpID = 0;
767 dumpEntryPtr->parent = 0;
768 dumpEntryPtr->level = 0;
769 dumpEntryPtr->flags = 0;
770
771 strcpy(dumpEntryPtr->volumeSetName, "");
772 strcpy(dumpEntryPtr->dumpPath, "");
773 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
774
775 dumpEntryPtr->created = tapeEntPtr->dump;
776 dumpEntryPtr->incTime = 0;
777 dumpEntryPtr->nVolumes = 0;
778
779 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
780 strcat(dumpEntryPtr->tapes.format, ".%d");
781 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
782 dumpEntryPtr->tapes.maxTapes = 0;
783 return 0;
784}
785
786/* readDbTape
787 * prompt for a specific database tape
788 */
789
790afs_int32
791readDbTape(struct butm_tapeInfo *tapeInfoPtr,
792 struct rstTapeInfo *rstTapeInfoPtr, int query)
793{
794 afs_int32 code = 0;
795 int interactiveFlag;
796 afs_int32 taskId;
797 struct butm_tapeLabel oldTapeLabel;
798 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
799 struct tapeEntryList *endList;
800 int tapecount = 1;
801 struct budb_dumpEntry de;
802 struct budb_tapeEntry te;
803
804 taskId = rstTapeInfoPtr->taskId;
805 interactiveFlag = query;
806
807 /* construct the name of the tape */
808 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
809 strcpy(tapeName, AFStapeName);
810
811 /* Will prompt for the latest saved database tape, but will accept any one */
812 if (rstTapeInfoPtr->tapeSeq == 1) {
813 code = bcdb_FindLatestDump("", "", &de);
814 if (!code)
815 rstTapeInfoPtr->dumpid = de.id;
816 }
817 if (rstTapeInfoPtr->dumpid) {
818 code =
819 bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
820 &te);
821 if (!code)
822 strcpy(tapeName, te.name);
823 }
824
825 while (1) { /*w */
826 if (interactiveFlag) { /* need a tape to read */
827 code =
828 PromptForTape(RESTOREDBOPCODE, tapeName,
829 rstTapeInfoPtr->dumpid, taskId, tapecount);
830 if (code)
831 ERROR_EXIT(code);
832 }
833 interactiveFlag = 1;
834 tapecount++;
835
836 code = butm_Mount(tapeInfoPtr, tapeName);
837 if (code) {
838 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
839 goto getNewTape;
840 }
841
842 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
843 if (code) {
844 TapeLog(0, taskId, code, tapeInfoPtr->error,
845 "Can't read tape label\n");
846 goto getNewTape;
847 }
848
849 /* Check for name of tape and matching dump id (if applicable). */
850 if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
851 || ((rstTapeInfoPtr->tapeSeq != 1)
852 && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
853 char expTape[BU_MAXTAPELEN + 32];
854 char gotTape[BU_MAXTAPELEN + 32];
855
856 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
857 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
858
859 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
860 gotTape);
861 goto getNewTape;
862 }
863
864 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
865 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
866
867 break;
868
869 getNewTape:
870 unmountTape(taskId, tapeInfoPtr);
871 } /*w */
872
873
874 /* Initialize a tapeEntry for later inclusion into the database */
875 listEntryPtr = calloc(1, sizeof(struct tapeEntryList));
876 if (!listEntryPtr)
877 ERROR_EXIT(TC_NOMEMORY);
878
879 /* Fill in tape entry so we can save it later */
880 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
881 tapeEntryPtr->dump = oldTapeLabel.dumpid;
882 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
883 tapeEntryPtr->written = oldTapeLabel.creationTime;
884 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
885 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
886 tapeEntryPtr->useCount = oldTapeLabel.useCount;
887 tapeEntryPtr->useKBytes = 0;
888 tapeEntryPtr->labelpos = 0;
889
890 /* Thread onto end of single-linked list */
891 if (listEntryHead) {
892 endList = listEntryHead;
893 while (endList->next)
894 endList = endList->next;
895 endList->next = listEntryPtr;
896 } else
897 listEntryHead = listEntryPtr;
898
899 error_exit:
900 return (code);
901}
902
903static afs_int32 nbytes = 0; /* # bytes left in buffer */
904static void
905initTapeBuffering(void)
906{
907 nbytes = 0;
908}
909
910
911/* restoreDbEntries
912 * restore all the items on the tape
913 * entry:
914 * tape positioned after tape label
915 */
916
917static int
918restoreDbEntries(struct butm_tapeInfo *tapeInfoPtr,
919 struct rstTapeInfo *rstTapeInfoPtr)
920{
921 struct structDumpHeader netItemHeader, hostItemHeader;
922 afs_int32 more = 1;
923 afs_int32 taskId, code = 0;
924 int count = 0;
925
926 taskId = rstTapeInfoPtr->taskId;
927
928 /* clear state for the buffer routine(s) */
929 initTapeBuffering();
930
931 code = butm_ReadFileBegin(tapeInfoPtr);
932 if (code) {
933 ErrorLog(0, taskId, code, tapeInfoPtr->error,
934 "Can't read FileBegin on tape\n");
935 ERROR_EXIT(code);
936 }
937
938 /* get the first item-header */
939 memset(&netItemHeader, 0, sizeof(netItemHeader));
940 code =
941 getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
942 sizeof(netItemHeader));
943 if (code)
944 ERROR_EXIT(code);
945 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
946
947 while (more) {
948 switch (hostItemHeader.type) {
949 case SD_DBHEADER:
950 code =
951 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
952 if (code)
953 ERROR_EXIT(code);
954 break;
955
956 case SD_DUMP:
957 if (++count > 25) { /*every 25 dumps, wait */
958 waitDbWatcher();
959 count = 0;
960 }
961 code =
962 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
963 if (code)
964 ERROR_EXIT(code);
965 break;
966
967 case SD_TAPE:
968 case SD_VOLUME:
969 ERROR_EXIT(-1);
970 break;
971
972 case SD_TEXT_DUMPSCHEDULE:
973 case SD_TEXT_VOLUMESET:
974 case SD_TEXT_TAPEHOSTS:
975 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
976 if (code)
977 ERROR_EXIT(code);
978 break;
979
980 case SD_END:
981 more = 0;
982 break;
983
984 default:
985 TLog(taskId, "Unknown database header type %d\n",
986 hostItemHeader.type);
987 ERROR_EXIT(-1);
988 break;
989 }
990 }
991
992 code = butm_ReadFileEnd(tapeInfoPtr);
993 if (code) {
994 ErrorLog(0, taskId, code, tapeInfoPtr->error,
995 "Can't read EOF on tape\n");
996 ERROR_EXIT(code);
997 }
998
999 /* Mark tape as having been written */
1000 tapeEntryPtr->useKBytes =
1001 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1002 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1003
1004 error_exit:
1005 return (code);
1006}
1007
1008/* restoreDbFromTape
1009 * restore the backup database from tape.
1010 */
1011
1012void *
1013restoreDbFromTape(void *param)
1014{
1015 afs_uint32 taskId = (intptr_t) param;
1016 afs_int32 code = 0;
1017 afs_int32 i;
1018 struct butm_tapeInfo tapeInfo;
1019 struct rstTapeInfo rstTapeInfo;
1020 struct budb_dumpEntry dumpEntry;
1021
1022 extern struct tapeConfig globalTapeConfig;
1023 extern struct deviceSyncNode *deviceLatch;
1024
1025 afs_pthread_setname_self("Db restore");
1026 setStatus(taskId, DRIVE_WAIT);
1027 EnterDeviceQueue(deviceLatch); /* lock tape device */
1028 clearStatus(taskId, DRIVE_WAIT);
1029
1030 printf("\n\n");
1031 TLog(taskId, "RestoreDb\n");
1032
1033 tapeInfo.structVersion = BUTM_MAJORVERSION;
1034 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1035 if (code) {
1036 ErrorLog(0, taskId, code, tapeInfo.error,
1037 "Can't initialize tape module\n");
1038 ERROR_EXIT(code);
1039 }
1040
1041 listEntryHead = NULL;
1042
1043 rstTapeInfo.taskId = taskId;
1044 rstTapeInfo.tapeSeq = 1;
1045 rstTapeInfo.dumpid = 0;
1046
1047 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1048 if (code)
1049 ERROR_EXIT(code);
1050
1051 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1052 if (code)
1053 ERROR_EXIT(code);
1054
1055 error_exit:
1056 /* Now put this dump into the database */
1057 /* Make a dump entry from first tape */
1058 listEntryPtr = listEntryHead;
1059 if (listEntryPtr) {
1060 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1061 if (dumpEntry.id != 0) {
1062 i = bcdb_CreateDump(&dumpEntry);
1063 if (i) {
1064 if (i == BUDB_DUMPIDEXISTS)
1065 fprintf(stderr,
1066 "Dump id %d not added to database - already exists\n",
1067 dumpEntry.id);
1068 else
1069 TapeLog(0, taskId, i, 0,
1070 "Dump id %d not added to database\n",
1071 dumpEntry.id);
1072 } else {
1073 i = addTapesToDb(taskId);
1074 if (!code)
1075 code = i;
1076
1077 i = bcdb_FinishDump(&dumpEntry);
1078 if (!code)
1079 code = i;
1080 }
1081 }
1082 freeTapeList();
1083 }
1084
1085 unmountTape(taskId, &tapeInfo);
1086 waitDbWatcher();
1087
1088 if (code == TC_ABORTEDBYREQUEST) {
1089 TLog(taskId, "RestoreDb: Aborted by request\n");
1090 clearStatus(taskId, ABORT_REQUEST);
1091 setStatus(taskId, ABORT_DONE);
1092 } else if (code) {
1093 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1094 setStatus(taskId, TASK_ERROR);
1095 } else {
1096 TLog(taskId, "RestoreDb: Finished\n");
1097 }
1098
1099 LeaveDeviceQueue(deviceLatch);
1100 setStatus(taskId, TASK_DONE);
1101
1102 return (void *)(intptr_t)(code);
1103}
1104
1105/* KeepAlive
1106 *
1107 * While dumping the database, keeps the connection alive.
1108 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
1109 * This resets the database's internal timer so that it does not
1110 * prematuraly quit (on asking for new tapes and such).
1111 *
1112 * Use the same udbHandle as writeDbDump so we go to the same server.
1113 */
1114void *
1115KeepAlive(void *unused)
1116{
1117 charListT charList;
1118 afs_int32 code;
1119 afs_int32 done;
1120
1121 extern struct udbHandleS udbHandle;
1122
1123 afs_pthread_setname_self("Keep-alive");
1124 while (1) {
1125#ifdef AFS_PTHREAD_ENV
1126 sleep(5);
1127#else
1128 IOMGR_Sleep(5);
1129#endif
1130 charList.charListT_val = 0;
1131 charList.charListT_len = 0;
1132 code =
1133 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1134 UF_SINGLESERVER, 0, 0, &charList, &done);
1135 if (code || done)
1136 break;
1137 }
1138 return 0;
1139}
1140
1141
1142/* restoreDbHeader
1143 * restore special items in the header
1144 */
1145
1146int
1147restoreDbHeader(struct butm_tapeInfo *tapeInfo,
1148 struct rstTapeInfo *rstTapeInfoPtr,
1149 struct structDumpHeader *nextHeader)
1150{
1151 struct structDumpHeader netItemHeader;
1152 struct DbHeader netDbHeader, hostDbHeader;
1153 afs_int32 code = 0;
1154
1155 extern struct udbHandleS udbHandle;
1156
1157 /* Read the database header */
1158 memset(&netDbHeader, 0, sizeof(netDbHeader));
1159 code =
1160 getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1161 sizeof(netDbHeader));
1162 if (code)
1163 ERROR_EXIT(code);
1164 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1165
1166 /* Add the database header to the database */
1167 code =
1168 ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1169 &hostDbHeader);
1170 if (code) {
1171 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1172 "Can't restore DB Header\n");
1173 ERROR_EXIT(code);
1174 }
1175
1176 /* get the next item-header */
1177 memset(nextHeader, 0, sizeof(*nextHeader));
1178 code =
1179 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1180 sizeof(netItemHeader));
1181 if (code)
1182 ERROR_EXIT(code);
1183 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1184
1185 error_exit:
1186 return (code);
1187}
1188
1189
1190/* restoreDbDump
1191 * restore a single dump, including all its tapes and volumes, from
1192 * the tape.
1193 * entry:
1194 * nextHeader - ptr to structure for return value
1195 * exit:
1196 * nextHeader - next structure header from tape
1197 * notes:
1198 * upon entry, the dump structure header has been read confirming that
1199 * a database dump tree exists on the tape
1200 */
1201
1202int
1203restoreDbDump(struct butm_tapeInfo *tapeInfo,
1204 struct rstTapeInfo *rstTapeInfoPtr,
1205 struct structDumpHeader *nextHeader)
1206{
1207 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1208 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1209 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1210 struct structDumpHeader netItemHeader;
1211 int restoreThisDump = 1;
1212 afs_int32 code = 0;
1213
1214 extern struct udbHandleS udbHandle;
1215
1216 /* read dump entry */
1217 memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1218 code =
1219 getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry,
1220 sizeof(netDumpEntry));
1221 if (code)
1222 ERROR_EXIT(code);
1223
1224 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1225 if (rstTapeInfoPtr->dumpid == 0) {
1226 netDumpEntry.initialDumpID = 0;
1227 netDumpEntry.appendedDumpID = 0;
1228 }
1229
1230 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1231
1232 /* The dump entry for this database tape is incomplete, so don't include it */
1233 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1234 restoreThisDump = 0;
1235
1236 /* add the dump to the database */
1237 if (restoreThisDump) {
1238 code =
1239 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1240 DLQ_USEDUMP);
1241 if (code)
1242 ERROR_EXIT(code);
1243 }
1244
1245 /* get the next item-header */
1246 memset(nextHeader, 0, sizeof(*nextHeader));
1247 code =
1248 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1249 sizeof(netItemHeader));
1250 if (code)
1251 ERROR_EXIT(code);
1252 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1253
1254 /* Add every tape to the db */
1255 while (nextHeader->type == SD_TAPE) { /*t */
1256
1257 /* read the tape entry */
1258 memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1259 code =
1260 getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry,
1261 sizeof(netTapeEntry));
1262 if (code)
1263 ERROR_EXIT(code);
1264 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1265
1266 /* Add the tape to the database */
1267 if (restoreThisDump) {
1268 code =
1269 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1270 DLQ_USETAPE);
1271 if (code)
1272 ERROR_EXIT(code);
1273 }
1274
1275 /* get the next item-header */
1276 memset(nextHeader, 0, sizeof(*nextHeader));
1277 code =
1278 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1279 sizeof(netItemHeader));
1280 if (code)
1281 ERROR_EXIT(code);
1282 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1283
1284 /* Add every volume to the db */
1285 while (nextHeader->type == SD_VOLUME) { /*v */
1286
1287 /* read the volume entry */
1288 memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1289 code =
1290 getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry,
1291 sizeof(netVolumeEntry));
1292 if (code)
1293 ERROR_EXIT(code);
1294 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1295
1296 if (restoreThisDump) {
1297 code =
1298 threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry),
1299 DLQ_VOLENTRY);
1300 if (code)
1301 ERROR_EXIT(code);
1302 }
1303
1304 /* get the next item-header */
1305 memset(nextHeader, 0, sizeof(*nextHeader));
1306 code =
1307 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1308 sizeof(netItemHeader));
1309 if (code)
1310 ERROR_EXIT(code);
1311 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1312 } /*v */
1313
1314 /* Finish the tape */
1315 if (restoreThisDump) {
1316 code =
1317 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1318 DLQ_FINISHTAPE);
1319 if (code)
1320 ERROR_EXIT(code);
1321 }
1322 } /*t */
1323
1324 /* Finish the dump */
1325 if (restoreThisDump) {
1326 code =
1327 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1328 DLQ_FINISHDUMP);
1329 if (code)
1330 ERROR_EXIT(code);
1331 }
1332
1333 error_exit:
1334 return (code);
1335}
1336
1337/* saveTextFile
1338 * Save the specified file as configuration text in the ubik database.
1339 * Have to setup the client text structure so that we can call
1340 * the routine to transmit the text to the db.
1341 */
1342
1343afs_int32
1344saveTextFile(afs_int32 taskId, afs_int32 textType, char *fileName)
1345{
1346 udbClientTextP ctPtr = 0;
1347 afs_int32 code = 0;
1348 int tlock = 0;
1349
1350 ctPtr = calloc(1, sizeof(*ctPtr));
1351 if (!ctPtr)
1352 ERROR_EXIT(TC_NOMEMORY);
1353
1354 ctPtr->textType = textType;
1355
1356 /* lock the text in the database */
1357 code = bc_LockText(ctPtr);
1358 if (code) {
1359 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1360 ERROR_EXIT(code);
1361 }
1362 tlock = 1;
1363
1364 ctPtr->textStream = fopen(fileName, "r");
1365 if (!ctPtr->textStream) {
1366 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1367 ERROR_EXIT(errno);
1368 }
1369
1370 /* now send the text to the database */
1371 code = bcdb_SaveTextFile(ctPtr);
1372 if (code) {
1373 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1374 ERROR_EXIT(code);
1375 }
1376
1377 error_exit:
1378 if (ctPtr) {
1379 if (ctPtr->textStream)
1380 fclose(ctPtr->textStream);
1381 if (tlock)
1382 bc_UnlockText(ctPtr);
1383 free(ctPtr);
1384 }
1385 return (code);
1386}
1387
1388/* restoreText
1389 * read the text off the tape, and store it in the appropriate
1390 * text type in the database.
1391 * entry:
1392 * nextHeader - ptr to struct for return information
1393 * exit:
1394 * nextHeader - struct header for next item on the tape
1395 */
1396
1397int
1398restoreText(struct butm_tapeInfo *tapeInfo,
1399 struct rstTapeInfo *rstTapeInfoPtr,
1400 struct structDumpHeader *nextHeader)
1401{
1402 char filename[64];
1403 afs_int32 nbytes;
1404 char *readBuffer = 0;
1405 afs_int32 readBlockSize;
1406 afs_int32 transferSize;
1407 struct structDumpHeader netItemHeader;
1408 int fid = -1;
1409 afs_int32 code = 0;
1410
1411 udbClientTextP ctPtr = 0;
1412 afs_int32 textType;
1413
1414 ctPtr = malloc(sizeof(*ctPtr));
1415 if (!ctPtr)
1416 ERROR_EXIT(TC_NOMEMORY);
1417
1418 /* determine the type of text block */
1419 switch (nextHeader->type) {
1420 case SD_TEXT_DUMPSCHEDULE:
1421 textType = TB_DUMPSCHEDULE;
1422 break;
1423
1424 case SD_TEXT_VOLUMESET:
1425 textType = TB_VOLUMESET;
1426 break;
1427
1428 case SD_TEXT_TAPEHOSTS:
1429 textType = TB_TAPEHOSTS;
1430 break;
1431
1432 default:
1433 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0,
1434 "Unknown text block\n");
1435 ERROR_EXIT(TC_INTERNALERROR);
1436 break;
1437 }
1438
1439 /* open the text file */
1440 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1441 fid = mkstemp(filename);
1442 if (fid < 0) {
1443 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1444 "Can't open temporary text file: %s\n", filename);
1445 ERROR_EXIT(errno);
1446 }
1447
1448 /* allocate buffer for text */
1449 readBlockSize = BUTM_BLKSIZE;
1450 readBuffer = malloc(readBlockSize);
1451 if (!readBuffer)
1452 ERROR_EXIT(TC_NOMEMORY);
1453
1454 /* read the text into the temporary file */
1455 nbytes = nextHeader->size;
1456 while (nbytes > 0) {
1457 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1458
1459 /* read it from the tape */
1460 code =
1461 getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1462 if (code)
1463 ERROR_EXIT(code);
1464
1465 /* write to the file */
1466 if (write(fid, readBuffer, transferSize) != transferSize) {
1467 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1468 "Can't write temporary text file: %s\n", filename);
1469 ERROR_EXIT(errno);
1470 }
1471
1472 nbytes -= transferSize;
1473 }
1474
1475 close(fid);
1476 fid = -1;
1477 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1478 if (code)
1479 ERROR_EXIT(code);
1480 unlink(filename);
1481
1482 /* get the next item-header */
1483 memset(nextHeader, 0, sizeof(*nextHeader));
1484 code =
1485 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1486 sizeof(netItemHeader));
1487 if (code)
1488 ERROR_EXIT(code);
1489 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1490
1491 error_exit:
1492 if (ctPtr)
1493 free(ctPtr);
1494 if (readBuffer)
1495 free(readBuffer);
1496 if (fid != -1) {
1497 close(fid);
1498 unlink(filename);
1499 }
1500 return (code);
1501}
1502
1503
1504/* ----------------------------------
1505 * Tape data buffering - for reading database dumps
1506 * ----------------------------------
1507 */
1508
1509static char *tapeReadBuffer = 0; /* input buffer */
1510static char *tapeReadBufferPtr = 0; /* position in buffer */
1511
1512/* getTapeData
1513 * Read information from tape, and place the requested number of bytes
1514 * in the buffer supplied
1515 * entry:
1516 * tapeInfo
1517 * rstTapeInfoPtr - Info about the dump being restored.
1518 * buffer - buffer for requested data
1519 * requestedBytes - no. of bytes requested
1520 * exit:
1521 * fn retn - 0, ok, n, error
1522 */
1523
1524int
1525getTapeData(struct butm_tapeInfo *tapeInfoPtr,
1526 struct rstTapeInfo *rstTapeInfoPtr,
1527 void *out, afs_int32 requestedBytes)
1528{
1529 char *buffer = (char *) out;
1530 afs_int32 taskId, transferBytes;
1531 afs_int32 code = 0;
1532
1533 taskId = rstTapeInfoPtr->taskId;
1534
1535 if (checkAbortByTaskId(taskId))
1536 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1537
1538 if (!tapeReadBuffer) {
1539 tapeReadBuffer = malloc(BUTM_BLOCKSIZE);
1540 if (!tapeReadBuffer)
1541 ERROR_EXIT(TC_NOMEMORY);
1542 }
1543
1544 while (requestedBytes > 0) {
1545 if (nbytes == 0) {
1546 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1547
1548 /* get more data */
1549 code =
1550 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1551 BUTM_BLKSIZE, &nbytes);
1552 if (code) {
1553 /* detect if we hit the end-of-tape and get next tape */
1554 if (code == BUTM_ENDVOLUME) {
1555 /* Update fields in tape entry for this tape */
1556 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1557 tapeEntryPtr->useKBytes =
1558 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1559
1560 unmountTape(taskId, tapeInfoPtr);
1561
1562 rstTapeInfoPtr->tapeSeq++;
1563 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1564 if (code)
1565 ERROR_EXIT(code);
1566
1567 code = butm_ReadFileBegin(tapeInfoPtr);
1568 if (code) {
1569 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1570 "Can't read FileBegin on tape\n");
1571 ERROR_EXIT(code);
1572 }
1573
1574 continue;
1575 }
1576
1577 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1578 "Can't read FileData on tape\n");
1579 ERROR_EXIT(code);
1580 }
1581 }
1582
1583 /* copy out data */
1584 transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1585 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1586 tapeReadBufferPtr += transferBytes;
1587 buffer += transferBytes;
1588 nbytes -= transferBytes;
1589 requestedBytes -= transferBytes;
1590 }
1591
1592 error_exit:
1593 return (code);
1594}