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