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>
15 #include <sys/types.h>
22 #include <netinet/in.h>
28 #include <afs/afsint.h>
30 #include <afs/procmgmt.h>
31 #include <afs/assert.h>
32 #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 extern int dump_namecheck;
53 * create a dump entry for a saved database
56 afs_int32 CreateDBDump(dumpEntryPtr)
57 struct budb_dumpEntry *dumpEntryPtr;
61 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
63 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
64 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
65 strcat(dumpEntryPtr->tapes.format, ".%d");
66 strcpy(dumpEntryPtr->volumeSetName, "");
67 strcpy(dumpEntryPtr->dumpPath, "");
68 dumpEntryPtr->created = 0; /* let database assign it */
69 dumpEntryPtr->incTime = 0;
70 dumpEntryPtr->nVolumes = 0;
71 dumpEntryPtr->initialDumpID = 0;
72 dumpEntryPtr->parent = 0;
73 dumpEntryPtr->level = 0;
74 dumpEntryPtr->tapes.maxTapes = 0;
75 dumpEntryPtr->tapes.b = 1;
77 /* now call the database to create the entry */
78 code = bcdb_CreateDump(dumpEntryPtr);
84 struct tapeEntryList *next;
86 struct budb_tapeEntry tapeEnt;
88 struct tapeEntryList *listEntryHead;
89 struct tapeEntryList *listEntryPtr;
90 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
91 struct budb_dumpEntry lastDump; /* the last dump of this volset */
94 * Load a DB tape, read and over write its label.
95 * Leave the tape mounted.
97 afs_int32 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag, wroteLabel)
100 struct butm_tapeInfo *tapeInfoPtr;
108 char tapeName[BU_MAXTAPELEN];
116 struct butm_tapeLabel oldTapeLabel, newLabel;
117 struct tapeEntryList *endList;
118 extern struct tapeConfig globalTapeConfig;
120 /* construct the name of the tape */
121 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
123 interactiveFlag = queryFlag;
126 while ( ! *wroteLabel )
128 if ( interactiveFlag ) /* need a tape to write */
130 code = PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId, tapecount);
131 if (code) ERROR_EXIT(code);
136 code = butm_Mount(tapeInfoPtr, tapeName);
139 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
143 memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
144 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
147 oldTapeLabel.useCount = 0; /* no label exists */
148 oldTapeLabel.structVersion = 0;
149 strcpy(oldTapeLabel.pName, "");
153 /* If tape has a name, it must be null or database tape name */
154 if ( dump_namecheck &&
155 strcmp(oldTapeLabel.AFSName,"") && !databaseTape(oldTapeLabel.AFSName) )
157 char gotName[BU_MAXTAPELEN+32];
159 LABELNAME(gotName, &oldTapeLabel);
160 TLog(taskId, "This tape %s must be a database tape or NULL tape\n", gotName);
163 unmountTape(taskId, tapeInfoPtr);
167 /* Do not overwrite a tape that belongs to this dump */
168 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
169 ErrorLog(0, taskId, 0, 0,
170 "Can't overwrite tape containing the dump in progress\n");
174 /* On first tape, the savedb has not started yet, so the database is not locked
175 * and we can therefore, access information from it. This is easier to do because
176 * database dumps don't have appended dumps (nor appended).
180 struct budb_dumpEntry de, de2;
182 /* Verify the tape has not expired
183 * Early database dumps don't have a dumpid
185 if (!tapeExpired(&oldTapeLabel)) {
186 TLog(taskId, "This tape has not expired\n");
190 /* Since the dumpset on this tape will be deleted from database, check if
191 * any of the dumps in this dumpset are most-recent-dumps.
193 for (dmp=oldTapeLabel.dumpid; dmp; dmp=de.appendedDumpID) {
194 if (dmp == lastDump.id) {
195 memcpy(&de, &lastDump, sizeof(de));
196 memcpy(&de2, &lastDump, sizeof(de2));
199 code = bcdb_FindDumpByID(dmp, &de);
201 sprintf(strlevel, "%d", de.level);
202 code = bcdb_FindLatestDump(de.volumeSetName, strlevel, &de2);
206 if (de.id == de2.id) {
207 if (strcmp(DUMP_TAPE_NAME,de2.name) == 0) {
208 ErrorLog(0, taskId, 0, 0,
209 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
213 ErrorLog(0, taskId, 0, 0,
214 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
215 de.volumeSetName, de.name, de.id);
221 /* Otherwise, the savedb is in progress and we can't
222 * access the database (it's locked). So we rely on the
223 * information available (and not the backup database).
226 /* Check the tape's expiration date. Use the expiration on the label */
227 gettimeofday(&tp,&tzp);
229 if (curTime < oldTapeLabel.expirationDate) {
230 TLog(taskId, "This tape has not expired\n");
234 /* Check if this previous-dump of the dump-in-progress is on this tape */
235 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == lastDump.id)) {
236 ErrorLog(0, taskId, 0, 0,
237 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
238 lastDump.name, lastDump.id);
244 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
245 newLabel.expirationDate = expires;
246 newLabel.useCount = oldTapeLabel.useCount + 1;
247 newLabel.dumpid = dumpid;
248 newLabel.size = tapeInfoPtr->tapeSize;
250 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
253 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't label tape\n");
259 /* Initialize a tapeEntry for later inclusion into the database*/
260 listEntryPtr = (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
261 if (!listEntryPtr) ERROR_EXIT(TC_NOMEMORY);
262 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
264 /* Remember dumpid so we can delete it later */
265 if ( (oldTapeLabel.structVersion >= TAPE_VERSION_3) && oldTapeLabel.dumpid )
266 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
268 /* Fill in tape entry so we can save it later */
269 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
270 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
271 tapeEntryPtr->written = newLabel.creationTime;
272 tapeEntryPtr->expires = expires;
273 tapeEntryPtr->seq = sequence;
274 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
275 tapeEntryPtr->dump = dumpid;
276 tapeEntryPtr->useKBytes = 0;
277 tapeEntryPtr->labelpos = 0;
279 /* Thread onto end of single-linked list */
282 endList = listEntryHead;
283 while ( endList->next )
284 endList = endList->next;
285 endList->next = listEntryPtr;
288 listEntryHead = listEntryPtr;
296 * With the list of tapes, free the structures.
299 afs_int32 freeTapeList()
301 struct tapeEntryList *next;
303 listEntryPtr = listEntryHead;
304 while ( listEntryPtr )
306 next = listEntryPtr->next;
311 listEntryHead = NULL;
316 * With the list of tapes, add them to the database.
317 * Also delete any olddumpids that are around.
320 afs_int32 addTapesToDb(taskId)
325 struct tapeEntryList *next;
327 listEntryPtr = listEntryHead;
328 while ( listEntryPtr )
330 next = listEntryPtr->next;
332 /* Remove the old database entry */
333 if ( listEntryPtr->oldDumpId )
335 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
336 if (i && (i != BUDB_NOENT))
338 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
339 listEntryPtr->oldDumpId);
343 /* Add the tape to the database */
344 code = bcdb_UseTape(tapeEntryPtr, &new);
347 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n", tapeEntryPtr->name);
351 code = bcdb_FinishTape(tapeEntryPtr);
354 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n", tapeEntryPtr->name);
366 * dump backup database to tape
370 saveDbToTape(saveDbIfPtr)
371 struct saveDbIf *saveDbIfPtr;
380 struct butm_tapeInfo tapeInfo;
381 struct budb_dumpEntry dumpEntry;
382 struct tapeEntryList *next;
383 struct budb_dumpEntry de;
385 extern struct deviceSyncNode *deviceLatch;
386 extern struct tapeConfig globalTapeConfig;
388 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
389 taskId = saveDbIfPtr->taskId;
391 setStatus(taskId, DRIVE_WAIT);
392 EnterDeviceQueue(deviceLatch); /* lock tape device */
393 clearStatus(taskId, DRIVE_WAIT);
396 TLog(taskId, "SaveDb\n");
398 tapeInfo.structVersion = BUTM_MAJORVERSION;
399 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
402 ErrorLog(0, taskId, code, tapeInfo.error, "Can't initialize tape module\n");
406 /* Determine what the last database dump was */
407 memset(&lastDump, 0, sizeof(lastDump));
408 code = bcdb_FindLatestDump("", "", &lastDump);
410 if (code != BUDB_NODUMPNAME) {
411 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
414 memset(&lastDump, 0, sizeof(lastDump));
417 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
420 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
425 listEntryHead = NULL;
427 /* Get the tape and write a new label to it */
428 code = GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery, &wroteLabel);
431 * If did not write the label, remove created dump
432 * Else if wrote the label, remove old dump from db so it's not saved.
436 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
438 if ( i && (i != BUDB_NOENT) )
439 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n", dumpEntry.id);
441 else if (listEntryHead->oldDumpId)
443 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
444 listEntryHead->oldDumpId = 0;
445 if ( i && (i != BUDB_NOENT) )
447 ErrorLog(0, taskId, i, 0,
448 "Unable to delete old DB entry %u.\n", listEntryHead->oldDumpId);
452 if (code) ERROR_EXIT(code);
454 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
456 /* we have a writable tape */
457 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
458 if (code) ERROR_EXIT(code);
460 /* Now delete the entries between time 0 and archive-time */
461 if (saveDbIfPtr->archiveTime)
462 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
465 unmountTape(taskId, &tapeInfo);
467 /* Add this dump's tapes to the database and mark it finished */
470 i = addTapesToDb(taskId);
471 if ( !code ) code = i;
473 i = bcdb_FinishDump(&dumpEntry);
474 if ( !code ) code = i;
478 if (code == TC_ABORTEDBYREQUEST)
480 TLog(taskId, "SaveDb: Aborted by request\n");
481 clearStatus(taskId, ABORT_REQUEST);
482 setStatus (taskId, ABORT_DONE);
486 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
487 setStatus(taskId, TASK_ERROR);
491 TLog(taskId, "SaveDb: Finished\n");
493 setStatus(taskId, TASK_DONE);
496 LeaveDeviceQueue(deviceLatch);
507 * Make a database dump entry given a tape label.
510 afs_int32 makeDbDumpEntry(tapeEntPtr, dumpEntryPtr)
511 struct budb_tapeEntry *tapeEntPtr;
512 struct budb_dumpEntry *dumpEntryPtr;
516 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
518 dumpEntryPtr->id = tapeEntPtr->dump;
519 dumpEntryPtr->initialDumpID = 0;
520 dumpEntryPtr->parent = 0;
521 dumpEntryPtr->level = 0;
522 dumpEntryPtr->flags = 0;
524 strcpy(dumpEntryPtr->volumeSetName, "");
525 strcpy(dumpEntryPtr->dumpPath, "");
526 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
528 dumpEntryPtr->created = tapeEntPtr->dump;
529 dumpEntryPtr->incTime = 0;
530 dumpEntryPtr->nVolumes = 0;
532 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
533 strcat(dumpEntryPtr->tapes.format, ".%d");
534 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
535 dumpEntryPtr->tapes.maxTapes = 0;
539 * prompt for a specific database tape
542 afs_int32 readDbTape(tapeInfoPtr, rstTapeInfoPtr, query)
543 struct butm_tapeInfo *tapeInfoPtr;
544 struct rstTapeInfo *rstTapeInfoPtr;
550 struct butm_tapeLabel oldTapeLabel;
551 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
552 struct tapeEntryList *endList;
554 struct budb_dumpEntry de;
555 struct budb_tapeEntry te;
557 taskId = rstTapeInfoPtr->taskId;
558 interactiveFlag = query;
560 /* construct the name of the tape */
561 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
562 strcpy(tapeName, AFStapeName);
564 /* Will prompt for the latest saved database tape, but will accept any one */
565 if (rstTapeInfoPtr->tapeSeq == 1)
567 code = bcdb_FindLatestDump("", "", &de);
568 if (!code) rstTapeInfoPtr->dumpid = de.id;
570 if (rstTapeInfoPtr->dumpid)
572 code = bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq, &te);
573 if (!code) strcpy(tapeName, te.name);
579 if (interactiveFlag) /* need a tape to read */
581 code = PromptForTape(RESTOREDBOPCODE, tapeName,
582 rstTapeInfoPtr->dumpid, taskId, tapecount);
583 if (code) ERROR_EXIT(code);
588 code = butm_Mount(tapeInfoPtr, tapeName);
591 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
595 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
598 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't read tape label\n");
602 /* Check for name of tape and matching dump id (if applicable). */
603 if ( (strcmp(oldTapeLabel.AFSName, AFStapeName) != 0) ||
604 ( (rstTapeInfoPtr->tapeSeq != 1) &&
605 (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid) ) )
607 char expTape[BU_MAXTAPELEN+32];
608 char gotTape[BU_MAXTAPELEN+32];
610 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
611 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
613 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape, gotTape);
617 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
618 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
623 unmountTape(taskId, tapeInfoPtr);
627 /* Initialize a tapeEntry for later inclusion into the database*/
628 listEntryPtr = (struct tapeEntryList *) malloc(sizeof(struct tapeEntryList));
629 if (!listEntryPtr) ERROR_EXIT(TC_NOMEMORY);
630 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
632 /* Fill in tape entry so we can save it later */
633 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
634 tapeEntryPtr->dump = oldTapeLabel.dumpid;
635 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
636 tapeEntryPtr->written = oldTapeLabel.creationTime;
637 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
638 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
639 tapeEntryPtr->useCount = oldTapeLabel.useCount;
640 tapeEntryPtr->useKBytes = 0;
641 tapeEntryPtr->labelpos = 0;
643 /* Thread onto end of single-linked list */
646 endList = listEntryHead;
647 while ( endList->next )
648 endList = endList->next;
649 endList->next = listEntryPtr;
652 listEntryHead = listEntryPtr;
659 * restore the backup database from tape.
663 restoreDbFromTape(taskId)
668 struct dumpNode *node;
669 struct butm_tapeInfo tapeInfo;
670 struct rstTapeInfo rstTapeInfo;
671 struct budb_dumpEntry dumpEntry;
673 extern struct tapeConfig globalTapeConfig;
674 extern struct deviceSyncNode *deviceLatch;
676 setStatus(taskId, DRIVE_WAIT);
677 EnterDeviceQueue(deviceLatch); /* lock tape device */
678 clearStatus(taskId, DRIVE_WAIT);
681 TLog(taskId, "RestoreDb\n");
683 tapeInfo.structVersion = BUTM_MAJORVERSION;
684 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
687 ErrorLog(0, taskId, code, tapeInfo.error, "Can't initialize tape module\n");
691 listEntryHead = NULL;
693 rstTapeInfo.taskId = taskId;
694 rstTapeInfo.tapeSeq = 1;
695 rstTapeInfo.dumpid = 0;
697 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
698 if (code) ERROR_EXIT(code);
700 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
701 if (code) ERROR_EXIT(code);
704 /* Now put this dump into the database */
705 /* Make a dump entry from first tape */
706 listEntryPtr = listEntryHead;
709 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
710 if (dumpEntry.id != 0)
712 i = bcdb_CreateDump(&dumpEntry);
715 if (i == BUDB_DUMPIDEXISTS)
716 fprintf(stderr, "Dump id %d not added to database - already exists\n",
719 TapeLog(0, taskId, i, 0, "Dump id %d not added to database\n", dumpEntry.id);
723 i = addTapesToDb(taskId);
726 i = bcdb_FinishDump(&dumpEntry);
733 unmountTape(taskId, &tapeInfo);
736 if (code == TC_ABORTEDBYREQUEST)
738 TLog(taskId, "RestoreDb: Aborted by request\n");
739 clearStatus(taskId, ABORT_REQUEST);
740 setStatus (taskId, ABORT_DONE);
744 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
745 setStatus(taskId, TASK_ERROR);
749 TLog(taskId, "RestoreDb: Finished\n");
752 LeaveDeviceQueue(deviceLatch);
753 setStatus(taskId, TASK_DONE);
760 * While dumping the database, keeps the connection alive.
761 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
762 * This resets the database's internal timer so that it does not
763 * prematuraly quit (on asking for new tapes and such).
765 * Use the same udbHandle as writeDbDump so we go to the same server.
773 extern struct udbHandleS udbHandle;
777 #ifdef AFS_PTHREAD_ENV
782 charList.charListT_val = 0;
783 charList.charListT_len = 0;
784 code = ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
786 0, 0, &charList, &done);
792 #define BIGCHUNK 102400
796 * this code assumes that the blocksize on reads is smaller than
797 * the blocksize on writes
801 writeDbDump(tapeInfoPtr, taskId, expires, dumpid)
802 struct butm_tapeInfo *tapeInfoPtr;
808 afs_int32 writeBufNbytes = 0;
809 char *writeBlock = 0;
810 char *writeBuffer = 0;
812 afs_int32 transferSize;
815 afs_int32 maxReadSize;
820 afs_int32 chunksize = 0;
821 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
825 #ifdef AFS_PTHREAD_ENV
827 pthread_attr_t tattr;
833 extern struct tapeConfig globalTapeConfig;
834 extern struct udbHandleS udbHandle;
836 extern int KeepAlive();
838 blockSize = BUTM_BLKSIZE;
839 writeBlock = (char *) malloc(BUTM_BLOCKSIZE);
840 if (!writeBlock) ERROR_EXIT(TC_NOMEMORY);
842 writeBuffer = writeBlock + sizeof(struct blockMark);
843 memset(writeBuffer, 0, BUTM_BLKSIZE);
847 * The margin of space to check for end of tape is set to the
848 * amount of space used to write an end-of-tape multiplied by 2.
849 * The amount of space is size of a 16K EODump marker, its EOF
850 * marker, and up to two EOF markers done on close (1 16K blocks +
853 tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
854 tc_KEndMargin = tc_EndMargin / 1024;
856 /* have to write enclose the dump in file marks */
857 code = butm_WriteFileBegin(tapeInfoPtr);
860 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't write FileBegin on tape\n");
864 writeBufPtr = &writeBuffer[0];
867 charList.charListT_val = 0;
868 charList.charListT_len = 0;
872 /* When no data in buffer, read data from the budb_server */
873 if ( charList.charListT_len == 0 )
875 /* get more data. let rx allocate space */
876 if ( charList.charListT_val )
878 free(charList.charListT_val);
879 charList.charListT_val = 0;
883 code = ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
885 firstcall, maxReadSize, &charList, &done);
888 ErrorLog(0, taskId, code, 0, "Can't read database\n");
892 /* If this if the first call to the budb server, create a thread
893 * that will keep the connection alive (during tape changes).
896 #ifdef AFS_PTHREAD_ENV
897 code = pthread_attr_init(&tattr);
899 ErrorLog(0, taskId, code, 0, "Can't pthread_attr_init Keep-alive process\n");
903 code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
905 ErrorLog(0, taskId, code, 0, "Can't pthread_attr_setdetachstate Keep-alive process\n");
910 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
911 AFS_SIGSET_RESTORE();
913 code = LWP_CreateProcess(KeepAlive, 16384, 1, (void *) NULL,
914 "Keep-alive process", &alivePid);
916 /* XXX should we check code here ??? XXX */
920 readBufPtr = charList.charListT_val;
923 if ( (charList.charListT_len == 0) && done )
926 /* compute how many bytes and transfer to the write Buffer */
927 transferSize = (charList.charListT_len < (blockSize - writeBufNbytes)) ?
928 charList.charListT_len : (blockSize - writeBufNbytes);
930 memcpy(writeBufPtr, readBufPtr, transferSize);
931 charList.charListT_len -= transferSize;
932 writeBufPtr += transferSize;
933 readBufPtr += transferSize;
934 writeBufNbytes += transferSize;
936 /* If filled the write buffer, then write it to tape */
937 if (writeBufNbytes == blockSize)
939 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
942 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't write data on tape\n");
946 memset(writeBuffer, 0, blockSize);
947 writeBufPtr = &writeBuffer[0];
950 /* Every BIGCHUNK bytes check if aborted */
951 chunksize += blockSize;
952 if ( chunksize > BIGCHUNK )
955 if ( checkAbortByTaskId(taskId) ) ERROR_EXIT(TC_ABORTEDBYREQUEST);
959 * check if tape is full - since we filled a blockSize worth of data
960 * assume that there is more data.
962 kRemaining = butm_remainingKSpace(tapeInfoPtr);
963 if( kRemaining < tc_KEndMargin )
965 code = butm_WriteFileEnd(tapeInfoPtr);
968 ErrorLog(0, taskId, code, tapeInfoPtr->error,
969 "Can't write FileEnd on tape\n");
973 code = butm_WriteEOT(tapeInfoPtr);
976 ErrorLog(0, taskId, code, tapeInfoPtr->error,
977 "Can't write end-of-dump on tape\n");
981 /* Mark tape as having been written */
982 tapeEntryPtr->useKBytes = tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
983 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
985 unmountTape(taskId, tapeInfoPtr);
987 /* Get next tape and writes its label */
989 code = GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, 1, &wroteLabel);
990 if (code) ERROR_EXIT(code);
992 code = butm_WriteFileBegin(tapeInfoPtr);
995 ErrorLog(0, taskId, code, tapeInfoPtr->error,
996 "Can't write FileBegin on tape\n");
1003 /* no more data to be read - if necessary, flush out the last buffer */
1004 if (writeBufNbytes > 0)
1006 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
1009 ErrorLog(1, taskId, code, tapeInfoPtr->error, "Can't write data on tape\n");
1014 code = butm_WriteFileEnd(tapeInfoPtr);
1017 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't write FileEnd on tape\n");
1021 /* Mark tape as having been written */
1022 tapeEntryPtr->useKBytes = tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1023 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1026 /* Let the KeepAlive process stop on its own */
1027 code = ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client, UF_END_SINGLESERVER, 0);
1029 if ( writeBlock ) free(writeBlock);
1030 if ( charList.charListT_val ) free(charList.charListT_val);
1036 * restore all the items on the tape
1038 * tape positioned after tape label
1042 restoreDbEntries(tapeInfoPtr, rstTapeInfoPtr)
1043 struct butm_tapeInfo *tapeInfoPtr;
1044 struct rstTapeInfo *rstTapeInfoPtr;
1046 struct structDumpHeader netItemHeader, hostItemHeader;
1048 afs_int32 taskId, code = 0;
1051 taskId = rstTapeInfoPtr->taskId;
1053 /* clear state for the buffer routine(s) */
1054 initTapeBuffering();
1056 code = butm_ReadFileBegin(tapeInfoPtr);
1059 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't read FileBegin on tape\n");
1063 /* get the first item-header */
1064 memset(&netItemHeader, 0, sizeof(netItemHeader));
1065 code = getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1066 if (code) ERROR_EXIT(code);
1067 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
1071 switch (hostItemHeader.type)
1074 code = restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
1075 if (code) ERROR_EXIT(code);
1079 if (++count > 25) { /*every 25 dumps, wait */
1083 code = restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
1084 if (code) ERROR_EXIT(code);
1092 case SD_TEXT_DUMPSCHEDULE:
1093 case SD_TEXT_VOLUMESET:
1094 case SD_TEXT_TAPEHOSTS:
1095 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
1096 if (code) ERROR_EXIT(code);
1104 TLog(taskId, "Unknown database header type %d\n", hostItemHeader.type);
1110 code = butm_ReadFileEnd(tapeInfoPtr);
1113 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't read EOF on tape\n");
1117 /* Mark tape as having been written */
1118 tapeEntryPtr->useKBytes = tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1119 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1126 * restore special items in the header
1129 restoreDbHeader(tapeInfo, rstTapeInfoPtr, nextHeader)
1130 struct butm_tapeInfo *tapeInfo;
1131 struct rstTapeInfo *rstTapeInfoPtr;
1132 struct structDumpHeader *nextHeader;
1134 struct structDumpHeader netItemHeader;
1135 struct DbHeader netDbHeader, hostDbHeader;
1138 extern struct udbHandleS udbHandle;
1140 /* Read the database header */
1141 memset(&netDbHeader, 0, sizeof(netDbHeader));
1142 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader, sizeof(netDbHeader));
1143 if (code) ERROR_EXIT(code);
1144 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1146 /* Add the database header to the database */
1147 code = ubik_Call(BUDB_RestoreDbHeader, udbHandle.uh_client, 0, &hostDbHeader);
1150 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0, "Can't restore DB Header\n");
1154 /* get the next item-header */
1155 memset(nextHeader, 0, sizeof(*nextHeader));
1156 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1157 if (code) ERROR_EXIT(code);
1158 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1166 * restore a single dump, including all its tapes and volumes, from
1169 * nextHeader - ptr to structure for return value
1171 * nextHeader - next structure header from tape
1173 * upon entry, the dump structure header has been read confirming that
1174 * a database dump tree exists on the tape
1177 restoreDbDump(tapeInfo, rstTapeInfoPtr, nextHeader)
1178 struct butm_tapeInfo *tapeInfo;
1179 struct rstTapeInfo *rstTapeInfoPtr;
1180 struct structDumpHeader *nextHeader;
1182 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1183 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1184 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1185 struct structDumpHeader netItemHeader;
1186 afs_int32 newTape, taskId;
1187 int restoreThisDump = 1;
1188 afs_int32 code = 0, tcode;
1190 extern struct udbHandleS udbHandle;
1192 taskId = rstTapeInfoPtr->taskId;
1194 /* read dump entry */
1195 memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1196 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry, sizeof(netDumpEntry));
1197 if (code) ERROR_EXIT(code);
1199 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1200 if (rstTapeInfoPtr->dumpid == 0)
1202 netDumpEntry.initialDumpID = 0;
1203 netDumpEntry.appendedDumpID = 0;
1206 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1208 /* The dump entry for this database tape is incomplete, so don't include it */
1209 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1210 restoreThisDump = 0;
1212 /* add the dump to the database */
1213 if (restoreThisDump) {
1214 code = threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry), DLQ_USEDUMP);
1215 if (code) ERROR_EXIT(code);
1218 /* get the next item-header */
1219 memset(nextHeader, 0, sizeof(*nextHeader));
1220 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1221 if (code) ERROR_EXIT(code);
1222 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1224 /* Add every tape to the db */
1225 while ( nextHeader->type == SD_TAPE )
1228 /* read the tape entry */
1229 memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1230 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry, sizeof(netTapeEntry));
1231 if (code) ERROR_EXIT(code);
1232 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1234 /* Add the tape to the database */
1235 if (restoreThisDump) {
1236 code = threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry), DLQ_USETAPE);
1237 if (code) ERROR_EXIT(code);
1240 /* get the next item-header */
1241 memset(nextHeader, 0, sizeof(*nextHeader));
1242 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1243 if (code) ERROR_EXIT(code);
1244 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1246 /* Add every volume to the db */
1247 while ( nextHeader->type == SD_VOLUME )
1250 /* read the volume entry */
1251 memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1252 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry, sizeof(netVolumeEntry));
1253 if (code) ERROR_EXIT(code);
1254 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1256 if (restoreThisDump) {
1257 code = threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry), DLQ_VOLENTRY);
1258 if (code) ERROR_EXIT(code);
1261 /* get the next item-header */
1262 memset(nextHeader, 0, sizeof(*nextHeader));
1263 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1264 if (code) ERROR_EXIT(code);
1265 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1268 /* Finish the tape */
1269 if (restoreThisDump) {
1270 code = threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry), DLQ_FINISHTAPE);
1271 if (code) ERROR_EXIT(code);
1275 /* Finish the dump */
1276 if (restoreThisDump) {
1277 code = threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry), DLQ_FINISHDUMP);
1278 if (code) ERROR_EXIT(code);
1286 * Save the specified file as configuration text in the ubik database.
1287 * Have to setup the client text structure so that we can call
1288 * the routine to transmit the text to the db.
1292 saveTextFile(taskId, textType, fileName)
1297 udbClientTextP ctPtr = 0;
1301 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1302 if (!ctPtr) ERROR_EXIT(TC_NOMEMORY);
1304 memset(ctPtr, 0, sizeof(*ctPtr));
1305 ctPtr->textType = textType;
1307 /* lock the text in the database */
1308 code = bc_LockText(ctPtr);
1311 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1316 ctPtr->textStream = fopen(fileName, "r");
1317 if (!ctPtr->textStream)
1319 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1323 /* now send the text to the database */
1324 code = bcdb_SaveTextFile(ctPtr);
1327 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1334 if (ctPtr->textStream) fclose(ctPtr->textStream);
1335 if (tlock) bc_UnlockText(ctPtr);
1342 * read the text off the tape, and store it in the appropriate
1343 * text type in the database.
1345 * nextHeader - ptr to struct for return information
1347 * nextHeader - struct header for next item on the tape
1350 restoreText(tapeInfo, rstTapeInfoPtr, nextHeader)
1351 struct butm_tapeInfo *tapeInfo;
1352 struct rstTapeInfo *rstTapeInfoPtr;
1353 struct structDumpHeader *nextHeader;
1357 char *readBuffer = 0;
1358 afs_int32 readBlockSize;
1359 afs_int32 transferSize;
1360 struct structDumpHeader netItemHeader;
1364 udbClientTextP ctPtr = 0;
1367 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1368 if (!ctPtr) ERROR_EXIT(TC_NOMEMORY);
1370 /* determine the type of text block */
1371 switch (nextHeader->type)
1373 case SD_TEXT_DUMPSCHEDULE:
1374 textType = TB_DUMPSCHEDULE;
1377 case SD_TEXT_VOLUMESET:
1378 textType = TB_VOLUMESET;
1381 case SD_TEXT_TAPEHOSTS:
1382 textType = TB_TAPEHOSTS;
1386 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0, "Unknown text block\n");
1387 ERROR_EXIT(TC_INTERNALERROR);
1391 /* open the text file */
1392 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1393 #if defined (AFS_LINUX20_ENV)
1394 fid = open(mkstemp(filename), O_RDWR|O_CREAT|O_EXCL, 0600);
1395 #elif defined (HAVE_MKSTEMP)
1396 fid = mkstemp(filename);
1398 fid = open(mktemp(filename), O_RDWR|O_CREAT|O_EXCL, 0600);
1402 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1403 "Can't open temporary text file: %s\n", filename);
1407 /* allocate buffer for text */
1408 readBlockSize = BUTM_BLKSIZE;
1409 readBuffer = (char *) malloc(readBlockSize);
1410 if (!readBuffer) ERROR_EXIT(TC_NOMEMORY);
1412 /* read the text into the temporary file */
1413 nbytes = nextHeader->size;
1414 while ( nbytes > 0 )
1416 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1418 /* read it from the tape */
1419 code = getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1420 if (code) ERROR_EXIT(code);
1422 /* write to the file */
1423 if ( write(fid, readBuffer, transferSize) != transferSize )
1425 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1426 "Can't write temporary text file: %s\n", filename);
1430 nbytes -= transferSize;
1435 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1436 if (code) ERROR_EXIT(code);
1439 /* get the next item-header */
1440 memset(nextHeader, 0, sizeof(*nextHeader));
1441 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1442 if (code) ERROR_EXIT(code);
1443 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1446 if (ctPtr) free(ctPtr);
1447 if (readBuffer) free(readBuffer);
1457 /* ----------------------------------
1458 * Tape data buffering - for reading database dumps
1459 * ----------------------------------
1462 static char *tapeReadBuffer = 0; /* input buffer */
1463 static char *tapeReadBufferPtr = 0; /* position in buffer */
1464 static afs_int32 nbytes = 0; /* # bytes left in buffer */
1473 * Read information from tape, and place the requested number of bytes
1474 * in the buffer supplied
1477 * rstTapeInfoPtr - Info about the dump being restored.
1478 * buffer - buffer for requested data
1479 * requestedBytes - no. of bytes requested
1481 * fn retn - 0, ok, n, error
1484 getTapeData(tapeInfoPtr, rstTapeInfoPtr, buffer, requestedBytes)
1485 struct butm_tapeInfo *tapeInfoPtr;
1486 struct rstTapeInfo *rstTapeInfoPtr;
1488 afs_int32 requestedBytes;
1490 afs_int32 taskId, transferBytes, new;
1494 taskId = rstTapeInfoPtr->taskId;
1496 if ( checkAbortByTaskId(taskId) ) ERROR_EXIT(TC_ABORTEDBYREQUEST);
1498 if (!tapeReadBuffer)
1500 tapeReadBuffer = (char *) malloc(BUTM_BLOCKSIZE);
1501 if (!tapeReadBuffer) ERROR_EXIT(TC_NOMEMORY);
1504 while ( requestedBytes > 0 )
1508 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1511 code = butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr, BUTM_BLKSIZE, &nbytes);
1514 /* detect if we hit the end-of-tape and get next tape */
1515 if (code == BUTM_ENDVOLUME)
1517 /* Update fields in tape entry for this tape */
1518 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1519 tapeEntryPtr->useKBytes = tapeInfoPtr->kBytes +
1520 (tapeInfoPtr->nBytes ? 1 : 0);
1522 unmountTape(taskId, tapeInfoPtr);
1524 rstTapeInfoPtr->tapeSeq++;
1525 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1526 if (code) ERROR_EXIT(code);
1528 code = butm_ReadFileBegin(tapeInfoPtr);
1531 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1532 "Can't read FileBegin on tape\n");
1539 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't read FileData on tape\n");
1545 transferBytes = (nbytes < requestedBytes ) ? nbytes : requestedBytes;
1546 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1547 tapeReadBufferPtr += transferBytes;
1548 buffer += transferBytes;
1549 nbytes -= transferBytes;
1550 requestedBytes -= transferBytes;