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