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"
20 #include <sys/types.h>
30 #include <netinet/in.h>
36 #include <afs/afsint.h>
39 #include <afs/procmgmt.h>
40 #include <afs/afs_assert.h>
41 #include <afs/prs_fs.h>
46 #include <afs/cellconfig.h>
50 #include <afs/volser.h>
51 #include <afs/vlserver.h>
52 #include <afs/tcdata.h>
54 #include <afs/budb_client.h>
55 #include <afs/bubasics.h>
56 #include <afs/bucoord_prototypes.h>
57 #include <afs/butm_prototypes.h>
58 #include <afs/budb_prototypes.h>
59 #include <afs/afsutil.h>
60 #include "butc_internal.h"
61 #include "error_macros.h"
63 /* GLOBAL CONFIGURATION PARAMETERS */
64 #define BIGCHUNK 102400
66 extern int dump_namecheck;
75 static void initTapeBuffering(void);
76 static int writeDbDump(struct butm_tapeInfo *, afs_uint32, Date, afs_uint32);
77 static int restoreDbEntries(struct butm_tapeInfo *, struct rstTapeInfo *);
79 int getTapeData(struct butm_tapeInfo *, struct rstTapeInfo *, void *,
81 int restoreDbHeader(struct butm_tapeInfo *, struct rstTapeInfo *,
82 struct structDumpHeader *);
83 int restoreDbDump(struct butm_tapeInfo *, struct rstTapeInfo *,
84 struct structDumpHeader *);
85 int restoreText(struct butm_tapeInfo *, struct rstTapeInfo *,
86 struct structDumpHeader *);
90 void * KeepAlive(void *);
92 * create a dump entry for a saved database
96 CreateDBDump(struct budb_dumpEntry *dumpEntryPtr)
100 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
102 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
103 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
104 strcat(dumpEntryPtr->tapes.format, ".%d");
105 strcpy(dumpEntryPtr->volumeSetName, "");
106 strcpy(dumpEntryPtr->dumpPath, "");
107 dumpEntryPtr->created = 0; /* let database assign it */
108 dumpEntryPtr->incTime = 0;
109 dumpEntryPtr->nVolumes = 0;
110 dumpEntryPtr->initialDumpID = 0;
111 dumpEntryPtr->parent = 0;
112 dumpEntryPtr->level = 0;
113 dumpEntryPtr->tapes.maxTapes = 0;
114 dumpEntryPtr->tapes.b = 1;
116 /* now call the database to create the entry */
117 code = bcdb_CreateDump(dumpEntryPtr);
121 struct tapeEntryList {
122 struct tapeEntryList *next;
123 afs_uint32 oldDumpId;
124 struct budb_tapeEntry tapeEnt;
126 struct tapeEntryList *listEntryHead;
127 struct tapeEntryList *listEntryPtr;
128 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
129 struct budb_dumpEntry lastDump; /* the last dump of this volset */
132 * Load a DB tape, read and over write its label.
133 * Leave the tape mounted.
136 GetDBTape(afs_int32 taskId, Date expires, struct butm_tapeInfo *tapeInfoPtr,
137 afs_uint32 dumpid, afs_int32 sequence, int queryFlag,
142 char tapeName[BU_MAXTAPELEN];
149 struct butm_tapeLabel oldTapeLabel, newLabel;
150 struct tapeEntryList *endList;
152 /* construct the name of the tape */
153 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
155 interactiveFlag = queryFlag;
158 while (!*wroteLabel) { /*w */
159 if (interactiveFlag) { /* need a tape to write */
161 PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
169 code = butm_Mount(tapeInfoPtr, tapeName);
171 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
175 memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
176 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
178 oldTapeLabel.useCount = 0; /* no label exists */
179 oldTapeLabel.structVersion = 0;
180 strcpy(oldTapeLabel.pName, "");
182 /* If tape has a name, it must be null or database tape name */
183 if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
184 && !databaseTape(oldTapeLabel.AFSName)) {
185 char gotName[BU_MAXTAPELEN + 32];
187 LABELNAME(gotName, &oldTapeLabel);
189 "This tape %s must be a database tape or NULL tape\n",
193 unmountTape(taskId, tapeInfoPtr);
197 /* Do not overwrite a tape that belongs to this dump */
198 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
199 ErrorLog(0, taskId, 0, 0,
200 "Can't overwrite tape containing the dump in progress\n");
204 /* On first tape, the savedb has not started yet, so the database is not locked
205 * and we can therefore, access information from it. This is easier to do because
206 * database dumps don't have appended dumps (nor appended).
210 struct budb_dumpEntry de, de2;
212 /* Verify the tape has not expired
213 * Early database dumps don't have a dumpid
215 if (!tapeExpired(&oldTapeLabel)) {
216 TLog(taskId, "This tape has not expired\n");
220 /* Since the dumpset on this tape will be deleted from database, check if
221 * any of the dumps in this dumpset are most-recent-dumps.
223 for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
224 if (dmp == lastDump.id) {
225 memcpy(&de, &lastDump, sizeof(de));
226 memcpy(&de2, &lastDump, sizeof(de2));
228 code = bcdb_FindDumpByID(dmp, &de);
231 sprintf(strlevel, "%d", de.level);
233 bcdb_FindLatestDump(de.volumeSetName, strlevel,
239 if (de.id == de2.id) {
240 if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
241 ErrorLog(0, taskId, 0, 0,
242 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
245 ErrorLog(0, taskId, 0, 0,
246 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
247 de.volumeSetName, de.name, de.id);
253 /* Otherwise, the savedb is in progress and we can't
254 * access the database (it's locked). So we rely on the
255 * information available (and not the backup database).
258 /* Check the tape's expiration date. Use the expiration on the label */
259 gettimeofday(&tp, &tzp);
261 if (curTime < oldTapeLabel.expirationDate) {
262 TLog(taskId, "This tape has not expired\n");
266 /* Check if this previous-dump of the dump-in-progress is on this tape */
267 if (oldTapeLabel.dumpid
268 && (oldTapeLabel.dumpid == lastDump.id)) {
269 ErrorLog(0, taskId, 0, 0,
270 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
271 lastDump.name, lastDump.id);
277 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
278 newLabel.expirationDate = expires;
279 newLabel.useCount = oldTapeLabel.useCount + 1;
280 newLabel.dumpid = dumpid;
281 newLabel.size = tapeInfoPtr->tapeSize;
283 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
285 TapeLog(0, taskId, code, tapeInfoPtr->error,
286 "Can't label tape\n");
292 /* Initialize a tapeEntry for later inclusion into the database */
294 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
296 ERROR_EXIT(TC_NOMEMORY);
297 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
299 /* Remember dumpid so we can delete it later */
300 if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
301 && oldTapeLabel.dumpid)
302 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
304 /* Fill in tape entry so we can save it later */
305 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
306 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
307 tapeEntryPtr->written = newLabel.creationTime;
308 tapeEntryPtr->expires = expires;
309 tapeEntryPtr->seq = sequence;
310 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
311 tapeEntryPtr->dump = dumpid;
312 tapeEntryPtr->useKBytes = 0;
313 tapeEntryPtr->labelpos = 0;
315 /* Thread onto end of single-linked list */
317 endList = listEntryHead;
318 while (endList->next)
319 endList = endList->next;
320 endList->next = listEntryPtr;
322 listEntryHead = listEntryPtr;
330 * With the list of tapes, free the structures.
336 struct tapeEntryList *next;
338 listEntryPtr = listEntryHead;
339 while (listEntryPtr) {
340 next = listEntryPtr->next;
345 listEntryHead = NULL;
350 * With the list of tapes, add them to the database.
351 * Also delete any olddumpids that are around.
355 addTapesToDb(afs_int32 taskId)
359 struct tapeEntryList *next;
361 listEntryPtr = listEntryHead;
362 while (listEntryPtr) {
363 next = listEntryPtr->next;
365 /* Remove the old database entry */
366 if (listEntryPtr->oldDumpId) {
367 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
368 if (i && (i != BUDB_NOENT)) {
369 ErrorLog(0, taskId, i, 0,
370 "Unable to delete old DB entry %u.\n",
371 listEntryPtr->oldDumpId);
375 /* Add the tape to the database */
376 code = bcdb_UseTape(tapeEntryPtr, &new);
378 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n",
383 code = bcdb_FinishTape(tapeEntryPtr);
385 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n",
399 * this code assumes that the blocksize on reads is smaller than
400 * the blocksize on writes
404 writeDbDump(struct butm_tapeInfo *tapeInfoPtr, afs_uint32 taskId,
405 Date expires, afs_uint32 dumpid)
408 afs_int32 writeBufNbytes = 0;
409 char *writeBlock = 0;
410 char *writeBuffer = 0;
412 afs_int32 transferSize;
414 char *readBufPtr = NULL;
415 afs_int32 maxReadSize;
420 afs_int32 chunksize = 0;
421 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
425 #ifdef AFS_PTHREAD_ENV
427 pthread_attr_t tattr;
433 extern struct tapeConfig globalTapeConfig;
434 extern struct udbHandleS udbHandle;
436 blockSize = BUTM_BLKSIZE;
437 writeBlock = (char *)malloc(BUTM_BLOCKSIZE);
439 ERROR_EXIT(TC_NOMEMORY);
441 writeBuffer = writeBlock + sizeof(struct blockMark);
442 memset(writeBuffer, 0, BUTM_BLKSIZE);
446 * The margin of space to check for end of tape is set to the
447 * amount of space used to write an end-of-tape multiplied by 2.
448 * The amount of space is size of a 16K EODump marker, its EOF
449 * marker, and up to two EOF markers done on close (1 16K blocks +
452 tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
453 tc_KEndMargin = tc_EndMargin / 1024;
455 /* have to write enclose the dump in file marks */
456 code = butm_WriteFileBegin(tapeInfoPtr);
458 ErrorLog(0, taskId, code, tapeInfoPtr->error,
459 "Can't write FileBegin on tape\n");
463 writeBufPtr = &writeBuffer[0];
466 charList.charListT_val = 0;
467 charList.charListT_len = 0;
470 /* When no data in buffer, read data from the budb_server */
471 if (charList.charListT_len == 0) {
472 /* get more data. let rx allocate space */
473 if (charList.charListT_val) {
474 free(charList.charListT_val);
475 charList.charListT_val = 0;
480 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
481 UF_SINGLESERVER, firstcall,
482 maxReadSize, &charList, &done);
484 ErrorLog(0, taskId, code, 0, "Can't read database\n");
488 /* If this if the first call to the budb server, create a thread
489 * that will keep the connection alive (during tape changes).
492 #ifdef AFS_PTHREAD_ENV
493 code = pthread_attr_init(&tattr);
495 ErrorLog(0, taskId, code, 0,
496 "Can't pthread_attr_init Keep-alive process\n");
501 pthread_attr_setdetachstate(&tattr,
502 PTHREAD_CREATE_DETACHED);
504 ErrorLog(0, taskId, code, 0,
505 "Can't pthread_attr_setdetachstate Keep-alive process\n");
510 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
511 AFS_SIGSET_RESTORE();
514 LWP_CreateProcess(KeepAlive, 16384, 1, (void *)NULL,
515 "Keep-alive process", &alivePid);
517 /* XXX should we check code here ??? XXX */
521 readBufPtr = charList.charListT_val;
524 if ((charList.charListT_len == 0) && done)
527 /* compute how many bytes and transfer to the write Buffer */
529 (charList.charListT_len <
531 writeBufNbytes)) ? charList.charListT_len : (blockSize -
534 memcpy(writeBufPtr, readBufPtr, transferSize);
535 charList.charListT_len -= transferSize;
536 writeBufPtr += transferSize;
537 readBufPtr += transferSize;
538 writeBufNbytes += transferSize;
540 /* If filled the write buffer, then write it to tape */
541 if (writeBufNbytes == blockSize) {
542 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
544 ErrorLog(0, taskId, code, tapeInfoPtr->error,
545 "Can't write data on tape\n");
549 memset(writeBuffer, 0, blockSize);
550 writeBufPtr = &writeBuffer[0];
553 /* Every BIGCHUNK bytes check if aborted */
554 chunksize += blockSize;
555 if (chunksize > BIGCHUNK) {
557 if (checkAbortByTaskId(taskId))
558 ERROR_EXIT(TC_ABORTEDBYREQUEST);
562 * check if tape is full - since we filled a blockSize worth of data
563 * assume that there is more data.
565 kRemaining = butm_remainingKSpace(tapeInfoPtr);
566 if (kRemaining < tc_KEndMargin) {
567 code = butm_WriteFileEnd(tapeInfoPtr);
569 ErrorLog(0, taskId, code, tapeInfoPtr->error,
570 "Can't write FileEnd on tape\n");
574 code = butm_WriteEOT(tapeInfoPtr);
576 ErrorLog(0, taskId, code, tapeInfoPtr->error,
577 "Can't write end-of-dump on tape\n");
581 /* Mark tape as having been written */
582 tapeEntryPtr->useKBytes =
583 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
584 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
586 unmountTape(taskId, tapeInfoPtr);
588 /* Get next tape and writes its label */
591 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
596 code = butm_WriteFileBegin(tapeInfoPtr);
598 ErrorLog(0, taskId, code, tapeInfoPtr->error,
599 "Can't write FileBegin on tape\n");
606 /* no more data to be read - if necessary, flush out the last buffer */
607 if (writeBufNbytes > 0) {
608 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
610 ErrorLog(1, taskId, code, tapeInfoPtr->error,
611 "Can't write data on tape\n");
616 code = butm_WriteFileEnd(tapeInfoPtr);
618 ErrorLog(0, taskId, code, tapeInfoPtr->error,
619 "Can't write FileEnd on tape\n");
623 /* Mark tape as having been written */
624 tapeEntryPtr->useKBytes =
625 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
626 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
629 /* Let the KeepAlive process stop on its own */
631 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
632 UF_END_SINGLESERVER, 0);
636 if (charList.charListT_val)
637 free(charList.charListT_val);
642 * dump backup database to tape
646 saveDbToTape(void *param)
648 struct saveDbIf *saveDbIfPtr = (struct saveDbIf *)param;
655 struct butm_tapeInfo tapeInfo;
656 struct budb_dumpEntry dumpEntry;
658 extern struct deviceSyncNode *deviceLatch;
659 extern struct tapeConfig globalTapeConfig;
661 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
662 taskId = saveDbIfPtr->taskId;
664 setStatus(taskId, DRIVE_WAIT);
665 EnterDeviceQueue(deviceLatch); /* lock tape device */
666 clearStatus(taskId, DRIVE_WAIT);
669 TLog(taskId, "SaveDb\n");
671 tapeInfo.structVersion = BUTM_MAJORVERSION;
672 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
674 ErrorLog(0, taskId, code, tapeInfo.error,
675 "Can't initialize tape module\n");
679 /* Determine what the last database dump was */
680 memset(&lastDump, 0, sizeof(lastDump));
681 code = bcdb_FindLatestDump("", "", &lastDump);
683 if (code != BUDB_NODUMPNAME) {
684 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
687 memset(&lastDump, 0, sizeof(lastDump));
690 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
692 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
697 listEntryHead = NULL;
699 /* Get the tape and write a new label to it */
701 GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
705 * If did not write the label, remove created dump
706 * Else if wrote the label, remove old dump from db so it's not saved.
709 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
711 if (i && (i != BUDB_NOENT))
712 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
714 } else if (listEntryHead->oldDumpId) {
715 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
716 listEntryHead->oldDumpId = 0;
717 if (i && (i != BUDB_NOENT)) {
718 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
719 listEntryHead->oldDumpId);
726 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
728 /* we have a writable tape */
729 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
733 /* Now delete the entries between time 0 and archive-time */
734 if (saveDbIfPtr->archiveTime)
735 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
738 unmountTape(taskId, &tapeInfo);
740 /* Add this dump's tapes to the database and mark it finished */
742 i = addTapesToDb(taskId);
746 i = bcdb_FinishDump(&dumpEntry);
752 if (code == TC_ABORTEDBYREQUEST) {
753 TLog(taskId, "SaveDb: Aborted by request\n");
754 clearStatus(taskId, ABORT_REQUEST);
755 setStatus(taskId, ABORT_DONE);
757 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
758 setStatus(taskId, TASK_ERROR);
760 TLog(taskId, "SaveDb: Finished\n");
762 setStatus(taskId, TASK_DONE);
765 LeaveDeviceQueue(deviceLatch);
766 return (void *)(intptr_t)(code);
771 * Make a database dump entry given a tape label.
775 makeDbDumpEntry(struct budb_tapeEntry *tapeEntPtr,
776 struct budb_dumpEntry *dumpEntryPtr)
778 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
780 dumpEntryPtr->id = tapeEntPtr->dump;
781 dumpEntryPtr->initialDumpID = 0;
782 dumpEntryPtr->parent = 0;
783 dumpEntryPtr->level = 0;
784 dumpEntryPtr->flags = 0;
786 strcpy(dumpEntryPtr->volumeSetName, "");
787 strcpy(dumpEntryPtr->dumpPath, "");
788 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
790 dumpEntryPtr->created = tapeEntPtr->dump;
791 dumpEntryPtr->incTime = 0;
792 dumpEntryPtr->nVolumes = 0;
794 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
795 strcat(dumpEntryPtr->tapes.format, ".%d");
796 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
797 dumpEntryPtr->tapes.maxTapes = 0;
802 * prompt for a specific database tape
806 readDbTape(struct butm_tapeInfo *tapeInfoPtr,
807 struct rstTapeInfo *rstTapeInfoPtr, int query)
812 struct butm_tapeLabel oldTapeLabel;
813 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
814 struct tapeEntryList *endList;
816 struct budb_dumpEntry de;
817 struct budb_tapeEntry te;
819 taskId = rstTapeInfoPtr->taskId;
820 interactiveFlag = query;
822 /* construct the name of the tape */
823 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
824 strcpy(tapeName, AFStapeName);
826 /* Will prompt for the latest saved database tape, but will accept any one */
827 if (rstTapeInfoPtr->tapeSeq == 1) {
828 code = bcdb_FindLatestDump("", "", &de);
830 rstTapeInfoPtr->dumpid = de.id;
832 if (rstTapeInfoPtr->dumpid) {
834 bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
837 strcpy(tapeName, te.name);
842 if (interactiveFlag) { /* need a tape to read */
844 PromptForTape(RESTOREDBOPCODE, tapeName,
845 rstTapeInfoPtr->dumpid, taskId, tapecount);
852 code = butm_Mount(tapeInfoPtr, tapeName);
854 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
858 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
860 TapeLog(0, taskId, code, tapeInfoPtr->error,
861 "Can't read tape label\n");
865 /* Check for name of tape and matching dump id (if applicable). */
866 if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
867 || ((rstTapeInfoPtr->tapeSeq != 1)
868 && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
869 char expTape[BU_MAXTAPELEN + 32];
870 char gotTape[BU_MAXTAPELEN + 32];
872 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
873 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
875 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
880 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
881 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
886 unmountTape(taskId, tapeInfoPtr);
890 /* Initialize a tapeEntry for later inclusion into the database */
892 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
894 ERROR_EXIT(TC_NOMEMORY);
895 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
897 /* Fill in tape entry so we can save it later */
898 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
899 tapeEntryPtr->dump = oldTapeLabel.dumpid;
900 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
901 tapeEntryPtr->written = oldTapeLabel.creationTime;
902 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
903 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
904 tapeEntryPtr->useCount = oldTapeLabel.useCount;
905 tapeEntryPtr->useKBytes = 0;
906 tapeEntryPtr->labelpos = 0;
908 /* Thread onto end of single-linked list */
910 endList = listEntryHead;
911 while (endList->next)
912 endList = endList->next;
913 endList->next = listEntryPtr;
915 listEntryHead = listEntryPtr;
921 static afs_int32 nbytes = 0; /* # bytes left in buffer */
923 initTapeBuffering(void)
930 * restore all the items on the tape
932 * tape positioned after tape label
936 restoreDbEntries(struct butm_tapeInfo *tapeInfoPtr,
937 struct rstTapeInfo *rstTapeInfoPtr)
939 struct structDumpHeader netItemHeader, hostItemHeader;
941 afs_int32 taskId, code = 0;
944 taskId = rstTapeInfoPtr->taskId;
946 /* clear state for the buffer routine(s) */
949 code = butm_ReadFileBegin(tapeInfoPtr);
951 ErrorLog(0, taskId, code, tapeInfoPtr->error,
952 "Can't read FileBegin on tape\n");
956 /* get the first item-header */
957 memset(&netItemHeader, 0, sizeof(netItemHeader));
959 getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
960 sizeof(netItemHeader));
963 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
966 switch (hostItemHeader.type) {
969 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
975 if (++count > 25) { /*every 25 dumps, wait */
980 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
990 case SD_TEXT_DUMPSCHEDULE:
991 case SD_TEXT_VOLUMESET:
992 case SD_TEXT_TAPEHOSTS:
993 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
1003 TLog(taskId, "Unknown database header type %d\n",
1004 hostItemHeader.type);
1010 code = butm_ReadFileEnd(tapeInfoPtr);
1012 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1013 "Can't read EOF on tape\n");
1017 /* Mark tape as having been written */
1018 tapeEntryPtr->useKBytes =
1019 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1020 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1026 /* restoreDbFromTape
1027 * restore the backup database from tape.
1031 restoreDbFromTape(void *param)
1033 afs_uint32 taskId = (intptr_t) param;
1036 struct butm_tapeInfo tapeInfo;
1037 struct rstTapeInfo rstTapeInfo;
1038 struct budb_dumpEntry dumpEntry;
1040 extern struct tapeConfig globalTapeConfig;
1041 extern struct deviceSyncNode *deviceLatch;
1043 setStatus(taskId, DRIVE_WAIT);
1044 EnterDeviceQueue(deviceLatch); /* lock tape device */
1045 clearStatus(taskId, DRIVE_WAIT);
1048 TLog(taskId, "RestoreDb\n");
1050 tapeInfo.structVersion = BUTM_MAJORVERSION;
1051 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1053 ErrorLog(0, taskId, code, tapeInfo.error,
1054 "Can't initialize tape module\n");
1058 listEntryHead = NULL;
1060 rstTapeInfo.taskId = taskId;
1061 rstTapeInfo.tapeSeq = 1;
1062 rstTapeInfo.dumpid = 0;
1064 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1068 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1073 /* Now put this dump into the database */
1074 /* Make a dump entry from first tape */
1075 listEntryPtr = listEntryHead;
1077 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1078 if (dumpEntry.id != 0) {
1079 i = bcdb_CreateDump(&dumpEntry);
1081 if (i == BUDB_DUMPIDEXISTS)
1083 "Dump id %d not added to database - already exists\n",
1086 TapeLog(0, taskId, i, 0,
1087 "Dump id %d not added to database\n",
1090 i = addTapesToDb(taskId);
1094 i = bcdb_FinishDump(&dumpEntry);
1102 unmountTape(taskId, &tapeInfo);
1105 if (code == TC_ABORTEDBYREQUEST) {
1106 TLog(taskId, "RestoreDb: Aborted by request\n");
1107 clearStatus(taskId, ABORT_REQUEST);
1108 setStatus(taskId, ABORT_DONE);
1110 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1111 setStatus(taskId, TASK_ERROR);
1113 TLog(taskId, "RestoreDb: Finished\n");
1116 LeaveDeviceQueue(deviceLatch);
1117 setStatus(taskId, TASK_DONE);
1119 return (void *)(intptr_t)(code);
1124 * While dumping the database, keeps the connection alive.
1125 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
1126 * This resets the database's internal timer so that it does not
1127 * prematuraly quit (on asking for new tapes and such).
1129 * Use the same udbHandle as writeDbDump so we go to the same server.
1132 KeepAlive(void *unused)
1138 extern struct udbHandleS udbHandle;
1141 #ifdef AFS_PTHREAD_ENV
1146 charList.charListT_val = 0;
1147 charList.charListT_len = 0;
1149 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1150 UF_SINGLESERVER, 0, 0, &charList, &done);
1159 * restore special items in the header
1163 restoreDbHeader(struct butm_tapeInfo *tapeInfo,
1164 struct rstTapeInfo *rstTapeInfoPtr,
1165 struct structDumpHeader *nextHeader)
1167 struct structDumpHeader netItemHeader;
1168 struct DbHeader netDbHeader, hostDbHeader;
1171 extern struct udbHandleS udbHandle;
1173 /* Read the database header */
1174 memset(&netDbHeader, 0, sizeof(netDbHeader));
1176 getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1177 sizeof(netDbHeader));
1180 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1182 /* Add the database header to the database */
1184 ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1187 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1188 "Can't restore DB Header\n");
1192 /* get the next item-header */
1193 memset(nextHeader, 0, sizeof(*nextHeader));
1195 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1196 sizeof(netItemHeader));
1199 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1207 * restore a single dump, including all its tapes and volumes, from
1210 * nextHeader - ptr to structure for return value
1212 * nextHeader - next structure header from tape
1214 * upon entry, the dump structure header has been read confirming that
1215 * a database dump tree exists on the tape
1219 restoreDbDump(struct butm_tapeInfo *tapeInfo,
1220 struct rstTapeInfo *rstTapeInfoPtr,
1221 struct structDumpHeader *nextHeader)
1223 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1224 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1225 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1226 struct structDumpHeader netItemHeader;
1227 int restoreThisDump = 1;
1230 extern struct udbHandleS udbHandle;
1232 /* read dump entry */
1233 memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1235 getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry,
1236 sizeof(netDumpEntry));
1240 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1241 if (rstTapeInfoPtr->dumpid == 0) {
1242 netDumpEntry.initialDumpID = 0;
1243 netDumpEntry.appendedDumpID = 0;
1246 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1248 /* The dump entry for this database tape is incomplete, so don't include it */
1249 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1250 restoreThisDump = 0;
1252 /* add the dump to the database */
1253 if (restoreThisDump) {
1255 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1261 /* get the next item-header */
1262 memset(nextHeader, 0, sizeof(*nextHeader));
1264 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1265 sizeof(netItemHeader));
1268 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1270 /* Add every tape to the db */
1271 while (nextHeader->type == SD_TAPE) { /*t */
1273 /* read the tape entry */
1274 memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1276 getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry,
1277 sizeof(netTapeEntry));
1280 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1282 /* Add the tape to the database */
1283 if (restoreThisDump) {
1285 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1291 /* get the next item-header */
1292 memset(nextHeader, 0, sizeof(*nextHeader));
1294 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1295 sizeof(netItemHeader));
1298 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1300 /* Add every volume to the db */
1301 while (nextHeader->type == SD_VOLUME) { /*v */
1303 /* read the volume entry */
1304 memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1306 getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry,
1307 sizeof(netVolumeEntry));
1310 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1312 if (restoreThisDump) {
1314 threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry),
1320 /* get the next item-header */
1321 memset(nextHeader, 0, sizeof(*nextHeader));
1323 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1324 sizeof(netItemHeader));
1327 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1330 /* Finish the tape */
1331 if (restoreThisDump) {
1333 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1340 /* Finish the dump */
1341 if (restoreThisDump) {
1343 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1354 * Save the specified file as configuration text in the ubik database.
1355 * Have to setup the client text structure so that we can call
1356 * the routine to transmit the text to the db.
1360 saveTextFile(afs_int32 taskId, afs_int32 textType, char *fileName)
1362 udbClientTextP ctPtr = 0;
1366 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1368 ERROR_EXIT(TC_NOMEMORY);
1370 memset(ctPtr, 0, sizeof(*ctPtr));
1371 ctPtr->textType = textType;
1373 /* lock the text in the database */
1374 code = bc_LockText(ctPtr);
1376 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1381 ctPtr->textStream = fopen(fileName, "r");
1382 if (!ctPtr->textStream) {
1383 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1387 /* now send the text to the database */
1388 code = bcdb_SaveTextFile(ctPtr);
1390 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1396 if (ctPtr->textStream)
1397 fclose(ctPtr->textStream);
1399 bc_UnlockText(ctPtr);
1406 * read the text off the tape, and store it in the appropriate
1407 * text type in the database.
1409 * nextHeader - ptr to struct for return information
1411 * nextHeader - struct header for next item on the tape
1415 restoreText(struct butm_tapeInfo *tapeInfo,
1416 struct rstTapeInfo *rstTapeInfoPtr,
1417 struct structDumpHeader *nextHeader)
1421 char *readBuffer = 0;
1422 afs_int32 readBlockSize;
1423 afs_int32 transferSize;
1424 struct structDumpHeader netItemHeader;
1428 udbClientTextP ctPtr = 0;
1431 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1433 ERROR_EXIT(TC_NOMEMORY);
1435 /* determine the type of text block */
1436 switch (nextHeader->type) {
1437 case SD_TEXT_DUMPSCHEDULE:
1438 textType = TB_DUMPSCHEDULE;
1441 case SD_TEXT_VOLUMESET:
1442 textType = TB_VOLUMESET;
1445 case SD_TEXT_TAPEHOSTS:
1446 textType = TB_TAPEHOSTS;
1450 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0,
1451 "Unknown text block\n");
1452 ERROR_EXIT(TC_INTERNALERROR);
1456 /* open the text file */
1457 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1458 fid = mkstemp(filename);
1460 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1461 "Can't open temporary text file: %s\n", filename);
1465 /* allocate buffer for text */
1466 readBlockSize = BUTM_BLKSIZE;
1467 readBuffer = (char *)malloc(readBlockSize);
1469 ERROR_EXIT(TC_NOMEMORY);
1471 /* read the text into the temporary file */
1472 nbytes = nextHeader->size;
1473 while (nbytes > 0) {
1474 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1476 /* read it from the tape */
1478 getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1482 /* write to the file */
1483 if (write(fid, readBuffer, transferSize) != transferSize) {
1484 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1485 "Can't write temporary text file: %s\n", filename);
1489 nbytes -= transferSize;
1494 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1499 /* get the next item-header */
1500 memset(nextHeader, 0, sizeof(*nextHeader));
1502 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1503 sizeof(netItemHeader));
1506 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1521 /* ----------------------------------
1522 * Tape data buffering - for reading database dumps
1523 * ----------------------------------
1526 static char *tapeReadBuffer = 0; /* input buffer */
1527 static char *tapeReadBufferPtr = 0; /* position in buffer */
1530 * Read information from tape, and place the requested number of bytes
1531 * in the buffer supplied
1534 * rstTapeInfoPtr - Info about the dump being restored.
1535 * buffer - buffer for requested data
1536 * requestedBytes - no. of bytes requested
1538 * fn retn - 0, ok, n, error
1542 getTapeData(struct butm_tapeInfo *tapeInfoPtr,
1543 struct rstTapeInfo *rstTapeInfoPtr,
1544 void *out, afs_int32 requestedBytes)
1546 char *buffer = (char *) out;
1547 afs_int32 taskId, transferBytes;
1550 taskId = rstTapeInfoPtr->taskId;
1552 if (checkAbortByTaskId(taskId))
1553 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1555 if (!tapeReadBuffer) {
1556 tapeReadBuffer = (char *)malloc(BUTM_BLOCKSIZE);
1557 if (!tapeReadBuffer)
1558 ERROR_EXIT(TC_NOMEMORY);
1561 while (requestedBytes > 0) {
1563 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1567 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1568 BUTM_BLKSIZE, &nbytes);
1570 /* detect if we hit the end-of-tape and get next tape */
1571 if (code == BUTM_ENDVOLUME) {
1572 /* Update fields in tape entry for this tape */
1573 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1574 tapeEntryPtr->useKBytes =
1575 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1577 unmountTape(taskId, tapeInfoPtr);
1579 rstTapeInfoPtr->tapeSeq++;
1580 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1584 code = butm_ReadFileBegin(tapeInfoPtr);
1586 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1587 "Can't read FileBegin on tape\n");
1594 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1595 "Can't read FileData on tape\n");
1601 transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1602 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1603 tapeReadBufferPtr += transferBytes;
1604 buffer += transferBytes;
1605 nbytes -= transferBytes;
1606 requestedBytes -= transferBytes;