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>
16 #include <sys/types.h>
23 #include <netinet/in.h>
29 #include <afs/afsint.h>
32 #include <afs/procmgmt.h>
33 #include <afs/assert.h>
34 #include <afs/prs_fs.h>
39 #include <afs/cellconfig.h>
43 #include <afs/tcdata.h>
45 #include <afs/budb_client.h>
46 #include <afs/bubasics.h>
47 #include "error_macros.h"
49 /* GLOBAL CONFIGURATION PARAMETERS */
50 #define BIGCHUNK 102400
52 extern int dump_namecheck;
55 static void initTapeBuffering();
57 static restoreDbEntries();
60 * create a dump entry for a saved database
64 CreateDBDump(dumpEntryPtr)
65 struct budb_dumpEntry *dumpEntryPtr;
69 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
71 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
72 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
73 strcat(dumpEntryPtr->tapes.format, ".%d");
74 strcpy(dumpEntryPtr->volumeSetName, "");
75 strcpy(dumpEntryPtr->dumpPath, "");
76 dumpEntryPtr->created = 0; /* let database assign it */
77 dumpEntryPtr->incTime = 0;
78 dumpEntryPtr->nVolumes = 0;
79 dumpEntryPtr->initialDumpID = 0;
80 dumpEntryPtr->parent = 0;
81 dumpEntryPtr->level = 0;
82 dumpEntryPtr->tapes.maxTapes = 0;
83 dumpEntryPtr->tapes.b = 1;
85 /* now call the database to create the entry */
86 code = bcdb_CreateDump(dumpEntryPtr);
90 struct tapeEntryList {
91 struct tapeEntryList *next;
93 struct budb_tapeEntry tapeEnt;
95 struct tapeEntryList *listEntryHead;
96 struct tapeEntryList *listEntryPtr;
97 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
98 struct budb_dumpEntry lastDump; /* the last dump of this volset */
101 * Load a DB tape, read and over write its label.
102 * Leave the tape mounted.
105 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag,
109 struct butm_tapeInfo *tapeInfoPtr;
117 char tapeName[BU_MAXTAPELEN];
124 struct butm_tapeLabel oldTapeLabel, newLabel;
125 struct tapeEntryList *endList;
126 extern struct tapeConfig globalTapeConfig;
128 /* construct the name of the tape */
129 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
131 interactiveFlag = queryFlag;
134 while (!*wroteLabel) { /*w */
135 if (interactiveFlag) { /* need a tape to write */
137 PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
145 code = butm_Mount(tapeInfoPtr, tapeName);
147 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
151 memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
152 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
154 oldTapeLabel.useCount = 0; /* no label exists */
155 oldTapeLabel.structVersion = 0;
156 strcpy(oldTapeLabel.pName, "");
158 /* If tape has a name, it must be null or database tape name */
159 if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
160 && !databaseTape(oldTapeLabel.AFSName)) {
161 char gotName[BU_MAXTAPELEN + 32];
163 LABELNAME(gotName, &oldTapeLabel);
165 "This tape %s must be a database tape or NULL tape\n",
169 unmountTape(taskId, tapeInfoPtr);
173 /* Do not overwrite a tape that belongs to this dump */
174 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
175 ErrorLog(0, taskId, 0, 0,
176 "Can't overwrite tape containing the dump in progress\n");
180 /* On first tape, the savedb has not started yet, so the database is not locked
181 * and we can therefore, access information from it. This is easier to do because
182 * database dumps don't have appended dumps (nor appended).
186 struct budb_dumpEntry de, de2;
188 /* Verify the tape has not expired
189 * Early database dumps don't have a dumpid
191 if (!tapeExpired(&oldTapeLabel)) {
192 TLog(taskId, "This tape has not expired\n");
196 /* Since the dumpset on this tape will be deleted from database, check if
197 * any of the dumps in this dumpset are most-recent-dumps.
199 for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
200 if (dmp == lastDump.id) {
201 memcpy(&de, &lastDump, sizeof(de));
202 memcpy(&de2, &lastDump, sizeof(de2));
204 code = bcdb_FindDumpByID(dmp, &de);
207 sprintf(strlevel, "%d", de.level);
209 bcdb_FindLatestDump(de.volumeSetName, strlevel,
215 if (de.id == de2.id) {
216 if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
217 ErrorLog(0, taskId, 0, 0,
218 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
221 ErrorLog(0, taskId, 0, 0,
222 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
223 de.volumeSetName, de.name, de.id);
229 /* Otherwise, the savedb is in progress and we can't
230 * access the database (it's locked). So we rely on the
231 * information available (and not the backup database).
234 /* Check the tape's expiration date. Use the expiration on the label */
235 gettimeofday(&tp, &tzp);
237 if (curTime < oldTapeLabel.expirationDate) {
238 TLog(taskId, "This tape has not expired\n");
242 /* Check if this previous-dump of the dump-in-progress is on this tape */
243 if (oldTapeLabel.dumpid
244 && (oldTapeLabel.dumpid == lastDump.id)) {
245 ErrorLog(0, taskId, 0, 0,
246 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
247 lastDump.name, lastDump.id);
253 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
254 newLabel.expirationDate = expires;
255 newLabel.useCount = oldTapeLabel.useCount + 1;
256 newLabel.dumpid = dumpid;
257 newLabel.size = tapeInfoPtr->tapeSize;
259 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
261 TapeLog(0, taskId, code, tapeInfoPtr->error,
262 "Can't label tape\n");
268 /* Initialize a tapeEntry for later inclusion into the database */
270 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
272 ERROR_EXIT(TC_NOMEMORY);
273 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
275 /* Remember dumpid so we can delete it later */
276 if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
277 && oldTapeLabel.dumpid)
278 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
280 /* Fill in tape entry so we can save it later */
281 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
282 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
283 tapeEntryPtr->written = newLabel.creationTime;
284 tapeEntryPtr->expires = expires;
285 tapeEntryPtr->seq = sequence;
286 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
287 tapeEntryPtr->dump = dumpid;
288 tapeEntryPtr->useKBytes = 0;
289 tapeEntryPtr->labelpos = 0;
291 /* Thread onto end of single-linked list */
293 endList = listEntryHead;
294 while (endList->next)
295 endList = endList->next;
296 endList->next = listEntryPtr;
298 listEntryHead = listEntryPtr;
306 * With the list of tapes, free the structures.
312 struct tapeEntryList *next;
314 listEntryPtr = listEntryHead;
315 while (listEntryPtr) {
316 next = listEntryPtr->next;
321 listEntryHead = NULL;
326 * With the list of tapes, add them to the database.
327 * Also delete any olddumpids that are around.
336 struct tapeEntryList *next;
338 listEntryPtr = listEntryHead;
339 while (listEntryPtr) {
340 next = listEntryPtr->next;
342 /* Remove the old database entry */
343 if (listEntryPtr->oldDumpId) {
344 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
345 if (i && (i != BUDB_NOENT)) {
346 ErrorLog(0, taskId, i, 0,
347 "Unable to delete old DB entry %u.\n",
348 listEntryPtr->oldDumpId);
352 /* Add the tape to the database */
353 code = bcdb_UseTape(tapeEntryPtr, &new);
355 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n",
360 code = bcdb_FinishTape(tapeEntryPtr);
362 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n",
376 * this code assumes that the blocksize on reads is smaller than
377 * the blocksize on writes
381 writeDbDump(tapeInfoPtr, taskId, expires, dumpid)
382 struct butm_tapeInfo *tapeInfoPtr;
388 afs_int32 writeBufNbytes = 0;
389 char *writeBlock = 0;
390 char *writeBuffer = 0;
392 afs_int32 transferSize;
395 afs_int32 maxReadSize;
400 afs_int32 chunksize = 0;
401 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
405 #ifdef AFS_PTHREAD_ENV
407 pthread_attr_t tattr;
413 extern struct tapeConfig globalTapeConfig;
414 extern struct udbHandleS udbHandle;
416 extern int KeepAlive();
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(saveDbIfPtr)
629 struct saveDbIf *saveDbIfPtr;
637 struct butm_tapeInfo tapeInfo;
638 struct budb_dumpEntry dumpEntry;
640 extern struct deviceSyncNode *deviceLatch;
641 extern struct tapeConfig globalTapeConfig;
643 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
644 taskId = saveDbIfPtr->taskId;
646 setStatus(taskId, DRIVE_WAIT);
647 EnterDeviceQueue(deviceLatch); /* lock tape device */
648 clearStatus(taskId, DRIVE_WAIT);
651 TLog(taskId, "SaveDb\n");
653 tapeInfo.structVersion = BUTM_MAJORVERSION;
654 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
656 ErrorLog(0, taskId, code, tapeInfo.error,
657 "Can't initialize tape module\n");
661 /* Determine what the last database dump was */
662 memset(&lastDump, 0, sizeof(lastDump));
663 code = bcdb_FindLatestDump("", "", &lastDump);
665 if (code != BUDB_NODUMPNAME) {
666 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
669 memset(&lastDump, 0, sizeof(lastDump));
672 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
674 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
679 listEntryHead = NULL;
681 /* Get the tape and write a new label to it */
683 GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
687 * If did not write the label, remove created dump
688 * Else if wrote the label, remove old dump from db so it's not saved.
691 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
693 if (i && (i != BUDB_NOENT))
694 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
696 } else if (listEntryHead->oldDumpId) {
697 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
698 listEntryHead->oldDumpId = 0;
699 if (i && (i != BUDB_NOENT)) {
700 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
701 listEntryHead->oldDumpId);
708 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
710 /* we have a writable tape */
711 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
715 /* Now delete the entries between time 0 and archive-time */
716 if (saveDbIfPtr->archiveTime)
717 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
720 unmountTape(taskId, &tapeInfo);
722 /* Add this dump's tapes to the database and mark it finished */
724 i = addTapesToDb(taskId);
728 i = bcdb_FinishDump(&dumpEntry);
734 if (code == TC_ABORTEDBYREQUEST) {
735 TLog(taskId, "SaveDb: Aborted by request\n");
736 clearStatus(taskId, ABORT_REQUEST);
737 setStatus(taskId, ABORT_DONE);
739 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
740 setStatus(taskId, TASK_ERROR);
742 TLog(taskId, "SaveDb: Finished\n");
744 setStatus(taskId, TASK_DONE);
747 LeaveDeviceQueue(deviceLatch);
758 * Make a database dump entry given a tape label.
762 makeDbDumpEntry(tapeEntPtr, dumpEntryPtr)
763 struct budb_tapeEntry *tapeEntPtr;
764 struct budb_dumpEntry *dumpEntryPtr;
766 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
768 dumpEntryPtr->id = tapeEntPtr->dump;
769 dumpEntryPtr->initialDumpID = 0;
770 dumpEntryPtr->parent = 0;
771 dumpEntryPtr->level = 0;
772 dumpEntryPtr->flags = 0;
774 strcpy(dumpEntryPtr->volumeSetName, "");
775 strcpy(dumpEntryPtr->dumpPath, "");
776 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
778 dumpEntryPtr->created = tapeEntPtr->dump;
779 dumpEntryPtr->incTime = 0;
780 dumpEntryPtr->nVolumes = 0;
782 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
783 strcat(dumpEntryPtr->tapes.format, ".%d");
784 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
785 dumpEntryPtr->tapes.maxTapes = 0;
790 * prompt for a specific database tape
794 readDbTape(tapeInfoPtr, rstTapeInfoPtr, query)
795 struct butm_tapeInfo *tapeInfoPtr;
796 struct rstTapeInfo *rstTapeInfoPtr;
802 struct butm_tapeLabel oldTapeLabel;
803 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
804 struct tapeEntryList *endList;
806 struct budb_dumpEntry de;
807 struct budb_tapeEntry te;
809 taskId = rstTapeInfoPtr->taskId;
810 interactiveFlag = query;
812 /* construct the name of the tape */
813 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
814 strcpy(tapeName, AFStapeName);
816 /* Will prompt for the latest saved database tape, but will accept any one */
817 if (rstTapeInfoPtr->tapeSeq == 1) {
818 code = bcdb_FindLatestDump("", "", &de);
820 rstTapeInfoPtr->dumpid = de.id;
822 if (rstTapeInfoPtr->dumpid) {
824 bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
827 strcpy(tapeName, te.name);
832 if (interactiveFlag) { /* need a tape to read */
834 PromptForTape(RESTOREDBOPCODE, tapeName,
835 rstTapeInfoPtr->dumpid, taskId, tapecount);
842 code = butm_Mount(tapeInfoPtr, tapeName);
844 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
848 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
850 TapeLog(0, taskId, code, tapeInfoPtr->error,
851 "Can't read tape label\n");
855 /* Check for name of tape and matching dump id (if applicable). */
856 if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
857 || ((rstTapeInfoPtr->tapeSeq != 1)
858 && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
859 char expTape[BU_MAXTAPELEN + 32];
860 char gotTape[BU_MAXTAPELEN + 32];
862 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
863 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
865 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
870 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
871 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
876 unmountTape(taskId, tapeInfoPtr);
880 /* Initialize a tapeEntry for later inclusion into the database */
882 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
884 ERROR_EXIT(TC_NOMEMORY);
885 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
887 /* Fill in tape entry so we can save it later */
888 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
889 tapeEntryPtr->dump = oldTapeLabel.dumpid;
890 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
891 tapeEntryPtr->written = oldTapeLabel.creationTime;
892 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
893 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
894 tapeEntryPtr->useCount = oldTapeLabel.useCount;
895 tapeEntryPtr->useKBytes = 0;
896 tapeEntryPtr->labelpos = 0;
898 /* Thread onto end of single-linked list */
900 endList = listEntryHead;
901 while (endList->next)
902 endList = endList->next;
903 endList->next = listEntryPtr;
905 listEntryHead = listEntryPtr;
911 static afs_int32 nbytes = 0; /* # bytes left in buffer */
920 * restore all the items on the tape
922 * tape positioned after tape label
926 restoreDbEntries(tapeInfoPtr, rstTapeInfoPtr)
927 struct butm_tapeInfo *tapeInfoPtr;
928 struct rstTapeInfo *rstTapeInfoPtr;
930 struct structDumpHeader netItemHeader, hostItemHeader;
932 afs_int32 taskId, code = 0;
935 taskId = rstTapeInfoPtr->taskId;
937 /* clear state for the buffer routine(s) */
940 code = butm_ReadFileBegin(tapeInfoPtr);
942 ErrorLog(0, taskId, code, tapeInfoPtr->error,
943 "Can't read FileBegin on tape\n");
947 /* get the first item-header */
948 memset(&netItemHeader, 0, sizeof(netItemHeader));
950 getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
951 sizeof(netItemHeader));
954 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
957 switch (hostItemHeader.type) {
960 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
966 if (++count > 25) { /*every 25 dumps, wait */
971 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
981 case SD_TEXT_DUMPSCHEDULE:
982 case SD_TEXT_VOLUMESET:
983 case SD_TEXT_TAPEHOSTS:
984 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
994 TLog(taskId, "Unknown database header type %d\n",
995 hostItemHeader.type);
1001 code = butm_ReadFileEnd(tapeInfoPtr);
1003 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1004 "Can't read EOF on tape\n");
1008 /* Mark tape as having been written */
1009 tapeEntryPtr->useKBytes =
1010 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1011 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1017 /* restoreDbFromTape
1018 * restore the backup database from tape.
1022 restoreDbFromTape(taskId)
1027 struct butm_tapeInfo tapeInfo;
1028 struct rstTapeInfo rstTapeInfo;
1029 struct budb_dumpEntry dumpEntry;
1031 extern struct tapeConfig globalTapeConfig;
1032 extern struct deviceSyncNode *deviceLatch;
1034 setStatus(taskId, DRIVE_WAIT);
1035 EnterDeviceQueue(deviceLatch); /* lock tape device */
1036 clearStatus(taskId, DRIVE_WAIT);
1039 TLog(taskId, "RestoreDb\n");
1041 tapeInfo.structVersion = BUTM_MAJORVERSION;
1042 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1044 ErrorLog(0, taskId, code, tapeInfo.error,
1045 "Can't initialize tape module\n");
1049 listEntryHead = NULL;
1051 rstTapeInfo.taskId = taskId;
1052 rstTapeInfo.tapeSeq = 1;
1053 rstTapeInfo.dumpid = 0;
1055 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1059 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1064 /* Now put this dump into the database */
1065 /* Make a dump entry from first tape */
1066 listEntryPtr = listEntryHead;
1068 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1069 if (dumpEntry.id != 0) {
1070 i = bcdb_CreateDump(&dumpEntry);
1072 if (i == BUDB_DUMPIDEXISTS)
1074 "Dump id %d not added to database - already exists\n",
1077 TapeLog(0, taskId, i, 0,
1078 "Dump id %d not added to database\n",
1081 i = addTapesToDb(taskId);
1085 i = bcdb_FinishDump(&dumpEntry);
1093 unmountTape(taskId, &tapeInfo);
1096 if (code == TC_ABORTEDBYREQUEST) {
1097 TLog(taskId, "RestoreDb: Aborted by request\n");
1098 clearStatus(taskId, ABORT_REQUEST);
1099 setStatus(taskId, ABORT_DONE);
1101 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1102 setStatus(taskId, TASK_ERROR);
1104 TLog(taskId, "RestoreDb: Finished\n");
1107 LeaveDeviceQueue(deviceLatch);
1108 setStatus(taskId, TASK_DONE);
1115 * While dumping the database, keeps the connection alive.
1116 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
1117 * This resets the database's internal timer so that it does not
1118 * prematuraly quit (on asking for new tapes and such).
1120 * Use the same udbHandle as writeDbDump so we go to the same server.
1129 extern struct udbHandleS udbHandle;
1132 #ifdef AFS_PTHREAD_ENV
1137 charList.charListT_val = 0;
1138 charList.charListT_len = 0;
1140 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1141 UF_SINGLESERVER, 0, 0, &charList, &done);
1150 * restore special items in the header
1153 restoreDbHeader(tapeInfo, rstTapeInfoPtr, nextHeader)
1154 struct butm_tapeInfo *tapeInfo;
1155 struct rstTapeInfo *rstTapeInfoPtr;
1156 struct structDumpHeader *nextHeader;
1158 struct structDumpHeader netItemHeader;
1159 struct DbHeader netDbHeader, hostDbHeader;
1162 extern struct udbHandleS udbHandle;
1164 /* Read the database header */
1165 memset(&netDbHeader, 0, sizeof(netDbHeader));
1167 getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1168 sizeof(netDbHeader));
1171 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1173 /* Add the database header to the database */
1175 ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1178 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1179 "Can't restore DB Header\n");
1183 /* get the next item-header */
1184 memset(nextHeader, 0, sizeof(*nextHeader));
1186 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1187 sizeof(netItemHeader));
1190 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1198 * restore a single dump, including all its tapes and volumes, from
1201 * nextHeader - ptr to structure for return value
1203 * nextHeader - next structure header from tape
1205 * upon entry, the dump structure header has been read confirming that
1206 * a database dump tree exists on the tape
1209 restoreDbDump(tapeInfo, rstTapeInfoPtr, nextHeader)
1210 struct butm_tapeInfo *tapeInfo;
1211 struct rstTapeInfo *rstTapeInfoPtr;
1212 struct structDumpHeader *nextHeader;
1214 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1215 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1216 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1217 struct structDumpHeader netItemHeader;
1219 int restoreThisDump = 1;
1222 extern struct udbHandleS udbHandle;
1224 taskId = rstTapeInfoPtr->taskId;
1226 /* read dump entry */
1227 memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1229 getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry,
1230 sizeof(netDumpEntry));
1234 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1235 if (rstTapeInfoPtr->dumpid == 0) {
1236 netDumpEntry.initialDumpID = 0;
1237 netDumpEntry.appendedDumpID = 0;
1240 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1242 /* The dump entry for this database tape is incomplete, so don't include it */
1243 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1244 restoreThisDump = 0;
1246 /* add the dump to the database */
1247 if (restoreThisDump) {
1249 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1255 /* get the next item-header */
1256 memset(nextHeader, 0, sizeof(*nextHeader));
1258 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1259 sizeof(netItemHeader));
1262 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1264 /* Add every tape to the db */
1265 while (nextHeader->type == SD_TAPE) { /*t */
1267 /* read the tape entry */
1268 memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1270 getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry,
1271 sizeof(netTapeEntry));
1274 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1276 /* Add the tape to the database */
1277 if (restoreThisDump) {
1279 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1285 /* get the next item-header */
1286 memset(nextHeader, 0, sizeof(*nextHeader));
1288 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1289 sizeof(netItemHeader));
1292 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1294 /* Add every volume to the db */
1295 while (nextHeader->type == SD_VOLUME) { /*v */
1297 /* read the volume entry */
1298 memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1300 getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry,
1301 sizeof(netVolumeEntry));
1304 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1306 if (restoreThisDump) {
1308 threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry),
1314 /* get the next item-header */
1315 memset(nextHeader, 0, sizeof(*nextHeader));
1317 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1318 sizeof(netItemHeader));
1321 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1324 /* Finish the tape */
1325 if (restoreThisDump) {
1327 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1334 /* Finish the dump */
1335 if (restoreThisDump) {
1337 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1348 * Save the specified file as configuration text in the ubik database.
1349 * Have to setup the client text structure so that we can call
1350 * the routine to transmit the text to the db.
1354 saveTextFile(taskId, textType, fileName)
1359 udbClientTextP ctPtr = 0;
1363 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1365 ERROR_EXIT(TC_NOMEMORY);
1367 memset(ctPtr, 0, sizeof(*ctPtr));
1368 ctPtr->textType = textType;
1370 /* lock the text in the database */
1371 code = bc_LockText(ctPtr);
1373 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1378 ctPtr->textStream = fopen(fileName, "r");
1379 if (!ctPtr->textStream) {
1380 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1384 /* now send the text to the database */
1385 code = bcdb_SaveTextFile(ctPtr);
1387 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1393 if (ctPtr->textStream)
1394 fclose(ctPtr->textStream);
1396 bc_UnlockText(ctPtr);
1403 * read the text off the tape, and store it in the appropriate
1404 * text type in the database.
1406 * nextHeader - ptr to struct for return information
1408 * nextHeader - struct header for next item on the tape
1411 restoreText(tapeInfo, rstTapeInfoPtr, nextHeader)
1412 struct butm_tapeInfo *tapeInfo;
1413 struct rstTapeInfo *rstTapeInfoPtr;
1414 struct structDumpHeader *nextHeader;
1418 char *readBuffer = 0;
1419 afs_int32 readBlockSize;
1420 afs_int32 transferSize;
1421 struct structDumpHeader netItemHeader;
1425 udbClientTextP ctPtr = 0;
1428 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1430 ERROR_EXIT(TC_NOMEMORY);
1432 /* determine the type of text block */
1433 switch (nextHeader->type) {
1434 case SD_TEXT_DUMPSCHEDULE:
1435 textType = TB_DUMPSCHEDULE;
1438 case SD_TEXT_VOLUMESET:
1439 textType = TB_VOLUMESET;
1442 case SD_TEXT_TAPEHOSTS:
1443 textType = TB_TAPEHOSTS;
1447 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0,
1448 "Unknown text block\n");
1449 ERROR_EXIT(TC_INTERNALERROR);
1453 /* open the text file */
1454 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1455 #if defined (HAVE_MKSTEMP)
1456 fid = mkstemp(filename);
1458 fid = open(mktemp(filename), O_RDWR | O_CREAT | O_EXCL, 0600);
1461 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1462 "Can't open temporary text file: %s\n", filename);
1466 /* allocate buffer for text */
1467 readBlockSize = BUTM_BLKSIZE;
1468 readBuffer = (char *)malloc(readBlockSize);
1470 ERROR_EXIT(TC_NOMEMORY);
1472 /* read the text into the temporary file */
1473 nbytes = nextHeader->size;
1474 while (nbytes > 0) {
1475 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1477 /* read it from the tape */
1479 getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1483 /* write to the file */
1484 if (write(fid, readBuffer, transferSize) != transferSize) {
1485 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1486 "Can't write temporary text file: %s\n", filename);
1490 nbytes -= transferSize;
1495 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1500 /* get the next item-header */
1501 memset(nextHeader, 0, sizeof(*nextHeader));
1503 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1504 sizeof(netItemHeader));
1507 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1522 /* ----------------------------------
1523 * Tape data buffering - for reading database dumps
1524 * ----------------------------------
1527 static char *tapeReadBuffer = 0; /* input buffer */
1528 static char *tapeReadBufferPtr = 0; /* position in buffer */
1531 * Read information from tape, and place the requested number of bytes
1532 * in the buffer supplied
1535 * rstTapeInfoPtr - Info about the dump being restored.
1536 * buffer - buffer for requested data
1537 * requestedBytes - no. of bytes requested
1539 * fn retn - 0, ok, n, error
1542 getTapeData(tapeInfoPtr, rstTapeInfoPtr, buffer, requestedBytes)
1543 struct butm_tapeInfo *tapeInfoPtr;
1544 struct rstTapeInfo *rstTapeInfoPtr;
1546 afs_int32 requestedBytes;
1548 afs_int32 taskId, transferBytes, new;
1552 taskId = rstTapeInfoPtr->taskId;
1554 if (checkAbortByTaskId(taskId))
1555 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1557 if (!tapeReadBuffer) {
1558 tapeReadBuffer = (char *)malloc(BUTM_BLOCKSIZE);
1559 if (!tapeReadBuffer)
1560 ERROR_EXIT(TC_NOMEMORY);
1563 while (requestedBytes > 0) {
1565 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1569 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1570 BUTM_BLKSIZE, &nbytes);
1572 /* detect if we hit the end-of-tape and get next tape */
1573 if (code == BUTM_ENDVOLUME) {
1574 /* Update fields in tape entry for this tape */
1575 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1576 tapeEntryPtr->useKBytes =
1577 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1579 unmountTape(taskId, tapeInfoPtr);
1581 rstTapeInfoPtr->tapeSeq++;
1582 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1586 code = butm_ReadFileBegin(tapeInfoPtr);
1588 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1589 "Can't read FileBegin on tape\n");
1596 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1597 "Can't read FileData on tape\n");
1603 transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1604 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1605 tapeReadBufferPtr += transferBytes;
1606 buffer += transferBytes;
1607 nbytes -= transferBytes;
1608 requestedBytes -= transferBytes;