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