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