tape.c revision 1.13 1 /*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 /*static char sccsid[] = "from: @(#)tape.c 8.3 (Berkeley) 4/1/94";*/
41 static char *rcsid = "$Id: tape.c,v 1.13 1994/09/23 14:27:57 mycroft Exp $";
42 #endif /* not lint */
43
44 #include <sys/param.h>
45 #include <sys/file.h>
46 #include <sys/ioctl.h>
47 #include <sys/mtio.h>
48 #include <sys/stat.h>
49
50 #include <ufs/ufs/dinode.h>
51 #include <protocols/dumprestore.h>
52
53 #include <errno.h>
54 #include <setjmp.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <unistd.h>
59
60 #include "restore.h"
61 #include "extern.h"
62 #include "pathnames.h"
63
64 static long fssize = MAXBSIZE;
65 static int mt = -1;
66 static int pipein = 0;
67 static char magtape[BUFSIZ];
68 static int blkcnt;
69 static int numtrec;
70 static char *tapebuf;
71 static union u_spcl endoftapemark;
72 static long blksread; /* blocks read since last header */
73 static long tpblksread = 0; /* TP_BSIZE blocks read */
74 static long tapesread;
75 static jmp_buf restart;
76 static int gettingfile = 0; /* restart has a valid frame */
77 static char *host = NULL;
78
79 static int ofile;
80 static char *map;
81 static char lnkbuf[MAXPATHLEN + 1];
82 static int pathlen;
83
84 int oldinofmt; /* old inode format conversion required */
85 int Bcvt; /* Swap Bytes (for CCI or sun) */
86 static int Qcvt; /* Swap quads (for sun) */
87
88 #define FLUSHTAPEBUF() blkcnt = ntrec + 1
89
90 static void accthdr __P((struct s_spcl *));
91 static int checksum __P((int *));
92 static void findinode __P((struct s_spcl *));
93 static void findtapeblksize __P((void));
94 static int gethead __P((struct s_spcl *));
95 static void readtape __P((char *));
96 static void setdumpnum __P((void));
97 static u_long swabl __P((u_long));
98 static u_char *swablong __P((u_char *, int));
99 static u_char *swabshort __P((u_char *, int));
100 static void terminateinput __P((void));
101 static void xtrfile __P((char *, long));
102 static void xtrlnkfile __P((char *, long));
103 static void xtrlnkskip __P((char *, long));
104 static void xtrmap __P((char *, long));
105 static void xtrmapskip __P((char *, long));
106 static void xtrskip __P((char *, long));
107
108 /*
109 * Set up an input source
110 */
111 void
112 setinput(source)
113 char *source;
114 {
115 FLUSHTAPEBUF();
116 if (bflag)
117 newtapebuf(ntrec);
118 else
119 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
120 terminal = stdin;
121
122 #ifdef RRESTORE
123 if (strchr(source, ':')) {
124 host = source;
125 source = strchr(host, ':');
126 *source++ = '\0';
127 if (rmthost(host) == 0)
128 done(1);
129 } else
130 #endif
131 if (strcmp(source, "-") == 0) {
132 /*
133 * Since input is coming from a pipe we must establish
134 * our own connection to the terminal.
135 */
136 terminal = fopen(_PATH_TTY, "r");
137 if (terminal == NULL) {
138 (void)fprintf(stderr, "cannot open %s: %s\n",
139 _PATH_TTY, strerror(errno));
140 terminal = fopen(_PATH_DEVNULL, "r");
141 if (terminal == NULL) {
142 (void)fprintf(stderr, "cannot open %s: %s\n",
143 _PATH_DEVNULL, strerror(errno));
144 done(1);
145 }
146 }
147 pipein++;
148 }
149 setuid(getuid()); /* no longer need or want root privileges */
150 (void) strcpy(magtape, source);
151 }
152
153 void
154 newtapebuf(size)
155 long size;
156 {
157 static tapebufsize = -1;
158
159 ntrec = size;
160 if (size <= tapebufsize)
161 return;
162 if (tapebuf != NULL)
163 free(tapebuf);
164 tapebuf = malloc(size * TP_BSIZE);
165 if (tapebuf == NULL) {
166 fprintf(stderr, "Cannot allocate space for tape buffer\n");
167 done(1);
168 }
169 tapebufsize = size;
170 }
171
172 /*
173 * Verify that the tape drive can be accessed and
174 * that it actually is a dump tape.
175 */
176 void
177 setup()
178 {
179 int i, j, *ip;
180 struct stat stbuf;
181
182 vprintf(stdout, "Verify tape and initialize maps\n");
183 #ifdef RRESTORE
184 if (host)
185 mt = rmtopen(magtape, 0);
186 else
187 #endif
188 if (pipein)
189 mt = 0;
190 else
191 mt = open(magtape, O_RDONLY, 0);
192 if (mt < 0) {
193 fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
194 done(1);
195 }
196 volno = 1;
197 setdumpnum();
198 FLUSHTAPEBUF();
199 if (!pipein && !bflag)
200 findtapeblksize();
201 if (gethead(&spcl) == FAIL) {
202 blkcnt--; /* push back this block */
203 blksread--;
204 tpblksread--;
205 cvtflag++;
206 if (gethead(&spcl) == FAIL) {
207 fprintf(stderr, "Tape is not a dump tape\n");
208 done(1);
209 }
210 fprintf(stderr, "Converting to new file system format.\n");
211 }
212 if (pipein) {
213 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
214 endoftapemark.s_spcl.c_type = TS_END;
215 ip = (int *)&endoftapemark;
216 j = sizeof(union u_spcl) / sizeof(int);
217 i = 0;
218 do
219 i += *ip++;
220 while (--j);
221 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
222 }
223 if (vflag || command == 't')
224 printdumpinfo();
225 dumptime = spcl.c_ddate;
226 dumpdate = spcl.c_date;
227 if (stat(".", &stbuf) < 0) {
228 fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
229 done(1);
230 }
231 if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
232 fssize = stbuf.st_blksize;
233 if (((fssize - 1) & fssize) != 0) {
234 fprintf(stderr, "bad block size %d\n", fssize);
235 done(1);
236 }
237 if (spcl.c_volume != 1) {
238 fprintf(stderr, "Tape is not volume 1 of the dump\n");
239 done(1);
240 }
241 if (gethead(&spcl) == FAIL) {
242 dprintf(stdout, "header read failed at %d blocks\n", blksread);
243 panic("no header after volume mark!\n");
244 }
245 findinode(&spcl);
246 if (spcl.c_type != TS_CLRI) {
247 fprintf(stderr, "Cannot find file removal list\n");
248 done(1);
249 }
250 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
251 dprintf(stdout, "maxino = %d\n", maxino);
252 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
253 if (map == NULL)
254 panic("no memory for file removal list\n");
255 clrimap = map;
256 curfile.action = USING;
257 getfile(xtrmap, xtrmapskip);
258 if (spcl.c_type != TS_BITS) {
259 fprintf(stderr, "Cannot find file dump list\n");
260 done(1);
261 }
262 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
263 if (map == (char *)NULL)
264 panic("no memory for file dump list\n");
265 dumpmap = map;
266 curfile.action = USING;
267 getfile(xtrmap, xtrmapskip);
268 }
269
270 /*
271 * Prompt user to load a new dump volume.
272 * "Nextvol" is the next suggested volume to use.
273 * This suggested volume is enforced when doing full
274 * or incremental restores, but can be overrridden by
275 * the user when only extracting a subset of the files.
276 */
277 void
278 getvol(nextvol)
279 long nextvol;
280 {
281 long newvol, savecnt, wantnext, i;
282 union u_spcl tmpspcl;
283 # define tmpbuf tmpspcl.s_spcl
284 char buf[TP_BSIZE];
285
286 if (nextvol == 1) {
287 tapesread = 0;
288 gettingfile = 0;
289 }
290 if (pipein) {
291 if (nextvol != 1)
292 panic("Changing volumes on pipe input?\n");
293 if (volno == 1)
294 return;
295 goto gethdr;
296 }
297 savecnt = blksread;
298 again:
299 if (pipein)
300 done(1); /* pipes do not get a second chance */
301 if (command == 'R' || command == 'r' || curfile.action != SKIP) {
302 newvol = nextvol;
303 wantnext = 1;
304 } else {
305 newvol = 0;
306 wantnext = 0;
307 }
308 while (newvol <= 0) {
309 if (tapesread == 0) {
310 fprintf(stderr, "%s%s%s%s%s",
311 "You have not read any tapes yet.\n",
312 "Unless you know which volume your",
313 " file(s) are on you should start\n",
314 "with the last volume and work",
315 " towards towards the first.\n");
316 } else {
317 fprintf(stderr, "You have read volumes");
318 strcpy(buf, ": ");
319 for (i = 1; i < 32; i++)
320 if (tapesread & (1 << i)) {
321 fprintf(stderr, "%s%d", buf, i);
322 strcpy(buf, ", ");
323 }
324 fprintf(stderr, "\n");
325 }
326 do {
327 fprintf(stderr, "Specify next volume #: ");
328 (void) fflush(stderr);
329 (void) fgets(buf, BUFSIZ, terminal);
330 } while (!feof(terminal) && buf[0] == '\n');
331 if (feof(terminal))
332 done(1);
333 newvol = atoi(buf);
334 if (newvol <= 0) {
335 fprintf(stderr,
336 "Volume numbers are positive numerics\n");
337 }
338 }
339 if (newvol == volno) {
340 tapesread |= 1 << volno;
341 return;
342 }
343 closemt();
344 fprintf(stderr, "Mount tape volume %d\n", newvol);
345 fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
346 fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
347 (void) fflush(stderr);
348 (void) fgets(buf, BUFSIZ, terminal);
349 if (feof(terminal))
350 done(1);
351 if (!strcmp(buf, "none\n")) {
352 terminateinput();
353 return;
354 }
355 if (buf[0] != '\n') {
356 (void) strcpy(magtape, buf);
357 magtape[strlen(magtape) - 1] = '\0';
358 }
359 #ifdef RRESTORE
360 if (host)
361 mt = rmtopen(magtape, 0);
362 else
363 #endif
364 mt = open(magtape, O_RDONLY, 0);
365
366 if (mt == -1) {
367 fprintf(stderr, "Cannot open %s\n", magtape);
368 volno = -1;
369 goto again;
370 }
371 gethdr:
372 volno = newvol;
373 setdumpnum();
374 FLUSHTAPEBUF();
375 if (gethead(&tmpbuf) == FAIL) {
376 dprintf(stdout, "header read failed at %d blocks\n", blksread);
377 fprintf(stderr, "tape is not dump tape\n");
378 volno = 0;
379 goto again;
380 }
381 if (tmpbuf.c_volume != volno) {
382 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
383 volno = 0;
384 goto again;
385 }
386 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
387 fprintf(stderr, "Wrong dump date\n\tgot: %s",
388 ctime(&tmpbuf.c_date));
389 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
390 volno = 0;
391 goto again;
392 }
393 tapesread |= 1 << volno;
394 blksread = savecnt;
395 /*
396 * If continuing from the previous volume, skip over any
397 * blocks read already at the end of the previous volume.
398 *
399 * If coming to this volume at random, skip to the beginning
400 * of the next record.
401 */
402 dprintf(stdout, "read %ld recs, tape starts with %ld\n",
403 tpblksread, tmpbuf.c_firstrec);
404 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
405 if (!wantnext) {
406 tpblksread = tmpbuf.c_firstrec;
407 for (i = tmpbuf.c_count; i > 0; i--)
408 readtape(buf);
409 } else if (tmpbuf.c_firstrec > 0 &&
410 tmpbuf.c_firstrec < tpblksread - 1) {
411 /*
412 * -1 since we've read the volume header
413 */
414 i = tpblksread - tmpbuf.c_firstrec - 1;
415 dprintf(stderr, "Skipping %d duplicate record%s.\n",
416 i, i > 1 ? "s" : "");
417 while (--i >= 0)
418 readtape(buf);
419 }
420 }
421 if (curfile.action == USING) {
422 if (volno == 1)
423 panic("active file into volume 1\n");
424 return;
425 }
426 /*
427 * Skip up to the beginning of the next record
428 */
429 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
430 for (i = tmpbuf.c_count; i > 0; i--)
431 readtape(buf);
432 (void) gethead(&spcl);
433 findinode(&spcl);
434 if (gettingfile) {
435 gettingfile = 0;
436 longjmp(restart, 1);
437 }
438 }
439
440 /*
441 * Handle unexpected EOF.
442 */
443 static void
444 terminateinput()
445 {
446
447 if (gettingfile && curfile.action == USING) {
448 printf("Warning: %s %s\n",
449 "End-of-input encountered while extracting", curfile.name);
450 }
451 curfile.name = "<name unknown>";
452 curfile.action = UNKNOWN;
453 curfile.dip = NULL;
454 curfile.ino = maxino;
455 if (gettingfile) {
456 gettingfile = 0;
457 longjmp(restart, 1);
458 }
459 }
460
461 /*
462 * handle multiple dumps per tape by skipping forward to the
463 * appropriate one.
464 */
465 static void
466 setdumpnum()
467 {
468 struct mtop tcom;
469
470 if (dumpnum == 1 || volno != 1)
471 return;
472 if (pipein) {
473 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
474 done(1);
475 }
476 tcom.mt_op = MTFSF;
477 tcom.mt_count = dumpnum - 1;
478 #ifdef RRESTORE
479 if (host)
480 rmtioctl(MTFSF, dumpnum - 1);
481 else
482 #endif
483 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
484 fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
485 }
486
487 void
488 printdumpinfo()
489 {
490 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
491 fprintf(stdout, "Dumped from: %s",
492 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
493 if (spcl.c_host[0] == '\0')
494 return;
495 fprintf(stderr, "Level %d dump of %s on %s:%s\n",
496 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
497 fprintf(stderr, "Label: %s\n", spcl.c_label);
498 }
499
500 int
501 extractfile(name)
502 char *name;
503 {
504 int mode;
505 struct timeval timep[2];
506 struct entry *ep;
507
508 curfile.name = name;
509 curfile.action = USING;
510 timep[0].tv_sec = curfile.dip->di_atime.ts_sec;
511 timep[0].tv_usec = curfile.dip->di_atime.ts_nsec / 1000;
512 timep[1].tv_sec = curfile.dip->di_mtime.ts_sec;
513 timep[1].tv_usec = curfile.dip->di_mtime.ts_nsec / 1000;
514 mode = curfile.dip->di_mode;
515 switch (mode & IFMT) {
516
517 default:
518 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
519 skipfile();
520 return (FAIL);
521
522 case IFSOCK:
523 vprintf(stdout, "skipped socket %s\n", name);
524 skipfile();
525 return (GOOD);
526
527 case IFDIR:
528 if (mflag) {
529 ep = lookupname(name);
530 if (ep == NULL || ep->e_flags & EXTRACT)
531 panic("unextracted directory %s\n", name);
532 skipfile();
533 return (GOOD);
534 }
535 vprintf(stdout, "extract file %s\n", name);
536 return (genliteraldir(name, curfile.ino));
537
538 case IFLNK:
539 lnkbuf[0] = '\0';
540 pathlen = 0;
541 getfile(xtrlnkfile, xtrlnkskip);
542 if (pathlen == 0) {
543 vprintf(stdout,
544 "%s: zero length symbolic link (ignored)\n", name);
545 return (GOOD);
546 }
547 return (linkit(lnkbuf, name, SYMLINK));
548
549 case IFIFO:
550 vprintf(stdout, "extract fifo %s\n", name);
551 if (Nflag) {
552 skipfile();
553 return (GOOD);
554 }
555 if (mkfifo(name, mode) < 0) {
556 fprintf(stderr, "%s: cannot create fifo: %s\n",
557 name, strerror(errno));
558 skipfile();
559 return (FAIL);
560 }
561 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
562 (void) chmod(name, mode);
563 skipfile();
564 utimes(name, timep);
565 return (GOOD);
566
567 case IFCHR:
568 case IFBLK:
569 vprintf(stdout, "extract special file %s\n", name);
570 if (Nflag) {
571 skipfile();
572 return (GOOD);
573 }
574 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
575 fprintf(stderr, "%s: cannot create special file: %s\n",
576 name, strerror(errno));
577 skipfile();
578 return (FAIL);
579 }
580 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
581 (void) chmod(name, mode);
582 skipfile();
583 utimes(name, timep);
584 return (GOOD);
585
586 case IFREG:
587 vprintf(stdout, "extract file %s\n", name);
588 if (Nflag) {
589 skipfile();
590 return (GOOD);
591 }
592 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
593 0666)) < 0) {
594 fprintf(stderr, "%s: cannot create file: %s\n",
595 name, strerror(errno));
596 skipfile();
597 return (FAIL);
598 }
599 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
600 (void) fchmod(ofile, mode);
601 getfile(xtrfile, xtrskip);
602 (void) close(ofile);
603 utimes(name, timep);
604 return (GOOD);
605 }
606 /* NOTREACHED */
607 }
608
609 /*
610 * skip over bit maps on the tape
611 */
612 void
613 skipmaps()
614 {
615
616 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
617 skipfile();
618 }
619
620 /*
621 * skip over a file on the tape
622 */
623 void
624 skipfile()
625 {
626
627 curfile.action = SKIP;
628 getfile(xtrnull, xtrnull);
629 }
630
631 /*
632 * Extract a file from the tape.
633 * When an allocated block is found it is passed to the fill function;
634 * when an unallocated block (hole) is found, a zeroed buffer is passed
635 * to the skip function.
636 */
637 void
638 getfile(fill, skip)
639 void (*fill) __P((char *, long));
640 void (*skip) __P((char *, long));
641 {
642 register int i;
643 int curblk = 0;
644 long size = spcl.c_dinode.di_size;
645 static char clearedbuf[MAXBSIZE];
646 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
647 char junk[TP_BSIZE];
648
649 if (spcl.c_type == TS_END)
650 panic("ran off end of tape\n");
651 if (spcl.c_magic != NFS_MAGIC)
652 panic("not at beginning of a file\n");
653 if (!gettingfile && setjmp(restart) != 0)
654 return;
655 gettingfile++;
656 loop:
657 for (i = 0; i < spcl.c_count; i++) {
658 if (spcl.c_addr[i]) {
659 readtape(&buf[curblk++][0]);
660 if (curblk == fssize / TP_BSIZE) {
661 (*fill)((char *)buf, size > TP_BSIZE ?
662 (long) (fssize) :
663 (curblk - 1) * TP_BSIZE + size);
664 curblk = 0;
665 }
666 } else {
667 if (curblk > 0) {
668 (*fill)((char *)buf, size > TP_BSIZE ?
669 (long) (curblk * TP_BSIZE) :
670 (curblk - 1) * TP_BSIZE + size);
671 curblk = 0;
672 }
673 (*skip)(clearedbuf, size > TP_BSIZE ?
674 (long) TP_BSIZE : size);
675 }
676 if ((size -= TP_BSIZE) <= 0) {
677 for (i++; i < spcl.c_count; i++)
678 if (spcl.c_addr[i])
679 readtape(junk);
680 break;
681 }
682 }
683 if (gethead(&spcl) == GOOD && size > 0) {
684 if (spcl.c_type == TS_ADDR)
685 goto loop;
686 dprintf(stdout,
687 "Missing address (header) block for %s at %d blocks\n",
688 curfile.name, blksread);
689 }
690 if (curblk > 0)
691 (*fill)((char *)buf, (curblk * TP_BSIZE) + size);
692 findinode(&spcl);
693 gettingfile = 0;
694 }
695
696 /*
697 * Write out the next block of a file.
698 */
699 static void
700 xtrfile(buf, size)
701 char *buf;
702 long size;
703 {
704
705 if (Nflag)
706 return;
707 if (write(ofile, buf, (int) size) == -1) {
708 fprintf(stderr,
709 "write error extracting inode %d, name %s\nwrite: %s\n",
710 curfile.ino, curfile.name, strerror(errno));
711 done(1);
712 }
713 }
714
715 /*
716 * Skip over a hole in a file.
717 */
718 /* ARGSUSED */
719 static void
720 xtrskip(buf, size)
721 char *buf;
722 long size;
723 {
724
725 if (lseek(ofile, size, SEEK_CUR) == -1) {
726 fprintf(stderr,
727 "seek error extracting inode %d, name %s\nlseek: %s\n",
728 curfile.ino, curfile.name, strerror(errno));
729 done(1);
730 }
731 }
732
733 /*
734 * Collect the next block of a symbolic link.
735 */
736 static void
737 xtrlnkfile(buf, size)
738 char *buf;
739 long size;
740 {
741
742 pathlen += size;
743 if (pathlen > MAXPATHLEN) {
744 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
745 curfile.name, lnkbuf, buf, pathlen);
746 done(1);
747 }
748 (void) strcat(lnkbuf, buf);
749 }
750
751 /*
752 * Skip over a hole in a symbolic link (should never happen).
753 */
754 /* ARGSUSED */
755 static void
756 xtrlnkskip(buf, size)
757 char *buf;
758 long size;
759 {
760
761 fprintf(stderr, "unallocated block in symbolic link %s\n",
762 curfile.name);
763 done(1);
764 }
765
766 /*
767 * Collect the next block of a bit map.
768 */
769 static void
770 xtrmap(buf, size)
771 char *buf;
772 long size;
773 {
774
775 memcpy(map, buf, size);
776 map += size;
777 }
778
779 /*
780 * Skip over a hole in a bit map (should never happen).
781 */
782 /* ARGSUSED */
783 static void
784 xtrmapskip(buf, size)
785 char *buf;
786 long size;
787 {
788
789 panic("hole in map\n");
790 map += size;
791 }
792
793 /*
794 * Noop, when an extraction function is not needed.
795 */
796 /* ARGSUSED */
797 void
798 xtrnull(buf, size)
799 char *buf;
800 long size;
801 {
802
803 return;
804 }
805
806 /*
807 * Read TP_BSIZE blocks from the input.
808 * Handle read errors, and end of media.
809 */
810 static void
811 readtape(buf)
812 char *buf;
813 {
814 long rd, newvol, i;
815 int cnt, seek_failed;
816
817 if (blkcnt < numtrec) {
818 memcpy(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
819 blksread++;
820 tpblksread++;
821 return;
822 }
823 for (i = 0; i < ntrec; i++)
824 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
825 if (numtrec == 0)
826 numtrec = ntrec;
827 cnt = ntrec * TP_BSIZE;
828 rd = 0;
829 getmore:
830 #ifdef RRESTORE
831 if (host)
832 i = rmtread(&tapebuf[rd], cnt);
833 else
834 #endif
835 i = read(mt, &tapebuf[rd], cnt);
836 /*
837 * Check for mid-tape short read error.
838 * If found, skip rest of buffer and start with the next.
839 */
840 if (!pipein && numtrec < ntrec && i > 0) {
841 dprintf(stdout, "mid-media short read error.\n");
842 numtrec = ntrec;
843 }
844 /*
845 * Handle partial block read.
846 */
847 if (pipein && i == 0 && rd > 0)
848 i = rd;
849 else if (i > 0 && i != ntrec * TP_BSIZE) {
850 if (pipein) {
851 rd += i;
852 cnt -= i;
853 if (cnt > 0)
854 goto getmore;
855 i = rd;
856 } else {
857 /*
858 * Short read. Process the blocks read.
859 */
860 if (i % TP_BSIZE != 0)
861 vprintf(stdout,
862 "partial block read: %d should be %d\n",
863 i, ntrec * TP_BSIZE);
864 numtrec = i / TP_BSIZE;
865 }
866 }
867 /*
868 * Handle read error.
869 */
870 if (i < 0) {
871 fprintf(stderr, "Tape read error while ");
872 switch (curfile.action) {
873 default:
874 fprintf(stderr, "trying to set up tape\n");
875 break;
876 case UNKNOWN:
877 fprintf(stderr, "trying to resynchronize\n");
878 break;
879 case USING:
880 fprintf(stderr, "restoring %s\n", curfile.name);
881 break;
882 case SKIP:
883 fprintf(stderr, "skipping over inode %d\n",
884 curfile.ino);
885 break;
886 }
887 if (!yflag && !reply("continue"))
888 done(1);
889 i = ntrec * TP_BSIZE;
890 memset(tapebuf, 0, i);
891 #ifdef RRESTORE
892 if (host)
893 seek_failed = (rmtseek(i, 1) < 0);
894 else
895 #endif
896 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
897
898 if (seek_failed) {
899 fprintf(stderr,
900 "continuation failed: %s\n", strerror(errno));
901 done(1);
902 }
903 }
904 /*
905 * Handle end of tape.
906 */
907 if (i == 0) {
908 vprintf(stdout, "End-of-tape encountered\n");
909 if (!pipein) {
910 newvol = volno + 1;
911 volno = 0;
912 numtrec = 0;
913 getvol(newvol);
914 readtape(buf);
915 return;
916 }
917 if (rd % TP_BSIZE != 0)
918 panic("partial block read: %d should be %d\n",
919 rd, ntrec * TP_BSIZE);
920 terminateinput();
921 memcpy(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
922 }
923 blkcnt = 0;
924 memcpy(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
925 blksread++;
926 tpblksread++;
927 }
928
929 static void
930 findtapeblksize()
931 {
932 register long i;
933
934 for (i = 0; i < ntrec; i++)
935 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
936 blkcnt = 0;
937 #ifdef RRESTORE
938 if (host)
939 i = rmtread(tapebuf, ntrec * TP_BSIZE);
940 else
941 #endif
942 i = read(mt, tapebuf, ntrec * TP_BSIZE);
943
944 if (i <= 0) {
945 fprintf(stderr, "tape read error: %s\n", strerror(errno));
946 done(1);
947 }
948 if (i % TP_BSIZE != 0) {
949 fprintf(stderr, "Tape block size (%d) %s (%d)\n",
950 i, "is not a multiple of dump block size", TP_BSIZE);
951 done(1);
952 }
953 ntrec = i / TP_BSIZE;
954 numtrec = ntrec;
955 vprintf(stdout, "Tape block size is %d\n", ntrec);
956 }
957
958 void
959 closemt()
960 {
961
962 if (mt < 0)
963 return;
964 #ifdef RRESTORE
965 if (host)
966 rmtclose();
967 else
968 #endif
969 (void) close(mt);
970 }
971
972 /*
973 * Read the next block from the tape.
974 * Check to see if it is one of several vintage headers.
975 * If it is an old style header, convert it to a new style header.
976 * If it is not any valid header, return an error.
977 */
978 static int
979 gethead(buf)
980 struct s_spcl *buf;
981 {
982 long i;
983 union {
984 quad_t qval;
985 long val[2];
986 } qcvt;
987 union u_ospcl {
988 char dummy[TP_BSIZE];
989 struct s_ospcl {
990 long c_type;
991 long c_date;
992 long c_ddate;
993 long c_volume;
994 long c_tapea;
995 u_short c_inumber;
996 long c_magic;
997 long c_checksum;
998 struct odinode {
999 unsigned short odi_mode;
1000 u_short odi_nlink;
1001 u_short odi_uid;
1002 u_short odi_gid;
1003 long odi_size;
1004 long odi_rdev;
1005 char odi_addr[36];
1006 long odi_atime;
1007 long odi_mtime;
1008 long odi_ctime;
1009 } c_dinode;
1010 long c_count;
1011 char c_addr[256];
1012 } s_ospcl;
1013 } u_ospcl;
1014
1015 if (!cvtflag) {
1016 readtape((char *)buf);
1017 if (buf->c_magic != NFS_MAGIC) {
1018 if (swabl(buf->c_magic) != NFS_MAGIC)
1019 return (FAIL);
1020 if (!Bcvt) {
1021 vprintf(stdout, "Note: Doing Byte swapping\n");
1022 Bcvt = 1;
1023 }
1024 }
1025 if (checksum((int *)buf) == FAIL)
1026 return (FAIL);
1027 if (Bcvt)
1028 swabst((u_char *)"8l4s31l", (u_char *)buf);
1029 goto good;
1030 }
1031 readtape((char *)(&u_ospcl.s_ospcl));
1032 memset(buf, 0, (long)TP_BSIZE);
1033 buf->c_type = u_ospcl.s_ospcl.c_type;
1034 buf->c_date = u_ospcl.s_ospcl.c_date;
1035 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1036 buf->c_volume = u_ospcl.s_ospcl.c_volume;
1037 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1038 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1039 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1040 buf->c_magic = u_ospcl.s_ospcl.c_magic;
1041 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1042 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1043 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1044 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1045 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1046 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1047 buf->c_dinode.di_atime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
1048 buf->c_dinode.di_mtime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1049 buf->c_dinode.di_ctime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1050 buf->c_count = u_ospcl.s_ospcl.c_count;
1051 memcpy(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1052 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1053 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1054 return(FAIL);
1055 buf->c_magic = NFS_MAGIC;
1056
1057 good:
1058 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1059 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1060 qcvt.qval = buf->c_dinode.di_size;
1061 if (qcvt.val[0] || qcvt.val[1]) {
1062 printf("Note: Doing Quad swapping\n");
1063 Qcvt = 1;
1064 }
1065 }
1066 if (Qcvt) {
1067 qcvt.qval = buf->c_dinode.di_size;
1068 i = qcvt.val[1];
1069 qcvt.val[1] = qcvt.val[0];
1070 qcvt.val[0] = i;
1071 buf->c_dinode.di_size = qcvt.qval;
1072 }
1073
1074 switch (buf->c_type) {
1075
1076 case TS_CLRI:
1077 case TS_BITS:
1078 /*
1079 * Have to patch up missing information in bit map headers
1080 */
1081 buf->c_inumber = 0;
1082 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1083 for (i = 0; i < buf->c_count; i++)
1084 buf->c_addr[i]++;
1085 break;
1086
1087 case TS_TAPE:
1088 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1089 oldinofmt = 1;
1090 /* fall through */
1091 case TS_END:
1092 buf->c_inumber = 0;
1093 break;
1094
1095 case TS_INODE:
1096 case TS_ADDR:
1097 break;
1098
1099 default:
1100 panic("gethead: unknown inode type %d\n", buf->c_type);
1101 break;
1102 }
1103 /*
1104 * If we are restoring a filesystem with old format inodes,
1105 * copy the uid/gid to the new location.
1106 */
1107 if (oldinofmt) {
1108 buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1109 buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1110 }
1111 if (dflag)
1112 accthdr(buf);
1113 return(GOOD);
1114 }
1115
1116 /*
1117 * Check that a header is where it belongs and predict the next header
1118 */
1119 static void
1120 accthdr(header)
1121 struct s_spcl *header;
1122 {
1123 static ino_t previno = 0x7fffffff;
1124 static int prevtype;
1125 static long predict;
1126 long blks, i;
1127
1128 if (header->c_type == TS_TAPE) {
1129 fprintf(stderr, "Volume header (%s inode format) ",
1130 oldinofmt ? "old" : "new");
1131 if (header->c_firstrec)
1132 fprintf(stderr, "begins with record %d",
1133 header->c_firstrec);
1134 fprintf(stderr, "\n");
1135 previno = 0x7fffffff;
1136 return;
1137 }
1138 if (previno == 0x7fffffff)
1139 goto newcalc;
1140 switch (prevtype) {
1141 case TS_BITS:
1142 fprintf(stderr, "Dump mask header");
1143 break;
1144 case TS_CLRI:
1145 fprintf(stderr, "Remove mask header");
1146 break;
1147 case TS_INODE:
1148 fprintf(stderr, "File header, ino %d", previno);
1149 break;
1150 case TS_ADDR:
1151 fprintf(stderr, "File continuation header, ino %d", previno);
1152 break;
1153 case TS_END:
1154 fprintf(stderr, "End of tape header");
1155 break;
1156 }
1157 if (predict != blksread - 1)
1158 fprintf(stderr, "; predicted %d blocks, got %d blocks",
1159 predict, blksread - 1);
1160 fprintf(stderr, "\n");
1161 newcalc:
1162 blks = 0;
1163 if (header->c_type != TS_END)
1164 for (i = 0; i < header->c_count; i++)
1165 if (header->c_addr[i] != 0)
1166 blks++;
1167 predict = blks;
1168 blksread = 0;
1169 prevtype = header->c_type;
1170 previno = header->c_inumber;
1171 }
1172
1173 /*
1174 * Find an inode header.
1175 * Complain if had to skip, and complain is set.
1176 */
1177 static void
1178 findinode(header)
1179 struct s_spcl *header;
1180 {
1181 static long skipcnt = 0;
1182 long i;
1183 char buf[TP_BSIZE];
1184
1185 curfile.name = "<name unknown>";
1186 curfile.action = UNKNOWN;
1187 curfile.dip = NULL;
1188 curfile.ino = 0;
1189 do {
1190 if (header->c_magic != NFS_MAGIC) {
1191 skipcnt++;
1192 while (gethead(header) == FAIL ||
1193 header->c_date != dumpdate)
1194 skipcnt++;
1195 }
1196 switch (header->c_type) {
1197
1198 case TS_ADDR:
1199 /*
1200 * Skip up to the beginning of the next record
1201 */
1202 for (i = 0; i < header->c_count; i++)
1203 if (header->c_addr[i])
1204 readtape(buf);
1205 while (gethead(header) == FAIL ||
1206 header->c_date != dumpdate)
1207 skipcnt++;
1208 break;
1209
1210 case TS_INODE:
1211 curfile.dip = &header->c_dinode;
1212 curfile.ino = header->c_inumber;
1213 break;
1214
1215 case TS_END:
1216 curfile.ino = maxino;
1217 break;
1218
1219 case TS_CLRI:
1220 curfile.name = "<file removal list>";
1221 break;
1222
1223 case TS_BITS:
1224 curfile.name = "<file dump list>";
1225 break;
1226
1227 case TS_TAPE:
1228 panic("unexpected tape header\n");
1229 /* NOTREACHED */
1230
1231 default:
1232 panic("unknown tape header type %d\n", spcl.c_type);
1233 /* NOTREACHED */
1234
1235 }
1236 } while (header->c_type == TS_ADDR);
1237 if (skipcnt > 0)
1238 fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
1239 skipcnt = 0;
1240 }
1241
1242 static int
1243 checksum(buf)
1244 register int *buf;
1245 {
1246 register int i, j;
1247
1248 j = sizeof(union u_spcl) / sizeof(int);
1249 i = 0;
1250 if(!Bcvt) {
1251 do
1252 i += *buf++;
1253 while (--j);
1254 } else {
1255 /* What happens if we want to read restore tapes
1256 for a 16bit int machine??? */
1257 do
1258 i += swabl(*buf++);
1259 while (--j);
1260 }
1261
1262 if (i != CHECKSUM) {
1263 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1264 curfile.ino, curfile.name);
1265 return(FAIL);
1266 }
1267 return(GOOD);
1268 }
1269
1270 #ifdef RRESTORE
1271 #if __STDC__
1272 #include <stdarg.h>
1273 #else
1274 #include <varargs.h>
1275 #endif
1276
1277 void
1278 #if __STDC__
1279 msg(const char *fmt, ...)
1280 #else
1281 msg(fmt, va_alist)
1282 char *fmt;
1283 va_dcl
1284 #endif
1285 {
1286 va_list ap;
1287 #if __STDC__
1288 va_start(ap, fmt);
1289 #else
1290 va_start(ap);
1291 #endif
1292 (void)vfprintf(stderr, fmt, ap);
1293 va_end(ap);
1294 }
1295 #endif /* RRESTORE */
1296
1297 static u_char *
1298 swabshort(sp, n)
1299 register u_char *sp;
1300 register int n;
1301 {
1302 char c;
1303
1304 while (--n >= 0) {
1305 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1306 sp += 2;
1307 }
1308 return (sp);
1309 }
1310
1311 static u_char *
1312 swablong(sp, n)
1313 register u_char *sp;
1314 register int n;
1315 {
1316 char c;
1317
1318 while (--n >= 0) {
1319 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1320 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1321 sp += 4;
1322 }
1323 return (sp);
1324 }
1325
1326 void
1327 swabst(cp, sp)
1328 register u_char *cp, *sp;
1329 {
1330 int n = 0;
1331
1332 while (*cp) {
1333 switch (*cp) {
1334 case '0': case '1': case '2': case '3': case '4':
1335 case '5': case '6': case '7': case '8': case '9':
1336 n = (n * 10) + (*cp++ - '0');
1337 continue;
1338
1339 case 's': case 'w': case 'h':
1340 if (n == 0)
1341 n = 1;
1342 sp = swabshort(sp, n);
1343 break;
1344
1345 case 'l':
1346 if (n == 0)
1347 n = 1;
1348 sp = swablong(sp, n);
1349 break;
1350
1351 default: /* Any other character, like 'b' counts as byte. */
1352 if (n == 0)
1353 n = 1;
1354 sp += n;
1355 break;
1356 }
1357 cp++;
1358 n = 0;
1359 }
1360 }
1361
1362 static u_long
1363 swabl(x)
1364 u_long x;
1365 {
1366 swabst((u_char *)"l", (u_char *)&x);
1367 return (x);
1368 }
1369