add Kerberos info
[unix-history] / usr / src / sbin / restore / main.c
index 3079cd7..fe9d358 100644 (file)
-/* Copyright (c) 1981 Regents of the University of California */
-
-char version[] = "@(#)main.c 1.5 %G%";
-
-/*     Modified to include h option (recursively extract all files within
- *     a subtree) and m option (recreate the heirarchical structure of
- *     that subtree and move extracted files to their proper homes).
- *     8/29/80         by Mike Litzkow
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     Includes the s (skip files) option for use with multiple dumps on
- *     a single tape.
+ * %sccs.include.redist.c%
  */
 
  */
 
-/* static char *sccsid = "@(#)restor.c 4.3 (Berkeley) 6/3/81"; */
-
-#define MAXINO 3000
-#define BITS   8
-#define NCACHE 3
-#define SIZEINC 10
-
-#ifndef STANDALONE
-#include <stdio.h>
-#include <signal.h>
-#endif
-#include "../h/param.h"
-#include "../h/inode.h"
-#include "../h/fs.h"
-#include "../h/buf.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/dumprestor.h"
-
-#define        MWORD(m,i) (m[(unsigned)(i-1)/MLEN])
-#define        MBIT(i) (1<<((unsigned)(i-1)%MLEN))
-#define        BIS(i,w)        (MWORD(w,i) |=  MBIT(i))
-#define        BIC(i,w)        (MWORD(w,i) &= ~MBIT(i))
-#define        BIT(i,w)        (MWORD(w,i) & MBIT(i))
-
-ino_t  ino, maxi;
-
-int    mt;
-
-int    eflag, hflag, mflag, vflag;
-
-char   mounted = 0;
-dev_t  dev = 0;
-char   tapename[] = "/dev/rmt8";
-char   *magtape = tapename;
-
-#ifdef STANDALONE
-char   mbuf[50];
-#endif
-
-daddr_t        seekpt;
-FILE   *df;
-int    ofile;
-char   dirfile[] = "rstXXXXXX";
-
-#define INOHASH(val) (val % MAXINO)
-struct inotab {
-       struct inotab *t_next;
-       ino_t   t_ino;
-       daddr_t t_seekpt;
-} *inotab[MAXINO];
-struct inotab *getinotab();
-
-#define XISDIR 1
-#define XTRACTD        2
-#define XINUSE 4
-#define XLINKED        8
-struct xtrlist {
-       struct xtrlist  *x_next;
-       struct xtrlist  *x_linkedto;
-       char            *x_name;
-       ino_t           x_ino;
-       time_t          x_timep[2];
-       char            x_flags;
-} *xtrlist[MAXINO];
-struct xtrlist *getxtr();
-int xtrcnt = 0;
-
-char   name[BUFSIZ + 1];
-
-#include <sys/mtio.h>
-struct mtop tcom;
-
-int dumpnum = 1;
-int    volno = 1;
-
-struct inode *cur_ip;
-
-short  dumpmap[MSIZ];
-short  clrimap[MSIZ];
-char   clearedbuf[BSIZE];
-
-int curblk = 0;
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
 
 
-int bct = NTREC+1;
-char tbf[NTREC*TP_BSIZE];
+#ifndef lint
+static char sccsid[] = "@(#)main.c     5.8 (Berkeley) %G%";
+#endif /* not lint */
 
 
-extern char *ctime();
-char **envp;
+/*
+ *     Modified to recursively extract all files within a subtree
+ *     (supressed by the h option) and recreate the heirarchical
+ *     structure of that subtree and move extracted files to their
+ *     proper homes (supressed by the m option).
+ *     Includes the s (skip files) option for use with multiple
+ *     dumps on a single tape.
+ *     8/29/80         by Mike Litzkow
+ *
+ *     Modified to work on the new file system and to recover from
+ *     tape read errors.
+ *     1/19/82         by Kirk McKusick
+ *
+ *     Full incremental restore running entirely in user code and
+ *     interactive tape browser.
+ *     1/19/83         by Kirk McKusick
+ */
 
 
-main(argc, argv, arge)
+#include "restore.h"
+#include <protocols/dumprestore.h>
+#include <sys/signal.h>
+#include "pathnames.h"
+
+int    bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
+int    hflag = 1, mflag = 1, Nflag = 0;
+char   command = '\0';
+long   dumpnum = 1;
+long   volno = 0;
+long   ntrec;
+char   *dumpmap;
+char   *clrimap;
+ino_t  maxino;
+time_t dumptime;
+time_t dumpdate;
+FILE   *terminal;
+
+main(argc, argv)
        int argc;
        char *argv[];
        int argc;
        char *argv[];
