1b66eb9c67b7ad9978bd606e7049c8c17a769cd8
[openafs.git] / src / butc / recoverDb.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 <stdio.h>
17 #ifdef AFS_NT40_ENV
18 #include <winsock2.h>
19 #else
20 #include <sys/time.h>
21 #include <sys/file.h>
22 #include <netinet/in.h>
23 #include <netdb.h>
24 #include <strings.h>
25 #endif
26 #include <sys/types.h>
27 #include <rx/xdr.h>
28 #include <rx/rx.h>
29 #include <lwp.h>
30 #include <lock.h>
31 #include <afs/tcdata.h>
32 #include <afs/bubasics.h>
33 #include <afs/budb.h>
34 #include "error_macros.h"
35
36 #define BELLCHAR 7              /* ascii for bell */
37
38 /* GLOBAL CONFIGURATION PARAMETERS */
39 extern int autoQuery;
40 extern int queryoperator;
41
42 /* Handle for the information read from all the tapes of a dump */
43 afs_int32 tapepos;              /* when read a label, remember its position */
44 struct tapeScanInfo {
45     struct butm_tapeLabel tapeLabel, dumpLabel;
46     struct budb_dumpEntry dumpEntry;
47     afs_int32 initialDumpId;
48     int addDbFlag;
49 };
50
51 extern struct tapeConfig globalTapeConfig;
52 extern struct deviceSyncNode *deviceLatch;
53
54 /* PrintDumpLabel
55  *      print out the tape (dump) label.
56  */
57
58 PrintDumpLabel(labelptr)
59      struct butm_tapeLabel *labelptr;
60 {
61     char tapeName[BU_MAXTAPELEN + 32];
62
63     printf("Dump label\n");
64     printf("----------\n");
65     TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
66     printf("permanent tape name = %s\n", tapeName);
67     TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
68     printf("AFS tape name = %s\n", tapeName);
69     printf("creationTime = %s", ctime(&labelptr->creationTime));
70     if (labelptr->expirationDate)
71         printf("expirationDate = %s", cTIME(&labelptr->expirationDate));
72     printf("cell = %s\n", labelptr->cell);
73     printf("size = %u Kbytes\n", labelptr->size);
74     printf("dump path = %s\n", labelptr->dumpPath);
75
76     if (labelptr->structVersion >= TAPE_VERSION_3) {
77         printf("dump id = %u\n", labelptr->dumpid);
78         printf("useCount = %d\n", labelptr->useCount);
79     }
80     printf("-- End of dump label --\n\n");
81 }
82
83 /* PrintVolumeHeader
84  *      print the contents of a volume header. 
85  */
86 static
87 PrintVolumeHeader(volHeader)
88      struct volumeHeader *volHeader;
89 {
90     printf("-- volume --\n");
91     printf("volume name: %s\n", volHeader->volumeName);
92     printf("volume ID %d\n", volHeader->volumeID);
93     /* printf("server %d\n", volHeader->server); */
94     printf("dumpSetName: %s\n", volHeader->dumpSetName);
95     printf("dumpID %d\n", volHeader->dumpID);
96     printf("level %d\n", volHeader->level);
97     printf("parentID %d\n", volHeader->parentID);
98     printf("endTime %d\n", volHeader->endTime);
99     /* printf("versionflags %d\n", volHeader->versionflags); */
100     printf("clonedate %s\n", ctime(&volHeader->cloneDate));
101 }
102
103 /* Ask
104  *      ask a question. returns true or false
105  * exit:
106  *      1 - yes
107  *      0 - no
108  */
109
110 afs_int32
111 Ask(st)
112      char *st;
113 {
114     int response;
115
116     while (1) {
117         FFlushInput();
118         putchar(BELLCHAR);
119         printf("%s? (y/n) ", st);
120         fflush(stdout);
121         response = getchar();
122         if (response == 'y')
123             return (1);
124         else if (response == 'n' || response == EOF)
125             return (0);
126         printf("please answer y/n\n");
127     }
128 }
129
130 /* Will read a dump, then see if there is a dump following it and
131  * try to read that dump too.
132  * The first tape label is the first dumpLabel.
133  */
134 readDumps(taskId, tapeInfoPtr, scanInfoPtr)
135      afs_uint32 taskId;
136      struct butm_tapeInfo *tapeInfoPtr;
137      struct tapeScanInfo *scanInfoPtr;
138 {
139     afs_int32 code, c;
140
141     memcpy(&scanInfoPtr->dumpLabel, &scanInfoPtr->tapeLabel,
142            sizeof(struct butm_tapeLabel));
143
144     while (1) {
145         code = readDump(taskId, tapeInfoPtr, scanInfoPtr);
146         if (code)
147             ERROR_EXIT(code);
148
149         if (scanInfoPtr->tapeLabel.structVersion < TAPE_VERSION_4)
150             break;
151
152         /* Remember the initial dump and see if appended dump exists */
153
154         if (!scanInfoPtr->initialDumpId)
155             scanInfoPtr->initialDumpId = scanInfoPtr->dumpEntry.id;
156
157         c = butm_ReadLabel(tapeInfoPtr, &scanInfoPtr->dumpLabel, 0);    /* no rewind */
158         tapepos = tapeInfoPtr->position - 1;
159         if (c)
160             break;
161     }
162
163   error_exit:
164     return (code);
165 }
166
167 afs_int32
168 getScanTape(taskId, tapeInfoPtr, tname, tapeId, prompt, tapeLabelPtr)
169      afs_int32 taskId;
170      struct butm_tapeInfo *tapeInfoPtr;
171      char *tname;
172      afs_int32 tapeId;
173      int prompt;
174      struct butm_tapeLabel *tapeLabelPtr;
175 {
176     afs_int32 code = 0;
177     int tapecount = 1;
178     afs_int32 curseq;
179     char tapename[BU_MAXTAPELEN + 32];
180     char gotname[BU_MAXTAPELEN + 32];
181
182     while (1) {
183         /* prompt for a tape */
184         if (prompt) {
185             code =
186                 PromptForTape(SCANOPCODE, tname, tapeId, taskId, tapecount);
187             if (code)
188                 ERROR_EXIT(code);
189         }
190         prompt = 1;
191         tapecount++;
192
193         code = butm_Mount(tapeInfoPtr, "");     /* open the tape device */
194         if (code) {
195             TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
196             goto newtape;
197         }
198
199         /* read the label on the tape */
200         code = butm_ReadLabel(tapeInfoPtr, tapeLabelPtr, 1);    /* rewind tape */
201         if (code) {
202             ErrorLog(0, taskId, code, tapeInfoPtr->error,
203                      "Can't read tape label\n");
204             goto newtape;
205         }
206         tapepos = tapeInfoPtr->position - 1;
207
208         /* Now check that the tape is good */
209         TAPENAME(tapename, tname, tapeId);
210         TAPENAME(gotname, tapeLabelPtr->AFSName, tapeLabelPtr->dumpid);
211
212         curseq = extractTapeSeq(tapeLabelPtr->AFSName);
213
214         /* Label can't be null or a bad name */
215         if (!strcmp(tapeLabelPtr->AFSName, "") || (curseq <= 0)) {
216             TLog(taskId, "Expected tape with dump, label seen %s\n", gotname);
217             goto newtape;
218         }
219
220         /* Label can't be a database tape */
221         if (databaseTape(tapeLabelPtr->AFSName)) {
222             TLog(taskId,
223                  "Expected tape with dump. Can't scan database tape %s\n",
224                  gotname);
225             goto newtape;
226         }
227
228         /* If no name, accept any tape */
229         if (strcmp(tname, "") == 0) {
230             break;              /* Start scan on any tape */
231 #ifdef notdef
232             if (curseq == 1)
233                 break;          /* The first tape */
234             else {
235                 TLog(taskId, "Expected first tape of dump, label seen %s\n",
236                      gotname);
237                 goto newtape;
238             }
239 #endif
240         }
241
242         if (strcmp(tname, tapeLabelPtr->AFSName)
243             || ((tapeLabelPtr->structVersion >= TAPE_VERSION_3)
244                 && (tapeLabelPtr->dumpid != tapeId))) {
245             TLog(taskId, "Tape label expected %s, label seen %s\n", tapename,
246                  gotname);
247             goto newtape;
248         }
249
250         /* We have the correct tape */
251         break;
252
253       newtape:
254         unmountTape(taskId, tapeInfoPtr);
255     }
256
257   error_exit:
258     return (code);
259 }
260
261 /* ScanDumps
262  *      This set of code fragments read a tape, and add the information to
263  *      the database. Builds a literal structure.
264  *      
265  */
266
267 ScanDumps(ptr)
268      struct scanTapeIf *ptr;
269 {
270     struct butm_tapeInfo curTapeInfo;
271     struct tapeScanInfo tapeScanInfo;
272     afs_uint32 taskId;
273     afs_int32 code = 0;
274
275     taskId = ptr->taskId;
276     setStatus(taskId, DRIVE_WAIT);
277     EnterDeviceQueue(deviceLatch);
278     clearStatus(taskId, DRIVE_WAIT);
279
280     printf("\n\n");
281     if (ptr->addDbFlag)
282         TLog(taskId, "ScanTape and add to the database\n");
283     else
284         TLog(taskId, "Scantape\n");
285
286     memset(&tapeScanInfo, 0, sizeof(tapeScanInfo));
287     tapeScanInfo.addDbFlag = ptr->addDbFlag;
288
289     memset(&curTapeInfo, 0, sizeof(curTapeInfo));
290     curTapeInfo.structVersion = BUTM_MAJORVERSION;
291     code = butm_file_Instantiate(&curTapeInfo, &globalTapeConfig);
292     if (code) {
293         ErrorLog(0, taskId, code, curTapeInfo.error,
294                  "Can't initialize tape module\n");
295         ERROR_EXIT(code);
296     }
297
298     code =
299         getScanTape(taskId, &curTapeInfo, "", 0, autoQuery,
300                     &tapeScanInfo.tapeLabel);
301     if (code)
302         ERROR_EXIT(code);
303
304     code = readDumps(taskId, &curTapeInfo, &tapeScanInfo);
305     if (code)
306         ERROR_EXIT(code);
307
308   error_exit:
309     unmountTape(taskId, &curTapeInfo);
310     waitDbWatcher();
311
312     if (code == TC_ABORTEDBYREQUEST) {
313         ErrorLog(0, taskId, 0, 0, "Scantape: Aborted by request\n");
314         clearStatus(taskId, ABORT_REQUEST);
315         setStatus(taskId, ABORT_DONE);
316     } else if (code) {
317         ErrorLog(0, taskId, code, 0, "Scantape: Finished with errors\n");
318         setStatus(taskId, TASK_ERROR);
319     } else {
320         TLog(taskId, "Scantape: Finished\n");
321     }
322
323     free(ptr);
324     setStatus(taskId, TASK_DONE);
325     LeaveDeviceQueue(deviceLatch);
326     return (code);
327 }
328
329 /* scanVolData
330  *      Skips the volume data on the tape. The end of the volume data is
331  *      detected by the presence of the volume trailer or by an EOF indication
332  *      from butm. This algorithm should be replaced by one that always
333  *      detects based on the volume trailer, returning the trailer to the
334  *      caller. This is of course more painful.
335  * entry:
336  *      curTapePtr - tape info structure
337  *      Tape must be positioned after volume header
338  * exit:
339  *      0 - success
340  *      3 - empty volume, requires special handling
341  *
342  *      Tape positioned after data, but before file end marker block.
343  *      In case of errors, positioned after the error causing block
344  */
345 #define BIGCHUNK 102400
346
347 static
348 scanVolData(taskId, curTapePtr, tapeVersion, volumeHeader, volumeTrailer,
349             bytesRead)
350      afs_int32 taskId;
351      struct butm_tapeInfo *curTapePtr;
352      afs_int32 tapeVersion;
353      struct volumeHeader *volumeHeader, *volumeTrailer;
354      afs_uint32 *bytesRead;
355 {
356     afs_int32 headBytes, tailBytes;
357     char *block = NULL;
358     char *buffer[2];
359     int hasdata[2], curr, prev;
360     afs_uint32 chunkSize = 0;
361     afs_int32 nbytes;
362     afs_int32 code = 0;
363     afs_int32 rcode, tcode;
364
365     memset(volumeHeader, 0, sizeof(struct volumeHeader));
366
367     block = (char *)malloc(2 * BUTM_BLOCKSIZE);
368     if (!block)
369         return (TC_NOMEMORY);
370     buffer[0] = &block[sizeof(struct blockMark)];
371     buffer[1] = &block[BUTM_BLOCKSIZE + sizeof(struct blockMark)];
372     hasdata[0] = hasdata[1] = 0;
373     curr = 0;
374
375     tcode = NextFile(curTapePtr);       /* guarantees we are at a filemark */
376     if (tcode)
377         ERROR_EXIT(tcode)
378
379             /* Read the FileBegin FileMark */
380             code = butm_ReadFileBegin(curTapePtr);
381     if (code) {
382         /*
383          * Tapes made with 3.0 have no software EOT markers. Therefore
384          * at this point, we will most likely get a read error, indicating
385          * the end of this dump
386          */
387         if ((tapeVersion == TAPE_VERSION_0)
388             || (tapeVersion == TAPE_VERSION_1)) {
389             /*
390              * then a tape error is possible at this point, and it
391              * signals the end of the dump. Tapes that are continued
392              * have an EOT marker.
393              */
394             TapeLog(0, taskId, code, curTapePtr->error,
395                     "Read error - end-of-dump inferred\n");
396             code = BUTM_EOD;
397         }
398
399         if (code != BUTM_EOD)
400             ErrorLog(0, taskId, code, curTapePtr->error,
401                      "Can't read FileBegin on tape\n");
402         ERROR_EXIT(code);
403     }
404
405     /* now read the volume header */
406     code = ReadVolHeader(taskId, curTapePtr, volumeHeader);
407     if (code)
408         ERROR_EXIT(code);
409
410     *bytesRead = 0;
411     while (1) {                 /*w */
412
413         /* Check for abort in the middle of scanning data */
414         if (*bytesRead >= chunkSize) {
415             if (checkAbortByTaskId(taskId))
416                 ERROR_EXIT(TC_ABORTEDBYREQUEST);
417             chunkSize += BIGCHUNK;
418         }
419
420         /* 
421          * Read volume date - If prematurely hit the HW EOF 
422          * marker, check to see if data contains a volumetrailer.
423          */
424         rcode =
425             butm_ReadFileData(curTapePtr, buffer[curr], BUTM_BLKSIZE,
426                               &nbytes);
427         if (rcode) {
428             hasdata[curr] = 0;
429             if ((rcode == BUTM_EOF) || (rcode == BUTM_ENDVOLUME))
430                 break;
431
432             ErrorLog(0, taskId, rcode, curTapePtr->error,
433                      "Can't read FileData on tape\n");
434             ERROR_EXIT(rcode)
435         }
436         hasdata[curr] = 1;
437         *bytesRead += nbytes;
438
439         if ((nbytes != BUTM_BLKSIZE)
440             ||
441             (FindVolTrailer(buffer[curr], nbytes, &tailBytes, volumeTrailer)))
442             break;
443
444         curr = ((curr == 0) ? 1 : 0);   /* Switch buffers */
445     }                           /*w */
446
447     /* Now verify that there is a volume trailer and its valid and copy it */
448     prev = ((curr == 0) ? 1 : 0);
449     if (!FindVolTrailer2
450         (buffer[prev], (hasdata[prev] ? BUTM_BLKSIZE : 0), &headBytes,
451          buffer[curr], nbytes, &tailBytes, volumeTrailer)) {
452         code = TC_MISSINGTRAILER;
453         ErrorLog(0, taskId, code, 0, "Missing volume trailer on tape\n");
454     } else {
455         /* subtract size of the volume trailer from data read */
456         *bytesRead -= sizeof(struct volumeHeader);
457     }
458
459     /* 
460      * If we didn't hit the EOF while reading data, read FileEnd marker 
461      * or EOF marker. 
462      */
463     if (!rcode) {
464         tcode = butm_ReadFileEnd(curTapePtr);
465         if (tcode) {
466             ErrorLog(0, taskId, tcode, curTapePtr->error,
467                      "Can't read EOF on tape\n");
468             ERROR_EXIT(tcode);
469         }
470     }
471
472   error_exit:
473     if (block)
474         free(block);
475     return (code);
476 }
477
478 /* nextTapeLabel
479  *      generate the name of the next tape label expected
480  * exit: 
481  *      ptr to static string
482  */
483
484 char *
485 nextTapeLabel(prevTapeName)
486      char *prevTapeName;
487 {
488     char *prevdot;
489     char *retval;
490     int seq;
491     static char buffer[BU_MAXTAPELEN];
492
493     retval = "";
494
495     /* extract information from previous tape label */
496     strcpy(buffer, prevTapeName);
497     prevdot = strrchr(buffer, '.');
498     if (!prevdot)
499         return (retval);
500     prevdot++;
501
502     seq = extractTapeSeq(prevTapeName);
503     seq++;
504     sprintf(prevdot, "%-d", seq);
505
506     return (&buffer[0]);
507 }
508
509 /* readDump
510  *      Read all the information on a tape. If to add to the database, queue
511  *      onto list so another thread adds the entries to the database.
512  * entry:
513  *      taskid      - butc task number.
514  *      tapeInfoPtr - Tape information.
515  *      scanInfoPtr - Info to keep so we can add entries to the db.
516  * exit:
517  *      0     - tape scanned.
518  *      non-0 - error. Abort the scan.
519  *      moreTapes set to 1 if this is not the last tape in the dump,
520  *                       0 if the last tape,
521  *                      -1 don't know if last tape or not.
522  */
523
524 afs_int32 RcreateDump();
525
526 static
527 readDump(taskId, tapeInfoPtr, scanInfoPtr)
528      afs_uint32 taskId;
529      struct butm_tapeInfo *tapeInfoPtr;
530      struct tapeScanInfo *scanInfoPtr;
531 {
532     int moreTapes = 1;
533     afs_int32 nbytes, flags, seq;
534     int newDump = 1, newTape = 1;
535     afs_int32 tapePosition;
536     afs_int32 code = 0, tcode;
537     int badscan;
538     struct volumeHeader volHeader, volTrailer;
539     struct budb_tapeEntry tapeEntry;
540     struct budb_volumeEntry volEntry;
541
542     volEntry.dump = 0;
543     PrintDumpLabel(&scanInfoPtr->dumpLabel);
544
545     while (moreTapes) {         /* While there is a tape to read *//*t */
546         badscan = 0;
547         while (1) {             /* Read each volume on the tape *//*w */
548             moreTapes = -1;
549             tapePosition = tapeInfoPtr->position;       /* remember position */
550
551             /*
552              * Skip the volume data
553              */
554             tcode =
555                 scanVolData(taskId, tapeInfoPtr,
556                             scanInfoPtr->tapeLabel.structVersion, &volHeader,
557                             &volTrailer, &nbytes);
558             if (tcode) {
559                 badscan++;
560
561                 if (tcode == TC_ABORTEDBYREQUEST) {     /* Aborted */
562                     ERROR_EXIT(tcode);
563                 }
564
565                 if (tcode == BUTM_EOD) {
566                     moreTapes = 0;      /* the end of the dump */
567                     break;
568                 }
569
570                 /* Found a volume but it's incomplete. Skip over these */
571                 if (volHeader.volumeID) {
572                     TapeLog(0, taskId, tcode, 0,
573                             "Warning: volume %s (%u) ignored. Incomplete\n",
574                             volHeader.volumeName, volHeader.volumeID);
575                     continue;
576                 }
577
578                 /* No volume was found. We may have hit the EOT or a 
579                  * bad-spot. Try to skip over this spot.
580                  */
581                 if (badscan < 2) {      /* allow 2 errors, then fail */
582                     TapeLog(0, taskId, tcode, 0,
583                             "Warning: Error in scanning tape - will try skipping volume\n");
584                     continue;
585                 }
586                 if (scanInfoPtr->tapeLabel.structVersion >= TAPE_VERSION_4) {
587                     TapeLog(0, taskId, tcode, 0,
588                             "Warning: Error in scanning tape - end-of-tape inferred\n");
589                     moreTapes = 1;      /* then assume next tape */
590                 } else {
591                     ErrorLog(0, taskId, tcode, 0, "Error in scanning tape\n");
592                     /* will ask if there is a next tape */
593                 }
594                 break;
595             }
596
597             PrintVolumeHeader(&volHeader);
598
599             /* If this is not the first volume fragment, make sure it follows
600              * the last volume fragment 
601              */
602             if (volEntry.dump) {
603                 if ((volEntry.dump != volHeader.dumpID)
604                     || (volEntry.id != volHeader.volumeID)
605                     || (volEntry.seq != volHeader.frag - 2)
606                     || (strcmp(volEntry.name, volHeader.volumeName))) {
607                     TLog(taskId,
608                          "Warning: volume %s (%u) ignored. Incomplete - no last fragment\n",
609                          volEntry.name, volEntry.id);
610
611                     if (scanInfoPtr->addDbFlag) {
612                         tcode = flushSavedEntries(DUMP_FAILED);
613                         if (tcode)
614                             ERROR_EXIT(tcode);
615                         volEntry.dump = 0;
616                     }
617                 }
618             }
619
620             /* If this is the first volume fragment, make sure says so */
621             if (scanInfoPtr->addDbFlag && !volEntry.dump
622                 && (volHeader.frag != 1)) {
623                 TLog(taskId,
624                      "Warning: volume %s (%u) ignored. Incomplete - no first fragment\n",
625                      volHeader.volumeName, volHeader.volumeID);
626             }
627
628             /* Check that this volume belongs to the dump we are scanning */
629             else if (scanInfoPtr->dumpLabel.dumpid
630                      && (volHeader.dumpID != scanInfoPtr->dumpLabel.dumpid)) {
631                 TLog(taskId,
632                      "Warning: volume %s (%u) ignored. Expected DumpId %u, got %u\n",
633                      volHeader.volumeName, volHeader.volumeID,
634                      scanInfoPtr->dumpLabel.dumpid, volHeader.dumpID);
635             }
636
637             /* Passed tests, Now add to the database (if dbadd flag is set) */
638             else if (scanInfoPtr->addDbFlag) {
639                 /* Have enough information to create a dump entry */
640                 if (newDump) {
641                     tcode = RcreateDump(scanInfoPtr, &volHeader);
642                     if (tcode) {
643                         ErrorLog(0, taskId, tcode, 0,
644                                  "Can't add dump %u to database\n",
645                                  volHeader.dumpID);
646                         ERROR_EXIT(tcode);
647                     }
648                     newDump = 0;
649                 }
650
651                 /* Have enough information to create a tape entry */
652                 if (newTape) {
653                     seq = extractTapeSeq(scanInfoPtr->tapeLabel.AFSName);
654                     if (seq < 0)
655                         ERROR_EXIT(TC_INTERNALERROR);
656
657                     tcode =
658                         useTape(&tapeEntry, volHeader.dumpID,
659                                 TNAME(&scanInfoPtr->tapeLabel), seq,
660                                 scanInfoPtr->tapeLabel.useCount,
661                                 scanInfoPtr->dumpLabel.creationTime,
662                                 scanInfoPtr->dumpLabel.expirationDate,
663                                 tapepos);
664                     if (tcode) {
665                         char gotName[BU_MAXTAPELEN + 32];
666
667                         LABELNAME(gotName, &scanInfoPtr->tapeLabel);
668                         ErrorLog(0, taskId, tcode, 0,
669                                  "Can't add tape %s for dump %u to database\n",
670                                  gotName, volHeader.dumpID);
671                         ERROR_EXIT(tcode);
672                     }
673                     newTape = 0;
674                 }
675
676                 /* Create the volume entry */
677                 flags = ((volHeader.frag == 1) ? BUDB_VOL_FIRSTFRAG : 0);
678                 if (!volTrailer.contd)
679                     flags |= BUDB_VOL_LASTFRAG;
680                 tcode =
681                     addVolume(&volEntry, volHeader.dumpID,
682                               TNAME(&scanInfoPtr->tapeLabel),
683                               volHeader.volumeName, volHeader.volumeID,
684                               volHeader.cloneDate, tapePosition, nbytes,
685                               (volHeader.frag - 1), flags);
686                 if (tcode) {
687                     ErrorLog(0, taskId, tcode, 0,
688                              "Can't add volume %s (%u) for dump %u to database\n",
689                              volHeader.volumeName, volHeader.volumeID,
690                              volHeader.dumpID);
691                     ERROR_EXIT(tcode);
692                 }
693             }
694
695             if (volTrailer.contd) {
696                 /* No need to read the EOD marker, we know there is a next tape */
697                 moreTapes = 1;
698                 break;
699             } else {
700                 if (scanInfoPtr->addDbFlag) {
701                     tcode = flushSavedEntries(DUMP_SUCCESS);
702                     if (tcode)
703                         ERROR_EXIT(tcode);
704                     volEntry.dump = 0;
705                 }
706             }
707         }                       /*w */
708
709         if (!newTape) {
710             if (scanInfoPtr->addDbFlag) {
711                 tcode =
712                     finishTape(&tapeEntry,
713                                (tapeInfoPtr->kBytes +
714                                 (tapeInfoPtr->nBytes ? 1 : 0)));
715                 if (tcode) {
716                     char gotName[BU_MAXTAPELEN + 32];
717
718                     LABELNAME(gotName, &scanInfoPtr->tapeLabel);
719                     ErrorLog(0, taskId, tcode, 0,
720                              "Can't mark tape %s 'completed' for dump %u in database\n",
721                              gotName, tapeEntry.dump);
722                     ERROR_EXIT(tcode);
723                 }
724             }
725         }
726
727         /* Ask if there is another tape if we can't figure it out */
728         if (moreTapes == -1)
729             moreTapes = (queryoperator ? Ask("Are there more tapes") : 1);
730
731         /* Get the next tape label */
732         if (moreTapes) {
733             char *tapeName;
734             afs_int32 dumpid;
735
736             unmountTape(taskId, tapeInfoPtr);
737
738             tapeName = nextTapeLabel(scanInfoPtr->tapeLabel.AFSName);
739             dumpid = scanInfoPtr->tapeLabel.dumpid;
740             tcode =
741                 getScanTape(taskId, tapeInfoPtr, tapeName, dumpid, 1,
742                             &scanInfoPtr->tapeLabel);
743             if (tcode)
744                 ERROR_EXIT(tcode);
745             newTape = 1;
746         }
747     }                           /*t */
748
749     if (!newDump) {
750         if (scanInfoPtr->addDbFlag) {
751             tcode = finishDump(&scanInfoPtr->dumpEntry);
752             if (tcode) {
753                 ErrorLog(0, taskId, tcode, 0,
754                          "Can't mark dump %u 'completed' in database\n",
755                          scanInfoPtr->dumpEntry.id);
756             }
757
758             tcode = flushSavedEntries(DUMP_SUCCESS);
759             if (tcode)
760                 ERROR_EXIT(tcode);
761         }
762     }
763
764   error_exit:
765     return (code);
766 }
767
768 /* validatePath
769  * exit:
770  *      0 - not ok
771  *      1 - ok
772  */
773 validatePath(labelptr, pathptr)
774      struct butm_tapeLabel *labelptr;
775      char *pathptr;
776 {
777     char *up, *tp;
778     char tapeName[BU_MAXTAPELEN];
779
780     /* check length */
781     if (strlen(pathptr) > BU_MAX_DUMP_PATH - 1) {
782         fprintf(stderr, "Invalid pathname - too long\n");
783         return (0);
784     }
785
786     if (!labelptr)
787         return (1);
788
789     strcpy(tapeName, labelptr->AFSName);
790
791     tp = strrchr(tapeName, '.');
792     if (!tp)
793         return (1);
794     tp++;
795
796     up = strrchr(pathptr, '/');
797     if (!up) {
798         fprintf(stderr, "Invalid path name, missing /\n");
799         return (0);
800     }
801     up++;
802
803     if (strcmp(up, tp) != 0) {
804         fprintf(stderr, "Invalid path name\n");
805         fprintf(stderr,
806                 "Mismatch between tape dump name '%s' and users dump name '%s'\n",
807                 tp, up);
808         return (0);
809     }
810     return (1);
811 }
812
813 /* volumesetNamePtr
814  *      return a pointer to a (static) volume set name string.
815  * entry:
816  *      ptr - ptr to a dump name
817  * exit:
818  *      0 - error. Can't extract volumeset name.
819  *      ptr - to static volumeset string.
820  */
821
822 char *
823 volumesetNamePtr(ptr)
824      char *ptr;
825 {
826     static char vsname[BU_MAXUNAMELEN];
827     char *dotPtr;
828     int dotIndex;
829
830     dotPtr = strchr(ptr, '.');
831     if (!dotPtr)
832         return (0);
833
834     dotIndex = dotPtr - ptr;
835     if ((dotIndex + 1) > sizeof(vsname))
836         return (0);             /* name too long */
837
838     strncpy(&vsname[0], ptr, dotIndex);
839     vsname[dotIndex] = 0;       /* ensure null terminated */
840
841     return (&vsname[0]);
842 }
843
844 char *
845 extractDumpName(ptr)
846      char *ptr;
847 {
848     static char dname[BU_MAXTAPELEN];
849     char *dotPtr;
850     int dotIndex;
851
852     dotPtr = strrchr(ptr, '.');
853     if (!dotPtr)
854         return (0);
855
856     dotIndex = dotPtr - ptr;
857     if ((dotIndex + 1) > sizeof(dname))
858         return (0);             /* name too long */
859
860     strncpy(&dname[0], ptr, dotIndex);
861     dname[dotIndex] = 0;        /* ensure null terminated */
862
863     return (&dname[0]);
864 }
865
866 /* extractTapeSeq
867  *      The routine assumes that tape names have an embedded sequence number
868  *      as the trialing component. It is suggested that any tape naming
869  *      changes retain the trailing seq. number
870  * entry: 
871  *      tapename - ptr to tape name 
872  * exit:
873  *      0 or positive - sequence number
874  *      -1 - error, couldn't extract sequence number
875  */
876
877 extractTapeSeq(tapename)
878      char *tapename;
879 {
880     char *sptr;
881
882     sptr = strrchr(tapename, '.');
883     if (!sptr)
884         return (-1);
885     sptr++;
886     return (atol(sptr));
887 }
888
889 /* databaseTape
890  *   returns true or false depending on whether the tape is 
891  *   a database tape or not.
892  */
893 int
894 databaseTape(tapeName)
895      char *tapeName;
896 {
897     char *sptr;
898     int c;
899
900     sptr = strrchr(tapeName, '.');
901     if (!sptr)
902         return (0);
903
904     c = (int)((afs_int32) sptr - (afs_int32) tapeName);
905     if (strncmp(tapeName, DUMP_TAPE_NAME, c) == 0)
906         return (1);
907
908     return (0);
909 }
910
911 afs_int32
912 RcreateDump(tapeScanInfoPtr, volHeaderPtr)
913      struct tapeScanInfo *tapeScanInfoPtr;
914      struct volumeHeader *volHeaderPtr;
915 {
916     afs_int32 code;
917     struct butm_tapeLabel *dumpLabelPtr = &tapeScanInfoPtr->dumpLabel;
918     struct budb_dumpEntry *dumpEntryPtr = &tapeScanInfoPtr->dumpEntry;
919
920     /* construct dump entry */
921     memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
922     dumpEntryPtr->id = volHeaderPtr->dumpID;
923     dumpEntryPtr->initialDumpID = tapeScanInfoPtr->initialDumpId;
924     dumpEntryPtr->parent = volHeaderPtr->parentID;
925     dumpEntryPtr->level = volHeaderPtr->level;
926     dumpEntryPtr->created = volHeaderPtr->dumpID;       /* time dump was created */
927     dumpEntryPtr->flags = 0;
928     dumpEntryPtr->incTime = 0;
929     dumpEntryPtr->nVolumes = 0;
930     strcpy(dumpEntryPtr->volumeSetName,
931            volumesetNamePtr(volHeaderPtr->dumpSetName));
932     strcpy(dumpEntryPtr->dumpPath, dumpLabelPtr->dumpPath);
933     strcpy(dumpEntryPtr->name, volHeaderPtr->dumpSetName);
934     default_tapeset(&dumpEntryPtr->tapes, volHeaderPtr->dumpSetName);
935     dumpEntryPtr->tapes.b = extractTapeSeq(dumpLabelPtr->AFSName);
936     copy_ktcPrincipal_to_budbPrincipal(&dumpLabelPtr->creator,
937                                        &dumpEntryPtr->dumper);
938
939     code = bcdb_CreateDump(dumpEntryPtr);
940     return (code);
941 }