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;
56 * create a dump entry for a saved database
60 CreateDBDump(dumpEntryPtr)
61 struct budb_dumpEntry *dumpEntryPtr;
65 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
67 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
68 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
69 strcat(dumpEntryPtr->tapes.format, ".%d");
70 strcpy(dumpEntryPtr->volumeSetName, "");
71 strcpy(dumpEntryPtr->dumpPath, "");
72 dumpEntryPtr->created = 0; /* let database assign it */
73 dumpEntryPtr->incTime = 0;
74 dumpEntryPtr->nVolumes = 0;
75 dumpEntryPtr->initialDumpID = 0;
76 dumpEntryPtr->parent = 0;
77 dumpEntryPtr->level = 0;
78 dumpEntryPtr->tapes.maxTapes = 0;
79 dumpEntryPtr->tapes.b = 1;
81 /* now call the database to create the entry */
82 code = bcdb_CreateDump(dumpEntryPtr);
86 struct tapeEntryList {
87 struct tapeEntryList *next;
89 struct budb_tapeEntry tapeEnt;
91 struct tapeEntryList *listEntryHead;
92 struct tapeEntryList *listEntryPtr;
93 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
94 struct budb_dumpEntry lastDump; /* the last dump of this volset */
97 * Load a DB tape, read and over write its label.
98 * Leave the tape mounted.
101 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag,
105 struct butm_tapeInfo *tapeInfoPtr;
113 char tapeName[BU_MAXTAPELEN];
120 struct butm_tapeLabel oldTapeLabel, newLabel;
121 struct tapeEntryList *endList;
122 extern struct tapeConfig globalTapeConfig;
124 /* construct the name of the tape */
125 sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
127 interactiveFlag = queryFlag;
130 while (!*wroteLabel) { /*w */
131 if (interactiveFlag) { /* need a tape to write */
133 PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
141 code = butm_Mount(tapeInfoPtr, tapeName);
143 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
147 memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
148 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind tape */
150 oldTapeLabel.useCount = 0; /* no label exists */
151 oldTapeLabel.structVersion = 0;
152 strcpy(oldTapeLabel.pName, "");
154 /* If tape has a name, it must be null or database tape name */
155 if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
156 && !databaseTape(oldTapeLabel.AFSName)) {
157 char gotName[BU_MAXTAPELEN + 32];
159 LABELNAME(gotName, &oldTapeLabel);
161 "This tape %s must be a database tape or NULL tape\n",
165 unmountTape(taskId, tapeInfoPtr);
169 /* Do not overwrite a tape that belongs to this dump */
170 if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
171 ErrorLog(0, taskId, 0, 0,
172 "Can't overwrite tape containing the dump in progress\n");
176 /* On first tape, the savedb has not started yet, so the database is not locked
177 * and we can therefore, access information from it. This is easier to do because
178 * database dumps don't have appended dumps (nor appended).
182 struct budb_dumpEntry de, de2;
184 /* Verify the tape has not expired
185 * Early database dumps don't have a dumpid
187 if (!tapeExpired(&oldTapeLabel)) {
188 TLog(taskId, "This tape has not expired\n");
192 /* Since the dumpset on this tape will be deleted from database, check if
193 * any of the dumps in this dumpset are most-recent-dumps.
195 for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
196 if (dmp == lastDump.id) {
197 memcpy(&de, &lastDump, sizeof(de));
198 memcpy(&de2, &lastDump, sizeof(de2));
200 code = bcdb_FindDumpByID(dmp, &de);
203 sprintf(strlevel, "%d", de.level);
205 bcdb_FindLatestDump(de.volumeSetName, strlevel,
211 if (de.id == de2.id) {
212 if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
213 ErrorLog(0, taskId, 0, 0,
214 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
217 ErrorLog(0, taskId, 0, 0,
218 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
219 de.volumeSetName, de.name, de.id);
225 /* Otherwise, the savedb is in progress and we can't
226 * access the database (it's locked). So we rely on the
227 * information available (and not the backup database).
230 /* Check the tape's expiration date. Use the expiration on the label */
231 gettimeofday(&tp, &tzp);
233 if (curTime < oldTapeLabel.expirationDate) {
234 TLog(taskId, "This tape has not expired\n");
238 /* Check if this previous-dump of the dump-in-progress is on this tape */
239 if (oldTapeLabel.dumpid
240 && (oldTapeLabel.dumpid == lastDump.id)) {
241 ErrorLog(0, taskId, 0, 0,
242 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
243 lastDump.name, lastDump.id);
249 GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
250 newLabel.expirationDate = expires;
251 newLabel.useCount = oldTapeLabel.useCount + 1;
252 newLabel.dumpid = dumpid;
253 newLabel.size = tapeInfoPtr->tapeSize;
255 code = butm_Create(tapeInfoPtr, &newLabel, 1); /* rewind tape */
257 TapeLog(0, taskId, code, tapeInfoPtr->error,
258 "Can't label tape\n");
264 /* Initialize a tapeEntry for later inclusion into the database */
266 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
268 ERROR_EXIT(TC_NOMEMORY);
269 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
271 /* Remember dumpid so we can delete it later */
272 if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
273 && oldTapeLabel.dumpid)
274 listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
276 /* Fill in tape entry so we can save it later */
277 strcpy(tapeEntryPtr->name, TNAME(&newLabel));
278 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
279 tapeEntryPtr->written = newLabel.creationTime;
280 tapeEntryPtr->expires = expires;
281 tapeEntryPtr->seq = sequence;
282 tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
283 tapeEntryPtr->dump = dumpid;
284 tapeEntryPtr->useKBytes = 0;
285 tapeEntryPtr->labelpos = 0;
287 /* Thread onto end of single-linked list */
289 endList = listEntryHead;
290 while (endList->next)
291 endList = endList->next;
292 endList->next = listEntryPtr;
294 listEntryHead = listEntryPtr;
302 * With the list of tapes, free the structures.
308 struct tapeEntryList *next;
310 listEntryPtr = listEntryHead;
311 while (listEntryPtr) {
312 next = listEntryPtr->next;
317 listEntryHead = NULL;
322 * With the list of tapes, add them to the database.
323 * Also delete any olddumpids that are around.
332 struct tapeEntryList *next;
334 listEntryPtr = listEntryHead;
335 while (listEntryPtr) {
336 next = listEntryPtr->next;
338 /* Remove the old database entry */
339 if (listEntryPtr->oldDumpId) {
340 i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
341 if (i && (i != BUDB_NOENT)) {
342 ErrorLog(0, taskId, i, 0,
343 "Unable to delete old DB entry %u.\n",
344 listEntryPtr->oldDumpId);
348 /* Add the tape to the database */
349 code = bcdb_UseTape(tapeEntryPtr, &new);
351 ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n",
356 code = bcdb_FinishTape(tapeEntryPtr);
358 ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n",
372 * this code assumes that the blocksize on reads is smaller than
373 * the blocksize on writes
377 writeDbDump(tapeInfoPtr, taskId, expires, dumpid)
378 struct butm_tapeInfo *tapeInfoPtr;
384 afs_int32 writeBufNbytes = 0;
385 char *writeBlock = 0;
386 char *writeBuffer = 0;
388 afs_int32 transferSize;
391 afs_int32 maxReadSize;
396 afs_int32 chunksize = 0;
397 afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
401 #ifdef AFS_PTHREAD_ENV
403 pthread_attr_t tattr;
409 extern struct tapeConfig globalTapeConfig;
410 extern struct udbHandleS udbHandle;
412 extern int KeepAlive();
414 blockSize = BUTM_BLKSIZE;
415 writeBlock = (char *)malloc(BUTM_BLOCKSIZE);
417 ERROR_EXIT(TC_NOMEMORY);
419 writeBuffer = writeBlock + sizeof(struct blockMark);
420 memset(writeBuffer, 0, BUTM_BLKSIZE);
424 * The margin of space to check for end of tape is set to the
425 * amount of space used to write an end-of-tape multiplied by 2.
426 * The amount of space is size of a 16K EODump marker, its EOF
427 * marker, and up to two EOF markers done on close (1 16K blocks +
430 tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
431 tc_KEndMargin = tc_EndMargin / 1024;
433 /* have to write enclose the dump in file marks */
434 code = butm_WriteFileBegin(tapeInfoPtr);
436 ErrorLog(0, taskId, code, tapeInfoPtr->error,
437 "Can't write FileBegin on tape\n");
441 writeBufPtr = &writeBuffer[0];
444 charList.charListT_val = 0;
445 charList.charListT_len = 0;
448 /* When no data in buffer, read data from the budb_server */
449 if (charList.charListT_len == 0) {
450 /* get more data. let rx allocate space */
451 if (charList.charListT_val) {
452 free(charList.charListT_val);
453 charList.charListT_val = 0;
458 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
459 UF_SINGLESERVER, firstcall,
460 maxReadSize, &charList, &done);
462 ErrorLog(0, taskId, code, 0, "Can't read database\n");
466 /* If this if the first call to the budb server, create a thread
467 * that will keep the connection alive (during tape changes).
470 #ifdef AFS_PTHREAD_ENV
471 code = pthread_attr_init(&tattr);
473 ErrorLog(0, taskId, code, 0,
474 "Can't pthread_attr_init Keep-alive process\n");
479 pthread_attr_setdetachstate(&tattr,
480 PTHREAD_CREATE_DETACHED);
482 ErrorLog(0, taskId, code, 0,
483 "Can't pthread_attr_setdetachstate Keep-alive process\n");
488 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
489 AFS_SIGSET_RESTORE();
492 LWP_CreateProcess(KeepAlive, 16384, 1, (void *)NULL,
493 "Keep-alive process", &alivePid);
495 /* XXX should we check code here ??? XXX */
499 readBufPtr = charList.charListT_val;
502 if ((charList.charListT_len == 0) && done)
505 /* compute how many bytes and transfer to the write Buffer */
507 (charList.charListT_len <
509 writeBufNbytes)) ? charList.charListT_len : (blockSize -
512 memcpy(writeBufPtr, readBufPtr, transferSize);
513 charList.charListT_len -= transferSize;
514 writeBufPtr += transferSize;
515 readBufPtr += transferSize;
516 writeBufNbytes += transferSize;
518 /* If filled the write buffer, then write it to tape */
519 if (writeBufNbytes == blockSize) {
520 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
522 ErrorLog(0, taskId, code, tapeInfoPtr->error,
523 "Can't write data on tape\n");
527 memset(writeBuffer, 0, blockSize);
528 writeBufPtr = &writeBuffer[0];
531 /* Every BIGCHUNK bytes check if aborted */
532 chunksize += blockSize;
533 if (chunksize > BIGCHUNK) {
535 if (checkAbortByTaskId(taskId))
536 ERROR_EXIT(TC_ABORTEDBYREQUEST);
540 * check if tape is full - since we filled a blockSize worth of data
541 * assume that there is more data.
543 kRemaining = butm_remainingKSpace(tapeInfoPtr);
544 if (kRemaining < tc_KEndMargin) {
545 code = butm_WriteFileEnd(tapeInfoPtr);
547 ErrorLog(0, taskId, code, tapeInfoPtr->error,
548 "Can't write FileEnd on tape\n");
552 code = butm_WriteEOT(tapeInfoPtr);
554 ErrorLog(0, taskId, code, tapeInfoPtr->error,
555 "Can't write end-of-dump on tape\n");
559 /* Mark tape as having been written */
560 tapeEntryPtr->useKBytes =
561 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
562 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
564 unmountTape(taskId, tapeInfoPtr);
566 /* Get next tape and writes its label */
569 GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
574 code = butm_WriteFileBegin(tapeInfoPtr);
576 ErrorLog(0, taskId, code, tapeInfoPtr->error,
577 "Can't write FileBegin on tape\n");
584 /* no more data to be read - if necessary, flush out the last buffer */
585 if (writeBufNbytes > 0) {
586 code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
588 ErrorLog(1, taskId, code, tapeInfoPtr->error,
589 "Can't write data on tape\n");
594 code = butm_WriteFileEnd(tapeInfoPtr);
596 ErrorLog(0, taskId, code, tapeInfoPtr->error,
597 "Can't write FileEnd on tape\n");
601 /* Mark tape as having been written */
602 tapeEntryPtr->useKBytes =
603 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
604 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
607 /* Let the KeepAlive process stop on its own */
609 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
610 UF_END_SINGLESERVER, 0);
614 if (charList.charListT_val)
615 free(charList.charListT_val);
620 * dump backup database to tape
624 saveDbToTape(saveDbIfPtr)
625 struct saveDbIf *saveDbIfPtr;
633 struct butm_tapeInfo tapeInfo;
634 struct budb_dumpEntry dumpEntry;
636 extern struct deviceSyncNode *deviceLatch;
637 extern struct tapeConfig globalTapeConfig;
639 expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
640 taskId = saveDbIfPtr->taskId;
642 setStatus(taskId, DRIVE_WAIT);
643 EnterDeviceQueue(deviceLatch); /* lock tape device */
644 clearStatus(taskId, DRIVE_WAIT);
647 TLog(taskId, "SaveDb\n");
649 tapeInfo.structVersion = BUTM_MAJORVERSION;
650 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
652 ErrorLog(0, taskId, code, tapeInfo.error,
653 "Can't initialize tape module\n");
657 /* Determine what the last database dump was */
658 memset(&lastDump, 0, sizeof(lastDump));
659 code = bcdb_FindLatestDump("", "", &lastDump);
661 if (code != BUDB_NODUMPNAME) {
662 ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
665 memset(&lastDump, 0, sizeof(lastDump));
668 code = CreateDBDump(&dumpEntry); /* Create a dump for this tape */
670 ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
675 listEntryHead = NULL;
677 /* Get the tape and write a new label to it */
679 GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
683 * If did not write the label, remove created dump
684 * Else if wrote the label, remove old dump from db so it's not saved.
687 i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
689 if (i && (i != BUDB_NOENT))
690 ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
692 } else if (listEntryHead->oldDumpId) {
693 i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
694 listEntryHead->oldDumpId = 0;
695 if (i && (i != BUDB_NOENT)) {
696 ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
697 listEntryHead->oldDumpId);
704 TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
706 /* we have a writable tape */
707 code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
711 /* Now delete the entries between time 0 and archive-time */
712 if (saveDbIfPtr->archiveTime)
713 code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
716 unmountTape(taskId, &tapeInfo);
718 /* Add this dump's tapes to the database and mark it finished */
720 i = addTapesToDb(taskId);
724 i = bcdb_FinishDump(&dumpEntry);
730 if (code == TC_ABORTEDBYREQUEST) {
731 TLog(taskId, "SaveDb: Aborted by request\n");
732 clearStatus(taskId, ABORT_REQUEST);
733 setStatus(taskId, ABORT_DONE);
735 TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
736 setStatus(taskId, TASK_ERROR);
738 TLog(taskId, "SaveDb: Finished\n");
740 setStatus(taskId, TASK_DONE);
743 LeaveDeviceQueue(deviceLatch);
754 * Make a database dump entry given a tape label.
758 makeDbDumpEntry(tapeEntPtr, dumpEntryPtr)
759 struct budb_tapeEntry *tapeEntPtr;
760 struct budb_dumpEntry *dumpEntryPtr;
762 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
764 dumpEntryPtr->id = tapeEntPtr->dump;
765 dumpEntryPtr->initialDumpID = 0;
766 dumpEntryPtr->parent = 0;
767 dumpEntryPtr->level = 0;
768 dumpEntryPtr->flags = 0;
770 strcpy(dumpEntryPtr->volumeSetName, "");
771 strcpy(dumpEntryPtr->dumpPath, "");
772 strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
774 dumpEntryPtr->created = tapeEntPtr->dump;
775 dumpEntryPtr->incTime = 0;
776 dumpEntryPtr->nVolumes = 0;
778 strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
779 strcat(dumpEntryPtr->tapes.format, ".%d");
780 dumpEntryPtr->tapes.b = tapeEntPtr->seq;
781 dumpEntryPtr->tapes.maxTapes = 0;
786 * prompt for a specific database tape
790 readDbTape(tapeInfoPtr, rstTapeInfoPtr, query)
791 struct butm_tapeInfo *tapeInfoPtr;
792 struct rstTapeInfo *rstTapeInfoPtr;
798 struct butm_tapeLabel oldTapeLabel;
799 char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
800 struct tapeEntryList *endList;
802 struct budb_dumpEntry de;
803 struct budb_tapeEntry te;
805 taskId = rstTapeInfoPtr->taskId;
806 interactiveFlag = query;
808 /* construct the name of the tape */
809 sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
810 strcpy(tapeName, AFStapeName);
812 /* Will prompt for the latest saved database tape, but will accept any one */
813 if (rstTapeInfoPtr->tapeSeq == 1) {
814 code = bcdb_FindLatestDump("", "", &de);
816 rstTapeInfoPtr->dumpid = de.id;
818 if (rstTapeInfoPtr->dumpid) {
820 bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
823 strcpy(tapeName, te.name);
828 if (interactiveFlag) { /* need a tape to read */
830 PromptForTape(RESTOREDBOPCODE, tapeName,
831 rstTapeInfoPtr->dumpid, taskId, tapecount);
838 code = butm_Mount(tapeInfoPtr, tapeName);
840 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
844 code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* will rewind the tape */
846 TapeLog(0, taskId, code, tapeInfoPtr->error,
847 "Can't read tape label\n");
851 /* Check for name of tape and matching dump id (if applicable). */
852 if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
853 || ((rstTapeInfoPtr->tapeSeq != 1)
854 && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
855 char expTape[BU_MAXTAPELEN + 32];
856 char gotTape[BU_MAXTAPELEN + 32];
858 TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
859 TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
861 TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
866 if (rstTapeInfoPtr->tapeSeq == 1) /* Remember this dumpId */
867 rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
872 unmountTape(taskId, tapeInfoPtr);
876 /* Initialize a tapeEntry for later inclusion into the database */
878 (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
880 ERROR_EXIT(TC_NOMEMORY);
881 memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
883 /* Fill in tape entry so we can save it later */
884 strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
885 tapeEntryPtr->dump = oldTapeLabel.dumpid;
886 tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
887 tapeEntryPtr->written = oldTapeLabel.creationTime;
888 tapeEntryPtr->expires = oldTapeLabel.expirationDate;
889 tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
890 tapeEntryPtr->useCount = oldTapeLabel.useCount;
891 tapeEntryPtr->useKBytes = 0;
892 tapeEntryPtr->labelpos = 0;
894 /* Thread onto end of single-linked list */
896 endList = listEntryHead;
897 while (endList->next)
898 endList = endList->next;
899 endList->next = listEntryPtr;
901 listEntryHead = listEntryPtr;
907 static afs_int32 nbytes = 0; /* # bytes left in buffer */
916 * restore all the items on the tape
918 * tape positioned after tape label
922 restoreDbEntries(tapeInfoPtr, rstTapeInfoPtr)
923 struct butm_tapeInfo *tapeInfoPtr;
924 struct rstTapeInfo *rstTapeInfoPtr;
926 struct structDumpHeader netItemHeader, hostItemHeader;
928 afs_int32 taskId, code = 0;
931 taskId = rstTapeInfoPtr->taskId;
933 /* clear state for the buffer routine(s) */
936 code = butm_ReadFileBegin(tapeInfoPtr);
938 ErrorLog(0, taskId, code, tapeInfoPtr->error,
939 "Can't read FileBegin on tape\n");
943 /* get the first item-header */
944 memset(&netItemHeader, 0, sizeof(netItemHeader));
946 getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
947 sizeof(netItemHeader));
950 structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
953 switch (hostItemHeader.type) {
956 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
962 if (++count > 25) { /*every 25 dumps, wait */
967 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
977 case SD_TEXT_DUMPSCHEDULE:
978 case SD_TEXT_VOLUMESET:
979 case SD_TEXT_TAPEHOSTS:
980 code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
990 TLog(taskId, "Unknown database header type %d\n",
991 hostItemHeader.type);
997 code = butm_ReadFileEnd(tapeInfoPtr);
999 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1000 "Can't read EOF on tape\n");
1004 /* Mark tape as having been written */
1005 tapeEntryPtr->useKBytes =
1006 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1007 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1013 /* restoreDbFromTape
1014 * restore the backup database from tape.
1018 restoreDbFromTape(taskId)
1023 struct butm_tapeInfo tapeInfo;
1024 struct rstTapeInfo rstTapeInfo;
1025 struct budb_dumpEntry dumpEntry;
1027 extern struct tapeConfig globalTapeConfig;
1028 extern struct deviceSyncNode *deviceLatch;
1030 setStatus(taskId, DRIVE_WAIT);
1031 EnterDeviceQueue(deviceLatch); /* lock tape device */
1032 clearStatus(taskId, DRIVE_WAIT);
1035 TLog(taskId, "RestoreDb\n");
1037 tapeInfo.structVersion = BUTM_MAJORVERSION;
1038 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1040 ErrorLog(0, taskId, code, tapeInfo.error,
1041 "Can't initialize tape module\n");
1045 listEntryHead = NULL;
1047 rstTapeInfo.taskId = taskId;
1048 rstTapeInfo.tapeSeq = 1;
1049 rstTapeInfo.dumpid = 0;
1051 code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1055 code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1060 /* Now put this dump into the database */
1061 /* Make a dump entry from first tape */
1062 listEntryPtr = listEntryHead;
1064 makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1065 if (dumpEntry.id != 0) {
1066 i = bcdb_CreateDump(&dumpEntry);
1068 if (i == BUDB_DUMPIDEXISTS)
1070 "Dump id %d not added to database - already exists\n",
1073 TapeLog(0, taskId, i, 0,
1074 "Dump id %d not added to database\n",
1077 i = addTapesToDb(taskId);
1081 i = bcdb_FinishDump(&dumpEntry);
1089 unmountTape(taskId, &tapeInfo);
1092 if (code == TC_ABORTEDBYREQUEST) {
1093 TLog(taskId, "RestoreDb: Aborted by request\n");
1094 clearStatus(taskId, ABORT_REQUEST);
1095 setStatus(taskId, ABORT_DONE);
1097 TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1098 setStatus(taskId, TASK_ERROR);
1100 TLog(taskId, "RestoreDb: Finished\n");
1103 LeaveDeviceQueue(deviceLatch);
1104 setStatus(taskId, TASK_DONE);
1111 * While dumping the database, keeps the connection alive.
1112 * Every 10 seconds, wake up and ask to read 0 bytes of the database.
1113 * This resets the database's internal timer so that it does not
1114 * prematuraly quit (on asking for new tapes and such).
1116 * Use the same udbHandle as writeDbDump so we go to the same server.
1125 extern struct udbHandleS udbHandle;
1128 #ifdef AFS_PTHREAD_ENV
1133 charList.charListT_val = 0;
1134 charList.charListT_len = 0;
1136 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1137 UF_SINGLESERVER, 0, 0, &charList, &done);
1146 * restore special items in the header
1149 restoreDbHeader(tapeInfo, rstTapeInfoPtr, nextHeader)
1150 struct butm_tapeInfo *tapeInfo;
1151 struct rstTapeInfo *rstTapeInfoPtr;
1152 struct structDumpHeader *nextHeader;
1154 struct structDumpHeader netItemHeader;
1155 struct DbHeader netDbHeader, hostDbHeader;
1158 extern struct udbHandleS udbHandle;
1160 /* Read the database header */
1161 memset(&netDbHeader, 0, sizeof(netDbHeader));
1163 getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1164 sizeof(netDbHeader));
1167 DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1169 /* Add the database header to the database */
1171 ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1174 ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1175 "Can't restore DB Header\n");
1179 /* get the next item-header */
1180 memset(nextHeader, 0, sizeof(*nextHeader));
1182 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1183 sizeof(netItemHeader));
1186 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1194 * restore a single dump, including all its tapes and volumes, from
1197 * nextHeader - ptr to structure for return value
1199 * nextHeader - next structure header from tape
1201 * upon entry, the dump structure header has been read confirming that
1202 * a database dump tree exists on the tape
1205 restoreDbDump(tapeInfo, rstTapeInfoPtr, nextHeader)
1206 struct butm_tapeInfo *tapeInfo;
1207 struct rstTapeInfo *rstTapeInfoPtr;
1208 struct structDumpHeader *nextHeader;
1210 struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1211 struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1212 struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1213 struct structDumpHeader netItemHeader;
1215 int restoreThisDump = 1;
1218 extern struct udbHandleS udbHandle;
1220 taskId = rstTapeInfoPtr->taskId;
1222 /* read dump entry */
1223 memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1225 getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry,
1226 sizeof(netDumpEntry));
1230 /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1231 if (rstTapeInfoPtr->dumpid == 0) {
1232 netDumpEntry.initialDumpID = 0;
1233 netDumpEntry.appendedDumpID = 0;
1236 dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1238 /* The dump entry for this database tape is incomplete, so don't include it */
1239 if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1240 restoreThisDump = 0;
1242 /* add the dump to the database */
1243 if (restoreThisDump) {
1245 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1251 /* get the next item-header */
1252 memset(nextHeader, 0, sizeof(*nextHeader));
1254 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1255 sizeof(netItemHeader));
1258 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1260 /* Add every tape to the db */
1261 while (nextHeader->type == SD_TAPE) { /*t */
1263 /* read the tape entry */
1264 memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1266 getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry,
1267 sizeof(netTapeEntry));
1270 tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1272 /* Add the tape to the database */
1273 if (restoreThisDump) {
1275 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1281 /* get the next item-header */
1282 memset(nextHeader, 0, sizeof(*nextHeader));
1284 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1285 sizeof(netItemHeader));
1288 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1290 /* Add every volume to the db */
1291 while (nextHeader->type == SD_VOLUME) { /*v */
1293 /* read the volume entry */
1294 memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1296 getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry,
1297 sizeof(netVolumeEntry));
1300 volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1302 if (restoreThisDump) {
1304 threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry),
1310 /* get the next item-header */
1311 memset(nextHeader, 0, sizeof(*nextHeader));
1313 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1314 sizeof(netItemHeader));
1317 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1320 /* Finish the tape */
1321 if (restoreThisDump) {
1323 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1330 /* Finish the dump */
1331 if (restoreThisDump) {
1333 threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1344 * Save the specified file as configuration text in the ubik database.
1345 * Have to setup the client text structure so that we can call
1346 * the routine to transmit the text to the db.
1350 saveTextFile(taskId, textType, fileName)
1355 udbClientTextP ctPtr = 0;
1359 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1361 ERROR_EXIT(TC_NOMEMORY);
1363 memset(ctPtr, 0, sizeof(*ctPtr));
1364 ctPtr->textType = textType;
1366 /* lock the text in the database */
1367 code = bc_LockText(ctPtr);
1369 ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1374 ctPtr->textStream = fopen(fileName, "r");
1375 if (!ctPtr->textStream) {
1376 ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1380 /* now send the text to the database */
1381 code = bcdb_SaveTextFile(ctPtr);
1383 ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1389 if (ctPtr->textStream)
1390 fclose(ctPtr->textStream);
1392 bc_UnlockText(ctPtr);
1399 * read the text off the tape, and store it in the appropriate
1400 * text type in the database.
1402 * nextHeader - ptr to struct for return information
1404 * nextHeader - struct header for next item on the tape
1407 restoreText(tapeInfo, rstTapeInfoPtr, nextHeader)
1408 struct butm_tapeInfo *tapeInfo;
1409 struct rstTapeInfo *rstTapeInfoPtr;
1410 struct structDumpHeader *nextHeader;
1414 char *readBuffer = 0;
1415 afs_int32 readBlockSize;
1416 afs_int32 transferSize;
1417 struct structDumpHeader netItemHeader;
1421 udbClientTextP ctPtr = 0;
1424 ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1426 ERROR_EXIT(TC_NOMEMORY);
1428 /* determine the type of text block */
1429 switch (nextHeader->type) {
1430 case SD_TEXT_DUMPSCHEDULE:
1431 textType = TB_DUMPSCHEDULE;
1434 case SD_TEXT_VOLUMESET:
1435 textType = TB_VOLUMESET;
1438 case SD_TEXT_TAPEHOSTS:
1439 textType = TB_TAPEHOSTS;
1443 ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0,
1444 "Unknown text block\n");
1445 ERROR_EXIT(TC_INTERNALERROR);
1449 /* open the text file */
1450 sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1451 #if defined (HAVE_MKSTEMP)
1452 fid = mkstemp(filename);
1454 fid = open(mktemp(filename), O_RDWR | O_CREAT | O_EXCL, 0600);
1457 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1458 "Can't open temporary text file: %s\n", filename);
1462 /* allocate buffer for text */
1463 readBlockSize = BUTM_BLKSIZE;
1464 readBuffer = (char *)malloc(readBlockSize);
1466 ERROR_EXIT(TC_NOMEMORY);
1468 /* read the text into the temporary file */
1469 nbytes = nextHeader->size;
1470 while (nbytes > 0) {
1471 transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1473 /* read it from the tape */
1475 getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1479 /* write to the file */
1480 if (write(fid, readBuffer, transferSize) != transferSize) {
1481 ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1482 "Can't write temporary text file: %s\n", filename);
1486 nbytes -= transferSize;
1491 code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1496 /* get the next item-header */
1497 memset(nextHeader, 0, sizeof(*nextHeader));
1499 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1500 sizeof(netItemHeader));
1503 structDumpHeader_ntoh(&netItemHeader, nextHeader);
1518 /* ----------------------------------
1519 * Tape data buffering - for reading database dumps
1520 * ----------------------------------
1523 static char *tapeReadBuffer = 0; /* input buffer */
1524 static char *tapeReadBufferPtr = 0; /* position in buffer */
1527 * Read information from tape, and place the requested number of bytes
1528 * in the buffer supplied
1531 * rstTapeInfoPtr - Info about the dump being restored.
1532 * buffer - buffer for requested data
1533 * requestedBytes - no. of bytes requested
1535 * fn retn - 0, ok, n, error
1538 getTapeData(tapeInfoPtr, rstTapeInfoPtr, buffer, requestedBytes)
1539 struct butm_tapeInfo *tapeInfoPtr;
1540 struct rstTapeInfo *rstTapeInfoPtr;
1542 afs_int32 requestedBytes;
1544 afs_int32 taskId, transferBytes, new;
1548 taskId = rstTapeInfoPtr->taskId;
1550 if (checkAbortByTaskId(taskId))
1551 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1553 if (!tapeReadBuffer) {
1554 tapeReadBuffer = (char *)malloc(BUTM_BLOCKSIZE);
1555 if (!tapeReadBuffer)
1556 ERROR_EXIT(TC_NOMEMORY);
1559 while (requestedBytes > 0) {
1561 tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1565 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1566 BUTM_BLKSIZE, &nbytes);
1568 /* detect if we hit the end-of-tape and get next tape */
1569 if (code == BUTM_ENDVOLUME) {
1570 /* Update fields in tape entry for this tape */
1571 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1572 tapeEntryPtr->useKBytes =
1573 tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1575 unmountTape(taskId, tapeInfoPtr);
1577 rstTapeInfoPtr->tapeSeq++;
1578 code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1582 code = butm_ReadFileBegin(tapeInfoPtr);
1584 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1585 "Can't read FileBegin on tape\n");
1592 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1593 "Can't read FileData on tape\n");
1599 transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1600 memcpy(buffer, tapeReadBufferPtr, transferBytes);
1601 tapeReadBufferPtr += transferBytes;
1602 buffer += transferBytes;
1603 nbytes -= transferBytes;
1604 requestedBytes -= transferBytes;