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