butc: avoid freeing uninitialized pointer in writeDbDump()
[openafs.git] / src / butc / tcudbprocs.c
index 7a902ef..3fe76f5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
+#include <afs/procmgmt.h>
+#include <roken.h>
 
-#include <sys/types.h>
-#ifdef AFS_NT40_ENV
-#include <winsock2.h>
-#include <io.h>
-#else
-#include <sys/time.h>
-#include <sys/file.h>
-#include <netinet/in.h>
-#include <netdb.h>
+#ifdef IGNORE_SOME_GCC_WARNINGS
+# pragma GCC diagnostic warning "-Wimplicit-function-declaration"
 #endif
-#include <errno.h>
+
 #include <rx/xdr.h>
 #include <rx/rx.h>
 #include <afs/afsint.h>
-#include <stdio.h>
-#include <afs/procmgmt.h>
-#include <afs/assert.h>
+#include <afs/afs_assert.h>
 #include <afs/prs_fs.h>
-#include <fcntl.h>
 #include <afs/nfs.h>
 #include <lwp.h>
 #include <lock.h>
-#include <afs/auth.h>
 #include <afs/cellconfig.h>
 #include <afs/keys.h>
 #include <ubik.h>
 #include <afs/acl.h>
+#include <afs/volser.h>
+#include <afs/vlserver.h>
 #include <afs/tcdata.h>
 #include <afs/budb.h>
 #include <afs/budb_client.h>
 #include <afs/bubasics.h>
+#include <afs/bucoord_prototypes.h>
+#include <afs/butm_prototypes.h>
+#include <afs/budb_prototypes.h>
+#include <afs/afsutil.h>
+
+#include "butc_internal.h"
 #include "error_macros.h"
 
 /* GLOBAL CONFIGURATION PARAMETERS */
+#define BIGCHUNK 102400
+
 extern int dump_namecheck;
 extern int autoQuery;
 
+struct rstTapeInfo {
+    afs_int32 taskId;
+    afs_int32 tapeSeq;
+    afs_uint32 dumpid;
+};
+
+static void initTapeBuffering(void);
+static int writeDbDump(struct butm_tapeInfo *, afs_uint32, Date, afs_uint32);
+static int restoreDbEntries(struct butm_tapeInfo *, struct rstTapeInfo *);
+
+int getTapeData(struct butm_tapeInfo *, struct rstTapeInfo *, void *,
+               afs_int32);
+int restoreDbHeader(struct butm_tapeInfo *, struct rstTapeInfo *,
+                   struct structDumpHeader *);
+int restoreDbDump(struct butm_tapeInfo *, struct rstTapeInfo *,
+                 struct structDumpHeader *);
+int restoreText(struct butm_tapeInfo *, struct rstTapeInfo *,
+               struct structDumpHeader *);
+
+
+
+void * KeepAlive(void *);
 /* CreateDBDump
- *      create a dump entry for a saved database 
+ *      create a dump entry for a saved database
  */
 
 afs_int32
-CreateDBDump(dumpEntryPtr)
-     struct budb_dumpEntry *dumpEntryPtr;
+CreateDBDump(struct budb_dumpEntry *dumpEntryPtr)
 {
     afs_int32 code = 0;
 
@@ -96,28 +116,20 @@ struct budb_dumpEntry lastDump;    /* the last dump of this volset */
  *      Leave the tape mounted.
  */
 afs_int32
-GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag,
-         wroteLabel)
-     afs_int32 taskId;
-     Date expires;
-     struct butm_tapeInfo *tapeInfoPtr;
-     afs_uint32 dumpid;
-     afs_int32 sequence;
-     int queryFlag;
-     int *wroteLabel;
+GetDBTape(afs_int32 taskId, Date expires, struct butm_tapeInfo *tapeInfoPtr,
+         afs_uint32 dumpid, afs_int32 sequence, int queryFlag,
+         int *wroteLabel)
 {
     afs_int32 code = 0;
     int interactiveFlag;
     char tapeName[BU_MAXTAPELEN];
     char strlevel[5];
     struct timeval tp;
-    struct timezone tzp;
     afs_int32 curTime;
     int tapecount = 1;
 
     struct butm_tapeLabel oldTapeLabel, newLabel;
     struct tapeEntryList *endList;
-    extern struct tapeConfig globalTapeConfig;
 
     /* construct the name of the tape */
     sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
@@ -171,7 +183,7 @@ GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag,
                goto getNewTape;
            }
 
-           /* On first tape, the savedb has not started yet, so the database is not locked 
+           /* On first tape, the savedb has not started yet, so the database is not locked
             * and we can therefore, access information from it. This is easier to do because
             * database dumps don't have appended dumps (nor appended).
             */
