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 #ifdef IGNORE_SOME_GCC_WARNINGS
14 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
17 #include <sys/types.h>
27 #include <netinet/in.h>
33 #include <afs/afsint.h>
36 #include <afs/procmgmt.h>
37 #include <afs/assert.h>
38 #include <afs/prs_fs.h>
43 #include <afs/cellconfig.h>
47 #include <afs/volser.h>
48 #include <afs/vlserver.h>
49 #include <afs/tcdata.h>
51 #include <afs/budb_client.h>
52 #include <afs/bubasics.h>
53 #include <afs/bucoord_prototypes.h>
54 #include <afs/butm_prototypes.h>
55 #include <afs/budb_prototypes.h>
56 #include <afs/afsutil.h>
57 #include "butc_internal.h"
58 #include "error_macros.h"
60 /* GLOBAL CONFIGURATION PARAMETERS */
61 #define BIGCHUNK 102400
63 extern int dump_namecheck;
72 static void initTapeBuffering(void);
73 static int writeDbDump(struct butm_tapeInfo *, afs_uint32, Date, afs_uint32);
74 static int restoreDbEntries(struct butm_tapeInfo *, struct rstTapeInfo *);
76 int getTapeData(struct butm_tapeInfo *, struct rstTapeInfo *, void *,
78 int restoreDbHeader(struct butm_tapeInfo *, struct rstTapeInfo *,
79 struct structDumpHeader *);
80 int restoreDbDump(struct butm_tapeInfo *, struct rstTapeInfo *,
81 struct structDumpHeader *);
82 int restoreText(struct butm_tapeInfo *, struct rstTapeInfo *,
83 struct structDumpHeader *);
87 void * KeepAlive(void *);
89 * create a dump entry for a saved database
93 CreateDBDump(struct budb_dumpEntry *dumpEntryPtr)
97 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
99 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
100 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
101 strcat(dumpEntryPtr->tapes.format, ".%d");
102 strcpy(dumpEntryPtr->volumeSetName, "");
103 strcpy(dumpEntryPtr->dumpPath, "");
104 dumpEntryPtr->created = 0; /* let database assign it */
105 dumpEntryPtr->incTime = 0;
106 dumpEntryPtr->nVolumes = 0;
107 dumpEntryPtr->initialDumpID = 0;
108 dumpEntryPtr->parent = 0;
109 dumpEntryPtr->level = 0;
110 dumpEntryPtr->tapes.maxTapes = 0;
111 dumpEntryPtr->tapes.b = 1;
113 /* now call the database to create the entry */
114 code = bcdb_CreateDump(dumpEntryPtr);
118 struct tapeEntryList {
119 struct tapeEntryList *next;
120 afs_uint32 oldDumpId;
121 struct budb_tapeEntry tapeEnt;
123 struct tapeEntryList *listEntryHead;
124 struct tapeEntryList *listEntryPtr;
125 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
126 struct budb_dumpEntry lastDump; /* the last dump of this volset */
129 * Load a DB tape, read and over write its label.
130 * Leave the tape mounted.
133 GetDBTape(afs_int32 taskId, Date expires, struct butm_tapeInfo *tapeInfoPtr,
134 afs_uint32 dumpid, afs_int32 sequence, int queryFlag,
139 char tapeName[BU_MAXTAPELEN];
146 struct butm_tapeLabel oldTapeLabel, newLabel;
147 struct tapeEntryList *endList;
149 /* construct the name of the tape */
150 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
152 interactiveFlag = queryFlag;
155 while (!*wroteLabel) { /*w */
156 if (interactiveFlag) { /* need a tape to write */
158 PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
166 code = butm_Mount(tapeInfoPtr, tapeName);
168 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
172 memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
173 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
175 oldTapeLabel.useCount = 0; /* no label exists */
176 oldTapeLabel.structVersion = 0;
177 strcpy(oldTapeLabel.pName, "");
179 /* If tape has a name, it must be null or database tape name */
180 if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
181 && !databaseTape(oldTapeLabel.AFSName)) {
182 char gotName[BU_MAXTAPELEN + 32];
184 LABELNAME(gotName, &oldTapeLabel);
186 "This tape %s must be a database tape or NULL tape\n",
190 unmountTape(taskId, tapeInfoPtr);
194 /* Do not overwrite a tape that belongs to this dump */
195 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
196 ErrorLog(0, taskId, 0, 0,
197 "Can't overwrite tape containing the dump in progress\n");
201 /* On first tape, the savedb has not started yet, so the database is not locked
202 * and we can therefore, access information from it. This is easier to do because
203 * database dumps don't have appended dumps (nor appended).
207 struct budb_dumpEntry de, de2;
209 /* Verify the tape has not expired
210 * Early database dumps don't have a dumpid
212 if (!tapeExpired(&oldTapeLabel)) {
213 TLog(taskId, "This tape has not expired\n");
217 /* Since the dumpset on this tape will be deleted from database, check if
218 * any of the dumps in this dumpset are most-recent-dumps.
220 for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
221 if (dmp == lastDump.id) {
222 memcpy(&de, &lastDump, sizeof(de));
223 memcpy(&de2, &lastDump, sizeof(de2));
225 code = bcdb_FindDumpByID(dmp, &de);
228 sprintf(strlevel, "%d", de.level);
230 bcdb_FindLatestDump(de.volumeSetName, strlevel,
236 if (de.id == de2.id) {
237 if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
238 ErrorLog(0, taskId, 0, 0,
239 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
242 ErrorLog(0, taskId, 0, 0,
243 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
244 de.volumeSetName, de.name, de.id);
250 /* Otherwise, the savedb is in progress and we can't
251 * access the database (it's locked). So we rely on the
252 * information available (and not the backup database).
255 /* Check the tape's expiration date. Use the expiration on the label */
256 gettimeofday(&tp, &tzp);
258 if (curTime < oldTapeLabel.expirationDate) {
259 TLog(taskId, "This tape has not expired\n");
263 /* Check if this previous-dump of the dump-in-progress is on this tape */
264 if (oldTapeLabel.dumpid
265 && (oldTapeLabel.dumpid == lastDump.id)) {
266 ErrorLog(0, taskId, 0, 0,
267 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
268 lastDump.name, lastDump.id);
274 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
275 newLabel.expirationDate = expires;
276 newLabel.useCount = oldTapeLabel.useCount + 1;
277 newLabel.dumpid = dumpid;
278 newLabel.size = tapeInfoPtr->tapeSize;
280 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
282 TapeLog(0, taskId, code, tapeInfoPtr->error,
283 "Can't label tape\n");
289 /* Initialize a tapeEntry for later inclusion into the database */
291 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
293 ERROR_EXIT(TC_NOMEMORY);
294 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
296 /* Remember dumpid so we can delete it later */
297 if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
298 && oldTapeLabel.dumpid)
299 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
301 /* Fill in tape entry so we can save it later */
302 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
303 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
304 tapeEntryPtr->written = newLabel.creationTime;
305 tapeEntryPtr->expires = expires;
306 tapeEntryPtr->seq = sequence;
307 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
308 tapeEntryPtr->dump = dumpid;
309 tapeEntryPtr->useKBytes = 0;
310 tapeEntryPtr->labelpos = 0;
312 /* Thread onto end of single-linked list */
314 endList = listEntryHead;
315 while (endList->next)
316 endList = endList->next;
317 endList->next = listEntryPtr;
319 listEntryHead = listEntryPtr;
327 * With the list of tapes, free the structures.
333 struct tapeEntryList *next;
335 listEntryPtr = listEntryHead;
336 while (listEntryPtr) {
337 next = listEntryPtr->next;
342 listEntryHead = NULL;
347 * With the list of tapes, add them to the database.
348 * Also delete any olddumpids that are around.
352 addTapesToDb(afs_int32 taskId)
356 struct tapeEntryList *next;
358 listEntryPtr = listEntryHead;
359 while (listEntryPtr) {
360 next = listEntryPtr->next;
362 /* Remove the old database entry */
363 if (listEntryPtr->oldDumpId) {
364 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
365 if (i && (i != BUDB_NOENT)) {
366 ErrorLog(0, taskId, i, 0,
367 "Unable to delete old DB entry %u.\n",
368 listEntryPtr->oldDumpId);
372 /* Add the tape to the database */
373 code = bcdb_UseTape(tapeEntryPtr, &new);
375 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n",
380 code = bcdb_FinishTape(tapeEntryPtr);
382 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n",
396 * this code assumes that the blocksize on reads is smaller than
397 * the blocksize on writes
401 writeDbDump(struct butm_tapeInfo *tapeInfoPtr, afs_uint32 taskId,
402 Date expires, afs_uint32 dumpid)
405 afs_int32 writeBufNbytes = 0;
406 char *writeBlock = 0;
407 char *writeBuffer = 0;
409 afs_int32 transferSize;
411 char *readBufPtr = NULL;
412 afs_int32 maxReadSize;
417 afs_int32 chunksize = 0;
418 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
422 #ifdef AFS_PTHREAD_ENV
424 pthread_attr_t tattr;
430 extern struct tapeConfig globalTapeConfig;
431 extern struct udbHandleS udbHandle;
433 blockSize = BUTM_BLKSIZE;
434 writeBlock = (char *)malloc(BUTM_BLOCKSIZE);
436 ERROR_EXIT(TC_NOMEMORY);
438 writeBuffer = writeBlock + sizeof(struct blockMark);
439 memset(writeBuffer, 0, BUTM_BLKSIZE);
443 * The margin of space to check for end of tape is set to the
444 * amount of space used to write an end-of-tape multiplied by 2.
445 * The amount of space is size of a 16K EODump marker, its EOF
446 * marker, and up to two EOF markers done on close (1 16K blocks +
449 tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
450 tc_KEndMargin = tc_EndMargin / 1024;
452 /* have to write enclose the dump in file marks */
453 code = butm_WriteFileBegin(tapeInfoPtr);
455 ErrorLog(0, taskId, code, tapeInfoPtr->error,
456 "Can't write FileBegin on tape\n");
460 writeBufPtr = &writeBuffer[0];
463 charList.charListT_val = 0;
464 charList.charListT_len = 0;
467 /* When no data in buffer, read data from the budb_server */
468 if (charList.charListT_len == 0) {
469 /* get more data. let rx allocate space */
470 if (charList.charListT_val) {
471 free(charList.charListT_val);
472 charList.charListT_val = 0;
477 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
478 UF_SINGLESERVER, firstcall,
479 maxReadSize, &charList, &done);
481 ErrorLog(0, taskId, code, 0, "Can't read database\n");
485 /* If this if the first call to the budb server, create a thread
486 * that will keep the connection alive (during tape changes).
489 #ifdef AFS_PTHREAD_ENV
490 code = pthread_attr_init(&tattr);
492 ErrorLog(0, taskId, code, 0,
493 "Can't pthread_attr_init Keep-alive process\n");
498 pthread_attr_setdetachstate(&tattr,
499 PTHREAD_CREATE_DETACHED);
501 ErrorLog(0, taskId, code, 0,
502 "Can't pthread_attr_setdetachstate Keep-alive process\n");
507 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
508 AFS_SIGSET_RESTORE();
511 LWP_CreateProcess(KeepAlive, 16384, 1, (void *)NULL,
512 "Keep-alive process", &alivePid);
514 /* XXX should we check code here ??? XXX */
518 readBufPtr = charList.charListT_val;
521 if ((charList.charListT_len == 0) && done)
524 /* compute how many bytes and transfer to the write Buffer */
526 (charList.charListT_len <
528 writeBufNbytes)) ? charList.charListT_len : (blockSize -
531 memcpy(writeBufPtr, readBufPtr, transferSize);
532 charList.charListT_len -= transferSize;
533 writeBufPtr += transferSize;
534 readBufPtr += transferSize;
535 writeBufNbytes += transferSize;
537 /* If filled the write buffer, then write it to tape */
538 if (writeBufNbytes == blockSize) {
539 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
541 ErrorLog(0, taskId, code, tapeInfoPtr->error,
542 "Can't write data on tape\n");
546 memset(writeBuffer, 0, blockSize);
547 writeBufPtr = &writeBuffer[0];
550 /* Every BIGCHUNK bytes check if aborted */
551 chunksize += blockSize;
552 if (chunksize > BIGCHUNK) {
554 if (checkAbortByTaskId(taskId))
555 ERROR_EXIT(TC_ABORTEDBYREQUEST);
559 * check if tape is full - since we filled a blockSize worth of data
560 * assume that there is more data.
562 kRemaining = butm_remainingKSpace(tapeInfoPtr);
563 if (kRemaining < tc_KEndMargin) {
564 code = butm_WriteFileEnd(tapeInfoPtr);
566 ErrorLog(0, taskId, code, tapeInfoPtr->error,
567 "Can't write FileEnd on tape\n");
571 code = butm_WriteEOT(tapeInfoPtr);
573 ErrorLog(0, taskId, code, tapeInfoPtr->error,
574 "Can't write end-of-dump on tape\n");
578 /* Mark tape as having been written */
579 tapeEntryPtr->useKBytes =
580 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
581 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
583 unmountTape(taskId, tapeInfoPtr);
585 /* Get next tape and writes its label */
588 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
593 code = butm_WriteFileBegin(tapeInfoPtr);
595 ErrorLog(0, taskId, code, tapeInfoPtr->error,
596 "Can't write FileBegin on tape\n");
603 /* no more data to be read - if necessary, flush out the last buffer */
604 if (writeBufNbytes > 0) {
605 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
607 ErrorLog(1, taskId, code, tapeInfoPtr->error,
608 "Can't write data on tape\n");
613 code = butm_WriteFileEnd(tapeInfoPtr);
615 ErrorLog(0, taskId, code, tapeInfoPtr->error,
616 "Can't write FileEnd on tape\n");
620 /* Mark tape as having been written */
621 tapeEntryPtr->useKBytes =
622 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
623 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
626 /* Let the KeepAlive process stop on its own */
628 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
629 UF_END_SINGLESERVER, 0);
633 if (charList.charListT_val)
634 free(charList.charListT_val);
639 * dump backup database to tape
643 saveDbToTape(void *param)
645 struct saveDbIf *saveDbIfPtr = (struct saveDbIf *)param;
652 struct butm_tapeInfo tapeInfo;
653 struct budb_dumpEntry dumpEntry;
655 extern struct deviceSyncNode *deviceLatch;
656 extern struct tapeConfig globalTapeConfig;
658 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
659 taskId = saveDbIfPtr->taskId;
661 setStatus(taskId, DRIVE_WAIT);
662 EnterDeviceQueue(deviceLatch); /* lock tape device */
663 clearStatus(taskId, DRIVE_WAIT);
666 TLog(taskId, "SaveDb\n");
668 tapeInfo.structVersion = BUTM_MAJORVERSION;
669 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
671 ErrorLog(0, taskId, code, tapeInfo.error,
672 "Can't initialize tape module\n");
676 /* Determine what the last database dump was */
677 memset(&lastDump, 0, sizeof(lastDump));
678 code = bcdb_FindLatestDump("", "", &lastDump);
680 if (code != BUDB_NODUMPNAME) {
681 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
684 memset(&lastDump, 0, sizeof(lastDump));
687 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
689 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
694 listEntryHead = NULL;
696 /* Get the tape and write a new label to it */
698 GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
702 * If did not write the label, remove created dump
703 * Else if wrote the label, remove old dump from db so it's not saved.
706 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
708 if (i && (i != BUDB_NOENT))
709 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
711 } else if (listEntryHead->oldDumpId) {
712 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
713 listEntryHead->oldDumpId = 0;
714 if (i && (i != BUDB_NOENT)) {
715 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
716 listEntryHead->oldDumpId);
723 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
725 /* we have a writable tape */
726 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
730 /* Now delete the entries between time 0 and archive-time */
731 if (saveDbIfPtr->archiveTime)
732 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
735 unmountTape(taskId, &tapeInfo);
737 /* Add this dump's tapes to the database and mark it finished */
739 i = addTapesToDb(taskId);
743 i = bcdb_FinishDump(&dumpEntry);
749 if (code == TC_ABORTEDBYREQUEST) {
750 TLog(taskId, "SaveDb: Aborted by request\n");
751 clearStatus(taskId, ABORT_REQUEST);
752 setStatus(taskId, ABORT_DONE);
754 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
755 setStatus(taskId, TASK_ERROR);
757 TLog(taskId, "SaveDb: Finished\n");
759 setStatus(taskId, TASK_DONE);
762 LeaveDeviceQueue(deviceLatch);
763 return (void *)(intptr_t)(code);
768 * Make a database dump entry given a tape label.
772 makeDbDumpEntry(struct budb_tapeEntry *tapeEntPtr,
773 struct budb_dumpEntry *dumpEntryPtr)
775 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
777 dumpEntryPtr->id = tapeEntPtr->dump;
778 dumpEntryPtr->initialDumpID = 0;
779 dumpEntryPtr->parent = 0;
780 dumpEntryPtr->level = 0;
781 dumpEntryPtr->flags = 0;
783 strcpy(dumpEntryPtr->volumeSetName, "");
784 strcpy(dumpEntryPtr->dumpPath, "");
785 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
787 dumpEntryPtr->created = tapeEntPtr->dump;
788 dumpEntryPtr->incTime = 0;
789 dumpEntryPtr->nVolumes = 0;
791 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
792 strcat(dumpEntryPtr->tapes.format, ".%d");
793 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
794 dumpEntryPtr->tapes.maxTapes = 0;
799 * prompt for a specific database tape
803 readDbTape(struct butm_tapeInfo *tapeInfoPtr,
804 struct rstTapeInfo *rstTapeInfoPtr, int query)
809 struct butm_tapeLabel oldTapeLabel;
810 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
811 struct tapeEntryList *endList;
813 struct budb_dumpEntry de;
814 struct budb_tapeEntry te;
816 taskId = rstTapeInfoPtr->taskId;
817 interactiveFlag = query;
819 /* construct the name of the tape */
820 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
821 strcpy(tapeName, AFStapeName);
823 /* Will prompt for the latest saved database tape, but will accept any one */
824 if (rstTapeInfoPtr->tapeSeq == 1) {
825 code = bcdb_FindLatestDump("", "", &de);
827 rstTapeInfoPtr->dumpid = de.id;
829 if (rstTapeInfoPtr->dumpid) {
831 bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
834 strcpy(tapeName, te.name);
839 if (interactiveFlag) { /* need a tape to read */
841 PromptForTape(RESTOREDBOPCODE, tapeName,
842 rstTapeInfoPtr->dumpid, taskId, tapecount);
849 code = butm_Mount(tapeInfoPtr, tapeName);
851 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
855 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
857 TapeLog(0, taskId, code, tapeInfoPtr->error,
858 "Can't read tape label\n");
862 /* Check for name of tape and matching dump id (if applicable). */
863 if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
864 || ((rstTapeInfoPtr->tapeSeq != 1)
865 && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
866 char expTape[BU_MAXTAPELEN + 32];
867 char gotTape[BU_MAXTAPELEN + 32];
869 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
870 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
872 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
877 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
878 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
883 unmountTape(taskId, tapeInfoPtr);
887 /* Initialize a tapeEntry for later inclusion into the database */
889 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
891 ERROR_EXIT(TC_NOMEMORY);
892 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
894 /* Fill in tape entry so we can save it later */
895 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
896 tapeEntryPtr->dump = oldTapeLabel.dumpid;
897 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
898 tapeEntryPtr->written = oldTapeLabel.creationTime;
899 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
900 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
901 tapeEntryPtr->useCount = oldTapeLabel.useCount;
902 tapeEntryPtr->useKBytes = 0;
903 tapeEntryPtr->labelpos = 0;
905 /* Thread onto end of single-linked list */
907 endList = listEntryHead;
908 while (endList->next)
909 endList = endList->next;
910 endList->next = listEntryPtr;
912 listEntryHead = listEntryPtr;
918 static afs_int32 nbytes = 0; /* # bytes left in buffer */
920 initTapeBuffering(void)
927 * restore all the items on the tape
929 * tape positioned after tape label
933 restoreDbEntries(struct butm_tapeInfo *tapeInfoPtr,
934 struct rstTapeInfo *rstTapeInfoPtr)
936 struct structDumpHeader netItemHeader, hostItemHeader;
938 afs_int32 taskId, code = 0;
941 taskId = rstTapeInfoPtr->taskId;
943 /* clear state for the buffer routine(s) */
946 code = butm_ReadFileBegin(tapeInfoPtr);
948 ErrorLog(0, taskId, code, tapeInfoPtr->error,
949 "Can't read FileBegin on tape\n");
953 /* get the first item-header */
954 memset(&netItemHeader, 0, sizeof(netItemHeader));
956 getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
957 sizeof(netItemHeader));
960 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
963 switch (hostItemHeader.type) {
966 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
972 if (++count > 25) { /*every 25 dumps, wait */
977 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
987 case SD_TEXT_DUMPSCHEDULE:
988 case SD_TEXT_VOLUMESET:
989 case SD_TEXT_TAPEHOSTS:
990 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
1000 TLog(taskId, "Unknown database header type %d\n",
1001 hostItemHeader.type);
1007 code = butm_ReadFileEnd(tapeInfoPtr);
1009 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1010 "Can't read EOF on tape\n");
1014 /* Mark tape as having been written */
1015 tapeEntryPtr->useKBytes =
1016 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1017 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1023 /* restoreDbFromTape
1024 * restore the backup database from tape.
1028 restoreDbFromTape(void *param)
1030 afs_uint32 taskId = (intptr_t) param;
1033 struct butm_tapeInfo tapeInfo;
1034 struct rstTapeInfo rstTapeInfo;
1035 struct budb_dumpEntry dumpEntry;
1037 extern struct tapeConfig globalTapeConfig;
1038 extern struct deviceSyncNode *deviceLatch;
1040 setStatus(taskId, DRIVE_WAIT);
1041 EnterDeviceQueue(deviceLatch); /* lock tape device */
1042 clearStatus(taskId, DRIVE_WAIT);
1045 TLog(taskId, "RestoreDb\n");
1047 tapeInfo.structVersion = BUTM_MAJORVERSION;
1048 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1050 ErrorLog(0, taskId, code, tapeInfo.error,
1051 "Can't initialize tape module\n");
1055 listEntryHead = NULL;
1057 rstTapeInfo.taskId = taskId;
1058 rstTapeInfo.tapeSeq = 1;
1059 rstTapeInfo.dumpid = 0;
1061 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1065 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1070 /* Now put this dump into the database */
1071 /* Make a dump entry from first tape */
1072 listEntryPtr = listEntryHead;
1074 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1075 if (dumpEntry.id != 0) {
1076 i = bcdb_CreateDump(&dumpEntry);
1078 if (i == BUDB_DUMPIDEXISTS)
1080 "Dump id %d not added to database - already exists\n",
1083 TapeLog(0, taskId, i, 0,
1084 "Dump id %d not added to database\n",
1087 i = addTapesToDb(taskId);
1091 i = bcdb_FinishDump(&dumpEntry);
1099 unmountTape(taskId, &tapeInfo);
1102 if (code == TC_ABORTEDBYREQUEST) {
1103 TLog(taskId, "RestoreDb: Aborted by request\n");
1104 clearStatus(taskId, ABORT_REQUEST);
1105 setStatus(taskId, ABORT_DONE);
1107 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1108 setStatus(taskId, TASK_ERROR);
1110 TLog(taskId, "RestoreDb: Finished\n");
1113 LeaveDeviceQueue(deviceLatch);
1114 setStatus(taskId, TASK_DONE);
1116 return (void *)(intptr_t)(code);
1121 * While dumping the database, keeps the connection alive.
1122 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
1123 * This resets the database's internal timer so that it does not
1124 * prematuraly quit (on asking for new tapes and such).
1126 * Use the same udbHandle as writeDbDump so we go to the same server.
1129 KeepAlive(void *unused)
1135 extern struct udbHandleS udbHandle;
1138 #ifdef AFS_PTHREAD_ENV
1143 charList.charListT_val = 0;
1144 charList.charListT_len = 0;
1146 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1147 UF_SINGLESERVER, 0, 0, &charList, &done);
1156 * restore special items in the header
1160 restoreDbHeader(struct butm_tapeInfo *tapeInfo,
1161 struct rstTapeInfo *rstTapeInfoPtr,
1162 struct structDumpHeader *nextHeader)
1164 struct structDumpHeader netItemHeader;
1165 struct DbHeader netDbHeader, hostDbHeader;
1168 extern struct udbHandleS udbHandle;
1170 /* Read the database header */
1171 memset(&netDbHeader, 0, sizeof(netDbHeader));
1173 getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1174 sizeof(netDbHeader));
1177 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1179 /* Add the database header to the database */
1181 ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1184 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1185 "Can't restore DB Header\n");
1189 /* get the next item-header */
1190 memset(nextHeader, 0, sizeof(*nextHeader));
1192 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1193 sizeof(netItemHeader));
1196 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1204 * restore a single dump, including all its tapes and volumes, from
1207 * nextHeader - ptr to structure for return value
1209 * nextHeader - next structure header from tape
1211 * upon entry, the dump structure header has been read confirming that
1212 * a database dump tree exists on the tape
1216 restoreDbDump(struct butm_tapeInfo *tapeInfo,
1217 struct rstTapeInfo *rstTapeInfoPtr,
1218 struct structDumpHeader *nextHeader)
1220 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1221 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1222 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1223 struct structDumpHeader netItemHeader;
1225 int restoreThisDump = 1;
1228 extern struct udbHandleS udbHandle;
1230 taskId = rstTapeInfoPtr->taskId;
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 #if defined (HAVE_MKSTEMP)
1459 fid = mkstemp(filename);
1461 fid = open(mktemp(filename), O_RDWR | O_CREAT | O_EXCL, 0600);
1464 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1465 "Can't open temporary text file: %s\n", filename);
1469 /* allocate buffer for text */
1470 readBlockSize = BUTM_BLKSIZE;
1471 readBuffer = (char *)malloc(readBlockSize);
1473 ERROR_EXIT(TC_NOMEMORY);
1475 /* read the text into the temporary file */
1476 nbytes = nextHeader->size;
1477 while (nbytes > 0) {
1478 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1480 /* read it from the tape */
1482 getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1486 /* write to the file */
1487 if (write(fid, readBuffer, transferSize) != transferSize) {
1488 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1489 "Can't write temporary text file: %s\n", filename);
1493 nbytes -= transferSize;
1498 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1503 /* get the next item-header */
1504 memset(nextHeader, 0, sizeof(*nextHeader));
1506 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1507 sizeof(netItemHeader));
1510 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1525 /* ----------------------------------
1526 * Tape data buffering - for reading database dumps
1527 * ----------------------------------
1530 static char *tapeReadBuffer = 0; /* input buffer */
1531 static char *tapeReadBufferPtr = 0; /* position in buffer */
1534 * Read information from tape, and place the requested number of bytes
1535 * in the buffer supplied
1538 * rstTapeInfoPtr - Info about the dump being restored.
1539 * buffer - buffer for requested data
1540 * requestedBytes - no. of bytes requested
1542 * fn retn - 0, ok, n, error
1546 getTapeData(struct butm_tapeInfo *tapeInfoPtr,
1547 struct rstTapeInfo *rstTapeInfoPtr,
1548 void *out, afs_int32 requestedBytes)
1550 char *buffer = (char *) out;
1551 afs_int32 taskId, transferBytes;
1554 taskId = rstTapeInfoPtr->taskId;
1556 if (checkAbortByTaskId(taskId))
1557 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1559 if (!tapeReadBuffer) {
1560 tapeReadBuffer = (char *)malloc(BUTM_BLOCKSIZE);
1561 if (!tapeReadBuffer)
1562 ERROR_EXIT(TC_NOMEMORY);
1565 while (requestedBytes > 0) {
1567 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1571 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1572 BUTM_BLKSIZE, &nbytes);
1574 /* detect if we hit the end-of-tape and get next tape */
1575 if (code == BUTM_ENDVOLUME) {
1576 /* Update fields in tape entry for this tape */
1577 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1578 tapeEntryPtr->useKBytes =
1579 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1581 unmountTape(taskId, tapeInfoPtr);
1583 rstTapeInfoPtr->tapeSeq++;
1584 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1588 code = butm_ReadFileBegin(tapeInfoPtr);
1590 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1591 "Can't read FileBegin on tape\n");
1598 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1599 "Can't read FileData on tape\n");
1605 transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1606 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1607 tapeReadBufferPtr += transferBytes;
1608 buffer += transferBytes;
1609 nbytes -= transferBytes;
1610 requestedBytes -= transferBytes;