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