set file flags; add restoration of FIFO's
[unix-history] / usr / src / sbin / restore / tape.c
index c0b3810..f539cff 100644 (file)
-#ifndef lint
-static char sccsid[] = "@(#)tape.c     3.26    (Berkeley)      85/02/18";
-#endif
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * %sccs.include.redist.c%
+ */
 
 
-/* Copyright (c) 1983 Regents of the University of California */
+#ifndef lint
+static char sccsid[] = "@(#)tape.c     8.4 (Berkeley) %G%";
+#endif /* not lint */
 
 
-#include "restore.h"
-#include <dumprestor.h>
+#include <sys/param.h>
+#include <sys/file.h>
 #include <sys/ioctl.h>
 #include <sys/mtio.h>
 #include <sys/ioctl.h>
 #include <sys/mtio.h>
-#include <sys/file.h>
-#include <setjmp.h>
 #include <sys/stat.h>
 
 #include <sys/stat.h>
 
+#include <ufs/ufs/dinode.h>
+#include <protocols/dumprestore.h>
+
+#include <errno.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "restore.h"
+#include "extern.h"
+#include "pathnames.h"
+
 static long    fssize = MAXBSIZE;
 static int     mt = -1;
 static int     pipein = 0;
 static char    magtape[BUFSIZ];
 static long    fssize = MAXBSIZE;
 static int     mt = -1;
 static int     pipein = 0;
 static char    magtape[BUFSIZ];
-static int     bct;
-static char    *tbf;
+static int     blkcnt;
+static int     numtrec;
+static char    *tapebuf;
 static union   u_spcl endoftapemark;
 static union   u_spcl endoftapemark;
-static long    blksread;
+static long    blksread;               /* blocks read since last header */
+static long    tpblksread = 0;         /* TP_BSIZE blocks read */
 static long    tapesread;
 static jmp_buf restart;
 static int     gettingfile = 0;        /* restart has a valid frame */
 static long    tapesread;
 static jmp_buf restart;
 static int     gettingfile = 0;        /* restart has a valid frame */
+static char    *host = NULL;
 
 static int     ofile;
 static char    *map;
 static char    lnkbuf[MAXPATHLEN + 1];
 static int     pathlen;
 
 
 static int     ofile;
 static char    *map;
 static char    lnkbuf[MAXPATHLEN + 1];
 static int     pathlen;
 
+int            oldinofmt;      /* old inode format conversion required */
+int            Bcvt;           /* Swap Bytes (for CCI or sun) */
+static int     Qcvt;           /* Swap quads (for sun) */
+
+#define        FLUSHTAPEBUF()  blkcnt = ntrec + 1
+
+static void     accthdr __P((struct s_spcl *));
+static int      checksum __P((int *));
+static void     findinode __P((struct s_spcl *));
+static void     findtapeblksize __P((void));
+static int      gethead __P((struct s_spcl *));
+static void     readtape __P((char *));
+static void     setdumpnum __P((void));
+static u_long   swabl __P((u_long));
+static u_char  *swablong __P((u_char *, int));
+static u_char  *swabshort __P((u_char *, int));
+static void     terminateinput __P((void));
+static void     xtrfile __P((char *, long));
+static void     xtrlnkfile __P((char *, long));
+static void     xtrlnkskip __P((char *, long));
+static void     xtrmap __P((char *, long));
+static void     xtrmapskip __P((char *, long));
+static void     xtrskip __P((char *, long));
+
 /*
  * Set up an input source
  */
 /*
  * Set up an input source
  */
+void
 setinput(source)
        char *source;
 {
 setinput(source)
        char *source;
 {
-#ifdef RRESTORE
-       char *host, *tape;
-#endif RRESTORE
-
-       flsht();
-       tbf = (char *)malloc(ntrec * TP_BSIZE);
-       if (tbf == NULL) {
-               fprintf(stderr, "Cannot allocate space for tape buffer\n");
-               done(1);
-       }
+       FLUSHTAPEBUF();
+       if (bflag)
+               newtapebuf(ntrec);
+       else
+               newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
        terminal = stdin;
        terminal = stdin;
+
 #ifdef RRESTORE
 #ifdef RRESTORE
-       host = source;
-       tape = index(host, ':');
-       if (tape == 0) {
-nohost:
-               msg("need keyletter ``f'' and device ``host:tape''\n");
-               done(1);
-       }
-       *tape++ = '\0';
-       (void) strcpy(magtape, tape);
-       if (rmthost(host) == 0)
-               done(1);
-       setuid(getuid());       /* no longer need or want root privileges */
-#else
+       if (index(source, ':')) {
+               host = source;
+               source = index(host, ':');
+               *source++ = '\0';
+               if (rmthost(host) == 0)
+                       done(1);
+       } else
+#endif
        if (strcmp(source, "-") == 0) {
                /*
                 * Since input is coming from a pipe we must establish
                 * our own connection to the terminal.
                 */
        if (strcmp(source, "-") == 0) {
                /*
                 * Since input is coming from a pipe we must establish
                 * our own connection to the terminal.
                 */
-               terminal = fopen("/dev/tty", "r");
+               terminal = fopen(_PATH_TTY, "r");
                if (terminal == NULL) {
                if (terminal == NULL) {
-                       perror("Cannot open(\"/dev/tty\")");
-                       terminal = fopen("/dev/null", "r");
+                       (void)fprintf(stderr, "cannot open %s: %s\n",
+                           _PATH_TTY, strerror(errno));
+                       terminal = fopen(_PATH_DEVNULL, "r");
                        if (terminal == NULL) {
                        if (terminal == NULL) {
-                               perror("Cannot open(\"/dev/null\")");
+                               (void)fprintf(stderr, "cannot open %s: %s\n",
+                                   _PATH_DEVNULL, strerror(errno));
                                done(1);
                        }
                }
                pipein++;
        }
                                done(1);
                        }
                }
                pipein++;
        }
+       setuid(getuid());       /* no longer need or want root privileges */
        (void) strcpy(magtape, source);
        (void) strcpy(magtape, source);
-#endif RRESTORE
+}
+
+void
+newtapebuf(size)
+       long size;
+{
+       static tapebufsize = -1;
+
+       ntrec = size;
+       if (size <= tapebufsize)
+               return;
+       if (tapebuf != NULL)
+               free(tapebuf);
+       tapebuf = malloc(size * TP_BSIZE);
+       if (tapebuf == NULL) {
+               fprintf(stderr, "Cannot allocate space for tape buffer\n");
+               done(1);
+       }
+       tapebufsize = size;
 }
 
 /*
  * Verify that the tape drive can be accessed and
  * that it actually is a dump tape.
  */
 }
 
 /*
  * Verify that the tape drive can be accessed and
  * that it actually is a dump tape.
  */
