BSD 4_3_Reno release
[unix-history] / usr / src / sbin / restore / tape.c
index a8fc7fe..19c8d76 100644 (file)
@@ -1,26 +1,44 @@
-/* Copyright (c) 1983 Regents of the University of California */
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)tape.c     3.4     (Berkeley)      83/02/27";
-#endif
+static char sccsid[] = "@(#)tape.c     5.19 (Berkeley) 6/1/90";
+#endif /* not lint */
 
 #include "restore.h"
 
 #include "restore.h"
-#include <dumprestor.h>
+#include <protocols/dumprestore.h>
 #include <sys/ioctl.h>
 #include <sys/mtio.h>
 #include <sys/file.h>
 #include <setjmp.h>
 #include <sys/ioctl.h>
 #include <sys/mtio.h>
 #include <sys/file.h>
 #include <setjmp.h>
-#include <stat.h>
+#include <sys/stat.h>
+#include "pathnames.h"
 
 
-static long    fssize;
+static long    fssize = MAXBSIZE;
 static int     mt = -1;
 static int     pipein = 0;
 static int     mt = -1;
 static int     pipein = 0;
-static char    *magtape;
-static int     insetup = 0;
-static int     bct = NTREC+1;
-static char    tbf[NTREC*TP_BSIZE];
+static char    magtape[BUFSIZ];
+static int     bct;
+static char    *tbf;
 static union   u_spcl endoftapemark;
 static long    blksread;
 static union   u_spcl endoftapemark;
 static long    blksread;
+static long    tapesread;
 static jmp_buf restart;
 static int     gettingfile = 0;        /* restart has a valid frame */
 
 static jmp_buf restart;
 static int     gettingfile = 0;        /* restart has a valid frame */
 
@@ -29,34 +47,78 @@ static char *map;
 static char    lnkbuf[MAXPATHLEN + 1];
 static int     pathlen;
 
 static char    lnkbuf[MAXPATHLEN + 1];
 static int     pathlen;
 
+int            Bcvt;           /* Swap Bytes (for CCI or sun) */
+static int     Qcvt;           /* Swap quads (for sun) */
 /*
  * Set up an input source
  */
 setinput(source)
        char *source;
 {
 /*
  * Set up an input source
  */
 setinput(source)
        char *source;
 {
-#ifdef RRESTOR
-       char *host;
-       char *index();
+       extern int errno;
+#ifdef RRESTORE
+       char *host, *tape;
+#endif RRESTORE
+       char *strerror();
 
 
+       flsht();
+       if (bflag)
+               newtapebuf(ntrec);
+       else
+               newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
+       terminal = stdin;
+#ifdef RRESTORE
        host = source;
        host = source;
-       magtape = index(host, ':');
-       if (magtape == 0) {
+       tape = index(host, ':');
+       if (tape == 0) {
 nohost:
 nohost:
-               msg("need keyletter ``f'' and device ``host:tape''");
+               msg("need keyletter ``f'' and device ``host:tape''\n");
                done(1);
        }
                done(1);
        }
-       *magtape++ = '\0';
+       *tape++ = '\0';
+       (void) strcpy(magtape, tape);
        if (rmthost(host) == 0)
                done(1);
        setuid(getuid());       /* no longer need or want root privileges */
 #else
        if (strcmp(source, "-") == 0) {
        if (rmthost(host) == 0)
                done(1);
        setuid(getuid());       /* no longer need or want root privileges */
 #else
        if (strcmp(source, "-") == 0) {
+               /*
+                * Since input is coming from a pipe we must establish
+                * our own connection to the terminal.
+                */
+               terminal = fopen(_PATH_TTY, "r");
+               if (terminal == NULL) {
+                       (void)fprintf(stderr, "Cannot open %s: %s\n",
+                           _PATH_TTY, strerror(errno));
+                       terminal = fopen(_PATH_DEVNULL, "r");
+                       if (terminal == NULL) {
+                           (void)fprintf(stderr, "Cannot open %s: %s\n",
+                               _PATH_DEVNULL, strerror(errno));
+                               done(1);
+                       }
+               }
                pipein++;
                pipein++;
-               yflag++;
        }
        }
-       magtape = source;
-#endif RRESTOR
+       (void) strcpy(magtape, source);
+#endif RRESTORE
+}
+
+newtapebuf(size)
+       long size;
+{
+       static tbfsize = -1;
+
+       ntrec = size;
+       if (size <= tbfsize)
+               return;
+       if (tbf != NULL)
+               free(tbf);
+       tbf = (char *)malloc(size * TP_BSIZE);
+       if (tbf == NULL) {
+               fprintf(stderr, "Cannot allocate space for tape buffer\n");
+               done(1);
+       }
+       tbfsize = size;
 }
 
 /*
 }
 
 /*
@@ -66,14 +128,11 @@ nohost:
 setup()
 {
        int i, j, *ip;
 setup()
 {
        int i, j, *ip;
-       struct mtop tcom;
        struct stat stbuf;
        struct stat stbuf;
-       extern char *ctime();
        extern int xtrmap(), xtrmapskip();
 
        vprintf(stdout, "Verify tape and initialize maps\n");
        extern int xtrmap(), xtrmapskip();
 
        vprintf(stdout, "Verify tape and initialize maps\n");
-       insetup = 1;
-#ifdef RRESTOR
+#ifdef RRESTORE
        if ((mt = rmtopen(magtape, 0)) < 0)
 #else
        if (pipein)
        if ((mt = rmtopen(magtape, 0)) < 0)
 #else
        if (pipein)
@@ -81,29 +140,18 @@ setup()
        else if ((mt = open(magtape, 0)) < 0)
 #endif
        {
        else if ((mt = open(magtape, 0)) < 0)
 #endif
        {
-               fprintf(stderr, "%s: cannot open tape\n", magtape);
+               perror(magtape);
                done(1);
        }
                done(1);
        }
-       if (dumpnum != 1) {
-               if (pipein) {
-                       fprintf(stderr,
-                               "Cannot have multiple dumps on pipe input\n");
-                       done(1);
-               }
-               tcom.mt_op = MTFSF;
-               tcom.mt_count = dumpnum - 1;
-#ifdef RRESTOR
-               rmtioctl(MTFSF, dumpnum - 1);
-#else
-               if (ioctl(mt, MTIOCTOP, &tcom) < 0)
-                       perror("ioctl MTFSF");
-#endif
-       }
+       volno = 1;
+       setdumpnum();
        flsht();
        flsht();
-       if (readhdr(&spcl) == FAIL) {
+       if (!pipein && !bflag)
+               findtapeblksize();
+       if (gethead(&spcl) == FAIL) {
                bct--; /* push back this block */
                cvtflag++;
                bct--; /* push back this block */
                cvtflag++;
-               if (readhdr(&spcl) == FAIL) {
+               if (gethead(&spcl) == FAIL) {
                        fprintf(stderr, "Tape is not a dump tape\n");
                        done(1);
                }
                        fprintf(stderr, "Tape is not a dump tape\n");
                        done(1);
                }
@@ -120,16 +168,17 @@ setup()
                while (--j);
                endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
        }
                while (--j);
                endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
        }
