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