+void
 setup()
 {
        int i, j, *ip;
        struct stat stbuf;
 setup()
 {
        int i, j, *ip;
        struct stat stbuf;
-       extern char *ctime();
-       extern int xtrmap(), xtrmapskip();
 
        vprintf(stdout, "Verify tape and initialize maps\n");
 #ifdef RRESTORE
 
        vprintf(stdout, "Verify tape and initialize maps\n");
 #ifdef RRESTORE
-       if ((mt = rmtopen(magtape, 0)) < 0)
-#else
+       if (host)
+               mt = rmtopen(magtape, 0);
+       else
+#endif
        if (pipein)
                mt = 0;
        if (pipein)
                mt = 0;
-       else if ((mt = open(magtape, 0)) < 0)
-#endif
-       {
-               perror(magtape);
+       else
+               mt = open(magtape, O_RDONLY, 0);
+       if (mt < 0) {
+               fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
                done(1);
        }
        volno = 1;
        setdumpnum();
                done(1);
        }
        volno = 1;
        setdumpnum();
-       flsht();
+       FLUSHTAPEBUF();
+       if (!pipein && !bflag)
+               findtapeblksize();
        if (gethead(&spcl) == FAIL) {
        if (gethead(&spcl) == FAIL) {
-               bct--; /* push back this block */
+               blkcnt--; /* push back this block */
+               blksread--;
+               tpblksread--;
                cvtflag++;
                if (gethead(&spcl) == FAIL) {
                        fprintf(stderr, "Tape is not a dump tape\n");
                cvtflag++;
                if (gethead(&spcl) == FAIL) {
                        fprintf(stderr, "Tape is not a dump tape\n");
@@ -126,14 +193,12 @@ setup()
                while (--j);
                endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
        }
                while (--j);
                endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
        }
-       if (vflag || command == 't') {
-               fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
-               fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
-       }
+       if (vflag || command == 't')
+               printdumpinfo();
        dumptime = spcl.c_ddate;
        dumpdate = spcl.c_date;
        if (stat(".", &stbuf) < 0) {
        dumptime = spcl.c_ddate;
        dumpdate = spcl.c_date;
        if (stat(".", &stbuf) < 0) {
-               perror("cannot stat .");
+               fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
                done(1);
        }
        if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
                done(1);
        }
        if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
@@ -142,26 +207,28 @@ setup()
                fprintf(stderr, "bad block size %d\n", fssize);
                done(1);
        }
                fprintf(stderr, "bad block size %d\n", fssize);
                done(1);
        }
-       if (checkvol(&spcl, (long)1) == FAIL) {
+       if (spcl.c_volume != 1) {
                fprintf(stderr, "Tape is not volume 1 of the dump\n");
                done(1);
        }
                fprintf(stderr, "Tape is not volume 1 of the dump\n");
                done(1);
        }
-       if (readhdr(&spcl) == FAIL)
+       if (gethead(&spcl) == FAIL) {
+               dprintf(stdout, "header read failed at %d blocks\n", blksread);
                panic("no header after volume mark!\n");
                panic("no header after volume mark!\n");
-       findinode(&spcl, 1);
-       if (checktype(&spcl, TS_CLRI) == FAIL) {
+       }
+       findinode(&spcl);
+       if (spcl.c_type != TS_CLRI) {
                fprintf(stderr, "Cannot find file removal list\n");
                done(1);
        }
        maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
        dprintf(stdout, "maxino = %d\n", maxino);
        map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
                fprintf(stderr, "Cannot find file removal list\n");
                done(1);
        }
        maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
        dprintf(stdout, "maxino = %d\n", maxino);
        map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
-       if (map == (char *)NIL)
+       if (map == NULL)
                panic("no memory for file removal list\n");
        clrimap = map;
        curfile.action = USING;
        getfile(xtrmap, xtrmapskip);
                panic("no memory for file removal list\n");
        clrimap = map;
        curfile.action = USING;
        getfile(xtrmap, xtrmapskip);
-       if (checktype(&spcl, TS_BITS) == FAIL) {
+       if (spcl.c_type != TS_BITS) {
                fprintf(stderr, "Cannot find file dump list\n");
                done(1);
        }
                fprintf(stderr, "Cannot find file dump list\n");
                done(1);
        }
@@ -180,13 +247,14 @@ setup()
  * or incremental restores, but can be overrridden by
  * the user when only extracting a subset of the files.
  */
  * or incremental restores, but can be overrridden by
  * the user when only extracting a subset of the files.
  */
+void
 getvol(nextvol)
        long nextvol;
 {
 getvol(nextvol)
        long nextvol;
 {
-       long newvol;
-       long savecnt, i;
+       long newvol, savecnt, wantnext, i;
        union u_spcl tmpspcl;
 #      define tmpbuf tmpspcl.s_spcl
        union u_spcl tmpspcl;
 #      define tmpbuf tmpspcl.s_spcl
+       char buf[TP_BSIZE];
 
        if (nextvol == 1) {
                tapesread = 0;
 
        if (nextvol == 1) {
                tapesread = 0;
@@ -203,10 +271,13 @@ getvol(nextvol)
 again:
        if (pipein)
                done(1); /* pipes do not get a second chance */
 again:
        if (pipein)
                done(1); /* pipes do not get a second chance */
-       if (command == 'R' || command == 'r' || curfile.action != SKIP)
+       if (command == 'R' || command == 'r' || curfile.action != SKIP) {
                newvol = nextvol;
                newvol = nextvol;
-       else 
+               wantnext = 1;
+       } else { 
                newvol = 0;
                newvol = 0;
+               wantnext = 0;
+       }
        while (newvol <= 0) {
                if (tapesread == 0) {
                        fprintf(stderr, "%s%s%s%s%s",
        while (newvol <= 0) {
                if (tapesread == 0) {
                        fprintf(stderr, "%s%s%s%s%s",
@@ -217,22 +288,22 @@ again:
                            " towards towards the first.\n");
                } else {
                        fprintf(stderr, "You have read volumes");
                            " towards towards the first.\n");
                } else {
                        fprintf(stderr, "You have read volumes");
-                       strcpy(tbf, ": ");
+                       strcpy(buf, ": ");
                        for (i = 1; i < 32; i++)
                                if (tapesread & (1 << i)) {
                        for (i = 1; i < 32; i++)
                                if (tapesread & (1 << i)) {
-                                       fprintf(stderr, "%s%d", tbf, i);
-                                       strcpy(tbf, ", ");
+                                       fprintf(stderr, "%s%d", buf, i);
+                                       strcpy(buf, ", ");
                                }
                        fprintf(stderr, "\n");
                }
                do      {
                        fprintf(stderr, "Specify next volume #: ");
                        (void) fflush(stderr);
                                }
                        fprintf(stderr, "\n");
                }
                do      {
                        fprintf(stderr, "Specify next volume #: ");
                        (void) fflush(stderr);
-                       (void) fgets(tbf, BUFSIZ, terminal);
-               } while (!feof(terminal) && tbf[0] == '\n');
+                       (void) fgets(buf, BUFSIZ, terminal);
+               } while (!feof(terminal) && buf[0] == '\n');
                if (feof(terminal))
                        done(1);
                if (feof(terminal))
                        done(1);
-               newvol = atoi(tbf);
+               newvol = atoi(buf);
                if (newvol <= 0) {
                        fprintf(stderr,
                            "Volume numbers are positive numerics\n");
                if (newvol <= 0) {
                        fprintf(stderr,
                            "Volume numbers are positive numerics\n");
@@ -244,21 +315,28 @@ again:
        }
        closemt();
        fprintf(stderr, "Mount tape volume %d\n", newvol);
        }
        closemt();
        fprintf(stderr, "Mount tape volume %d\n", newvol);
-       fprintf(stderr, "then enter tape name (default: %s) ", magtape);
+       fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
+       fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
        (void) fflush(stderr);
        (void) fflush(stderr);
-       (void) fgets(tbf, BUFSIZ, terminal);
+       (void) fgets(buf, BUFSIZ, terminal);
        if (feof(terminal))
                done(1);
        if (feof(terminal))
                done(1);
-       if (tbf[0] != '\n') {
-               (void) strcpy(magtape, tbf);
+       if (!strcmp(buf, "none\n")) {
+               terminateinput();
+               return;
+       }
+       if (buf[0] != '\n') {
+               (void) strcpy(magtape, buf);
                magtape[strlen(magtape) - 1] = '\0';
        }
 #ifdef RRESTORE
                magtape[strlen(magtape) - 1] = '\0';
        }
 #ifdef RRESTORE
-       if ((mt = rmtopen(magtape, 0)) == -1)
-#else
-       if ((mt = open(magtape, 0)) == -1)
+       if (host)
+               mt = rmtopen(magtape, 0);
+       else
 #endif
 #endif
-       {
+               mt = open(magtape, O_RDONLY, 0);
+
+       if (mt == -1) {
                fprintf(stderr, "Cannot open %s\n", magtape);
                volno = -1;
                goto again;
                fprintf(stderr, "Cannot open %s\n", magtape);
                volno = -1;
                goto again;
@@ -266,13 +344,14 @@ again:
 gethdr:
        volno = newvol;
        setdumpnum();
 gethdr:
        volno = newvol;
        setdumpnum();
-       flsht();
-       if (readhdr(&tmpbuf) == FAIL) {
+       FLUSHTAPEBUF();
+       if (gethead(&tmpbuf) == FAIL) {
+               dprintf(stdout, "header read failed at %d blocks\n", blksread);
                fprintf(stderr, "tape is not dump tape\n");
                volno = 0;
                goto again;
        }
                fprintf(stderr, "tape is not dump tape\n");
                volno = 0;
                goto again;
        }
-       if (checkvol(&tmpbuf, volno) == FAIL) {
+       if (tmpbuf.c_volume != volno) {
                fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
                volno = 0;
                goto again;
                fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
                volno = 0;
                goto again;
@@ -286,13 +365,66 @@ gethdr:
        }
        tapesread |= 1 << volno;
        blksread = savecnt;
        }
        tapesread |= 1 << volno;
        blksread = savecnt;
+       /*
+        * If continuing from the previous volume, skip over any
+        * blocks read already at the end of the previous volume.
+        *
+        * If coming to this volume at random, skip to the beginning
+        * of the next record.
+        */
+       dprintf(stdout, "read %ld recs, tape starts with %ld\n", 
+               tpblksread, tmpbuf.c_firstrec);
+       if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
+               if (!wantnext) {
+                       tpblksread = tmpbuf.c_firstrec;
+                       for (i = tmpbuf.c_count; i > 0; i--)
+                               readtape(buf);
+               } else if (tmpbuf.c_firstrec > 0 &&
+                          tmpbuf.c_firstrec < tpblksread - 1) {
+                       /*
+                        * -1 since we've read the volume header
+                        */
+                       i = tpblksread - tmpbuf.c_firstrec - 1;
+                       dprintf(stderr, "Skipping %d duplicate record%s.\n",
+                               i, i > 1 ? "s" : "");
+                       while (--i >= 0)
+                               readtape(buf);
+               }
+       }
        if (curfile.action == USING) {
                if (volno == 1)
                        panic("active file into volume 1\n");
                return;
        }
        if (curfile.action == USING) {
                if (volno == 1)
                        panic("active file into volume 1\n");
                return;
        }
+       /*
+        * Skip up to the beginning of the next record
+        */
+       if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
+               for (i = tmpbuf.c_count; i > 0; i--)
+                       readtape(buf);
        (void) gethead(&spcl);
        (void) gethead(&spcl);
-       findinode(&spcl, curfile.action == UNKNOWN ? 1 : 0);
+       findinode(&spcl);
+       if (gettingfile) {
+               gettingfile = 0;
+               longjmp(restart, 1);
+       }
+}
+
+/*
+ * Handle unexpected EOF.
+ */
+static void
+terminateinput()
+{
+
+       if (gettingfile && curfile.action == USING) {
+               printf("Warning: %s %s\n",
+                   "End-of-input encountered while extracting", curfile.name);
+       }
+       curfile.name = "<name unknown>";
+       curfile.action = UNKNOWN;
+       curfile.dip = NULL;
+       curfile.ino = maxino;
        if (gettingfile) {
                gettingfile = 0;
                longjmp(restart, 1);
        if (gettingfile) {
                gettingfile = 0;
                longjmp(restart, 1);
@@ -303,6 +435,7 @@ gethdr:
  * handle multiple dumps per tape by skipping forward to the
  * appropriate one.
  */
  * handle multiple dumps per tape by skipping forward to the
  * appropriate one.
  */
+static void
 setdumpnum()
 {
        struct mtop tcom;
 setdumpnum()
 {
        struct mtop tcom;
@@ -316,27 +449,44 @@ setdumpnum()
        tcom.mt_op = MTFSF;
        tcom.mt_count = dumpnum - 1;
 #ifdef RRESTORE
        tcom.mt_op = MTFSF;
        tcom.mt_count = dumpnum - 1;
 #ifdef RRESTORE
-       rmtioctl(MTFSF, dumpnum - 1);
-#else
-       if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
-               perror("ioctl MTFSF");
+       if (host)
+               rmtioctl(MTFSF, dumpnum - 1);
+       else 
 #endif
 #endif
+               if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
+                       fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
 }
 
 }
 
+void
+printdumpinfo()
+{
+       fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
+       fprintf(stdout, "Dumped from: %s",
+           (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
+       if (spcl.c_host[0] == '\0')
+               return;
+       fprintf(stderr, "Level %d dump of %s on %s:%s\n",
+               spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
+       fprintf(stderr, "Label: %s\n", spcl.c_label);
+}
+
+int
 extractfile(name)
        char *name;
 {
 extractfile(name)
        char *name;
 {
-       int mode;
-       time_t timep[2];
+       int flags;
+       mode_t mode;
+       struct timeval timep[2];
        struct entry *ep;
        struct entry *ep;
-       extern int xtrlnkfile(), xtrlnkskip();
-       extern int xtrfile(), xtrskip();
 
        curfile.name = name;
        curfile.action = USING;
 
        curfile.name = name;
        curfile.action = USING;
-       timep[0] = curfile.dip->di_atime;
-       timep[1] = curfile.dip->di_mtime;
+       timep[0].tv_sec = curfile.dip->di_atime.ts_sec;
+       timep[0].tv_usec = curfile.dip->di_atime.ts_nsec / 1000;
+       timep[1].tv_sec = curfile.dip->di_mtime.ts_sec;
+       timep[1].tv_usec = curfile.dip->di_mtime.ts_nsec / 1000;
        mode = curfile.dip->di_mode;
        mode = curfile.dip->di_mode;
+       flags = curfile.dip->di_flags;
        switch (mode & IFMT) {
 
        default:
        switch (mode & IFMT) {
 
        default:
@@ -344,10 +494,15 @@ extractfile(name)
                skipfile();
                return (FAIL);
 
                skipfile();
                return (FAIL);
 
+       case IFSOCK:
+               vprintf(stdout, "skipped socket %s\n", name);
+               skipfile();
+               return (GOOD);
+
        case IFDIR:
                if (mflag) {
                        ep = lookupname(name);
        case IFDIR:
                if (mflag) {
                        ep = lookupname(name);
-                       if (ep == NIL || ep->e_flags & EXTRACT)
+                       if (ep == NULL || ep->e_flags & EXTRACT)
                                panic("unextracted directory %s\n", name);
                        skipfile();
                        return (GOOD);
                                panic("unextracted directory %s\n", name);
                        skipfile();
                        return (GOOD);
@@ -369,33 +524,60 @@ extractfile(name)
        case IFCHR:
        case IFBLK:
                vprintf(stdout, "extract special file %s\n", name);
        case IFCHR:
        case IFBLK:
                vprintf(stdout, "extract special file %s\n", name);
+               if (Nflag) {
+                       skipfile();
+                       return (GOOD);
+               }
                if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
                if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
-                       fprintf(stderr, "%s: ", name);
-                       (void) fflush(stderr);
-                       perror("cannot create special file");
+                       fprintf(stderr, "%s: cannot create special file: %s\n",
+                           name, strerror(errno));
+                       skipfile();
+                       return (FAIL);
+               }
+               (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
+               (void) chmod(name, mode);
+               (void) chflags(name, flags);
+               skipfile();
+               utimes(name, timep);
+               return (GOOD);
+
+       case IFIFO:
+               vprintf(stdout, "extract fifo %s\n", name);
+               if (Nflag) {
+                       skipfile();
+                       return (GOOD);
+               }
+               if (mkfifo(name, mode) < 0) {
+                       fprintf(stderr, "%s: cannot create fifo: %s\n",
+                           name, strerror(errno));
                        skipfile();
                        return (FAIL);
                }
                (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
                (void) chmod(name, mode);
                        skipfile();
                        return (FAIL);
                }
                (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
                (void) chmod(name, mode);
+               (void) chflags(name, flags);
                skipfile();
                skipfile();
-               utime(name, timep);
+               utimes(name, timep);
                return (GOOD);
 
        case IFREG:
                vprintf(stdout, "extract file %s\n", name);
                return (GOOD);
 
        case IFREG:
                vprintf(stdout, "extract file %s\n", name);
+               if (Nflag) {
+                       skipfile();
+                       return (GOOD);
+               }
                if ((ofile = creat(name, 0666)) < 0) {
                if ((ofile = creat(name, 0666)) < 0) {
-                       fprintf(stderr, "%s: ", name);
-                       (void) fflush(stderr);
-                       perror("cannot create file");
+                       fprintf(stderr, "%s: cannot create file: %s\n",
+                           name, strerror(errno));
                        skipfile();
                        return (FAIL);
                }
                (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
                (void) fchmod(ofile, mode);
                        skipfile();
                        return (FAIL);
                }
                (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
                (void) fchmod(ofile, mode);
+               (void) fchflags(ofile, flags);
                getfile(xtrfile, xtrskip);
                (void) close(ofile);
                getfile(xtrfile, xtrskip);
                (void) close(ofile);
-               utime(name, timep);
+               utimes(name, timep);
                return (GOOD);
        }
        /* NOTREACHED */
                return (GOOD);
        }
        /* NOTREACHED */
@@ -404,41 +586,46 @@ extractfile(name)
 /*
  * skip over bit maps on the tape
  */
 /*
  * skip over bit maps on the tape
  */
+void
 skipmaps()
 {
 
 skipmaps()
 {
 
-       while (checktype(&spcl, TS_CLRI) == GOOD ||
-              checktype(&spcl, TS_BITS) == GOOD)
+       while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
                skipfile();
 }
 
 /*
  * skip over a file on the tape
  */
                skipfile();
 }
 
 /*
  * skip over a file on the tape
  */
+void
 skipfile()
 {
 skipfile()
 {
-       extern int null();
 
        curfile.action = SKIP;
 
        curfile.action = SKIP;
-       getfile(null, null);
+       getfile(xtrnull, xtrnull);
 }
 
 /*
 }
 
 /*
- * Do the file extraction, calling the supplied functions
- * with the blocks
+ * Extract a file from the tape.
+ * When an allocated block is found it is passed to the fill function;
+ * when an unallocated block (hole) is found, a zeroed buffer is passed
+ * to the skip function.
  */
  */
-getfile(f1, f2)
-       int     (*f2)(), (*f1)();
+void
+getfile(fill, skip)
+       void    (*fill) __P((char *, long));
+       void    (*skip) __P((char *, long));
 {
        register int i;
        int curblk = 0;
 {
        register int i;
        int curblk = 0;
-       off_t size = spcl.c_dinode.di_size;
+       long size = spcl.c_dinode.di_size;
        static char clearedbuf[MAXBSIZE];
        char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
        static char clearedbuf[MAXBSIZE];
        char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
+       char junk[TP_BSIZE];
 
 
-       if (checktype(&spcl, TS_END) == GOOD)
+       if (spcl.c_type == TS_END)
                panic("ran off end of tape\n");
                panic("ran off end of tape\n");
-       if (ishead(&spcl) == FAIL)
+       if (spcl.c_magic != NFS_MAGIC)
                panic("not at beginning of a file\n");
        if (!gettingfile && setjmp(restart) != 0)
                return;
                panic("not at beginning of a file\n");
        if (!gettingfile && setjmp(restart) != 0)
                return;
@@ -448,69 +635,82 @@ loop:
                if (spcl.c_addr[i]) {
                        readtape(&buf[curblk++][0]);
                        if (curblk == fssize / TP_BSIZE) {
                if (spcl.c_addr[i]) {
                        readtape(&buf[curblk++][0]);
                        if (curblk == fssize / TP_BSIZE) {
-                               (*f1)(buf, size > TP_BSIZE ?
+                               (*fill)((char *)buf, size > TP_BSIZE ?
                                     (long) (fssize) :
                                     (curblk - 1) * TP_BSIZE + size);
                                curblk = 0;
                        }
                } else {
                        if (curblk > 0) {
                                     (long) (fssize) :
                                     (curblk - 1) * TP_BSIZE + size);
                                curblk = 0;
                        }
                } else {
                        if (curblk > 0) {
-                               (*f1)(buf, size > TP_BSIZE ?
+                               (*fill)((char *)buf, size > TP_BSIZE ?
                                     (long) (curblk * TP_BSIZE) :
                                     (curblk - 1) * TP_BSIZE + size);
                                curblk = 0;
                        }
                                     (long) (curblk * TP_BSIZE) :
                                     (curblk - 1) * TP_BSIZE + size);
                                curblk = 0;
                        }
-                       (*f2)(clearedbuf, size > TP_BSIZE ?
+                       (*skip)(clearedbuf, size > TP_BSIZE ?
                                (long) TP_BSIZE : size);
                }
                                (long) TP_BSIZE : size);
                }
-               if ((size -= TP_BSIZE) <= 0)
+               if ((size -= TP_BSIZE) <= 0) {
+                       for (i++; i < spcl.c_count; i++)
+                               if (spcl.c_addr[i])
+                                       readtape(junk);
                        break;
                        break;
+               }
        }
        }
-       if (readhdr(&spcl) == GOOD && size > 0) {
-               if (checktype(&spcl, TS_ADDR) == GOOD)
+       if (gethead(&spcl) == GOOD && size > 0) {
+               if (spcl.c_type == TS_ADDR)
                        goto loop;
                        goto loop;
-               dprintf(stdout, "Missing address (header) block for %s\n",
-                       curfile.name);
+               dprintf(stdout,
+                       "Missing address (header) block for %s at %d blocks\n",
+                       curfile.name, blksread);
        }
        if (curblk > 0)
        }
        if (curblk > 0)
-               (*f1)(buf, (curblk * TP_BSIZE) + size);
-       findinode(&spcl, 1);
+               (*fill)((char *)buf, (curblk * TP_BSIZE) + size);
+       findinode(&spcl);
        gettingfile = 0;
 }
 
 /*
        gettingfile = 0;
 }
 
 /*
- * The next routines are called during file extraction to
- * put the data into the right form and place.
+ * Write out the next block of a file.
  */
  */
+static void
 xtrfile(buf, size)
        char    *buf;
        long    size;
 {
 
 xtrfile(buf, size)
        char    *buf;
        long    size;
 {
 
+       if (Nflag)
+               return;
        if (write(ofile, buf, (int) size) == -1) {
        if (write(ofile, buf, (int) size) == -1) {
-               fprintf(stderr, "write error extracting inode %d, name %s\n",
-                       curfile.ino, curfile.name);
-               perror("write");
+               fprintf(stderr,
+                   "write error extracting inode %d, name %s\nwrite: %s\n",
+                       curfile.ino, curfile.name, strerror(errno));
                done(1);
        }
 }
 
                done(1);
        }
 }
 
+/*
+ * Skip over a hole in a file.
+ */
+/* ARGSUSED */
+static void
 xtrskip(buf, size)
        char *buf;
        long size;
 {
 
 xtrskip(buf, size)
        char *buf;
        long size;
 {
 
-#ifdef lint
-       buf = buf;
-#endif
-       if (lseek(ofile, size, 1) == (long)-1) {
-               fprintf(stderr, "seek error extracting inode %d, name %s\n",
-                       curfile.ino, curfile.name);
-               perror("lseek");
+       if (lseek(ofile, size, SEEK_CUR) == -1) {
+               fprintf(stderr,
+                   "seek error extracting inode %d, name %s\nlseek: %s\n",
+                       curfile.ino, curfile.name, strerror(errno));
                done(1);
        }
 }
 
                done(1);
        }
 }
 
+/*
+ * Collect the next block of a symbolic link.
+ */
+static void
 xtrlnkfile(buf, size)
        char    *buf;
        long    size;
 xtrlnkfile(buf, size)
        char    *buf;
        long    size;
@@ -525,19 +725,25 @@ xtrlnkfile(buf, size)
        (void) strcat(lnkbuf, buf);
 }
 
        (void) strcat(lnkbuf, buf);
 }
 
+/*
+ * Skip over a hole in a symbolic link (should never happen).
+ */
+/* ARGSUSED */
+static void
 xtrlnkskip(buf, size)
        char *buf;
        long size;
 {
 
 xtrlnkskip(buf, size)
        char *buf;
        long size;
 {
 
-#ifdef lint
-       buf = buf, size = size;
-#endif
        fprintf(stderr, "unallocated block in symbolic link %s\n",
                curfile.name);
        done(1);
 }
 
        fprintf(stderr, "unallocated block in symbolic link %s\n",
                curfile.name);
        done(1);
 }
 
+/*
+ * Collect the next block of a bit map.
+ */
+static void
 xtrmap(buf, size)
        char    *buf;
        long    size;
 xtrmap(buf, size)
        char    *buf;
        long    size;
@@ -547,148 +753,214 @@ xtrmap(buf, size)
        map += size;
 }
 
        map += size;
 }
 
+/*
+ * Skip over a hole in a bit map (should never happen).
+ */
+/* ARGSUSED */
+static void
 xtrmapskip(buf, size)
        char *buf;
        long size;
 {
 
 xtrmapskip(buf, size)
        char *buf;
        long size;
 {
 
-#ifdef lint
-       buf = buf;
-#endif
        panic("hole in map\n");
        map += size;
 }
 
        panic("hole in map\n");
        map += size;
 }
 
-null() {;}
+/*
+ * Noop, when an extraction function is not needed.
+ */
+/* ARGSUSED */
+void
+xtrnull(buf, size)
+       char *buf;
+       long size;
+{
+
+       return;
+}
 
 /*
 
 /*
- * Do the tape i/o, dealing with volume changes
- * etc..
+ * Read TP_BSIZE blocks from the input.
+ * Handle read errors, and end of media.
  */
  */
-readtape(b)
-       char *b;
+static void
+readtape(buf)
+       char *buf;
 {
 {
-       register long i;
-       long rd, newvol;
-       int cnt;
-
-       if (bct >= ntrec) {
-               for (i = 0; i < ntrec; i++)
-                       ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
-               bct = 0;
-               cnt = ntrec*TP_BSIZE;
-               rd = 0;
-       getmore:
+       long rd, newvol, i;
+       int cnt, seek_failed;
+
+       if (blkcnt < numtrec) {
+               bcopy(&tapebuf[(blkcnt++ * TP_BSIZE)], buf, (long)TP_BSIZE);
+               blksread++;
+               tpblksread++;
+               return;
+       }
+       for (i = 0; i < ntrec; i++)
+               ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
+       if (numtrec == 0)
+               numtrec = ntrec;
+       cnt = ntrec * TP_BSIZE;
+       rd = 0;
+getmore:
 #ifdef RRESTORE
 #ifdef RRESTORE
-               i = rmtread(&tbf[rd], cnt);
-#else
-               i = read(mt, &tbf[rd], cnt);
+       if (host)
+               i = rmtread(&tapebuf[rd], cnt);
+       else
 #endif
 #endif
-               if (i > 0 && i != ntrec*TP_BSIZE) {
-                       if (!pipein)
-                               panic("partial block read: %d should be %d\n",
-                                       i, ntrec*TP_BSIZE);
+               i = read(mt, &tapebuf[rd], cnt);
+       /*
+        * Check for mid-tape short read error.
+        * If found, skip rest of buffer and start with the next.
+        */
+       if (!pipein && numtrec < ntrec && i > 0) {
+               dprintf(stdout, "mid-media short read error.\n");
+               numtrec = ntrec;
+       }
+       /*
+        * Handle partial block read.
+        */
+       if (pipein && i == 0 && rd > 0)
+               i = rd;
+       else if (i > 0 && i != ntrec * TP_BSIZE) {
+               if (pipein) {
                        rd += i;
                        cnt -= i;
                        if (cnt > 0)
                                goto getmore;
                        i = rd;
                        rd += i;
                        cnt -= i;
                        if (cnt > 0)
                                goto getmore;
                        i = rd;
+               } else {
+                       /*
+                        * Short read. Process the blocks read.
+                        */
+                       if (i % TP_BSIZE != 0)
+                               vprintf(stdout,
+                                   "partial block read: %d should be %d\n",
+                                   i, ntrec * TP_BSIZE);
+                       numtrec = i / TP_BSIZE;
                }
                }
-               if (i < 0) {
-                       fprintf(stderr, "Tape read error while ");
-                       switch (curfile.action) {
-                       default:
-                               fprintf(stderr, "trying to set up tape\n");
-                               break;
-                       case UNKNOWN:
-                               fprintf(stderr, "trying to resyncronize\n");
-                               break;
-                       case USING:
-                               fprintf(stderr, "restoring %s\n", curfile.name);
-                               break;
-                       case SKIP:
-                               fprintf(stderr, "skipping over inode %d\n",
-                                       curfile.ino);
-                               break;
-                       }
-                       if (!yflag && !reply("continue"))
-                               done(1);
-                       i = ntrec*TP_BSIZE;
-                       bzero(tbf, i);
+       }
+       /*
+        * Handle read error.
+        */
+       if (i < 0) {
+               fprintf(stderr, "Tape read error while ");
+               switch (curfile.action) {
+               default:
+                       fprintf(stderr, "trying to set up tape\n");
+                       break;
+               case UNKNOWN:
+                       fprintf(stderr, "trying to resynchronize\n");
+                       break;
+               case USING:
+                       fprintf(stderr, "restoring %s\n", curfile.name);
+                       break;
+               case SKIP:
+                       fprintf(stderr, "skipping over inode %d\n",
+                               curfile.ino);
+                       break;
+               }
+               if (!yflag && !reply("continue"))
+                       done(1);
+               i = ntrec * TP_BSIZE;
+               bzero(tapebuf, i);
 #ifdef RRESTORE
 #ifdef RRESTORE
-                       if (rmtseek(i, 1) < 0)
-#else
-                       if (lseek(mt, i, 1) == (long)-1)
+               if (host)
+                       seek_failed = (rmtseek(i, 1) < 0);
+               else
 #endif
 #endif
-                       {
-                               perror("continuation failed");
-                               done(1);
-                       }
+                       seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
+
+               if (seek_failed) {
+                       fprintf(stderr,
+                           "continuation failed: %s\n", strerror(errno));
+                       done(1);
                }
                }
-               if (i == 0) {
-                       if (pipein) {
-                               bcopy((char *)&endoftapemark, b,
-                                       (long)TP_BSIZE);
-                               flsht();
-                               return;
-                       }
+       }
+       /*
+        * Handle end of tape.
+        */
+       if (i == 0) {
+               vprintf(stdout, "End-of-tape encountered\n");
+               if (!pipein) {
                        newvol = volno + 1;
                        volno = 0;
                        newvol = volno + 1;
                        volno = 0;
+                       numtrec = 0;
                        getvol(newvol);
                        getvol(newvol);
-                       readtape(b);
+                       readtape(buf);
                        return;
                }
                        return;
                }
+               if (rd % TP_BSIZE != 0)
+                       panic("partial block read: %d should be %d\n",
+                               rd, ntrec * TP_BSIZE);
+               terminateinput();
+               bcopy((char *)&endoftapemark, &tapebuf[rd], (long)TP_BSIZE);
        }
        }
-       bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
+       blkcnt = 0;
+       bcopy(&tapebuf[(blkcnt++ * TP_BSIZE)], buf, (long)TP_BSIZE);
        blksread++;
        blksread++;
+       tpblksread++;
 }
 
 }
 
-flsht()
+static void
+findtapeblksize()
 {
 {
+       register long i;
 
 
-       bct = ntrec+1;
+       for (i = 0; i < ntrec; i++)
+               ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
+       blkcnt = 0;
+#ifdef RRESTORE
+       if (host)
+               i = rmtread(tapebuf, ntrec * TP_BSIZE);
+       else
+#endif
+               i = read(mt, tapebuf, ntrec * TP_BSIZE);
+
+       if (i <= 0) {
+               fprintf(stderr, "tape read error: %s\n", strerror(errno));
+               done(1);
+       }
+       if (i % TP_BSIZE != 0) {
+               fprintf(stderr, "Tape block size (%d) %s (%d)\n",
+                       i, "is not a multiple of dump block size", TP_BSIZE);
+               done(1);
+       }
+       ntrec = i / TP_BSIZE;
+       numtrec = ntrec;
+       vprintf(stdout, "Tape block size is %d\n", ntrec);
 }
 
 }
 
+void
 closemt()
 {
 closemt()
 {
+
        if (mt < 0)
                return;
 #ifdef RRESTORE
        if (mt < 0)
                return;
 #ifdef RRESTORE
-       rmtclose();
-#else
-       (void) close(mt);
+       if (host)
+               rmtclose();
+       else
 #endif
 #endif
-}
-
-checkvol(b, t)
-       struct s_spcl *b;
-       long t;
-{
-
-       if (b->c_volume != t)
-               return(FAIL);
-       return(GOOD);
-}
-
-readhdr(b)
-       struct s_spcl *b;
-{
-
-       if (gethead(b) == FAIL) {
-               dprintf(stdout, "readhdr fails at %d blocks\n", blksread);
-               return(FAIL);
-       }
-       return(GOOD);
+               (void) close(mt);
 }
 
 /*
 }
 
 /*
- * read the tape into buf, then return whether or
- * or not it is a header block.
+ * Read the next block from the tape.
+ * Check to see if it is one of several vintage headers.
+ * If it is an old style header, convert it to a new style header.
+ * If it is not any valid header, return an error.
  */
  */
+static int
 gethead(buf)
        struct s_spcl *buf;
 {
        long i;
 gethead(buf)
        struct s_spcl *buf;
 {
        long i;
+       union {
+               quad_t  qval;
+               long    val[2];
+       } qcvt;
        union u_ospcl {
                char dummy[TP_BSIZE];
                struct  s_ospcl {
        union u_ospcl {
                char dummy[TP_BSIZE];
                struct  s_ospcl {
@@ -719,8 +991,18 @@ gethead(buf)
 
        if (!cvtflag) {
                readtape((char *)buf);
 
        if (!cvtflag) {
                readtape((char *)buf);
-               if (buf->c_magic != NFS_MAGIC || checksum((int *)buf) == FAIL)
-                       return(FAIL);
+               if (buf->c_magic != NFS_MAGIC) {
+                       if (swabl(buf->c_magic) != NFS_MAGIC)
+                               return (FAIL);
+                       if (!Bcvt) {
+                               vprintf(stdout, "Note: Doing Byte swapping\n");
+                               Bcvt = 1;
+                       }
+               }
+               if (checksum((int *)buf) == FAIL)
+                       return (FAIL);
+               if (Bcvt)
+                       swabst((u_char *)"8l4s31l", (u_char *)buf);
                goto good;
        }
        readtape((char *)(&u_ospcl.s_ospcl));
                goto good;
        }
        readtape((char *)(&u_ospcl.s_ospcl));
@@ -739,9 +1021,9 @@ gethead(buf)
        buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
        buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
        buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
        buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
        buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
        buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
-       buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
-       buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
-       buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
+       buf->c_dinode.di_atime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
+       buf->c_dinode.di_mtime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
+       buf->c_dinode.di_ctime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
        buf->c_count = u_ospcl.s_ospcl.c_count;
        bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
        if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
        buf->c_count = u_ospcl.s_ospcl.c_count;
        bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
        if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
@@ -750,6 +1032,22 @@ gethead(buf)
        buf->c_magic = NFS_MAGIC;
 
 good:
        buf->c_magic = NFS_MAGIC;
 
 good:
+       if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
+           (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
+               qcvt.qval = buf->c_dinode.di_size;
+               if (qcvt.val[0] || qcvt.val[1]) {
+                       printf("Note: Doing Quad swapping\n");
+                       Qcvt = 1;
+               }
+       }
+       if (Qcvt) {
+               qcvt.qval = buf->c_dinode.di_size;
+               i = qcvt.val[1];
+               qcvt.val[1] = qcvt.val[0];
+               qcvt.val[0] = i;
+               buf->c_dinode.di_size = qcvt.qval;
+       }
+
        switch (buf->c_type) {
 
        case TS_CLRI:
        switch (buf->c_type) {
 
        case TS_CLRI:
@@ -764,6 +1062,9 @@ good:
                break;
 
        case TS_TAPE:
                break;
 
        case TS_TAPE:
+               if ((buf->c_flags & DR_NEWINODEFMT) == 0)
+                       oldinofmt = 1;
+               /* fall through */
        case TS_END:
                buf->c_inumber = 0;
                break;
        case TS_END:
                buf->c_inumber = 0;
                break;
@@ -776,6 +1077,14 @@ good:
                panic("gethead: unknown inode type %d\n", buf->c_type);
                break;
        }
                panic("gethead: unknown inode type %d\n", buf->c_type);
                break;
        }
+       /*
+        * If we are restoring a filesystem with old format inodes, 
+        * copy the uid/gid to the new location.
+        */
+       if (oldinofmt) {
+               buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
+               buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
+       }
        if (dflag)
                accthdr(buf);
        return(GOOD);
        if (dflag)
                accthdr(buf);
        return(GOOD);
@@ -784,6 +1093,7 @@ good:
 /*
  * Check that a header is where it belongs and predict the next header
  */
 /*
  * Check that a header is where it belongs and predict the next header
  */
+static void
 accthdr(header)
        struct s_spcl *header;
 {
 accthdr(header)
        struct s_spcl *header;
 {
@@ -793,7 +1103,13 @@ accthdr(header)
        long blks, i;
 
        if (header->c_type == TS_TAPE) {
        long blks, i;
 
        if (header->c_type == TS_TAPE) {
-               fprintf(stderr, "Volume header\n");
+               fprintf(stderr, "Volume header (%s inode format) ",
+                   oldinofmt ? "old" : "new");
+               if (header->c_firstrec)
+                       fprintf(stderr, "begins with record %d",
+                               header->c_firstrec);
+               fprintf(stderr, "\n");
+               previno = 0x7fffffff;
                return;
        }
        if (previno == 0x7fffffff)
                return;
        }
        if (previno == 0x7fffffff)
@@ -835,93 +1151,195 @@ newcalc:
  * Find an inode header.
  * Complain if had to skip, and complain is set.
  */
  * Find an inode header.
  * Complain if had to skip, and complain is set.
  */
-findinode(header, complain)
+static void
+findinode(header)
        struct s_spcl *header;
        struct s_spcl *header;
-       int complain;
 {
        static long skipcnt = 0;
 {
        static long skipcnt = 0;
+       long i;
+       char buf[TP_BSIZE];
 
        curfile.name = "<name unknown>";
        curfile.action = UNKNOWN;
 
        curfile.name = "<name unknown>";
        curfile.action = UNKNOWN;
-       curfile.dip = (struct dinode *)NIL;
+       curfile.dip = NULL;
        curfile.ino = 0;
        curfile.ino = 0;
-       if (ishead(header) == FAIL) {
-               skipcnt++;
-               while (gethead(header) == FAIL)
+       do {
+               if (header->c_magic != NFS_MAGIC) {
                        skipcnt++;
                        skipcnt++;
-       }
-       for (;;) {
-               if (checktype(header, TS_INODE) == GOOD) {
+                       while (gethead(header) == FAIL ||
+                           header->c_date != dumpdate)
+                               skipcnt++;
+               }
+               switch (header->c_type) {
+
+               case TS_ADDR:
+                       /*
+                        * Skip up to the beginning of the next record
+                        */
+                       for (i = 0; i < header->c_count; i++)
+                               if (header->c_addr[i])
+                                       readtape(buf);
+                       while (gethead(header) == FAIL ||
+                           header->c_date != dumpdate)
+                               skipcnt++;
+                       break;
+
+               case TS_INODE:
                        curfile.dip = &header->c_dinode;
                        curfile.ino = header->c_inumber;
                        break;
                        curfile.dip = &header->c_dinode;
                        curfile.ino = header->c_inumber;
                        break;
-               }
-               if (checktype(header, TS_END) == GOOD) {
+
+               case TS_END:
                        curfile.ino = maxino;
                        break;
                        curfile.ino = maxino;
                        break;
-               }
-               if (checktype(header, TS_CLRI) == GOOD) {
+
+               case TS_CLRI:
                        curfile.name = "<file removal list>";
                        break;
                        curfile.name = "<file removal list>";
                        break;
-               }
-               if (checktype(header, TS_BITS) == GOOD) {
+
+               case TS_BITS:
                        curfile.name = "<file dump list>";
                        break;
                        curfile.name = "<file dump list>";
                        break;
+
+               case TS_TAPE:
+                       panic("unexpected tape header\n");
+                       /* NOTREACHED */
+
+               default:
+                       panic("unknown tape header type %d\n", spcl.c_type);
+                       /* NOTREACHED */
+
                }
                }
-               while (gethead(header) == FAIL)
-                       skipcnt++;
-       }
-       if (skipcnt > 0 && complain)
+       } while (header->c_type == TS_ADDR);
+       if (skipcnt > 0)
                fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
        skipcnt = 0;
 }
 
                fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
        skipcnt = 0;
 }
 
-/*
- * return whether or not the buffer contains a header block
- */
-ishead(buf)
-       struct s_spcl *buf;
+static int
+checksum(buf)
+       register int *buf;
 {
 {
+       register int i, j;
 
 
-       if (buf->c_magic != NFS_MAGIC)
+       j = sizeof(union u_spcl) / sizeof(int);
+       i = 0;
+       if(!Bcvt) {
+               do
+                       i += *buf++;
+               while (--j);
+       } else {
+               /* What happens if we want to read restore tapes
+                       for a 16bit int machine??? */
+               do 
+                       i += swabl(*buf++);
+               while (--j);
+       }
+                       
+       if (i != CHECKSUM) {
+               fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
+                       curfile.ino, curfile.name);
                return(FAIL);
                return(FAIL);
+       }
        return(GOOD);
 }
 
        return(GOOD);
 }
 
-checktype(b, t)
-       struct s_spcl *b;
-       int     t;
+#ifdef RRESTORE
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+msg(const char *fmt, ...)
+#else
+msg(fmt, va_alist)
+       char *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+#if __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void)vfprintf(stderr, fmt, ap);
+       va_end(ap);
+}
+#endif /* RRESTORE */
+
+static u_char *
+swabshort(sp, n)
+       register u_char *sp;
+       register int n;
 {
 {
+       char c;
 
 
-       if (b->c_type != t)
-               return(FAIL);
-       return(GOOD);
+       while (--n >= 0) {
+               c = sp[0]; sp[0] = sp[1]; sp[1] = c;
+               sp += 2;
+       }
+       return (sp);
 }
 
 }
 
-checksum(b)
-       register int *b;
+static u_char *
+swablong(sp, n)
+       register u_char *sp;
+       register int n;
 {
 {
-       register int i, j;
+       char c;
 
 
-       j = sizeof(union u_spcl) / sizeof(int);
-       i = 0;
-       do
-               i += *b++;
-       while (--j);
-       if (i != CHECKSUM) {
-               fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
-                       curfile.ino, curfile.name);
-               return(FAIL);
+       while (--n >= 0) {
+               c = sp[0]; sp[0] = sp[3]; sp[3] = c;
+               c = sp[2]; sp[2] = sp[1]; sp[1] = c;
+               sp += 4;
        }
        }
-       return(GOOD);
+       return (sp);
 }
 
 }
 
-#ifdef RRESTORE
-/* VARARGS1 */
-msg(cp, a1, a2, a3)
-       char *cp;
+void
+swabst(cp, sp)
+       register u_char *cp, *sp;
 {
 {
+       int n = 0;
+
+       while (*cp) {
+               switch (*cp) {
+               case '0': case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                       n = (n * 10) + (*cp++ - '0');
+                       continue;
+               
+               case 's': case 'w': case 'h':
+                       if (n == 0)
+                               n = 1;
+                       sp = swabshort(sp, n);
+                       break;
+
+               case 'l':
+                       if (n == 0)
+                               n = 1;
+                       sp = swablong(sp, n);
+                       break;
 
 
-       fprintf(stderr, cp, a1, a2, a3);
+               default: /* Any other character, like 'b' counts as byte. */
+                       if (n == 0)
+                               n = 1;
+                       sp += n;
+                       break;
+               }
+               cp++;
+               n = 0;
+       }
+}
+
+static u_long
+swabl(x)
+       u_long x;
+{
+       swabst((u_char *)"l", (u_char *)&x);
+       return (x);
 }
 }
-#endif RRESTORE