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 <afs/param.h>
11 #include <sys/types.h>
18 #include <netinet/in.h>
24 #include <afs/afsint.h>
26 #include <afs/procmgmt.h>
27 #include <afs/assert.h>
28 #include <afs/prs_fs.h>
34 #include <afs/cellconfig.h>
38 #include <afs/tcdata.h>
40 #include <afs/budb_client.h>
41 #include <afs/bubasics.h>
42 #include "error_macros.h"
44 /* GLOBAL CONFIGURATION PARAMETERS */
45 extern int dump_namecheck;
49 * create a dump entry for a saved database
52 afs_int32 CreateDBDump(dumpEntryPtr)
53 struct budb_dumpEntry *dumpEntryPtr;
57 bzero(dumpEntryPtr, sizeof(struct budb_dumpEntry));
59 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
60 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
61 strcat(dumpEntryPtr->tapes.format, ".%d");
62 strcpy(dumpEntryPtr->volumeSetName, "");
63 strcpy(dumpEntryPtr->dumpPath, "");
64 dumpEntryPtr->created = 0; /* let database assign it */
65 dumpEntryPtr->incTime = 0;
66 dumpEntryPtr->nVolumes = 0;
67 dumpEntryPtr->initialDumpID = 0;
68 dumpEntryPtr->parent = 0;
69 dumpEntryPtr->level = 0;
70 dumpEntryPtr->tapes.maxTapes = 0;
71 dumpEntryPtr->tapes.b = 1;
73 /* now call the database to create the entry */
74 code = bcdb_CreateDump(dumpEntryPtr);
80 struct tapeEntryList *next;
82 struct budb_tapeEntry tapeEnt;
84 struct tapeEntryList *listEntryHead;
85 struct tapeEntryList *listEntryPtr;
86 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
87 struct budb_dumpEntry lastDump; /* the last dump of this volset */
90 * Load a DB tape, read and over write its label.
91 * Leave the tape mounted.
93 afs_int32 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag, wroteLabel)
96 struct butm_tapeInfo *tapeInfoPtr;
104 char tapeName[BU_MAXTAPELEN];
112 struct butm_tapeLabel oldTapeLabel, newLabel;
113 struct tapeEntryList *endList;
114 extern struct tapeConfig globalTapeConfig;
116 /* construct the name of the tape */
117 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
119 interactiveFlag = queryFlag;
122 while ( ! *wroteLabel )
124 if ( interactiveFlag ) /* need a tape to write */
126 code = PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId, tapecount);
127 if (code) ERROR_EXIT(code);
132 code = butm_Mount(tapeInfoPtr, tapeName);
135 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
139 bzero(&oldTapeLabel, sizeof(oldTapeLabel));
140 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
143 oldTapeLabel.useCount = 0; /* no label exists */
144 oldTapeLabel.structVersion = 0;
145 strcpy(oldTapeLabel.pName, "");
149 /* If tape has a name, it must be null or database tape name */
150 if ( dump_namecheck &&
151 strcmp(oldTapeLabel.AFSName,"") && !databaseTape(oldTapeLabel.AFSName) )
153 char gotName[BU_MAXTAPELEN+32];
155 LABELNAME(gotName, &oldTapeLabel);
156 TLog(taskId, "This tape %s must be a database tape or NULL tape\n", gotName);
159 unmountTape(taskId, tapeInfoPtr);
163 /* Do not overwrite a tape that belongs to this dump */
164 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
165 ErrorLog(0, taskId, 0, 0,
166 "Can't overwrite tape containing the dump in progress\n");
170 /* On first tape, the savedb has not started yet, so the database is not locked
171 * and we can therefore, access information from it. This is easier to do because
172 * database dumps don't have appended dumps (nor appended).
176 struct budb_dumpEntry de, de2;
178 /* Verify the tape has not expired
179 * Early database dumps don't have a dumpid
181 if (!tapeExpired(&oldTapeLabel)) {
182 TLog(taskId, "This tape has not expired\n");
186 /* Since the dumpset on this tape will be deleted from database, check if
187 * any of the dumps in this dumpset are most-recent-dumps.
189 for (dmp=oldTapeLabel.dumpid; dmp; dmp=de.appendedDumpID) {
190 if (dmp == lastDump.id) {
191 bcopy(&lastDump, &de, sizeof(de));
192 bcopy(&lastDump, &de2, sizeof(de2));
195 code = bcdb_FindDumpByID(dmp, &de);
197 sprintf(strlevel, "%d", de.level);
198 code = bcdb_FindLatestDump(de.volumeSetName, strlevel, &de2);
202 if (de.id == de2.id) {
203 if (strcmp(DUMP_TAPE_NAME,de2.name) == 0) {
204 ErrorLog(0, taskId, 0, 0,
205 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
209 ErrorLog(0, taskId, 0, 0,
210 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
211 de.volumeSetName, de.name, de.id);
217 /* Otherwise, the savedb is in progress and we can't
218 * access the database (it's locked). So we rely on the
219 * information available (and not the backup database).
222 /* Check the tape's expiration date. Use the expiration on the label */
223 gettimeofday(&tp,&tzp);
225 if (curTime < oldTapeLabel.expirationDate) {
226 TLog(taskId, "This tape has not expired\n");
230 /* Check if this previous-dump of the dump-in-progress is on this tape */
231 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == lastDump.id)) {
232 ErrorLog(0, taskId, 0, 0,
233 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
234 lastDump.name, lastDump.id);
240 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
241 newLabel.expirationDate = expires;
242 newLabel.useCount = oldTapeLabel.useCount + 1;
243 newLabel.dumpid = dumpid;
244 newLabel.size = tapeInfoPtr->tapeSize;
246 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
249 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't label tape\n");
255 /* Initialize a tapeEntry for later inclusion into the database*/
256 listEntryPtr = (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
257 if (!listEntryPtr) ERROR_EXIT(TC_NOMEMORY);
258 bzero(listEntryPtr, sizeof(struct tapeEntryList));
260 /* Remember dumpid so we can delete it later */
261 if ( (oldTapeLabel.structVersion >= TAPE_VERSION_3) && oldTapeLabel.dumpid )
262 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
264 /* Fill in tape entry so we can save it later */
265 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
266 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
267 tapeEntryPtr->written = newLabel.creationTime;
268 tapeEntryPtr->expires = expires;
269 tapeEntryPtr->seq = sequence;
270 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
271 tapeEntryPtr->dump = dumpid;
272 tapeEntryPtr->useKBytes = 0;
273 tapeEntryPtr->labelpos = 0;
275 /* Thread onto end of single-linked list */
278 endList = listEntryHead;
279 while ( endList->next )
280 endList = endList->next;
281 endList->next = listEntryPtr;
284 listEntryHead = listEntryPtr;
292 * With the list of tapes, free the structures.
295 afs_int32 freeTapeList()
297 struct tapeEntryList *next;
299 listEntryPtr = listEntryHead;
300 while ( listEntryPtr )
302 next = listEntryPtr->next;
307 listEntryHead = (struct tapeEntryList *)0;
312 * With the list of tapes, add them to the database.
313 * Also delete any olddumpids that are around.
316 afs_int32 addTapesToDb(taskId)
321 struct tapeEntryList *next;
323 listEntryPtr = listEntryHead;
324 while ( listEntryPtr )
326 next = listEntryPtr->next;
328 /* Remove the old database entry */
329 if ( listEntryPtr->oldDumpId )
331 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
332 if (i && (i != BUDB_NOENT))
334 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
335 listEntryPtr->oldDumpId);
339 /* Add the tape to the database */
340 code = bcdb_UseTape(tapeEntryPtr, &new);
343 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n", tapeEntryPtr->name);
347 code = bcdb_FinishTape(tapeEntryPtr);
350 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n", tapeEntryPtr->name);
362 * dump backup database to tape
366 saveDbToTape(saveDbIfPtr)
367 struct saveDbIf *saveDbIfPtr;
376 struct butm_tapeInfo tapeInfo;
377 struct budb_dumpEntry dumpEntry;
378 struct tapeEntryList *next;
379 struct budb_dumpEntry de;
381 extern struct deviceSyncNode *deviceLatch;
382 extern struct tapeConfig globalTapeConfig;
384 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
385 taskId = saveDbIfPtr->taskId;
387 setStatus(taskId, DRIVE_WAIT);
388 EnterDeviceQueue(deviceLatch); /* lock tape device */
389 clearStatus(taskId, DRIVE_WAIT);
392 TLog(taskId, "SaveDb\n");
394 tapeInfo.structVersion = BUTM_MAJORVERSION;
395 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
398 ErrorLog(0, taskId, code, tapeInfo.error, "Can't initialize tape module\n");
402 /* Determine what the last database dump was */
403 bzero(&lastDump, sizeof(lastDump));
404 code = bcdb_FindLatestDump("", "", &lastDump);
406 if (code != BUDB_NODUMPNAME) {
407 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
410 bzero(&lastDump, sizeof(lastDump));
413 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
416 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
421 listEntryHead = (struct tapeEntryList *)0;
423 /* Get the tape and write a new label to it */
424 code = GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery, &wroteLabel);
427 * If did not write the label, remove created dump
428 * Else if wrote the label, remove old dump from db so it's not saved.
432 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
434 if ( i && (i != BUDB_NOENT) )
435 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n", dumpEntry.id);
437 else if (listEntryHead->oldDumpId)
439 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
440 listEntryHead->oldDumpId = 0;
441 if ( i && (i != BUDB_NOENT) )
443 ErrorLog(0, taskId, i, 0,
444 "Unable to delete old DB entry %u.\n", listEntryHead->oldDumpId);
448 if (code) ERROR_EXIT(code);
450 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
452 /* we have a writable tape */
453 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
454 if (code) ERROR_EXIT(code);
456 /* Now delete the entries between time 0 and archive-time */
457 if (saveDbIfPtr->archiveTime)
458 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
461 unmountTape(taskId, &tapeInfo);
463 /* Add this dump's tapes to the database and mark it finished */
466 i = addTapesToDb(taskId);
467 if ( !code ) code = i;
469 i = bcdb_FinishDump(&dumpEntry);
470 if ( !code ) code = i;
474 if (code == TC_ABORTEDBYREQUEST)
476 TLog(taskId, "SaveDb: Aborted by request\n");
477 clearStatus(taskId, ABORT_REQUEST);
478 setStatus (taskId, ABORT_DONE);
482 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
483 setStatus(taskId, TASK_ERROR);
487 TLog(taskId, "SaveDb: Finished\n");
489 setStatus(taskId, TASK_DONE);
492 LeaveDeviceQueue(deviceLatch);
503 * Make a database dump entry given a tape label.
506 afs_int32 makeDbDumpEntry(tapeEntPtr, dumpEntryPtr)
507 struct budb_tapeEntry *tapeEntPtr;
508 struct budb_dumpEntry *dumpEntryPtr;
512 bzero(dumpEntryPtr, sizeof(struct budb_dumpEntry));
514 dumpEntryPtr->id = tapeEntPtr->dump;
515 dumpEntryPtr->initialDumpID = 0;
516 dumpEntryPtr->parent = 0;
517 dumpEntryPtr->level = 0;
518 dumpEntryPtr->flags = 0;
520 strcpy(dumpEntryPtr->volumeSetName, "");
521 strcpy(dumpEntryPtr->dumpPath, "");
522 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
524 dumpEntryPtr->created = tapeEntPtr->dump;
525 dumpEntryPtr->incTime = 0;
526 dumpEntryPtr->nVolumes = 0;
528 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
529 strcat(dumpEntryPtr->tapes.format, ".%d");
530 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
531 dumpEntryPtr->tapes.maxTapes = 0;
535 * prompt for a specific database tape
538 afs_int32 readDbTape(tapeInfoPtr, rstTapeInfoPtr, query)
539 struct butm_tapeInfo *tapeInfoPtr;
540 struct rstTapeInfo *rstTapeInfoPtr;
546 struct butm_tapeLabel oldTapeLabel;
547 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
548 struct tapeEntryList *endList;
550 struct budb_dumpEntry de;
551 struct budb_tapeEntry te;
553 taskId = rstTapeInfoPtr->taskId;
554 interactiveFlag = query;
556 /* construct the name of the tape */
557 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
558 strcpy(tapeName, AFStapeName);
560 /* Will prompt for the latest saved database tape, but will accept any one */
561 if (rstTapeInfoPtr->tapeSeq == 1)
563 code = bcdb_FindLatestDump("", "", &de);
564 if (!code) rstTapeInfoPtr->dumpid = de.id;
566 if (rstTapeInfoPtr->dumpid)
568 code = bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq, &te);
569 if (!code) strcpy(tapeName, te.name);
575 if (interactiveFlag) /* need a tape to read */
577 code = PromptForTape(RESTOREDBOPCODE, tapeName,
578 rstTapeInfoPtr->dumpid, taskId, tapecount);
579 if (code) ERROR_EXIT(code);
584 code = butm_Mount(tapeInfoPtr, tapeName);
587 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
591 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
594 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't read tape label\n");
598 /* Check for name of tape and matching dump id (if applicable). */
599 if ( (strcmp(oldTapeLabel.AFSName, AFStapeName) != 0) ||
600 ( (rstTapeInfoPtr->tapeSeq != 1) &&
601 (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid) ) )
603 char expTape[BU_MAXTAPELEN+32];
604 char gotTape[BU_MAXTAPELEN+32];
606 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
607 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
609 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape, gotTape);
613 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
614 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
619 unmountTape(taskId, tapeInfoPtr);
623 /* Initialize a tapeEntry for later inclusion into the database*/
624 listEntryPtr = (struct tapeEntryList *) malloc(sizeof(struct tapeEntryList));
625 if (!listEntryPtr) ERROR_EXIT(TC_NOMEMORY);
626 bzero(listEntryPtr, sizeof(struct tapeEntryList));
628 /* Fill in tape entry so we can save it later */
629 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
630 tapeEntryPtr->dump = oldTapeLabel.dumpid;
631 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
632 tapeEntryPtr->written = oldTapeLabel.creationTime;
633 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
634 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
635 tapeEntryPtr->useCount = oldTapeLabel.useCount;
636 tapeEntryPtr->useKBytes = 0;
637 tapeEntryPtr->labelpos = 0;
639 /* Thread onto end of single-linked list */
642 endList = listEntryHead;
643 while ( endList->next )
644 endList = endList->next;
645 endList->next = listEntryPtr;
648 listEntryHead = listEntryPtr;
655 * restore the backup database from tape.
659 restoreDbFromTape(taskId)
664 struct dumpNode *node;
665 struct butm_tapeInfo tapeInfo;
666 struct rstTapeInfo rstTapeInfo;
667 struct budb_dumpEntry dumpEntry;
669 extern struct tapeConfig globalTapeConfig;
670 extern struct deviceSyncNode *deviceLatch;
672 setStatus(taskId, DRIVE_WAIT);
673 EnterDeviceQueue(deviceLatch); /* lock tape device */
674 clearStatus(taskId, DRIVE_WAIT);
677 TLog(taskId, "RestoreDb\n");
679 tapeInfo.structVersion = BUTM_MAJORVERSION;
680 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
683 ErrorLog(0, taskId, code, tapeInfo.error, "Can't initialize tape module\n");
687 listEntryHead = (struct tapeEntryList *)0;
689 rstTapeInfo.taskId = taskId;
690 rstTapeInfo.tapeSeq = 1;
691 rstTapeInfo.dumpid = 0;
693 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
694 if (code) ERROR_EXIT(code);
696 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
697 if (code) ERROR_EXIT(code);
700 /* Now put this dump into the database */
701 /* Make a dump entry from first tape */
702 listEntryPtr = listEntryHead;
705 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
706 if (dumpEntry.id != 0)
708 i = bcdb_CreateDump(&dumpEntry);
711 if (i == BUDB_DUMPIDEXISTS)
712 fprintf(stderr, "Dump id %d not added to database - already exists\n",
715 TapeLog(0, taskId, i, 0, "Dump id %d not added to database\n", dumpEntry.id);
719 i = addTapesToDb(taskId);
722 i = bcdb_FinishDump(&dumpEntry);
729 unmountTape(taskId, &tapeInfo);
732 if (code == TC_ABORTEDBYREQUEST)
734 TLog(taskId, "RestoreDb: Aborted by request\n");
735 clearStatus(taskId, ABORT_REQUEST);
736 setStatus (taskId, ABORT_DONE);
740 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
741 setStatus(taskId, TASK_ERROR);
745 TLog(taskId, "RestoreDb: Finished\n");
748 LeaveDeviceQueue(deviceLatch);
749 setStatus(taskId, TASK_DONE);
756 * While dumping the database, keeps the connection alive.
757 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
758 * This resets the database's internal timer so that it does not
759 * prematuraly quit (on asking for new tapes and such).
761 * Use the same udbHandle as writeDbDump so we go to the same server.
769 extern struct udbHandleS udbHandle;
773 #ifdef AFS_PTHREAD_ENV
778 charList.charListT_val = 0;
779 charList.charListT_len = 0;
780 code = ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
782 0, 0, &charList, &done);
788 #define BIGCHUNK 102400
792 * this code assumes that the blocksize on reads is smaller than
793 * the blocksize on writes
797 writeDbDump(tapeInfoPtr, taskId, expires, dumpid)
798 struct butm_tapeInfo *tapeInfoPtr;
804 afs_int32 writeBufNbytes = 0;
805 char *writeBlock = 0;
806 char *writeBuffer = 0;
808 afs_int32 transferSize;
811 afs_int32 maxReadSize;
816 afs_int32 chunksize = 0;
817 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
821 #ifdef AFS_PTHREAD_ENV
823 pthread_attr_t tattr;
829 extern struct tapeConfig globalTapeConfig;
830 extern struct udbHandleS udbHandle;
832 extern int KeepAlive();
834 blockSize = BUTM_BLKSIZE;
835 writeBlock = (char *) malloc(BUTM_BLOCKSIZE);
836 if (!writeBlock) ERROR_EXIT(TC_NOMEMORY);
838 writeBuffer = writeBlock + sizeof(struct blockMark);
839 bzero(writeBuffer, BUTM_BLKSIZE);
843 * The margin of space to check for end of tape is set to the
844 * amount of space used to write an end-of-tape multiplied by 2.
845 * The amount of space is size of a 16K EODump marker, its EOF
846 * marker, and up to two EOF markers done on close (1 16K blocks +
849 tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
850 tc_KEndMargin = tc_EndMargin / 1024;
852 /* have to write enclose the dump in file marks */
853 code = butm_WriteFileBegin(tapeInfoPtr);
856 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't write FileBegin on tape\n");
860 writeBufPtr = &writeBuffer[0];
863 charList.charListT_val = 0;
864 charList.charListT_len = 0;
868 /* When no data in buffer, read data from the budb_server */
869 if ( charList.charListT_len == 0 )
871 /* get more data. let rx allocate space */
872 if ( charList.charListT_val )
874 free(charList.charListT_val);
875 charList.charListT_val = 0;
879 code = ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
881 firstcall, maxReadSize, &charList, &done);
884 ErrorLog(0, taskId, code, 0, "Can't read database\n");
888 /* If this if the first call to the budb server, create a thread
889 * that will keep the connection alive (during tape changes).
892 #ifdef AFS_PTHREAD_ENV
893 code = pthread_attr_init(&tattr);
895 ErrorLog(0, taskId, code, 0, "Can't pthread_attr_init Keep-alive process\n");
899 code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
901 ErrorLog(0, taskId, code, 0, "Can't pthread_attr_setdetachstate Keep-alive process\n");
906 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
907 AFS_SIGSET_RESTORE();
909 code = LWP_CreateProcess(KeepAlive, 16384, 1, (char *)0,
910 "Keep-alive process", &alivePid);
912 /* XXX should we check code here ??? XXX */
916 readBufPtr = charList.charListT_val;
919 if ( (charList.charListT_len == 0) && done )
922 /* compute how many bytes and transfer to the write Buffer */
923 transferSize = (charList.charListT_len < (blockSize - writeBufNbytes)) ?
924 charList.charListT_len : (blockSize - writeBufNbytes);
926 bcopy(readBufPtr, writeBufPtr, transferSize);
927 charList.charListT_len -= transferSize;
928 writeBufPtr += transferSize;
929 readBufPtr += transferSize;
930 writeBufNbytes += transferSize;
932 /* If filled the write buffer, then write it to tape */
933 if (writeBufNbytes == blockSize)
935 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
938 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't write data on tape\n");
942 bzero(writeBuffer, blockSize);
943 writeBufPtr = &writeBuffer[0];
946 /* Every BIGCHUNK bytes check if aborted */
947 chunksize += blockSize;
948 if ( chunksize > BIGCHUNK )
951 if ( checkAbortByTaskId(taskId) ) ERROR_EXIT(TC_ABORTEDBYREQUEST);
955 * check if tape is full - since we filled a blockSize worth of data
956 * assume that there is more data.
958 kRemaining = butm_remainingKSpace(tapeInfoPtr);
959 if( kRemaining < tc_KEndMargin )
961 code = butm_WriteFileEnd(tapeInfoPtr);
964 ErrorLog(0, taskId, code, tapeInfoPtr->error,
965 "Can't write FileEnd on tape\n");
969 code = butm_WriteEOT(tapeInfoPtr);
972 ErrorLog(0, taskId, code, tapeInfoPtr->error,
973 "Can't write end-of-dump on tape\n");
977 /* Mark tape as having been written */
978 tapeEntryPtr->useKBytes = tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
979 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
981 unmountTape(taskId, tapeInfoPtr);
983 /* Get next tape and writes its label */
985 code = GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, 1, &wroteLabel);
986 if (code) ERROR_EXIT(code);
988 code = butm_WriteFileBegin(tapeInfoPtr);
991 ErrorLog(0, taskId, code, tapeInfoPtr->error,
992 "Can't write FileBegin on tape\n");
999 /* no more data to be read - if necessary, flush out the last buffer */
1000 if (writeBufNbytes > 0)
1002 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
1005 ErrorLog(1, taskId, code, tapeInfoPtr->error, "Can't write data on tape\n");
1010 code = butm_WriteFileEnd(tapeInfoPtr);
1013 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't write FileEnd on tape\n");
1017 /* Mark tape as having been written */
1018 tapeEntryPtr->useKBytes = tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1019 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1022 /* Let the KeepAlive process stop on its own */
1023 code = ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client, UF_END_SINGLESERVER, 0);
1025 if ( writeBlock ) free(writeBlock);
1026 if ( charList.charListT_val ) free(charList.charListT_val);
1032 * restore all the items on the tape
1034 * tape positioned after tape label
1038 restoreDbEntries(tapeInfoPtr, rstTapeInfoPtr)
1039 struct butm_tapeInfo *tapeInfoPtr;
1040 struct rstTapeInfo *rstTapeInfoPtr;
1042 struct structDumpHeader netItemHeader, hostItemHeader;
1044 afs_int32 taskId, code = 0;
1047 taskId = rstTapeInfoPtr->taskId;
1049 /* clear state for the buffer routine(s) */
1050 initTapeBuffering();
1052 code = butm_ReadFileBegin(tapeInfoPtr);
1055 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't read FileBegin on tape\n");
1059 /* get the first item-header */
1060 bzero(&netItemHeader, sizeof(netItemHeader));
1061 code = getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1062 if (code) ERROR_EXIT(code);
1063 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
1067 switch (hostItemHeader.type)
1070 code = restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
1071 if (code) ERROR_EXIT(code);
1075 if (++count > 25) { /*every 25 dumps, wait */
1079 code = restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
1080 if (code) ERROR_EXIT(code);
1088 case SD_TEXT_DUMPSCHEDULE:
1089 case SD_TEXT_VOLUMESET:
1090 case SD_TEXT_TAPEHOSTS:
1091 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
1092 if (code) ERROR_EXIT(code);
1100 TLog(taskId, "Unknown database header type %d\n", hostItemHeader.type);
1106 code = butm_ReadFileEnd(tapeInfoPtr);
1109 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't read EOF on tape\n");
1113 /* Mark tape as having been written */
1114 tapeEntryPtr->useKBytes = tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1115 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1122 * restore special items in the header
1125 restoreDbHeader(tapeInfo, rstTapeInfoPtr, nextHeader)
1126 struct butm_tapeInfo *tapeInfo;
1127 struct rstTapeInfo *rstTapeInfoPtr;
1128 struct structDumpHeader *nextHeader;
1130 struct structDumpHeader netItemHeader;
1131 struct DbHeader netDbHeader, hostDbHeader;
1134 extern struct udbHandleS udbHandle;
1136 /* Read the database header */
1137 bzero(&netDbHeader, sizeof(netDbHeader));
1138 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader, sizeof(netDbHeader));
1139 if (code) ERROR_EXIT(code);
1140 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1142 /* Add the database header to the database */
1143 code = ubik_Call(BUDB_RestoreDbHeader, udbHandle.uh_client, 0, &hostDbHeader);
1146 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0, "Can't restore DB Header\n");
1150 /* get the next item-header */
1151 bzero(nextHeader, sizeof(*nextHeader));
1152 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1153 if (code) ERROR_EXIT(code);
1154 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1162 * restore a single dump, including all its tapes and volumes, from
1165 * nextHeader - ptr to structure for return value
1167 * nextHeader - next structure header from tape
1169 * upon entry, the dump structure header has been read confirming that
1170 * a database dump tree exists on the tape
1173 restoreDbDump(tapeInfo, rstTapeInfoPtr, nextHeader)
1174 struct butm_tapeInfo *tapeInfo;
1175 struct rstTapeInfo *rstTapeInfoPtr;
1176 struct structDumpHeader *nextHeader;
1178 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1179 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1180 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1181 struct structDumpHeader netItemHeader;
1182 afs_int32 newTape, taskId;
1183 int restoreThisDump = 1;
1184 afs_int32 code = 0, tcode;
1186 extern struct udbHandleS udbHandle;
1188 taskId = rstTapeInfoPtr->taskId;
1190 /* read dump entry */
1191 bzero(&netDumpEntry, sizeof(netDumpEntry));
1192 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry, sizeof(netDumpEntry));
1193 if (code) ERROR_EXIT(code);
1195 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1196 if (rstTapeInfoPtr->dumpid == 0)
1198 netDumpEntry.initialDumpID = 0;
1199 netDumpEntry.appendedDumpID = 0;
1202 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1204 /* The dump entry for this database tape is incomplete, so don't include it */
1205 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1206 restoreThisDump = 0;
1208 /* add the dump to the database */
1209 if (restoreThisDump) {
1210 code = threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry), DLQ_USEDUMP);
1211 if (code) ERROR_EXIT(code);
1214 /* get the next item-header */
1215 bzero(nextHeader, sizeof(*nextHeader));
1216 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1217 if (code) ERROR_EXIT(code);
1218 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1220 /* Add every tape to the db */
1221 while ( nextHeader->type == SD_TAPE )
1224 /* read the tape entry */
1225 bzero(&netTapeEntry, sizeof(netTapeEntry));
1226 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry, sizeof(netTapeEntry));
1227 if (code) ERROR_EXIT(code);
1228 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1230 /* Add the tape to the database */
1231 if (restoreThisDump) {
1232 code = threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry), DLQ_USETAPE);
1233 if (code) ERROR_EXIT(code);
1236 /* get the next item-header */
1237 bzero(nextHeader, sizeof(*nextHeader));
1238 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1239 if (code) ERROR_EXIT(code);
1240 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1242 /* Add every volume to the db */
1243 while ( nextHeader->type == SD_VOLUME )
1246 /* read the volume entry */
1247 bzero(&netVolumeEntry, sizeof(netVolumeEntry));
1248 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry, sizeof(netVolumeEntry));
1249 if (code) ERROR_EXIT(code);
1250 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1252 if (restoreThisDump) {
1253 code = threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry), DLQ_VOLENTRY);
1254 if (code) ERROR_EXIT(code);
1257 /* get the next item-header */
1258 bzero(nextHeader, sizeof(*nextHeader));
1259 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1260 if (code) ERROR_EXIT(code);
1261 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1264 /* Finish the tape */
1265 if (restoreThisDump) {
1266 code = threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry), DLQ_FINISHTAPE);
1267 if (code) ERROR_EXIT(code);
1271 /* Finish the dump */
1272 if (restoreThisDump) {
1273 code = threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry), DLQ_FINISHDUMP);
1274 if (code) ERROR_EXIT(code);
1282 * Save the specified file as configuration text in the ubik database.
1283 * Have to setup the client text structure so that we can call
1284 * the routine to transmit the text to the db.
1288 saveTextFile(taskId, textType, fileName)
1293 udbClientTextP ctPtr = 0;
1297 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1298 if (!ctPtr) ERROR_EXIT(TC_NOMEMORY);
1300 bzero(ctPtr, sizeof(*ctPtr));
1301 ctPtr->textType = textType;
1303 /* lock the text in the database */
1304 code = bc_LockText(ctPtr);
1307 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1312 ctPtr->textStream = fopen(fileName, "r");
1313 if (!ctPtr->textStream)
1315 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1319 /* now send the text to the database */
1320 code = bcdb_SaveTextFile(ctPtr);
1323 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1330 if (ctPtr->textStream) fclose(ctPtr->textStream);
1331 if (tlock) bc_UnlockText(ctPtr);
1338 * read the text off the tape, and store it in the appropriate
1339 * text type in the database.
1341 * nextHeader - ptr to struct for return information
1343 * nextHeader - struct header for next item on the tape
1346 restoreText(tapeInfo, rstTapeInfoPtr, nextHeader)
1347 struct butm_tapeInfo *tapeInfo;
1348 struct rstTapeInfo *rstTapeInfoPtr;
1349 struct structDumpHeader *nextHeader;
1353 char *readBuffer = 0;
1354 afs_int32 readBlockSize;
1355 afs_int32 transferSize;
1356 struct structDumpHeader netItemHeader;
1360 udbClientTextP ctPtr = 0;
1363 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1364 if (!ctPtr) ERROR_EXIT(TC_NOMEMORY);
1366 /* determine the type of text block */
1367 switch (nextHeader->type)
1369 case SD_TEXT_DUMPSCHEDULE:
1370 textType = TB_DUMPSCHEDULE;
1373 case SD_TEXT_VOLUMESET:
1374 textType = TB_VOLUMESET;
1377 case SD_TEXT_TAPEHOSTS:
1378 textType = TB_TAPEHOSTS;
1382 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0, "Unknown text block\n");
1383 ERROR_EXIT(TC_INTERNALERROR);
1387 /* open the text file */
1388 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1389 fid = open(mktemp(filename), O_RDWR|O_CREAT|O_EXCL, 0600);
1392 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1393 "Can't open temporary text file: %s\n", filename);
1397 /* allocate buffer for text */
1398 readBlockSize = BUTM_BLKSIZE;
1399 readBuffer = (char *) malloc(readBlockSize);
1400 if (!readBuffer) ERROR_EXIT(TC_NOMEMORY);
1402 /* read the text into the temporary file */
1403 nbytes = nextHeader->size;
1404 while ( nbytes > 0 )
1406 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1408 /* read it from the tape */
1409 code = getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1410 if (code) ERROR_EXIT(code);
1412 /* write to the file */
1413 if ( write(fid, readBuffer, transferSize) != transferSize )
1415 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1416 "Can't write temporary text file: %s\n", filename);
1420 nbytes -= transferSize;
1425 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1426 if (code) ERROR_EXIT(code);
1429 /* get the next item-header */
1430 bzero(nextHeader, sizeof(*nextHeader));
1431 code = getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader, sizeof(netItemHeader));
1432 if (code) ERROR_EXIT(code);
1433 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1436 if (ctPtr) free(ctPtr);
1437 if (readBuffer) free(readBuffer);
1447 /* ----------------------------------
1448 * Tape data buffering - for reading database dumps
1449 * ----------------------------------
1452 static char *tapeReadBuffer = 0; /* input buffer */
1453 static char *tapeReadBufferPtr = 0; /* position in buffer */
1454 static afs_int32 nbytes = 0; /* # bytes left in buffer */
1463 * Read information from tape, and place the requested number of bytes
1464 * in the buffer supplied
1467 * rstTapeInfoPtr - Info about the dump being restored.
1468 * buffer - buffer for requested data
1469 * requestedBytes - no. of bytes requested
1471 * fn retn - 0, ok, n, error
1474 getTapeData(tapeInfoPtr, rstTapeInfoPtr, buffer, requestedBytes)
1475 struct butm_tapeInfo *tapeInfoPtr;
1476 struct rstTapeInfo *rstTapeInfoPtr;
1478 afs_int32 requestedBytes;
1480 afs_int32 taskId, transferBytes, new;
1484 taskId = rstTapeInfoPtr->taskId;
1486 if ( checkAbortByTaskId(taskId) ) ERROR_EXIT(TC_ABORTEDBYREQUEST);
1488 if (!tapeReadBuffer)
1490 tapeReadBuffer = (char *) malloc(BUTM_BLOCKSIZE);
1491 if (!tapeReadBuffer) ERROR_EXIT(TC_NOMEMORY);
1494 while ( requestedBytes > 0 )
1498 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1501 code = butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr, BUTM_BLKSIZE, &nbytes);
1504 /* detect if we hit the end-of-tape and get next tape */
1505 if (code == BUTM_ENDVOLUME)
1507 /* Update fields in tape entry for this tape */
1508 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1509 tapeEntryPtr->useKBytes = tapeInfoPtr->kBytes +
1510 (tapeInfoPtr->nBytes ? 1 : 0);
1512 unmountTape(taskId, tapeInfoPtr);
1514 rstTapeInfoPtr->tapeSeq++;
1515 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1516 if (code) ERROR_EXIT(code);
1518 code = butm_ReadFileBegin(tapeInfoPtr);
1521 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1522 "Can't read FileBegin on tape\n");
1529 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't read FileData on tape\n");
1535 transferBytes = (nbytes < requestedBytes ) ? nbytes : requestedBytes;
1536 bcopy(tapeReadBufferPtr, buffer, transferBytes);
1537 tapeReadBufferPtr += transferBytes;
1538 buffer += transferBytes;
1539 nbytes -= transferBytes;
1540 requestedBytes -= transferBytes;