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