2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
13 #include <afs/procmgmt.h>
16 #ifdef IGNORE_SOME_GCC_WARNINGS
17 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
22 #include <afs/afsint.h>
23 #include <afs/prs_fs.h>
27 #include <afs/cellconfig.h>
31 #include <afs/volser.h>
32 #include <afs/vlserver.h>
33 #include <afs/tcdata.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>
42 #include "butc_internal.h"
43 #include "error_macros.h"
45 /* GLOBAL CONFIGURATION PARAMETERS */
46 #define BIGCHUNK 102400
48 extern int dump_namecheck
;
57 static void initTapeBuffering(void);
58 static int writeDbDump(struct butm_tapeInfo
*, afs_uint32
, Date
, afs_uint32
);
59 static int restoreDbEntries(struct butm_tapeInfo
*, struct rstTapeInfo
*);
61 int getTapeData(struct butm_tapeInfo
*, struct rstTapeInfo
*, void *,
63 int restoreDbHeader(struct butm_tapeInfo
*, struct rstTapeInfo
*,
64 struct structDumpHeader
*);
65 int restoreDbDump(struct butm_tapeInfo
*, struct rstTapeInfo
*,
66 struct structDumpHeader
*);
67 int restoreText(struct butm_tapeInfo
*, struct rstTapeInfo
*,
68 struct structDumpHeader
*);
72 void * KeepAlive(void *);
74 * create a dump entry for a saved database
78 CreateDBDump(struct budb_dumpEntry
*dumpEntryPtr
)
82 memset(dumpEntryPtr
, 0, sizeof(struct budb_dumpEntry
));
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;
98 /* now call the database to create the entry */
99 code
= bcdb_CreateDump(dumpEntryPtr
);
103 struct tapeEntryList
{
104 struct tapeEntryList
*next
;
105 afs_uint32 oldDumpId
;
106 struct budb_tapeEntry tapeEnt
;
108 struct tapeEntryList
*listEntryHead
;
109 struct tapeEntryList
*listEntryPtr
;
110 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
111 struct budb_dumpEntry lastDump
; /* the last dump of this volset */
114 * Load a DB tape, read and over write its label.
115 * Leave the tape mounted.
118 GetDBTape(afs_int32 taskId
, Date expires
, struct butm_tapeInfo
*tapeInfoPtr
,
119 afs_uint32 dumpid
, afs_int32 sequence
, int queryFlag
,
124 char tapeName
[BU_MAXTAPELEN
];
130 struct butm_tapeLabel oldTapeLabel
, newLabel
;
131 struct tapeEntryList
*endList
;
133 /* construct the name of the tape */
134 sprintf(tapeName
, "%s.%-d", DUMP_TAPE_NAME
, sequence
);
136 interactiveFlag
= queryFlag
;
139 while (!*wroteLabel
) { /*w */
140 if (interactiveFlag
) { /* need a tape to write */
142 PromptForTape(SAVEDBOPCODE
, tapeName
, dumpid
, taskId
,
150 code
= butm_Mount(tapeInfoPtr
, tapeName
);
152 TapeLog(0, taskId
, code
, tapeInfoPtr
->error
, "Can't open tape\n");
156 memset(&oldTapeLabel
, 0, sizeof(oldTapeLabel
));
157 code
= butm_ReadLabel(tapeInfoPtr
, &oldTapeLabel
, 1); /* rewind tape */
159 oldTapeLabel
.useCount
= 0; /* no label exists */
160 oldTapeLabel
.structVersion
= 0;
161 strcpy(oldTapeLabel
.pName
, "");
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];
168 LABELNAME(gotName
, &oldTapeLabel
);
170 "This tape %s must be a database tape or NULL tape\n",
174 unmountTape(taskId
, tapeInfoPtr
);
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");
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).
191 struct budb_dumpEntry de
, de2
;
193 /* Verify the tape has not expired
194 * Early database dumps don't have a dumpid
196 if (!tapeExpired(&oldTapeLabel
)) {
197 TLog(taskId
, "This tape has not expired\n");
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.
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
));
209 code
= bcdb_FindDumpByID(dmp
, &de
);
212 sprintf(strlevel
, "%d", de
.level
);
214 bcdb_FindLatestDump(de
.volumeSetName
, strlevel
,
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",
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
);
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).
239 /* Check the tape's expiration date. Use the expiration on the label */
240 gettimeofday(&tp
, NULL
);
242 if (curTime
< oldTapeLabel
.expirationDate
) {
243 TLog(taskId
, "This tape has not expired\n");
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
);
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
;
264 code
= butm_Create(tapeInfoPtr
, &newLabel
, 1); /* rewind tape */
266 TapeLog(0, taskId
, code
, tapeInfoPtr
->error
,
267 "Can't label tape\n");
273 /* Initialize a tapeEntry for later inclusion into the database */
274 listEntryPtr
= calloc(1, sizeof(struct tapeEntryList
));
276 ERROR_EXIT(TC_NOMEMORY
);
278 /* Remember dumpid so we can delete it later */
279 if ((oldTapeLabel
.structVersion
>= TAPE_VERSION_3
)
280 && oldTapeLabel
.dumpid
)
281 listEntryPtr
->oldDumpId
= oldTapeLabel
.dumpid
;
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;
294 /* Thread onto end of single-linked list */
296 endList
= listEntryHead
;
297 while (endList
->next
)
298 endList
= endList
->next
;
299 endList
->next
= listEntryPtr
;
301 listEntryHead
= listEntryPtr
;
309 * With the list of tapes, free the structures.
315 struct tapeEntryList
*next
;
317 listEntryPtr
= listEntryHead
;
318 while (listEntryPtr
) {
319 next
= listEntryPtr
->next
;
324 listEntryHead
= NULL
;
329 * With the list of tapes, add them to the database.
330 * Also delete any olddumpids that are around.
334 addTapesToDb(afs_int32 taskId
)
338 struct tapeEntryList
*next
;
340 listEntryPtr
= listEntryHead
;
341 while (listEntryPtr
) {
342 next
= listEntryPtr
->next
;
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
);
354 /* Add the tape to the database */
355 code
= bcdb_UseTape(tapeEntryPtr
, &new);
357 ErrorLog(0, taskId
, code
, 0, "Can't add tape to database: %s\n",
362 code
= bcdb_FinishTape(tapeEntryPtr
);
364 ErrorLog(0, taskId
, code
, 0, "Can't finish tape: %s\n",
378 * this code assumes that the blocksize on reads is smaller than
379 * the blocksize on writes
383 writeDbDump(struct butm_tapeInfo
*tapeInfoPtr
, afs_uint32 taskId
,
384 Date expires
, afs_uint32 dumpid
)
387 afs_int32 writeBufNbytes
= 0;
388 char *writeBlock
= 0;
389 char *writeBuffer
= 0;
391 afs_int32 transferSize
;
393 char *readBufPtr
= NULL
;
394 afs_int32 maxReadSize
;
399 afs_int32 chunksize
= 0;
400 afs_int32 tc_EndMargin
, tc_KEndMargin
, kRemaining
;
404 #ifdef AFS_PTHREAD_ENV
406 pthread_attr_t tattr
;
412 extern struct tapeConfig globalTapeConfig
;
413 extern struct udbHandleS udbHandle
;
415 charList
.charListT_val
= 0;
416 charList
.charListT_len
= 0;
417 blockSize
= BUTM_BLKSIZE
;
418 writeBlock
= malloc(BUTM_BLOCKSIZE
);
420 ERROR_EXIT(TC_NOMEMORY
);
422 writeBuffer
= writeBlock
+ sizeof(struct blockMark
);
423 memset(writeBuffer
, 0, BUTM_BLKSIZE
);
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 +
433 tc_EndMargin
= (16384 + 3 * globalTapeConfig
.fileMarkSize
) * 2;
434 tc_KEndMargin
= tc_EndMargin
/ 1024;
436 /* have to write enclose the dump in file marks */
437 code
= butm_WriteFileBegin(tapeInfoPtr
);
439 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
440 "Can't write FileBegin on tape\n");
444 writeBufPtr
= &writeBuffer
[0];
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;
459 ubik_Call_SingleServer(BUDB_DumpDB
, udbHandle
.uh_client
,
460 UF_SINGLESERVER
, firstcall
,
461 maxReadSize
, &charList
, &done
);
463 ErrorLog(0, taskId
, code
, 0, "Can't read database\n");
467 /* If this if the first call to the budb server, create a thread
468 * that will keep the connection alive (during tape changes).
471 #ifdef AFS_PTHREAD_ENV
472 code
= pthread_attr_init(&tattr
);
474 ErrorLog(0, taskId
, code
, 0,
475 "Can't pthread_attr_init Keep-alive process\n");
480 pthread_attr_setdetachstate(&tattr
,
481 PTHREAD_CREATE_DETACHED
);
483 ErrorLog(0, taskId
, code
, 0,
484 "Can't pthread_attr_setdetachstate Keep-alive process\n");
489 code
= pthread_create(&alivePid
, &tattr
, KeepAlive
, 0);
490 AFS_SIGSET_RESTORE();
493 LWP_CreateProcess(KeepAlive
, 16384, 1, NULL
,
494 "Keep-alive process", &alivePid
);
497 ErrorLog(0, taskId
, code
, 0,
498 "Failed to create keep alive process\n");
504 readBufPtr
= charList
.charListT_val
;
507 if ((charList
.charListT_len
== 0) && done
)
510 /* compute how many bytes and transfer to the write Buffer */
512 (charList
.charListT_len
<
514 writeBufNbytes
)) ? charList
.charListT_len
: (blockSize
-
517 memcpy(writeBufPtr
, readBufPtr
, transferSize
);
518 charList
.charListT_len
-= transferSize
;
519 writeBufPtr
+= transferSize
;
520 readBufPtr
+= transferSize
;
521 writeBufNbytes
+= transferSize
;
523 /* If filled the write buffer, then write it to tape */
524 if (writeBufNbytes
== blockSize
) {
525 code
= butm_WriteFileData(tapeInfoPtr
, writeBuffer
, 1, blockSize
);
527 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
528 "Can't write data on tape\n");
532 memset(writeBuffer
, 0, blockSize
);
533 writeBufPtr
= &writeBuffer
[0];
536 /* Every BIGCHUNK bytes check if aborted */
537 chunksize
+= blockSize
;
538 if (chunksize
> BIGCHUNK
) {
540 if (checkAbortByTaskId(taskId
))
541 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
545 * check if tape is full - since we filled a blockSize worth of data
546 * assume that there is more data.
548 kRemaining
= butm_remainingKSpace(tapeInfoPtr
);
549 if (kRemaining
< tc_KEndMargin
) {
550 code
= butm_WriteFileEnd(tapeInfoPtr
);
552 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
553 "Can't write FileEnd on tape\n");
557 code
= butm_WriteEOT(tapeInfoPtr
);
559 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
560 "Can't write end-of-dump on tape\n");
564 /* Mark tape as having been written */
565 tapeEntryPtr
->useKBytes
=
566 tapeInfoPtr
->kBytes
+ (tapeInfoPtr
->nBytes
? 1 : 0);
567 tapeEntryPtr
->flags
= BUDB_TAPE_WRITTEN
;
569 unmountTape(taskId
, tapeInfoPtr
);
571 /* Get next tape and writes its label */
574 GetDBTape(taskId
, expires
, tapeInfoPtr
, dumpid
, sequence
,
579 code
= butm_WriteFileBegin(tapeInfoPtr
);
581 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
582 "Can't write FileBegin on tape\n");
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
);
593 ErrorLog(1, taskId
, code
, tapeInfoPtr
->error
,
594 "Can't write data on tape\n");
599 code
= butm_WriteFileEnd(tapeInfoPtr
);
601 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
602 "Can't write FileEnd on tape\n");
606 /* Mark tape as having been written */
607 tapeEntryPtr
->useKBytes
=
608 tapeInfoPtr
->kBytes
+ (tapeInfoPtr
->nBytes
? 1 : 0);
609 tapeEntryPtr
->flags
= BUDB_TAPE_WRITTEN
;
612 /* Let the KeepAlive process stop on its own */
614 ubik_Call_SingleServer(BUDB_DumpDB
, udbHandle
.uh_client
,
615 UF_END_SINGLESERVER
, 0);
619 if (charList
.charListT_val
)
620 free(charList
.charListT_val
);
625 * dump backup database to tape
629 saveDbToTape(void *param
)
631 struct saveDbIf
*saveDbIfPtr
= (struct saveDbIf
*)param
;
638 struct butm_tapeInfo tapeInfo
;
639 struct budb_dumpEntry dumpEntry
;
641 extern struct deviceSyncNode
*deviceLatch
;
642 extern struct tapeConfig globalTapeConfig
;
644 afs_pthread_setname_self("Db save");
645 expires
= (saveDbIfPtr
->archiveTime
? NEVERDATE
: 0);
646 taskId
= saveDbIfPtr
->taskId
;
649 setStatus(taskId
, DRIVE_WAIT
);
650 EnterDeviceQueue(deviceLatch
); /* lock tape device */
651 clearStatus(taskId
, DRIVE_WAIT
);
654 TLog(taskId
, "SaveDb\n");
656 tapeInfo
.structVersion
= BUTM_MAJORVERSION
;
657 code
= butm_file_Instantiate(&tapeInfo
, &globalTapeConfig
);
659 ErrorLog(0, taskId
, code
, tapeInfo
.error
,
660 "Can't initialize tape module\n");
664 /* Determine what the last database dump was */
665 memset(&lastDump
, 0, sizeof(lastDump
));
666 code
= bcdb_FindLatestDump("", "", &lastDump
);
668 if (code
!= BUDB_NODUMPNAME
) {
669 ErrorLog(0, taskId
, code
, 0, "Can't read backup database\n");
672 memset(&lastDump
, 0, sizeof(lastDump
));
675 code
= CreateDBDump(&dumpEntry
); /* Create a dump for this tape */
677 ErrorLog(0, taskId
, code
, 0, "Can't create dump in database\n");
682 listEntryHead
= NULL
;
684 /* Get the tape and write a new label to it */
686 GetDBTape(taskId
, expires
, &tapeInfo
, dumpEntry
.id
, 1, autoQuery
,
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.
694 i
= bcdb_deleteDump(dumpEntry
.id
, 0, 0, 0);
696 if (i
&& (i
!= BUDB_NOENT
))
697 ErrorLog(0, taskId
, i
, 0, "Unable to delete DB entry %u.\n",
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
);
711 TapeLog(1, taskId
, 0, 0, "Tape accepted - now dumping database\n");
713 /* we have a writable tape */
714 code
= writeDbDump(&tapeInfo
, taskId
, expires
, dumpEntry
.id
);
718 /* Now delete the entries between time 0 and archive-time */
719 if (saveDbIfPtr
->archiveTime
)
720 code
= bcdb_deleteDump(0, 0, saveDbIfPtr
->archiveTime
, 0);
723 unmountTape(taskId
, &tapeInfo
);
725 /* Add this dump's tapes to the database and mark it finished */
727 i
= addTapesToDb(taskId
);
731 i
= bcdb_FinishDump(&dumpEntry
);
737 if (code
== TC_ABORTEDBYREQUEST
) {
738 TLog(taskId
, "SaveDb: Aborted by request\n");
739 clearStatus(taskId
, ABORT_REQUEST
);
740 setStatus(taskId
, ABORT_DONE
);
742 TapeLog(0, taskId
, code
, 0, "SaveDb: Finished with errors\n");
743 setStatus(taskId
, TASK_ERROR
);
745 TLog(taskId
, "SaveDb: Finished\n");
747 setStatus(taskId
, TASK_DONE
);
750 LeaveDeviceQueue(deviceLatch
);
751 return (void *)(intptr_t)(code
);
756 * Make a database dump entry given a tape label.
760 makeDbDumpEntry(struct budb_tapeEntry
*tapeEntPtr
,
761 struct budb_dumpEntry
*dumpEntryPtr
)
763 memset(dumpEntryPtr
, 0, sizeof(struct budb_dumpEntry
));
765 dumpEntryPtr
->id
= tapeEntPtr
->dump
;
766 dumpEntryPtr
->initialDumpID
= 0;
767 dumpEntryPtr
->parent
= 0;
768 dumpEntryPtr
->level
= 0;
769 dumpEntryPtr
->flags
= 0;
771 strcpy(dumpEntryPtr
->volumeSetName
, "");
772 strcpy(dumpEntryPtr
->dumpPath
, "");
773 strcpy(dumpEntryPtr
->name
, DUMP_TAPE_NAME
);
775 dumpEntryPtr
->created
= tapeEntPtr
->dump
;
776 dumpEntryPtr
->incTime
= 0;
777 dumpEntryPtr
->nVolumes
= 0;
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;
787 * prompt for a specific database tape
791 readDbTape(struct butm_tapeInfo
*tapeInfoPtr
,
792 struct rstTapeInfo
*rstTapeInfoPtr
, int query
)
797 struct butm_tapeLabel oldTapeLabel
;
798 char AFStapeName
[BU_MAXTAPELEN
], tapeName
[BU_MAXTAPELEN
];
799 struct tapeEntryList
*endList
;
801 struct budb_dumpEntry de
;
802 struct budb_tapeEntry te
;
804 taskId
= rstTapeInfoPtr
->taskId
;
805 interactiveFlag
= query
;
807 /* construct the name of the tape */
808 sprintf(AFStapeName
, "%s.%-d", DUMP_TAPE_NAME
, rstTapeInfoPtr
->tapeSeq
);
809 strcpy(tapeName
, AFStapeName
);
811 /* Will prompt for the latest saved database tape, but will accept any one */
812 if (rstTapeInfoPtr
->tapeSeq
== 1) {
813 code
= bcdb_FindLatestDump("", "", &de
);
815 rstTapeInfoPtr
->dumpid
= de
.id
;
817 if (rstTapeInfoPtr
->dumpid
) {
819 bcdb_FindTapeSeq(rstTapeInfoPtr
->dumpid
, rstTapeInfoPtr
->tapeSeq
,
822 strcpy(tapeName
, te
.name
);
826 if (interactiveFlag
) { /* need a tape to read */
828 PromptForTape(RESTOREDBOPCODE
, tapeName
,
829 rstTapeInfoPtr
->dumpid
, taskId
, tapecount
);
836 code
= butm_Mount(tapeInfoPtr
, tapeName
);
838 TapeLog(0, taskId
, code
, tapeInfoPtr
->error
, "Can't open tape\n");
842 code
= butm_ReadLabel(tapeInfoPtr
, &oldTapeLabel
, 1); /* will rewind the tape */
844 TapeLog(0, taskId
, code
, tapeInfoPtr
->error
,
845 "Can't read tape label\n");
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];
856 TAPENAME(expTape
, tapeName
, rstTapeInfoPtr
->dumpid
);
857 TAPENAME(gotTape
, oldTapeLabel
.AFSName
, oldTapeLabel
.dumpid
);
859 TLog(taskId
, "Tape label expected %s, label seen %s\n", expTape
,
864 if (rstTapeInfoPtr
->tapeSeq
== 1) /* Remember this dumpId */
865 rstTapeInfoPtr
->dumpid
= oldTapeLabel
.dumpid
;
870 unmountTape(taskId
, tapeInfoPtr
);
874 /* Initialize a tapeEntry for later inclusion into the database */
875 listEntryPtr
= calloc(1, sizeof(struct tapeEntryList
));
877 ERROR_EXIT(TC_NOMEMORY
);
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;
890 /* Thread onto end of single-linked list */
892 endList
= listEntryHead
;
893 while (endList
->next
)
894 endList
= endList
->next
;
895 endList
->next
= listEntryPtr
;
897 listEntryHead
= listEntryPtr
;
903 static afs_int32 nbytes
= 0; /* # bytes left in buffer */
905 initTapeBuffering(void)
912 * restore all the items on the tape
914 * tape positioned after tape label
918 restoreDbEntries(struct butm_tapeInfo
*tapeInfoPtr
,
919 struct rstTapeInfo
*rstTapeInfoPtr
)
921 struct structDumpHeader netItemHeader
, hostItemHeader
;
923 afs_int32 taskId
, code
= 0;
926 taskId
= rstTapeInfoPtr
->taskId
;
928 /* clear state for the buffer routine(s) */
931 code
= butm_ReadFileBegin(tapeInfoPtr
);
933 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
934 "Can't read FileBegin on tape\n");
938 /* get the first item-header */
939 memset(&netItemHeader
, 0, sizeof(netItemHeader
));
941 getTapeData(tapeInfoPtr
, rstTapeInfoPtr
, &netItemHeader
,
942 sizeof(netItemHeader
));
945 structDumpHeader_ntoh(&netItemHeader
, &hostItemHeader
);
948 switch (hostItemHeader
.type
) {
951 restoreDbHeader(tapeInfoPtr
, rstTapeInfoPtr
, &hostItemHeader
);
957 if (++count
> 25) { /*every 25 dumps, wait */
962 restoreDbDump(tapeInfoPtr
, rstTapeInfoPtr
, &hostItemHeader
);
972 case SD_TEXT_DUMPSCHEDULE
:
973 case SD_TEXT_VOLUMESET
:
974 case SD_TEXT_TAPEHOSTS
:
975 code
= restoreText(tapeInfoPtr
, rstTapeInfoPtr
, &hostItemHeader
);
985 TLog(taskId
, "Unknown database header type %d\n",
986 hostItemHeader
.type
);
992 code
= butm_ReadFileEnd(tapeInfoPtr
);
994 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
995 "Can't read EOF on tape\n");
999 /* Mark tape as having been written */
1000 tapeEntryPtr
->useKBytes
=
1001 tapeInfoPtr
->kBytes
+ (tapeInfoPtr
->nBytes
? 1 : 0);
1002 tapeEntryPtr
->flags
= BUDB_TAPE_WRITTEN
;
1008 /* restoreDbFromTape
1009 * restore the backup database from tape.
1013 restoreDbFromTape(void *param
)
1015 afs_uint32 taskId
= (intptr_t) param
;
1018 struct butm_tapeInfo tapeInfo
;
1019 struct rstTapeInfo rstTapeInfo
;
1020 struct budb_dumpEntry dumpEntry
;
1022 extern struct tapeConfig globalTapeConfig
;
1023 extern struct deviceSyncNode
*deviceLatch
;
1025 afs_pthread_setname_self("Db restore");
1026 setStatus(taskId
, DRIVE_WAIT
);
1027 EnterDeviceQueue(deviceLatch
); /* lock tape device */
1028 clearStatus(taskId
, DRIVE_WAIT
);
1031 TLog(taskId
, "RestoreDb\n");
1033 tapeInfo
.structVersion
= BUTM_MAJORVERSION
;
1034 code
= butm_file_Instantiate(&tapeInfo
, &globalTapeConfig
);
1036 ErrorLog(0, taskId
, code
, tapeInfo
.error
,
1037 "Can't initialize tape module\n");
1041 listEntryHead
= NULL
;
1043 rstTapeInfo
.taskId
= taskId
;
1044 rstTapeInfo
.tapeSeq
= 1;
1045 rstTapeInfo
.dumpid
= 0;
1047 code
= readDbTape(&tapeInfo
, &rstTapeInfo
, autoQuery
);
1051 code
= restoreDbEntries(&tapeInfo
, &rstTapeInfo
);
1056 /* Now put this dump into the database */
1057 /* Make a dump entry from first tape */
1058 listEntryPtr
= listEntryHead
;
1060 makeDbDumpEntry(tapeEntryPtr
, &dumpEntry
);
1061 if (dumpEntry
.id
!= 0) {
1062 i
= bcdb_CreateDump(&dumpEntry
);
1064 if (i
== BUDB_DUMPIDEXISTS
)
1066 "Dump id %d not added to database - already exists\n",
1069 TapeLog(0, taskId
, i
, 0,
1070 "Dump id %d not added to database\n",
1073 i
= addTapesToDb(taskId
);
1077 i
= bcdb_FinishDump(&dumpEntry
);
1085 unmountTape(taskId
, &tapeInfo
);
1088 if (code
== TC_ABORTEDBYREQUEST
) {
1089 TLog(taskId
, "RestoreDb: Aborted by request\n");
1090 clearStatus(taskId
, ABORT_REQUEST
);
1091 setStatus(taskId
, ABORT_DONE
);
1093 TapeLog(0, taskId
, code
, 0, "RestoreDb: Finished with errors\n");
1094 setStatus(taskId
, TASK_ERROR
);
1096 TLog(taskId
, "RestoreDb: Finished\n");
1099 LeaveDeviceQueue(deviceLatch
);
1100 setStatus(taskId
, TASK_DONE
);
1102 return (void *)(intptr_t)(code
);
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).
1112 * Use the same udbHandle as writeDbDump so we go to the same server.
1115 KeepAlive(void *unused
)
1121 extern struct udbHandleS udbHandle
;
1123 afs_pthread_setname_self("Keep-alive");
1125 #ifdef AFS_PTHREAD_ENV
1130 charList
.charListT_val
= 0;
1131 charList
.charListT_len
= 0;
1133 ubik_Call_SingleServer(BUDB_DumpDB
, udbHandle
.uh_client
,
1134 UF_SINGLESERVER
, 0, 0, &charList
, &done
);
1143 * restore special items in the header
1147 restoreDbHeader(struct butm_tapeInfo
*tapeInfo
,
1148 struct rstTapeInfo
*rstTapeInfoPtr
,
1149 struct structDumpHeader
*nextHeader
)
1151 struct structDumpHeader netItemHeader
;
1152 struct DbHeader netDbHeader
, hostDbHeader
;
1155 extern struct udbHandleS udbHandle
;
1157 /* Read the database header */
1158 memset(&netDbHeader
, 0, sizeof(netDbHeader
));
1160 getTapeData(tapeInfo
, rstTapeInfoPtr
, &netDbHeader
,
1161 sizeof(netDbHeader
));
1164 DbHeader_ntoh(&netDbHeader
, &hostDbHeader
);
1166 /* Add the database header to the database */
1168 ubik_BUDB_RestoreDbHeader(udbHandle
.uh_client
, 0,
1171 ErrorLog(0, rstTapeInfoPtr
->taskId
, code
, 0,
1172 "Can't restore DB Header\n");
1176 /* get the next item-header */
1177 memset(nextHeader
, 0, sizeof(*nextHeader
));
1179 getTapeData(tapeInfo
, rstTapeInfoPtr
, &netItemHeader
,
1180 sizeof(netItemHeader
));
1183 structDumpHeader_ntoh(&netItemHeader
, nextHeader
);
1191 * restore a single dump, including all its tapes and volumes, from
1194 * nextHeader - ptr to structure for return value
1196 * nextHeader - next structure header from tape
1198 * upon entry, the dump structure header has been read confirming that
1199 * a database dump tree exists on the tape
1203 restoreDbDump(struct butm_tapeInfo
*tapeInfo
,
1204 struct rstTapeInfo
*rstTapeInfoPtr
,
1205 struct structDumpHeader
*nextHeader
)
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;
1214 extern struct udbHandleS udbHandle
;
1216 /* read dump entry */
1217 memset(&netDumpEntry
, 0, sizeof(netDumpEntry
));
1219 getTapeData(tapeInfo
, rstTapeInfoPtr
, &netDumpEntry
,
1220 sizeof(netDumpEntry
));
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;
1230 dumpEntry_ntoh(&netDumpEntry
, &hostDumpEntry
);
1232 /* The dump entry for this database tape is incomplete, so don't include it */
1233 if (hostDumpEntry
.id
== rstTapeInfoPtr
->dumpid
)
1234 restoreThisDump
= 0;
1236 /* add the dump to the database */
1237 if (restoreThisDump
) {
1239 threadEntryDir(&hostDumpEntry
, sizeof(hostDumpEntry
),
1245 /* get the next item-header */
1246 memset(nextHeader
, 0, sizeof(*nextHeader
));
1248 getTapeData(tapeInfo
, rstTapeInfoPtr
, &netItemHeader
,
1249 sizeof(netItemHeader
));
1252 structDumpHeader_ntoh(&netItemHeader
, nextHeader
);
1254 /* Add every tape to the db */
1255 while (nextHeader
->type
== SD_TAPE
) { /*t */
1257 /* read the tape entry */
1258 memset(&netTapeEntry
, 0, sizeof(netTapeEntry
));
1260 getTapeData(tapeInfo
, rstTapeInfoPtr
, &netTapeEntry
,
1261 sizeof(netTapeEntry
));
1264 tapeEntry_ntoh(&netTapeEntry
, &hostTapeEntry
);
1266 /* Add the tape to the database */
1267 if (restoreThisDump
) {
1269 threadEntryDir(&hostTapeEntry
, sizeof(hostTapeEntry
),
1275 /* get the next item-header */
1276 memset(nextHeader
, 0, sizeof(*nextHeader
));
1278 getTapeData(tapeInfo
, rstTapeInfoPtr
, &netItemHeader
,
1279 sizeof(netItemHeader
));
1282 structDumpHeader_ntoh(&netItemHeader
, nextHeader
);
1284 /* Add every volume to the db */
1285 while (nextHeader
->type
== SD_VOLUME
) { /*v */
1287 /* read the volume entry */
1288 memset(&netVolumeEntry
, 0, sizeof(netVolumeEntry
));
1290 getTapeData(tapeInfo
, rstTapeInfoPtr
, &netVolumeEntry
,
1291 sizeof(netVolumeEntry
));
1294 volumeEntry_ntoh(&netVolumeEntry
, &hostVolumeEntry
);
1296 if (restoreThisDump
) {
1298 threadEntryDir(&hostVolumeEntry
, sizeof(hostVolumeEntry
),
1304 /* get the next item-header */
1305 memset(nextHeader
, 0, sizeof(*nextHeader
));
1307 getTapeData(tapeInfo
, rstTapeInfoPtr
, &netItemHeader
,
1308 sizeof(netItemHeader
));
1311 structDumpHeader_ntoh(&netItemHeader
, nextHeader
);
1314 /* Finish the tape */
1315 if (restoreThisDump
) {
1317 threadEntryDir(&hostTapeEntry
, sizeof(hostTapeEntry
),
1324 /* Finish the dump */
1325 if (restoreThisDump
) {
1327 threadEntryDir(&hostDumpEntry
, sizeof(hostDumpEntry
),
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.
1344 saveTextFile(afs_int32 taskId
, afs_int32 textType
, char *fileName
)
1346 udbClientTextP ctPtr
= 0;
1350 ctPtr
= calloc(1, sizeof(*ctPtr
));
1352 ERROR_EXIT(TC_NOMEMORY
);
1354 ctPtr
->textType
= textType
;
1356 /* lock the text in the database */
1357 code
= bc_LockText(ctPtr
);
1359 ErrorLog(0, taskId
, code
, 0, "Can't lock text file\n");
1364 ctPtr
->textStream
= fopen(fileName
, "r");
1365 if (!ctPtr
->textStream
) {
1366 ErrorLog(0, taskId
, errno
, 0, "Can't open text file\n");
1370 /* now send the text to the database */
1371 code
= bcdb_SaveTextFile(ctPtr
);
1373 ErrorLog(0, taskId
, code
, 0, "Can't save text file\n");
1379 if (ctPtr
->textStream
)
1380 fclose(ctPtr
->textStream
);
1382 bc_UnlockText(ctPtr
);
1389 * read the text off the tape, and store it in the appropriate
1390 * text type in the database.
1392 * nextHeader - ptr to struct for return information
1394 * nextHeader - struct header for next item on the tape
1398 restoreText(struct butm_tapeInfo
*tapeInfo
,
1399 struct rstTapeInfo
*rstTapeInfoPtr
,
1400 struct structDumpHeader
*nextHeader
)
1404 char *readBuffer
= 0;
1405 afs_int32 readBlockSize
;
1406 afs_int32 transferSize
;
1407 struct structDumpHeader netItemHeader
;
1411 udbClientTextP ctPtr
= 0;
1414 ctPtr
= malloc(sizeof(*ctPtr
));
1416 ERROR_EXIT(TC_NOMEMORY
);
1418 /* determine the type of text block */
1419 switch (nextHeader
->type
) {
1420 case SD_TEXT_DUMPSCHEDULE
:
1421 textType
= TB_DUMPSCHEDULE
;
1424 case SD_TEXT_VOLUMESET
:
1425 textType
= TB_VOLUMESET
;
1428 case SD_TEXT_TAPEHOSTS
:
1429 textType
= TB_TAPEHOSTS
;
1433 ErrorLog(0, rstTapeInfoPtr
->taskId
, TC_INTERNALERROR
, 0,
1434 "Unknown text block\n");
1435 ERROR_EXIT(TC_INTERNALERROR
);
1439 /* open the text file */
1440 sprintf(filename
, "%s/bu_XXXXXX", gettmpdir());
1441 fid
= mkstemp(filename
);
1443 ErrorLog(0, rstTapeInfoPtr
->taskId
, errno
, 0,
1444 "Can't open temporary text file: %s\n", filename
);
1448 /* allocate buffer for text */
1449 readBlockSize
= BUTM_BLKSIZE
;
1450 readBuffer
= malloc(readBlockSize
);
1452 ERROR_EXIT(TC_NOMEMORY
);
1454 /* read the text into the temporary file */
1455 nbytes
= nextHeader
->size
;
1456 while (nbytes
> 0) {
1457 transferSize
= (readBlockSize
< nbytes
) ? readBlockSize
: nbytes
;
1459 /* read it from the tape */
1461 getTapeData(tapeInfo
, rstTapeInfoPtr
, readBuffer
, transferSize
);
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
);
1472 nbytes
-= transferSize
;
1477 code
= saveTextFile(rstTapeInfoPtr
->taskId
, textType
, filename
);
1482 /* get the next item-header */
1483 memset(nextHeader
, 0, sizeof(*nextHeader
));
1485 getTapeData(tapeInfo
, rstTapeInfoPtr
, &netItemHeader
,
1486 sizeof(netItemHeader
));
1489 structDumpHeader_ntoh(&netItemHeader
, nextHeader
);
1504 /* ----------------------------------
1505 * Tape data buffering - for reading database dumps
1506 * ----------------------------------
1509 static char *tapeReadBuffer
= 0; /* input buffer */
1510 static char *tapeReadBufferPtr
= 0; /* position in buffer */
1513 * Read information from tape, and place the requested number of bytes
1514 * in the buffer supplied
1517 * rstTapeInfoPtr - Info about the dump being restored.
1518 * buffer - buffer for requested data
1519 * requestedBytes - no. of bytes requested
1521 * fn retn - 0, ok, n, error
1525 getTapeData(struct butm_tapeInfo
*tapeInfoPtr
,
1526 struct rstTapeInfo
*rstTapeInfoPtr
,
1527 void *out
, afs_int32 requestedBytes
)
1529 char *buffer
= (char *) out
;
1530 afs_int32 taskId
, transferBytes
;
1533 taskId
= rstTapeInfoPtr
->taskId
;
1535 if (checkAbortByTaskId(taskId
))
1536 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
1538 if (!tapeReadBuffer
) {
1539 tapeReadBuffer
= malloc(BUTM_BLOCKSIZE
);
1540 if (!tapeReadBuffer
)
1541 ERROR_EXIT(TC_NOMEMORY
);
1544 while (requestedBytes
> 0) {
1546 tapeReadBufferPtr
= &tapeReadBuffer
[sizeof(struct blockMark
)];
1550 butm_ReadFileData(tapeInfoPtr
, tapeReadBufferPtr
,
1551 BUTM_BLKSIZE
, &nbytes
);
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);
1560 unmountTape(taskId
, tapeInfoPtr
);
1562 rstTapeInfoPtr
->tapeSeq
++;
1563 code
= readDbTape(tapeInfoPtr
, rstTapeInfoPtr
, 1);
1567 code
= butm_ReadFileBegin(tapeInfoPtr
);
1569 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
1570 "Can't read FileBegin on tape\n");
1577 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
1578 "Can't read FileData on tape\n");
1584 transferBytes
= (nbytes
< requestedBytes
) ? nbytes
: requestedBytes
;
1585 memcpy(buffer
, tapeReadBufferPtr
, transferBytes
);
1586 tapeReadBufferPtr
+= transferBytes
;
1587 buffer
+= transferBytes
;
1588 nbytes
-= transferBytes
;
1589 requestedBytes
-= transferBytes
;