lint; fix bug in multi-dump tapes
[unix-history] / usr / src / sbin / restore / tape.c
index 20b25c1..0174d06 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (c) 1983 Regents of the University of California */
 
 #ifndef lint
 /* Copyright (c) 1983 Regents of the University of California */
 
 #ifndef lint
-static char sccsid[] = "@(#)tape.c     3.2     (Berkeley)      83/02/26";
+static char sccsid[] = "@(#)tape.c     3.9     (Berkeley)      83/03/27";
 #endif
 
 #include "restore.h"
 #endif
 
 #include "restore.h"
@@ -16,7 +16,6 @@ static long   fssize;
 static int     mt = -1;
 static int     pipein = 0;
 static char    *magtape;
 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 union   u_spcl endoftapemark;
 static int     bct = NTREC+1;
 static char    tbf[NTREC*TP_BSIZE];
 static union   u_spcl endoftapemark;
@@ -43,7 +42,7 @@ setinput(source)
        magtape = index(host, ':');
        if (magtape == 0) {
 nohost:
        magtape = index(host, ':');
        if (magtape == 0) {
 nohost:
-               msg("need keyletter ``f'' and device ``host:tape''");
+               msg("need keyletter ``f'' and device ``host:tape''\n");
                done(1);
        }
        *magtape++ = '\0';
                done(1);
        }
        *magtape++ = '\0';
@@ -66,13 +65,11 @@ nohost:
 setup()
 {
        int i, j, *ip;
 setup()
 {
        int i, j, *ip;
-       struct mtop tcom;
        struct stat stbuf;
        extern char *ctime();
        extern int xtrmap(), xtrmapskip();
 
        vprintf(stdout, "Verify tape and initialize maps\n");
        struct stat stbuf;
        extern char *ctime();
        extern int xtrmap(), xtrmapskip();
 
        vprintf(stdout, "Verify tape and initialize maps\n");
-       insetup = 1;
 #ifdef RRESTOR
        if ((mt = rmtopen(magtape, 0)) < 0)
 #else
 #ifdef RRESTOR
        if ((mt = rmtopen(magtape, 0)) < 0)
 #else
@@ -84,26 +81,13 @@ setup()
                fprintf(stderr, "%s: cannot open tape\n", magtape);
                done(1);
        }
                fprintf(stderr, "%s: cannot open tape\n", magtape);
                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 (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);
                }
@@ -145,8 +129,8 @@ setup()
                done(1);
        }
        maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
                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");
        curfile.action = USING;
        if (map == (char *)NIL)
                panic("no memory for file removal list\n");
        curfile.action = USING;
@@ -156,13 +140,12 @@ setup()
                fprintf(stderr, "Cannot find file dump list\n");
                done(1);
        }
                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");
        curfile.action = USING;
        getfile(xtrmap, xtrmapskip);
        dumpmap = map;
        if (map == (char *)NULL)
                panic("no memory for file dump list\n");
        curfile.action = USING;
        getfile(xtrmap, xtrmapskip);
        dumpmap = map;
-       insetup = 0;
 }
 
 getvol(nextvol)
 }
 
 getvol(nextvol)
@@ -173,29 +156,23 @@ getvol(nextvol)
        union u_spcl tmpspcl;
 #      define tmpbuf tmpspcl.s_spcl
 
        union u_spcl tmpspcl;
 #      define tmpbuf tmpspcl.s_spcl
 
-       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 (pipein) {
        if (pipein) {
-               if (volno != 1 || newvol != 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 #: ");
+               fprintf(stderr, "Specify next volume #: ");
                if (gets(tbf) == NULL)
                        continue;
                newvol = atoi(tbf);
                if (gets(tbf) == NULL)
                        continue;
                newvol = atoi(tbf);
@@ -207,7 +184,7 @@ again:
        if (newvol == volno)
                return;
        closemt();
        if (newvol == volno)
                return;
        closemt();
-       fprintf(stderr, "Mount tape volume %d then type return: ", newvol);
+       fprintf(stderr, "Mount tape volume %d then type return ", newvol);
        while (getchar() != '\n')
                ;
 #ifdef RRESTOR
        while (getchar() != '\n')
                ;
 #ifdef RRESTOR
@@ -219,7 +196,9 @@ again:
                fprintf(stderr, "Cannot open tape!\n");
                goto again;
        }
                fprintf(stderr, "Cannot open tape!\n");
                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,16 +211,18 @@ 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 (%s)\n",
+                       ctime(&tmpbuf.c_date));
                volno = 0;
                goto again;
        }
                volno = 0;
                goto again;
        }
+       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;
        }
+       (void) gethead(&spcl);
        findinode(&spcl, curfile.action == UNKNOWN ? 1 : 0);
        if (gettingfile) {
                gettingfile = 0;
        findinode(&spcl, curfile.action == UNKNOWN ? 1 : 0);
        if (gettingfile) {
                gettingfile = 0;
@@ -249,6 +230,30 @@ again:
        }
 }
 
        }
 }
 