@@ -180,7 +192,7 @@ GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag,
                struct budb_dumpEntry de, de2;
 
                /* Verify the tape has not expired
-                * Early database dumps don't have a dumpid 
+                * Early database dumps don't have a dumpid
                 */
                if (!tapeExpired(&oldTapeLabel)) {
                    TLog(taskId, "This tape has not expired\n");
@@ -221,12 +233,12 @@ GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag,
            }
 
            /* Otherwise, the savedb is in progress and we can't
-            * access the database (it's locked). So we rely on the 
+            * access the database (it's locked). So we rely on the
             * information available (and not the backup database).
             */
            else {
                /* Check the tape's expiration date. Use the expiration on the label */
-               gettimeofday(&tp, &tzp);
+               gettimeofday(&tp, NULL);
                curTime = tp.tv_sec;
                if (curTime < oldTapeLabel.expirationDate) {
                    TLog(taskId, "This tape has not expired\n");
@@ -301,7 +313,7 @@ GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence, queryFlag,
  */
 
 afs_int32
-freeTapeList()
+freeTapeList(void)
 {
     struct tapeEntryList *next;
 
@@ -317,13 +329,12 @@ freeTapeList()
 }
 
 /* addTapesToDb
- *       With the list of tapes, add them to the database. 
+ *       With the list of tapes, add them to the database.
  *       Also delete any olddumpids that are around.
  */
 
 afs_int32
-addTapesToDb(taskId)
-     afs_int32 taskId;
+addTapesToDb(afs_int32 taskId)
 {
     afs_int32 code = 0;
     afs_int32 i, new;
@@ -365,148 +376,388 @@ addTapesToDb(taskId)
     return (code);
 }
 
-/* saveDbToTape
- *     dump backup database to tape
+/* writeDbDump
+ * notes:
+ *     this code assumes that the blocksize on reads is smaller than
+ *     the blocksize on writes
  */
 
-afs_int32
-saveDbToTape(saveDbIfPtr)
-     struct saveDbIf *saveDbIfPtr;
+static int
+writeDbDump(struct butm_tapeInfo *tapeInfoPtr, afs_uint32 taskId,
+           Date expires, afs_uint32 dumpid)
 {
-    afs_int32 code = 0;
-    afs_int32 i;
-    int wroteLabel;
-    afs_uint32 taskId;
-    Date expires;
+    afs_int32 blockSize;
+    afs_int32 writeBufNbytes = 0;
+    char *writeBlock = 0;
+    char *writeBuffer = 0;
+    char *writeBufPtr;
+    afs_int32 transferSize;
 
-    struct butm_tapeInfo tapeInfo;
-    struct budb_dumpEntry dumpEntry;
+    char *readBufPtr = NULL;
+    afs_int32 maxReadSize;
+
+    charListT charList;
+    afs_int32 done;
+    afs_int32 code;
+    afs_int32 chunksize = 0;
+    afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
+    int sequence;
+    int wroteLabel;
+    int firstcall;
+#ifdef AFS_PTHREAD_ENV
+    pthread_t alivePid;
+    pthread_attr_t tattr;
+    AFS_SIGSET_DECL;
+#else
+    PROCESS alivePid;
+#endif
 
-    extern struct deviceSyncNode *deviceLatch;
     extern struct tapeConfig globalTapeConfig;
+    extern struct udbHandleS udbHandle;
 
-    expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
-    taskId = saveDbIfPtr->taskId;
+    charList.charListT_val = 0;
+    charList.charListT_len = 0;
+    blockSize = BUTM_BLKSIZE;
+    writeBlock = (char *)malloc(BUTM_BLOCKSIZE);
+    if (!writeBlock)
+       ERROR_EXIT(TC_NOMEMORY);
 
-    setStatus(taskId, DRIVE_WAIT);
-    EnterDeviceQueue(deviceLatch);     /* lock tape device */
-    clearStatus(taskId, DRIVE_WAIT);
+    writeBuffer = writeBlock + sizeof(struct blockMark);
+    memset(writeBuffer, 0, BUTM_BLKSIZE);
+    maxReadSize = 1024;
 
-    printf("\n\n");
-    TLog(taskId, "SaveDb\n");
+    /*
+     * The margin of space to check for end of tape is set to the
+     * amount of space used to write an end-of-tape multiplied by 2.
+     * The amount of space is size of a 16K EODump marker, its EOF
+     * marker, and up to two EOF markers done on close (1 16K blocks +
+     * 3 EOF * markers).
+     */
+    tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
+    tc_KEndMargin = tc_EndMargin / 1024;
 
-    tapeInfo.structVersion = BUTM_MAJORVERSION;
-    code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
+    /* have to write enclose the dump in file marks */
+    code = butm_WriteFileBegin(tapeInfoPtr);
     if (code) {
-       ErrorLog(0, taskId, code, tapeInfo.error,
-                "Can't initialize tape module\n");
+       ErrorLog(0, taskId, code, tapeInfoPtr->error,
+                "Can't write FileBegin on tape\n");
        ERROR_EXIT(code);
     }
 
-    /* Determine what the last database dump was */
-    memset(&lastDump, 0, sizeof(lastDump));
-    code = bcdb_FindLatestDump("", "", &lastDump);
-    if (code) {
-       if (code != BUDB_NODUMPNAME) {
-           ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
-           ERROR_EXIT(code);
-       }
-       memset(&lastDump, 0, sizeof(lastDump));
-    }
+    writeBufPtr = &writeBuffer[0];
+    firstcall = 1;
+    sequence = 1;
 
-    code = CreateDBDump(&dumpEntry);   /* Create a dump for this tape */
-    if (code) {
-       ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
-       ERROR_EXIT(code);
-    }
+    while (1) {                        /*w */
+       /* When no data in buffer, read data from the budb_server */
+       if (charList.charListT_len == 0) {
+           /* get more data. let rx allocate space */
+           if (charList.charListT_val) {
+               free(charList.charListT_val);
+               charList.charListT_val = 0;
+           }
 
+           /* get the data */
+           code =
+               ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
+                                      UF_SINGLESERVER, firstcall,
+                                      maxReadSize, &charList, &done);
+           if (code) {
+               ErrorLog(0, taskId, code, 0, "Can't read database\n");
+               ERROR_EXIT(code);
+           }
 
-    listEntryHead = NULL;
+           /* If this if the first call to the budb server, create a thread
+            * that will keep the connection alive (during tape changes).
+            */
+           if (firstcall) {
+#ifdef AFS_PTHREAD_ENV
+               code = pthread_attr_init(&tattr);
+               if (code) {
+                   ErrorLog(0, taskId, code, 0,
+                            "Can't pthread_attr_init Keep-alive process\n");
+                   ERROR_EXIT(code);
+               }
 
-    /* Get the tape and write a new label to it */
-    code =
-       GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
-                 &wroteLabel);
+               code =
+                   pthread_attr_setdetachstate(&tattr,
+                                               PTHREAD_CREATE_DETACHED);
+               if (code) {
+                   ErrorLog(0, taskId, code, 0,
+                            "Can't pthread_attr_setdetachstate Keep-alive process\n");
+                   ERROR_EXIT(code);
+               }
 
-    /*
-     * If did not write the label, remove created dump 
-     * Else if wrote the label, remove old dump from db so it's not saved.
-     */
-    if (!wroteLabel) {
-       i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
-       dumpEntry.id = 0;
-       if (i && (i != BUDB_NOENT))
-           ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
-                    dumpEntry.id);
-    } else if (listEntryHead->oldDumpId) {
-       i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
-       listEntryHead->oldDumpId = 0;
-       if (i && (i != BUDB_NOENT)) {
-           ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
-                    listEntryHead->oldDumpId);
-           ERROR_EXIT(i);
+               AFS_SIGSET_CLEAR();
+               code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
+               AFS_SIGSET_RESTORE();
+#else
+               code =
+                   LWP_CreateProcess(KeepAlive, 16384, 1, (void *)NULL,
+                                     "Keep-alive process", &alivePid);
+#endif
+               /* XXX should we check code here ??? XXX */
+           }
+           firstcall = 0;
+
+           readBufPtr = charList.charListT_val;
        }
-    }
-    if (code)
-       ERROR_EXIT(code);
 
-    TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
+       if ((charList.charListT_len == 0) && done)
+           break;
 
-    /* we have a writable tape */
-    code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
-    if (code)
-       ERROR_EXIT(code);
+       /* compute how many bytes and transfer to the write Buffer */
+       transferSize =
+           (charList.charListT_len <
+            (blockSize -
+             writeBufNbytes)) ? charList.charListT_len : (blockSize -
+                                                          writeBufNbytes);
 
-    /* Now delete the entries between time 0 and archive-time */
-    if (saveDbIfPtr->archiveTime)
-       code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
+       memcpy(writeBufPtr, readBufPtr, transferSize);
+       charList.charListT_len -= transferSize;
+       writeBufPtr += transferSize;
+       readBufPtr += transferSize;
+       writeBufNbytes += transferSize;
 
-  error_exit:
-    unmountTape(taskId, &tapeInfo);
+       /* If filled the write buffer, then write it to tape */
+       if (writeBufNbytes == blockSize) {
+           code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
+           if (code) {
+               ErrorLog(0, taskId, code, tapeInfoPtr->error,
+                        "Can't write data on tape\n");
+               ERROR_EXIT(code);
+           }
 
-    /* Add this dump's tapes to the database and mark it finished */
-    if (dumpEntry.id) {
-       i = addTapesToDb(taskId);
-       if (!code)
-           code = i;
+           memset(writeBuffer, 0, blockSize);
+           writeBufPtr = &writeBuffer[0];
+           writeBufNbytes = 0;
 
-       i = bcdb_FinishDump(&dumpEntry);
-       if (!code)
-           code = i;
-    }
-    freeTapeList();
+           /* Every BIGCHUNK bytes check if aborted */
+           chunksize += blockSize;
+           if (chunksize > BIGCHUNK) {
+               chunksize = 0;
+               if (checkAbortByTaskId(taskId))
+                   ERROR_EXIT(TC_ABORTEDBYREQUEST);
+           }
 
-    if (code == TC_ABORTEDBYREQUEST) {
-       TLog(taskId, "SaveDb: Aborted by request\n");
-       clearStatus(taskId, ABORT_REQUEST);
-       setStatus(taskId, ABORT_DONE);
-    } else if (code) {
-       TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
-       setStatus(taskId, TASK_ERROR);
-    } else {
-       TLog(taskId, "SaveDb: Finished\n");
-    }
-    setStatus(taskId, TASK_DONE);
+           /*
+            * check if tape is full - since we filled a blockSize worth of data
+            * assume that there is more data.
+            */
+           kRemaining = butm_remainingKSpace(tapeInfoPtr);
+           if (kRemaining < tc_KEndMargin) {
+               code = butm_WriteFileEnd(tapeInfoPtr);
+               if (code) {
+                   ErrorLog(0, taskId, code, tapeInfoPtr->error,
+                            "Can't write FileEnd on tape\n");
+                   ERROR_EXIT(code);
+               }
 
-    free(saveDbIfPtr);
-    LeaveDeviceQueue(deviceLatch);
-    return (code);
-}
+               code = butm_WriteEOT(tapeInfoPtr);
+               if (code) {
+                   ErrorLog(0, taskId, code, tapeInfoPtr->error,
+                            "Can't write end-of-dump on tape\n");
+                   ERROR_EXIT(code);
+               }
+
+               /* Mark tape as having been written */
+               tapeEntryPtr->useKBytes =
+                   tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
+               tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
+
+               unmountTape(taskId, tapeInfoPtr);
+
+               /* Get next tape and writes its label */
+               sequence++;
+               code =
+                   GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
+                             1, &wroteLabel);
+               if (code)
+                   ERROR_EXIT(code);
+
+               code = butm_WriteFileBegin(tapeInfoPtr);
+               if (code) {
+                   ErrorLog(0, taskId, code, tapeInfoPtr->error,
+                            "Can't write FileBegin on tape\n");
+                   ERROR_EXIT(code);
+               }
+           }
+       }
+    }                          /*w */
+
+    /* no more data to be read - if necessary, flush out the last buffer */
+    if (writeBufNbytes > 0) {
+       code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
+       if (code) {
+           ErrorLog(1, taskId, code, tapeInfoPtr->error,
+                    "Can't write data on tape\n");
+           ERROR_EXIT(code);
+       }
+    }
+
+    code = butm_WriteFileEnd(tapeInfoPtr);
+    if (code) {
+       ErrorLog(0, taskId, code, tapeInfoPtr->error,
+                "Can't write FileEnd on tape\n");
+       ERROR_EXIT(code);
+    }
+
+    /* Mark tape as having been written */
+    tapeEntryPtr->useKBytes =
+       tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
+    tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
+
+  error_exit:
+    /* Let the KeepAlive process stop on its own */
+    code =
+       ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
+                              UF_END_SINGLESERVER, 0);
+
+    if (writeBlock)
+       free(writeBlock);
+    if (charList.charListT_val)
+       free(charList.charListT_val);
+    return (code);
+}
+
+/* saveDbToTape
+ *     dump backup database to tape
+ */
+
+void *
+saveDbToTape(void *param)
+{
+    struct saveDbIf *saveDbIfPtr = (struct saveDbIf *)param;
+    afs_int32 code;
+    afs_int32 i;
+    int wroteLabel;
+    afs_uint32 taskId;
+    Date expires;
+
+    struct butm_tapeInfo tapeInfo;
+    struct budb_dumpEntry dumpEntry;
+
+    extern struct deviceSyncNode *deviceLatch;
+    extern struct tapeConfig globalTapeConfig;
+
+    afs_pthread_setname_self("Db save");
+    expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
+    taskId = saveDbIfPtr->taskId;
+    dumpEntry.id = 0;
+
+    setStatus(taskId, DRIVE_WAIT);
+    EnterDeviceQueue(deviceLatch);     /* lock tape device */
+    clearStatus(taskId, DRIVE_WAIT);
+
+    printf("\n\n");
+    TLog(taskId, "SaveDb\n");
+
+    tapeInfo.structVersion = BUTM_MAJORVERSION;
+    code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
+    if (code) {
+       ErrorLog(0, taskId, code, tapeInfo.error,
+                "Can't initialize tape module\n");
+       ERROR_EXIT(code);
+    }
+
+    /* Determine what the last database dump was */
+    memset(&lastDump, 0, sizeof(lastDump));
+    code = bcdb_FindLatestDump("", "", &lastDump);
+    if (code) {
+       if (code != BUDB_NODUMPNAME) {
+           ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
+           ERROR_EXIT(code);
+       }
+       memset(&lastDump, 0, sizeof(lastDump));
+    }
+
+    code = CreateDBDump(&dumpEntry);   /* Create a dump for this tape */
+    if (code) {
+       ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
+       ERROR_EXIT(code);
+    }
+
+
+    listEntryHead = NULL;
+
+    /* Get the tape and write a new label to it */
+    code =
+       GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
+                 &wroteLabel);
+
+    /*
+     * If did not write the label, remove created dump
+     * Else if wrote the label, remove old dump from db so it's not saved.
+     */
+    if (!wroteLabel) {
+       i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
+       dumpEntry.id = 0;
+       if (i && (i != BUDB_NOENT))
+           ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
+                    dumpEntry.id);
+    } else if (listEntryHead->oldDumpId) {
+       i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
+       listEntryHead->oldDumpId = 0;
+       if (i && (i != BUDB_NOENT)) {
+           ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
+                    listEntryHead->oldDumpId);
+           ERROR_EXIT(i);
+       }
+    }
+    if (code)
+       ERROR_EXIT(code);
+
+    TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
+
+    /* we have a writable tape */
+    code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
+    if (code)
+       ERROR_EXIT(code);
+
+    /* Now delete the entries between time 0 and archive-time */
+    if (saveDbIfPtr->archiveTime)
+       code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
+
+  error_exit:
+    unmountTape(taskId, &tapeInfo);
+
+    /* Add this dump's tapes to the database and mark it finished */
+    if (dumpEntry.id) {
+       i = addTapesToDb(taskId);
+       if (!code)
+           code = i;
+
+       i = bcdb_FinishDump(&dumpEntry);
+       if (!code)
+           code = i;
+    }
+    freeTapeList();
+
+    if (code == TC_ABORTEDBYREQUEST) {
+       TLog(taskId, "SaveDb: Aborted by request\n");
+       clearStatus(taskId, ABORT_REQUEST);
+       setStatus(taskId, ABORT_DONE);
+    } else if (code) {
+       TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
+       setStatus(taskId, TASK_ERROR);
+    } else {
+       TLog(taskId, "SaveDb: Finished\n");
+    }
+    setStatus(taskId, TASK_DONE);
+
+    free(saveDbIfPtr);
+    LeaveDeviceQueue(deviceLatch);
+    return (void *)(intptr_t)(code);
+}
 
