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);
496 /* XXX should we check code here ??? XXX */
500 readBufPtr = charList.charListT_val;
503 if ((charList.charListT_len == 0) && done)
506 /* compute how many bytes and transfer to the write Buffer */
508 (charList.charListT_len <
510 writeBufNbytes)) ? charList.charListT_len : (blockSize -
513 memcpy(writeBufPtr, readBufPtr, transferSize);
514 charList.charListT_len -= transferSize;
515 writeBufPtr += transferSize;
516 readBufPtr += transferSize;
517 writeBufNbytes += transferSize;
519 /* If filled the write buffer, then write it to tape */
520 if (writeBufNbytes == blockSize) {
521 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
523 ErrorLog(0, taskId, code, tapeInfoPtr->error,
524 "Can't write data on tape\n");
528 memset(writeBuffer, 0, blockSize);
529 writeBufPtr = &writeBuffer[0];
532 /* Every BIGCHUNK bytes check if aborted */
533 chunksize += blockSize;
534 if (chunksize > BIGCHUNK) {
536 if (checkAbortByTaskId(taskId))
537 ERROR_EXIT(TC_ABORTEDBYREQUEST);
541 * check if tape is full - since we filled a blockSize worth of data
542 * assume that there is more data.
544 kRemaining = butm_remainingKSpace(tapeInfoPtr);
545 if (kRemaining < tc_KEndMargin) {
546 code = butm_WriteFileEnd(tapeInfoPtr);
548 ErrorLog(0, taskId, code, tapeInfoPtr->error,
549 "Can't write FileEnd on tape\n");
553 code = butm_WriteEOT(tapeInfoPtr);
555 ErrorLog(0, taskId, code, tapeInfoPtr->error,
556 "Can't write end-of-dump on tape\n");
560 /* Mark tape as having been written */
561 tapeEntryPtr->useKBytes =
562 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
563 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
565 unmountTape(taskId, tapeInfoPtr);
567 /* Get next tape and writes its label */
570 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
575 code = butm_WriteFileBegin(tapeInfoPtr);
577 ErrorLog(0, taskId, code, tapeInfoPtr->error,
578 "Can't write FileBegin on tape\n");
585 /* no more data to be read - if necessary, flush out the last buffer */
586 if (writeBufNbytes > 0) {
587 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
589 ErrorLog(1, taskId, code, tapeInfoPtr->error,
590 "Can't write data on tape\n");
595 code = butm_WriteFileEnd(tapeInfoPtr);
597 ErrorLog(0, taskId, code, tapeInfoPtr->error,
598 "Can't write FileEnd on tape\n");
602 /* Mark tape as having been written */
603 tapeEntryPtr->useKBytes =
604 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
605 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
608 /* Let the KeepAlive process stop on its own */
610 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
611 UF_END_SINGLESERVER, 0);
615 if (charList.charListT_val)
616 free(charList.charListT_val);
621 * dump backup database to tape
625 saveDbToTape(void *param)
627 struct saveDbIf *saveDbIfPtr = (struct saveDbIf *)param;
634 struct butm_tapeInfo tapeInfo;
635 struct budb_dumpEntry dumpEntry;
637 extern struct deviceSyncNode *deviceLatch;
638 extern struct tapeConfig globalTapeConfig;
640 afs_pthread_setname_self("Db save");
641 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
642 taskId = saveDbIfPtr->taskId;
645 setStatus(taskId, DRIVE_WAIT);
646 EnterDeviceQueue(deviceLatch); /* lock tape device */
647 clearStatus(taskId, DRIVE_WAIT);
650 TLog(taskId, "SaveDb\n");
652 tapeInfo.structVersion = BUTM_MAJORVERSION;
653 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
655 ErrorLog(0, taskId, code, tapeInfo.error,
656 "Can't initialize tape module\n");
660 /* Determine what the last database dump was */
661 memset(&lastDump, 0, sizeof(lastDump));
662 code = bcdb_FindLatestDump("", "", &lastDump);
664 if (code != BUDB_NODUMPNAME) {
665 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
668 memset(&lastDump, 0, sizeof(lastDump));
671 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
673 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
678 listEntryHead = NULL;
680 /* Get the tape and write a new label to it */
682 GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
686 * If did not write the label, remove created dump
687 * Else if wrote the label, remove old dump from db so it's not saved.
690 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
692 if (i && (i != BUDB_NOENT))
693 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
695 } else if (listEntryHead->oldDumpId) {
696 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
697 listEntryHead->oldDumpId = 0;
698 if (i && (i != BUDB_NOENT)) {
699 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
700 listEntryHead->oldDumpId);
707 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
709 /* we have a writable tape */
710 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
714 /* Now delete the entries between time 0 and archive-time */
715 if (saveDbIfPtr->archiveTime)
716 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
719 unmountTape(taskId, &tapeInfo);
721 /* Add this dump's tapes to the database and mark it finished */
723 i = addTapesToDb(taskId);
727 i = bcdb_FinishDump(&dumpEntry);
733 if (code == TC_ABORTEDBYREQUEST) {
734 TLog(taskId, "SaveDb: Aborted by request\n");
735 clearStatus(taskId, ABORT_REQUEST);
736 setStatus(taskId, ABORT_DONE);
738 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
739 setStatus(taskId, TASK_ERROR);
741 TLog(taskId, "SaveDb: Finished\n");
743 setStatus(taskId, TASK_DONE);
746 LeaveDeviceQueue(deviceLatch);
747 return (void *)(intptr_t)(code);
752 * Make a database dump entry given a tape label.
756 makeDbDumpEntry(struct budb_tapeEntry *tapeEntPtr,
757 struct budb_dumpEntry *dumpEntryPtr)
759 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
761 dumpEntryPtr->id = tapeEntPtr->dump;
762 dumpEntryPtr->initialDumpID = 0;
763 dumpEntryPtr->parent = 0;
764 dumpEntryPtr->level = 0;
765 dumpEntryPtr->flags = 0;
767 strcpy(dumpEntryPtr->volumeSetName, "");
768 strcpy(dumpEntryPtr->dumpPath, "");
769 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
771 dumpEntryPtr->created = tapeEntPtr->dump;
772 dumpEntryPtr->incTime = 0;
773 dumpEntryPtr->nVolumes = 0;
775 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
776 strcat(dumpEntryPtr->tapes.format, ".%d");
777 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
778 dumpEntryPtr->tapes.maxTapes = 0;
783 * prompt for a specific database tape
787 readDbTape(struct butm_tapeInfo *tapeInfoPtr,
788 struct rstTapeInfo *rstTapeInfoPtr, int query)
793 struct butm_tapeLabel oldTapeLabel;
794 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
795 struct tapeEntryList *endList;
797 struct budb_dumpEntry de;
798 struct budb_tapeEntry te;
800 taskId = rstTapeInfoPtr->taskId;
801 interactiveFlag = query;
803 /* construct the name of the tape */
804 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
805 strcpy(tapeName, AFStapeName);
807 /* Will prompt for the latest saved database tape, but will accept any one */
808 if (rstTapeInfoPtr->tapeSeq == 1) {
809 code = bcdb_FindLatestDump("", "", &de);
811 rstTapeInfoPtr->dumpid = de.id;
813 if (rstTapeInfoPtr->dumpid) {
815 bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
818 strcpy(tapeName, te.name);
823 if (interactiveFlag) { /* need a tape to read */
825 PromptForTape(RESTOREDBOPCODE, tapeName,
826 rstTapeInfoPtr->dumpid, taskId, tapecount);
833 code = butm_Mount(tapeInfoPtr, tapeName);
835 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
839 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
841 TapeLog(0, taskId, code, tapeInfoPtr->error,
842 "Can't read tape label\n");
846 /* Check for name of tape and matching dump id (if applicable). */
847 if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
848 || ((rstTapeInfoPtr->tapeSeq != 1)
849 && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
850 char expTape[BU_MAXTAPELEN + 32];
851 char gotTape[BU_MAXTAPELEN + 32];
853 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
854 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
856 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
861 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
862 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
867 unmountTape(taskId, tapeInfoPtr);
871 /* Initialize a tapeEntry for later inclusion into the database */
872 listEntryPtr = calloc(1, sizeof(struct tapeEntryList));
874 ERROR_EXIT(TC_NOMEMORY);
876 /* Fill in tape entry so we can save it later */
877 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
878 tapeEntryPtr->dump = oldTapeLabel.dumpid;
879 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
880 tapeEntryPtr->written = oldTapeLabel.creationTime;
881 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
882 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
883 tapeEntryPtr->useCount = oldTapeLabel.useCount;
884 tapeEntryPtr->useKBytes = 0;
885 tapeEntryPtr->labelpos = 0;
887 /* Thread onto end of single-linked list */
889 endList = listEntryHead;
890 while (endList->next)
891 endList = endList->next;
892 endList->next = listEntryPtr;
894 listEntryHead = listEntryPtr;
900 static afs_int32 nbytes = 0; /* # bytes left in buffer */
902 initTapeBuffering(void)
909 * restore all the items on the tape
911 * tape positioned after tape label
915 restoreDbEntries(struct butm_tapeInfo *tapeInfoPtr,
916 struct rstTapeInfo *rstTapeInfoPtr)
918 struct structDumpHeader netItemHeader, hostItemHeader;
920 afs_int32 taskId, code = 0;
923 taskId = rstTapeInfoPtr->taskId;
925 /* clear state for the buffer routine(s) */
928 code = butm_ReadFileBegin(tapeInfoPtr);
930 ErrorLog(0, taskId, code, tapeInfoPtr->error,
931 "Can't read FileBegin on tape\n");
935 /* get the first item-header */
936 memset(&netItemHeader, 0, sizeof(netItemHeader));
938 getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
939 sizeof(netItemHeader));
942 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
945 switch (hostItemHeader.type) {
948 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
954 if (++count > 25) { /*every 25 dumps, wait */
959 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
969 case SD_TEXT_DUMPSCHEDULE:
970 case SD_TEXT_VOLUMESET:
971 case SD_TEXT_TAPEHOSTS:
972 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
982 TLog(taskId, "Unknown database header type %d\n",
983 hostItemHeader.type);
989 code = butm_ReadFileEnd(tapeInfoPtr);
991 ErrorLog(0, taskId, code, tapeInfoPtr->error,
992 "Can't read EOF on tape\n");
996 /* Mark tape as having been written */
997 tapeEntryPtr->useKBytes =
998 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
999 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1005 /* restoreDbFromTape
1006 * restore the backup database from tape.
1010 restoreDbFromTape(void *param)
1012 afs_uint32 taskId = (intptr_t) param;
1015 struct butm_tapeInfo tapeInfo;
1016 struct rstTapeInfo rstTapeInfo;
1017 struct budb_dumpEntry dumpEntry;
1019 extern struct tapeConfig globalTapeConfig;
1020 extern struct deviceSyncNode *deviceLatch;
1022 afs_pthread_setname_self("Db restore");
1023 setStatus(taskId, DRIVE_WAIT);
1024 EnterDeviceQueue(deviceLatch); /* lock tape device */
1025 clearStatus(taskId, DRIVE_WAIT);
1028 TLog(taskId, "RestoreDb\n");
1030 tapeInfo.structVersion = BUTM_MAJORVERSION;
1031 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1033 ErrorLog(0, taskId, code, tapeInfo.error,
1034 "Can't initialize tape module\n");
1038 listEntryHead = NULL;
1040 rstTapeInfo.taskId = taskId;
1041 rstTapeInfo.tapeSeq = 1;
1042 rstTapeInfo.dumpid = 0;
1044 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1048 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1053 /* Now put this dump into the database */
1054 /* Make a dump entry from first tape */
1055 listEntryPtr = listEntryHead;
1057 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1058 if (dumpEntry.id != 0) {
1059 i = bcdb_CreateDump(&dumpEntry);
1061 if (i == BUDB_DUMPIDEXISTS)
1063 "Dump id %d not added to database - already exists\n",
1066 TapeLog(0, taskId, i, 0,
1067 "Dump id %d not added to database\n",
1070 i = addTapesToDb(taskId);
1074 i = bcdb_FinishDump(&dumpEntry);
1082 unmountTape(taskId, &tapeInfo);
1085 if (code == TC_ABORTEDBYREQUEST) {
1086 TLog(taskId, "RestoreDb: Aborted by request\n");
1087 clearStatus(taskId, ABORT_REQUEST);
1088 setStatus(taskId, ABORT_DONE);
1090 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1091 setStatus(taskId, TASK_ERROR);
1093 TLog(taskId, "RestoreDb: Finished\n");
1096 LeaveDeviceQueue(deviceLatch);
1097 setStatus(taskId, TASK_DONE);
1099 return (void *)(intptr_t)(code);
1104 * While dumping the database, keeps the connection alive.
1105 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
1106 * This resets the database's internal timer so that it does not
1107 * prematuraly quit (on asking for new tapes and such).
1109 * Use the same udbHandle as writeDbDump so we go to the same server.
1112 KeepAlive(void *unused)
1118 extern struct udbHandleS udbHandle;
1120 afs_pthread_setname_self("Keep-alive");
1122 #ifdef AFS_PTHREAD_ENV
1127 charList.charListT_val = 0;
1128 charList.charListT_len = 0;
1130 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1131 UF_SINGLESERVER, 0, 0, &charList, &done);
1140 * restore special items in the header
1144 restoreDbHeader(struct butm_tapeInfo *tapeInfo,
1145 struct rstTapeInfo *rstTapeInfoPtr,
1146 struct structDumpHeader *nextHeader)
1148 struct structDumpHeader netItemHeader;
1149 struct DbHeader netDbHeader, hostDbHeader;
1152 extern struct udbHandleS udbHandle;
1154 /* Read the database header */
1155 memset(&netDbHeader, 0, sizeof(netDbHeader));
1157 getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1158 sizeof(netDbHeader));
1161 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1163 /* Add the database header to the database */
1165 ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1168 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1169 "Can't restore DB Header\n");
1173 /* get the next item-header */
1174 memset(nextHeader, 0, sizeof(*nextHeader));
1176 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1177 sizeof(netItemHeader));
1180 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1188 * restore a single dump, including all its tapes and volumes, from
1191 * nextHeader - ptr to structure for return value
1193 * nextHeader - next structure header from tape
1195 * upon entry, the dump structure header has been read confirming that
1196 * a database dump tree exists on the tape
1200 restoreDbDump(struct butm_tapeInfo *tapeInfo,
1201 struct rstTapeInfo *rstTapeInfoPtr,
1202 struct structDumpHeader *nextHeader)
1204 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1205 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1206 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1207 struct structDumpHeader netItemHeader;
1208 int restoreThisDump = 1;
1211 extern struct udbHandleS udbHandle;
1213 /* read dump entry */
1214 memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1216 getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry,
1217 sizeof(netDumpEntry));
1221 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1222 if (rstTapeInfoPtr->dumpid == 0) {
1223 netDumpEntry.initialDumpID = 0;
1224 netDumpEntry.appendedDumpID = 0;
1227 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1229 /* The dump entry for this database tape is incomplete, so don't include it */
1230 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1231 restoreThisDump = 0;
1233 /* add the dump to the database */
1234 if (restoreThisDump) {
1236 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1242 /* get the next item-header */
1243 memset(nextHeader, 0, sizeof(*nextHeader));
1245 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1246 sizeof(netItemHeader));
1249 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1251 /* Add every tape to the db */
1252 while (nextHeader->type == SD_TAPE) { /*t */
1254 /* read the tape entry */
1255 memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1257 getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry,
1258 sizeof(netTapeEntry));
1261 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1263 /* Add the tape to the database */
1264 if (restoreThisDump) {
1266 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1272 /* get the next item-header */
1273 memset(nextHeader, 0, sizeof(*nextHeader));
1275 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1276 sizeof(netItemHeader));
1279 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1281 /* Add every volume to the db */
1282 while (nextHeader->type == SD_VOLUME) { /*v */
1284 /* read the volume entry */
1285 memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1287 getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry,
1288 sizeof(netVolumeEntry));
1291 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1293 if (restoreThisDump) {
1295 threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry),
1301 /* get the next item-header */
1302 memset(nextHeader, 0, sizeof(*nextHeader));
1304 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1305 sizeof(netItemHeader));
1308 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1311 /* Finish the tape */
1312 if (restoreThisDump) {
1314 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1321 /* Finish the dump */
1322 if (restoreThisDump) {
1324 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1335 * Save the specified file as configuration text in the ubik database.
1336 * Have to setup the client text structure so that we can call
1337 * the routine to transmit the text to the db.
1341 saveTextFile(afs_int32 taskId, afs_int32 textType, char *fileName)
1343 udbClientTextP ctPtr = 0;
1347 ctPtr = calloc(1, sizeof(*ctPtr));
1349 ERROR_EXIT(TC_NOMEMORY);
1351 ctPtr->textType = textType;
1353 /* lock the text in the database */
1354 code = bc_LockText(ctPtr);
1356 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1361 ctPtr->textStream = fopen(fileName, "r");
1362 if (!ctPtr->textStream) {
1363 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1367 /* now send the text to the database */
1368 code = bcdb_SaveTextFile(ctPtr);
1370 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1376 if (ctPtr->textStream)
1377 fclose(ctPtr->textStream);
1379 bc_UnlockText(ctPtr);
1386 * read the text off the tape, and store it in the appropriate
1387 * text type in the database.
1389 * nextHeader - ptr to struct for return information
1391 * nextHeader - struct header for next item on the tape
1395 restoreText(struct butm_tapeInfo *tapeInfo,
1396 struct rstTapeInfo *rstTapeInfoPtr,
1397 struct structDumpHeader *nextHeader)
1401 char *readBuffer = 0;
1402 afs_int32 readBlockSize;
1403 afs_int32 transferSize;
1404 struct structDumpHeader netItemHeader;
1408 udbClientTextP ctPtr = 0;
1411 ctPtr = malloc(sizeof(*ctPtr));
1413 ERROR_EXIT(TC_NOMEMORY);
1415 /* determine the type of text block */
1416 switch (nextHeader->type) {
1417 case SD_TEXT_DUMPSCHEDULE:
1418 textType = TB_DUMPSCHEDULE;
1421 case SD_TEXT_VOLUMESET:
1422 textType = TB_VOLUMESET;
1425 case SD_TEXT_TAPEHOSTS:
1426 textType = TB_TAPEHOSTS;
1430 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0,
1431 "Unknown text block\n");
1432 ERROR_EXIT(TC_INTERNALERROR);
1436 /* open the text file */
1437 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1438 fid = mkstemp(filename);
1440 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1441 "Can't open temporary text file: %s\n", filename);
1445 /* allocate buffer for text */
1446 readBlockSize = BUTM_BLKSIZE;
1447 readBuffer = malloc(readBlockSize);
1449 ERROR_EXIT(TC_NOMEMORY);
1451 /* read the text into the temporary file */
1452 nbytes = nextHeader->size;
1453 while (nbytes > 0) {
1454 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1456 /* read it from the tape */
1458 getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1462 /* write to the file */
1463 if (write(fid, readBuffer, transferSize) != transferSize) {
1464 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1465 "Can't write temporary text file: %s\n", filename);
1469 nbytes -= transferSize;
1474 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1479 /* get the next item-header */
1480 memset(nextHeader, 0, sizeof(*nextHeader));
1482 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1483 sizeof(netItemHeader));
1486 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1501 /* ----------------------------------
1502 * Tape data buffering - for reading database dumps
1503 * ----------------------------------
1506 static char *tapeReadBuffer = 0; /* input buffer */
1507 static char *tapeReadBufferPtr = 0; /* position in buffer */
1510 * Read information from tape, and place the requested number of bytes
1511 * in the buffer supplied
1514 * rstTapeInfoPtr - Info about the dump being restored.
1515 * buffer - buffer for requested data
1516 * requestedBytes - no. of bytes requested
1518 * fn retn - 0, ok, n, error
1522 getTapeData(struct butm_tapeInfo *tapeInfoPtr,
1523 struct rstTapeInfo *rstTapeInfoPtr,
1524 void *out, afs_int32 requestedBytes)
1526 char *buffer = (char *) out;
1527 afs_int32 taskId, transferBytes;
1530 taskId = rstTapeInfoPtr->taskId;
1532 if (checkAbortByTaskId(taskId))
1533 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1535 if (!tapeReadBuffer) {
1536 tapeReadBuffer = malloc(BUTM_BLOCKSIZE);
1537 if (!tapeReadBuffer)
1538 ERROR_EXIT(TC_NOMEMORY);
1541 while (requestedBytes > 0) {
1543 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1547 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1548 BUTM_BLKSIZE, &nbytes);
1550 /* detect if we hit the end-of-tape and get next tape */
1551 if (code == BUTM_ENDVOLUME) {
1552 /* Update fields in tape entry for this tape */
1553 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1554 tapeEntryPtr->useKBytes =
1555 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1557 unmountTape(taskId, tapeInfoPtr);
1559 rstTapeInfoPtr->tapeSeq++;
1560 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1564 code = butm_ReadFileBegin(tapeInfoPtr);
1566 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1567 "Can't read FileBegin on tape\n");
1574 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1575 "Can't read FileData on tape\n");
1581 transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1582 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1583 tapeReadBufferPtr += transferBytes;
1584 buffer += transferBytes;
1585 nbytes -= transferBytes;
1586 requestedBytes -= transferBytes;