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>
32 #include <afs/procmgmt.h>
33 #include <afs/assert.h>
34 #include <afs/prs_fs.h>
39 #include <afs/cellconfig.h>
43 #include <afs/tcdata.h>
45 #include <afs/budb_client.h>
46 #include <afs/bubasics.h>
47 #include "error_macros.h"
49 /* GLOBAL CONFIGURATION PARAMETERS */
50 #define BIGCHUNK 102400
52 extern int dump_namecheck;
55 static void initTapeBuffering();
57 static restoreDbEntries();
59 void * KeepAlive(void *);
61 * create a dump entry for a saved database
65 CreateDBDump(dumpEntryPtr)
66 struct budb_dumpEntry *dumpEntryPtr;
70 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
72 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
73 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
74 strcat(dumpEntryPtr->tapes.format, ".%d");
75 strcpy(dumpEntryPtr->volumeSetName, "");
76 strcpy(dumpEntryPtr->dumpPath, "");
77 dumpEntryPtr->created = 0; /* let database assign it */
78 dumpEntryPtr->incTime = 0;
79 dumpEntryPtr->nVolumes = 0;
80 dumpEntryPtr->initialDumpID = 0;
81 dumpEntryPtr->parent = 0;
82 dumpEntryPtr->level = 0;
83 dumpEntryPtr->tapes.maxTapes = 0;
84 dumpEntryPtr->tapes.b = 1;
86 /* now call the database to create the entry */
87 code = bcdb_CreateDump(dumpEntryPtr);
91 struct tapeEntryList {
92 struct tapeEntryList *next;
94 struct budb_tapeEntry tapeEnt;
96 struct tapeEntryList *listEntryHead;
97 struct tapeEntryList *listEntryPtr;
98 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
99 struct budb_dumpEntry lastDump; /* the last dump of this volset */
102 * Load a DB tape, read and over write its label.
103 * Leave the tape mounted.
106 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag,
110 struct butm_tapeInfo *tapeInfoPtr;
118 char tapeName[BU_MAXTAPELEN];
125 struct butm_tapeLabel oldTapeLabel, newLabel;
126 struct tapeEntryList *endList;
127 extern struct tapeConfig globalTapeConfig;
129 /* construct the name of the tape */
130 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
132 interactiveFlag = queryFlag;
135 while (!*wroteLabel) { /*w */
136 if (interactiveFlag) { /* need a tape to write */
138 PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
146 code = butm_Mount(tapeInfoPtr, tapeName);
148 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
152 memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
153 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
155 oldTapeLabel.useCount = 0; /* no label exists */
156 oldTapeLabel.structVersion = 0;
157 strcpy(oldTapeLabel.pName, "");
159 /* If tape has a name, it must be null or database tape name */
160 if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
161 && !databaseTape(oldTapeLabel.AFSName)) {
162 char gotName[BU_MAXTAPELEN + 32];
164 LABELNAME(gotName, &oldTapeLabel);
166 "This tape %s must be a database tape or NULL tape\n",
170 unmountTape(taskId, tapeInfoPtr);
174 /* Do not overwrite a tape that belongs to this dump */
175 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
176 ErrorLog(0, taskId, 0, 0,
177 "Can't overwrite tape containing the dump in progress\n");
181 /* On first tape, the savedb has not started yet, so the database is not locked
182 * and we can therefore, access information from it. This is easier to do because
183 * database dumps don't have appended dumps (nor appended).
187 struct budb_dumpEntry de, de2;
189 /* Verify the tape has not expired
190 * Early database dumps don't have a dumpid
192 if (!tapeExpired(&oldTapeLabel)) {
193 TLog(taskId, "This tape has not expired\n");
197 /* Since the dumpset on this tape will be deleted from database, check if
198 * any of the dumps in this dumpset are most-recent-dumps.
200 for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
201 if (dmp == lastDump.id) {
202 memcpy(&de, &lastDump, sizeof(de));
203 memcpy(&de2, &lastDump, sizeof(de2));
205 code = bcdb_FindDumpByID(dmp, &de);
208 sprintf(strlevel, "%d", de.level);
210 bcdb_FindLatestDump(de.volumeSetName, strlevel,
216 if (de.id == de2.id) {
217 if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
218 ErrorLog(0, taskId, 0, 0,
219 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
222 ErrorLog(0, taskId, 0, 0,
223 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
224 de.volumeSetName, de.name, de.id);
230 /* Otherwise, the savedb is in progress and we can't
231 * access the database (it's locked). So we rely on the
232 * information available (and not the backup database).
235 /* Check the tape's expiration date. Use the expiration on the label */
236 gettimeofday(&tp, &tzp);
238 if (curTime < oldTapeLabel.expirationDate) {
239 TLog(taskId, "This tape has not expired\n");
243 /* Check if this previous-dump of the dump-in-progress is on this tape */
244 if (oldTapeLabel.dumpid
245 && (oldTapeLabel.dumpid == lastDump.id)) {
246 ErrorLog(0, taskId, 0, 0,
247 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
248 lastDump.name, lastDump.id);
254 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
255 newLabel.expirationDate = expires;
256 newLabel.useCount = oldTapeLabel.useCount + 1;
257 newLabel.dumpid = dumpid;
258 newLabel.size = tapeInfoPtr->tapeSize;
260 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
262 TapeLog(0, taskId, code, tapeInfoPtr->error,
263 "Can't label tape\n");
269 /* Initialize a tapeEntry for later inclusion into the database */
271 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
273 ERROR_EXIT(TC_NOMEMORY);
274 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
276 /* Remember dumpid so we can delete it later */
277 if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
278 && oldTapeLabel.dumpid)
279 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
281 /* Fill in tape entry so we can save it later */
282 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
283 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
284 tapeEntryPtr->written = newLabel.creationTime;
285 tapeEntryPtr->expires = expires;
286 tapeEntryPtr->seq = sequence;
287 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
288 tapeEntryPtr->dump = dumpid;
289 tapeEntryPtr->useKBytes = 0;
290 tapeEntryPtr->labelpos = 0;
292 /* Thread onto end of single-linked list */
294 endList = listEntryHead;
295 while (endList->next)
296 endList = endList->next;
297 endList->next = listEntryPtr;
299 listEntryHead = listEntryPtr;
307 * With the list of tapes, free the structures.
313 struct tapeEntryList *next;
315 listEntryPtr = listEntryHead;
316 while (listEntryPtr) {
317 next = listEntryPtr->next;
322 listEntryHead = NULL;
327 * With the list of tapes, add them to the database.
328 * Also delete any olddumpids that are around.
337 struct tapeEntryList *next;
339 listEntryPtr = listEntryHead;
340 while (listEntryPtr) {
341 next = listEntryPtr->next;
343 /* Remove the old database entry */
344 if (listEntryPtr->oldDumpId) {
345 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
346 if (i && (i != BUDB_NOENT)) {
347 ErrorLog(0, taskId, i, 0,
348 "Unable to delete old DB entry %u.\n",
349 listEntryPtr->oldDumpId);
353 /* Add the tape to the database */
354 code = bcdb_UseTape(tapeEntryPtr, &new);
356 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n",
361 code = bcdb_FinishTape(tapeEntryPtr);
363 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n",
377 * this code assumes that the blocksize on reads is smaller than
378 * the blocksize on writes
382 writeDbDump(tapeInfoPtr, taskId, expires, dumpid)
383 struct butm_tapeInfo *tapeInfoPtr;
389 afs_int32 writeBufNbytes = 0;
390 char *writeBlock = 0;
391 char *writeBuffer = 0;
393 afs_int32 transferSize;
395 char *readBufPtr = NULL;
396 afs_int32 maxReadSize;
401 afs_int32 chunksize = 0;
402 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
406 #ifdef AFS_PTHREAD_ENV
408 pthread_attr_t tattr;
414 extern struct tapeConfig globalTapeConfig;
415 extern struct udbHandleS udbHandle;
417 blockSize = BUTM_BLKSIZE;
418 writeBlock = (char *)malloc(BUTM_BLOCKSIZE);
420 ERROR_EXIT(TC_NOMEMORY);
422 writeBuffer = writeBlock + sizeof(struct blockMark);
423 memset(writeBuffer, 0, BUTM_BLKSIZE);
427 * The margin of space to check for end of tape is set to the
428 * amount of space used to write an end-of-tape multiplied by 2.
429 * The amount of space is size of a 16K EODump marker, its EOF
430 * marker, and up to two EOF markers done on close (1 16K blocks +
433 tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
434 tc_KEndMargin = tc_EndMargin / 1024;
436 /* have to write enclose the dump in file marks */
437 code = butm_WriteFileBegin(tapeInfoPtr);
439 ErrorLog(0, taskId, code, tapeInfoPtr->error,
440 "Can't write FileBegin on tape\n");
444 writeBufPtr = &writeBuffer[0];
447 charList.charListT_val = 0;
448 charList.charListT_len = 0;
451 /* When no data in buffer, read data from the budb_server */
452 if (charList.charListT_len == 0) {
453 /* get more data. let rx allocate space */
454 if (charList.charListT_val) {
455 free(charList.charListT_val);
456 charList.charListT_val = 0;
461 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
462 UF_SINGLESERVER, firstcall,
463 maxReadSize, &charList, &done);
465 ErrorLog(0, taskId, code, 0, "Can't read database\n");
469 /* If this if the first call to the budb server, create a thread
470 * that will keep the connection alive (during tape changes).
473 #ifdef AFS_PTHREAD_ENV
474 code = pthread_attr_init(&tattr);
476 ErrorLog(0, taskId, code, 0,
477 "Can't pthread_attr_init Keep-alive process\n");
482 pthread_attr_setdetachstate(&tattr,
483 PTHREAD_CREATE_DETACHED);
485 ErrorLog(0, taskId, code, 0,
486 "Can't pthread_attr_setdetachstate Keep-alive process\n");
491 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
492 AFS_SIGSET_RESTORE();
495 LWP_CreateProcess(KeepAlive, 16384, 1, (void *)NULL,
496 "Keep-alive process", &alivePid);
498 /* XXX should we check code here ??? XXX */
502 readBufPtr = charList.charListT_val;
505 if ((charList.charListT_len == 0) && done)
508 /* compute how many bytes and transfer to the write Buffer */
510 (charList.charListT_len <
512 writeBufNbytes)) ? charList.charListT_len : (blockSize -
515 memcpy(writeBufPtr, readBufPtr, transferSize);
516 charList.charListT_len -= transferSize;
517 writeBufPtr += transferSize;
518 readBufPtr += transferSize;
519 writeBufNbytes += transferSize;
521 /* If filled the write buffer, then write it to tape */
522 if (writeBufNbytes == blockSize) {
523 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
525 ErrorLog(0, taskId, code, tapeInfoPtr->error,
526 "Can't write data on tape\n");
530 memset(writeBuffer, 0, blockSize);
531 writeBufPtr = &writeBuffer[0];
534 /* Every BIGCHUNK bytes check if aborted */
535 chunksize += blockSize;
536 if (chunksize > BIGCHUNK) {
538 if (checkAbortByTaskId(taskId))
539 ERROR_EXIT(TC_ABORTEDBYREQUEST);
543 * check if tape is full - since we filled a blockSize worth of data
544 * assume that there is more data.
546 kRemaining = butm_remainingKSpace(tapeInfoPtr);
547 if (kRemaining < tc_KEndMargin) {
548 code = butm_WriteFileEnd(tapeInfoPtr);
550 ErrorLog(0, taskId, code, tapeInfoPtr->error,
551 "Can't write FileEnd on tape\n");
555 code = butm_WriteEOT(tapeInfoPtr);
557 ErrorLog(0, taskId, code, tapeInfoPtr->error,
558 "Can't write end-of-dump on tape\n");
562 /* Mark tape as having been written */
563 tapeEntryPtr->useKBytes =
564 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
565 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
567 unmountTape(taskId, tapeInfoPtr);
569 /* Get next tape and writes its label */
572 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
577 code = butm_WriteFileBegin(tapeInfoPtr);
579 ErrorLog(0, taskId, code, tapeInfoPtr->error,
580 "Can't write FileBegin on tape\n");
587 /* no more data to be read - if necessary, flush out the last buffer */
588 if (writeBufNbytes > 0) {
589 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
591 ErrorLog(1, taskId, code, tapeInfoPtr->error,
592 "Can't write data on tape\n");
597 code = butm_WriteFileEnd(tapeInfoPtr);
599 ErrorLog(0, taskId, code, tapeInfoPtr->error,
600 "Can't write FileEnd on tape\n");
604 /* Mark tape as having been written */
605 tapeEntryPtr->useKBytes =
606 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
607 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
610 /* Let the KeepAlive process stop on its own */
612 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
613 UF_END_SINGLESERVER, 0);
617 if (charList.charListT_val)
618 free(charList.charListT_val);
623 * dump backup database to tape
627 saveDbToTape(void *param)
629 struct saveDbIf *saveDbIfPtr = (struct saveDbIf *)param;
636 struct butm_tapeInfo tapeInfo;
637 struct budb_dumpEntry dumpEntry;
639 extern struct deviceSyncNode *deviceLatch;
640 extern struct tapeConfig globalTapeConfig;
642 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
643 taskId = saveDbIfPtr->taskId;
645 setStatus(taskId, DRIVE_WAIT);
646 EnterDeviceQueue(deviceLatch); /* lock tape device */
647 clearStatus(taskId, DRIVE_WAIT);
650 TLog(taskId, "SaveDb\n");
652 tapeInfo.structVersion = BUTM_MAJORVERSION;
653 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
655 ErrorLog(0, taskId, code, tapeInfo.error,
656 "Can't initialize tape module\n");
660 /* Determine what the last database dump was */
661 memset(&lastDump, 0, sizeof(lastDump));
662 code = bcdb_FindLatestDump("", "", &lastDump);
664 if (code != BUDB_NODUMPNAME) {
665 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
668 memset(&lastDump, 0, sizeof(lastDump));
671 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
673 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
678 listEntryHead = NULL;
680 /* Get the tape and write a new label to it */
682 GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
686 * If did not write the label, remove created dump
687 * Else if wrote the label, remove old dump from db so it's not saved.
690 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
692 if (i && (i != BUDB_NOENT))
693 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
695 } else if (listEntryHead->oldDumpId) {
696 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
697 listEntryHead->oldDumpId = 0;
698 if (i && (i != BUDB_NOENT)) {
699 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
700 listEntryHead->oldDumpId);
707 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
709 /* we have a writable tape */
710 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
714 /* Now delete the entries between time 0 and archive-time */
715 if (saveDbIfPtr->archiveTime)
716 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
719 unmountTape(taskId, &tapeInfo);
721 /* Add this dump's tapes to the database and mark it finished */
723 i = addTapesToDb(taskId);
727 i = bcdb_FinishDump(&dumpEntry);
733 if (code == TC_ABORTEDBYREQUEST) {
734 TLog(taskId, "SaveDb: Aborted by request\n");
735 clearStatus(taskId, ABORT_REQUEST);
736 setStatus(taskId, ABORT_DONE);
738 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
739 setStatus(taskId, TASK_ERROR);
741 TLog(taskId, "SaveDb: Finished\n");
743 setStatus(taskId, TASK_DONE);
746 LeaveDeviceQueue(deviceLatch);
747 return (void *)(code);
757 * Make a database dump entry given a tape label.
761 makeDbDumpEntry(tapeEntPtr, dumpEntryPtr)
762 struct budb_tapeEntry *tapeEntPtr;
763 struct budb_dumpEntry *dumpEntryPtr;
765 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
767 dumpEntryPtr->id = tapeEntPtr->dump;
768 dumpEntryPtr->initialDumpID = 0;
769 dumpEntryPtr->parent = 0;
770 dumpEntryPtr->level = 0;
771 dumpEntryPtr->flags = 0;
773 strcpy(dumpEntryPtr->volumeSetName, "");
774 strcpy(dumpEntryPtr->dumpPath, "");
775 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
777 dumpEntryPtr->created = tapeEntPtr->dump;
778 dumpEntryPtr->incTime = 0;
779 dumpEntryPtr->nVolumes = 0;
781 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
782 strcat(dumpEntryPtr->tapes.format, ".%d");
783 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
784 dumpEntryPtr->tapes.maxTapes = 0;
789 * prompt for a specific database tape
793 readDbTape(tapeInfoPtr, rstTapeInfoPtr, query)
794 struct butm_tapeInfo *tapeInfoPtr;
795 struct rstTapeInfo *rstTapeInfoPtr;
801 struct butm_tapeLabel oldTapeLabel;
802 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
803 struct tapeEntryList *endList;
805 struct budb_dumpEntry de;
806 struct budb_tapeEntry te;
808 taskId = rstTapeInfoPtr->taskId;
809 interactiveFlag = query;
811 /* construct the name of the tape */
812 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
813 strcpy(tapeName, AFStapeName);
815 /* Will prompt for the latest saved database tape, but will accept any one */
816 if (rstTapeInfoPtr->tapeSeq == 1) {
817 code = bcdb_FindLatestDump("", "", &de);
819 rstTapeInfoPtr->dumpid = de.id;
821 if (rstTapeInfoPtr->dumpid) {
823 bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
826 strcpy(tapeName, te.name);
831 if (interactiveFlag) { /* need a tape to read */
833 PromptForTape(RESTOREDBOPCODE, tapeName,
834 rstTapeInfoPtr->dumpid, taskId, tapecount);
841 code = butm_Mount(tapeInfoPtr, tapeName);
843 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
847 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
849 TapeLog(0, taskId, code, tapeInfoPtr->error,
850 "Can't read tape label\n");
854 /* Check for name of tape and matching dump id (if applicable). */
855 if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
856 || ((rstTapeInfoPtr->tapeSeq != 1)
857 && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
858 char expTape[BU_MAXTAPELEN + 32];
859 char gotTape[BU_MAXTAPELEN + 32];
861 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
862 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
864 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
869 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
870 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
875 unmountTape(taskId, tapeInfoPtr);
879 /* Initialize a tapeEntry for later inclusion into the database */
881 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
883 ERROR_EXIT(TC_NOMEMORY);
884 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
886 /* Fill in tape entry so we can save it later */
887 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
888 tapeEntryPtr->dump = oldTapeLabel.dumpid;
889 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
890 tapeEntryPtr->written = oldTapeLabel.creationTime;
891 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
892 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
893 tapeEntryPtr->useCount = oldTapeLabel.useCount;
894 tapeEntryPtr->useKBytes = 0;
895 tapeEntryPtr->labelpos = 0;
897 /* Thread onto end of single-linked list */
899 endList = listEntryHead;
900 while (endList->next)
901 endList = endList->next;
902 endList->next = listEntryPtr;
904 listEntryHead = listEntryPtr;
910 static afs_int32 nbytes = 0; /* # bytes left in buffer */
919 * restore all the items on the tape
921 * tape positioned after tape label
925 restoreDbEntries(tapeInfoPtr, rstTapeInfoPtr)
926 struct butm_tapeInfo *tapeInfoPtr;
927 struct rstTapeInfo *rstTapeInfoPtr;
929 struct structDumpHeader netItemHeader, hostItemHeader;
931 afs_int32 taskId, code = 0;
934 taskId = rstTapeInfoPtr->taskId;
936 /* clear state for the buffer routine(s) */
939 code = butm_ReadFileBegin(tapeInfoPtr);
941 ErrorLog(0, taskId, code, tapeInfoPtr->error,
942 "Can't read FileBegin on tape\n");
946 /* get the first item-header */
947 memset(&netItemHeader, 0, sizeof(netItemHeader));
949 getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
950 sizeof(netItemHeader));
953 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
956 switch (hostItemHeader.type) {
959 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
965 if (++count > 25) { /*every 25 dumps, wait */
970 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
980 case SD_TEXT_DUMPSCHEDULE:
981 case SD_TEXT_VOLUMESET:
982 case SD_TEXT_TAPEHOSTS:
983 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
993 TLog(taskId, "Unknown database header type %d\n",
994 hostItemHeader.type);
1000 code = butm_ReadFileEnd(tapeInfoPtr);
1002 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1003 "Can't read EOF on tape\n");
1007 /* Mark tape as having been written */
1008 tapeEntryPtr->useKBytes =
1009 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1010 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1016 /* restoreDbFromTape
1017 * restore the backup database from tape.
1021 restoreDbFromTape(void *param)
1023 afs_uint32 taskId = (afs_uint32) param;
1026 struct butm_tapeInfo tapeInfo;
1027 struct rstTapeInfo rstTapeInfo;
1028 struct budb_dumpEntry dumpEntry;
1030 extern struct tapeConfig globalTapeConfig;
1031 extern struct deviceSyncNode *deviceLatch;
1033 setStatus(taskId, DRIVE_WAIT);
1034 EnterDeviceQueue(deviceLatch); /* lock tape device */
1035 clearStatus(taskId, DRIVE_WAIT);
1038 TLog(taskId, "RestoreDb\n");
1040 tapeInfo.structVersion = BUTM_MAJORVERSION;
1041 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1043 ErrorLog(0, taskId, code, tapeInfo.error,
1044 "Can't initialize tape module\n");
1048 listEntryHead = NULL;
1050 rstTapeInfo.taskId = taskId;
1051 rstTapeInfo.tapeSeq = 1;
1052 rstTapeInfo.dumpid = 0;
1054 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1058 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1063 /* Now put this dump into the database */
1064 /* Make a dump entry from first tape */
1065 listEntryPtr = listEntryHead;
1067 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1068 if (dumpEntry.id != 0) {
1069 i = bcdb_CreateDump(&dumpEntry);
1071 if (i == BUDB_DUMPIDEXISTS)
1073 "Dump id %d not added to database - already exists\n",
1076 TapeLog(0, taskId, i, 0,
1077 "Dump id %d not added to database\n",
1080 i = addTapesToDb(taskId);
1084 i = bcdb_FinishDump(&dumpEntry);
1092 unmountTape(taskId, &tapeInfo);
1095 if (code == TC_ABORTEDBYREQUEST) {
1096 TLog(taskId, "RestoreDb: Aborted by request\n");
1097 clearStatus(taskId, ABORT_REQUEST);
1098 setStatus(taskId, ABORT_DONE);
1100 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1101 setStatus(taskId, TASK_ERROR);
1103 TLog(taskId, "RestoreDb: Finished\n");
1106 LeaveDeviceQueue(deviceLatch);
1107 setStatus(taskId, TASK_DONE);
1109 return (void *)(code);
1114 * While dumping the database, keeps the connection alive.
1115 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
1116 * This resets the database's internal timer so that it does not
1117 * prematuraly quit (on asking for new tapes and such).
1119 * Use the same udbHandle as writeDbDump so we go to the same server.
1122 KeepAlive(void *unused)
1128 extern struct udbHandleS udbHandle;
1131 #ifdef AFS_PTHREAD_ENV
1136 charList.charListT_val = 0;
1137 charList.charListT_len = 0;
1139 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1140 UF_SINGLESERVER, 0, 0, &charList, &done);
1149 * restore special items in the header
1152 restoreDbHeader(tapeInfo, rstTapeInfoPtr, nextHeader)
1153 struct butm_tapeInfo *tapeInfo;
1154 struct rstTapeInfo *rstTapeInfoPtr;
1155 struct structDumpHeader *nextHeader;
1157 struct structDumpHeader netItemHeader;
1158 struct DbHeader netDbHeader, hostDbHeader;
1161 extern struct udbHandleS udbHandle;
1163 /* Read the database header */
1164 memset(&netDbHeader, 0, sizeof(netDbHeader));
1166 getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1167 sizeof(netDbHeader));
1170 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1172 /* Add the database header to the database */
1174 ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1177 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1178 "Can't restore DB Header\n");
1182 /* get the next item-header */
1183 memset(nextHeader, 0, sizeof(*nextHeader));
1185 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1186 sizeof(netItemHeader));
1189 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1197 * restore a single dump, including all its tapes and volumes, from
1200 * nextHeader - ptr to structure for return value
1202 * nextHeader - next structure header from tape
1204 * upon entry, the dump structure header has been read confirming that
1205 * a database dump tree exists on the tape
1208 restoreDbDump(tapeInfo, rstTapeInfoPtr, nextHeader)
1209 struct butm_tapeInfo *tapeInfo;
1210 struct rstTapeInfo *rstTapeInfoPtr;
1211 struct structDumpHeader *nextHeader;
1213 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1214 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1215 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1216 struct structDumpHeader netItemHeader;
1218 int restoreThisDump = 1;
1221 extern struct udbHandleS udbHandle;
1223 taskId = rstTapeInfoPtr->taskId;
1225 /* read dump entry */
1226 memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1228 getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry,
1229 sizeof(netDumpEntry));
1233 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1234 if (rstTapeInfoPtr->dumpid == 0) {
1235 netDumpEntry.initialDumpID = 0;
1236 netDumpEntry.appendedDumpID = 0;
1239 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1241 /* The dump entry for this database tape is incomplete, so don't include it */
1242 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1243 restoreThisDump = 0;
1245 /* add the dump to the database */
1246 if (restoreThisDump) {
1248 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1254 /* get the next item-header */
1255 memset(nextHeader, 0, sizeof(*nextHeader));
1257 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1258 sizeof(netItemHeader));
1261 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1263 /* Add every tape to the db */
1264 while (nextHeader->type == SD_TAPE) { /*t */
1266 /* read the tape entry */
1267 memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1269 getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry,
1270 sizeof(netTapeEntry));
1273 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1275 /* Add the tape to the database */
1276 if (restoreThisDump) {
1278 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1284 /* get the next item-header */
1285 memset(nextHeader, 0, sizeof(*nextHeader));
1287 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1288 sizeof(netItemHeader));
1291 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1293 /* Add every volume to the db */
1294 while (nextHeader->type == SD_VOLUME) { /*v */
1296 /* read the volume entry */
1297 memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1299 getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry,
1300 sizeof(netVolumeEntry));
1303 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1305 if (restoreThisDump) {
1307 threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry),
1313 /* get the next item-header */
1314 memset(nextHeader, 0, sizeof(*nextHeader));
1316 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1317 sizeof(netItemHeader));
1320 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1323 /* Finish the tape */
1324 if (restoreThisDump) {
1326 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1333 /* Finish the dump */
1334 if (restoreThisDump) {
1336 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1347 * Save the specified file as configuration text in the ubik database.
1348 * Have to setup the client text structure so that we can call
1349 * the routine to transmit the text to the db.
1353 saveTextFile(taskId, textType, fileName)
1358 udbClientTextP ctPtr = 0;
1362 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1364 ERROR_EXIT(TC_NOMEMORY);
1366 memset(ctPtr, 0, sizeof(*ctPtr));
1367 ctPtr->textType = textType;
1369 /* lock the text in the database */
1370 code = bc_LockText(ctPtr);
1372 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1377 ctPtr->textStream = fopen(fileName, "r");
1378 if (!ctPtr->textStream) {
1379 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1383 /* now send the text to the database */
1384 code = bcdb_SaveTextFile(ctPtr);
1386 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1392 if (ctPtr->textStream)
1393 fclose(ctPtr->textStream);
1395 bc_UnlockText(ctPtr);
1402 * read the text off the tape, and store it in the appropriate
1403 * text type in the database.
1405 * nextHeader - ptr to struct for return information
1407 * nextHeader - struct header for next item on the tape
1410 restoreText(tapeInfo, rstTapeInfoPtr, nextHeader)
1411 struct butm_tapeInfo *tapeInfo;
1412 struct rstTapeInfo *rstTapeInfoPtr;
1413 struct structDumpHeader *nextHeader;
1417 char *readBuffer = 0;
1418 afs_int32 readBlockSize;
1419 afs_int32 transferSize;
1420 struct structDumpHeader netItemHeader;
1424 udbClientTextP ctPtr = 0;
1427 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1429 ERROR_EXIT(TC_NOMEMORY);
1431 /* determine the type of text block */
1432 switch (nextHeader->type) {
1433 case SD_TEXT_DUMPSCHEDULE:
1434 textType = TB_DUMPSCHEDULE;
1437 case SD_TEXT_VOLUMESET:
1438 textType = TB_VOLUMESET;
1441 case SD_TEXT_TAPEHOSTS:
1442 textType = TB_TAPEHOSTS;
1446 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0,
1447 "Unknown text block\n");
1448 ERROR_EXIT(TC_INTERNALERROR);
1452 /* open the text file */
1453 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1454 #if defined (HAVE_MKSTEMP)
1455 fid = mkstemp(filename);
1457 fid = open(mktemp(filename), O_RDWR | O_CREAT | O_EXCL, 0600);
1460 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1461 "Can't open temporary text file: %s\n", filename);
1465 /* allocate buffer for text */
1466 readBlockSize = BUTM_BLKSIZE;
1467 readBuffer = (char *)malloc(readBlockSize);
1469 ERROR_EXIT(TC_NOMEMORY);
1471 /* read the text into the temporary file */
1472 nbytes = nextHeader->size;
1473 while (nbytes > 0) {
1474 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1476 /* read it from the tape */
1478 getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1482 /* write to the file */
1483 if (write(fid, readBuffer, transferSize) != transferSize) {
1484 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1485 "Can't write temporary text file: %s\n", filename);
1489 nbytes -= transferSize;
1494 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1499 /* get the next item-header */
1500 memset(nextHeader, 0, sizeof(*nextHeader));
1502 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1503 sizeof(netItemHeader));
1506 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1521 /* ----------------------------------
1522 * Tape data buffering - for reading database dumps
1523 * ----------------------------------
1526 static char *tapeReadBuffer = 0; /* input buffer */
1527 static char *tapeReadBufferPtr = 0; /* position in buffer */
1530 * Read information from tape, and place the requested number of bytes
1531 * in the buffer supplied
1534 * rstTapeInfoPtr - Info about the dump being restored.
1535 * buffer - buffer for requested data
1536 * requestedBytes - no. of bytes requested
1538 * fn retn - 0, ok, n, error
1541 getTapeData(tapeInfoPtr, rstTapeInfoPtr, buffer, requestedBytes)
1542 struct butm_tapeInfo *tapeInfoPtr;
1543 struct rstTapeInfo *rstTapeInfoPtr;
1545 afs_int32 requestedBytes;
1547 afs_int32 taskId, transferBytes, new;
1551 taskId = rstTapeInfoPtr->taskId;
1553 if (checkAbortByTaskId(taskId))
1554 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1556 if (!tapeReadBuffer) {
1557 tapeReadBuffer = (char *)malloc(BUTM_BLOCKSIZE);
1558 if (!tapeReadBuffer)
1559 ERROR_EXIT(TC_NOMEMORY);
1562 while (requestedBytes > 0) {
1564 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1568 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1569 BUTM_BLKSIZE, &nbytes);
1571 /* detect if we hit the end-of-tape and get next tape */
1572 if (code == BUTM_ENDVOLUME) {
1573 /* Update fields in tape entry for this tape */
1574 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1575 tapeEntryPtr->useKBytes =
1576 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1578 unmountTape(taskId, tapeInfoPtr);
1580 rstTapeInfoPtr->tapeSeq++;
1581 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1585 code = butm_ReadFileBegin(tapeInfoPtr);
1587 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1588 "Can't read FileBegin on tape\n");
1595 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1596 "Can't read FileData on tape\n");
1602 transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1603 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1604 tapeReadBufferPtr += transferBytes;
1605 buffer += transferBytes;
1606 nbytes -= transferBytes;
1607 requestedBytes -= transferBytes;