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>
31 #include <afs/procmgmt.h>
32 #include <afs/assert.h>
33 #include <afs/prs_fs.h>
38 #include <afs/cellconfig.h>
42 #include <afs/tcdata.h>
44 #include <afs/budb_client.h>
45 #include <afs/bubasics.h>
46 #include "error_macros.h"
48 /* GLOBAL CONFIGURATION PARAMETERS */
49 #define BIGCHUNK 102400
51 extern int dump_namecheck;
55 * create a dump entry for a saved database
59 CreateDBDump(dumpEntryPtr)
60 struct budb_dumpEntry *dumpEntryPtr;
64 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
66 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
67 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
68 strcat(dumpEntryPtr->tapes.format, ".%d");
69 strcpy(dumpEntryPtr->volumeSetName, "");
70 strcpy(dumpEntryPtr->dumpPath, "");
71 dumpEntryPtr->created = 0; /* let database assign it */
72 dumpEntryPtr->incTime = 0;
73 dumpEntryPtr->nVolumes = 0;
74 dumpEntryPtr->initialDumpID = 0;
75 dumpEntryPtr->parent = 0;
76 dumpEntryPtr->level = 0;
77 dumpEntryPtr->tapes.maxTapes = 0;
78 dumpEntryPtr->tapes.b = 1;
80 /* now call the database to create the entry */
81 code = bcdb_CreateDump(dumpEntryPtr);
85 struct tapeEntryList {
86 struct tapeEntryList *next;
88 struct budb_tapeEntry tapeEnt;
90 struct tapeEntryList *listEntryHead;
91 struct tapeEntryList *listEntryPtr;
92 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
93 struct budb_dumpEntry lastDump; /* the last dump of this volset */
96 * Load a DB tape, read and over write its label.
97 * Leave the tape mounted.
100 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag,
104 struct butm_tapeInfo *tapeInfoPtr;
112 char tapeName[BU_MAXTAPELEN];
119 struct butm_tapeLabel oldTapeLabel, newLabel;
120 struct tapeEntryList *endList;
121 extern struct tapeConfig globalTapeConfig;
123 /* construct the name of the tape */
124 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
126 interactiveFlag = queryFlag;
129 while (!*wroteLabel) { /*w */
130 if (interactiveFlag) { /* need a tape to write */
132 PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
140 code = butm_Mount(tapeInfoPtr, tapeName);
142 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
146 memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
147 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
149 oldTapeLabel.useCount = 0; /* no label exists */
150 oldTapeLabel.structVersion = 0;
151 strcpy(oldTapeLabel.pName, "");
153 /* If tape has a name, it must be null or database tape name */
154 if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
155 && !databaseTape(oldTapeLabel.AFSName)) {
156 char gotName[BU_MAXTAPELEN + 32];
158 LABELNAME(gotName, &oldTapeLabel);
160 "This tape %s must be a database tape or NULL tape\n",
164 unmountTape(taskId, tapeInfoPtr);
168 /* Do not overwrite a tape that belongs to this dump */
169 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
170 ErrorLog(0, taskId, 0, 0,
171 "Can't overwrite tape containing the dump in progress\n");
175 /* On first tape, the savedb has not started yet, so the database is not locked
176 * and we can therefore, access information from it. This is easier to do because
177 * database dumps don't have appended dumps (nor appended).
181 struct budb_dumpEntry de, de2;
183 /* Verify the tape has not expired
184 * Early database dumps don't have a dumpid
186 if (!tapeExpired(&oldTapeLabel)) {
187 TLog(taskId, "This tape has not expired\n");
191 /* Since the dumpset on this tape will be deleted from database, check if
192 * any of the dumps in this dumpset are most-recent-dumps.
194 for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
195 if (dmp == lastDump.id) {
196 memcpy(&de, &lastDump, sizeof(de));
197 memcpy(&de2, &lastDump, sizeof(de2));
199 code = bcdb_FindDumpByID(dmp, &de);
202 sprintf(strlevel, "%d", de.level);
204 bcdb_FindLatestDump(de.volumeSetName, strlevel,
210 if (de.id == de2.id) {
211 if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
212 ErrorLog(0, taskId, 0, 0,
213 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
216 ErrorLog(0, taskId, 0, 0,
217 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
218 de.volumeSetName, de.name, de.id);
224 /* Otherwise, the savedb is in progress and we can't
225 * access the database (it's locked). So we rely on the
226 * information available (and not the backup database).
229 /* Check the tape's expiration date. Use the expiration on the label */
230 gettimeofday(&tp, &tzp);
232 if (curTime < oldTapeLabel.expirationDate) {
233 TLog(taskId, "This tape has not expired\n");
237 /* Check if this previous-dump of the dump-in-progress is on this tape */
238 if (oldTapeLabel.dumpid
239 && (oldTapeLabel.dumpid == lastDump.id)) {
240 ErrorLog(0, taskId, 0, 0,
241 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
242 lastDump.name, lastDump.id);
248 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
249 newLabel.expirationDate = expires;
250 newLabel.useCount = oldTapeLabel.useCount + 1;
251 newLabel.dumpid = dumpid;
252 newLabel.size = tapeInfoPtr->tapeSize;
254 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
256 TapeLog(0, taskId, code, tapeInfoPtr->error,
257 "Can't label tape\n");
263 /* Initialize a tapeEntry for later inclusion into the database */
265 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
267 ERROR_EXIT(TC_NOMEMORY);
268 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
270 /* Remember dumpid so we can delete it later */
271 if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
272 && oldTapeLabel.dumpid)
273 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
275 /* Fill in tape entry so we can save it later */
276 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
277 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
278 tapeEntryPtr->written = newLabel.creationTime;
279 tapeEntryPtr->expires = expires;
280 tapeEntryPtr->seq = sequence;
281 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
282 tapeEntryPtr->dump = dumpid;
283 tapeEntryPtr->useKBytes = 0;
284 tapeEntryPtr->labelpos = 0;
286 /* Thread onto end of single-linked list */
288 endList = listEntryHead;
289 while (endList->next)
290 endList = endList->next;
291 endList->next = listEntryPtr;
293 listEntryHead = listEntryPtr;
301 * With the list of tapes, free the structures.
307 struct tapeEntryList *next;
309 listEntryPtr = listEntryHead;
310 while (listEntryPtr) {
311 next = listEntryPtr->next;
316 listEntryHead = NULL;
321 * With the list of tapes, add them to the database.
322 * Also delete any olddumpids that are around.
331 struct tapeEntryList *next;
333 listEntryPtr = listEntryHead;
334 while (listEntryPtr) {
335 next = listEntryPtr->next;
337 /* Remove the old database entry */
338 if (listEntryPtr->oldDumpId) {
339 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
340 if (i && (i != BUDB_NOENT)) {
341 ErrorLog(0, taskId, i, 0,
342 "Unable to delete old DB entry %u.\n",
343 listEntryPtr->oldDumpId);
347 /* Add the tape to the database */
348 code = bcdb_UseTape(tapeEntryPtr, &new);
350 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n",
355 code = bcdb_FinishTape(tapeEntryPtr);
357 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n",
371 * this code assumes that the blocksize on reads is smaller than
372 * the blocksize on writes
376 writeDbDump(tapeInfoPtr, taskId, expires, dumpid)
377 struct butm_tapeInfo *tapeInfoPtr;
383 afs_int32 writeBufNbytes = 0;
384 char *writeBlock = 0;
385 char *writeBuffer = 0;
387 afs_int32 transferSize;
390 afs_int32 maxReadSize;
395 afs_int32 chunksize = 0;
396 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
400 #ifdef AFS_PTHREAD_ENV
402 pthread_attr_t tattr;
408 extern struct tapeConfig globalTapeConfig;
409 extern struct udbHandleS udbHandle;
411 extern int KeepAlive();
413 blockSize = BUTM_BLKSIZE;
414 writeBlock = (char *)malloc(BUTM_BLOCKSIZE);
416 ERROR_EXIT(TC_NOMEMORY);
418 writeBuffer = writeBlock + sizeof(struct blockMark);
419 memset(writeBuffer, 0, BUTM_BLKSIZE);
423 * The margin of space to check for end of tape is set to the
424 * amount of space used to write an end-of-tape multiplied by 2.
425 * The amount of space is size of a 16K EODump marker, its EOF
426 * marker, and up to two EOF markers done on close (1 16K blocks +
429 tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
430 tc_KEndMargin = tc_EndMargin / 1024;
432 /* have to write enclose the dump in file marks */
433 code = butm_WriteFileBegin(tapeInfoPtr);
435 ErrorLog(0, taskId, code, tapeInfoPtr->error,
436 "Can't write FileBegin on tape\n");
440 writeBufPtr = &writeBuffer[0];
443 charList.charListT_val = 0;
444 charList.charListT_len = 0;
447 /* When no data in buffer, read data from the budb_server */
448 if (charList.charListT_len == 0) {
449 /* get more data. let rx allocate space */
450 if (charList.charListT_val) {
451 free(charList.charListT_val);
452 charList.charListT_val = 0;
457 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
458 UF_SINGLESERVER, firstcall,
459 maxReadSize, &charList, &done);
461 ErrorLog(0, taskId, code, 0, "Can't read database\n");
465 /* If this if the first call to the budb server, create a thread
466 * that will keep the connection alive (during tape changes).
469 #ifdef AFS_PTHREAD_ENV
470 code = pthread_attr_init(&tattr);
472 ErrorLog(0, taskId, code, 0,
473 "Can't pthread_attr_init Keep-alive process\n");
478 pthread_attr_setdetachstate(&tattr,
479 PTHREAD_CREATE_DETACHED);
481 ErrorLog(0, taskId, code, 0,
482 "Can't pthread_attr_setdetachstate Keep-alive process\n");
487 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
488 AFS_SIGSET_RESTORE();
491 LWP_CreateProcess(KeepAlive, 16384, 1, (void *)NULL,
492 "Keep-alive process", &alivePid);
494 /* XXX should we check code here ??? XXX */
498 readBufPtr = charList.charListT_val;
501 if ((charList.charListT_len == 0) && done)
504 /* compute how many bytes and transfer to the write Buffer */
506 (charList.charListT_len <
508 writeBufNbytes)) ? charList.charListT_len : (blockSize -
511 memcpy(writeBufPtr, readBufPtr, transferSize);
512 charList.charListT_len -= transferSize;
513 writeBufPtr += transferSize;
514 readBufPtr += transferSize;
515 writeBufNbytes += transferSize;
517 /* If filled the write buffer, then write it to tape */
518 if (writeBufNbytes == blockSize) {
519 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
521 ErrorLog(0, taskId, code, tapeInfoPtr->error,
522 "Can't write data on tape\n");
526 memset(writeBuffer, 0, blockSize);
527 writeBufPtr = &writeBuffer[0];
530 /* Every BIGCHUNK bytes check if aborted */
531 chunksize += blockSize;
532 if (chunksize > BIGCHUNK) {
534 if (checkAbortByTaskId(taskId))
535 ERROR_EXIT(TC_ABORTEDBYREQUEST);
539 * check if tape is full - since we filled a blockSize worth of data
540 * assume that there is more data.
542 kRemaining = butm_remainingKSpace(tapeInfoPtr);
543 if (kRemaining < tc_KEndMargin) {
544 code = butm_WriteFileEnd(tapeInfoPtr);
546 ErrorLog(0, taskId, code, tapeInfoPtr->error,
547 "Can't write FileEnd on tape\n");
551 code = butm_WriteEOT(tapeInfoPtr);
553 ErrorLog(0, taskId, code, tapeInfoPtr->error,
554 "Can't write end-of-dump on tape\n");
558 /* Mark tape as having been written */
559 tapeEntryPtr->useKBytes =
560 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
561 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
563 unmountTape(taskId, tapeInfoPtr);
565 /* Get next tape and writes its label */
568 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
573 code = butm_WriteFileBegin(tapeInfoPtr);
575 ErrorLog(0, taskId, code, tapeInfoPtr->error,
576 "Can't write FileBegin on tape\n");
583 /* no more data to be read - if necessary, flush out the last buffer */
584 if (writeBufNbytes > 0) {
585 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
587 ErrorLog(1, taskId, code, tapeInfoPtr->error,
588 "Can't write data on tape\n");
593 code = butm_WriteFileEnd(tapeInfoPtr);
595 ErrorLog(0, taskId, code, tapeInfoPtr->error,
596 "Can't write FileEnd on tape\n");
600 /* Mark tape as having been written */
601 tapeEntryPtr->useKBytes =
602 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
603 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
606 /* Let the KeepAlive process stop on its own */
608 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
609 UF_END_SINGLESERVER, 0);
613 if (charList.charListT_val)
614 free(charList.charListT_val);
619 * dump backup database to tape
623 saveDbToTape(saveDbIfPtr)
624 struct saveDbIf *saveDbIfPtr;
632 struct butm_tapeInfo tapeInfo;
633 struct budb_dumpEntry dumpEntry;
635 extern struct deviceSyncNode *deviceLatch;
636 extern struct tapeConfig globalTapeConfig;
638 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
639 taskId = saveDbIfPtr->taskId;
641 setStatus(taskId, DRIVE_WAIT);
642 EnterDeviceQueue(deviceLatch); /* lock tape device */
643 clearStatus(taskId, DRIVE_WAIT);
646 TLog(taskId, "SaveDb\n");
648 tapeInfo.structVersion = BUTM_MAJORVERSION;
649 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
651 ErrorLog(0, taskId, code, tapeInfo.error,
652 "Can't initialize tape module\n");
656 /* Determine what the last database dump was */
657 memset(&lastDump, 0, sizeof(lastDump));
658 code = bcdb_FindLatestDump("", "", &lastDump);
660 if (code != BUDB_NODUMPNAME) {
661 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
664 memset(&lastDump, 0, sizeof(lastDump));
667 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
669 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
674 listEntryHead = NULL;
676 /* Get the tape and write a new label to it */
678 GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
682 * If did not write the label, remove created dump
683 * Else if wrote the label, remove old dump from db so it's not saved.
686 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
688 if (i && (i != BUDB_NOENT))
689 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
691 } else if (listEntryHead->oldDumpId) {
692 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
693 listEntryHead->oldDumpId = 0;
694 if (i && (i != BUDB_NOENT)) {
695 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
696 listEntryHead->oldDumpId);
703 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
705 /* we have a writable tape */
706 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
710 /* Now delete the entries between time 0 and archive-time */
711 if (saveDbIfPtr->archiveTime)
712 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
715 unmountTape(taskId, &tapeInfo);
717 /* Add this dump's tapes to the database and mark it finished */
719 i = addTapesToDb(taskId);
723 i = bcdb_FinishDump(&dumpEntry);
729 if (code == TC_ABORTEDBYREQUEST) {
730 TLog(taskId, "SaveDb: Aborted by request\n");
731 clearStatus(taskId, ABORT_REQUEST);
732 setStatus(taskId, ABORT_DONE);
734 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
735 setStatus(taskId, TASK_ERROR);
737 TLog(taskId, "SaveDb: Finished\n");
739 setStatus(taskId, TASK_DONE);
742 LeaveDeviceQueue(deviceLatch);
753 * Make a database dump entry given a tape label.
757 makeDbDumpEntry(tapeEntPtr, dumpEntryPtr)
758 struct budb_tapeEntry *tapeEntPtr;
759 struct budb_dumpEntry *dumpEntryPtr;
761 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
763 dumpEntryPtr->id = tapeEntPtr->dump;
764 dumpEntryPtr->initialDumpID = 0;
765 dumpEntryPtr->parent = 0;
766 dumpEntryPtr->level = 0;
767 dumpEntryPtr->flags = 0;
769 strcpy(dumpEntryPtr->volumeSetName, "");
770 strcpy(dumpEntryPtr->dumpPath, "");
771 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
773 dumpEntryPtr->created = tapeEntPtr->dump;
774 dumpEntryPtr->incTime = 0;
775 dumpEntryPtr->nVolumes = 0;
777 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
778 strcat(dumpEntryPtr->tapes.format, ".%d");
779 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
780 dumpEntryPtr->tapes.maxTapes = 0;
785 * prompt for a specific database tape
789 readDbTape(tapeInfoPtr, rstTapeInfoPtr, query)
790 struct butm_tapeInfo *tapeInfoPtr;
791 struct rstTapeInfo *rstTapeInfoPtr;
797 struct butm_tapeLabel oldTapeLabel;
798 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
799 struct tapeEntryList *endList;
801 struct budb_dumpEntry de;
802 struct budb_tapeEntry te;
804 taskId = rstTapeInfoPtr->taskId;
805 interactiveFlag = query;
807 /* construct the name of the tape */
808 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
809 strcpy(tapeName, AFStapeName);
811 /* Will prompt for the latest saved database tape, but will accept any one */
812 if (rstTapeInfoPtr->tapeSeq == 1) {
813 code = bcdb_FindLatestDump("", "", &de);
815 rstTapeInfoPtr->dumpid = de.id;
817 if (rstTapeInfoPtr->dumpid) {
819 bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
822 strcpy(tapeName, te.name);
827 if (interactiveFlag) { /* need a tape to read */
829 PromptForTape(RESTOREDBOPCODE, tapeName,
830 rstTapeInfoPtr->dumpid, taskId, tapecount);
837 code = butm_Mount(tapeInfoPtr, tapeName);
839 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
843 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
845 TapeLog(0, taskId, code, tapeInfoPtr->error,
846 "Can't read tape label\n");
850 /* Check for name of tape and matching dump id (if applicable). */
851 if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
852 || ((rstTapeInfoPtr->tapeSeq != 1)
853 && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
854 char expTape[BU_MAXTAPELEN + 32];
855 char gotTape[BU_MAXTAPELEN + 32];
857 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
858 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
860 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
865 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
866 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
871 unmountTape(taskId, tapeInfoPtr);
875 /* Initialize a tapeEntry for later inclusion into the database */
877 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
879 ERROR_EXIT(TC_NOMEMORY);
880 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
882 /* Fill in tape entry so we can save it later */
883 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
884 tapeEntryPtr->dump = oldTapeLabel.dumpid;
885 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
886 tapeEntryPtr->written = oldTapeLabel.creationTime;
887 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
888 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
889 tapeEntryPtr->useCount = oldTapeLabel.useCount;
890 tapeEntryPtr->useKBytes = 0;
891 tapeEntryPtr->labelpos = 0;
893 /* Thread onto end of single-linked list */
895 endList = listEntryHead;
896 while (endList->next)
897 endList = endList->next;
898 endList->next = listEntryPtr;
900 listEntryHead = listEntryPtr;
906 static afs_int32 nbytes = 0; /* # bytes left in buffer */
915 * restore all the items on the tape
917 * tape positioned after tape label
921 restoreDbEntries(tapeInfoPtr, rstTapeInfoPtr)
922 struct butm_tapeInfo *tapeInfoPtr;
923 struct rstTapeInfo *rstTapeInfoPtr;
925 struct structDumpHeader netItemHeader, hostItemHeader;
927 afs_int32 taskId, code = 0;
930 taskId = rstTapeInfoPtr->taskId;
932 /* clear state for the buffer routine(s) */
935 code = butm_ReadFileBegin(tapeInfoPtr);
937 ErrorLog(0, taskId, code, tapeInfoPtr->error,
938 "Can't read FileBegin on tape\n");
942 /* get the first item-header */
943 memset(&netItemHeader, 0, sizeof(netItemHeader));
945 getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
946 sizeof(netItemHeader));
949 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
952 switch (hostItemHeader.type) {
955 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
961 if (++count > 25) { /*every 25 dumps, wait */
966 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
976 case SD_TEXT_DUMPSCHEDULE:
977 case SD_TEXT_VOLUMESET:
978 case SD_TEXT_TAPEHOSTS:
979 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
989 TLog(taskId, "Unknown database header type %d\n",
990 hostItemHeader.type);
996 code = butm_ReadFileEnd(tapeInfoPtr);
998 ErrorLog(0, taskId, code, tapeInfoPtr->error,
999 "Can't read EOF on tape\n");
1003 /* Mark tape as having been written */
1004 tapeEntryPtr->useKBytes =
1005 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1006 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1012 /* restoreDbFromTape
1013 * restore the backup database from tape.
1017 restoreDbFromTape(taskId)
1022 struct butm_tapeInfo tapeInfo;
1023 struct rstTapeInfo rstTapeInfo;
1024 struct budb_dumpEntry dumpEntry;
1026 extern struct tapeConfig globalTapeConfig;
1027 extern struct deviceSyncNode *deviceLatch;
1029 setStatus(taskId, DRIVE_WAIT);
1030 EnterDeviceQueue(deviceLatch); /* lock tape device */
1031 clearStatus(taskId, DRIVE_WAIT);
1034 TLog(taskId, "RestoreDb\n");
1036 tapeInfo.structVersion = BUTM_MAJORVERSION;
1037 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1039 ErrorLog(0, taskId, code, tapeInfo.error,
1040 "Can't initialize tape module\n");
1044 listEntryHead = NULL;
1046 rstTapeInfo.taskId = taskId;
1047 rstTapeInfo.tapeSeq = 1;
1048 rstTapeInfo.dumpid = 0;
1050 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1054 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1059 /* Now put this dump into the database */
1060 /* Make a dump entry from first tape */
1061 listEntryPtr = listEntryHead;
1063 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1064 if (dumpEntry.id != 0) {
1065 i = bcdb_CreateDump(&dumpEntry);
1067 if (i == BUDB_DUMPIDEXISTS)
1069 "Dump id %d not added to database - already exists\n",
1072 TapeLog(0, taskId, i, 0,
1073 "Dump id %d not added to database\n",
1076 i = addTapesToDb(taskId);
1080 i = bcdb_FinishDump(&dumpEntry);
1088 unmountTape(taskId, &tapeInfo);
1091 if (code == TC_ABORTEDBYREQUEST) {
1092 TLog(taskId, "RestoreDb: Aborted by request\n");
1093 clearStatus(taskId, ABORT_REQUEST);
1094 setStatus(taskId, ABORT_DONE);
1096 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1097 setStatus(taskId, TASK_ERROR);
1099 TLog(taskId, "RestoreDb: Finished\n");
1102 LeaveDeviceQueue(deviceLatch);
1103 setStatus(taskId, TASK_DONE);
1110 * While dumping the database, keeps the connection alive.
1111 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
1112 * This resets the database's internal timer so that it does not
1113 * prematuraly quit (on asking for new tapes and such).
1115 * Use the same udbHandle as writeDbDump so we go to the same server.
1124 extern struct udbHandleS udbHandle;
1127 #ifdef AFS_PTHREAD_ENV
1132 charList.charListT_val = 0;
1133 charList.charListT_len = 0;
1135 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1136 UF_SINGLESERVER, 0, 0, &charList, &done);
1145 * restore special items in the header
1148 restoreDbHeader(tapeInfo, rstTapeInfoPtr, nextHeader)
1149 struct butm_tapeInfo *tapeInfo;
1150 struct rstTapeInfo *rstTapeInfoPtr;
1151 struct structDumpHeader *nextHeader;
1153 struct structDumpHeader netItemHeader;
1154 struct DbHeader netDbHeader, hostDbHeader;
1157 extern struct udbHandleS udbHandle;
1159 /* Read the database header */
1160 memset(&netDbHeader, 0, sizeof(netDbHeader));
1162 getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1163 sizeof(netDbHeader));
1166 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1168 /* Add the database header to the database */
1170 ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1173 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1174 "Can't restore DB Header\n");
1178 /* get the next item-header */
1179 memset(nextHeader, 0, sizeof(*nextHeader));
1181 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1182 sizeof(netItemHeader));
1185 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1193 * restore a single dump, including all its tapes and volumes, from
1196 * nextHeader - ptr to structure for return value
1198 * nextHeader - next structure header from tape
1200 * upon entry, the dump structure header has been read confirming that
1201 * a database dump tree exists on the tape
1204 restoreDbDump(tapeInfo, rstTapeInfoPtr, nextHeader)
1205 struct butm_tapeInfo *tapeInfo;
1206 struct rstTapeInfo *rstTapeInfoPtr;
1207 struct structDumpHeader *nextHeader;
1209 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1210 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1211 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1212 struct structDumpHeader netItemHeader;
1214 int restoreThisDump = 1;
1217 extern struct udbHandleS udbHandle;
1219 taskId = rstTapeInfoPtr->taskId;
1221 /* read dump entry */
1222 memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1224 getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry,
1225 sizeof(netDumpEntry));
1229 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1230 if (rstTapeInfoPtr->dumpid == 0) {
1231 netDumpEntry.initialDumpID = 0;
1232 netDumpEntry.appendedDumpID = 0;
1235 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1237 /* The dump entry for this database tape is incomplete, so don't include it */
1238 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1239 restoreThisDump = 0;
1241 /* add the dump to the database */
1242 if (restoreThisDump) {
1244 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1250 /* get the next item-header */
1251 memset(nextHeader, 0, sizeof(*nextHeader));
1253 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1254 sizeof(netItemHeader));
1257 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1259 /* Add every tape to the db */
1260 while (nextHeader->type == SD_TAPE) { /*t */
1262 /* read the tape entry */
1263 memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1265 getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry,
1266 sizeof(netTapeEntry));
1269 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1271 /* Add the tape to the database */
1272 if (restoreThisDump) {
1274 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1280 /* get the next item-header */
1281 memset(nextHeader, 0, sizeof(*nextHeader));
1283 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1284 sizeof(netItemHeader));
1287 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1289 /* Add every volume to the db */
1290 while (nextHeader->type == SD_VOLUME) { /*v */
1292 /* read the volume entry */
1293 memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1295 getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry,
1296 sizeof(netVolumeEntry));
1299 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1301 if (restoreThisDump) {
1303 threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry),
1309 /* get the next item-header */
1310 memset(nextHeader, 0, sizeof(*nextHeader));
1312 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1313 sizeof(netItemHeader));
1316 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1319 /* Finish the tape */
1320 if (restoreThisDump) {
1322 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1329 /* Finish the dump */
1330 if (restoreThisDump) {
1332 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1343 * Save the specified file as configuration text in the ubik database.
1344 * Have to setup the client text structure so that we can call
1345 * the routine to transmit the text to the db.
1349 saveTextFile(taskId, textType, fileName)
1354 udbClientTextP ctPtr = 0;
1358 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1360 ERROR_EXIT(TC_NOMEMORY);
1362 memset(ctPtr, 0, sizeof(*ctPtr));
1363 ctPtr->textType = textType;
1365 /* lock the text in the database */
1366 code = bc_LockText(ctPtr);
1368 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1373 ctPtr->textStream = fopen(fileName, "r");
1374 if (!ctPtr->textStream) {
1375 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1379 /* now send the text to the database */
1380 code = bcdb_SaveTextFile(ctPtr);
1382 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1388 if (ctPtr->textStream)
1389 fclose(ctPtr->textStream);
1391 bc_UnlockText(ctPtr);
1398 * read the text off the tape, and store it in the appropriate
1399 * text type in the database.
1401 * nextHeader - ptr to struct for return information
1403 * nextHeader - struct header for next item on the tape
1406 restoreText(tapeInfo, rstTapeInfoPtr, nextHeader)
1407 struct butm_tapeInfo *tapeInfo;
1408 struct rstTapeInfo *rstTapeInfoPtr;
1409 struct structDumpHeader *nextHeader;
1413 char *readBuffer = 0;
1414 afs_int32 readBlockSize;
1415 afs_int32 transferSize;
1416 struct structDumpHeader netItemHeader;
1420 udbClientTextP ctPtr = 0;
1423 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1425 ERROR_EXIT(TC_NOMEMORY);
1427 /* determine the type of text block */
1428 switch (nextHeader->type) {
1429 case SD_TEXT_DUMPSCHEDULE:
1430 textType = TB_DUMPSCHEDULE;
1433 case SD_TEXT_VOLUMESET:
1434 textType = TB_VOLUMESET;
1437 case SD_TEXT_TAPEHOSTS:
1438 textType = TB_TAPEHOSTS;
1442 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0,
1443 "Unknown text block\n");
1444 ERROR_EXIT(TC_INTERNALERROR);
1448 /* open the text file */
1449 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1450 #if defined (HAVE_MKSTEMP)
1451 fid = mkstemp(filename);
1453 fid = open(mktemp(filename), O_RDWR | O_CREAT | O_EXCL, 0600);
1456 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1457 "Can't open temporary text file: %s\n", filename);
1461 /* allocate buffer for text */
1462 readBlockSize = BUTM_BLKSIZE;
1463 readBuffer = (char *)malloc(readBlockSize);
1465 ERROR_EXIT(TC_NOMEMORY);
1467 /* read the text into the temporary file */
1468 nbytes = nextHeader->size;
1469 while (nbytes > 0) {
1470 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1472 /* read it from the tape */
1474 getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1478 /* write to the file */
1479 if (write(fid, readBuffer, transferSize) != transferSize) {
1480 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1481 "Can't write temporary text file: %s\n", filename);
1485 nbytes -= transferSize;
1490 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1495 /* get the next item-header */
1496 memset(nextHeader, 0, sizeof(*nextHeader));
1498 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1499 sizeof(netItemHeader));
1502 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1517 /* ----------------------------------
1518 * Tape data buffering - for reading database dumps
1519 * ----------------------------------
1522 static char *tapeReadBuffer = 0; /* input buffer */
1523 static char *tapeReadBufferPtr = 0; /* position in buffer */
1526 * Read information from tape, and place the requested number of bytes
1527 * in the buffer supplied
1530 * rstTapeInfoPtr - Info about the dump being restored.
1531 * buffer - buffer for requested data
1532 * requestedBytes - no. of bytes requested
1534 * fn retn - 0, ok, n, error
1537 getTapeData(tapeInfoPtr, rstTapeInfoPtr, buffer, requestedBytes)
1538 struct butm_tapeInfo *tapeInfoPtr;
1539 struct rstTapeInfo *rstTapeInfoPtr;
1541 afs_int32 requestedBytes;
1543 afs_int32 taskId, transferBytes, new;
1547 taskId = rstTapeInfoPtr->taskId;
1549 if (checkAbortByTaskId(taskId))
1550 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1552 if (!tapeReadBuffer) {
1553 tapeReadBuffer = (char *)malloc(BUTM_BLOCKSIZE);
1554 if (!tapeReadBuffer)
1555 ERROR_EXIT(TC_NOMEMORY);
1558 while (requestedBytes > 0) {
1560 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1564 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1565 BUTM_BLKSIZE, &nbytes);
1567 /* detect if we hit the end-of-tape and get next tape */
1568 if (code == BUTM_ENDVOLUME) {
1569 /* Update fields in tape entry for this tape */
1570 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1571 tapeEntryPtr->useKBytes =
1572 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1574 unmountTape(taskId, tapeInfoPtr);
1576 rstTapeInfoPtr->tapeSeq++;
1577 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1581 code = butm_ReadFileBegin(tapeInfoPtr);
1583 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1584 "Can't read FileBegin on tape\n");
1591 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1592 "Can't read FileData on tape\n");
1598 transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1599 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1600 tapeReadBufferPtr += transferBytes;
1601 buffer += transferBytes;
1602 nbytes -= transferBytes;
1603 requestedBytes -= transferBytes;