2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
17 #include <afs/tcdata.h>
23 afs_int32 nrestore
, nskip
;
24 int ask
, printlabels
, printheaders
, verbose
;
28 #define TAPE_MAGIC 1100000009 /* Defined in file_tm.c */
29 #define BLOCK_MAGIC 1100000005
30 #define FILE_MAGIC 1000000007
35 struct tapeLabel
{ /* also in file_tm.c */
37 struct butm_tapeLabel label
;
39 struct fileMark
{ /* also in file_tm.c */
44 /* Read a tape block of size 16K */
46 readblock(char *buffer
)
48 u_int nread
, total
= 0;
51 while (total
< BUTM_BLOCKSIZE
) {
52 rc
= USD_READ(fd
, buffer
+ total
, BUTM_BLOCKSIZE
- total
, &nread
);
55 } else if ((nread
== 0) && (total
== 0)) {
57 fprintf(stderr
, "Hardware file mark\n");
61 "Greater than 3 hardware file marks in a row - done\n");
64 } else if (nread
== 0) {
65 fprintf(stderr
, "Reached unexpected end of dump file\n");
75 printLabel(struct tapeLabel
*tapeLabelPtr
)
77 tapeLabelPtr
->label
.dumpid
= ntohl(tapeLabelPtr
->label
.dumpid
);
78 tapeLabelPtr
->label
.creationTime
=
79 ntohl(tapeLabelPtr
->label
.creationTime
);
80 tapeLabelPtr
->label
.expirationDate
=
81 ntohl(tapeLabelPtr
->label
.expirationDate
);
82 tapeLabelPtr
->label
.structVersion
=
83 ntohl(tapeLabelPtr
->label
.structVersion
);
84 tapeLabelPtr
->label
.useCount
= ntohl(tapeLabelPtr
->label
.useCount
);
85 tapeLabelPtr
->label
.size
= ntohl(tapeLabelPtr
->label
.size
);
87 fprintf(stderr
, "\nDUMP %u\n", tapeLabelPtr
->label
.dumpid
);
91 fprintf(stderr
, " AFS Tape Name : %s\n",
92 tapeLabelPtr
->label
.AFSName
);
93 fprintf(stderr
, " Permanent Name : %s\n",
94 tapeLabelPtr
->label
.pName
);
95 fprintf(stderr
, " Dump Id : %u\n",
96 tapeLabelPtr
->label
.dumpid
);
97 t
= tapeLabelPtr
->label
.dumpid
;
98 fprintf(stderr
, " Dump Id Time : %.24s\n",
100 t
= tapeLabelPtr
->label
.creationTime
;
101 fprintf(stderr
, " Date Created : %.24s\n",
103 t
= tapeLabelPtr
->label
.expirationDate
;
104 fprintf(stderr
, " Date Expires : %.24s\n",
106 fprintf(stderr
, " Version Number : %d\n",
107 tapeLabelPtr
->label
.structVersion
);
108 fprintf(stderr
, " Tape Use Count : %d\n",
109 tapeLabelPtr
->label
.useCount
);
110 fprintf(stderr
, " Tape Size : %u\n",
111 tapeLabelPtr
->label
.size
);
112 fprintf(stderr
, " Comment : %s\n",
113 tapeLabelPtr
->label
.comment
);
114 fprintf(stderr
, " Dump Path : %s\n",
115 tapeLabelPtr
->label
.dumpPath
);
116 fprintf(stderr
, " Cell Name : %s\n",
117 tapeLabelPtr
->label
.cell
);
118 fprintf(stderr
, " Creator Name : %s\n",
119 tapeLabelPtr
->label
.creator
.name
);
120 fprintf(stderr
, " Creator Instance : %s\n",
121 tapeLabelPtr
->label
.creator
.instance
);
122 fprintf(stderr
, " Creator Cell : %s\n",
123 tapeLabelPtr
->label
.creator
.cell
);
128 printHeader(struct volumeHeader
*headerPtr
, afs_int32
*isvolheader
)
130 static int volcount
= 0;
133 headerPtr
->volumeID
= ntohl(headerPtr
->volumeID
);
134 headerPtr
->server
= ntohl(headerPtr
->server
);
135 headerPtr
->part
= ntohl(headerPtr
->part
);
136 headerPtr
->from
= ntohl(headerPtr
->from
);
137 headerPtr
->frag
= ntohl(headerPtr
->frag
);
138 headerPtr
->magic
= ntohl(headerPtr
->magic
);
139 headerPtr
->contd
= ntohl(headerPtr
->contd
);
140 headerPtr
->dumpID
= ntohl(headerPtr
->dumpID
);
141 headerPtr
->level
= ntohl(headerPtr
->level
);
142 headerPtr
->parentID
= ntohl(headerPtr
->parentID
);
143 headerPtr
->endTime
= ntohl(headerPtr
->endTime
);
144 headerPtr
->versionflags
= ntohl(headerPtr
->versionflags
);
145 headerPtr
->cloneDate
= ntohl(headerPtr
->cloneDate
);
147 if (headerPtr
->magic
== TC_VOLBEGINMAGIC
) {
152 fprintf(stderr
, "Volume header\n");
155 "VOLUME %3d %s (%u) - %s dump from %.24s",
156 ++volcount
, headerPtr
->volumeName
, headerPtr
->volumeID
,
157 (headerPtr
->level
? "Incr" : "Full"),
158 (t
? (char *)ctime(&t
) : "0"));
159 /* do not include two ctime() calls in the same fprintf call as
160 * the same string buffer will be returned by each call. */
161 t
= headerPtr
->cloneDate
;
162 fprintf(stderr
, " till %.24s\n", ctime(&t
));
164 fprintf(stderr
, " Volume Name = %s\n",
165 headerPtr
->volumeName
);
166 fprintf(stderr
, " Volume ID = %u\n", headerPtr
->volumeID
);
167 t
= headerPtr
->cloneDate
;
168 fprintf(stderr
, " Clone Date = %.24s\n",
170 fprintf(stderr
, " Vol Fragment = %d\n", headerPtr
->frag
);
171 fprintf(stderr
, " Vol Continued = 0x%x\n", headerPtr
->contd
);
172 fprintf(stderr
, " DumpSet Name = %s\n",
173 headerPtr
->dumpSetName
);
174 fprintf(stderr
, " Dump ID = %u\n", headerPtr
->dumpID
);
175 fprintf(stderr
, " Dump Level = %d\n", headerPtr
->level
);
177 fprintf(stderr
, " Dump Since = %.24s\n",
179 fprintf(stderr
, " parent Dump ID = %u\n", headerPtr
->parentID
);
181 } else if (headerPtr
->magic
== TC_VOLENDMAGIC
) {
183 fprintf(stderr
, "Volume Trailer\n");
185 fprintf(stderr
, "Unrecognized Volume Header/Trailer\n");
190 openOutFile(struct volumeHeader
*headerPtr
)
199 /* If we were asked to skip this volume, then skip it */
204 /* Skip if we are not to restore any */
208 /* Get the volume name and strip off the BK or RO extension */
210 strcpy(filename
, outfile
);
212 strcpy(filename
, headerPtr
->volumeName
);
213 len
= strlen(filename
);
214 if ((len
> 7) && (strcmp(".backup", filename
+ len
- 7) == 0)) {
215 filename
[len
- 7] = 0;
217 && (strcmp(".readonly", filename
+ len
- 9) == 0)) {
218 filename
[len
- 9] = 0;
225 printf("Press return to retrieve volume %s (%u) to file %s; " "s"
226 " to skip\n", headerPtr
->volumeName
, headerPtr
->volumeID
,
230 if ((first
== 1) && (ch
== 's'))
232 if ((first
== 1) && (ch
== 'q'))
235 } while (ch
!= '\n');
237 printf("Will not restore volume %s\n", headerPtr
->volumeName
);
241 printf("Retrieve volume %s (%u) to file %s\n", headerPtr
->volumeName
,
242 headerPtr
->volumeID
, filename
);
245 /* Should I append the date onto the end of the name? */
247 /* Open the file to write to */
248 if (headerPtr
->contd
== TC_VOLCONTD
) {
249 /* Continuation of dump */
250 oflag
= USD_OPEN_RDWR
;
252 /* An all new dump */
253 oflag
= USD_OPEN_RDWR
| USD_OPEN_CREATE
;
255 rc
= usd_Open(filename
, oflag
, 0664, &ofd
);
257 fprintf(stderr
, "Unable to open file %s. Skipping. Code = %d\n",
262 if (headerPtr
->contd
!= TC_VOLCONTD
) {
264 rc
= USD_IOCTL(ofd
, USD_IOCTL_SETSIZE
, &size
);
266 fprintf(stderr
, "Unable to open file %s. Skipping. Code = %d\n",
278 writeData(char *data
, afs_int32 size
)
285 rc
= USD_WRITE(ofd
, data
, (u_int
) size
, &nwritten
);
287 fprintf(stderr
, "Unable to write volume data to file. Code = %d\n",
294 writeLastBlocks(char *lastblock
, char *lastblock2
)
297 struct blockMark
*bmark
, *bmark2
;
306 bmark
= (struct blockMark
*)lastblock
;
307 data
= &lastblock
[sizeof(struct blockMark
)];
308 count
= ntohl(bmark
->count
);
310 bmark2
= (struct blockMark
*)lastblock2
;
311 data2
= &lastblock2
[sizeof(struct blockMark
)];
312 count2
= ntohl(bmark2
->count
);
318 * Strip off all but the last twelve bytes of the volume trailer
320 skip
= sizeof(struct volumeHeader
) - 12;
322 count
= count
- skip
;
323 } else if (count
+ count2
>= skip
) {
324 count2
= count2
- (skip
- count
);
327 fprintf(stderr
, "Failed to strip off volume trailer (1).\n");
331 /* volume trailer is somewhere in the last 12 bytes of the tape file.
332 * The volume trailer may span tape blocks. */
335 memcpy(trailer
, data
+ (count
- 12), 12);
338 memcpy(trailer
, data2
+ (count2
- tlen
), tlen
);
340 memcpy(trailer
+ tlen
, data
, count
);
344 for (pos
= 0; pos
<= 2; pos
++) {
345 if (strncmp(&trailer
[pos
], "H++NAME#", 8) == 0) {
354 fprintf(stderr
, "Failed to strip off volume trailer (2).\n");
356 if (count2
- tlen
> 0) {
357 writeData(data2
, count2
- tlen
);
359 if ((tlen
== 0) && (count
> 12 - pos
)) {
360 writeData(data
, count
- (12 - pos
));
375 /* Decrement the number of volumes to restore */
381 WorkerBee(struct cmd_syndesc
*as
, void *arock
)
384 struct tapeLabel
*label
;
385 struct fileMark
*fmark
;
387 struct blockMark
*bmark
;
388 afs_int32 isheader
, isdatablock
;
392 struct volumeHeader
*volheaderPtr
= NULL
;
395 char *nextblock
; /* We cycle through three tape blocks so we */
396 char *lastblock
; /* can trim off the volume trailer from the */
397 char *lastblock2
; /* end of each volume without having to back */
398 char *tapeblock1
; /* up the output stream. */
402 tapedev
= as
->parms
[0].items
->data
; /* -tape */
404 (as
->parms
[1].items
? atol(as
->parms
[1].items
->data
) : 0x7fffffff);
405 nskip
= (as
->parms
[2].items
? atol(as
->parms
[2].items
->data
) : 0);
406 if (as
->parms
[4].items
)
407 nskip
= 0x7fffffff; /* -scan */
408 outfile
= (as
->parms
[3].items
? as
->parms
[3].items
->data
: 0);
409 ask
= (as
->parms
[5].items
? 0 : 1); /* -noask */
410 printlabels
= (as
->parms
[6].items
? 1 : 0); /* -label */
411 printheaders
= (as
->parms
[7].items
? 1 : 0); /* -vheaders */
412 verbose
= (as
->parms
[8].items
? 1 : 0); /* -verbose */
414 /* Open the tape device */
415 rc
= usd_Open(tapedev
, USD_OPEN_RDONLY
, 0, &fd
);
417 printf("Failed to open tape device %s. Code = %d\n", tapedev
, rc
);
422 * Initialize the tape block buffers
424 tapeblock1
= malloc(3 * 16384);
425 if (tapeblock1
== NULL
) {
426 printf("Failed to allocate I/O buffers.\n");
429 tapeblock2
= tapeblock1
+ 16384;
430 tapeblock3
= tapeblock2
+ 16384;
432 nextblock
= tapeblock1
;
436 /* Read each tape block deciding what to do with it */
437 do { /* while ((nskip!=0) && (nrestore!=0)) */
438 code
= readblock(nextblock
);
441 fprintf(stderr
, "Tape device read error: %d\n", code
);
446 /* A data block can be either a volume header, volume trailer,
447 * or actual data from a dump.
449 bmark
= (struct blockMark
*)nextblock
;
450 label
= (struct tapeLabel
*)nextblock
;
451 fmark
= (struct fileMark
*)nextblock
;
452 if (ntohl(bmark
->magic
) == BLOCK_MAGIC
) {
454 printf("Data block\n");
457 data
= &nextblock
[sizeof(struct blockMark
)];
458 if (strncmp(data
, "H++NAME#", 8) == 0) {
459 volheaderPtr
= (struct volumeHeader
*)data
;
460 printHeader(volheaderPtr
, &isheader
);
463 code
= openOutFile(volheaderPtr
);
464 nextblock
= tapeblock1
;
468 if (lastblock2
!= NULL
) {
469 data
= &lastblock2
[sizeof(struct blockMark
)];
470 bmark
= (struct blockMark
*)lastblock2
;
471 writeData(data
, ntohl(bmark
->count
));
473 } else if (lastblock
!= NULL
) {
478 lastblock2
= lastblock
;
479 lastblock
= nextblock
;
484 /* Filemarks come in 3 forms: BEGIN, END, and EOD.
485 * There is no information stored in filemarks.
487 else if (ntohl(fmark
->magic
) == FILE_MAGIC
) {
488 fmtype
= ntohl(fmark
->nBytes
);
489 if (fmtype
== FILE_BEGIN
) {
491 fprintf(stderr
, "File mark volume begin\n");
492 } else if (fmtype
== FILE_END
) {
494 fprintf(stderr
, "File mark volume end\n");
495 } else if (fmtype
== FILE_EOD
) {
497 fprintf(stderr
, "File mark end-of-dump\n");
503 else if (ntohl(label
->magic
) == TAPE_MAGIC
) {
505 fprintf(stderr
, "Dump label\n");
512 fprintf(stderr
, "Unrecognized tape block - end\n");
516 /* Anything other than a data block closes the out file.
517 * At this point nextblock contains the end of tape file mark,
518 * lastblock contains the last data block for the current volume,
519 * and lastblock2 contains the second to last block for the current
520 * volume. If the volume fits in a single block, lastblock2 will
521 * be NULL. Call writeLastBlocks to strip off the dump trailer before
522 * writing the last of the volume data to the dump file. The dump
523 * trailer may span block boundaries.
525 if (!isdatablock
&& lastblock
) {
526 writeLastBlocks(lastblock
, lastblock2
);
528 nextblock
= tapeblock1
;
532 } while ((nskip
!= 0) || (nrestore
!= 0));
540 main(int argc
, char **argv
)
542 struct cmd_syndesc
*ts
;
546 ts
= cmd_CreateSyntax(NULL
, WorkerBee
, NULL
, 0,
547 "Restore volumes from backup tape");
548 cmd_AddParm(ts
, "-tape", CMD_SINGLE
, CMD_REQUIRED
, "tape device");
549 cmd_AddParm(ts
, "-restore", CMD_SINGLE
, CMD_OPTIONAL
,
550 "# volumes to restore");
551 cmd_AddParm(ts
, "-skip", CMD_SINGLE
, CMD_OPTIONAL
, "# volumes to skip");
552 cmd_AddParm(ts
, "-file", CMD_SINGLE
, CMD_OPTIONAL
, "filename");
553 cmd_AddParm(ts
, "-scan", CMD_FLAG
, CMD_OPTIONAL
, "Scan the tape");
554 cmd_AddParm(ts
, "-noask", CMD_FLAG
, CMD_OPTIONAL
,
555 "Prompt for each volume");
556 cmd_AddParm(ts
, "-label", CMD_FLAG
, CMD_OPTIONAL
, "Display dump label");
557 cmd_AddParm(ts
, "-vheaders", CMD_FLAG
, CMD_OPTIONAL
,
558 "Display volume headers");
559 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, "verbose");
561 return cmd_Dispatch(argc
, argv
);