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