-struct rstTapeInfo {
-    afs_int32 taskId;
-    afs_int32 tapeSeq;
-    afs_uint32 dumpid;
-};
 
 /* makeDbDumpEntry()
  *      Make a database dump entry given a tape label.
  */
 
 afs_int32
-makeDbDumpEntry(tapeEntPtr, dumpEntryPtr)
-     struct budb_tapeEntry *tapeEntPtr;
-     struct budb_dumpEntry *dumpEntryPtr;
+makeDbDumpEntry(struct budb_tapeEntry *tapeEntPtr,
+               struct budb_dumpEntry *dumpEntryPtr)
 {
     memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
 
@@ -536,10 +787,8 @@ makeDbDumpEntry(tapeEntPtr, dumpEntryPtr)
  */
 
 afs_int32
-readDbTape(tapeInfoPtr, rstTapeInfoPtr, query)
-     struct butm_tapeInfo *tapeInfoPtr;
-     struct rstTapeInfo *rstTapeInfoPtr;
-     int query;
+readDbTape(struct butm_tapeInfo *tapeInfoPtr,
+          struct rstTapeInfo *rstTapeInfoPtr, int query)
 {
     afs_int32 code = 0;
     int interactiveFlag;
@@ -578,463 +827,88 @@ readDbTape(tapeInfoPtr, rstTapeInfoPtr, query)
            code =
                PromptForTape(RESTOREDBOPCODE, tapeName,
                              rstTapeInfoPtr->dumpid, taskId, tapecount);
-           if (code)
-               ERROR_EXIT(code);
-       }
-       interactiveFlag = 1;
-       tapecount++;
-
-       code = butm_Mount(tapeInfoPtr, tapeName);
-       if (code) {
-           TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
-           goto getNewTape;
-       }
-
-       code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1);   /* will rewind the tape */
-       if (code) {
-           TapeLog(0, taskId, code, tapeInfoPtr->error,
-                   "Can't read tape label\n");
-           goto getNewTape;
-       }
-
-       /* Check for name of tape and matching dump id (if applicable). */
-       if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
-           || ((rstTapeInfoPtr->tapeSeq != 1)
-               && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
-           char expTape[BU_MAXTAPELEN + 32];
-           char gotTape[BU_MAXTAPELEN + 32];
-
-           TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
-           TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
-
-           TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
-                gotTape);
-           goto getNewTape;
-       }
-
-       if (rstTapeInfoPtr->tapeSeq == 1)       /* Remember this dumpId */
-           rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
-
-       break;
-
-      getNewTape:
-       unmountTape(taskId, tapeInfoPtr);
-    }                          /*w */
-
-
-    /* Initialize a tapeEntry for later inclusion into the database */
-    listEntryPtr =
-       (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
-    if (!listEntryPtr)
-       ERROR_EXIT(TC_NOMEMORY);
-    memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
-
-    /* Fill in tape entry so we can save it later */
-    strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
-    tapeEntryPtr->dump = oldTapeLabel.dumpid;
-    tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
-    tapeEntryPtr->written = oldTapeLabel.creationTime;
-    tapeEntryPtr->expires = oldTapeLabel.expirationDate;
-    tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
-    tapeEntryPtr->useCount = oldTapeLabel.useCount;
-    tapeEntryPtr->useKBytes = 0;
-    tapeEntryPtr->labelpos = 0;
-
-    /* Thread onto end of single-linked list */
-    if (listEntryHead) {
-       endList = listEntryHead;
-       while (endList->next)
-           endList = endList->next;
-       endList->next = listEntryPtr;
-    } else
-       listEntryHead = listEntryPtr;
-
-  error_exit:
-    return (code);
-}
-
-/* restoreDbFromTape
- *     restore the backup database from tape.
- */
-
-afs_int32
-restoreDbFromTape(taskId)
-     afs_uint32 taskId;
-{
-    afs_int32 code = 0;
-    afs_int32 i;
-    struct butm_tapeInfo tapeInfo;
-    struct rstTapeInfo rstTapeInfo;
-    struct budb_dumpEntry dumpEntry;
-
-    extern struct tapeConfig globalTapeConfig;
-    extern struct deviceSyncNode *deviceLatch;
-
-    setStatus(taskId, DRIVE_WAIT);
-    EnterDeviceQueue(deviceLatch);     /* lock tape device */
-    clearStatus(taskId, DRIVE_WAIT);
-
-    printf("\n\n");
-    TLog(taskId, "RestoreDb\n");
-
-    tapeInfo.structVersion = BUTM_MAJORVERSION;
-    code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
-    if (code) {
-       ErrorLog(0, taskId, code, tapeInfo.error,
-                "Can't initialize tape module\n");
-       ERROR_EXIT(code);
-    }
-
-    listEntryHead = NULL;
-
-    rstTapeInfo.taskId = taskId;
-    rstTapeInfo.tapeSeq = 1;
-    rstTapeInfo.dumpid = 0;
-
-    code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
-    if (code)
-       ERROR_EXIT(code);
-
-    code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
-    if (code)
-       ERROR_EXIT(code);
-
-  error_exit:
-    /* Now put this dump into the database */
-    /* Make a dump entry from first tape   */
-    listEntryPtr = listEntryHead;
-    if (listEntryPtr) {
-       makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
-       if (dumpEntry.id != 0) {
-           i = bcdb_CreateDump(&dumpEntry);
-           if (i) {
-               if (i == BUDB_DUMPIDEXISTS)
-                   fprintf(stderr,
-                           "Dump id %d not added to database - already exists\n",
-                           dumpEntry.id);
-               else
-                   TapeLog(0, taskId, i, 0,
-                           "Dump id %d not added to database\n",
-                           dumpEntry.id);
-           } else {
-               i = addTapesToDb(taskId);
-               if (!code)
-                   code = i;
-
-               i = bcdb_FinishDump(&dumpEntry);
-               if (!code)
-                   code = i;
-           }
-       }
-       freeTapeList();
-    }
-
-    unmountTape(taskId, &tapeInfo);
-    waitDbWatcher();
-
-    if (code == TC_ABORTEDBYREQUEST) {
-       TLog(taskId, "RestoreDb: Aborted by request\n");
-       clearStatus(taskId, ABORT_REQUEST);
-       setStatus(taskId, ABORT_DONE);
-    } else if (code) {
-       TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
-       setStatus(taskId, TASK_ERROR);
-    } else {
-       TLog(taskId, "RestoreDb: Finished\n");
-    }
-
-    LeaveDeviceQueue(deviceLatch);
-    setStatus(taskId, TASK_DONE);
-
-    return (code);
-}
-
-/* KeepAlive
- * 
- *      While dumping the database, keeps the connection alive.  
- *      Every 10 seconds, wake up and ask to read 0 bytes of the database.
- *      This resets the database's internal timer so that it does not 
- *      prematuraly quit (on asking for new tapes and such).
- *      
- *      Use the same udbHandle as writeDbDump so we go to the same server.
- */
-int
-KeepAlive()
-{
-    charListT charList;
-    afs_int32 code;
-    afs_int32 done;
-
-    extern struct udbHandleS udbHandle;
-
-    while (1) {
-#ifdef AFS_PTHREAD_ENV
-       sleep(5);
-#else
-       IOMGR_Sleep(5);
-#endif
-       charList.charListT_val = 0;
-       charList.charListT_len = 0;
-       code =
-           ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
-                                  UF_SINGLESERVER, 0, 0, &charList, &done);
-       if (code || done)
-           break;
-    }
-    return 0;
-}
-
-#define BIGCHUNK 102400
-
-/* writeDbDump
- * notes:
- *     this code assumes that the blocksize on reads is smaller than
- *     the blocksize on writes
- */
-
-static
-writeDbDump(tapeInfoPtr, taskId, expires, dumpid)
-     struct butm_tapeInfo *tapeInfoPtr;
-     afs_uint32 taskId;
-     Date expires;
-     afs_uint32 dumpid;
-{
-    afs_int32 blockSize;
-    afs_int32 writeBufNbytes = 0;
-    char *writeBlock = 0;
-    char *writeBuffer = 0;
-    char *writeBufPtr;
-    afs_int32 transferSize;
-
-    char *readBufPtr;
-    afs_int32 maxReadSize;
-
-    charListT charList;
-    afs_int32 done;
-    afs_int32 code;
-    afs_int32 chunksize = 0;
-    afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
-    int sequence;
-    int wroteLabel;
-    int firstcall;
-#ifdef AFS_PTHREAD_ENV
-    pthread_t alivePid;
-    pthread_attr_t tattr;
-    AFS_SIGSET_DECL;
-#else
-    PROCESS alivePid;
-#endif
-
-    extern struct tapeConfig globalTapeConfig;
-    extern struct udbHandleS udbHandle;
-
-    extern int KeepAlive();
-
-    blockSize = BUTM_BLKSIZE;
-    writeBlock = (char *)malloc(BUTM_BLOCKSIZE);
-    if (!writeBlock)
-       ERROR_EXIT(TC_NOMEMORY);
-
-    writeBuffer = writeBlock + sizeof(struct blockMark);
-    memset(writeBuffer, 0, BUTM_BLKSIZE);
-    maxReadSize = 1024;
-
-    /* 
-     * The margin of space to check for end of tape is set to the 
-     * amount of space used to write an end-of-tape multiplied by 2. 
-     * The amount of space is size of a 16K EODump marker, its EOF
-     * marker, and up to two EOF markers done on close (1 16K blocks +
-     * 3 EOF * markers). 
-     */
-    tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
-    tc_KEndMargin = tc_EndMargin / 1024;
-
-    /* have to write enclose the dump in file marks */
-    code = butm_WriteFileBegin(tapeInfoPtr);
-    if (code) {
-       ErrorLog(0, taskId, code, tapeInfoPtr->error,
-                "Can't write FileBegin on tape\n");
-       ERROR_EXIT(code);
-    }
-
-    writeBufPtr = &writeBuffer[0];
-    firstcall = 1;
-    sequence = 1;
-    charList.charListT_val = 0;
-    charList.charListT_len = 0;
-
-    while (1) {                        /*w */
-       /* When no data in buffer, read data from the budb_server */
-       if (charList.charListT_len == 0) {
-           /* get more data. let rx allocate space */
-           if (charList.charListT_val) {
-               free(charList.charListT_val);
-               charList.charListT_val = 0;
-           }
-
-           /* get the data */
-           code =
-               ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
-                                      UF_SINGLESERVER, firstcall,
-                                      maxReadSize, &charList, &done);
-           if (code) {
-               ErrorLog(0, taskId, code, 0, "Can't read database\n");
-               ERROR_EXIT(code);
-           }
-
-           /* If this if the first call to the budb server, create a thread
-            * that will keep the connection alive (during tape changes).
-            */
-           if (firstcall) {
-#ifdef AFS_PTHREAD_ENV
-               code = pthread_attr_init(&tattr);
-               if (code) {
-                   ErrorLog(0, taskId, code, 0,
-                            "Can't pthread_attr_init Keep-alive process\n");
-                   ERROR_EXIT(code);
-               }
-
-               code =
-                   pthread_attr_setdetachstate(&tattr,
-                                               PTHREAD_CREATE_DETACHED);
-               if (code) {
-                   ErrorLog(0, taskId, code, 0,
-                            "Can't pthread_attr_setdetachstate Keep-alive process\n");
-                   ERROR_EXIT(code);
-               }
-
-               AFS_SIGSET_CLEAR();
-               code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
-               AFS_SIGSET_RESTORE();
-#else
-               code =
-                   LWP_CreateProcess(KeepAlive, 16384, 1, (void *)NULL,
-                                     "Keep-alive process", &alivePid);
-#endif
-               /* XXX should we check code here ??? XXX */
-           }
-           firstcall = 0;
-
-           readBufPtr = charList.charListT_val;
-       }
-
-       if ((charList.charListT_len == 0) && done)
-           break;
-
-       /* compute how many bytes and transfer to the write Buffer */
-       transferSize =
-           (charList.charListT_len <
-            (blockSize -
-             writeBufNbytes)) ? charList.charListT_len : (blockSize -
-                                                          writeBufNbytes);
-
-       memcpy(writeBufPtr, readBufPtr, transferSize);
-       charList.charListT_len -= transferSize;
-       writeBufPtr += transferSize;
-       readBufPtr += transferSize;
-       writeBufNbytes += transferSize;
-
-       /* If filled the write buffer, then write it to tape */
-       if (writeBufNbytes == blockSize) {
-           code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
-           if (code) {
-               ErrorLog(0, taskId, code, tapeInfoPtr->error,
-                        "Can't write data on tape\n");
-               ERROR_EXIT(code);
-           }
-
-           memset(writeBuffer, 0, blockSize);
-           writeBufPtr = &writeBuffer[0];
-           writeBufNbytes = 0;
-
-           /* Every BIGCHUNK bytes check if aborted */
-           chunksize += blockSize;
-           if (chunksize > BIGCHUNK) {
-               chunksize = 0;
-               if (checkAbortByTaskId(taskId))
-                   ERROR_EXIT(TC_ABORTEDBYREQUEST);
-           }
-
-           /*
-            * check if tape is full - since we filled a blockSize worth of data
-            * assume that there is more data.
-            */
-           kRemaining = butm_remainingKSpace(tapeInfoPtr);
-           if (kRemaining < tc_KEndMargin) {
-               code = butm_WriteFileEnd(tapeInfoPtr);
-               if (code) {
-                   ErrorLog(0, taskId, code, tapeInfoPtr->error,
-                            "Can't write FileEnd on tape\n");
-                   ERROR_EXIT(code);
-               }
+           if (code)
+               ERROR_EXIT(code);
+       }
+       interactiveFlag = 1;
+       tapecount++;
 
-               code = butm_WriteEOT(tapeInfoPtr);
-               if (code) {
-                   ErrorLog(0, taskId, code, tapeInfoPtr->error,
-                            "Can't write end-of-dump on tape\n");
-                   ERROR_EXIT(code);
-               }
+       code = butm_Mount(tapeInfoPtr, tapeName);
+       if (code) {
+           TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
+           goto getNewTape;
+       }
 
-               /* Mark tape as having been written */
-               tapeEntryPtr->useKBytes =
-                   tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
-               tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
+       code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1);   /* will rewind the tape */
+       if (code) {
+           TapeLog(0, taskId, code, tapeInfoPtr->error,
+                   "Can't read tape label\n");
+           goto getNewTape;
+       }
 
-               unmountTape(taskId, tapeInfoPtr);
+       /* Check for name of tape and matching dump id (if applicable). */
+       if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
+           || ((rstTapeInfoPtr->tapeSeq != 1)
+               && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
+           char expTape[BU_MAXTAPELEN + 32];
+           char gotTape[BU_MAXTAPELEN + 32];
 
-               /* Get next tape and writes its label */
-               sequence++;
-               code =
-                   GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
-                             1, &wroteLabel);
-               if (code)
-                   ERROR_EXIT(code);
+           TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
+           TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
 
-               code = butm_WriteFileBegin(tapeInfoPtr);
-               if (code) {
-                   ErrorLog(0, taskId, code, tapeInfoPtr->error,
-                            "Can't write FileBegin on tape\n");
-                   ERROR_EXIT(code);
-               }
-           }
+           TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
+                gotTape);
+           goto getNewTape;
        }
