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>
14 #include <sys/types.h>
21 #include <netinet/in.h>
27 #include <afs/afsint.h>
30 #include <afs/procmgmt.h>
31 #include <afs/assert.h>
32 #include <afs/prs_fs.h>
37 #include <afs/cellconfig.h>
41 #include <afs/tcdata.h>
43 #include <afs/budb_client.h>
44 #include <afs/bubasics.h>
45 #include "error_macros.h"
47 /* GLOBAL CONFIGURATION PARAMETERS */
48 #define BIGCHUNK 102400
50 extern int dump_namecheck;
53 static void initTapeBuffering();
55 static restoreDbEntries();
57 void * KeepAlive(void *);
59 * create a dump entry for a saved database
63 CreateDBDump(dumpEntryPtr)
64 struct budb_dumpEntry *dumpEntryPtr;
68 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
70 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
71 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
72 strcat(dumpEntryPtr->tapes.format, ".%d");
73 strcpy(dumpEntryPtr->volumeSetName, "");
74 strcpy(dumpEntryPtr->dumpPath, "");
75 dumpEntryPtr->created = 0; /* let database assign it */
76 dumpEntryPtr->incTime = 0;
77 dumpEntryPtr->nVolumes = 0;
78 dumpEntryPtr->initialDumpID = 0;
79 dumpEntryPtr->parent = 0;
80 dumpEntryPtr->level = 0;
81 dumpEntryPtr->tapes.maxTapes = 0;
82 dumpEntryPtr->tapes.b = 1;
84 /* now call the database to create the entry */
85 code = bcdb_CreateDump(dumpEntryPtr);
89 struct tapeEntryList {
90 struct tapeEntryList *next;
92 struct budb_tapeEntry tapeEnt;
94 struct tapeEntryList *listEntryHead;
95 struct tapeEntryList *listEntryPtr;
96 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
97 struct budb_dumpEntry lastDump; /* the last dump of this volset */
100 * Load a DB tape, read and over write its label.
101 * Leave the tape mounted.
104 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag,
108 struct butm_tapeInfo *tapeInfoPtr;
116 char tapeName[BU_MAXTAPELEN];
123 struct butm_tapeLabel oldTapeLabel, newLabel;
124 struct tapeEntryList *endList;
125 extern struct tapeConfig globalTapeConfig;
127 /* construct the name of the tape */
128 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
130 interactiveFlag = queryFlag;
133 while (!*wroteLabel) { /*w */
134 if (interactiveFlag) { /* need a tape to write */
136 PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
144 code = butm_Mount(tapeInfoPtr, tapeName);
146 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
150 memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
151 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
153 oldTapeLabel.useCount = 0; /* no label exists */
154 oldTapeLabel.structVersion = 0;
155 strcpy(oldTapeLabel.pName, "");
157 /* If tape has a name, it must be null or database tape name */
158 if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
159 && !databaseTape(oldTapeLabel.AFSName)) {
160 char gotName[BU_MAXTAPELEN + 32];
162 LABELNAME(gotName, &oldTapeLabel);
164 "This tape %s must be a database tape or NULL tape\n",
168 unmountTape(taskId, tapeInfoPtr);
172 /* Do not overwrite a tape that belongs to this dump */
173 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
174 ErrorLog(0, taskId, 0, 0,
175 "Can't overwrite tape containing the dump in progress\n");
179 /* On first tape, the savedb has not started yet, so the database is not locked
180 * and we can therefore, access information from it. This is easier to do because
181 * database dumps don't have appended dumps (nor appended).
185 struct budb_dumpEntry de, de2;
187 /* Verify the tape has not expired
188 * Early database dumps don't have a dumpid
190 if (!tapeExpired(&oldTapeLabel)) {
191 TLog(taskId, "This tape has not expired\n");
195 /* Since the dumpset on this tape will be deleted from database, check if
196 * any of the dumps in this dumpset are most-recent-dumps.
198 for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
199 if (dmp == lastDump.id) {
200 memcpy(&de, &lastDump, sizeof(de));
201 memcpy(&de2, &lastDump, sizeof(de2));
203 code = bcdb_FindDumpByID(dmp, &de);
206 sprintf(strlevel, "%d", de.level);
208 bcdb_FindLatestDump(de.volumeSetName, strlevel,
214 if (de.id == de2.id) {
215 if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
216 ErrorLog(0, taskId, 0, 0,
217 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
220 ErrorLog(0, taskId, 0, 0,
221 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
222 de.volumeSetName, de.name, de.id);
228 /* Otherwise, the savedb is in progress and we can't
229 * access the database (it's locked). So we rely on the
230 * information available (and not the backup database).
233 /* Check the tape's expiration date. Use the expiration on the label */
234 gettimeofday(&tp, &tzp);
236 if (curTime < oldTapeLabel.expirationDate) {
237 TLog(taskId, "This tape has not expired\n");
241 /* Check if this previous-dump of the dump-in-progress is on this tape */
242 if (oldTapeLabel.dumpid
243 && (oldTapeLabel.dumpid == lastDump.id)) {
244 ErrorLog(0, taskId, 0, 0,
245 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
246 lastDump.name, lastDump.id);
252 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
253 newLabel.expirationDate = expires;
254 newLabel.useCount = oldTapeLabel.useCount + 1;
255 newLabel.dumpid = dumpid;
256 newLabel.size = tapeInfoPtr->tapeSize;
258 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
260 TapeLog(0, taskId, code, tapeInfoPtr->error,
261 "Can't label tape\n");
267 /* Initialize a tapeEntry for later inclusion into the database */
269 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
271 ERROR_EXIT(TC_NOMEMORY);
272 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
274 /* Remember dumpid so we can delete it later */
275 if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
276 && oldTapeLabel.dumpid)
277 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
279 /* Fill in tape entry so we can save it later */
280 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
281 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
282 tapeEntryPtr->written = newLabel.creationTime;
283 tapeEntryPtr->expires = expires;
284 tapeEntryPtr->seq = sequence;
285 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
286 tapeEntryPtr->dump = dumpid;
287 tapeEntryPtr->useKBytes = 0;
288 tapeEntryPtr->labelpos = 0;
290 /* Thread onto end of single-linked list */
292 endList = listEntryHead;
293 while (endList->next)
294 endList = endList->next;
295 endList->next = listEntryPtr;
297 listEntryHead = listEntryPtr;
305 * With the list of tapes, free the structures.
311 struct tapeEntryList *next;
313 listEntryPtr = listEntryHead;
314 while (listEntryPtr) {
315 next = listEntryPtr->next;
320 listEntryHead = NULL;
325 * With the list of tapes, add them to the database.
326 * Also delete any olddumpids that are around.
335 struct tapeEntryList *next;
337 listEntryPtr = listEntryHead;
338 while (listEntryPtr) {
339 next = listEntryPtr->next;
341 /* Remove the old database entry */
342 if (listEntryPtr->oldDumpId) {
343 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
344 if (i && (i != BUDB_NOENT)) {
345 ErrorLog(0, taskId, i, 0,
346 "Unable to delete old DB entry %u.\n",
347 listEntryPtr->oldDumpId);
351 /* Add the tape to the database */
352 code = bcdb_UseTape(tapeEntryPtr, &new);
354 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n",
359 code = bcdb_FinishTape(tapeEntryPtr);
361 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n",
375 * this code assumes that the blocksize on reads is smaller than
376 * the blocksize on writes
380 writeDbDump(tapeInfoPtr, taskId, expires, dumpid)
381 struct butm_tapeInfo *tapeInfoPtr;
387 afs_int32 writeBufNbytes = 0;
388 char *writeBlock = 0;
389 char *writeBuffer = 0;
391 afs_int32 transferSize;
393 char *readBufPtr = NULL;
394 afs_int32 maxReadSize;
399 afs_int32 chunksize = 0;
400 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
404 #ifdef AFS_PTHREAD_ENV
406 pthread_attr_t tattr;
412 extern struct tapeConfig globalTapeConfig;
413 extern struct udbHandleS udbHandle;
415 blockSize = BUTM_BLKSIZE;
416 writeBlock = (char *)malloc(BUTM_BLOCKSIZE);
418 ERROR_EXIT(TC_NOMEMORY);
420 writeBuffer = writeBlock + sizeof(struct blockMark);
421 memset(writeBuffer, 0, BUTM_BLKSIZE);
425 * The margin of space to check for end of tape is set to the
426 * amount of space used to write an end-of-tape multiplied by 2.
427 * The amount of space is size of a 16K EODump marker, its EOF
428 * marker, and up to two EOF markers done on close (1 16K blocks +
431 tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
432 tc_KEndMargin = tc_EndMargin / 1024;
434 /* have to write enclose the dump in file marks */
435 code = butm_WriteFileBegin(tapeInfoPtr);
437 ErrorLog(0, taskId, code, tapeInfoPtr->error,
438 "Can't write FileBegin on tape\n");
442 writeBufPtr = &writeBuffer[0];
445 charList.charListT_val = 0;
446 charList.charListT_len = 0;
449 /* When no data in buffer, read data from the budb_server */
450 if (charList.charListT_len == 0) {
451 /* get more data. let rx allocate space */
452 if (charList.charListT_val) {
453 free(charList.charListT_val);
454 charList.charListT_val = 0;
459 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
460 UF_SINGLESERVER, firstcall,
461 maxReadSize, &charList, &done);
463 ErrorLog(0, taskId, code, 0, "Can't read database\n");
467 /* If this if the first call to the budb server, create a thread
468 * that will keep the connection alive (during tape changes).
471 #ifdef AFS_PTHREAD_ENV
472 code = pthread_attr_init(&tattr);
474 ErrorLog(0, taskId, code, 0,
475 "Can't pthread_attr_init Keep-alive process\n");
480 pthread_attr_setdetachstate(&tattr,
481 PTHREAD_CREATE_DETACHED);
483 ErrorLog(0, taskId, code, 0,
484 "Can't pthread_attr_setdetachstate Keep-alive process\n");
489 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
490 AFS_SIGSET_RESTORE();
493 LWP_CreateProcess(KeepAlive, 16384, 1, (void *)NULL,
494 "Keep-alive process", &alivePid);
496 /* XXX should we check code here ??? XXX */
500 readBufPtr = charList.charListT_val;
503 if ((charList.charListT_len == 0) && done)
506 /* compute how many bytes and transfer to the write Buffer */
508 (charList.charListT_len <
510 writeBufNbytes)) ? charList.charListT_len : (blockSize -
513 memcpy(writeBufPtr, readBufPtr, transferSize);
514 charList.charListT_len -= transferSize;
515 writeBufPtr += transferSize;
516 readBufPtr += transferSize;
517 writeBufNbytes += transferSize;
519 /* If filled the write buffer, then write it to tape */
520 if (writeBufNbytes == blockSize) {
521 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
523 ErrorLog(0, taskId, code, tapeInfoPtr->error,
524 "Can't write data on tape\n");
528 memset(writeBuffer, 0, blockSize);
529 writeBufPtr = &writeBuffer[0];
532 /* Every BIGCHUNK bytes check if aborted */
533 chunksize += blockSize;
534 if (chunksize > BIGCHUNK) {
536 if (checkAbortByTaskId(taskId))
537 ERROR_EXIT(TC_ABORTEDBYREQUEST);
541 * check if tape is full - since we filled a blockSize worth of data
542 * assume that there is more data.
544 kRemaining = butm_remainingKSpace(tapeInfoPtr);
545 if (kRemaining < tc_KEndMargin) {
546 code = butm_WriteFileEnd(tapeInfoPtr);
548 ErrorLog(0, taskId, code, tapeInfoPtr->error,
549 "Can't write FileEnd on tape\n");
553 code = butm_WriteEOT(tapeInfoPtr);
555 ErrorLog(0, taskId, code, tapeInfoPtr->error,
556 "Can't write end-of-dump on tape\n");
560 /* Mark tape as having been written */
561 tapeEntryPtr->useKBytes =
562 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
563 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
565 unmountTape(taskId, tapeInfoPtr);
567 /* Get next tape and writes its label */
570 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
575 code = butm_WriteFileBegin(tapeInfoPtr);
577 ErrorLog(0, taskId, code, tapeInfoPtr->error,
578 "Can't write FileBegin on tape\n");
585 /* no more data to be read - if necessary, flush out the last buffer */
586 if (writeBufNbytes > 0) {
587 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
589 ErrorLog(1, taskId, code, tapeInfoPtr->error,
590 "Can't write data on tape\n");
595 code = butm_WriteFileEnd(tapeInfoPtr);
597 ErrorLog(0, taskId, code, tapeInfoPtr->error,
598 "Can't write FileEnd on tape\n");
602 /* Mark tape as having been written */
603 tapeEntryPtr->useKBytes =
604 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
605 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
608 /* Let the KeepAlive process stop on its own */
610 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
611 UF_END_SINGLESERVER, 0);
615 if (charList.charListT_val)
616 free(charList.charListT_val);
621 * dump backup database to tape
625 saveDbToTape(void *param)
627 struct saveDbIf *saveDbIfPtr = (struct saveDbIf *)param;
634 struct butm_tapeInfo tapeInfo;
635 struct budb_dumpEntry dumpEntry;
637 extern struct deviceSyncNode *deviceLatch;
638 extern struct tapeConfig globalTapeConfig;
640 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
641 taskId = saveDbIfPtr->taskId;
643 setStatus(taskId, DRIVE_WAIT);
644 EnterDeviceQueue(deviceLatch); /* lock tape device */
645 clearStatus(taskId, DRIVE_WAIT);
648 TLog(taskId, "SaveDb\n");
650 tapeInfo.structVersion = BUTM_MAJORVERSION;
651 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
653 ErrorLog(0, taskId, code, tapeInfo.error,
654 "Can't initialize tape module\n");
658 /* Determine what the last database dump was */
659 memset(&lastDump, 0, sizeof(lastDump));
660 code = bcdb_FindLatestDump("", "", &lastDump);
662 if (code != BUDB_NODUMPNAME) {
663 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
666 memset(&lastDump, 0, sizeof(lastDump));
669 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
671 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
676 listEntryHead = NULL;
678 /* Get the tape and write a new label to it */
680 GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
684 * If did not write the label, remove created dump
685 * Else if wrote the label, remove old dump from db so it's not saved.
688 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
690 if (i && (i != BUDB_NOENT))
691 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
693 } else if (listEntryHead->oldDumpId) {
694 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
695 listEntryHead->oldDumpId = 0;
696 if (i && (i != BUDB_NOENT)) {
697 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
698 listEntryHead->oldDumpId);
705 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
707 /* we have a writable tape */
708 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
712 /* Now delete the entries between time 0 and archive-time */
713 if (saveDbIfPtr->archiveTime)
714 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
717 unmountTape(taskId, &tapeInfo);
719 /* Add this dump's tapes to the database and mark it finished */
721 i = addTapesToDb(taskId);
725 i = bcdb_FinishDump(&dumpEntry);
731 if (code == TC_ABORTEDBYREQUEST) {
732 TLog(taskId, "SaveDb: Aborted by request\n");
733 clearStatus(taskId, ABORT_REQUEST);
734 setStatus(taskId, ABORT_DONE);
736 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
737 setStatus(taskId, TASK_ERROR);
739 TLog(taskId, "SaveDb: Finished\n");
741 setStatus(taskId, TASK_DONE);
744 LeaveDeviceQueue(deviceLatch);
745 return (void *)(code);
755 * Make a database dump entry given a tape label.
759 makeDbDumpEntry(tapeEntPtr, dumpEntryPtr)
760 struct budb_tapeEntry *tapeEntPtr;
761 struct budb_dumpEntry *dumpEntryPtr;
763 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
765 dumpEntryPtr->id = tapeEntPtr->dump;
766 dumpEntryPtr->initialDumpID = 0;
767 dumpEntryPtr->parent = 0;
768 dumpEntryPtr->level = 0;
769 dumpEntryPtr->flags = 0;
771 strcpy(dumpEntryPtr->volumeSetName, "");
772 strcpy(dumpEntryPtr->dumpPath, "");
773 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
775 dumpEntryPtr->created = tapeEntPtr->dump;
776 dumpEntryPtr->incTime = 0;
777 dumpEntryPtr->nVolumes = 0;
779 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
780 strcat(dumpEntryPtr->tapes.format, ".%d");
781 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
782 dumpEntryPtr->tapes.maxTapes = 0;
787 * prompt for a specific database tape
791 readDbTape(tapeInfoPtr, rstTapeInfoPtr, query)
792 struct butm_tapeInfo *tapeInfoPtr;
793 struct rstTapeInfo *rstTapeInfoPtr;
799 struct butm_tapeLabel oldTapeLabel;
800 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
801 struct tapeEntryList *endList;
803 struct budb_dumpEntry de;
804 struct budb_tapeEntry te;
806 taskId = rstTapeInfoPtr->taskId;
807 interactiveFlag = query;
809 /* construct the name of the tape */
810 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
811 strcpy(tapeName, AFStapeName);
813 /* Will prompt for the latest saved database tape, but will accept any one */
814 if (rstTapeInfoPtr->tapeSeq == 1) {
815 code = bcdb_FindLatestDump("", "", &de);
817 rstTapeInfoPtr->dumpid = de.id;
819 if (rstTapeInfoPtr->dumpid) {
821 bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
824 strcpy(tapeName, te.name);
829 if (interactiveFlag) { /* need a tape to read */
831 PromptForTape(RESTOREDBOPCODE, tapeName,
832 rstTapeInfoPtr->dumpid, taskId, tapecount);
839 code = butm_Mount(tapeInfoPtr, tapeName);
841 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
845 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
847 TapeLog(0, taskId, code, tapeInfoPtr->error,
848 "Can't read tape label\n");
852 /* Check for name of tape and matching dump id (if applicable). */
853 if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
854 || ((rstTapeInfoPtr->tapeSeq != 1)
855 && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
856 char expTape[BU_MAXTAPELEN + 32];
857 char gotTape[BU_MAXTAPELEN + 32];
859 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
860 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
862 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
867 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
868 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
873 unmountTape(taskId, tapeInfoPtr);
877 /* Initialize a tapeEntry for later inclusion into the database */
879 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
881 ERROR_EXIT(TC_NOMEMORY);
882 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
884 /* Fill in tape entry so we can save it later */
885 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
886 tapeEntryPtr->dump = oldTapeLabel.dumpid;
887 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
888 tapeEntryPtr->written = oldTapeLabel.creationTime;
889 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
890 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
891 tapeEntryPtr->useCount = oldTapeLabel.useCount;
892 tapeEntryPtr->useKBytes = 0;
893 tapeEntryPtr->labelpos = 0;
895 /* Thread onto end of single-linked list */
897 endList = listEntryHead;
898 while (endList->next)
899 endList = endList->next;
900 endList->next = listEntryPtr;
902 listEntryHead = listEntryPtr;
908 static afs_int32 nbytes = 0; /* # bytes left in buffer */
917 * restore all the items on the tape
919 * tape positioned after tape label
923 restoreDbEntries(tapeInfoPtr, rstTapeInfoPtr)
924 struct butm_tapeInfo *tapeInfoPtr;
925 struct rstTapeInfo *rstTapeInfoPtr;
927 struct structDumpHeader netItemHeader, hostItemHeader;
929 afs_int32 taskId, code = 0;
932 taskId = rstTapeInfoPtr->taskId;
934 /* clear state for the buffer routine(s) */
937 code = butm_ReadFileBegin(tapeInfoPtr);
939 ErrorLog(0, taskId, code, tapeInfoPtr->error,
940 "Can't read FileBegin on tape\n");
944 /* get the first item-header */
945 memset(&netItemHeader, 0, sizeof(netItemHeader));
947 getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
948 sizeof(netItemHeader));
951 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
954 switch (hostItemHeader.type) {
957 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
963 if (++count > 25) { /*every 25 dumps, wait */
968 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
978 case SD_TEXT_DUMPSCHEDULE:
979 case SD_TEXT_VOLUMESET:
980 case SD_TEXT_TAPEHOSTS:
981 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
991 TLog(taskId, "Unknown database header type %d\n",
992 hostItemHeader.type);
998 code = butm_ReadFileEnd(tapeInfoPtr);
1000 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1001 "Can't read EOF on tape\n");
1005 /* Mark tape as having been written */
1006 tapeEntryPtr->useKBytes =
1007 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1008 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1014 /* restoreDbFromTape
1015 * restore the backup database from tape.
1019 restoreDbFromTape(void *param)
1021 afs_uint32 taskId = (afs_uint32) param;
1024 struct butm_tapeInfo tapeInfo;
1025 struct rstTapeInfo rstTapeInfo;
1026 struct budb_dumpEntry dumpEntry;
1028 extern struct tapeConfig globalTapeConfig;
1029 extern struct deviceSyncNode *deviceLatch;
1031 setStatus(taskId, DRIVE_WAIT);
1032 EnterDeviceQueue(deviceLatch); /* lock tape device */
1033 clearStatus(taskId, DRIVE_WAIT);
1036 TLog(taskId, "RestoreDb\n");
1038 tapeInfo.structVersion = BUTM_MAJORVERSION;
1039 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1041 ErrorLog(0, taskId, code, tapeInfo.error,
1042 "Can't initialize tape module\n");
1046 listEntryHead = NULL;
1048 rstTapeInfo.taskId = taskId;
1049 rstTapeInfo.tapeSeq = 1;
1050 rstTapeInfo.dumpid = 0;
1052 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1056 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1061 /* Now put this dump into the database */
1062 /* Make a dump entry from first tape */
1063 listEntryPtr = listEntryHead;
1065 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1066 if (dumpEntry.id != 0) {
1067 i = bcdb_CreateDump(&dumpEntry);
1069 if (i == BUDB_DUMPIDEXISTS)
1071 "Dump id %d not added to database - already exists\n",
1074 TapeLog(0, taskId, i, 0,
1075 "Dump id %d not added to database\n",
1078 i = addTapesToDb(taskId);
1082 i = bcdb_FinishDump(&dumpEntry);
1090 unmountTape(taskId, &tapeInfo);
1093 if (code == TC_ABORTEDBYREQUEST) {
1094 TLog(taskId, "RestoreDb: Aborted by request\n");
1095 clearStatus(taskId, ABORT_REQUEST);
1096 setStatus(taskId, ABORT_DONE);
1098 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1099 setStatus(taskId, TASK_ERROR);
1101 TLog(taskId, "RestoreDb: Finished\n");
1104 LeaveDeviceQueue(deviceLatch);
1105 setStatus(taskId, TASK_DONE);
1107 return (void *)(code);
1112 * While dumping the database, keeps the connection alive.
1113 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
1114 * This resets the database's internal timer so that it does not
1115 * prematuraly quit (on asking for new tapes and such).
1117 * Use the same udbHandle as writeDbDump so we go to the same server.
1120 KeepAlive(void *unused)
1126 extern struct udbHandleS udbHandle;
1129 #ifdef AFS_PTHREAD_ENV
1134 charList.charListT_val = 0;
1135 charList.charListT_len = 0;
1137 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1138 UF_SINGLESERVER, 0, 0, &charList, &done);
1147 * restore special items in the header
1150 restoreDbHeader(tapeInfo, rstTapeInfoPtr, nextHeader)
1151 struct butm_tapeInfo *tapeInfo;
1152 struct rstTapeInfo *rstTapeInfoPtr;
1153 struct structDumpHeader *nextHeader;
1155 struct structDumpHeader netItemHeader;
1156 struct DbHeader netDbHeader, hostDbHeader;
1159 extern struct udbHandleS udbHandle;
1161 /* Read the database header */
1162 memset(&netDbHeader, 0, sizeof(netDbHeader));
1164 getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1165 sizeof(netDbHeader));
1168 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1170 /* Add the database header to the database */
1172 ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1175 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1176 "Can't restore DB Header\n");
1180 /* get the next item-header */
1181 memset(nextHeader, 0, sizeof(*nextHeader));
1183 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1184 sizeof(netItemHeader));
1187 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1195 * restore a single dump, including all its tapes and volumes, from
1198 * nextHeader - ptr to structure for return value
1200 * nextHeader - next structure header from tape
1202 * upon entry, the dump structure header has been read confirming that
1203 * a database dump tree exists on the tape
1206 restoreDbDump(tapeInfo, rstTapeInfoPtr, nextHeader)
1207 struct butm_tapeInfo *tapeInfo;
1208 struct rstTapeInfo *rstTapeInfoPtr;
1209 struct structDumpHeader *nextHeader;
1211 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1212 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1213 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1214 struct structDumpHeader netItemHeader;
1216 int restoreThisDump = 1;
1219 extern struct udbHandleS udbHandle;
1221 taskId = rstTapeInfoPtr->taskId;
1223 /* read dump entry */
1224 memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1226 getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry,
1227 sizeof(netDumpEntry));
1231 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1232 if (rstTapeInfoPtr->dumpid == 0) {
1233 netDumpEntry.initialDumpID = 0;
1234 netDumpEntry.appendedDumpID = 0;
1237 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1239 /* The dump entry for this database tape is incomplete, so don't include it */
1240 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1241 restoreThisDump = 0;
1243 /* add the dump to the database */
1244 if (restoreThisDump) {
1246 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1252 /* get the next item-header */
1253 memset(nextHeader, 0, sizeof(*nextHeader));
1255 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1256 sizeof(netItemHeader));
1259 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1261 /* Add every tape to the db */
1262 while (nextHeader->type == SD_TAPE) { /*t */
1264 /* read the tape entry */
1265 memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1267 getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry,
1268 sizeof(netTapeEntry));
1271 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1273 /* Add the tape to the database */
1274 if (restoreThisDump) {
1276 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1282 /* get the next item-header */
1283 memset(nextHeader, 0, sizeof(*nextHeader));
1285 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1286 sizeof(netItemHeader));
1289 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1291 /* Add every volume to the db */
1292 while (nextHeader->type == SD_VOLUME) { /*v */
1294 /* read the volume entry */
1295 memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1297 getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry,
1298 sizeof(netVolumeEntry));
1301 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1303 if (restoreThisDump) {
1305 threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry),
1311 /* get the next item-header */
1312 memset(nextHeader, 0, sizeof(*nextHeader));
1314 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1315 sizeof(netItemHeader));
1318 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1321 /* Finish the tape */
1322 if (restoreThisDump) {
1324 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1331 /* Finish the dump */
1332 if (restoreThisDump) {
1334 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1345 * Save the specified file as configuration text in the ubik database.
1346 * Have to setup the client text structure so that we can call
1347 * the routine to transmit the text to the db.
1351 saveTextFile(taskId, textType, fileName)
1356 udbClientTextP ctPtr = 0;
1360 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1362 ERROR_EXIT(TC_NOMEMORY);
1364 memset(ctPtr, 0, sizeof(*ctPtr));
1365 ctPtr->textType = textType;
1367 /* lock the text in the database */
1368 code = bc_LockText(ctPtr);
1370 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1375 ctPtr->textStream = fopen(fileName, "r");
1376 if (!ctPtr->textStream) {
1377 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1381 /* now send the text to the database */
1382 code = bcdb_SaveTextFile(ctPtr);
1384 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1390 if (ctPtr->textStream)
1391 fclose(ctPtr->textStream);
1393 bc_UnlockText(ctPtr);
1400 * read the text off the tape, and store it in the appropriate
1401 * text type in the database.
1403 * nextHeader - ptr to struct for return information
1405 * nextHeader - struct header for next item on the tape
1408 restoreText(tapeInfo, rstTapeInfoPtr, nextHeader)
1409 struct butm_tapeInfo *tapeInfo;
1410 struct rstTapeInfo *rstTapeInfoPtr;
1411 struct structDumpHeader *nextHeader;
1415 char *readBuffer = 0;
1416 afs_int32 readBlockSize;
1417 afs_int32 transferSize;
1418 struct structDumpHeader netItemHeader;
1422 udbClientTextP ctPtr = 0;
1425 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1427 ERROR_EXIT(TC_NOMEMORY);
1429 /* determine the type of text block */
1430 switch (nextHeader->type) {
1431 case SD_TEXT_DUMPSCHEDULE:
1432 textType = TB_DUMPSCHEDULE;
1435 case SD_TEXT_VOLUMESET:
1436 textType = TB_VOLUMESET;
1439 case SD_TEXT_TAPEHOSTS:
1440 textType = TB_TAPEHOSTS;
1444 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0,
1445 "Unknown text block\n");
1446 ERROR_EXIT(TC_INTERNALERROR);
1450 /* open the text file */
1451 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1452 #if defined (HAVE_MKSTEMP)
1453 fid = mkstemp(filename);
1455 fid = open(mktemp(filename), O_RDWR | O_CREAT | O_EXCL, 0600);
1458 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1459 "Can't open temporary text file: %s\n", filename);
1463 /* allocate buffer for text */
1464 readBlockSize = BUTM_BLKSIZE;
1465 readBuffer = (char *)malloc(readBlockSize);
1467 ERROR_EXIT(TC_NOMEMORY);
1469 /* read the text into the temporary file */
1470 nbytes = nextHeader->size;
1471 while (nbytes > 0) {
1472 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1474 /* read it from the tape */
1476 getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1480 /* write to the file */
1481 if (write(fid, readBuffer, transferSize) != transferSize) {
1482 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1483 "Can't write temporary text file: %s\n", filename);
1487 nbytes -= transferSize;
1492 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1497 /* get the next item-header */
1498 memset(nextHeader, 0, sizeof(*nextHeader));
1500 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1501 sizeof(netItemHeader));
1504 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1519 /* ----------------------------------
1520 * Tape data buffering - for reading database dumps
1521 * ----------------------------------
1524 static char *tapeReadBuffer = 0; /* input buffer */
1525 static char *tapeReadBufferPtr = 0; /* position in buffer */
1528 * Read information from tape, and place the requested number of bytes
1529 * in the buffer supplied
1532 * rstTapeInfoPtr - Info about the dump being restored.
1533 * buffer - buffer for requested data
1534 * requestedBytes - no. of bytes requested
1536 * fn retn - 0, ok, n, error
1539 getTapeData(tapeInfoPtr, rstTapeInfoPtr, buffer, requestedBytes)
1540 struct butm_tapeInfo *tapeInfoPtr;
1541 struct rstTapeInfo *rstTapeInfoPtr;
1543 afs_int32 requestedBytes;
1545 afs_int32 taskId, transferBytes, new;
1549 taskId = rstTapeInfoPtr->taskId;
1551 if (checkAbortByTaskId(taskId))
1552 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1554 if (!tapeReadBuffer) {
1555 tapeReadBuffer = (char *)malloc(BUTM_BLOCKSIZE);
1556 if (!tapeReadBuffer)
1557 ERROR_EXIT(TC_NOMEMORY);
1560 while (requestedBytes > 0) {
1562 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1566 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1567 BUTM_BLKSIZE, &nbytes);
1569 /* detect if we hit the end-of-tape and get next tape */
1570 if (code == BUTM_ENDVOLUME) {
1571 /* Update fields in tape entry for this tape */
1572 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1573 tapeEntryPtr->useKBytes =
1574 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1576 unmountTape(taskId, tapeInfoPtr);
1578 rstTapeInfoPtr->tapeSeq++;
1579 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1583 code = butm_ReadFileBegin(tapeInfoPtr);
1585 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1586 "Can't read FileBegin on tape\n");
1593 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1594 "Can't read FileData on tape\n");
1600 transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1601 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1602 tapeReadBufferPtr += transferBytes;
1603 buffer += transferBytes;
1604 nbytes -= transferBytes;
1605 requestedBytes -= transferBytes;