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