+
+       if (rstTapeInfoPtr->tapeSeq == 1)       /* Remember this dumpId */
+           rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
+
+       break;
+
+      getNewTape:
+       unmountTape(taskId, tapeInfoPtr);
     }                          /*w */
 
-    /* no more data to be read - if necessary, flush out the last buffer */
-    if (writeBufNbytes > 0) {
-       code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
-       if (code) {
-           ErrorLog(1, taskId, code, tapeInfoPtr->error,
-                    "Can't write data on tape\n");
-           ERROR_EXIT(code);
-       }
-    }
 
-    code = butm_WriteFileEnd(tapeInfoPtr);
-    if (code) {
-       ErrorLog(0, taskId, code, tapeInfoPtr->error,
-                "Can't write FileEnd on tape\n");
-       ERROR_EXIT(code);
-    }
+    /* Initialize a tapeEntry for later inclusion into the database */
+    listEntryPtr =
+       (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
+    if (!listEntryPtr)
+       ERROR_EXIT(TC_NOMEMORY);
+    memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
 
-    /* Mark tape as having been written */
-    tapeEntryPtr->useKBytes =
-       tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
-    tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
+    /* Fill in tape entry so we can save it later */
+    strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
+    tapeEntryPtr->dump = oldTapeLabel.dumpid;
+    tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
+    tapeEntryPtr->written = oldTapeLabel.creationTime;
+    tapeEntryPtr->expires = oldTapeLabel.expirationDate;
+    tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
+    tapeEntryPtr->useCount = oldTapeLabel.useCount;
+    tapeEntryPtr->useKBytes = 0;
+    tapeEntryPtr->labelpos = 0;
 
-  error_exit:
-    /* Let the KeepAlive process stop on its own */
-    code =
-       ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
-                              UF_END_SINGLESERVER, 0);
+    /* Thread onto end of single-linked list */
+    if (listEntryHead) {
+       endList = listEntryHead;
+       while (endList->next)
+           endList = endList->next;
+       endList->next = listEntryPtr;
+    } else
+       listEntryHead = listEntryPtr;
 