-       vprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
-       vprintf(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) {
-               fprintf(stderr, "cannot stat .\n");
+               perror("cannot stat .");
                done(1);
        }
                done(1);
        }
-       fssize = stbuf.st_blksize;
-       if (fssize <= 0 || ((fssize - 1) & fssize) != 0) {
+       if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
+               fssize = stbuf.st_blksize;
+       if (((fssize - 1) & fssize) != 0) {
                fprintf(stderr, "bad block size %d\n", fssize);
                done(1);
        }
                fprintf(stderr, "bad block size %d\n", fssize);
                done(1);
        }
@@ -139,87 +188,137 @@ setup()
        }
        if (readhdr(&spcl) == FAIL)
                panic("no header after volume mark!\n");
        }
        if (readhdr(&spcl) == FAIL)
                panic("no header after volume mark!\n");
-       findinode(&spcl, 1);
+       findinode(&spcl);
        if (checktype(&spcl, TS_CLRI) == FAIL) {
                fprintf(stderr, "Cannot find file removal list\n");
                done(1);
        }
        maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
        if (checktype(&spcl, TS_CLRI) == FAIL) {
                fprintf(stderr, "Cannot find file removal list\n");
                done(1);
        }
        maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
-       dprintf(stderr, "maxino = %d\n", maxino);
-       map = (char *)calloc(1, (int)howmany(maxino, NBBY));
+       dprintf(stdout, "maxino = %d\n", maxino);
+       map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
        if (map == (char *)NIL)
                panic("no memory for file removal list\n");
        if (map == (char *)NIL)
                panic("no memory for file removal list\n");
+       clrimap = map;
        curfile.action = USING;
        getfile(xtrmap, xtrmapskip);
        curfile.action = USING;
        getfile(xtrmap, xtrmapskip);
-       clrimap = map;
        if (checktype(&spcl, TS_BITS) == FAIL) {
                fprintf(stderr, "Cannot find file dump list\n");
                done(1);
        }
        if (checktype(&spcl, TS_BITS) == FAIL) {
                fprintf(stderr, "Cannot find file dump list\n");
                done(1);
        }
-       map = (char *)calloc(1, (int)howmany(maxino, NBBY));
+       map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
        if (map == (char *)NULL)
                panic("no memory for file dump list\n");
        if (map == (char *)NULL)
                panic("no memory for file dump list\n");
+       dumpmap = map;
        curfile.action = USING;
        getfile(xtrmap, xtrmapskip);
        curfile.action = USING;
        getfile(xtrmap, xtrmapskip);
-       dumpmap = map;
-       insetup = 0;
 }
 
 }
 
