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