-    if (writeBlock)
-       free(writeBlock);
-    if (charList.charListT_val)
-       free(charList.charListT_val);
+  error_exit:
     return (code);
 }
 
+static afs_int32 nbytes = 0;   /* # bytes left in buffer */
+static void
+initTapeBuffering(void)
+{
+    nbytes = 0;
+}
+
 
 /* restoreDbEntries
  *     restore all the items on the tape
@@ -1042,10 +916,9 @@ writeDbDump(tapeInfoPtr, taskId, expires, dumpid)
  *     tape positioned after tape label
  */
 
-static
-restoreDbEntries(tapeInfoPtr, rstTapeInfoPtr)
-     struct butm_tapeInfo *tapeInfoPtr;
-     struct rstTapeInfo *rstTapeInfoPtr;
+static int
+restoreDbEntries(struct butm_tapeInfo *tapeInfoPtr,
+                struct rstTapeInfo *rstTapeInfoPtr)
 {
     struct structDumpHeader netItemHeader, hostItemHeader;
     afs_int32 more = 1;
@@ -1134,14 +1007,148 @@ restoreDbEntries(tapeInfoPtr, rstTapeInfoPtr)
     return (code);
 }
 
+/* restoreDbFromTape
+ *     restore the backup database from tape.
+ */
+
+void *
+restoreDbFromTape(void *param)
+{
+    afs_uint32 taskId = (intptr_t) param;
+    afs_int32 code = 0;
+    afs_int32 i;
+    struct butm_tapeInfo tapeInfo;
+    struct rstTapeInfo rstTapeInfo;
+    struct budb_dumpEntry dumpEntry;
+
+    extern struct tapeConfig globalTapeConfig;
+    extern struct deviceSyncNode *deviceLatch;
+
+    afs_pthread_setname_self("Db restore");
+    setStatus(taskId, DRIVE_WAIT);
+    EnterDeviceQueue(deviceLatch);     /* lock tape device */
+    clearStatus(taskId, DRIVE_WAIT);
+
+    printf("\n\n");
+    TLog(taskId, "RestoreDb\n");
+
+    tapeInfo.structVersion = BUTM_MAJORVERSION;
+    code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
+    if (code) {
+       ErrorLog(0, taskId, code, tapeInfo.error,
+                "Can't initialize tape module\n");
+       ERROR_EXIT(code);
+    }
+
+    listEntryHead = NULL;
+
+    rstTapeInfo.taskId = taskId;
+    rstTapeInfo.tapeSeq = 1;
+    rstTapeInfo.dumpid = 0;
+
+    code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
+    if (code)
+       ERROR_EXIT(code);
+
+    code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
+    if (code)
+       ERROR_EXIT(code);
+
+  error_exit:
+    /* Now put this dump into the database */
+    /* Make a dump entry from first tape   */
+    listEntryPtr = listEntryHead;
+    if (listEntryPtr) {
+       makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
+       if (dumpEntry.id != 0) {
+           i = bcdb_CreateDump(&dumpEntry);
+           if (i) {
+               if (i == BUDB_DUMPIDEXISTS)
+                   fprintf(stderr,
+                           "Dump id %d not added to database - already exists\n",
+                           dumpEntry.id);
+               else
+                   TapeLog(0, taskId, i, 0,
+                           "Dump id %d not added to database\n",
+                           dumpEntry.id);
+           } else {
+               i = addTapesToDb(taskId);
+               if (!code)
+                   code = i;
+
+               i = bcdb_FinishDump(&dumpEntry);
+               if (!code)
+                   code = i;
+           }
+       }
+       freeTapeList();
+    }
+
+    unmountTape(taskId, &tapeInfo);
+    waitDbWatcher();
+
+    if (code == TC_ABORTEDBYREQUEST) {
+       TLog(taskId, "RestoreDb: Aborted by request\n");
+       clearStatus(taskId, ABORT_REQUEST);
+       setStatus(taskId, ABORT_DONE);
+    } else if (code) {
+       TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
+       setStatus(taskId, TASK_ERROR);
+    } else {
+       TLog(taskId, "RestoreDb: Finished\n");
+    }
+
+    LeaveDeviceQueue(deviceLatch);
+    setStatus(taskId, TASK_DONE);
+
+    return (void *)(intptr_t)(code);
+}
+
+/* KeepAlive
+ *
+ *      While dumping the database, keeps the connection alive.
+ *      Every 10 seconds, wake up and ask to read 0 bytes of the database.
+ *      This resets the database's internal timer so that it does not
+ *      prematuraly quit (on asking for new tapes and such).
+ *
+ *      Use the same udbHandle as writeDbDump so we go to the same server.
+ */
+void *
+KeepAlive(void *unused)
+{
+    charListT charList;
+    afs_int32 code;
+    afs_int32 done;
+
+    extern struct udbHandleS udbHandle;
+
+    afs_pthread_setname_self("Keep-alive");
+    while (1) {
+#ifdef AFS_PTHREAD_ENV
+       sleep(5);
+#else
+       IOMGR_Sleep(5);
+#endif
+       charList.charListT_val = 0;
+       charList.charListT_len = 0;
+       code =
+           ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
+                                  UF_SINGLESERVER, 0, 0, &charList, &done);
+       if (code || done)
+           break;
+    }
+    return 0;
+}
+
+
 /* restoreDbHeader
  *     restore special items in the header
  */
 