+/*
+ * Prompt user to load a new dump volume.
+ * "Nextvol" is the next suggested volume to use.
+ * This suggested volume is enforced when doing full
+ * or incremental restores, but can be overrridden by
+ * the user when only extracting a subset of the files.
+ */
 getvol(nextvol)
        long nextvol;
 {
        long newvol;
 getvol(nextvol)
        long nextvol;
 {
        long newvol;
-       long savecnt;
+       long savecnt, i;
        union u_spcl tmpspcl;
 #      define tmpbuf tmpspcl.s_spcl
        union u_spcl tmpspcl;
 #      define tmpbuf tmpspcl.s_spcl
+       char buf[TP_BSIZE];
+       extern char *ctime();
 
 
-       if (dumpnum > 1) {
-               /*
-                * if this is a multi-dump tape we always start with 
-                * volume 1, so as to avoid accidentally restoring
-                * from a different dump!
-                */
-               if (volno != 1)
-                       panic("multiple dump at volno %d\n", volno);
-               dumpnum = 1;
+       if (nextvol == 1) {
+               tapesread = 0;
+               gettingfile = 0;
        }
        if (pipein) {
        }
        if (pipein) {
-               if (volno != 1 || nextvol != 1)
+               if (nextvol != 1)
                        panic("Changing volumes on pipe input?\n");
                        panic("Changing volumes on pipe input?\n");
-               return;
+               if (volno == 1)
+                       return;
+               goto gethdr;
        }
        savecnt = blksread;
 again:
        }
        savecnt = blksread;
 again:
+       if (pipein)
+               done(1); /* pipes do not get a second chance */
        if (command == 'R' || command == 'r' || curfile.action != SKIP)
                newvol = nextvol;
        else 
                newvol = 0;
        while (newvol <= 0) {
        if (command == 'R' || command == 'r' || curfile.action != SKIP)
                newvol = nextvol;
        else 
                newvol = 0;
        while (newvol <= 0) {
-               fprintf(stderr, "Specify volume #: ");
-               if (gets(tbf) == NULL)
-                       continue;
+               if (tapesread == 0) {
+                       fprintf(stderr, "%s%s%s%s%s",
+                           "You have not read any tapes yet.\n",
+                           "Unless you know which volume your",
+                           " file(s) are on you should start\n",
+                           "with the last volume and work",
+                           " towards towards the first.\n");
+               } else {
+                       fprintf(stderr, "You have read volumes");
+                       strcpy(tbf, ": ");
+                       for (i = 1; i < 32; i++)
+                               if (tapesread & (1 << i)) {
+                                       fprintf(stderr, "%s%d", tbf, i);
+                                       strcpy(tbf, ", ");
+                               }
+                       fprintf(stderr, "\n");
+               }
+               do      {
+                       fprintf(stderr, "Specify next volume #: ");
+                       (void) fflush(stderr);
+                       (void) fgets(tbf, BUFSIZ, terminal);
+               } while (!feof(terminal) && tbf[0] == '\n');
+               if (feof(terminal))
+                       done(1);
                newvol = atoi(tbf);
                if (newvol <= 0) {
                        fprintf(stderr,
                            "Volume numbers are positive numerics\n");
                }
        }
                newvol = atoi(tbf);
                if (newvol <= 0) {
                        fprintf(stderr,
                            "Volume numbers are positive numerics\n");
                }
        }
-       if (newvol == volno)
+       if (newvol == volno) {
+               tapesread |= 1 << volno;
                return;
                return;
+       }
        closemt();
        closemt();
-       fprintf(stderr, "Mount tape volume %d then type return: ", newvol);
-       while (getchar() != '\n')
-               ;
-#ifdef RRESTOR
+       fprintf(stderr, "Mount tape volume %d\n", newvol);
+       fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
+       fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
+       (void) fflush(stderr);
+       (void) fgets(tbf, BUFSIZ, terminal);
+       if (feof(terminal))
+               done(1);
+       if (!strcmp(tbf, "none\n")) {
+               curfile.name = "<name unknown>";
+               curfile.action = UNKNOWN;
+               curfile.dip = (struct dinode *)NIL;
+               curfile.ino = maxino;
+               if (gettingfile) {
+                       gettingfile = 0;
+                       longjmp(restart, 1);
+               }
+       }
+       if (tbf[0] != '\n') {
+               (void) strcpy(magtape, tbf);
+               magtape[strlen(magtape) - 1] = '\0';
+       }
+#ifdef RRESTORE
        if ((mt = rmtopen(magtape, 0)) == -1)
 #else
        if ((mt = open(magtape, 0)) == -1)
 #endif
        {
        if ((mt = rmtopen(magtape, 0)) == -1)
 #else
        if ((mt = open(magtape, 0)) == -1)
 #endif
        {
-               fprintf(stderr, "Cannot open tape!\n");
+               fprintf(stderr, "Cannot open %s\n", magtape);
+               volno = -1;
                goto again;
        }
                goto again;
        }
+gethdr:
        volno = newvol;
        volno = newvol;
+       setdumpnum();
        flsht();
        if (readhdr(&tmpbuf) == FAIL) {
                fprintf(stderr, "tape is not dump tape\n");
        flsht();
        if (readhdr(&tmpbuf) == FAIL) {
                fprintf(stderr, "tape is not dump tape\n");
@@ -232,36 +331,86 @@ again:
                goto again;
        }
        if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
                goto again;
        }
        if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
-               fprintf(stderr, "Wrong dump date (%s)\n", ctime(tmpbuf.c_date));
+               fprintf(stderr, "Wrong dump date\n\tgot: %s",
+                       ctime(&tmpbuf.c_date));
+               fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
                volno = 0;
                goto again;
        }
                volno = 0;
                goto again;
        }
