Build and use roken's mkstemp
[openafs.git] / src / butc / tcudbprocs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
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
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <afs/procmgmt.h>
14 #include <roken.h>
15
16 #ifdef IGNORE_SOME_GCC_WARNINGS
17 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
18 #endif
19
20 #include <sys/types.h>
21 #ifdef HAVE_STDINT_H
22 # include <stdint.h>
23 #endif
24 #ifdef AFS_NT40_ENV
25 #include <winsock2.h>
26 #include <io.h>
27 #else
28 #include <sys/time.h>
29 #include <sys/file.h>
30 #include <netinet/in.h>
31 #include <netdb.h>
32 #endif
33 #include <errno.h>
34 #include <rx/xdr.h>
35 #include <rx/rx.h>
36 #include <afs/afsint.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <afs/procmgmt.h>
40 #include <afs/afs_assert.h>
41 #include <afs/prs_fs.h>
42 #include <fcntl.h>
43 #include <afs/nfs.h>
44 #include <lwp.h>
45 #include <lock.h>
46 #include <afs/cellconfig.h>
47 #include <afs/keys.h>
48 #include <ubik.h>
49 #include <afs/acl.h>
50 #include <afs/volser.h>
51 #include <afs/vlserver.h>
52 #include <afs/tcdata.h>
53 #include <afs/budb.h>
54 #include <afs/budb_client.h>
55 #include <afs/bubasics.h>
56 #include <afs/bucoord_prototypes.h>
57 #include <afs/butm_prototypes.h>
58 #include <afs/budb_prototypes.h>
59 #include <afs/afsutil.h>
60 #include "butc_internal.h"
61 #include "error_macros.h"
62
63 /* GLOBAL CONFIGURATION PARAMETERS */
64 #define BIGCHUNK 102400
65
66 extern int dump_namecheck;
67 extern int autoQuery;
68
69 struct rstTapeInfo {
70     afs_int32 taskId;
71     afs_int32 tapeSeq;
72     afs_uint32 dumpid;
73 };
74
75 static void initTapeBuffering(void);
76 static int writeDbDump(struct butm_tapeInfo *, afs_uint32, Date, afs_uint32);
77 static int restoreDbEntries(struct butm_tapeInfo *, struct rstTapeInfo *);
78
79 int getTapeData(struct butm_tapeInfo *, struct rstTapeInfo *, void *,
80                 afs_int32);
81 int restoreDbHeader(struct butm_tapeInfo *, struct rstTapeInfo *,
82                     struct structDumpHeader *);
83 int restoreDbDump(struct butm_tapeInfo *, struct rstTapeInfo *,
84                   struct structDumpHeader *);
85 int restoreText(struct butm_tapeInfo *, struct rstTapeInfo *,
86                 struct structDumpHeader *);
87
88
89
90 void * KeepAlive(void *);
91 /* CreateDBDump
92  *      create a dump entry for a saved database
93  */
94
95 afs_int32
96 CreateDBDump(struct budb_dumpEntry *dumpEntryPtr)
97 {
98     afs_int32 code = 0;
99
100     memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
101
102     strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
103     strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
104     strcat(dumpEntryPtr->tapes.format, ".%d");
105     strcpy(dumpEntryPtr->volumeSetName, "");
106     strcpy(dumpEntryPtr->dumpPath, "");
107     dumpEntryPtr->created = 0;  /* let database assign it */
108     dumpEntryPtr->incTime = 0;
109     dumpEntryPtr->nVolumes = 0;
110     dumpEntryPtr->initialDumpID = 0;
111     dumpEntryPtr->parent = 0;
112     dumpEntryPtr->level = 0;
113     dumpEntryPtr->tapes.maxTapes = 0;
114     dumpEntryPtr->tapes.b = 1;
115
116     /* now call the database to create the entry */
117     code = bcdb_CreateDump(dumpEntryPtr);
118     return (code);
119 }
120
121 struct tapeEntryList {
122     struct tapeEntryList *next;
123     afs_uint32 oldDumpId;
124     struct budb_tapeEntry tapeEnt;
125 };
126 struct tapeEntryList *listEntryHead;
127 struct tapeEntryList *listEntryPtr;
128 #define tapeEntryPtr (&listEntryPtr->tapeEnt)
129 struct budb_dumpEntry lastDump; /* the last dump of this volset */
130
131 /* GetDBTape
132  *      Load a DB tape, read and over write its label.
133  *      Leave the tape mounted.
134  */
135 afs_int32
136 GetDBTape(afs_int32 taskId, Date expires, struct butm_tapeInfo *tapeInfoPtr,
137           afs_uint32 dumpid, afs_int32 sequence, int queryFlag,
138           int *wroteLabel)
139 {
140     afs_int32 code = 0;
141     int interactiveFlag;
142     char tapeName[BU_MAXTAPELEN];
143     char strlevel[5];
144     struct timeval tp;
145     struct timezone tzp;
146     afs_int32 curTime;
147     int tapecount = 1;
148
149     struct butm_tapeLabel oldTapeLabel, newLabel;
150     struct tapeEntryList *endList;
151
152     /* construct the name of the tape */
153     sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);
154
155     interactiveFlag = queryFlag;
156     *wroteLabel = 0;
157
158     while (!*wroteLabel) {      /*w */
159         if (interactiveFlag) {  /* need a tape to write */
160             code =
161                 PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
162                               tapecount);
163             if (code)
164                 ERROR_EXIT(code);
165         }
166         interactiveFlag = 1;
167         tapecount++;
168
169         code = butm_Mount(tapeInfoPtr, tapeName);
170         if (code) {
171             TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
172             goto getNewTape;
173         }
174
175         memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
176         code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1);   /* rewind tape */
177         if (code) {
178             oldTapeLabel.useCount = 0;  /* no label exists */
179             oldTapeLabel.structVersion = 0;
180             strcpy(oldTapeLabel.pName, "");
181         } else {
182             /* If tape has a name, it must be null or database tape name */
183             if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
184                 && !databaseTape(oldTapeLabel.AFSName)) {
185                 char gotName[BU_MAXTAPELEN + 32];
186
187                 LABELNAME(gotName, &oldTapeLabel);
188                 TLog(taskId,
189                      "This tape %s must be a database tape or NULL tape\n",
190                      gotName);
191
192               getNewTape:
193                 unmountTape(taskId, tapeInfoPtr);
194                 continue;
195             }
196
197             /* Do not overwrite a tape that belongs to this dump */
198             if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
199                 ErrorLog(0, taskId, 0, 0,
200                          "Can't overwrite tape containing the dump in progress\n");
201                 goto getNewTape;
202             }
203
204             /* On first tape, the savedb has not started yet, so the database is not locked
205              * and we can therefore, access information from it. This is easier to do because
206              * database dumps don't have appended dumps (nor appended).
207              */
208             if (sequence == 1) {
209                 afs_uint32 dmp;
210                 struct budb_dumpEntry de, de2;
211
212                 /* Verify the tape has not expired
213                  * Early database dumps don't have a dumpid
214                  */
215                 if (!tapeExpired(&oldTapeLabel)) {
216                     TLog(taskId, "This tape has not expired\n");
217                     goto getNewTape;
218                 }
219
220                 /* Since the dumpset on this tape will be deleted from database, check if
221                  * any of the dumps in this dumpset are most-recent-dumps.
222                  */
223                 for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
224                     if (dmp == lastDump.id) {
225                         memcpy(&de, &lastDump, sizeof(de));
226                         memcpy(&de2, &lastDump, sizeof(de2));
227                     } else {
228                         code = bcdb_FindDumpByID(dmp, &de);
229                         if (code)
230                             break;
231                         sprintf(strlevel, "%d", de.level);
232                         code =
233                             bcdb_FindLatestDump(de.volumeSetName, strlevel,
234                                                 &de2);
235                         if (code)
236                             continue;
237                     }
238
239                     if (de.id == de2.id) {
240                         if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
241                             ErrorLog(0, taskId, 0, 0,
242                                      "Warning: Overwriting most recent dump %s (DumpID %u)\n",
243                                      de.name, de.id);
244                         } else {
245                             ErrorLog(0, taskId, 0, 0,
246                                      "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
247                                      de.volumeSetName, de.name, de.id);
248                         }
249                     }
250                 }
251             }
252
253             /* Otherwise, the savedb is in progress and we can't
254              * access the database (it's locked). So we rely on the
255              * information available (and not the backup database).
256              */
257             else {
258                 /* Check the tape's expiration date. Use the expiration on the label */
259                 gettimeofday(&tp, &tzp);
260                 curTime = tp.tv_sec;
261                 if (curTime < oldTapeLabel.expirationDate) {
262                     TLog(taskId, "This tape has not expired\n");
263                     goto getNewTape;
264                 }
265
266                 /* Check if this previous-dump of the dump-in-progress is on this tape */
267                 if (oldTapeLabel.dumpid
268                     && (oldTapeLabel.dumpid == lastDump.id)) {
269                     ErrorLog(0, taskId, 0, 0,
270                              "Warning: Overwriting most recent dump %s (DumpID %u)\n",
271                              lastDump.name, lastDump.id);
272                 }
273
274             }
275         }
276
277         GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
278         newLabel.expirationDate = expires;
279         newLabel.useCount = oldTapeLabel.useCount + 1;
280         newLabel.dumpid = dumpid;
281         newLabel.size = tapeInfoPtr->tapeSize;
282
283         code = butm_Create(tapeInfoPtr, &newLabel, 1);  /* rewind tape */
284         if (code) {
285             TapeLog(0, taskId, code, tapeInfoPtr->error,
286                     "Can't label tape\n");
287             goto getNewTape;
288         }
289
290         *wroteLabel = 1;
291
292         /* Initialize a tapeEntry for later inclusion into the database */
293         listEntryPtr =
294             (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
295         if (!listEntryPtr)
296             ERROR_EXIT(TC_NOMEMORY);
297         memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
298
299         /* Remember dumpid so we can delete it later */
300         if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
301             && oldTapeLabel.dumpid)
302             listEntryPtr->oldDumpId = oldTapeLabel.dumpid;
303
304         /* Fill in tape entry so we can save it later */
305         strcpy(tapeEntryPtr->name, TNAME(&newLabel));
306         tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
307         tapeEntryPtr->written = newLabel.creationTime;
308         tapeEntryPtr->expires = expires;
309         tapeEntryPtr->seq = sequence;
310         tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
311         tapeEntryPtr->dump = dumpid;
312         tapeEntryPtr->useKBytes = 0;
313         tapeEntryPtr->labelpos = 0;
314
315         /* Thread onto end of single-linked list */
316         if (listEntryHead) {
317             endList = listEntryHead;
318             while (endList->next)
319                 endList = endList->next;
320             endList->next = listEntryPtr;
321         } else
322             listEntryHead = listEntryPtr;
323     }                           /*w */
324
325   error_exit:
326     return (code);
327 }
328
329 /* freeTapeList
330  *       With the list of tapes, free the structures.
331  */
332
333 afs_int32
334 freeTapeList(void)
335 {
336     struct tapeEntryList *next;
337
338     listEntryPtr = listEntryHead;
339     while (listEntryPtr) {
340         next = listEntryPtr->next;
341         free(listEntryPtr);
342         listEntryPtr = next;
343     }
344
345     listEntryHead = NULL;
346     return (0);
347 }
348
349 /* addTapesToDb
350  *       With the list of tapes, add them to the database.
351  *       Also delete any olddumpids that are around.
352  */
353
354 afs_int32
355 addTapesToDb(afs_int32 taskId)
356 {
357     afs_int32 code = 0;
358     afs_int32 i, new;
359     struct tapeEntryList *next;
360
361     listEntryPtr = listEntryHead;
362     while (listEntryPtr) {
363         next = listEntryPtr->next;
364
365         /* Remove the old database entry */
366         if (listEntryPtr->oldDumpId) {
367             i = bcdb_deleteDump(listEntryPtr->oldDumpId, 0, 0, 0);
368             if (i && (i != BUDB_NOENT)) {
369                 ErrorLog(0, taskId, i, 0,
370                          "Unable to delete old DB entry %u.\n",
371                          listEntryPtr->oldDumpId);
372             }
373         }
374
375         /* Add the tape to the database */
376         code = bcdb_UseTape(tapeEntryPtr, &new);
377         if (code) {
378             ErrorLog(0, taskId, code, 0, "Can't add tape to database: %s\n",
379                      tapeEntryPtr->name);
380             ERROR_EXIT(code);
381         }
382
383         code = bcdb_FinishTape(tapeEntryPtr);
384         if (code) {
385             ErrorLog(0, taskId, code, 0, "Can't finish tape: %s\n",
386                      tapeEntryPtr->name);
387             ERROR_EXIT(code);
388         }
389
390         listEntryPtr = next;
391     }
392
393   error_exit:
394     return (code);
395 }
396
397 /* writeDbDump
398  * notes:
399  *      this code assumes that the blocksize on reads is smaller than
400  *      the blocksize on writes
401  */
402
403 static int
404 writeDbDump(struct butm_tapeInfo *tapeInfoPtr, afs_uint32 taskId,
405             Date expires, afs_uint32 dumpid)
406 {
407     afs_int32 blockSize;
408     afs_int32 writeBufNbytes = 0;
409     char *writeBlock = 0;
410     char *writeBuffer = 0;
411     char *writeBufPtr;
412     afs_int32 transferSize;
413
414     char *readBufPtr = NULL;
415     afs_int32 maxReadSize;
416
417     charListT charList;
418     afs_int32 done;
419     afs_int32 code;
420     afs_int32 chunksize = 0;
421     afs_int32 tc_EndMargin, tc_KEndMargin, kRemaining;
422     int sequence;
423     int wroteLabel;
424     int firstcall;
425 #ifdef AFS_PTHREAD_ENV
426     pthread_t alivePid;
427     pthread_attr_t tattr;
428     AFS_SIGSET_DECL;
429 #else
430     PROCESS alivePid;
431 #endif
432
433     extern struct tapeConfig globalTapeConfig;
434     extern struct udbHandleS udbHandle;
435
436     blockSize = BUTM_BLKSIZE;
437     writeBlock = (char *)malloc(BUTM_BLOCKSIZE);
438     if (!writeBlock)
439         ERROR_EXIT(TC_NOMEMORY);
440
441     writeBuffer = writeBlock + sizeof(struct blockMark);
442     memset(writeBuffer, 0, BUTM_BLKSIZE);
443     maxReadSize = 1024;
444
445     /*
446      * The margin of space to check for end of tape is set to the
447      * amount of space used to write an end-of-tape multiplied by 2.
448      * The amount of space is size of a 16K EODump marker, its EOF
449      * marker, and up to two EOF markers done on close (1 16K blocks +
450      * 3 EOF * markers).
451      */
452     tc_EndMargin = (16384 + 3 * globalTapeConfig.fileMarkSize) * 2;
453     tc_KEndMargin = tc_EndMargin / 1024;
454
455     /* have to write enclose the dump in file marks */
456     code = butm_WriteFileBegin(tapeInfoPtr);
457     if (code) {
458         ErrorLog(0, taskId, code, tapeInfoPtr->error,
459                  "Can't write FileBegin on tape\n");
460         ERROR_EXIT(code);
461     }
462
463     writeBufPtr = &writeBuffer[0];
464     firstcall = 1;
465     sequence = 1;
466     charList.charListT_val = 0;
467     charList.charListT_len = 0;
468
469     while (1) {                 /*w */
470         /* When no data in buffer, read data from the budb_server */
471         if (charList.charListT_len == 0) {
472             /* get more data. let rx allocate space */
473             if (charList.charListT_val) {
474                 free(charList.charListT_val);
475                 charList.charListT_val = 0;
476             }
477
478             /* get the data */
479             code =
480                 ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
481                                        UF_SINGLESERVER, firstcall,
482                                        maxReadSize, &charList, &done);
483             if (code) {
484                 ErrorLog(0, taskId, code, 0, "Can't read database\n");
485                 ERROR_EXIT(code);
486             }
487
488             /* If this if the first call to the budb server, create a thread
489              * that will keep the connection alive (during tape changes).
490              */
491             if (firstcall) {
492 #ifdef AFS_PTHREAD_ENV
493                 code = pthread_attr_init(&tattr);
494                 if (code) {
495                     ErrorLog(0, taskId, code, 0,
496                              "Can't pthread_attr_init Keep-alive process\n");
497                     ERROR_EXIT(code);
498                 }
499
500                 code =
501                     pthread_attr_setdetachstate(&tattr,
502                                                 PTHREAD_CREATE_DETACHED);
503                 if (code) {
504                     ErrorLog(0, taskId, code, 0,
505                              "Can't pthread_attr_setdetachstate Keep-alive process\n");
506                     ERROR_EXIT(code);
507                 }
508
509                 AFS_SIGSET_CLEAR();
510                 code = pthread_create(&alivePid, &tattr, KeepAlive, 0);
511                 AFS_SIGSET_RESTORE();
512 #else
513                 code =
514                     LWP_CreateProcess(KeepAlive, 16384, 1, (void *)NULL,
515                                       "Keep-alive process", &alivePid);
516 #endif
517                 /* XXX should we check code here ??? XXX */
518             }
519             firstcall = 0;
520
521             readBufPtr = charList.charListT_val;
522         }
523
524         if ((charList.charListT_len == 0) && done)
525             break;
526
527         /* compute how many bytes and transfer to the write Buffer */
528         transferSize =
529             (charList.charListT_len <
530              (blockSize -
531               writeBufNbytes)) ? charList.charListT_len : (blockSize -
532                                                            writeBufNbytes);
533
534         memcpy(writeBufPtr, readBufPtr, transferSize);
535         charList.charListT_len -= transferSize;
536         writeBufPtr += transferSize;
537         readBufPtr += transferSize;
538         writeBufNbytes += transferSize;
539
540         /* If filled the write buffer, then write it to tape */
541         if (writeBufNbytes == blockSize) {
542             code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
543             if (code) {
544                 ErrorLog(0, taskId, code, tapeInfoPtr->error,
545                          "Can't write data on tape\n");
546                 ERROR_EXIT(code);
547             }
548
549             memset(writeBuffer, 0, blockSize);
550             writeBufPtr = &writeBuffer[0];
551             writeBufNbytes = 0;
552
553             /* Every BIGCHUNK bytes check if aborted */
554             chunksize += blockSize;
555             if (chunksize > BIGCHUNK) {
556                 chunksize = 0;
557                 if (checkAbortByTaskId(taskId))
558                     ERROR_EXIT(TC_ABORTEDBYREQUEST);
559             }
560
561             /*
562              * check if tape is full - since we filled a blockSize worth of data
563              * assume that there is more data.
564              */
565             kRemaining = butm_remainingKSpace(tapeInfoPtr);
566             if (kRemaining < tc_KEndMargin) {
567                 code = butm_WriteFileEnd(tapeInfoPtr);
568                 if (code) {
569                     ErrorLog(0, taskId, code, tapeInfoPtr->error,
570                              "Can't write FileEnd on tape\n");
571                     ERROR_EXIT(code);
572                 }
573
574                 code = butm_WriteEOT(tapeInfoPtr);
575                 if (code) {
576                     ErrorLog(0, taskId, code, tapeInfoPtr->error,
577                              "Can't write end-of-dump on tape\n");
578                     ERROR_EXIT(code);
579                 }
580
581                 /* Mark tape as having been written */
582                 tapeEntryPtr->useKBytes =
583                     tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
584                 tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
585
586                 unmountTape(taskId, tapeInfoPtr);
587
588                 /* Get next tape and writes its label */
589                 sequence++;
590                 code =
591                     GetDBTape(taskId, expires, tapeInfoPtr, dumpid, sequence,
592                               1, &wroteLabel);
593                 if (code)
594                     ERROR_EXIT(code);
595
596                 code = butm_WriteFileBegin(tapeInfoPtr);
597                 if (code) {
598                     ErrorLog(0, taskId, code, tapeInfoPtr->error,
599                              "Can't write FileBegin on tape\n");
600                     ERROR_EXIT(code);
601                 }
602             }
603         }
604     }                           /*w */
605
606     /* no more data to be read - if necessary, flush out the last buffer */
607     if (writeBufNbytes > 0) {
608         code = butm_WriteFileData(tapeInfoPtr, writeBuffer, 1, blockSize);
609         if (code) {
610             ErrorLog(1, taskId, code, tapeInfoPtr->error,
611                      "Can't write data on tape\n");
612             ERROR_EXIT(code);
613         }
614     }
615
616     code = butm_WriteFileEnd(tapeInfoPtr);
617     if (code) {
618         ErrorLog(0, taskId, code, tapeInfoPtr->error,
619                  "Can't write FileEnd on tape\n");
620         ERROR_EXIT(code);
621     }
622
623     /* Mark tape as having been written */
624     tapeEntryPtr->useKBytes =
625         tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
626     tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
627
628   error_exit:
629     /* Let the KeepAlive process stop on its own */
630     code =
631         ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
632                                UF_END_SINGLESERVER, 0);
633
634     if (writeBlock)
635         free(writeBlock);
636     if (charList.charListT_val)
637         free(charList.charListT_val);
638     return (code);
639 }
640
641 /* saveDbToTape
642  *      dump backup database to tape
643  */
644
645 void *
646 saveDbToTape(void *param)
647 {
648     struct saveDbIf *saveDbIfPtr = (struct saveDbIf *)param;
649     afs_int32 code = 0;
650     afs_int32 i;
651     int wroteLabel;
652     afs_uint32 taskId;
653     Date expires;
654
655     struct butm_tapeInfo tapeInfo;
656     struct budb_dumpEntry dumpEntry;
657
658     extern struct deviceSyncNode *deviceLatch;
659     extern struct tapeConfig globalTapeConfig;
660
661     expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
662     taskId = saveDbIfPtr->taskId;
663
664     setStatus(taskId, DRIVE_WAIT);
665     EnterDeviceQueue(deviceLatch);      /* lock tape device */
666     clearStatus(taskId, DRIVE_WAIT);
667
668     printf("\n\n");
669     TLog(taskId, "SaveDb\n");
670
671     tapeInfo.structVersion = BUTM_MAJORVERSION;
672     code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
673     if (code) {
674         ErrorLog(0, taskId, code, tapeInfo.error,
675                  "Can't initialize tape module\n");
676         ERROR_EXIT(code);
677     }
678
679     /* Determine what the last database dump was */
680     memset(&lastDump, 0, sizeof(lastDump));
681     code = bcdb_FindLatestDump("", "", &lastDump);
682     if (code) {
683         if (code != BUDB_NODUMPNAME) {
684             ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
685             ERROR_EXIT(code);
686         }
687         memset(&lastDump, 0, sizeof(lastDump));
688     }
689
690     code = CreateDBDump(&dumpEntry);    /* Create a dump for this tape */
691     if (code) {
692         ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
693         ERROR_EXIT(code);
694     }
695
696
697     listEntryHead = NULL;
698
699     /* Get the tape and write a new label to it */
700     code =
701         GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
702                   &wroteLabel);
703
704     /*
705      * If did not write the label, remove created dump
706      * Else if wrote the label, remove old dump from db so it's not saved.
707      */
708     if (!wroteLabel) {
709         i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
710         dumpEntry.id = 0;
711         if (i && (i != BUDB_NOENT))
712             ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
713                      dumpEntry.id);
714     } else if (listEntryHead->oldDumpId) {
715         i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
716         listEntryHead->oldDumpId = 0;
717         if (i && (i != BUDB_NOENT)) {
718             ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
719                      listEntryHead->oldDumpId);
720             ERROR_EXIT(i);
721         }
722     }
723     if (code)
724         ERROR_EXIT(code);
725
726     TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");
727
728     /* we have a writable tape */
729     code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
730     if (code)
731         ERROR_EXIT(code);
732
733     /* Now delete the entries between time 0 and archive-time */
734     if (saveDbIfPtr->archiveTime)
735         code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);
736
737   error_exit:
738     unmountTape(taskId, &tapeInfo);
739
740     /* Add this dump's tapes to the database and mark it finished */
741     if (dumpEntry.id) {
742         i = addTapesToDb(taskId);
743         if (!code)
744             code = i;
745
746         i = bcdb_FinishDump(&dumpEntry);
747         if (!code)
748             code = i;
749     }
750     freeTapeList();
751
752     if (code == TC_ABORTEDBYREQUEST) {
753         TLog(taskId, "SaveDb: Aborted by request\n");
754         clearStatus(taskId, ABORT_REQUEST);
755         setStatus(taskId, ABORT_DONE);
756     } else if (code) {
757         TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
758         setStatus(taskId, TASK_ERROR);
759     } else {
760         TLog(taskId, "SaveDb: Finished\n");
761     }
762     setStatus(taskId, TASK_DONE);
763
764     free(saveDbIfPtr);
765     LeaveDeviceQueue(deviceLatch);
766     return (void *)(intptr_t)(code);
767 }
768
769
770 /* makeDbDumpEntry()
771  *      Make a database dump entry given a tape label.
772  */
773
774 afs_int32
775 makeDbDumpEntry(struct budb_tapeEntry *tapeEntPtr,
776                 struct budb_dumpEntry *dumpEntryPtr)
777 {
778     memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
779
780     dumpEntryPtr->id = tapeEntPtr->dump;
781     dumpEntryPtr->initialDumpID = 0;
782     dumpEntryPtr->parent = 0;
783     dumpEntryPtr->level = 0;
784     dumpEntryPtr->flags = 0;
785
786     strcpy(dumpEntryPtr->volumeSetName, "");
787     strcpy(dumpEntryPtr->dumpPath, "");
788     strcpy(dumpEntryPtr->name, DUMP_TAPE_NAME);
789
790     dumpEntryPtr->created = tapeEntPtr->dump;
791     dumpEntryPtr->incTime = 0;
792     dumpEntryPtr->nVolumes = 0;
793
794     strcpy(dumpEntryPtr->tapes.format, DUMP_TAPE_NAME);
795     strcat(dumpEntryPtr->tapes.format, ".%d");
796     dumpEntryPtr->tapes.b = tapeEntPtr->seq;
797     dumpEntryPtr->tapes.maxTapes = 0;
798     return 0;
799 }
800
801 /* readDbTape
802  *      prompt for a specific database tape
803  */
804
805 afs_int32
806 readDbTape(struct butm_tapeInfo *tapeInfoPtr,
807            struct rstTapeInfo *rstTapeInfoPtr, int query)
808 {
809     afs_int32 code = 0;
810     int interactiveFlag;
811     afs_int32 taskId;
812     struct butm_tapeLabel oldTapeLabel;
813     char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
814     struct tapeEntryList *endList;
815     int tapecount = 1;
816     struct budb_dumpEntry de;
817     struct budb_tapeEntry te;
818
819     taskId = rstTapeInfoPtr->taskId;
820     interactiveFlag = query;
821
822     /* construct the name of the tape */
823     sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
824     strcpy(tapeName, AFStapeName);
825
826     /* Will prompt for the latest saved database tape, but will accept any one */
827     if (rstTapeInfoPtr->tapeSeq == 1) {
828         code = bcdb_FindLatestDump("", "", &de);
829         if (!code)
830             rstTapeInfoPtr->dumpid = de.id;
831     }
832     if (rstTapeInfoPtr->dumpid) {
833         code =
834             bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
835                              &te);
836         if (!code)
837             strcpy(tapeName, te.name);
838     }
839     code = 0;
840
841     while (1) {                 /*w */
842         if (interactiveFlag) {  /* need a tape to read */
843             code =
844                 PromptForTape(RESTOREDBOPCODE, tapeName,
845                               rstTapeInfoPtr->dumpid, taskId, tapecount);
846             if (code)
847                 ERROR_EXIT(code);
848         }
849         interactiveFlag = 1;
850         tapecount++;
851
852         code = butm_Mount(tapeInfoPtr, tapeName);
853         if (code) {
854             TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
855             goto getNewTape;
856         }
857
858         code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1);   /* will rewind the tape */
859         if (code) {
860             TapeLog(0, taskId, code, tapeInfoPtr->error,
861                     "Can't read tape label\n");
862             goto getNewTape;
863         }
864
865         /* Check for name of tape and matching dump id (if applicable). */
866         if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
867             || ((rstTapeInfoPtr->tapeSeq != 1)
868                 && (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
869             char expTape[BU_MAXTAPELEN + 32];
870             char gotTape[BU_MAXTAPELEN + 32];
871
872             TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
873             TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);
874
875             TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
876                  gotTape);
877             goto getNewTape;
878         }
879
880         if (rstTapeInfoPtr->tapeSeq == 1)       /* Remember this dumpId */
881             rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;
882
883         break;
884
885       getNewTape:
886         unmountTape(taskId, tapeInfoPtr);
887     }                           /*w */
888
889
890     /* Initialize a tapeEntry for later inclusion into the database */
891     listEntryPtr =
892         (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
893     if (!listEntryPtr)
894         ERROR_EXIT(TC_NOMEMORY);
895     memset(listEntryPtr, 0, sizeof(struct tapeEntryList));
896
897     /* Fill in tape entry so we can save it later */
898     strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
899     tapeEntryPtr->dump = oldTapeLabel.dumpid;
900     tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
901     tapeEntryPtr->written = oldTapeLabel.creationTime;
902     tapeEntryPtr->expires = oldTapeLabel.expirationDate;
903     tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
904     tapeEntryPtr->useCount = oldTapeLabel.useCount;
905     tapeEntryPtr->useKBytes = 0;
906     tapeEntryPtr->labelpos = 0;
907
908     /* Thread onto end of single-linked list */
909     if (listEntryHead) {
910         endList = listEntryHead;
911         while (endList->next)
912             endList = endList->next;
913         endList->next = listEntryPtr;
914     } else
915         listEntryHead = listEntryPtr;
916
917   error_exit:
918     return (code);
919 }
920
921 static afs_int32 nbytes = 0;    /* # bytes left in buffer */
922 static void
923 initTapeBuffering(void)
924 {
925     nbytes = 0;
926 }
927
928
929 /* restoreDbEntries
930  *      restore all the items on the tape
931  * entry:
932  *      tape positioned after tape label
933  */
934
935 static int
936 restoreDbEntries(struct butm_tapeInfo *tapeInfoPtr,
937                  struct rstTapeInfo *rstTapeInfoPtr)
938 {
939     struct structDumpHeader netItemHeader, hostItemHeader;
940     afs_int32 more = 1;
941     afs_int32 taskId, code = 0;
942     int count = 0;
943
944     taskId = rstTapeInfoPtr->taskId;
945
946     /* clear state for the buffer routine(s) */
947     initTapeBuffering();
948
949     code = butm_ReadFileBegin(tapeInfoPtr);
950     if (code) {
951         ErrorLog(0, taskId, code, tapeInfoPtr->error,
952                  "Can't read FileBegin on tape\n");
953         ERROR_EXIT(code);
954     }
955
956     /* get the first item-header */
957     memset(&netItemHeader, 0, sizeof(netItemHeader));
958     code =
959         getTapeData(tapeInfoPtr, rstTapeInfoPtr, &netItemHeader,
960                     sizeof(netItemHeader));
961     if (code)
962         ERROR_EXIT(code);
963     structDumpHeader_ntoh(&netItemHeader, &hostItemHeader);
964
965     while (more) {
966         switch (hostItemHeader.type) {
967         case SD_DBHEADER:
968             code =
969                 restoreDbHeader(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
970             if (code)
971                 ERROR_EXIT(code);
972             break;
973
974         case SD_DUMP:
975             if (++count > 25) { /*every 25 dumps, wait */
976                 waitDbWatcher();
977                 count = 0;
978             }
979             code =
980                 restoreDbDump(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
981             if (code)
982                 ERROR_EXIT(code);
983             break;
984
985         case SD_TAPE:
986         case SD_VOLUME:
987             ERROR_EXIT(-1);
988             break;
989
990         case SD_TEXT_DUMPSCHEDULE:
991         case SD_TEXT_VOLUMESET:
992         case SD_TEXT_TAPEHOSTS:
993             code = restoreText(tapeInfoPtr, rstTapeInfoPtr, &hostItemHeader);
994             if (code)
995                 ERROR_EXIT(code);
996             break;
997
998         case SD_END:
999             more = 0;
1000             break;
1001
1002         default:
1003             TLog(taskId, "Unknown database header type %d\n",
1004                  hostItemHeader.type);
1005             ERROR_EXIT(-1);
1006             break;
1007         }
1008     }
1009
1010     code = butm_ReadFileEnd(tapeInfoPtr);
1011     if (code) {
1012         ErrorLog(0, taskId, code, tapeInfoPtr->error,
1013                  "Can't read EOF on tape\n");
1014         ERROR_EXIT(code);
1015     }
1016
1017     /* Mark tape as having been written */
1018     tapeEntryPtr->useKBytes =
1019         tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1020     tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1021
1022   error_exit:
1023     return (code);
1024 }
1025
1026 /* restoreDbFromTape
1027  *      restore the backup database from tape.
1028  */
1029
1030 void *
1031 restoreDbFromTape(void *param)
1032 {
1033     afs_uint32 taskId = (intptr_t) param;
1034     afs_int32 code = 0;
1035     afs_int32 i;
1036     struct butm_tapeInfo tapeInfo;
1037     struct rstTapeInfo rstTapeInfo;
1038     struct budb_dumpEntry dumpEntry;
1039
1040     extern struct tapeConfig globalTapeConfig;
1041     extern struct deviceSyncNode *deviceLatch;
1042
1043     setStatus(taskId, DRIVE_WAIT);
1044     EnterDeviceQueue(deviceLatch);      /* lock tape device */
1045     clearStatus(taskId, DRIVE_WAIT);
1046
1047     printf("\n\n");
1048     TLog(taskId, "RestoreDb\n");
1049
1050     tapeInfo.structVersion = BUTM_MAJORVERSION;
1051     code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1052     if (code) {
1053         ErrorLog(0, taskId, code, tapeInfo.error,
1054                  "Can't initialize tape module\n");
1055         ERROR_EXIT(code);
1056     }
1057
1058     listEntryHead = NULL;
1059
1060     rstTapeInfo.taskId = taskId;
1061     rstTapeInfo.tapeSeq = 1;
1062     rstTapeInfo.dumpid = 0;
1063
1064     code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
1065     if (code)
1066         ERROR_EXIT(code);
1067
1068     code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
1069     if (code)
1070         ERROR_EXIT(code);
1071
1072   error_exit:
1073     /* Now put this dump into the database */
1074     /* Make a dump entry from first tape   */
1075     listEntryPtr = listEntryHead;
1076     if (listEntryPtr) {
1077         makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
1078         if (dumpEntry.id != 0) {
1079             i = bcdb_CreateDump(&dumpEntry);
1080             if (i) {
1081                 if (i == BUDB_DUMPIDEXISTS)
1082                     fprintf(stderr,
1083                             "Dump id %d not added to database - already exists\n",
1084                             dumpEntry.id);
1085                 else
1086                     TapeLog(0, taskId, i, 0,
1087                             "Dump id %d not added to database\n",
1088                             dumpEntry.id);
1089             } else {
1090                 i = addTapesToDb(taskId);
1091                 if (!code)
1092                     code = i;
1093
1094                 i = bcdb_FinishDump(&dumpEntry);
1095                 if (!code)
1096                     code = i;
1097             }
1098         }
1099         freeTapeList();
1100     }
1101
1102     unmountTape(taskId, &tapeInfo);
1103     waitDbWatcher();
1104
1105     if (code == TC_ABORTEDBYREQUEST) {
1106         TLog(taskId, "RestoreDb: Aborted by request\n");
1107         clearStatus(taskId, ABORT_REQUEST);
1108         setStatus(taskId, ABORT_DONE);
1109     } else if (code) {
1110         TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
1111         setStatus(taskId, TASK_ERROR);
1112     } else {
1113         TLog(taskId, "RestoreDb: Finished\n");
1114     }
1115
1116     LeaveDeviceQueue(deviceLatch);
1117     setStatus(taskId, TASK_DONE);
1118
1119     return (void *)(intptr_t)(code);
1120 }
1121
1122 /* KeepAlive
1123  *
1124  *      While dumping the database, keeps the connection alive.
1125  *      Every 10 seconds, wake up and ask to read 0 bytes of the database.
1126  *      This resets the database's internal timer so that it does not
1127  *      prematuraly quit (on asking for new tapes and such).
1128  *
1129  *      Use the same udbHandle as writeDbDump so we go to the same server.
1130  */
1131 void *
1132 KeepAlive(void *unused)
1133 {
1134     charListT charList;
1135     afs_int32 code;
1136     afs_int32 done;
1137
1138     extern struct udbHandleS udbHandle;
1139
1140     while (1) {
1141 #ifdef AFS_PTHREAD_ENV
1142         sleep(5);
1143 #else
1144         IOMGR_Sleep(5);
1145 #endif
1146         charList.charListT_val = 0;
1147         charList.charListT_len = 0;
1148         code =
1149             ubik_Call_SingleServer(BUDB_DumpDB, udbHandle.uh_client,
1150                                    UF_SINGLESERVER, 0, 0, &charList, &done);
1151         if (code || done)
1152             break;
1153     }
1154     return 0;
1155 }
1156
1157
1158 /* restoreDbHeader
1159  *      restore special items in the header
1160  */
1161
1162 int
1163 restoreDbHeader(struct butm_tapeInfo *tapeInfo,
1164                 struct rstTapeInfo *rstTapeInfoPtr,
1165                 struct structDumpHeader *nextHeader)
1166 {
1167     struct structDumpHeader netItemHeader;
1168     struct DbHeader netDbHeader, hostDbHeader;
1169     afs_int32 code = 0;
1170
1171     extern struct udbHandleS udbHandle;
1172
1173     /* Read the database header */
1174     memset(&netDbHeader, 0, sizeof(netDbHeader));
1175     code =
1176         getTapeData(tapeInfo, rstTapeInfoPtr, &netDbHeader,
1177                     sizeof(netDbHeader));
1178     if (code)
1179         ERROR_EXIT(code);
1180     DbHeader_ntoh(&netDbHeader, &hostDbHeader);
1181
1182     /* Add the database header to the database */
1183     code =
1184         ubik_BUDB_RestoreDbHeader(udbHandle.uh_client, 0,
1185                   &hostDbHeader);
1186     if (code) {
1187         ErrorLog(0, rstTapeInfoPtr->taskId, code, 0,
1188                  "Can't restore DB Header\n");
1189         ERROR_EXIT(code);
1190     }
1191
1192     /* get the next item-header */
1193     memset(nextHeader, 0, sizeof(*nextHeader));
1194     code =
1195         getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1196                     sizeof(netItemHeader));
1197     if (code)
1198         ERROR_EXIT(code);
1199     structDumpHeader_ntoh(&netItemHeader, nextHeader);
1200
1201   error_exit:
1202     return (code);
1203 }
1204
1205
1206 /* restoreDbDump
1207  *      restore a single dump, including all its tapes and volumes, from
1208  *      the tape.
1209  * entry:
1210  *      nextHeader - ptr to structure for return value
1211  * exit:
1212  *      nextHeader - next structure header from tape
1213  * notes:
1214  *      upon entry, the dump structure header has been read confirming that
1215  *      a database dump tree exists on the tape
1216  */
1217
1218 int
1219 restoreDbDump(struct butm_tapeInfo *tapeInfo,
1220               struct rstTapeInfo *rstTapeInfoPtr,
1221               struct structDumpHeader *nextHeader)
1222 {
1223     struct budb_dumpEntry netDumpEntry, hostDumpEntry;
1224     struct budb_tapeEntry netTapeEntry, hostTapeEntry;
1225     struct budb_volumeEntry netVolumeEntry, hostVolumeEntry;
1226     struct structDumpHeader netItemHeader;
1227     int restoreThisDump = 1;
1228     afs_int32 code = 0;
1229
1230     extern struct udbHandleS udbHandle;
1231
1232     /* read dump entry */
1233     memset(&netDumpEntry, 0, sizeof(netDumpEntry));
1234     code =
1235         getTapeData(tapeInfo, rstTapeInfoPtr, &netDumpEntry,
1236                     sizeof(netDumpEntry));
1237     if (code)
1238         ERROR_EXIT(code);
1239
1240     /* If database tape does not have a dumpid (AFS 3.3) then no initial/appended dumps */
1241     if (rstTapeInfoPtr->dumpid == 0) {
1242         netDumpEntry.initialDumpID = 0;
1243         netDumpEntry.appendedDumpID = 0;
1244     }
1245
1246     dumpEntry_ntoh(&netDumpEntry, &hostDumpEntry);
1247
1248     /* The dump entry for this database tape is incomplete, so don't include it */
1249     if (hostDumpEntry.id == rstTapeInfoPtr->dumpid)
1250         restoreThisDump = 0;
1251
1252     /* add the dump to the database */
1253     if (restoreThisDump) {
1254         code =
1255             threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1256                            DLQ_USEDUMP);
1257         if (code)
1258             ERROR_EXIT(code);
1259     }
1260
1261     /* get the next item-header */
1262     memset(nextHeader, 0, sizeof(*nextHeader));
1263     code =
1264         getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1265                     sizeof(netItemHeader));
1266     if (code)
1267         ERROR_EXIT(code);
1268     structDumpHeader_ntoh(&netItemHeader, nextHeader);
1269
1270     /* Add every tape to the db */
1271     while (nextHeader->type == SD_TAPE) {       /*t */
1272
1273         /* read the tape entry */
1274         memset(&netTapeEntry, 0, sizeof(netTapeEntry));
1275         code =
1276             getTapeData(tapeInfo, rstTapeInfoPtr, &netTapeEntry,
1277                         sizeof(netTapeEntry));
1278         if (code)
1279             ERROR_EXIT(code);
1280         tapeEntry_ntoh(&netTapeEntry, &hostTapeEntry);
1281
1282         /* Add the tape to the database */
1283         if (restoreThisDump) {
1284             code =
1285                 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1286                                DLQ_USETAPE);
1287             if (code)
1288                 ERROR_EXIT(code);
1289         }
1290
1291         /* get the next item-header */
1292         memset(nextHeader, 0, sizeof(*nextHeader));
1293         code =
1294             getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1295                         sizeof(netItemHeader));
1296         if (code)
1297             ERROR_EXIT(code);
1298         structDumpHeader_ntoh(&netItemHeader, nextHeader);
1299
1300         /* Add every volume to the db */
1301         while (nextHeader->type == SD_VOLUME) { /*v */
1302
1303             /* read the volume entry */
1304             memset(&netVolumeEntry, 0, sizeof(netVolumeEntry));
1305             code =
1306                 getTapeData(tapeInfo, rstTapeInfoPtr, &netVolumeEntry,
1307                             sizeof(netVolumeEntry));
1308             if (code)
1309                 ERROR_EXIT(code);
1310             volumeEntry_ntoh(&netVolumeEntry, &hostVolumeEntry);
1311
1312             if (restoreThisDump) {
1313                 code =
1314                     threadEntryDir(&hostVolumeEntry, sizeof(hostVolumeEntry),
1315                                    DLQ_VOLENTRY);
1316                 if (code)
1317                     ERROR_EXIT(code);
1318             }
1319
1320             /* get the next item-header */
1321             memset(nextHeader, 0, sizeof(*nextHeader));
1322             code =
1323                 getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1324                             sizeof(netItemHeader));
1325             if (code)
1326                 ERROR_EXIT(code);
1327             structDumpHeader_ntoh(&netItemHeader, nextHeader);
1328         }                       /*v */
1329
1330         /* Finish the tape */
1331         if (restoreThisDump) {
1332             code =
1333                 threadEntryDir(&hostTapeEntry, sizeof(hostTapeEntry),
1334                                DLQ_FINISHTAPE);
1335             if (code)
1336                 ERROR_EXIT(code);
1337         }
1338     }                           /*t */
1339
1340     /* Finish the dump */
1341     if (restoreThisDump) {
1342         code =
1343             threadEntryDir(&hostDumpEntry, sizeof(hostDumpEntry),
1344                            DLQ_FINISHDUMP);
1345         if (code)
1346             ERROR_EXIT(code);
1347     }
1348
1349   error_exit:
1350     return (code);
1351 }
1352
1353 /* saveTextFile
1354  *      Save the specified file as configuration text in the ubik database.
1355  *      Have to setup the client text structure so that we can call
1356  *      the routine to transmit the text to the db.
1357  */
1358
1359 afs_int32
1360 saveTextFile(afs_int32 taskId, afs_int32 textType, char *fileName)
1361 {
1362     udbClientTextP ctPtr = 0;
1363     afs_int32 code = 0;
1364     int tlock = 0;
1365
1366     ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1367     if (!ctPtr)
1368         ERROR_EXIT(TC_NOMEMORY);
1369
1370     memset(ctPtr, 0, sizeof(*ctPtr));
1371     ctPtr->textType = textType;
1372
1373     /* lock the text in the database */
1374     code = bc_LockText(ctPtr);
1375     if (code) {
1376         ErrorLog(0, taskId, code, 0, "Can't lock text file\n");
1377         ERROR_EXIT(code);
1378     }
1379     tlock = 1;
1380
1381     ctPtr->textStream = fopen(fileName, "r");
1382     if (!ctPtr->textStream) {
1383         ErrorLog(0, taskId, errno, 0, "Can't open text file\n");
1384         ERROR_EXIT(errno);
1385     }
1386
1387     /* now send the text to the database */
1388     code = bcdb_SaveTextFile(ctPtr);
1389     if (code) {
1390         ErrorLog(0, taskId, code, 0, "Can't save text file\n");
1391         ERROR_EXIT(code);
1392     }
1393
1394   error_exit:
1395     if (ctPtr) {
1396         if (ctPtr->textStream)
1397             fclose(ctPtr->textStream);
1398         if (tlock)
1399             bc_UnlockText(ctPtr);
1400         free(ctPtr);
1401     }
1402     return (code);
1403 }
1404
1405 /* restoreText
1406  *      read the text off the tape, and store it in the appropriate
1407  *      text type in the database.
1408  * entry:
1409  *      nextHeader - ptr to struct for return information
1410  * exit:
1411  *      nextHeader - struct header for next item on the tape
1412  */
1413
1414 int
1415 restoreText(struct butm_tapeInfo *tapeInfo,
1416             struct rstTapeInfo *rstTapeInfoPtr,
1417             struct structDumpHeader *nextHeader)
1418 {
1419     char filename[64];
1420     afs_int32 nbytes;
1421     char *readBuffer = 0;
1422     afs_int32 readBlockSize;
1423     afs_int32 transferSize;
1424     struct structDumpHeader netItemHeader;
1425     int fid = -1;
1426     afs_int32 code = 0;
1427
1428     udbClientTextP ctPtr = 0;
1429     afs_int32 textType;
1430
1431     ctPtr = (udbClientTextP) malloc(sizeof(*ctPtr));
1432     if (!ctPtr)
1433         ERROR_EXIT(TC_NOMEMORY);
1434
1435     /* determine the type of text block */
1436     switch (nextHeader->type) {
1437     case SD_TEXT_DUMPSCHEDULE:
1438         textType = TB_DUMPSCHEDULE;
1439         break;
1440
1441     case SD_TEXT_VOLUMESET:
1442         textType = TB_VOLUMESET;
1443         break;
1444
1445     case SD_TEXT_TAPEHOSTS:
1446         textType = TB_TAPEHOSTS;
1447         break;
1448
1449     default:
1450         ErrorLog(0, rstTapeInfoPtr->taskId, TC_INTERNALERROR, 0,
1451                  "Unknown text block\n");
1452         ERROR_EXIT(TC_INTERNALERROR);
1453         break;
1454     }
1455
1456     /* open the text file */
1457     sprintf(filename, "%s/bu_XXXXXX", gettmpdir());
1458     fid = mkstemp(filename);
1459     if (fid < 0) {
1460         ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1461                  "Can't open temporary text file: %s\n", filename);
1462         ERROR_EXIT(errno);
1463     }
1464
1465     /* allocate buffer for text */
1466     readBlockSize = BUTM_BLKSIZE;
1467     readBuffer = (char *)malloc(readBlockSize);
1468     if (!readBuffer)
1469         ERROR_EXIT(TC_NOMEMORY);
1470
1471     /* read the text into the temporary file */
1472     nbytes = nextHeader->size;
1473     while (nbytes > 0) {
1474         transferSize = (readBlockSize < nbytes) ? readBlockSize : nbytes;
1475
1476         /* read it from the tape */
1477         code =
1478             getTapeData(tapeInfo, rstTapeInfoPtr, readBuffer, transferSize);
1479         if (code)
1480             ERROR_EXIT(code);
1481
1482         /* write to the file */
1483         if (write(fid, readBuffer, transferSize) != transferSize) {
1484             ErrorLog(0, rstTapeInfoPtr->taskId, errno, 0,
1485                      "Can't write temporary text file: %s\n", filename);
1486             ERROR_EXIT(errno);
1487         }
1488
1489         nbytes -= transferSize;
1490     }
1491
1492     close(fid);
1493     fid = -1;
1494     code = saveTextFile(rstTapeInfoPtr->taskId, textType, filename);
1495     if (code)
1496         ERROR_EXIT(code);
1497     unlink(filename);
1498
1499     /* get the next item-header */
1500     memset(nextHeader, 0, sizeof(*nextHeader));
1501     code =
1502         getTapeData(tapeInfo, rstTapeInfoPtr, &netItemHeader,
1503                     sizeof(netItemHeader));
1504     if (code)
1505         ERROR_EXIT(code);
1506     structDumpHeader_ntoh(&netItemHeader, nextHeader);
1507
1508   error_exit:
1509     if (ctPtr)
1510         free(ctPtr);
1511     if (readBuffer)
1512         free(readBuffer);
1513     if (fid != -1) {
1514         close(fid);
1515         unlink(filename);
1516     }
1517     return (code);
1518 }
1519
1520
1521 /* ----------------------------------
1522  * Tape data buffering - for reading database dumps
1523  * ----------------------------------
1524  */
1525
1526 static char *tapeReadBuffer = 0;        /* input buffer */
1527 static char *tapeReadBufferPtr = 0;     /* position in buffer */
1528
1529 /* getTapeData
1530  *      Read information from tape, and place the requested number of bytes
1531  *      in the buffer supplied
1532  * entry:
1533  *      tapeInfo
1534  *      rstTapeInfoPtr - Info about the dump being restored.
1535  *      buffer - buffer for requested data
1536  *      requestedBytes - no. of bytes requested
1537  * exit:
1538  *      fn retn - 0, ok, n, error
1539  */
1540
1541 int
1542 getTapeData(struct butm_tapeInfo *tapeInfoPtr,
1543             struct rstTapeInfo *rstTapeInfoPtr,
1544             void *out, afs_int32 requestedBytes)
1545 {
1546     char *buffer = (char *) out;
1547     afs_int32 taskId, transferBytes;
1548     afs_int32 code = 0;
1549
1550     taskId = rstTapeInfoPtr->taskId;
1551
1552     if (checkAbortByTaskId(taskId))
1553         ERROR_EXIT(TC_ABORTEDBYREQUEST);
1554
1555     if (!tapeReadBuffer) {
1556         tapeReadBuffer = (char *)malloc(BUTM_BLOCKSIZE);
1557         if (!tapeReadBuffer)
1558             ERROR_EXIT(TC_NOMEMORY);
1559     }
1560
1561     while (requestedBytes > 0) {
1562         if (nbytes == 0) {
1563             tapeReadBufferPtr = &tapeReadBuffer[sizeof(struct blockMark)];
1564
1565             /* get more data */
1566             code =
1567                 butm_ReadFileData(tapeInfoPtr, tapeReadBufferPtr,
1568                                   BUTM_BLKSIZE, &nbytes);
1569             if (code) {
1570                 /* detect if we hit the end-of-tape and get next tape */
1571                 if (code == BUTM_ENDVOLUME) {
1572                     /* Update fields in tape entry for this tape */
1573                     tapeEntryPtr->flags = BUDB_TAPE_WRITTEN;
1574                     tapeEntryPtr->useKBytes =
1575                         tapeInfoPtr->kBytes + (tapeInfoPtr->nBytes ? 1 : 0);
1576
1577                     unmountTape(taskId, tapeInfoPtr);
1578
1579                     rstTapeInfoPtr->tapeSeq++;
1580                     code = readDbTape(tapeInfoPtr, rstTapeInfoPtr, 1);
1581                     if (code)
1582                         ERROR_EXIT(code);
1583
1584                     code = butm_ReadFileBegin(tapeInfoPtr);
1585                     if (code) {
1586                         ErrorLog(0, taskId, code, tapeInfoPtr->error,
1587                                  "Can't read FileBegin on tape\n");
1588                         ERROR_EXIT(code);
1589                     }
1590
1591                     continue;
1592                 }
1593
1594                 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1595                          "Can't read FileData on tape\n");
1596                 ERROR_EXIT(code);
1597             }
1598         }
1599
1600         /* copy out data */
1601         transferBytes = (nbytes < requestedBytes) ? nbytes : requestedBytes;
1602         memcpy(buffer, tapeReadBufferPtr, transferBytes);
1603         tapeReadBufferPtr += transferBytes;
1604         buffer += transferBytes;
1605         nbytes -= transferBytes;
1606         requestedBytes -= transferBytes;
1607     }
1608
1609   error_exit:
1610     return (code);
1611 }