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