+       tapesread |= 1 << volno;
+       blksread = savecnt;
        if (curfile.action == USING) {
                if (volno == 1)
                        panic("active file into volume 1\n");
        if (curfile.action == USING) {
                if (volno == 1)
                        panic("active file into volume 1\n");
-               blksread = savecnt;
                return;
        }
                return;
        }
-       findinode(&spcl, curfile.action == UNKNOWN ? 1 : 0);
+       /*
+        * 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);
+       findinode(&spcl);
        if (gettingfile) {
                gettingfile = 0;
                longjmp(restart, 1);
        }
 }
 
        if (gettingfile) {
                gettingfile = 0;
                longjmp(restart, 1);
        }
 }
 
+/*
+ * handle multiple dumps per tape by skipping forward to the
+ * appropriate one.
+ */
+setdumpnum()
+{
+       struct mtop tcom;
+
+       if (dumpnum == 1 || volno != 1)
+               return;
+       if (pipein) {
+               fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
+               done(1);
+       }
+       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");
+#endif
+}
+
+printdumpinfo()
+{
+       extern char *ctime();
+
+       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);
+}
+
 extractfile(name)
        char *name;
 {
        int mode;
 extractfile(name)
        char *name;
 {
        int mode;
-       time_t timep[2];
+       struct timeval timep[2];
        struct entry *ep;
        extern int xtrlnkfile(), xtrlnkskip();
        extern int xtrfile(), xtrskip();
 
        curfile.name = name;
        curfile.action = USING;
        struct entry *ep;
        extern int xtrlnkfile(), xtrlnkskip();
        extern int xtrfile(), xtrskip();
 
        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;
+       timep[0].tv_usec = 0;
+       timep[1].tv_sec = curfile.dip->di_mtime;
+       timep[1].tv_usec = 0;
        mode = curfile.dip->di_mode;
        switch (mode & IFMT) {
 
        mode = curfile.dip->di_mode;
        switch (mode & IFMT) {
 
@@ -270,6 +419,11 @@ 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);
@@ -288,46 +442,67 @@ extractfile(name)
                if (pathlen == 0) {
                        vprintf(stdout,
                            "%s: zero length symbolic link (ignored)\n", name);
                if (pathlen == 0) {
                        vprintf(stdout,
                            "%s: zero length symbolic link (ignored)\n", name);
-               } else if (symlink(lnkbuf, name) < 0) {
-                       fprintf(stderr, "%s: cannot create symbolic link\n",
-                           name);
-                       return (FAIL);
-               } else
-                       vprintf(stdout, "extract symbolic link %s\n", name);
-               return (GOOD);
+                       return (GOOD);
+               }
+               return (linkit(lnkbuf, name, SYMLINK));
 
        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: cannot create special file\n",
-                           name);
+                       fprintf(stderr, "%s: ", name);
+                       (void) fflush(stderr);
+                       perror("cannot create special file");
                        skipfile();
                        return (FAIL);
                }
                        skipfile();
                        return (FAIL);
                }
-               chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
-               chmod(name, mode);
+               (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
+               (void) chmod(name, mode);
                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 ((ofile = open(name, FWRONLY|FCREATE, 0666)) < 0) {
-                       fprintf(stderr, "%s: cannot create file\n", name);
+               if (Nflag) {
+                       skipfile();
+                       return (GOOD);
+               }
+               if ((ofile = creat(name, 0666)) < 0) {
+                       fprintf(stderr, "%s: ", name);
+                       (void) fflush(stderr);
+                       perror("cannot create file");
                        skipfile();
                        return (FAIL);
                }
                        skipfile();
                        return (FAIL);
                }
-               fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
-               fchmod(ofile, mode);
+               (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
+               (void) fchmod(ofile, mode);
                getfile(xtrfile, xtrskip);
                getfile(xtrfile, xtrskip);
-               close(ofile);
-               utime(name, timep);
+               (void) close(ofile);
+               utimes(name, timep);
                return (GOOD);
        }
        /* NOTREACHED */
 }
 
                return (GOOD);
        }
        /* NOTREACHED */
 }
 