-       char **arge;
 {
        register char *cp;
 {
        register char *cp;
-       char command;
-       int (*signal())();
-       int done();
-
-#ifndef STANDALONE
-       envp = arge;
-       mktmp(dirfile);
+       ino_t ino;
+       char *inputdev = _PATH_DEFTAPE;
+       char *symtbl = "./restoresymtable";
+       char name[MAXPATHLEN];
+       void onintr();
+
+       if (signal(SIGINT, onintr) == SIG_IGN)
+               (void) signal(SIGINT, SIG_IGN);
+       if (signal(SIGTERM, onintr) == SIG_IGN)
+               (void) signal(SIGTERM, SIG_IGN);
+       setlinebuf(stderr);
        if (argc < 2) {
 usage:
        if (argc < 2) {
 usage:
-               fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n");
+               fprintf(stderr, "Usage:\n%s%s%s%s%s",
+                       "\trestore tfhsvy [file file ...]\n",
+                       "\trestore xfhmsvy [file file ...]\n",
+                       "\trestore ifhmsvy\n",
+                       "\trestore rfsvy\n",
+                       "\trestore Rfsvy\n");
                done(1);
        }
        argv++;
        argc -= 2;
                done(1);
        }
        argv++;
        argc -= 2;
+       command = '\0';
        for (cp = *argv++; *cp; cp++) {
                switch (*cp) {
                case '-':
                        break;
        for (cp = *argv++; *cp; cp++) {
                switch (*cp) {
                case '-':
                        break;
-               case 'f':
-                       magtape = *argv++;
-                       argc--;
+               case 'c':
+                       cvtflag++;
                        break;
                        break;
-               /* s dumpnum (skip to) for multifile dump tapes */
-               case 's':
-                       dumpnum = atoi(*argv++);
-                       if(dumpnum <= 0) {
-                               fprintf(stderr, "Dump number must be a positive integer\n");
-                               done(1);
-                       }
-                       argc--;
+               case 'd':
+                       dflag++;
                        break;
                case 'h':
                        break;
                case 'h':
-                       hflag++;
+                       hflag = 0;
                        break;
                case 'm':
                        break;
                case 'm':
-                       mflag++;
+                       mflag = 0;
                        break;
                        break;
-               case 'r':
-               case 'R':
-               case 't':
-               case 'x':
-                       command = *cp;
+               case 'N':
+                       Nflag++;
                        break;
                case 'v':
                        vflag++;
                        break;
                        break;
                case 'v':
                        vflag++;
                        break;
-               default:
-                       fprintf(stderr, "Bad key character %c\n", *cp);
-                       goto usage;
-               }
-       }
-       if (command == 'x') {
-               if (signal(SIGINT, done) == SIG_IGN)
-                       signal(SIGINT, SIG_IGN);
-               if (signal(SIGTERM, done) == SIG_IGN)
-                       signal(SIGTERM, SIG_IGN);
-
-               df = fopen(dirfile, "w");
-               if (df == 0) {
-                       fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile);
-                       done(1);
-               }
-               xmount(envp);
-               mounted++;
-       }
-       doit(command, argc, argv);
-       if (command == 'x')
-               unlink(dirfile);
-       done(0);
-#else
-       magtape = "tape";
-       doit('r', 1, 0);
-#endif
-}
-
-doit(command, argc, argv)
-       char    command;
-       int     argc;
-       char    *argv[]; 
-{
-#ifndef STANDALONE
-       if ((mt = open(magtape, 0)) < 0) {
-               fprintf(stderr, "%s: cannot open tape\n", magtape);
-               done(1);
-       }
-       if(dumpnum != 1) {
-               tcom.mt_op = MTFSF;
-               tcom.mt_count = dumpnum -1;
-               if( ioctl(mt,MTIOCTOP,&tcom) < 0)
-                       perror("ioctl MTFSF");
-       }
-#else
-       do {
-               fprintf(stderr, "Tape? ");
-               gets(mbuf);
-               mt = open(mbuf, 0);
-       } while (mt == -1);
-       magtape = mbuf;
-       clearbuf(clearedbuf);
-#endif
-       switch(command) {
-#ifndef STANDALONE
-       case 't':
-               if (readhdr(&spcl) == 0) {
-                       fprintf(stderr, "Tape is not a dump tape\n");
-                       done(1);
-               }
-               fprintf(stderr, "Dump   date: %s", ctime(&spcl.c_date));
-               fprintf(stderr, "Dumped from: %s", ctime(&spcl.c_ddate));
-               return;
-       case 'x':
-               extractfiles(argc, argv);
-               return;
-       case 'r':
-       case 'R':
-               restorfiles(command, argv);
-               return;
-       }
-#endif
-}
-
-#ifndef STANDALONE
-extractfiles(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *ststore();
-       register struct xtrlist *xp;
-       struct xtrlist **xpp;
-       ino_t   d;
-       int     xtrfile(), skip(), null();
-       int mode;
-       time_t timep[2];
-
-       if (readhdr(&spcl) == 0) {
-               fprintf(stderr, "Tape is not a dump tape\n");
-               done(1);
-       }
-       if (checkvol(&spcl, 1) == 0) {
-               fprintf(stderr, "Tape is not volume 1 of the dump\n");
-       }
-       pass1();  /* This sets the various maps on the way by */
-       while( argc-- ) {
-               if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
-                       fprintf(stderr,  "%s: not on tape\n", *argv++ );
-                       continue;
-               }
-               if(hflag)
-                       getleaves(d, *argv++);
-               else {
-                       xp = getxtr(d);
-                       xp->x_flags |= XINUSE;
-                       if( mflag )
-                               xp->x_name = ststore( *argv );
-                       fprintf(stderr,  "%s: inode %u\n", *argv, d );
-                       argv++;
-               }
-       }
-
-
-       if(dumpnum > 1)
-               tcom.mt_op = MTBSF;
-       else    tcom.mt_op = MTREW;
-       tcom.mt_count = 1;
-
-newvol:
-       flsht();
-       ioctl(mt,MTIOCTOP,&tcom);
-       if( dumpnum > 1 ) {
-               tcom.mt_op = MTFSF;
-               tcom.mt_count = 1;
-               ioctl(mt,MTIOCTOP,&tcom);
-       }
-       lseek(mt, (long)0, 0);
-
-
-getvol:
-       fprintf(stderr, "Mount desired tape volume: Specify volume #: ");
-       if (gets(tbf) == NULL)
-               return;
-       volno = atoi(tbf);
-       if (volno <= 0) {
-               fprintf(stderr, "Volume numbers are positive numerics\n");
-               goto getvol;
-       }
-       if (readhdr(&spcl) == 0) {
-               fprintf(stderr, "tape is not dump tape\n");
-               goto newvol;
-       }
-       if (checkvol(&spcl, volno) == 0) {
-               fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume);
-               goto newvol;
-       }
-rbits:
-       while (gethead(&spcl) == 0)
-               ;
-       if (checktype(&spcl, TS_INODE) == 1) {
-               fprintf(stderr, "Can't find inode mask!\n");
-               goto newvol;
-       }
-       if (checktype(&spcl, TS_BITS) == 0)
-               goto rbits;
-       readbits(dumpmap);
-       while (xtrcnt > 0) {
-again:
-               if (ishead(&spcl) == 0)
-                       while(gethead(&spcl) == 0)
-                               ;
-               if (checktype(&spcl, TS_END) == 1) {
-                       fprintf(stderr, "end of tape\n");
+               case 'y':
+                       yflag++;
                        break;
                        break;
-               }
-               if (checktype(&spcl, TS_INODE) == 0) {
-                       gethead(&spcl);
-                       goto again;
-               }
-               d = spcl.c_inumber;
-               for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
-                       if (d != xp->x_ino)
-                               continue;
-                       if (xp->x_flags & XLINKED)
-                               continue;
-                       xp->x_timep[0] = spcl.c_dinode.di_atime;
-                       xp->x_timep[1] = spcl.c_dinode.di_mtime;
-                       mode = spcl.c_dinode.di_mode;
-                       if (mflag)
-                               sprintf(name, "%s", xp->x_name);
-                       else
-                               sprintf(name, "%u", xp->x_ino);
-                       switch (mode & IFMT) {
-                       default:
-                               fprintf(stderr, "%s: unknown file type\n");
-                               xp->x_flags |= XTRACTD;
-                               xtrcnt--;
-                               goto skipfile;
-                       case IFCHR:
-                       case IFBLK:
-                               if (vflag)
-                                       fprintf(stderr, "extract special file %s\n", name);
-                               if (xmknod(name, mode, spcl.c_dinode.di_rdev)) {
-                                       fprintf(stderr, "%s: cannot create special file\n", name);
-                                       xp->x_flags |= XTRACTD;
-                                       xtrcnt--;
-                                       goto skipfile;
-                               }
-                               getfile(null, null, spcl.c_dinode.di_size);
-                               break;
-                       case IFDIR:
-                               if (mflag) {
-                                       if (vflag)
-                                               fprintf(stderr, "extract directory %s\n", name);
-                                       strncat(name, "/.", BUFSIZ);
-                                       checkdir( name );
-                                       xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
-                                       getfile(null, null, spcl.c_dinode.di_size);
-                                       break;
-                               }
-                               /* else fall through */
-                       case IFREG:
-                               if (vflag)
-                                       fprintf(stderr, "extract file %s\n", name);
-                               if ((ofile = xcreat(name, 0666)) < 0) {
-                                       fprintf(stderr, "%s: cannot create file\n", name);
-                                       xp->x_flags |= XTRACTD;
-                                       xtrcnt--;
-                                       goto skipfile;
-                               }
-                               xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
-                               getfile(xtrfile, skip, spcl.c_dinode.di_size);
-                               xclose(ofile);
-                               break;
-                       }
-                       xchmod(name, mode);
-                       xutime(name, xp->x_timep);
-                       xp->x_flags |= XTRACTD;
-                       xtrcnt--;
-                       goto finished;
-               }
-skipfile:
-               getfile(null, null, spcl.c_dinode.di_size);
-finished:
-               ;
-       }
-       if (xtrcnt == 0 && !mflag)
-               return;
-       for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
-               for (xp = *xpp; xp; xp = xp->x_next) {
-                       if (mflag && (xp->x_flags & XISDIR))
-                               xutime(xp->x_name, xp->x_timep);
-                       if (xp->x_flags & XTRACTD)
-                               continue;
-                       if ((xp->x_flags & XLINKED) == 0) {
-                               fprintf(stderr, "cannot find file %s\n",
-                                       xp->x_name);
-                               continue;
-                       }
-                       if (vflag)
-                               fprintf(stderr, "link %s to %s\n",
-                                       xp->x_linkedto->x_name, xp->x_name);
-                       if (xlink(xp->x_linkedto->x_name, xp->x_name) < 0)
-                               fprintf(stderr, "link failed\n");
-               }
-       }
-}
-#endif
-
-restorfiles(command, argv)
-       char command;
-       char **argv;
-{
-       int     rstrfile(), rstrskip();
-       register struct dinode *dp;
-       register struct inode *ip;
-       struct fs *fs;
-       int mode;
-       char mount[BUFSIZ + 1];
-       char *ptr[2];
-
-#ifndef STANDALONE
-       mount[0] = '\0';
-       strcpy(mount, "MOUNT=");
-       strncat(mount, *argv, BUFSIZ);
-       ptr[0] = mount;
-       ptr[1] = 0;
-       xmount(ptr);
-       iput(u.u_cdir); /* release root inode */
-       iput(u.u_rdir); /* release root inode */
-       mounted++;
-#else
-       do {
-               fprintf(stderr, "Disk? ");
-               gets(mount);
-               fi = open(mount, 2);
-       } while (fi == -1);
-#endif
-#ifndef STANDALONE
-       if (command == 'R') {
-               fprintf(stderr, "Enter starting volume number: ");
-               if (gets(tbf) == EOF) {
-                       volno = 1;
-                       fprintf(stderr, "\n");
-               }
-               else
-                       volno = atoi(tbf);
-       }
-       else
-#endif
-               volno = 1;
-       fprintf(stderr, "Last chance before scribbling on %s. ",
-#ifdef STANDALONE
-                                                       "disk");
-#else
-                                                       *argv);
-#endif
-       while (getchar() != '\n');
-       fs = getfs(dev);
-       maxi = fs->fs_ipg * fs->fs_ncg;
-       if (readhdr(&spcl) == 0) {
-               fprintf(stderr, "Missing volume record\n");
-               done(1);
-       }
-       if (checkvol(&spcl, volno) == 0) {
-               fprintf(stderr, "Tape is not volume %d\n", volno);
-               done(1);
-       }
-       gethead(&spcl);
-       for (;;) {
-ragain:
-               if (ishead(&spcl) == 0) {
-                       fprintf(stderr, "Missing header block\n");
-                       while (gethead(&spcl) == 0)
-                               ;
-                       eflag++;
-               }
-               if (checktype(&spcl, TS_END) == 1) {
-                       fprintf(stderr, "End of tape\n");
-                       close(mt);
-                       return;
-               }
-               if (checktype(&spcl, TS_CLRI) == 1) {
-                       readbits(clrimap);
-                       for (ino = 1; ino <= maxi; ino++)
-                               if (BIT(ino, clrimap) == 0) {
-                                       if (!iexist(dev, ino))
-                                               continue;
-                                       ip = iget(dev, ino);
-                                       if (ip == NULL) {
-                                               fprintf(stderr, "can't find inode %u\n", ino);
-                                               done(1);
-                                       }
-                                       ip->i_nlink = 0;
-                                       ip->i_flag |= ICHG;
-                                       iput(ip);
-                               }
-                       goto ragain;
-               }
-               if (checktype(&spcl, TS_BITS) == 1) {
-                       readbits(dumpmap);
-                       goto ragain;
-               }
-               if (checktype(&spcl, TS_INODE) == 0) {
-                       fprintf(stderr, "Unknown header type\n");
-                       eflag++;
-                       gethead(&spcl);
-                       goto ragain;
-               }
-               ino = spcl.c_inumber;
-               if (eflag)
-                       fprintf(stderr, "Resynced at inode %u\n", ino);
-               eflag = 0;
-               if (ino > maxi) {
-                       fprintf(stderr, "%u: ilist too small\n", ino);
-                       gethead(&spcl);
-                       goto ragain;
-               }
-               if (iexist(dev, ino)) {
-                       ip = iget(dev, ino);
-                       if (ip == NULL) {
-                               fprintf(stderr, "can't find inode %u\n",
-                                       ino);
+               case 'f':
+                       if (argc < 1) {
+                               fprintf(stderr, "missing device specifier\n");
                                done(1);
                        }
                                done(1);
                        }
-                       ip->i_nlink = 0;
-                       ip->i_flag |= ICHG;
-                       iput(ip);
-               }
-               dp = &spcl.c_dinode;
-               ip = ialloc(dev, ino, dp->di_mode);
-               if (ip == NULL || ip->i_number != ino) {
-                       fprintf(stderr, "can't create inode %u\n", ino);
-                       done(1);
-               }
-               ip->i_mode = mode = dp->di_mode;
-               ip->i_nlink = dp->di_nlink;
-               ip->i_uid = dp->di_uid;
-               ip->i_gid = dp->di_gid;
-               ip->i_atime = dp->di_atime;
-               ip->i_mtime = dp->di_mtime;
-               ip->i_ctime = dp->di_ctime;
-               if ((ip->i_mode & IFMT) == IFCHR ||
-                   (ip->i_mode & IFMT) == IFBLK)
-                       ip->i_rdev = dp->di_rdev;
-               ip->i_size = 0;
-               cur_ip = ip;
-               u.u_offset = 0;
-               u.u_segflg = 1;
-               getfile(rstrfile, rstrskip, dp->di_size);
-               ip->i_mode = mode;
-               ip->i_flag &= ~(IUPD|IACC);
-               ip->i_flag |= ICHG;
-               iput(ip);
-       }
-}
-
-/*
- * Read the tape, bulding up a directory structure for extraction
- * by name
- */
-#ifndef STANDALONE
-pass1()
-{
-       register int i;
-       register struct dinode *ip;
-       struct direct nulldir;
-       register struct inotab *itp;
-       int     putdir(), null();
-
-       nulldir.d_ino = 0;
-       strncpy(nulldir.d_name, "/", DIRSIZ);
-       while (gethead(&spcl) == 0) {
-               fprintf(stderr, "Can't find directory header!\n");
-       }
-       for (;;) {
-               if (checktype(&spcl, TS_BITS) == 1) {
-                       readbits(dumpmap);
-                       continue;
-               }
-               if (checktype(&spcl, TS_CLRI) == 1) {
-                       readbits(clrimap);
-                       continue;
-               }
-               if (checktype(&spcl, TS_INODE) == 0) {
-finish:
-/*     
-                       close(mt);
-*/
-                       freopen(dirfile, "r", df);
-                       return;
-               }
-               ip = &spcl.c_dinode;
-               i = ip->di_mode & IFMT;
-               if (i != IFDIR) {
-                       goto finish;
-               }
-               itp = getinotab(spcl.c_inumber);
-               itp->t_seekpt = seekpt;
-               getfile(putdir, null, spcl.c_dinode.di_size);
-               putent(&nulldir);
-       }
-}
-#endif
-
-/*
- * Do the file extraction, calling the supplied functions
- * with the blocks
- */
-getfile(f1, f2, size)
-       int     (*f2)(), (*f1)();
-       long    size;
-{
-       register int i;
-       char buf[BLKING * FRAG][TP_BSIZE];
-       union u_spcl addrblk;
-#      define addrblock addrblk.s_spcl
-
-       addrblock = spcl;
-       for (;;) {
-               for (i = 0; i < addrblock.c_count; i++) {
-                       if (addrblock.c_addr[i]) {
-                               readtape(&buf[curblk++][0]);
-                               if (curblk == BLKING * FRAG) {
-                                       (*f1)(buf, size > TP_BSIZE ?
-                                            (long) (BLKING * FRAG * TP_BSIZE) :
-                                            (curblk - 1) * TP_BSIZE + size);
-                                       curblk = 0;
-                               }
-                       }
-                       else {
-                               if (curblk > 0) {
-                                       (*f1)(buf, size > TP_BSIZE ?
-                                            (long) (curblk * TP_BSIZE) :
-                                            (curblk - 1) * TP_BSIZE + size);
-                                       curblk = 0;
-                               }
-                               (*f2)(clearedbuf, size > TP_BSIZE ? (long) TP_BSIZE : size);
-                       }
-                       if ((size -= TP_BSIZE) <= 0) {
-eloop:
-                               while (gethead(&spcl) == 0)
-                                       ;
-                               if (checktype(&spcl, TS_ADDR) == 1)
-                                       goto eloop;
-                               goto out;
+                       inputdev = *argv++;
+                       argc--;
+                       break;
+               case 'b':
+                       /*
+                        * change default tape blocksize
+                        */
+                       bflag++;
+                       if (argc < 1) {
+                               fprintf(stderr, "missing block size\n");
+                               done(1);
                        }
                        }
-               }
-               if (gethead(&addrblock) == 0) {
-                       fprintf(stderr, "Missing address (header) block, ino%u\n", ino);
-                       goto eloop;
-               }
-               if (checktype(&addrblock, TS_ADDR) == 0) {
-                       spcl = addrblock;
-                       goto out;
-               }
-       }
-out:
-       if (curblk > 0) {
-               (*f1)(buf, (curblk * TP_BSIZE) + size);
-               curblk = 0;
-       }
-}
-
-/*
- * Do the tape i/o, dealing with volume changes
- * etc..
- */
-readtape(b)
-       char *b;
-{
-       register int i;
-       struct s_spcl tmpbuf;
-
-       if (bct >= NTREC) {
-               for (i = 0; i < NTREC; i++)
-                       ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
-               bct = 0;
-               if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
-                       perror("Tape read error");
-                       eflag++;
-                       done(1);
-               }
-               if (i == 0) {
-                       bct = NTREC + 1;
-                       volno++;
-loop:
-                       flsht();
-                       close(mt);
-                       fprintf(stderr, "Mount volume %d\n", volno);
-                       while (getchar() != '\n')
-                               ;
-                       if ((mt = open(magtape, 0)) == -1) {
-                               fprintf(stderr, "Cannot open tape!\n");
-                               goto loop;
+                       ntrec = atoi(*argv++);
+                       if (ntrec <= 0) {
+                               fprintf(stderr, "Block size must be a positive integer\n");
+                               done(1);
                        }
                        }
-                       if (readhdr(&tmpbuf) == 0) {
-                               fprintf(stderr, "Not a dump tape.Try again\n");
-                               goto loop;
+                       argc--;
+                       break;
+               case 's':
+                       /*
+                        * dumpnum (skip to) for multifile dump tapes
+                        */
+                       if (argc < 1) {
+                               fprintf(stderr, "missing dump number\n");
+                               done(1);
                        }
                        }
-                       if (checkvol(&tmpbuf, volno) == 0) {
-                               fprintf(stderr, "Wrong tape. Try again\n");
-                               goto loop;
+                       dumpnum = atoi(*argv++);
+                       if (dumpnum <= 0) {
+                               fprintf(stderr, "Dump number must be a positive integer\n");
+                               done(1);
                        }
                        }
-                       readtape(b);
-                       return;
-               }
-       }
-       copy(&tbf[(bct++*TP_BSIZE)], b, TP_BSIZE);
-}
-
-flsht()
-{
-       bct = NTREC+1;
-}
-
-copy(f, t, s)
-       register char *f, *t;
-{
-       register int i;
-
-       i = s;
-       do
-               *t++ = *f++;
-       while (--i);
-}
-
-/*
- * Put the directory entries in the directory file
- */
-#ifndef STANDALONE
-putdir(buf, size)
-       char *buf;
-       int size;
-{
-       register struct direct *dp;
-       register int i;
-
-       for (dp = (struct direct *)buf, i = 0; i < size; dp++, i += sizeof(*dp))
-               if (dp->d_ino != 0)
-                       putent(dp);
-}
-
-putent(dp)
-       struct direct *dp;
-{
-       fwrite(dp, 1, sizeof(struct direct), df);
-       seekpt = ftell(df);
-}
-
-/*
- * search the directory inode ino
- * looking for entry cp
- */
-ino_t
-search(inum, cp)
-       ino_t   inum;
-       char    *cp;
-{
-       register int i;
-       struct direct dir;
-       register struct inotab *itp;
-
-       for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
-               if (itp->t_ino == inum)
-                       goto found;
-       return(0);
-found:
-       fseek(df, itp->t_seekpt, 0);
-       do {
-               fread(&dir, 1, sizeof(struct direct), df);
-               if (!strncmp(dir.d_name, "/", DIRSIZ))
-                       return(0);
-       } while (strncmp(dir.d_name, cp, DIRSIZ));
-       return(dir.d_ino);
-}
-
-/*
- * Search the directory tree rooted at inode ROOTINO
- * for the path pointed at by n
- */
-psearch(n)
-       char    *n;
-{
-       register char *cp, *cp1;
-       char c;
-
-       ino = ROOTINO;
-       if (*(cp = n) == '/')
-               cp++;
-next:
-       cp1 = cp + 1;
-       while (*cp1 != '/' && *cp1)
-               cp1++;
-       c = *cp1;
-       *cp1 = 0;
-       ino = search(ino, cp);
-       if (ino == 0) {
-               *cp1 = c;
-               return(0);
-       }
-       *cp1 = c;
-       if (c == '/') {
-               cp = cp1+1;
-               goto next;
-       }
-       return(ino);
-}
-#endif
-
-/*
- * read the tape into buf, then return whether or
- * or not it is a header block.
- */
-gethead(buf)
-       struct s_spcl *buf;
-{
-       readtape((char *)buf);
-       if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
-               return(0);
-       return(1);
-}
-
-/*
- * return whether or not the buffer contains a header block
- */
-ishead(buf)
-       struct s_spcl *buf;
-{
-       if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
-               return(0);
-       return(1);
-}
-
-checktype(b, t)
-       struct s_spcl *b;
-       int     t;
-{
-       return(b->c_type == t);
-}
-
-
-checksum(b)
-       int *b;
-{
-       register int i, j;
-
-       j = sizeof(union u_spcl) / sizeof(int);
-       i = 0;
-       do
-               i += *b++;
-       while (--j);
-       if (i != CHECKSUM) {
-               fprintf(stderr, "Checksum error %o, ino %u\n", i, ino);
-               return(0);
-       }
-       return(1);
-}
-
-checkvol(b, t)
-       struct s_spcl *b;
-       int t;
-{
-       if (b->c_volume == t)
-               return(1);
-       return(0);
-}
-
-readhdr(b)
-       struct s_spcl *b;
-{
-       if (gethead(b) == 0)
-               return(0);
-       if (checktype(b, TS_TAPE) == 0)
-               return(0);
-       return(1);
-}
-
-/*
- * The next routines are called during file extraction to
- * put the data into the right form and place.
- */
-#ifndef STANDALONE
-xtrfile(buf, size)
-       char    *buf;
-       long    size;
-{
-       if (xwrite(ofile, buf, (int) size) == -1) {
-               perror("extract write:");
-               done(1);
-       }
-}
-
-null() {;}
-
-skip(buf, size)
-       char *buf;
-       long size;
-{
-       if (xseek(ofile, size, 1) == -1) {
-               perror("extract seek:");
-               done(1);
-       }
-}
-#endif
-
-
-rstrfile(buf, size)
-       char *buf;
-       long size;
-{
-       u.u_base = buf;
-       u.u_count = size;
-       writei(cur_ip);
-       if (u.u_error) {
-               perror("restor write:");
-               done(1);
-       }
-}
-
-rstrskip(buf, size)
-       char *buf;
-       long size;
-{
-       u.u_offset += size;
-}
-
-/*
- * tell whether an inode is allocated
- * this is drawn from ialloccg in sys/alloc.c
- */
-iexist(dev, ino)
-       dev_t dev;
-       ino_t ino;
-{
-       register struct fs *fs;
-       register struct cg *cgp;
-       register struct buf *bp;
-       int cg;
-
-       fs = getfs(dev);
-       if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg)
-               return (0);
-       cg = itog(ino, fs);
-       bp = bread(dev, cgtod(cg, fs), BSIZE);
-       if (bp->b_flags & B_ERROR)
-               return(0);
-       cgp = bp->b_un.b_cg;
-       ino %= fs->fs_ipg;
-       if (isclr(cgp->cg_iused, ino)) {
-               brelse(bp);
-               return(0);
-       }
-       brelse(bp);
-       return (1);
-}
-
-/*
- * read a bit mask from the tape into m.
- */
-readbits(m)
-       short   *m;
-{
-       register int i;
-
-       i = spcl.c_count;
-
-       while (i--) {
-               readtape((char *) m);
-               m += (TP_BSIZE/(MLEN/BITS));
-       }
-       while (gethead(&spcl) == 0)
-               ;
-}
-
-done(exitcode)
-       int exitcode;
-{
-#ifndef STANDALONE
-       unlink(dirfile);
-#endif
-       if (mounted)
-               xumount();
-       exit(exitcode);
-}
-
-struct inotab *
-getinotab(ino)
-       ino_t ino;
-{
-       register struct inotab  *itp;
-
-       itp = (struct inotab *)calloc(1, sizeof(struct inotab));
-       itp->t_next = inotab[INOHASH(ino)];
-       inotab[INOHASH(ino)] = itp;
-       itp->t_ino = ino;
-       return itp;
-}
-
-struct xtrlist *
-getxtr(ino)
-       ino_t ino;
-{
-       struct xtrlist  *xp;
-
-       xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist));
-       xp->x_next = xtrlist[INOHASH(ino)];
-       xtrlist[INOHASH(ino)] = xp;
-       xp->x_ino = ino;
-       xtrcnt++;
-       return xp;
-}
-
-/*
- *     Check for access into each directory in the pathname of an extracted
- *     file and create such a directory if needed in preparation for moving 
- *     the file to its proper home.
- */
-checkdir(name)
-       register char *name;
-{
-       register char *cp;
-       int i;
-
-       for (cp = name; *cp; cp++) {
-               if (*cp == '/') {
-                       *cp = '\0';
-                       if (xaccess(name, 01) < 0) {
-                               register int pid, rp;
-
-                               xumount();
-                               if ((pid = fork()) == 0) {
-                                       execl("/bin/xmkdir", "xmkdir", name, 0);
-                                       execl("/usr/bin/xmkdir", "xmkdir", name, 0);
-                                       execl("./xmkdir", "xmkdir", name, 0);
-                                       fprintf(stderr, "xrestor: cannot find xmkdir!\n");
-                                       done(0);
-                               }
-                               while ((rp = wait(&i)) >= 0 && rp != pid)
-                                       ;
-                               xmount(envp);
+                       argc--;
+                       break;
+               case 't':
+               case 'R':
+               case 'r':
+               case 'x':
+               case 'i':
+                       if (command != '\0') {
+                               fprintf(stderr,
+                                       "%c and %c are mutually exclusive\n",
+                                       *cp, command);
+                               goto usage;
                        }
                        }
-                       *cp = '/';
+                       command = *cp;
+                       break;
+               default:
+                       fprintf(stderr, "Bad key character %c\n", *cp);
+                       goto usage;
                }
        }
                }
        }
