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>
16 #include <afs/tcdata.h>
18 #include <sys/types.h>
19 #include <netinet/in.h>
30 afs_int32 nrestore, nskip;
31 int ask, printlabels, printheaders, verbose;
35 #define TAPE_MAGIC 1100000009 /* Defined in file_tm.c */
36 #define BLOCK_MAGIC 1100000005
37 #define FILE_MAGIC 1000000007
42 struct tapeLabel { /* also in file_tm.c */
44 struct butm_tapeLabel label;
46 struct fileMark { /* also in file_tm.c */
51 /* Forward declarations */
52 int writeData(char *data, afs_int32 size);
54 /* Read a tape block of size 16K */
56 readblock(char *buffer)
58 u_int nread, total = 0;
61 while (total < BUTM_BLOCKSIZE) {
62 rc = USD_READ(fd, buffer + total, BUTM_BLOCKSIZE - total, &nread);
65 } else if ((nread == 0) && (total == 0)) {
67 fprintf(stderr, "Hardware file mark\n");
71 "Greater than 3 hardware file marks in a row - done\n");
74 } else if (nread == 0) {
75 fprintf(stderr, "Reached unexpected end of dump file\n");
85 printLabel(struct tapeLabel *tapeLabelPtr)
87 tapeLabelPtr->label.dumpid = ntohl(tapeLabelPtr->label.dumpid);
88 tapeLabelPtr->label.creationTime =
89 ntohl(tapeLabelPtr->label.creationTime);
90 tapeLabelPtr->label.expirationDate =
91 ntohl(tapeLabelPtr->label.expirationDate);
92 tapeLabelPtr->label.structVersion =
93 ntohl(tapeLabelPtr->label.structVersion);
94 tapeLabelPtr->label.useCount = ntohl(tapeLabelPtr->label.useCount);
95 tapeLabelPtr->label.size = ntohl(tapeLabelPtr->label.size);
97 fprintf(stderr, "\nDUMP %u\n", tapeLabelPtr->label.dumpid);
101 fprintf(stderr, " AFS Tape Name : %s\n",
102 tapeLabelPtr->label.AFSName);
103 fprintf(stderr, " Permanent Name : %s\n",
104 tapeLabelPtr->label.pName);
105 fprintf(stderr, " Dump Id : %u\n",
106 tapeLabelPtr->label.dumpid);
107 t = tapeLabelPtr->label.dumpid;
108 fprintf(stderr, " Dump Id Time : %.24s\n",
110 t = tapeLabelPtr->label.creationTime;
111 fprintf(stderr, " Date Created : %.24s\n",
113 t = tapeLabelPtr->label.expirationDate;
114 fprintf(stderr, " Date Expires : %.24s\n",
116 fprintf(stderr, " Version Number : %d\n",
117 tapeLabelPtr->label.structVersion);
118 fprintf(stderr, " Tape Use Count : %d\n",
119 tapeLabelPtr->label.useCount);
120 fprintf(stderr, " Tape Size : %u\n",
121 tapeLabelPtr->label.size);
122 fprintf(stderr, " Comment : %s\n",
123 tapeLabelPtr->label.comment);
124 fprintf(stderr, " Dump Path : %s\n",
125 tapeLabelPtr->label.dumpPath);
126 fprintf(stderr, " Cell Name : %s\n",
127 tapeLabelPtr->label.cell);
128 fprintf(stderr, " Creator Name : %s\n",
129 tapeLabelPtr->label.creator.name);
130 fprintf(stderr, " Creator Instance : %s\n",
131 tapeLabelPtr->label.creator.instance);
132 fprintf(stderr, " Creator Cell : %s\n",
133 tapeLabelPtr->label.creator.cell);
138 printHeader(struct volumeHeader *headerPtr, afs_int32 *isvolheader)
140 static int volcount = 0;
143 headerPtr->volumeID = ntohl(headerPtr->volumeID);
144 headerPtr->server = ntohl(headerPtr->server);
145 headerPtr->part = ntohl(headerPtr->part);
146 headerPtr->from = ntohl(headerPtr->from);
147 headerPtr->frag = ntohl(headerPtr->frag);
148 headerPtr->magic = ntohl(headerPtr->magic);
149 headerPtr->contd = ntohl(headerPtr->contd);
150 headerPtr->dumpID = ntohl(headerPtr->dumpID);
151 headerPtr->level = ntohl(headerPtr->level);
152 headerPtr->parentID = ntohl(headerPtr->parentID);
153 headerPtr->endTime = ntohl(headerPtr->endTime);
154 headerPtr->versionflags = ntohl(headerPtr->versionflags);
155 headerPtr->cloneDate = ntohl(headerPtr->cloneDate);
157 if (headerPtr->magic == TC_VOLBEGINMAGIC) {
162 fprintf(stderr, "Volume header\n");
165 "VOLUME %3d %s (%u) - %s dump from %.24s",
166 ++volcount, headerPtr->volumeName, headerPtr->volumeID,
167 (headerPtr->level ? "Incr" : "Full"),
168 (t ? (char *)ctime(&t) : "0"));
169 /* do not include two ctime() calls in the same fprintf call as
170 * the same string buffer will be returned by each call. */
171 t = headerPtr->cloneDate;
172 fprintf(stderr, " till %.24s\n", ctime(&t));
174 fprintf(stderr, " Volume Name = %s\n",
175 headerPtr->volumeName);
176 fprintf(stderr, " Volume ID = %u\n", headerPtr->volumeID);
177 t = headerPtr->cloneDate;
178 fprintf(stderr, " Clone Date = %.24s\n",
180 fprintf(stderr, " Vol Fragment = %d\n", headerPtr->frag);
181 fprintf(stderr, " Vol Continued = 0x%x\n", headerPtr->contd);
182 fprintf(stderr, " DumpSet Name = %s\n",
183 headerPtr->dumpSetName);
184 fprintf(stderr, " Dump ID = %u\n", headerPtr->dumpID);
185 fprintf(stderr, " Dump Level = %d\n", headerPtr->level);
187 fprintf(stderr, " Dump Since = %.24s\n",
189 fprintf(stderr, " parent Dump ID = %u\n", headerPtr->parentID);
191 } else if (headerPtr->magic == TC_VOLENDMAGIC) {
193 fprintf(stderr, "Volume Trailer\n");
195 fprintf(stderr, "Unrecognized Volume Header/Trailer\n");
200 openOutFile(struct volumeHeader *headerPtr)
209 /* If we were asked to skip this volume, then skip it */
214 /* Skip if we are not to restore any */
218 /* Get the volume name and strip off the BK or RO extension */
220 strcpy(filename, outfile);
222 strcpy(filename, headerPtr->volumeName);
223 len = strlen(filename);
224 if ((len > 7) && (strcmp(".backup", filename + len - 7) == 0)) {
225 filename[len - 7] = 0;
227 && (strcmp(".readonly", filename + len - 9) == 0)) {
228 filename[len - 9] = 0;
235 printf("Press return to retreive volume %s (%u) to file %s; " "s"
236 " to skip\n", headerPtr->volumeName, headerPtr->volumeID,
240 if ((first == 1) && (ch == 's'))
242 if ((first == 1) && (ch == 'q'))
245 } while (ch != '\n');
247 printf("Will not restore volume %s\n", headerPtr->volumeName);
251 printf("Retrieve volume %s (%u) to file %s\n", headerPtr->volumeName,
252 headerPtr->volumeID, filename);
255 /* Should I append the date onto the end of the name? */
257 /* Open the file to write to */
258 if (headerPtr->contd == TC_VOLCONTD) {
259 /* Continuation of dump */
260 oflag = USD_OPEN_RDWR;
262 /* An all new dump */
263 oflag = USD_OPEN_RDWR | USD_OPEN_CREATE;
265 rc = usd_Open(filename, oflag, 0664, &ofd);
267 fprintf(stderr, "Unable to open file %s. Skipping. Code = %d\n",
272 if (headerPtr->contd != TC_VOLCONTD) {
274 rc = USD_IOCTL(ofd, USD_IOCTL_SETSIZE, &size);
276 fprintf(stderr, "Unable to open file %s. Skipping. Code = %d\n",
288 writeLastBlocks(char *lastblock, char *lastblock2)
292 struct blockMark *bmark, *bmark2;
301 bmark = (struct blockMark *)lastblock;
302 data = &lastblock[sizeof(struct blockMark)];
303 count = ntohl(bmark->count);
305 bmark2 = (struct blockMark *)lastblock2;
306 data2 = &lastblock2[sizeof(struct blockMark)];
307 count2 = ntohl(bmark2->count);
313 * Strip off all but the last twelve bytes of the volume trailer
315 skip = sizeof(struct volumeHeader) - 12;
317 count = count - skip;
318 } else if (count + count2 >= skip) {
319 count2 = count2 - (skip - count);
322 fprintf(stderr, "Failed to strip off volume trailer (1).\n");
326 /* volume trailer is somewhere in the last 12 bytes of the tape file.
327 * The volume trailer may span tape blocks. */
330 memcpy(trailer, data + (count - 12), 12);
333 memcpy(trailer, data2 + (count2 - tlen), tlen);
335 memcpy(trailer + tlen, data, count);
339 for (pos = 0; pos <= 2; pos++) {
340 if (strncmp(&trailer[pos], "H++NAME#", 8) == 0) {
349 fprintf(stderr, "Failed to strip off volume trailer (2).\n");
351 if (count2 - tlen > 0) {
352 rc = writeData(data2, count2 - tlen);
354 if ((tlen == 0) && (count > 12 - pos)) {
355 rc = writeData(data, count - (12 - pos));
370 /* Decrement the number of volumes to restore */
376 writeData(char *data, afs_int32 size)
383 rc = USD_WRITE(ofd, data, (u_int) size, &nwritten);
385 fprintf(stderr, "Unable to write volume data to file. Code = %d\n",
392 WorkerBee(struct cmd_syndesc *as, void *arock)
395 struct tapeLabel *label;
396 struct fileMark *fmark;
398 struct blockMark *bmark;
399 afs_int32 isheader, isdatablock;
403 struct volumeHeader *volheaderPtr = NULL;
406 char *nextblock; /* We cycle through three tape blocks so we */
407 char *lastblock; /* can trim off the volume trailer from the */
408 char *lastblock2; /* end of each volume without having to back */
409 char *tapeblock1; /* up the output stream. */
413 tapedev = as->parms[0].items->data; /* -tape */
415 (as->parms[1].items ? atol(as->parms[1].items->data) : 0x7fffffff);
416 nskip = (as->parms[2].items ? atol(as->parms[2].items->data) : 0);
417 if (as->parms[4].items)
418 nskip = 0x7fffffff; /* -scan */
419 outfile = (as->parms[3].items ? as->parms[3].items->data : 0);
420 ask = (as->parms[5].items ? 0 : 1); /* -noask */
421 printlabels = (as->parms[6].items ? 1 : 0); /* -label */
422 printheaders = (as->parms[7].items ? 1 : 0); /* -vheaders */
423 verbose = (as->parms[8].items ? 1 : 0); /* -verbose */
425 /* Open the tape device */
426 rc = usd_Open(tapedev, USD_OPEN_RDONLY, 0, &fd);
428 printf("Failed to open tape device %s. Code = %d\n", tapedev, rc);
433 * Initialize the tape block buffers
435 tapeblock1 = (char *)malloc(3 * 16384);
436 if (tapeblock1 == NULL) {
437 printf("Failed to allocate I/O buffers.\n");
440 tapeblock2 = tapeblock1 + 16384;
441 tapeblock3 = tapeblock2 + 16384;
443 nextblock = tapeblock1;
447 /* Read each tape block deciding what to do with it */
448 do { /* while ((nskip!=0) && (nrestore!=0)) */
449 code = readblock(nextblock);
452 fprintf(stderr, "Tape device read error: %d\n", code);
457 /* A data block can be either a volume header, volume trailer,
458 * or actual data from a dump.
460 bmark = (struct blockMark *)nextblock;
461 label = (struct tapeLabel *)nextblock;
462 fmark = (struct fileMark *)nextblock;
463 if (ntohl(bmark->magic) == BLOCK_MAGIC) {
465 printf("Data block\n");
468 data = &nextblock[sizeof(struct blockMark)];
469 if (strncmp(data, "H++NAME#", 8) == 0) {
470 volheaderPtr = (struct volumeHeader *)data;
471 printHeader(volheaderPtr, &isheader);
474 code = openOutFile(volheaderPtr);
475 nextblock = tapeblock1;
479 if (lastblock2 != NULL) {
480 data = &lastblock2[sizeof(struct blockMark)];
481 bmark = (struct blockMark *)lastblock2;
482 code = writeData(data, ntohl(bmark->count));
484 } else if (lastblock != NULL) {
489 lastblock2 = lastblock;
490 lastblock = nextblock;
495 /* Filemarks come in 3 forms: BEGIN, END, and EOD.
496 * There is no information stored in filemarks.
498 else if (ntohl(fmark->magic) == FILE_MAGIC) {
499 fmtype = ntohl(fmark->nBytes);
500 if (fmtype == FILE_BEGIN) {
502 fprintf(stderr, "File mark volume begin\n");
503 } else if (fmtype == FILE_END) {
505 fprintf(stderr, "File mark volume end\n");
506 } else if (fmtype == FILE_EOD) {
508 fprintf(stderr, "File mark end-of-dump\n");
514 else if (ntohl(label->magic) == TAPE_MAGIC) {
516 fprintf(stderr, "Dump label\n");
523 fprintf(stderr, "Unrecognized tape block - end\n");
527 /* Anything other than a data block closes the out file.
528 * At this point nextblock contains the end of tape file mark,
529 * lastblock contains the last data block for the current volume,
530 * and lastblock2 contains the second to last block for the current
531 * volume. If the volume fits in a single block, lastblock2 will
532 * be NULL. Call writeLastBlocks to strip off the dump trailer before
533 * writing the last of the volume data to the dump file. The dump
534 * trailer may span block boundaries.
536 if (!isdatablock && lastblock) {
537 writeLastBlocks(lastblock, lastblock2);
539 nextblock = tapeblock1;
543 } while ((nskip != 0) || (nrestore != 0));
551 main(int argc, char **argv)
553 struct cmd_syndesc *ts;
557 ts = cmd_CreateSyntax(NULL, WorkerBee, NULL,
558 "Restore volumes from backup tape");
559 cmd_AddParm(ts, "-tape", CMD_SINGLE, CMD_REQUIRED, "tape device");
560 cmd_AddParm(ts, "-restore", CMD_SINGLE, CMD_OPTIONAL,
561 "# volumes to restore");
562 cmd_AddParm(ts, "-skip", CMD_SINGLE, CMD_OPTIONAL, "# volumes to skip");
563 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "filename");
564 cmd_AddParm(ts, "-scan", CMD_FLAG, CMD_OPTIONAL, "Scan the tape");
565 cmd_AddParm(ts, "-noask", CMD_FLAG, CMD_OPTIONAL,
566 "Prompt for each volume");
567 cmd_AddParm(ts, "-label", CMD_FLAG, CMD_OPTIONAL, "Display dump label");
568 cmd_AddParm(ts, "-vheaders", CMD_FLAG, CMD_OPTIONAL,
569 "Display volume headers");
570 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
572 return cmd_Dispatch(argc, argv);