+/*
+ * 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 RRESTOR
+       rmtioctl(MTFSF, dumpnum - 1);
+#else
+       if (ioctl(mt, MTIOCTOP, &tcom) < 0)
+               perror("ioctl MTFSF");
+#endif
+}
+
 extractfile(name)
        char *name;
 {
 extractfile(name)
        char *name;
 {
@@ -305,8 +310,8 @@ extractfile(name)
                        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();
                utime(name, timep);
                return (GOOD);
                skipfile();
                utime(name, timep);
                return (GOOD);
@@ -318,16 +323,30 @@ extractfile(name)
                        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);
+               (void) close(ofile);
                utime(name, timep);
                return (GOOD);
        }
        /* NOTREACHED */
 }
 
                utime(name, timep);
                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();
@@ -351,9 +370,9 @@ getfile(f1, f2)
 
        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,21 +395,17 @@ loop:
                        (*f2)(clearedbuf, size > TP_BSIZE ?
                                (long) TP_BSIZE : size);
                }
                        (*f2)(clearedbuf, size > TP_BSIZE ?
                                (long) TP_BSIZE : size);
                }
-               if ((size -= TP_BSIZE) <= 0) {
-                       gethead(&spcl);
-                       goto out;
-               }
+               if ((size -= TP_BSIZE) <= 0)
+                       break;
        }
        }
-       if (gethead(&spcl) == FAIL || checktype(&spcl, TS_ADDR) == FAIL) {
-               fprintf(stderr, "Missing address (header) block for %s\n",
+       if (readhdr(&spcl) == GOOD && size > 0) {
+               if (checktype(&spcl, TS_ADDR) == GOOD)
+                       goto loop;
+               dprintf(stdout, "Missing address (header) block for %s\n",
                        curfile.name);
                        curfile.name);
-               goto out;
        }
        }
-       goto loop;
-out:
-       if (curblk > 0) {
+       if (curblk > 0)
                (*f1)(buf, (curblk * TP_BSIZE) + size);
                (*f1)(buf, (curblk * TP_BSIZE) + size);
-       }
        findinode(&spcl, 1);
        gettingfile = 0;
 }
        findinode(&spcl, 1);
        gettingfile = 0;
 }
@@ -485,20 +500,37 @@ readtape(b)
        char *b;
 {
        register long i;
        char *b;
 {
        register long i;
-       long newvol;
+       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;
 
        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
 #ifdef RRESTOR
-               if ((i = rmtread(tbf, NTREC*TP_BSIZE)) < 0)
+               i = rmtread(&tbf[rd], cnt);
 #else
 #else
-               if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0)
+               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);
+                       rd += i;
+                       cnt -= i;
+                       if (cnt > 0)
+                               goto getmore;
+                       i = rd;
+               }
+               if (i < 0) {
                        fprintf(stderr, "Tape read error while ");
                        switch (curfile.action) {
                        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 UNKNOWN:
                                fprintf(stderr, "trying to resyncronize\n");
                                break;
@@ -555,7 +587,7 @@ closemt()
 #ifdef RRESTOR
        rmtclose();
 #else
 #ifdef RRESTOR
        rmtclose();
 #else
-       close(mt);
+       (void) close(mt);
 #endif
 }
 
 #endif
 }
 
@@ -573,8 +605,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);
 }
 
@@ -585,6 +619,7 @@ readhdr(b)
 gethead(buf)
        struct s_spcl *buf;
 {
 gethead(buf)
        struct s_spcl *buf;
 {
+       long i;
        union u_ospcl {
                char dummy[TP_BSIZE];
                struct  s_ospcl {
        union u_ospcl {
                char dummy[TP_BSIZE];
                struct  s_ospcl {
@@ -615,14 +650,9 @@ 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);
+               if (buf->c_magic != NFS_MAGIC || checksum((int *)buf) == FAIL)
                        return(FAIL);
                        return(FAIL);
-               }
-               if (dflag)
-                       accthdr(buf);
-               return(GOOD);
+               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);
@@ -646,11 +676,37 @@ 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:
+       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);
@@ -662,41 +718,41 @@ 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");
+               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++;
@@ -715,7 +771,6 @@ findinode(header, complain)
        int complain;
 {
        static long skipcnt = 0;
        int complain;
 {
        static long skipcnt = 0;
-       long i;
 
        curfile.name = "<name unknown>";
        curfile.action = UNKNOWN;
 
        curfile.name = "<name unknown>";
        curfile.action = UNKNOWN;
@@ -738,21 +793,11 @@ 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++;
@@ -802,7 +847,35 @@ 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)
+               (void) signal(SIGINT, SIG_IGN);
+       if (signal(SIGTERM, onintr) == SIG_IGN)
+               (void) signal(SIGTERM, SIG_IGN);
+}
+
+/*
+ * handle unexpected inconsistencies
+ */
+/* VARARGS1 */
+panic(msg, d1, d2)
+       char *msg;
+       long d1, d2;
+{
+
+       fprintf(stderr, msg, d1, d2);
+       if (pipein || reply("abort") == GOOD)
+               abort();
+}
+
 #ifdef RRESTOR
 #ifdef RRESTOR
+/* VARARGS1 */
 msg(cp, a1, a2, a3)
        char *cp;
 {
 msg(cp, a1, a2, a3)
        char *cp;
 {