-}
-
-/*
- *     Store a string in core returning a pointer to it.  Allocate space
- *     as needed.
- */
-char *
-ststore( stringp )
-       char *stringp;
-{
-       static char *spacep;
-       static int spaceleft;
-       char *rtnp, *savep;
-
-       rtnp = spacep;
-       savep = stringp;
-       while( spaceleft-- && (*spacep++ = *stringp++) );
-       if( spaceleft >= 0 )
-               return( rtnp );
-       else {
-               spaceleft = 10 * BUFSIZ;
-               spacep = (char *)malloc( spaceleft );
-               return( ststore(savep) );
+       if (command == '\0') {
+               fprintf(stderr, "must specify i, t, r, R, or x\n");
+               goto usage;
        }
        }
-}
-
-/*
- *     Recursively find names and inumbers of all files in subtree 
- *     pname and put them in xtrlist[]
- */
-getleaves(ino, pname)
-       ino_t ino;
-       char *pname;
-{
-       register struct xtrlist *xp, *pxp;
-       register struct inotab *itp;
-       int namelen;
-       daddr_t bpt;
-       char    locname[BUFSIZ];
-       struct direct dir;
-
-       if (BIT(ino, dumpmap) == 0) {
-               fprintf(stderr, "%s: not on the tape\n", pname);
-               return;
+       setinput(inputdev);
+       if (argc == 0) {
+               argc = 1;
+               *--argv = ".";
        }
        }
-       for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
-               if (itp->t_ino != ino)
-                       continue;
-               /*
-                * pname is a directory name 
-                */
-               xp = getxtr(ino);
-               xp->x_flags |= (XINUSE | XISDIR);
-               xp->x_name = ststore(pname);
-               if (vflag)
-                       fprintf(stderr, "%s: directory inode %u\n", pname, ino);
-               /*
-                * begin search through the directory
-                * skipping over "." and ".."
-                */
-               strncpy(locname, pname, BUFSIZ);
-               strncat(locname, "/", BUFSIZ);
-               namelen = strlen(locname);
-               bpt = itp->t_seekpt;
-               fseek(df, bpt, 0);
-               fread(&dir, 1, sizeof(struct direct), df);
-               fread(&dir, 1, sizeof(struct direct), df);
-               fread(&dir, 1, sizeof(struct direct), df);
-               bpt = ftell(df);
-               /*
-                * "/" signals end of directory
-                */
-               while (strncmp(dir.d_name, "/", DIRSIZ)) {
-                       locname[namelen] = '\0';
-                       strncat(locname, dir.d_name, DIRSIZ);
-                       if (strlen(locname) >= BUFSIZ) {
-                               fprintf(stderr, "%s: name exceedes %d char\n",
-                                       locname, BUFSIZ);
-                               continue;
-                       }
+       switch (command) {
+       /*
+        * Interactive mode.
+        */
+       case 'i':
+               setup();
+               extractdirs(1);
+               initsymtable((char *)0);
+               runcmdshell();
+               done(0);
+       /*
+        * Incremental restoration of a file system.
+        */
+       case 'r':
+               setup();
+               if (dumptime > 0) {
                        /*
                        /*
-                        * info for rereading drblock later
+                        * This is an incremental dump tape.
                         */
                         */
-                       getleaves(dir.d_ino, locname);
+                       vprintf(stdout, "Begin incremental restore\n");
+                       initsymtable(symtbl);
+                       extractdirs(1);
+                       removeoldleaves();
+                       vprintf(stdout, "Calculate node updates.\n");
+                       treescan(".", ROOTINO, nodeupdates);
+                       findunreflinks();
+                       removeoldnodes();
+               } else {
                        /*
                        /*
-                        * get next entry from drblock; reset
-                        * readsize iff physical disk read
+                        * This is a level zero dump tape.
                         */
                         */
-                       fseek(df, bpt, 0);
-                       fread(&dir, 1, sizeof(struct direct), df);
-                       bpt = ftell(df);
+                       vprintf(stdout, "Begin level 0 restore\n");
+                       initsymtable((char *)0);
+                       extractdirs(1);
+                       vprintf(stdout, "Calculate extraction list.\n");
+                       treescan(".", ROOTINO, nodeupdates);
                }
                }
-               return;
-       }
+               createleaves(symtbl);
+               createlinks();
+               setdirmodes();
+               checkrestore();
+               if (dflag) {
+                       vprintf(stdout, "Verify the directory structure\n");
+                       treescan(".", ROOTINO, verifyfile);
+               }
+               dumpsymtable(symtbl, (long)1);
+               done(0);
        /*
        /*
-        * locname is name of a simple file 
+        * Resume an incremental file system restoration.
         */
         */
-       xp = getxtr(ino);
-       xp->x_flags |= XINUSE;
-       xp->x_name = ststore(pname);
-       for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
-               if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
-                       xp->x_flags |= XLINKED;
-                       xp->x_linkedto = pxp;
-                       break;
+       case 'R':
+               initsymtable(symtbl);
+               skipmaps();
+               skipdirs();
+               createleaves(symtbl);
+               createlinks();
+               setdirmodes();
+               checkrestore();
+               dumpsymtable(symtbl, (long)1);
+               done(0);
+       /*
+        * List contents of tape.
+        */
+       case 't':
+               setup();
+               extractdirs(0);
+               initsymtable((char *)0);
+               while (argc--) {
+                       canon(*argv++, name);
+                       ino = dirlookup(name);
+                       if (ino == 0)
+                               continue;
+                       treescan(name, ino, listfile);
+               }
+               done(0);
+       /*
+        * Batch extraction of tape contents.
+        */
+       case 'x':
+               setup();
+               extractdirs(1);
+               initsymtable((char *)0);
+               while (argc--) {
+                       canon(*argv++, name);
+                       ino = dirlookup(name);
+                       if (ino == 0)
+                               continue;
+                       if (mflag)
+                               pathcheck(name);
+                       treescan(name, ino, addfile);
                }
                }
-       if (!vflag)
-               return;
-       if (xp->x_flags & XLINKED)
-               fprintf(stderr, "%s: linked to %s\n", xp->x_name, pxp->x_name);
-       else
-               fprintf(stderr, "%s: inode %u\n", xp->x_name, ino);
+               createfiles();
+               createlinks();
+               setdirmodes();
+               if (dflag)
+                       checkrestore();
+               done(0);
+       }
 }
 }