+/*
+ * skip over bit maps on the tape
+ */
+skipmaps()
+{
+
+       while (checktype(&spcl, TS_CLRI) == GOOD ||
+              checktype(&spcl, TS_BITS) == GOOD)
+               skipfile();
+}
+
+/*
+ * skip over a file on the tape
+ */
 skipfile()
 {
        extern int null();
 skipfile()
 {
        extern int null();
@@ -348,12 +523,13 @@ getfile(f1, f2)
        off_t size = spcl.c_dinode.di_size;
        static char clearedbuf[MAXBSIZE];
        char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
        off_t size = spcl.c_dinode.di_size;
        static char clearedbuf[MAXBSIZE];
        char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
+       char junk[TP_BSIZE];
 
        if (checktype(&spcl, TS_END) == GOOD)
                panic("ran off end of tape\n");
 
        if (checktype(&spcl, TS_END) == GOOD)
                panic("ran off end of tape\n");
-       if (!insetup && checktype(&spcl, TS_INODE) == FAIL)
+       if (ishead(&spcl) == FAIL)
                panic("not at beginning of a file\n");
                panic("not at beginning of a file\n");
-       if (setjmp(restart) != 0)
+       if (!gettingfile && setjmp(restart) != 0)
                return;
        gettingfile++;
 loop:
                return;
        gettingfile++;
 loop:
@@ -376,18 +552,22 @@ loop:
                        (*f2)(clearedbuf, size > TP_BSIZE ?
                                (long) TP_BSIZE : size);
                }
                        (*f2)(clearedbuf, size > TP_BSIZE ?
                                (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 (gethead(&spcl) == GOOD && size > 0) {
+       if (readhdr(&spcl) == GOOD && size > 0) {
                if (checktype(&spcl, TS_ADDR) == GOOD)
                        goto loop;
                if (checktype(&spcl, TS_ADDR) == GOOD)
                        goto loop;
-               fprintf(stderr, "Missing address (header) block for %s\n",
+               dprintf(stdout, "Missing address (header) block for %s\n",
                        curfile.name);
        }
        if (curblk > 0)
                (*f1)(buf, (curblk * TP_BSIZE) + size);
                        curfile.name);
        }
        if (curblk > 0)
                (*f1)(buf, (curblk * TP_BSIZE) + size);
-       findinode(&spcl, 1);
+       findinode(&spcl);
        gettingfile = 0;
 }
 
        gettingfile = 0;
 }
 
@@ -400,6 +580,8 @@ xtrfile(buf, size)
        long    size;
 {
 
        long    size;
 {
 
+       if (Nflag)
+               return;
        if (write(ofile, buf, (int) size) == -1) {
                fprintf(stderr, "write error extracting inode %d, name %s\n",
                        curfile.ino, curfile.name);
        if (write(ofile, buf, (int) size) == -1) {
                fprintf(stderr, "write error extracting inode %d, name %s\n",
                        curfile.ino, curfile.name);
@@ -435,7 +617,7 @@ xtrlnkfile(buf, size)
                    curfile.name, lnkbuf, buf, pathlen);
                done(1);
        }
                    curfile.name, lnkbuf, buf, pathlen);
                done(1);
        }
-       strcat(lnkbuf, buf);
+       (void) strcat(lnkbuf, buf);
 }
 
 xtrlnkskip(buf, size)
 }
 
 xtrlnkskip(buf, size)
@@ -457,6 +639,7 @@ xtrmap(buf, size)
 {
 
        bcopy(buf, map, size);
 {
 
        bcopy(buf, map, size);
+       map += size;
 }
 
 xtrmapskip(buf, size)
 }
 
 xtrmapskip(buf, size)
@@ -466,9 +649,9 @@ xtrmapskip(buf, size)
 
 #ifdef lint
        buf = buf;
 
 #ifdef lint
        buf = buf;
-       size = size;
 #endif
        panic("hole in map\n");
 #endif
        panic("hole in map\n");
+       map += size;
 }
 
 null() {;}
 }
 
 null() {;}
