Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / butc / recoverDb.c
CommitLineData
805e021f
CE
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 */
34extern int autoQuery;
35extern int queryoperator;
36
37/* Handle for the information read from all the tapes of a dump */
38afs_int32 tapepos; /* when read a label, remember its position */
39struct tapeScanInfo {
40 struct butm_tapeLabel tapeLabel, dumpLabel;
41 struct budb_dumpEntry dumpEntry;
42 afs_int32 initialDumpId;
43 int addDbFlag;
44};
45
46extern struct tapeConfig globalTapeConfig;
47extern struct deviceSyncNode *deviceLatch;
48
49static int readDump(afs_uint32, struct butm_tapeInfo *,
50 struct tapeScanInfo *);
51afs_int32 getScanTape(afs_int32, struct butm_tapeInfo *, char *,
52 afs_int32, int prompt, struct butm_tapeLabel *);
53afs_int32 RcreateDump(struct tapeScanInfo *, struct volumeHeader *);
54void copy_ktcPrincipal_to_budbPrincipal(struct ktc_principal *,
55 struct budb_principal *);
56
57/* PrintDumpLabel
58 * print out the tape (dump) label.
59 */
60void
61PrintDumpLabel(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 */
92static void
93PrintVolumeHeader(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
118afs_int32
119Ask(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
155static int
156scanVolData(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
288char *
289nextTapeLabel(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
327static int
328readDump(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 */
572int
573readDumps(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
604afs_int32
605getScanTape(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
699void *
700ScanDumps(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 */
770int
771validatePath(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
818char *
819volumesetNamePtr(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
839char *
840extractDumpName(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
871int
872extractTapeSeq(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 */
887int
888databaseTape(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
904afs_int32
905RcreateDump(struct tapeScanInfo *tapeScanInfoPtr,
906 struct volumeHeader *volHeaderPtr)
907{
908 afs_int32 code;
909 const char *volsetName;
910 struct butm_tapeLabel *dumpLabelPtr = &tapeScanInfoPtr->dumpLabel;
911 struct budb_dumpEntry *dumpEntryPtr = &tapeScanInfoPtr->dumpEntry;
912
913 /* construct dump entry */
914 memset(dumpEntryPtr, 0, sizeof(struct budb_dumpEntry));
915 dumpEntryPtr->id = volHeaderPtr->dumpID;
916 dumpEntryPtr->initialDumpID = tapeScanInfoPtr->initialDumpId;
917 dumpEntryPtr->parent = volHeaderPtr->parentID;
918 dumpEntryPtr->level = volHeaderPtr->level;
919 dumpEntryPtr->created = volHeaderPtr->dumpID; /* time dump was created */
920 dumpEntryPtr->flags = 0;
921 dumpEntryPtr->incTime = 0;
922 dumpEntryPtr->nVolumes = 0;
923 volsetName = volumesetNamePtr(volHeaderPtr->dumpSetName);
924 if (volsetName == NULL)
925 return BUDB_BADARGUMENT;
926 strcpy(dumpEntryPtr->volumeSetName, volsetName);
927 strcpy(dumpEntryPtr->dumpPath, dumpLabelPtr->dumpPath);
928 strcpy(dumpEntryPtr->name, volHeaderPtr->dumpSetName);
929 default_tapeset(&dumpEntryPtr->tapes, volHeaderPtr->dumpSetName);
930 dumpEntryPtr->tapes.b = extractTapeSeq(dumpLabelPtr->AFSName);
931 copy_ktcPrincipal_to_budbPrincipal(&dumpLabelPtr->creator,
932 &dumpEntryPtr->dumper);
933
934 code = bcdb_CreateDump(dumpEntryPtr);
935 return (code);
936}