-restoreDbHeader(tapeInfo, rstTapeInfoPtr, nextHeader)
-     struct butm_tapeInfo *tapeInfo;
-     struct rstTapeInfo *rstTapeInfoPtr;
-     struct structDumpHeader *nextHeader;
+int
+restoreDbHeader(struct butm_tapeInfo *tapeInfo,
+               struct rstTapeInfo *rstTapeInfoPtr,
+               struct structDumpHeader *nextHeader)
 {
     struct structDumpHeader netItemHeader;
     struct DbHeader netDbHeader, hostDbHeader;
@@ -1160,7 +1167,7 @@ restoreDbHeader(tapeInfo, rstTapeInfoPtr, nextHeader)
 
     /* Add the database header to the database */
     code =
-       ubik_Call(BUDB_RestoreDbHeader, udbHandle.uh_client, 0,
+       ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
                  &hostDbHeader);
     if (code) {
        ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
@@ -1189,28 +1196,25 @@ restoreDbHeader(tapeInfo, rstTapeInfoPtr, nextHeader)
  *     nextHeader - ptr to structure for return value
  * exit:
  *     nextHeader - next structure header from tape
- * notes: 
+ * notes:
  *     upon entry, the dump structure header has been read confirming that
  *     a database dump tree exists on the tape
  */
 
-restoreDbDump(tapeInfo, rstTapeInfoPtr, nextHeader)
-     struct butm_tapeInfo *tapeInfo;
-     struct rstTapeInfo *rstTapeInfoPtr;
-     struct structDumpHeader *nextHeader;
+int
+restoreDbDump(struct butm_tapeInfo *tapeInfo,
+             struct rstTapeInfo *rstTapeInfoPtr,
+             struct structDumpHeader *nextHeader)
 {
     struct budb_dumpEntry netDumpEntry, hostDumpEntry;
     struct budb_tapeEntry netTapeEntry, hostTapeEntry;
     struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
     struct structDumpHeader netItemHeader;
-    afs_int32 taskId;
     int restoreThisDump = 1;
     afs_int32 code = 0;
 
     extern struct udbHandleS udbHandle;
 
-    taskId = rstTapeInfoPtr->taskId;
-
     /* read dump entry */
     memset(&netDumpEntry, 0, sizeof(netDumpEntry));
     code =
@@ -1339,10 +1343,7 @@ restoreDbDump(tapeInfo, rstTapeInfoPtr, nextHeader)
  */
 
 afs_int32
-saveTextFile(taskId, textType, fileName)
-     afs_int32 taskId;
-     afs_int32 textType;
-     char *fileName;
+saveTextFile(afs_int32 taskId, afs_int32 textType, char *fileName)
 {
     udbClientTextP ctPtr = 0;
     afs_int32 code = 0;
@@ -1396,10 +1397,10 @@ saveTextFile(taskId, textType, fileName)
  *     nextHeader - struct header for next item on the tape
  */
 
-restoreText(tapeInfo, rstTapeInfoPtr, nextHeader)
-     struct butm_tapeInfo *tapeInfo;
-     struct rstTapeInfo *rstTapeInfoPtr;
-     struct structDumpHeader *nextHeader;
+int
+restoreText(struct butm_tapeInfo *tapeInfo,
+           struct rstTapeInfo *rstTapeInfoPtr,
+           struct structDumpHeader *nextHeader)
 {
     char filename[64];
     afs_int32 nbytes;
@@ -1440,11 +1441,7 @@ restoreText(tapeInfo, rstTapeInfoPtr, nextHeader)
 
     /* open the text file */
     sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
-#if defined (HAVE_MKSTEMP)
     fid = mkstemp(filename);
-#else
-    fid = open(mktemp(filename), O_RDWR | O_CREAT | O_EXCL, 0600);
-#endif
     if (fid < 0) {
        ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
                 "Can't open temporary text file: %s\n", filename);
@@ -1514,17 +1511,10 @@ restoreText(tapeInfo, rstTapeInfoPtr, nextHeader)
 
 static char *tapeReadBuffer = 0;       /* input buffer */
 static char *tapeReadBufferPtr = 0;    /* position in buffer */
-static afs_int32 nbytes = 0;   /* # bytes left in buffer */
-
-static
-initTapeBuffering()
-{
-    nbytes = 0;
-}
 
 /* getTapeData
  *     Read information from tape, and place the requested number of bytes
- *     in the buffer supplied 
+ *     in the buffer supplied
  * entry:
  *     tapeInfo
  *     rstTapeInfoPtr - Info about the dump being restored.
@@ -1534,15 +1524,14 @@ initTapeBuffering()
  *     fn retn - 0, ok, n, error
  */
 
-getTapeData(tapeInfoPtr, rstTapeInfoPtr, buffer, requestedBytes)
-     struct butm_tapeInfo *tapeInfoPtr;
-     struct rstTapeInfo *rstTapeInfoPtr;
-     char *buffer;
-     afs_int32 requestedBytes;
+int
+getTapeData(struct butm_tapeInfo *tapeInfoPtr,
+           struct rstTapeInfo *rstTapeInfoPtr,
+           void *out, afs_int32 requestedBytes)
 {
-    afs_int32 taskId, transferBytes, new;
+    char *buffer = (char *) out;
+    afs_int32 taskId, transferBytes;
     afs_int32 code = 0;
-    afs_uint32 dumpid;
 
     taskId = rstTapeInfoPtr->taskId;