@@ -481,93 +664,127 @@ readtape(b)
        char *b;
 {
        register long i;
        char *b;
 {
        register long i;
-       long rd, cnt, newvol;
-
-       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:
-#ifdef RRESTOR
-               i = rmtread(&tbf[rd], cnt);
+       long rd, newvol;
+       int cnt;
+
+       if (bct < ntrec) {
+               bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
+               blksread++;
+               return;
+       }
+       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:
+#ifdef RRESTORE
+       i = rmtread(&tbf[rd], cnt);
 #else
 #else
-               i = read(mt, &tbf[rd], cnt);
+       i = read(mt, &tbf[rd], cnt);
 #endif
 #endif
-               if (i > 0 && i != NTREC*TP_BSIZE) {
-                       if (!pipein)
-                               panic("partial block read: %d should be %d\n",
-                                       i, NTREC*TP_BSIZE);
+       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 {
+                       if (i % TP_BSIZE != 0)
+                               panic("partial block read: %d should be %d\n",
+                                       i, ntrec * TP_BSIZE);
+                       bcopy((char *)&endoftapemark, &tbf[i],
+                               (long)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);
-#ifdef RRESTOR
-                       if (rmtseek(i, 1) < 0)
+       }
+       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(tbf, i);
+#ifdef RRESTORE
+               if (rmtseek(i, 1) < 0)
 #else
 #else
-                       if (lseek(mt, i, 1) == (long)-1)
+               if (lseek(mt, i, 1) == (long)-1)
 #endif
 #endif
-                       {
-                               fprintf(stderr, "continuation failed\n");
-                               done(1);
-                       }
+               {
+                       perror("continuation failed");
+                       done(1);
                }
                }
-               if (i == 0) {
-                       if (pipein) {
-                               bcopy((char *)&endoftapemark, b,
-                                       (long)TP_BSIZE);
-                               flsht();
-                               return;
-                       }
+       }
+       if (i == 0) {
+               if (!pipein) {
                        newvol = volno + 1;
                        volno = 0;
                        getvol(newvol);
                        readtape(b);
                        return;
                }
                        newvol = volno + 1;
                        volno = 0;
                        getvol(newvol);
                        readtape(b);
                        return;
                }
+               if (rd % TP_BSIZE != 0)
+                       panic("partial block read: %d should be %d\n",
+                               rd, ntrec * TP_BSIZE);
+               bcopy((char *)&endoftapemark, &tbf[rd], (long)TP_BSIZE);
        }
        bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
        blksread++;
 }
 
        }
        bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
        blksread++;
 }
 
