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/afs_assert.h>
24 #include <afs/prs_fs.h>
28 #include <afs/cellconfig.h>
32 #include <afs/volser.h>
33 #include <afs/vlserver.h>
34 #include <afs/tcdata.h>
36 #include <afs/budb_client.h>
37 #include <afs/bubasics.h>
38 #include <afs/bucoord_prototypes.h>
39 #include <afs/butm_prototypes.h>
40 #include <afs/budb_prototypes.h>
41 #include <afs/afsutil.h>
43 #include "butc_internal.h"
44 #include "error_macros.h"
46 /* GLOBAL CONFIGURATION PARAMETERS */
47 #define BIGCHUNK 102400
49 extern int dump_namecheck;
58 static void initTapeBuffering(void);
59 static int writeDbDump(struct butm_tapeInfo *, afs_uint32, Date, afs_uint32);
60 static int restoreDbEntries(struct butm_tapeInfo *, struct rstTapeInfo *);
62 int getTapeData(struct butm_tapeInfo *, struct rstTapeInfo *, void *,
64 int restoreDbHeader(struct butm_tapeInfo *, struct rstTapeInfo *,
65 struct structDumpHeader *);
66 int restoreDbDump(struct butm_tapeInfo *, struct rstTapeInfo *,
67 struct structDumpHeader *);
68 int restoreText(struct butm_tapeInfo *, struct rstTapeInfo *,
69 struct structDumpHeader *);
73 void * KeepAlive(void *);
75 * create a dump entry for a saved database
79 CreateDBDump(struct budb_dumpEntry *dumpEntryPtr)
83 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
85 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
86 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
87 strcat(dumpEntryPtr->tapes.format, ".%d");
88 strcpy(dumpEntryPtr->volumeSetName, "");
89 strcpy(dumpEntryPtr->dumpPath, "");
90 dumpEntryPtr->created = 0; /* let database assign it */
91 dumpEntryPtr->incTime = 0;
92 dumpEntryPtr->nVolumes = 0;
93 dumpEntryPtr->initialDumpID = 0;
94 dumpEntryPtr->parent = 0;
95 dumpEntryPtr->level = 0;
96 dumpEntryPtr->tapes.maxTapes = 0;
97 dumpEntryPtr->tapes.b = 1;
99 /* now call the database to create the entry */
100 code = bcdb_CreateDump(dumpEntryPtr);
104 struct tapeEntryList {
105 struct tapeEntryList *next;
106 afs_uint32 oldDumpId;
107 struct budb_tapeEntry tapeEnt;
109 struct tapeEntryList *listEntryHead;
110 struct tapeEntryList *listEntryPtr;
111 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
112 struct budb_dumpEntry lastDump; /* the last dump of this volset */
115 * Load a DB tape, read and over write its label.
116 * Leave the tape mounted.
119 GetDBTape(afs_int32 taskId, Date expires, struct butm_tapeInfo *tapeInfoPtr,
120 afs_uint32 dumpid, afs_int32 sequence, int queryFlag,
125 char tapeName[BU_MAXTAPELEN];
131 struct butm_tapeLabel oldTapeLabel, newLabel;
132 struct tapeEntryList *endList;
134 /* construct the name of the tape */
135 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
137 interactiveFlag = queryFlag;
140 while (!*wroteLabel) { /*w */
141 if (interactiveFlag) { /* need a tape to write */
143 PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
151 code = butm_Mount(tapeInfoPtr, tapeName);
153 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
157 memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
158 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
160 oldTapeLabel.useCount = 0; /* no label exists */
161 oldTapeLabel.structVersion = 0;
162 strcpy(oldTapeLabel.pName, "");
164 /* If tape has a name, it must be null or database tape name */
165 if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
166 && !databaseTape(oldTapeLabel.AFSName)) {
167 char gotName[BU_MAXTAPELEN + 32];
169 LABELNAME(gotName, &oldTapeLabel);
171 "This tape %s must be a database tape or NULL tape\n",
175 unmountTape(taskId, tapeInfoPtr);
179 /* Do not overwrite a tape that belongs to this dump */
180 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
181 ErrorLog(0, taskId, 0, 0,
182 "Can't overwrite tape containing the dump in progress\n");
186 /* On first tape, the savedb has not started yet, so the database is not locked
187 * and we can therefore, access information from it. This is easier to do because
188 * database dumps don't have appended dumps (nor appended).
192 struct budb_dumpEntry de, de2;
194 /* Verify the tape has not expired
195 * Early database dumps don't have a dumpid
197 if (!tapeExpired(&oldTapeLabel)) {
198 TLog(taskId, "This tape has not expired\n");
202 /* Since the dumpset on this tape will be deleted from database, check if
203 * any of the dumps in this dumpset are most-recent-dumps.
205 for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
206 if (dmp == lastDump.id) {
207 memcpy(&de, &lastDump, sizeof(de));
208 memcpy(&de2, &lastDump, sizeof(de2));
210 code = bcdb_FindDumpByID(dmp, &de);
213 sprintf(strlevel, "%d", de.level);
215 bcdb_FindLatestDump(de.volumeSetName, strlevel,
221 if (de.id == de2.id) {
222 if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
223 ErrorLog(0, taskId, 0, 0,
224 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
227 ErrorLog(0, taskId, 0, 0,
228 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
229 de.volumeSetName, de.name, de.id);
235 /* Otherwise, the savedb is in progress and we can't
236 * access the database (it's locked). So we rely on the
237 * information available (and not the backup database).
240 /* Check the tape's expiration date. Use the expiration on the label */
241 gettimeofday(&tp, NULL);
243 if (curTime < oldTapeLabel.expirationDate) {
244 TLog(taskId, "This tape has not expired\n");
248 /* Check if this previous-dump of the dump-in-progress is on this tape */
249 if (oldTapeLabel.dumpid
250 && (oldTapeLabel.dumpid == lastDump.id)) {
251 ErrorLog(0, taskId, 0, 0,
252 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
253 lastDump.name, lastDump.id);
259 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
260 newLabel.expirationDate = expires;
261 newLabel.useCount = oldTapeLabel.useCount + 1;
262 newLabel.dumpid = dumpid;
263 newLabel.size = tapeInfoPtr->tapeSize;
265 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
267 TapeLog(0, taskId, code, tapeInfoPtr->error,
268 "Can't label tape\n");
274 /* Initialize a tapeEntry for later inclusion into the database */
276 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
278 ERROR_EXIT(TC_NOMEMORY);
279 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
281 /* Remember dumpid so we can delete it later */
282 if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
283 && oldTapeLabel.dumpid)
284 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
286 /* Fill in tape entry so we can save it later */
287 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
288 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
289 tapeEntryPtr->written = newLabel.creationTime;
290 tapeEntryPtr->expires = expires;
291 tapeEntryPtr->seq = sequence;
292 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
293 tapeEntryPtr->dump = dumpid;
294 tapeEntryPtr->useKBytes = 0;
295 tapeEntryPtr->labelpos = 0;
297 /* Thread onto end of single-linked list */
299 endList = listEntryHead;
300 while (endList->next)
301 endList = endList->next;
302 endList->next = listEntryPtr;
304 listEntryHead = listEntryPtr;
312 * With the list of tapes, free the structures.
318 struct tapeEntryList *next;
320 listEntryPtr = listEntryHead;
321 while (listEntryPtr) {
322 next = listEntryPtr->next;
327 listEntryHead = NULL;
332 * With the list of tapes, add them to the database.
333 * Also delete any olddumpids that are around.
337 addTapesToDb(afs_int32 taskId)
341 struct tapeEntryList *next;
343 listEntryPtr = listEntryHead;
344 while (listEntryPtr) {
345 next = listEntryPtr->next;
347 /* Remove the old database entry */
348 if (listEntryPtr->oldDumpId) {
349 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
350 if (i && (i != BUDB_NOENT)) {
351 ErrorLog(0, taskId, i, 0,
352 "Unable to delete old DB entry %u.\n",
353 listEntryPtr->oldDumpId);
357 /* Add the tape to the database */
358 code = bcdb_UseTape(tapeEntryPtr, &new);
360 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n",
365 code = bcdb_FinishTape(tapeEntryPtr);
367 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n",
381 * this code assumes that the blocksize on reads is smaller than
382 * the blocksize on writes
386 writeDbDump(struct butm_tapeInfo *tapeInfoPtr, afs_uint32 taskId,
387 Date expires, afs_uint32 dumpid)
390 afs_int32 writeBufNbytes = 0;
391 char *writeBlock = 0;
392 char *writeBuffer = 0;
394 afs_int32 transferSize;
396 char *readBufPtr = NULL;
397 afs_int32 maxReadSize;
402 afs_int32 chunksize = 0;
403 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
407 #ifdef AFS_PTHREAD_ENV
409 pthread_attr_t tattr;
415 extern struct tapeConfig globalTapeConfig;
416 extern struct udbHandleS udbHandle;
418 blockSize = BUTM_BLKSIZE;
419 writeBlock = (char *)malloc(BUTM_BLOCKSIZE);
421 ERROR_EXIT(TC_NOMEMORY);
423 writeBuffer = writeBlock + sizeof(struct blockMark);
424 memset(writeBuffer, 0, BUTM_BLKSIZE);
428 * The margin of space to check for end of tape is set to the
429 * amount of space used to write an end-of-tape multiplied by 2.
430 * The amount of space is size of a 16K EODump marker, its EOF
431 * marker, and up to two EOF markers done on close (1 16K blocks +
434 tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
435 tc_KEndMargin = tc_EndMargin / 1024;
437 /* have to write enclose the dump in file marks */
438 code = butm_WriteFileBegin(tapeInfoPtr);
440 ErrorLog(0, taskId, code, tapeInfoPtr->error,
441 "Can't write FileBegin on tape\n");
445 writeBufPtr = &writeBuffer[0];
448 charList.charListT_val = 0;
449 charList.charListT_len = 0;
452 /* When no data in buffer, read data from the budb_server */
453 if (charList.charListT_len == 0) {
454 /* get more data. let rx allocate space */
455 if (charList.charListT_val) {
456 free(charList.charListT_val);
457 charList.charListT_val = 0;
462 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
463 UF_SINGLESERVER, firstcall,
464 maxReadSize, &charList, &done);
466 ErrorLog(0, taskId, code, 0, "Can't read database\n");
470 /* If this if the first call to the budb server, create a thread
471 * that will keep the connection alive (during tape changes).
474 #ifdef AFS_PTHREAD_ENV
475 code = pthread_attr_init(&tattr);
477 ErrorLog(0, taskId, code, 0,
478 "Can't pthread_attr_init Keep-alive process\n");
483 pthread_attr_setdetachstate(&tattr,
484 PTHREAD_CREATE_DETACHED);
486 ErrorLog(0, taskId, code, 0,
487 "Can't pthread_attr_setdetachstate Keep-alive process\n");
492 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
493 AFS_SIGSET_RESTORE();
496 LWP_CreateProcess(KeepAlive, 16384, 1, (void *)NULL,
497 "Keep-alive process", &alivePid);
499 /* XXX should we check code here ??? XXX */
503 readBufPtr = charList.charListT_val;
506 if ((charList.charListT_len == 0) && done)
509 /* compute how many bytes and transfer to the write Buffer */
511 (charList.charListT_len <
513 writeBufNbytes)) ? charList.charListT_len : (blockSize -
516 memcpy(writeBufPtr, readBufPtr, transferSize);
517 charList.charListT_len -= transferSize;
518 writeBufPtr += transferSize;
519 readBufPtr += transferSize;
520 writeBufNbytes += transferSize;
522 /* If filled the write buffer, then write it to tape */
523 if (writeBufNbytes == blockSize) {
524 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
526 ErrorLog(0, taskId, code, tapeInfoPtr->error,
527 "Can't write data on tape\n");
531 memset(writeBuffer, 0, blockSize);
532 writeBufPtr = &writeBuffer[0];
535 /* Every BIGCHUNK bytes check if aborted */
536 chunksize += blockSize;
537 if (chunksize > BIGCHUNK) {
539 if (checkAbortByTaskId(taskId))
540 ERROR_EXIT(TC_ABORTEDBYREQUEST);
544 * check if tape is full - since we filled a blockSize worth of data
545 * assume that there is more data.
547 kRemaining = butm_remainingKSpace(tapeInfoPtr);
548 if (kRemaining < tc_KEndMargin) {
549 code = butm_WriteFileEnd(tapeInfoPtr);
551 ErrorLog(0, taskId, code, tapeInfoPtr->error,
552 "Can't write FileEnd on tape\n");
556 code = butm_WriteEOT(tapeInfoPtr);
558 ErrorLog(0, taskId, code, tapeInfoPtr->error,
559 "Can't write end-of-dump on tape\n");
563 /* Mark tape as having been written */
564 tapeEntryPtr->useKBytes =
565 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
566 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
568 unmountTape(taskId, tapeInfoPtr);
570 /* Get next tape and writes its label */
573 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
578 code = butm_WriteFileBegin(tapeInfoPtr);
580 ErrorLog(0, taskId, code, tapeInfoPtr->error,
581 "Can't write FileBegin on tape\n");
588 /* no more data to be read - if necessary, flush out the last buffer */
589 if (writeBufNbytes > 0) {
590 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
592 ErrorLog(1, taskId, code, tapeInfoPtr->error,
593 "Can't write data on tape\n");
598 code = butm_WriteFileEnd(tapeInfoPtr);
600 ErrorLog(0, taskId, code, tapeInfoPtr->error,
601 "Can't write FileEnd on tape\n");
605 /* Mark tape as having been written */
606 tapeEntryPtr->useKBytes =
607 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
608 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
611 /* Let the KeepAlive process stop on its own */
613 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
614 UF_END_SINGLESERVER, 0);
618 if (charList.charListT_val)
619 free(charList.charListT_val);
624 * dump backup database to tape
628 saveDbToTape(void *param)
630 struct saveDbIf *saveDbIfPtr = (struct saveDbIf *)param;
637 struct butm_tapeInfo tapeInfo;
638 struct budb_dumpEntry dumpEntry;
640 extern struct deviceSyncNode *deviceLatch;
641 extern struct tapeConfig globalTapeConfig;
643 afs_pthread_setname_self("Db save");
644 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
645 taskId = saveDbIfPtr->taskId;
648 setStatus(taskId, DRIVE_WAIT);
649 EnterDeviceQueue(deviceLatch); /* lock tape device */
650 clearStatus(taskId, DRIVE_WAIT);
653 TLog(taskId, "SaveDb\n");
655 tapeInfo.structVersion = BUTM_MAJORVERSION;
656 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
658 ErrorLog(0, taskId, code, tapeInfo.error,
659 "Can't initialize tape module\n");
663 /* Determine what the last database dump was */
664 memset(&lastDump, 0, sizeof(lastDump));
665 code = bcdb_FindLatestDump("", "", &lastDump);
667 if (code != BUDB_NODUMPNAME) {
668 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
671 memset(&lastDump, 0, sizeof(lastDump));
674 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
676 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
681 listEntryHead = NULL;
683 /* Get the tape and write a new label to it */
685 GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
689 * If did not write the label, remove created dump
690 * Else if wrote the label, remove old dump from db so it's not saved.
693 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
695 if (i && (i != BUDB_NOENT))
696 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
698 } else if (listEntryHead->oldDumpId) {
699 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
700 listEntryHead->oldDumpId = 0;
701 if (i && (i != BUDB_NOENT)) {
702 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
703 listEntryHead->oldDumpId);
710 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
712 /* we have a writable tape */
713 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
717 /* Now delete the entries between time 0 and archive-time */
718 if (saveDbIfPtr->archiveTime)
719 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
722 unmountTape(taskId, &tapeInfo);
724 /* Add this dump's tapes to the database and mark it finished */
726 i = addTapesToDb(taskId);
730 i = bcdb_FinishDump(&dumpEntry);
736 if (code == TC_ABORTEDBYREQUEST) {
737 TLog(taskId, "SaveDb: Aborted by request\n");
738 clearStatus(taskId, ABORT_REQUEST);
739 setStatus(taskId, ABORT_DONE);
741 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
742 setStatus(taskId, TASK_ERROR);
744 TLog(taskId, "SaveDb: Finished\n");
746 setStatus(taskId, TASK_DONE);
749 LeaveDeviceQueue(deviceLatch);
750 return (void *)(intptr_t)(code);
755 * Make a database dump entry given a tape label.
759 makeDbDumpEntry(struct budb_tapeEntry *tapeEntPtr,
760 struct budb_dumpEntry *dumpEntryPtr)
762 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
764 dumpEntryPtr->id = tapeEntPtr->dump;
765 dumpEntryPtr->initialDumpID = 0;
766 dumpEntryPtr->parent = 0;
767 dumpEntryPtr->level = 0;
768 dumpEntryPtr->flags = 0;
770 strcpy(dumpEntryPtr->volumeSetName, "");
771 strcpy(dumpEntryPtr->dumpPath, "");
772 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
774 dumpEntryPtr->created = tapeEntPtr->dump;
775 dumpEntryPtr->incTime = 0;
776 dumpEntryPtr->nVolumes = 0;
778 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
779 strcat(dumpEntryPtr->tapes.format, ".%d");
780 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
781 dumpEntryPtr->tapes.maxTapes = 0;
786 * prompt for a specific database tape
790 readDbTape(struct butm_tapeInfo *tapeInfoPtr,
791 struct rstTapeInfo *rstTapeInfoPtr, int query)
796 struct butm_tapeLabel oldTapeLabel;
797 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
798 struct tapeEntryList *endList;
800 struct budb_dumpEntry de;
801 struct budb_tapeEntry te;
803 taskId = rstTapeInfoPtr->taskId;
804 interactiveFlag = query;
806 /* construct the name of the tape */
807 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
808 strcpy(tapeName, AFStapeName);
810 /* Will prompt for the latest saved database tape, but will accept any one */
811 if (rstTapeInfoPtr->tapeSeq == 1) {
812 code = bcdb_FindLatestDump("", "", &de);
814 rstTapeInfoPtr->dumpid = de.id;
816 if (rstTapeInfoPtr->dumpid) {
818 bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
821 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 */
876 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
878 ERROR_EXIT(TC_NOMEMORY);
879 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
881 /* Fill in tape entry so we can save it later */
882 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
883 tapeEntryPtr->dump = oldTapeLabel.dumpid;
884 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
885 tapeEntryPtr->written = oldTapeLabel.creationTime;
886 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
887 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
888 tapeEntryPtr->useCount = oldTapeLabel.useCount;
889 tapeEntryPtr->useKBytes = 0;
890 tapeEntryPtr->labelpos = 0;
892 /* Thread onto end of single-linked list */
894 endList = listEntryHead;
895 while (endList->next)
896 endList = endList->next;
897 endList->next = listEntryPtr;
899 listEntryHead = listEntryPtr;
905 static afs_int32 nbytes = 0; /* # bytes left in buffer */
907 initTapeBuffering(void)
914 * restore all the items on the tape
916 * tape positioned after tape label
920 restoreDbEntries(struct butm_tapeInfo *tapeInfoPtr,
921 struct rstTapeInfo *rstTapeInfoPtr)
923 struct structDumpHeader netItemHeader, hostItemHeader;
925 afs_int32 taskId, code = 0;
928 taskId = rstTapeInfoPtr->taskId;
930 /* clear state for the buffer routine(s) */
933 code = butm_ReadFileBegin(tapeInfoPtr);
935 ErrorLog(0, taskId, code, tapeInfoPtr->error,
936 "Can't read FileBegin on tape\n");
940 /* get the first item-header */
941 memset(&netItemHeader, 0, sizeof(netItemHeader));
943 getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
944 sizeof(netItemHeader));
947 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
950 switch (hostItemHeader.type) {
953 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
959 if (++count > 25) { /*every 25 dumps, wait */
964 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
974 case SD_TEXT_DUMPSCHEDULE:
975 case SD_TEXT_VOLUMESET:
976 case SD_TEXT_TAPEHOSTS:
977 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
987 TLog(taskId, "Unknown database header type %d\n",
988 hostItemHeader.type);
994 code = butm_ReadFileEnd(tapeInfoPtr);
996 ErrorLog(0, taskId, code, tapeInfoPtr->error,
997 "Can't read EOF on tape\n");
1001 /* Mark tape as having been written */
1002 tapeEntryPtr->useKBytes =
1003 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1004 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1010 /* restoreDbFromTape
1011 * restore the backup database from tape.
1015 restoreDbFromTape(void *param)
1017 afs_uint32 taskId = (intptr_t) param;
1020 struct butm_tapeInfo tapeInfo;
1021 struct rstTapeInfo rstTapeInfo;
1022 struct budb_dumpEntry dumpEntry;
1024 extern struct tapeConfig globalTapeConfig;
1025 extern struct deviceSyncNode *deviceLatch;
1027 afs_pthread_setname_self("Db restore");
1028 setStatus(taskId, DRIVE_WAIT);
1029 EnterDeviceQueue(deviceLatch); /* lock tape device */
1030 clearStatus(taskId, DRIVE_WAIT);
1033 TLog(taskId, "RestoreDb\n");
1035 tapeInfo.structVersion = BUTM_MAJORVERSION;
1036 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1038 ErrorLog(0, taskId, code, tapeInfo.error,
1039 "Can't initialize tape module\n");
1043 listEntryHead = NULL;
1045 rstTapeInfo.taskId = taskId;
1046 rstTapeInfo.tapeSeq = 1;
1047 rstTapeInfo.dumpid = 0;
1049 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1053 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1058 /* Now put this dump into the database */
1059 /* Make a dump entry from first tape */
1060 listEntryPtr = listEntryHead;
1062 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1063 if (dumpEntry.id != 0) {
1064 i = bcdb_CreateDump(&dumpEntry);
1066 if (i == BUDB_DUMPIDEXISTS)
1068 "Dump id %d not added to database - already exists\n",
1071 TapeLog(0, taskId, i, 0,
1072 "Dump id %d not added to database\n",
1075 i = addTapesToDb(taskId);
1079 i = bcdb_FinishDump(&dumpEntry);
1087 unmountTape(taskId, &tapeInfo);
1090 if (code == TC_ABORTEDBYREQUEST) {
1091 TLog(taskId, "RestoreDb: Aborted by request\n");
1092 clearStatus(taskId, ABORT_REQUEST);
1093 setStatus(taskId, ABORT_DONE);
1095 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1096 setStatus(taskId, TASK_ERROR);
1098 TLog(taskId, "RestoreDb: Finished\n");
1101 LeaveDeviceQueue(deviceLatch);
1102 setStatus(taskId, TASK_DONE);
1104 return (void *)(intptr_t)(code);
1109 * While dumping the database, keeps the connection alive.
1110 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
1111 * This resets the database's internal timer so that it does not
1112 * prematuraly quit (on asking for new tapes and such).
1114 * Use the same udbHandle as writeDbDump so we go to the same server.
1117 KeepAlive(void *unused)
1123 extern struct udbHandleS udbHandle;
1125 afs_pthread_setname_self("Keep-alive");
1127 #ifdef AFS_PTHREAD_ENV
1132 charList.charListT_val = 0;
1133 charList.charListT_len = 0;
1135 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1136 UF_SINGLESERVER, 0, 0, &charList, &done);
1145 * restore special items in the header
1149 restoreDbHeader(struct butm_tapeInfo *tapeInfo,
1150 struct rstTapeInfo *rstTapeInfoPtr,
1151 struct structDumpHeader *nextHeader)
1153 struct structDumpHeader netItemHeader;
1154 struct DbHeader netDbHeader, hostDbHeader;
1157 extern struct udbHandleS udbHandle;
1159 /* Read the database header */
1160 memset(&netDbHeader, 0, sizeof(netDbHeader));
1162 getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1163 sizeof(netDbHeader));
1166 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1168 /* Add the database header to the database */
1170 ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1173 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1174 "Can't restore DB Header\n");
1178 /* get the next item-header */
1179 memset(nextHeader, 0, sizeof(*nextHeader));
1181 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1182 sizeof(netItemHeader));
1185 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1193 * restore a single dump, including all its tapes and volumes, from
1196 * nextHeader - ptr to structure for return value
1198 * nextHeader - next structure header from tape
1200 * upon entry, the dump structure header has been read confirming that
1201 * a database dump tree exists on the tape
1205 restoreDbDump(struct butm_tapeInfo *tapeInfo,
1206 struct rstTapeInfo *rstTapeInfoPtr,
1207 struct structDumpHeader *nextHeader)
1209 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1210 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1211 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1212 struct structDumpHeader netItemHeader;
1213 int restoreThisDump = 1;
1216 extern struct udbHandleS udbHandle;
1218 /* read dump entry */
1219 memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1221 getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry,
1222 sizeof(netDumpEntry));
1226 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1227 if (rstTapeInfoPtr->dumpid == 0) {
1228 netDumpEntry.initialDumpID = 0;
1229 netDumpEntry.appendedDumpID = 0;
1232 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1234 /* The dump entry for this database tape is incomplete, so don't include it */
1235 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1236 restoreThisDump = 0;
1238 /* add the dump to the database */
1239 if (restoreThisDump) {
1241 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1247 /* get the next item-header */
1248 memset(nextHeader, 0, sizeof(*nextHeader));
1250 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1251 sizeof(netItemHeader));
1254 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1256 /* Add every tape to the db */
1257 while (nextHeader->type == SD_TAPE) { /*t */
1259 /* read the tape entry */
1260 memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1262 getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry,
1263 sizeof(netTapeEntry));
1266 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1268 /* Add the tape to the database */
1269 if (restoreThisDump) {
1271 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1277 /* get the next item-header */
1278 memset(nextHeader, 0, sizeof(*nextHeader));
1280 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1281 sizeof(netItemHeader));
1284 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1286 /* Add every volume to the db */
1287 while (nextHeader->type == SD_VOLUME) { /*v */
1289 /* read the volume entry */
1290 memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1292 getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry,
1293 sizeof(netVolumeEntry));
1296 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1298 if (restoreThisDump) {
1300 threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry),
1306 /* get the next item-header */
1307 memset(nextHeader, 0, sizeof(*nextHeader));
1309 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1310 sizeof(netItemHeader));
1313 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1316 /* Finish the tape */
1317 if (restoreThisDump) {
1319 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1326 /* Finish the dump */
1327 if (restoreThisDump) {
1329 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1340 * Save the specified file as configuration text in the ubik database.
1341 * Have to setup the client text structure so that we can call
1342 * the routine to transmit the text to the db.
1346 saveTextFile(afs_int32 taskId, afs_int32 textType, char *fileName)
1348 udbClientTextP ctPtr = 0;
1352 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1354 ERROR_EXIT(TC_NOMEMORY);
1356 memset(ctPtr, 0, sizeof(*ctPtr));
1357 ctPtr->textType = textType;
1359 /* lock the text in the database */
1360 code = bc_LockText(ctPtr);
1362 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1367 ctPtr->textStream = fopen(fileName, "r");
1368 if (!ctPtr->textStream) {
1369 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1373 /* now send the text to the database */
1374 code = bcdb_SaveTextFile(ctPtr);
1376 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1382 if (ctPtr->textStream)
1383 fclose(ctPtr->textStream);
1385 bc_UnlockText(ctPtr);
1392 * read the text off the tape, and store it in the appropriate
1393 * text type in the database.
1395 * nextHeader - ptr to struct for return information
1397 * nextHeader - struct header for next item on the tape
1401 restoreText(struct butm_tapeInfo *tapeInfo,
1402 struct rstTapeInfo *rstTapeInfoPtr,
1403 struct structDumpHeader *nextHeader)
1407 char *readBuffer = 0;
1408 afs_int32 readBlockSize;
1409 afs_int32 transferSize;
1410 struct structDumpHeader netItemHeader;
1414 udbClientTextP ctPtr = 0;
1417 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1419 ERROR_EXIT(TC_NOMEMORY);
1421 /* determine the type of text block */
1422 switch (nextHeader->type) {
1423 case SD_TEXT_DUMPSCHEDULE:
1424 textType = TB_DUMPSCHEDULE;
1427 case SD_TEXT_VOLUMESET:
1428 textType = TB_VOLUMESET;
1431 case SD_TEXT_TAPEHOSTS:
1432 textType = TB_TAPEHOSTS;
1436 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0,
1437 "Unknown text block\n");
1438 ERROR_EXIT(TC_INTERNALERROR);
1442 /* open the text file */
1443 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1444 fid = mkstemp(filename);
1446 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1447 "Can't open temporary text file: %s\n", filename);
1451 /* allocate buffer for text */
1452 readBlockSize = BUTM_BLKSIZE;
1453 readBuffer = (char *)malloc(readBlockSize);
1455 ERROR_EXIT(TC_NOMEMORY);
1457 /* read the text into the temporary file */
1458 nbytes = nextHeader->size;
1459 while (nbytes > 0) {
1460 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1462 /* read it from the tape */
1464 getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1468 /* write to the file */
1469 if (write(fid, readBuffer, transferSize) != transferSize) {
1470 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1471 "Can't write temporary text file: %s\n", filename);
1475 nbytes -= transferSize;
1480 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1485 /* get the next item-header */
1486 memset(nextHeader, 0, sizeof(*nextHeader));
1488 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1489 sizeof(netItemHeader));
1492 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1507 /* ----------------------------------
1508 * Tape data buffering - for reading database dumps
1509 * ----------------------------------
1512 static char *tapeReadBuffer = 0; /* input buffer */
1513 static char *tapeReadBufferPtr = 0; /* position in buffer */
1516 * Read information from tape, and place the requested number of bytes
1517 * in the buffer supplied
1520 * rstTapeInfoPtr - Info about the dump being restored.
1521 * buffer - buffer for requested data
1522 * requestedBytes - no. of bytes requested
1524 * fn retn - 0, ok, n, error
1528 getTapeData(struct butm_tapeInfo *tapeInfoPtr,
1529 struct rstTapeInfo *rstTapeInfoPtr,
1530 void *out, afs_int32 requestedBytes)
1532 char *buffer = (char *) out;
1533 afs_int32 taskId, transferBytes;
1536 taskId = rstTapeInfoPtr->taskId;
1538 if (checkAbortByTaskId(taskId))
1539 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1541 if (!tapeReadBuffer) {
1542 tapeReadBuffer = (char *)malloc(BUTM_BLOCKSIZE);
1543 if (!tapeReadBuffer)
1544 ERROR_EXIT(TC_NOMEMORY);
1547 while (requestedBytes > 0) {
1549 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1553 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1554 BUTM_BLKSIZE, &nbytes);
1556 /* detect if we hit the end-of-tape and get next tape */
1557 if (code == BUTM_ENDVOLUME) {
1558 /* Update fields in tape entry for this tape */
1559 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1560 tapeEntryPtr->useKBytes =
1561 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1563 unmountTape(taskId, tapeInfoPtr);
1565 rstTapeInfoPtr->tapeSeq++;
1566 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1570 code = butm_ReadFileBegin(tapeInfoPtr);
1572 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1573 "Can't read FileBegin on tape\n");
1580 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1581 "Can't read FileData on tape\n");
1587 transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1588 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1589 tapeReadBufferPtr += transferBytes;
1590 buffer += transferBytes;
1591 nbytes -= transferBytes;
1592 requestedBytes -= transferBytes;