+findtapeblksize()
+{
+       register long i;
+
+       for (i = 0; i < ntrec; i++)
+               ((struct s_spcl *)&tbf[i * TP_BSIZE])->c_magic = 0;
+       bct = 0;
+#ifdef RRESTORE
+       i = rmtread(tbf, ntrec * TP_BSIZE);
+#else
+       i = read(mt, tbf, ntrec * TP_BSIZE);
+#endif
+       if (i <= 0) {
+               perror("Tape read error");
+               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;
+       vprintf(stdout, "Tape block size is %d\n", ntrec);
+}
+
 flsht()
 {
 
 flsht()
 {
 
-       bct = NTREC+1;
+       bct = ntrec+1;
 }
 
 closemt()
 {
        if (mt < 0)
                return;
 }
 
 closemt()
 {
        if (mt < 0)
                return;
-#ifdef RRESTOR
+#ifdef RRESTORE
        rmtclose();
 #else
        rmtclose();
 #else
-       close(mt);
+       (void) close(mt);
 #endif
 }
 
 #endif
 }
 
@@ -585,8 +802,10 @@ readhdr(b)
        struct s_spcl *b;
 {
 
        struct s_spcl *b;
 {
 
-       if (gethead(b) == FAIL)
+       if (gethead(b) == FAIL) {
+               dprintf(stdout, "readhdr fails at %d blocks\n", blksread);
                return(FAIL);
                return(FAIL);
+       }
        return(GOOD);
 }
 
        return(GOOD);
 }
 
@@ -597,6 +816,8 @@ readhdr(b)
 gethead(buf)
        struct s_spcl *buf;
 {
 gethead(buf)
        struct s_spcl *buf;
 {
+       long i;
+       u_long *j;
        union u_ospcl {
                char dummy[TP_BSIZE];
                struct  s_ospcl {
        union u_ospcl {
                char dummy[TP_BSIZE];
                struct  s_ospcl {
@@ -605,14 +826,14 @@ gethead(buf)
                        long    c_ddate;
                        long    c_volume;
                        long    c_tapea;
                        long    c_ddate;
                        long    c_volume;
                        long    c_tapea;
-                       short   c_inumber;
+                       u_short c_inumber;
                        long    c_magic;
                        long    c_checksum;
                        struct odinode {
                                unsigned short odi_mode;
                        long    c_magic;
                        long    c_checksum;
                        struct odinode {
                                unsigned short odi_mode;
-                               short   odi_nlink;
-                               short   odi_uid;
-                               short   odi_gid;
+                               u_short odi_nlink;
+                               u_short odi_uid;
+                               u_short odi_gid;
                                long    odi_size;
                                long    odi_rdev;
                                char    odi_addr[36];
                                long    odi_size;
                                long    odi_rdev;
                                char    odi_addr[36];
@@ -627,14 +848,19 @@ gethead(buf)
 
        if (!cvtflag) {
                readtape((char *)buf);
 
        if (!cvtflag) {
                readtape((char *)buf);
-               if (buf->c_magic != NFS_MAGIC || checksum((int *)buf) == FAIL) {
-                       dprintf(stderr, "gethead fails at %d blocks\n",
-                               blksread);
-                       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 (dflag)
-                       accthdr(buf);
-               return(GOOD);
+               if (checksum((int *)buf) == FAIL)
+                       return (FAIL);
+               if (Bcvt)
+                       swabst("8l4s31l", (char *)buf);
+               goto good;
        }
        readtape((char *)(&u_ospcl.s_ospcl));
        bzero((char *)buf, (long)TP_BSIZE);
        }
        readtape((char *)(&u_ospcl.s_ospcl));
        bzero((char *)buf, (long)TP_BSIZE);
@@ -658,11 +884,49 @@ gethead(buf)
        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 ||
-           checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) {
-               dprintf(stderr, "gethead fails at %d blocks\n", blksread);
+           checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
                return(FAIL);
                return(FAIL);
-       }
        buf->c_magic = NFS_MAGIC;
        buf->c_magic = NFS_MAGIC;
+
+good:
+       j = buf->c_dinode.di_qsize.val;
+       i = j[1];
+       if (buf->c_dinode.di_size == 0 &&
+           (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt==0) {
+               if (*j || i) {
+                       printf("Note: Doing Quad swapping\n");
+                       Qcvt = 1;
+               }
+       }
+       if (Qcvt) {
+               j[1] = *j; *j = i;
+       }
+       switch (buf->c_type) {
+
+       case TS_CLRI:
+       case TS_BITS:
+               /*
+                * Have to patch up missing information in bit map headers
+                */
+               buf->c_inumber = 0;
+               buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
+               for (i = 0; i < buf->c_count; i++)
+                       buf->c_addr[i]++;
+               break;
+
+       case TS_TAPE:
+       case TS_END:
+               buf->c_inumber = 0;
+               break;
+
+       case TS_INODE:
+       case TS_ADDR:
+               break;
+
+       default:
+               panic("gethead: unknown inode type %d\n", buf->c_type);
+               break;
+       }
        if (dflag)
                accthdr(buf);
        return(GOOD);
        if (dflag)
                accthdr(buf);
        return(GOOD);
@@ -674,41 +938,42 @@ gethead(buf)
 accthdr(header)
        struct s_spcl *header;
 {
 accthdr(header)
        struct s_spcl *header;
 {
-       static ino_t previno = 0;
+       static ino_t previno = 0x7fffffff;
        static int prevtype;
        static long predict;
        long blks, i;
 
        static int prevtype;
        static long predict;
        long blks, i;
 
-       if (previno == 0)
+       if (header->c_type == TS_TAPE) {
+               fprintf(stderr, "Volume header\n");
+               previno = 0x7fffffff;
+               return;
+       }
+       if (previno == 0x7fffffff)
                goto newcalc;
        switch (prevtype) {
                goto newcalc;
        switch (prevtype) {
-       case TS_TAPE:
-               fprintf(stderr, "Volume");
-               break;
        case TS_BITS:
        case TS_BITS:
-               fprintf(stderr, "Dump mask");
+               fprintf(stderr, "Dump mask header");
                break;
        case TS_CLRI:
                break;
        case TS_CLRI:
-               fprintf(stderr, "Remove mask");
+               fprintf(stderr, "Remove mask header");
                break;
        case TS_INODE:
                break;
        case TS_INODE:
-               fprintf(stderr, "File");
+               fprintf(stderr, "File header, ino %d", previno);
                break;
        case TS_ADDR:
                break;
        case TS_ADDR:
-               fprintf(stderr, "File continuation");
+               fprintf(stderr, "File continuation header, ino %d", previno);
                break;
        case TS_END:
                break;
        case TS_END:
-               fprintf(stderr, "End of tape");
+               fprintf(stderr, "End of tape header");
                break;
        }
                break;
        }
-       fprintf(stderr, " header, ino %d", previno);
        if (predict != blksread - 1)
                fprintf(stderr, "; predicted %d blocks, got %d blocks",
                        predict, blksread - 1);
        fprintf(stderr, "\n");
 newcalc:
        blks = 0;
        if (predict != blksread - 1)
                fprintf(stderr, "; predicted %d blocks, got %d blocks",
                        predict, blksread - 1);
        fprintf(stderr, "\n");
 newcalc:
        blks = 0;
-       if (header->c_type != TS_TAPE && header->c_type != TS_END)
+       if (header->c_type != TS_END)
                for (i = 0; i < header->c_count; i++)
                        if (header->c_addr[i] != 0)
                                blks++;
                for (i = 0; i < header->c_count; i++)
                        if (header->c_addr[i] != 0)
                                blks++;
@@ -722,12 +987,12 @@ 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)
+findinode(header)
        struct s_spcl *header;
        struct s_spcl *header;
-       int complain;
 {
        static long skipcnt = 0;
        long i;
 {
        static long skipcnt = 0;
        long i;
+       char buf[TP_BSIZE];
 
        curfile.name = "<name unknown>";
        curfile.action = UNKNOWN;
 
        curfile.name = "<name unknown>";
        curfile.action = UNKNOWN;
@@ -735,10 +1000,20 @@ findinode(header, complain)
        curfile.ino = 0;
        if (ishead(header) == FAIL) {
                skipcnt++;
        curfile.ino = 0;
        if (ishead(header) == FAIL) {
                skipcnt++;
-               while (gethead(header) == FAIL)
+               while (gethead(header) == FAIL || header->c_date != dumpdate)
                        skipcnt++;
        }
        for (;;) {
                        skipcnt++;
        }
        for (;;) {
+               if (checktype(header, TS_ADDR) == GOOD) {
+                       /*
+                        * Skip up to the beginning of the next record
+                        */
+                       for (i = 0; i < header->c_count; i++)
+                               if (header->c_addr[i])
+                                       readtape(buf);
+                       (void) gethead(header);
+                       continue;
+               }
                if (checktype(header, TS_INODE) == GOOD) {
                        curfile.dip = &header->c_dinode;
                        curfile.ino = header->c_inumber;
                if (checktype(header, TS_INODE) == GOOD) {
                        curfile.dip = &header->c_dinode;
                        curfile.ino = header->c_inumber;
@@ -750,27 +1025,17 @@ findinode(header, complain)
                }
                if (checktype(header, TS_CLRI) == GOOD) {
                        curfile.name = "<file removal list>";
                }
                if (checktype(header, TS_CLRI) == GOOD) {
                        curfile.name = "<file removal list>";
-                       header->c_dinode.di_size = header->c_count * TP_BSIZE;
-                       for (i = 0; i < header->c_count; i++)
-                               header->c_addr[i]++;
-                       if (insetup)
-                               break;
-                       skipfile();
+                       break;
                }
                if (checktype(header, TS_BITS) == GOOD) {
                        curfile.name = "<file dump list>";
                }
                if (checktype(header, TS_BITS) == GOOD) {
                        curfile.name = "<file dump list>";
-                       header->c_dinode.di_size = header->c_count * TP_BSIZE;
-                       for (i = 0; i < header->c_count; i++)
-                               header->c_addr[i]++;
-                       if (insetup)
-                               break;
-                       skipfile();
+                       break;
                }
                while (gethead(header) == FAIL)
                        skipcnt++;
        }
                }
                while (gethead(header) == FAIL)
                        skipcnt++;
        }
-       if (skipcnt > 0 && complain)
-               fprintf(stderr, "resync restor, skipped %d blocks\n", skipcnt);
+       if (skipcnt > 0)
+               fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
        skipcnt = 0;
 }
 
        skipcnt = 0;
 }
 
@@ -803,9 +1068,18 @@ checksum(b)
 
        j = sizeof(union u_spcl) / sizeof(int);
        i = 0;
 
        j = sizeof(union u_spcl) / sizeof(int);
        i = 0;
-       do
-               i += *b++;
-       while (--j);
+       if(!Bcvt) {
+               do
+                       i += *b++;
+               while (--j);
+       } else {
+               /* What happens if we want to read restore tapes
+                       for a 16bit int machine??? */
+               do 
+                       i += swabl(*b++);
+               while (--j);
+       }
+                       
        if (i != CHECKSUM) {
                fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
                        curfile.ino, curfile.name);
        if (i != CHECKSUM) {
                fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
                        curfile.ino, curfile.name);
@@ -814,39 +1088,43 @@ checksum(b)
        return(GOOD);
 }
 
        return(GOOD);
 }
 
-/*
- * respond to interrupts
- */
-onintr()
-{
-       if (pipein || reply("restore interrupted, continue") == FAIL)
-               done(1);
-       if (signal(SIGINT, onintr) == SIG_IGN)
-               signal(SIGINT, SIG_IGN);
-       if (signal(SIGTERM, onintr) == SIG_IGN)
-               signal(SIGTERM, SIG_IGN);
-}
-
-/*
- * handle unexpected inconsistencies
- */
+#ifdef RRESTORE
 /* VARARGS1 */
 /* VARARGS1 */
-panic(msg, d1, d2)
-       char *msg;
-       long d1, d2;
+msg(cp, a1, a2, a3)
+       char *cp;
 {
 
 {
 
-       fprintf(stderr, msg, d1, d2);
-       if (pipein || reply("abort") == GOOD)
-               abort();
+       fprintf(stderr, cp, a1, a2, a3);
 }
 }
+#endif RRESTORE
 
 
-#ifdef RRESTOR
-/* VARARGS1 */
-msg(cp, a1, a2, a3)
-       char *cp;
+swabst(cp, sp)
+register char *cp, *sp;
 {
 {
+       int n = 0;
+       char c;
+       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':
+                       c = sp[0]; sp[0] = sp[1]; sp[1] = c;
+                       sp++;
+                       break;
 
 
-       fprintf(stderr, cp, a1, a2, a3);
+               case 'l':
+                       c = sp[0]; sp[0] = sp[3]; sp[3] = c;
+                       c = sp[2]; sp[2] = sp[1]; sp[1] = c;
+                       sp += 3;
+               }
+               sp++; /* Any other character, like 'b' counts as byte. */
+               if (n <= 1) {
+                       n = 0; cp++;
+               } else
+                       n--;
+       }
 }
 }
-#endif RRESTOR
+swabl(x) { unsigned long l = x; swabst("l", (char *)&l); return l; }