tape.c revision 35852
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1983, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * (c) UNIX System Laboratories, Inc. 51558Srgrimes * All or some portions of this file are derived from material licensed 61558Srgrimes * to the University of California by American Telephone and Telegraph 71558Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 81558Srgrimes * the permission of UNIX System Laboratories, Inc. 91558Srgrimes * 101558Srgrimes * Redistribution and use in source and binary forms, with or without 111558Srgrimes * modification, are permitted provided that the following conditions 121558Srgrimes * are met: 131558Srgrimes * 1. Redistributions of source code must retain the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer. 151558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161558Srgrimes * notice, this list of conditions and the following disclaimer in the 171558Srgrimes * documentation and/or other materials provided with the distribution. 181558Srgrimes * 3. All advertising materials mentioning features or use of this software 191558Srgrimes * must display the following acknowledgement: 201558Srgrimes * This product includes software developed by the University of 211558Srgrimes * California, Berkeley and its contributors. 221558Srgrimes * 4. Neither the name of the University nor the names of its contributors 231558Srgrimes * may be used to endorse or promote products derived from this software 241558Srgrimes * without specific prior written permission. 251558Srgrimes * 261558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361558Srgrimes * SUCH DAMAGE. 371558Srgrimes */ 381558Srgrimes 391558Srgrimes#ifndef lint 4023685Speterstatic char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; 411558Srgrimes#endif /* not lint */ 421558Srgrimes 431558Srgrimes#include <sys/param.h> 441558Srgrimes#include <sys/file.h> 451558Srgrimes#include <sys/ioctl.h> 461558Srgrimes#include <sys/mtio.h> 471558Srgrimes#include <sys/stat.h> 481558Srgrimes 491558Srgrimes#include <ufs/ufs/dinode.h> 501558Srgrimes#include <protocols/dumprestore.h> 511558Srgrimes 521558Srgrimes#include <errno.h> 531558Srgrimes#include <setjmp.h> 541558Srgrimes#include <stdio.h> 551558Srgrimes#include <stdlib.h> 561558Srgrimes#include <string.h> 571558Srgrimes#include <unistd.h> 581558Srgrimes 591558Srgrimes#include "restore.h" 601558Srgrimes#include "extern.h" 611558Srgrimes#include "pathnames.h" 621558Srgrimes 631558Srgrimesstatic long fssize = MAXBSIZE; 641558Srgrimesstatic int mt = -1; 651558Srgrimesstatic int pipein = 0; 6621174Sguidostatic char *magtape; 671558Srgrimesstatic int blkcnt; 681558Srgrimesstatic int numtrec; 691558Srgrimesstatic char *tapebuf; 701558Srgrimesstatic union u_spcl endoftapemark; 711558Srgrimesstatic long blksread; /* blocks read since last header */ 721558Srgrimesstatic long tpblksread = 0; /* TP_BSIZE blocks read */ 731558Srgrimesstatic long tapesread; 741558Srgrimesstatic jmp_buf restart; 751558Srgrimesstatic int gettingfile = 0; /* restart has a valid frame */ 761558Srgrimesstatic char *host = NULL; 771558Srgrimes 781558Srgrimesstatic int ofile; 791558Srgrimesstatic char *map; 801558Srgrimesstatic char lnkbuf[MAXPATHLEN + 1]; 811558Srgrimesstatic int pathlen; 821558Srgrimes 831558Srgrimesint oldinofmt; /* old inode format conversion required */ 841558Srgrimesint Bcvt; /* Swap Bytes (for CCI or sun) */ 851558Srgrimesstatic int Qcvt; /* Swap quads (for sun) */ 861558Srgrimes 871558Srgrimes#define FLUSHTAPEBUF() blkcnt = ntrec + 1 881558Srgrimes 891558Srgrimesstatic void accthdr __P((struct s_spcl *)); 901558Srgrimesstatic int checksum __P((int *)); 911558Srgrimesstatic void findinode __P((struct s_spcl *)); 921558Srgrimesstatic void findtapeblksize __P((void)); 931558Srgrimesstatic int gethead __P((struct s_spcl *)); 941558Srgrimesstatic void readtape __P((char *)); 951558Srgrimesstatic void setdumpnum __P((void)); 961558Srgrimesstatic u_long swabl __P((u_long)); 971558Srgrimesstatic u_char *swablong __P((u_char *, int)); 981558Srgrimesstatic u_char *swabshort __P((u_char *, int)); 991558Srgrimesstatic void terminateinput __P((void)); 1001558Srgrimesstatic void xtrfile __P((char *, long)); 1011558Srgrimesstatic void xtrlnkfile __P((char *, long)); 1021558Srgrimesstatic void xtrlnkskip __P((char *, long)); 1031558Srgrimesstatic void xtrmap __P((char *, long)); 1041558Srgrimesstatic void xtrmapskip __P((char *, long)); 1051558Srgrimesstatic void xtrskip __P((char *, long)); 1061558Srgrimes 1071558Srgrimes/* 1081558Srgrimes * Set up an input source 1091558Srgrimes */ 1101558Srgrimesvoid 1111558Srgrimessetinput(source) 1121558Srgrimes char *source; 1131558Srgrimes{ 1141558Srgrimes FLUSHTAPEBUF(); 1151558Srgrimes if (bflag) 1161558Srgrimes newtapebuf(ntrec); 1171558Srgrimes else 1181558Srgrimes newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 1191558Srgrimes terminal = stdin; 1201558Srgrimes 1211558Srgrimes#ifdef RRESTORE 12223685Speter if (strchr(source, ':')) { 1231558Srgrimes host = source; 12423685Speter source = strchr(host, ':'); 1251558Srgrimes *source++ = '\0'; 1261558Srgrimes if (rmthost(host) == 0) 1271558Srgrimes done(1); 1281558Srgrimes } else 1291558Srgrimes#endif 1301558Srgrimes if (strcmp(source, "-") == 0) { 1311558Srgrimes /* 1321558Srgrimes * Since input is coming from a pipe we must establish 1331558Srgrimes * our own connection to the terminal. 1341558Srgrimes */ 1351558Srgrimes terminal = fopen(_PATH_TTY, "r"); 1361558Srgrimes if (terminal == NULL) { 1371558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1381558Srgrimes _PATH_TTY, strerror(errno)); 1391558Srgrimes terminal = fopen(_PATH_DEVNULL, "r"); 1401558Srgrimes if (terminal == NULL) { 1411558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1421558Srgrimes _PATH_DEVNULL, strerror(errno)); 1431558Srgrimes done(1); 1441558Srgrimes } 1451558Srgrimes } 1461558Srgrimes pipein++; 1471558Srgrimes } 1481558Srgrimes setuid(getuid()); /* no longer need or want root privileges */ 14921174Sguido magtape = strdup(source); 15021174Sguido if (magtape == NULL) { 15121174Sguido fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 15221174Sguido done(1); 15321174Sguido } 1541558Srgrimes} 1551558Srgrimes 1561558Srgrimesvoid 1571558Srgrimesnewtapebuf(size) 1581558Srgrimes long size; 1591558Srgrimes{ 1601558Srgrimes static tapebufsize = -1; 1611558Srgrimes 1621558Srgrimes ntrec = size; 1631558Srgrimes if (size <= tapebufsize) 1641558Srgrimes return; 1651558Srgrimes if (tapebuf != NULL) 1661558Srgrimes free(tapebuf); 1671558Srgrimes tapebuf = malloc(size * TP_BSIZE); 1681558Srgrimes if (tapebuf == NULL) { 1691558Srgrimes fprintf(stderr, "Cannot allocate space for tape buffer\n"); 1701558Srgrimes done(1); 1711558Srgrimes } 1721558Srgrimes tapebufsize = size; 1731558Srgrimes} 1741558Srgrimes 1751558Srgrimes/* 1761558Srgrimes * Verify that the tape drive can be accessed and 1771558Srgrimes * that it actually is a dump tape. 1781558Srgrimes */ 1791558Srgrimesvoid 1801558Srgrimessetup() 1811558Srgrimes{ 1821558Srgrimes int i, j, *ip; 1831558Srgrimes struct stat stbuf; 1841558Srgrimes 1851558Srgrimes vprintf(stdout, "Verify tape and initialize maps\n"); 1861558Srgrimes#ifdef RRESTORE 1871558Srgrimes if (host) 1881558Srgrimes mt = rmtopen(magtape, 0); 1891558Srgrimes else 1901558Srgrimes#endif 1911558Srgrimes if (pipein) 1921558Srgrimes mt = 0; 1931558Srgrimes else 1941558Srgrimes mt = open(magtape, O_RDONLY, 0); 1951558Srgrimes if (mt < 0) { 1961558Srgrimes fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 1971558Srgrimes done(1); 1981558Srgrimes } 1991558Srgrimes volno = 1; 2001558Srgrimes setdumpnum(); 2011558Srgrimes FLUSHTAPEBUF(); 2021558Srgrimes if (!pipein && !bflag) 2031558Srgrimes findtapeblksize(); 2041558Srgrimes if (gethead(&spcl) == FAIL) { 2051558Srgrimes blkcnt--; /* push back this block */ 2061558Srgrimes blksread--; 2071558Srgrimes tpblksread--; 2081558Srgrimes cvtflag++; 2091558Srgrimes if (gethead(&spcl) == FAIL) { 2101558Srgrimes fprintf(stderr, "Tape is not a dump tape\n"); 2111558Srgrimes done(1); 2121558Srgrimes } 2131558Srgrimes fprintf(stderr, "Converting to new file system format.\n"); 2141558Srgrimes } 2151558Srgrimes if (pipein) { 2161558Srgrimes endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; 2171558Srgrimes endoftapemark.s_spcl.c_type = TS_END; 2181558Srgrimes ip = (int *)&endoftapemark; 2191558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 2201558Srgrimes i = 0; 2211558Srgrimes do 2221558Srgrimes i += *ip++; 2231558Srgrimes while (--j); 2241558Srgrimes endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 2251558Srgrimes } 2261558Srgrimes if (vflag || command == 't') 2271558Srgrimes printdumpinfo(); 2281558Srgrimes dumptime = spcl.c_ddate; 2291558Srgrimes dumpdate = spcl.c_date; 2301558Srgrimes if (stat(".", &stbuf) < 0) { 2311558Srgrimes fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 2321558Srgrimes done(1); 2331558Srgrimes } 23434851Sjkh if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 23534851Sjkh fssize = TP_BSIZE; 23634851Sjkh if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 2371558Srgrimes fssize = stbuf.st_blksize; 2381558Srgrimes if (((fssize - 1) & fssize) != 0) { 2391558Srgrimes fprintf(stderr, "bad block size %d\n", fssize); 2401558Srgrimes done(1); 2411558Srgrimes } 2421558Srgrimes if (spcl.c_volume != 1) { 2431558Srgrimes fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2441558Srgrimes done(1); 2451558Srgrimes } 2461558Srgrimes if (gethead(&spcl) == FAIL) { 2471558Srgrimes dprintf(stdout, "header read failed at %d blocks\n", blksread); 2481558Srgrimes panic("no header after volume mark!\n"); 2491558Srgrimes } 2501558Srgrimes findinode(&spcl); 2511558Srgrimes if (spcl.c_type != TS_CLRI) { 2521558Srgrimes fprintf(stderr, "Cannot find file removal list\n"); 2531558Srgrimes done(1); 2541558Srgrimes } 2551558Srgrimes maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 2561558Srgrimes dprintf(stdout, "maxino = %d\n", maxino); 2571558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2581558Srgrimes if (map == NULL) 25923685Speter panic("no memory for active inode map\n"); 26023685Speter usedinomap = map; 2611558Srgrimes curfile.action = USING; 2621558Srgrimes getfile(xtrmap, xtrmapskip); 2631558Srgrimes if (spcl.c_type != TS_BITS) { 2641558Srgrimes fprintf(stderr, "Cannot find file dump list\n"); 2651558Srgrimes done(1); 2661558Srgrimes } 2671558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2681558Srgrimes if (map == (char *)NULL) 2691558Srgrimes panic("no memory for file dump list\n"); 2701558Srgrimes dumpmap = map; 2711558Srgrimes curfile.action = USING; 2721558Srgrimes getfile(xtrmap, xtrmapskip); 27323685Speter /* 27423685Speter * If there may be whiteout entries on the tape, pretend that the 27523685Speter * whiteout inode exists, so that the whiteout entries can be 27623685Speter * extracted. 27723685Speter */ 27823685Speter if (oldinofmt == 0) 27923685Speter SETINO(WINO, dumpmap); 2801558Srgrimes} 2811558Srgrimes 2821558Srgrimes/* 2831558Srgrimes * Prompt user to load a new dump volume. 2841558Srgrimes * "Nextvol" is the next suggested volume to use. 2851558Srgrimes * This suggested volume is enforced when doing full 2861558Srgrimes * or incremental restores, but can be overrridden by 2871558Srgrimes * the user when only extracting a subset of the files. 2881558Srgrimes */ 2891558Srgrimesvoid 2901558Srgrimesgetvol(nextvol) 2911558Srgrimes long nextvol; 2921558Srgrimes{ 2931558Srgrimes long newvol, savecnt, wantnext, i; 2941558Srgrimes union u_spcl tmpspcl; 2951558Srgrimes# define tmpbuf tmpspcl.s_spcl 2961558Srgrimes char buf[TP_BSIZE]; 2971558Srgrimes 2981558Srgrimes if (nextvol == 1) { 2991558Srgrimes tapesread = 0; 3001558Srgrimes gettingfile = 0; 3011558Srgrimes } 3021558Srgrimes if (pipein) { 3031558Srgrimes if (nextvol != 1) 3041558Srgrimes panic("Changing volumes on pipe input?\n"); 3051558Srgrimes if (volno == 1) 3061558Srgrimes return; 3071558Srgrimes goto gethdr; 3081558Srgrimes } 3091558Srgrimes savecnt = blksread; 3101558Srgrimesagain: 3111558Srgrimes if (pipein) 3121558Srgrimes done(1); /* pipes do not get a second chance */ 3131558Srgrimes if (command == 'R' || command == 'r' || curfile.action != SKIP) { 3141558Srgrimes newvol = nextvol; 3151558Srgrimes wantnext = 1; 3168871Srgrimes } else { 3171558Srgrimes newvol = 0; 3181558Srgrimes wantnext = 0; 3191558Srgrimes } 3201558Srgrimes while (newvol <= 0) { 3211558Srgrimes if (tapesread == 0) { 3221558Srgrimes fprintf(stderr, "%s%s%s%s%s", 3231558Srgrimes "You have not read any tapes yet.\n", 3241558Srgrimes "Unless you know which volume your", 3251558Srgrimes " file(s) are on you should start\n", 3261558Srgrimes "with the last volume and work", 32731925Smax " towards the first.\n"); 3281558Srgrimes } else { 3291558Srgrimes fprintf(stderr, "You have read volumes"); 3301558Srgrimes strcpy(buf, ": "); 3311558Srgrimes for (i = 1; i < 32; i++) 3321558Srgrimes if (tapesread & (1 << i)) { 3331558Srgrimes fprintf(stderr, "%s%d", buf, i); 3341558Srgrimes strcpy(buf, ", "); 3351558Srgrimes } 3361558Srgrimes fprintf(stderr, "\n"); 3371558Srgrimes } 3381558Srgrimes do { 3391558Srgrimes fprintf(stderr, "Specify next volume #: "); 3401558Srgrimes (void) fflush(stderr); 3411558Srgrimes (void) fgets(buf, BUFSIZ, terminal); 3421558Srgrimes } while (!feof(terminal) && buf[0] == '\n'); 3431558Srgrimes if (feof(terminal)) 3441558Srgrimes done(1); 3451558Srgrimes newvol = atoi(buf); 3461558Srgrimes if (newvol <= 0) { 3471558Srgrimes fprintf(stderr, 3481558Srgrimes "Volume numbers are positive numerics\n"); 3491558Srgrimes } 3501558Srgrimes } 3511558Srgrimes if (newvol == volno) { 3521558Srgrimes tapesread |= 1 << volno; 3531558Srgrimes return; 3541558Srgrimes } 3551558Srgrimes closemt(); 3561558Srgrimes fprintf(stderr, "Mount tape volume %d\n", newvol); 3571558Srgrimes fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 3581558Srgrimes fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 3591558Srgrimes (void) fflush(stderr); 3601558Srgrimes (void) fgets(buf, BUFSIZ, terminal); 3611558Srgrimes if (feof(terminal)) 3621558Srgrimes done(1); 3631558Srgrimes if (!strcmp(buf, "none\n")) { 3641558Srgrimes terminateinput(); 3651558Srgrimes return; 3661558Srgrimes } 3671558Srgrimes if (buf[0] != '\n') { 3681558Srgrimes (void) strcpy(magtape, buf); 3691558Srgrimes magtape[strlen(magtape) - 1] = '\0'; 3701558Srgrimes } 3711558Srgrimes#ifdef RRESTORE 3721558Srgrimes if (host) 3731558Srgrimes mt = rmtopen(magtape, 0); 3741558Srgrimes else 3751558Srgrimes#endif 3761558Srgrimes mt = open(magtape, O_RDONLY, 0); 3771558Srgrimes 3781558Srgrimes if (mt == -1) { 3791558Srgrimes fprintf(stderr, "Cannot open %s\n", magtape); 3801558Srgrimes volno = -1; 3811558Srgrimes goto again; 3821558Srgrimes } 3831558Srgrimesgethdr: 3841558Srgrimes volno = newvol; 3851558Srgrimes setdumpnum(); 3861558Srgrimes FLUSHTAPEBUF(); 3871558Srgrimes if (gethead(&tmpbuf) == FAIL) { 3881558Srgrimes dprintf(stdout, "header read failed at %d blocks\n", blksread); 3891558Srgrimes fprintf(stderr, "tape is not dump tape\n"); 3901558Srgrimes volno = 0; 3911558Srgrimes goto again; 3921558Srgrimes } 3931558Srgrimes if (tmpbuf.c_volume != volno) { 3941558Srgrimes fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume); 3951558Srgrimes volno = 0; 3961558Srgrimes goto again; 3971558Srgrimes } 3981558Srgrimes if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { 3991558Srgrimes fprintf(stderr, "Wrong dump date\n\tgot: %s", 4001558Srgrimes ctime(&tmpbuf.c_date)); 4011558Srgrimes fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 4021558Srgrimes volno = 0; 4031558Srgrimes goto again; 4041558Srgrimes } 4051558Srgrimes tapesread |= 1 << volno; 4061558Srgrimes blksread = savecnt; 4071558Srgrimes /* 4081558Srgrimes * If continuing from the previous volume, skip over any 4091558Srgrimes * blocks read already at the end of the previous volume. 4101558Srgrimes * 4111558Srgrimes * If coming to this volume at random, skip to the beginning 4121558Srgrimes * of the next record. 4131558Srgrimes */ 4148871Srgrimes dprintf(stdout, "read %ld recs, tape starts with %ld\n", 4151558Srgrimes tpblksread, tmpbuf.c_firstrec); 4161558Srgrimes if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { 4171558Srgrimes if (!wantnext) { 4181558Srgrimes tpblksread = tmpbuf.c_firstrec; 4191558Srgrimes for (i = tmpbuf.c_count; i > 0; i--) 4201558Srgrimes readtape(buf); 4211558Srgrimes } else if (tmpbuf.c_firstrec > 0 && 4221558Srgrimes tmpbuf.c_firstrec < tpblksread - 1) { 4231558Srgrimes /* 4241558Srgrimes * -1 since we've read the volume header 4251558Srgrimes */ 4261558Srgrimes i = tpblksread - tmpbuf.c_firstrec - 1; 4271558Srgrimes dprintf(stderr, "Skipping %d duplicate record%s.\n", 4281558Srgrimes i, i > 1 ? "s" : ""); 4291558Srgrimes while (--i >= 0) 4301558Srgrimes readtape(buf); 4311558Srgrimes } 4321558Srgrimes } 4331558Srgrimes if (curfile.action == USING) { 4341558Srgrimes if (volno == 1) 4351558Srgrimes panic("active file into volume 1\n"); 4361558Srgrimes return; 4371558Srgrimes } 4381558Srgrimes /* 4391558Srgrimes * Skip up to the beginning of the next record 4401558Srgrimes */ 4411558Srgrimes if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) 4421558Srgrimes for (i = tmpbuf.c_count; i > 0; i--) 4431558Srgrimes readtape(buf); 4441558Srgrimes (void) gethead(&spcl); 4451558Srgrimes findinode(&spcl); 4461558Srgrimes if (gettingfile) { 4471558Srgrimes gettingfile = 0; 4481558Srgrimes longjmp(restart, 1); 4491558Srgrimes } 4501558Srgrimes} 4511558Srgrimes 4521558Srgrimes/* 4531558Srgrimes * Handle unexpected EOF. 4541558Srgrimes */ 4551558Srgrimesstatic void 4561558Srgrimesterminateinput() 4571558Srgrimes{ 4581558Srgrimes 4591558Srgrimes if (gettingfile && curfile.action == USING) { 4601558Srgrimes printf("Warning: %s %s\n", 4611558Srgrimes "End-of-input encountered while extracting", curfile.name); 4621558Srgrimes } 4631558Srgrimes curfile.name = "<name unknown>"; 4641558Srgrimes curfile.action = UNKNOWN; 4651558Srgrimes curfile.dip = NULL; 4661558Srgrimes curfile.ino = maxino; 4671558Srgrimes if (gettingfile) { 4681558Srgrimes gettingfile = 0; 4691558Srgrimes longjmp(restart, 1); 4701558Srgrimes } 4711558Srgrimes} 4721558Srgrimes 4731558Srgrimes/* 4741558Srgrimes * handle multiple dumps per tape by skipping forward to the 4751558Srgrimes * appropriate one. 4761558Srgrimes */ 4771558Srgrimesstatic void 4781558Srgrimessetdumpnum() 4791558Srgrimes{ 4801558Srgrimes struct mtop tcom; 4811558Srgrimes 4821558Srgrimes if (dumpnum == 1 || volno != 1) 4831558Srgrimes return; 4841558Srgrimes if (pipein) { 4851558Srgrimes fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 4861558Srgrimes done(1); 4871558Srgrimes } 4881558Srgrimes tcom.mt_op = MTFSF; 4891558Srgrimes tcom.mt_count = dumpnum - 1; 4901558Srgrimes#ifdef RRESTORE 4911558Srgrimes if (host) 4921558Srgrimes rmtioctl(MTFSF, dumpnum - 1); 4938871Srgrimes else 4941558Srgrimes#endif 4951558Srgrimes if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) 4961558Srgrimes fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 4971558Srgrimes} 4981558Srgrimes 4991558Srgrimesvoid 5001558Srgrimesprintdumpinfo() 5011558Srgrimes{ 5021558Srgrimes fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); 5031558Srgrimes fprintf(stdout, "Dumped from: %s", 5041558Srgrimes (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate)); 5051558Srgrimes if (spcl.c_host[0] == '\0') 5061558Srgrimes return; 5071558Srgrimes fprintf(stderr, "Level %d dump of %s on %s:%s\n", 5081558Srgrimes spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 5091558Srgrimes fprintf(stderr, "Label: %s\n", spcl.c_label); 5101558Srgrimes} 5111558Srgrimes 5121558Srgrimesint 5131558Srgrimesextractfile(name) 5141558Srgrimes char *name; 5151558Srgrimes{ 51623685Speter int flags; 51723685Speter mode_t mode; 5181558Srgrimes struct timeval timep[2]; 5191558Srgrimes struct entry *ep; 5201558Srgrimes 5211558Srgrimes curfile.name = name; 5221558Srgrimes curfile.action = USING; 52323685Speter timep[0].tv_sec = curfile.dip->di_atime; 52423685Speter timep[0].tv_usec = curfile.dip->di_atimensec / 1000; 52523685Speter timep[1].tv_sec = curfile.dip->di_mtime; 52623685Speter timep[1].tv_usec = curfile.dip->di_mtimensec / 1000; 5271558Srgrimes mode = curfile.dip->di_mode; 52823685Speter flags = curfile.dip->di_flags; 5291558Srgrimes switch (mode & IFMT) { 5301558Srgrimes 5311558Srgrimes default: 5321558Srgrimes fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 5331558Srgrimes skipfile(); 5341558Srgrimes return (FAIL); 5351558Srgrimes 5361558Srgrimes case IFSOCK: 5371558Srgrimes vprintf(stdout, "skipped socket %s\n", name); 5381558Srgrimes skipfile(); 5391558Srgrimes return (GOOD); 5401558Srgrimes 5411558Srgrimes case IFDIR: 5421558Srgrimes if (mflag) { 5431558Srgrimes ep = lookupname(name); 5441558Srgrimes if (ep == NULL || ep->e_flags & EXTRACT) 5451558Srgrimes panic("unextracted directory %s\n", name); 5461558Srgrimes skipfile(); 5471558Srgrimes return (GOOD); 5481558Srgrimes } 5491558Srgrimes vprintf(stdout, "extract file %s\n", name); 5501558Srgrimes return (genliteraldir(name, curfile.ino)); 5511558Srgrimes 5521558Srgrimes case IFLNK: 5531558Srgrimes lnkbuf[0] = '\0'; 5541558Srgrimes pathlen = 0; 5551558Srgrimes getfile(xtrlnkfile, xtrlnkskip); 5561558Srgrimes if (pathlen == 0) { 5571558Srgrimes vprintf(stdout, 5581558Srgrimes "%s: zero length symbolic link (ignored)\n", name); 5591558Srgrimes return (GOOD); 5601558Srgrimes } 5611558Srgrimes return (linkit(lnkbuf, name, SYMLINK)); 5621558Srgrimes 5636305Smartin case IFIFO: 56423685Speter vprintf(stdout, "extract fifo %s\n", name); 56523685Speter if (Nflag) { 56623685Speter skipfile(); 56723685Speter return (GOOD); 56823685Speter } 56935852Sjkh if (uflag && !Nflag) 57035852Sjkh (void)unlink(name); 5716305Smartin if (mkfifo(name, mode) < 0) { 57223685Speter fprintf(stderr, "%s: cannot create fifo: %s\n", 57323685Speter name, strerror(errno)); 5746305Smartin skipfile(); 5756305Smartin return (FAIL); 5766305Smartin } 5776305Smartin (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 5786305Smartin (void) chmod(name, mode); 57923685Speter (void) chflags(name, flags); 5806305Smartin skipfile(); 5816305Smartin utimes(name, timep); 5826305Smartin return (GOOD); 5836305Smartin 5841558Srgrimes case IFCHR: 5851558Srgrimes case IFBLK: 5861558Srgrimes vprintf(stdout, "extract special file %s\n", name); 5871558Srgrimes if (Nflag) { 5881558Srgrimes skipfile(); 5891558Srgrimes return (GOOD); 5901558Srgrimes } 59135852Sjkh if (uflag) 59235852Sjkh (void)unlink(name); 5931558Srgrimes if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { 5941558Srgrimes fprintf(stderr, "%s: cannot create special file: %s\n", 5951558Srgrimes name, strerror(errno)); 5961558Srgrimes skipfile(); 5971558Srgrimes return (FAIL); 5981558Srgrimes } 5991558Srgrimes (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 6001558Srgrimes (void) chmod(name, mode); 60123685Speter (void) chflags(name, flags); 6021558Srgrimes skipfile(); 6031558Srgrimes utimes(name, timep); 6041558Srgrimes return (GOOD); 6051558Srgrimes 6061558Srgrimes case IFREG: 6071558Srgrimes vprintf(stdout, "extract file %s\n", name); 6081558Srgrimes if (Nflag) { 6091558Srgrimes skipfile(); 6101558Srgrimes return (GOOD); 6111558Srgrimes } 61235852Sjkh if (uflag) 61335852Sjkh (void)unlink(name); 61421149Simp if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 61521149Simp 0666)) < 0) { 6161558Srgrimes fprintf(stderr, "%s: cannot create file: %s\n", 6171558Srgrimes name, strerror(errno)); 6181558Srgrimes skipfile(); 6191558Srgrimes return (FAIL); 6201558Srgrimes } 6211558Srgrimes (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); 6221558Srgrimes (void) fchmod(ofile, mode); 62323685Speter (void) fchflags(ofile, flags); 6241558Srgrimes getfile(xtrfile, xtrskip); 6251558Srgrimes (void) close(ofile); 6261558Srgrimes utimes(name, timep); 6271558Srgrimes return (GOOD); 6281558Srgrimes } 6291558Srgrimes /* NOTREACHED */ 6301558Srgrimes} 6311558Srgrimes 6321558Srgrimes/* 6331558Srgrimes * skip over bit maps on the tape 6341558Srgrimes */ 6351558Srgrimesvoid 6361558Srgrimesskipmaps() 6371558Srgrimes{ 6381558Srgrimes 6391558Srgrimes while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 6401558Srgrimes skipfile(); 6411558Srgrimes} 6421558Srgrimes 6431558Srgrimes/* 6441558Srgrimes * skip over a file on the tape 6451558Srgrimes */ 6461558Srgrimesvoid 6471558Srgrimesskipfile() 6481558Srgrimes{ 6491558Srgrimes 6501558Srgrimes curfile.action = SKIP; 6511558Srgrimes getfile(xtrnull, xtrnull); 6521558Srgrimes} 6531558Srgrimes 6541558Srgrimes/* 6551558Srgrimes * Extract a file from the tape. 6561558Srgrimes * When an allocated block is found it is passed to the fill function; 6571558Srgrimes * when an unallocated block (hole) is found, a zeroed buffer is passed 6581558Srgrimes * to the skip function. 6591558Srgrimes */ 6601558Srgrimesvoid 6611558Srgrimesgetfile(fill, skip) 6621558Srgrimes void (*fill) __P((char *, long)); 6631558Srgrimes void (*skip) __P((char *, long)); 6641558Srgrimes{ 6651558Srgrimes register int i; 6661558Srgrimes int curblk = 0; 66723685Speter quad_t size = spcl.c_dinode.di_size; 6681558Srgrimes static char clearedbuf[MAXBSIZE]; 6691558Srgrimes char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 6701558Srgrimes char junk[TP_BSIZE]; 6711558Srgrimes 6721558Srgrimes if (spcl.c_type == TS_END) 6731558Srgrimes panic("ran off end of tape\n"); 6741558Srgrimes if (spcl.c_magic != NFS_MAGIC) 6751558Srgrimes panic("not at beginning of a file\n"); 6761558Srgrimes if (!gettingfile && setjmp(restart) != 0) 6771558Srgrimes return; 6781558Srgrimes gettingfile++; 6791558Srgrimesloop: 6801558Srgrimes for (i = 0; i < spcl.c_count; i++) { 6811558Srgrimes if (spcl.c_addr[i]) { 6821558Srgrimes readtape(&buf[curblk++][0]); 6831558Srgrimes if (curblk == fssize / TP_BSIZE) { 68423685Speter (*fill)((char *)buf, (long)(size > TP_BSIZE ? 68523685Speter fssize : (curblk - 1) * TP_BSIZE + size)); 6861558Srgrimes curblk = 0; 6871558Srgrimes } 6881558Srgrimes } else { 6891558Srgrimes if (curblk > 0) { 69023685Speter (*fill)((char *)buf, (long)(size > TP_BSIZE ? 69123685Speter curblk * TP_BSIZE : 69223685Speter (curblk - 1) * TP_BSIZE + size)); 6931558Srgrimes curblk = 0; 6941558Srgrimes } 69523685Speter (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 69623685Speter TP_BSIZE : size)); 6971558Srgrimes } 6981558Srgrimes if ((size -= TP_BSIZE) <= 0) { 6991558Srgrimes for (i++; i < spcl.c_count; i++) 7001558Srgrimes if (spcl.c_addr[i]) 7011558Srgrimes readtape(junk); 7021558Srgrimes break; 7031558Srgrimes } 7041558Srgrimes } 7051558Srgrimes if (gethead(&spcl) == GOOD && size > 0) { 7061558Srgrimes if (spcl.c_type == TS_ADDR) 7071558Srgrimes goto loop; 7081558Srgrimes dprintf(stdout, 7091558Srgrimes "Missing address (header) block for %s at %d blocks\n", 7101558Srgrimes curfile.name, blksread); 7111558Srgrimes } 7121558Srgrimes if (curblk > 0) 71323685Speter (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size)); 7141558Srgrimes findinode(&spcl); 7151558Srgrimes gettingfile = 0; 7161558Srgrimes} 7171558Srgrimes 7181558Srgrimes/* 7191558Srgrimes * Write out the next block of a file. 7201558Srgrimes */ 7211558Srgrimesstatic void 7221558Srgrimesxtrfile(buf, size) 7231558Srgrimes char *buf; 7241558Srgrimes long size; 7251558Srgrimes{ 7261558Srgrimes 7271558Srgrimes if (Nflag) 7281558Srgrimes return; 7291558Srgrimes if (write(ofile, buf, (int) size) == -1) { 7301558Srgrimes fprintf(stderr, 7311558Srgrimes "write error extracting inode %d, name %s\nwrite: %s\n", 7321558Srgrimes curfile.ino, curfile.name, strerror(errno)); 7331558Srgrimes done(1); 7341558Srgrimes } 7351558Srgrimes} 7361558Srgrimes 7371558Srgrimes/* 7381558Srgrimes * Skip over a hole in a file. 7391558Srgrimes */ 7401558Srgrimes/* ARGSUSED */ 7411558Srgrimesstatic void 7421558Srgrimesxtrskip(buf, size) 7431558Srgrimes char *buf; 7441558Srgrimes long size; 7451558Srgrimes{ 7461558Srgrimes 7471558Srgrimes if (lseek(ofile, size, SEEK_CUR) == -1) { 7481558Srgrimes fprintf(stderr, 7491558Srgrimes "seek error extracting inode %d, name %s\nlseek: %s\n", 7501558Srgrimes curfile.ino, curfile.name, strerror(errno)); 7511558Srgrimes done(1); 7521558Srgrimes } 7531558Srgrimes} 7541558Srgrimes 7551558Srgrimes/* 7561558Srgrimes * Collect the next block of a symbolic link. 7571558Srgrimes */ 7581558Srgrimesstatic void 7591558Srgrimesxtrlnkfile(buf, size) 7601558Srgrimes char *buf; 7611558Srgrimes long size; 7621558Srgrimes{ 7631558Srgrimes 7641558Srgrimes pathlen += size; 7651558Srgrimes if (pathlen > MAXPATHLEN) { 7661558Srgrimes fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 7671558Srgrimes curfile.name, lnkbuf, buf, pathlen); 7681558Srgrimes done(1); 7691558Srgrimes } 7701558Srgrimes (void) strcat(lnkbuf, buf); 7711558Srgrimes} 7721558Srgrimes 7731558Srgrimes/* 7741558Srgrimes * Skip over a hole in a symbolic link (should never happen). 7751558Srgrimes */ 7761558Srgrimes/* ARGSUSED */ 7771558Srgrimesstatic void 7781558Srgrimesxtrlnkskip(buf, size) 7791558Srgrimes char *buf; 7801558Srgrimes long size; 7811558Srgrimes{ 7821558Srgrimes 7831558Srgrimes fprintf(stderr, "unallocated block in symbolic link %s\n", 7841558Srgrimes curfile.name); 7851558Srgrimes done(1); 7861558Srgrimes} 7871558Srgrimes 7881558Srgrimes/* 7891558Srgrimes * Collect the next block of a bit map. 7901558Srgrimes */ 7911558Srgrimesstatic void 7921558Srgrimesxtrmap(buf, size) 7931558Srgrimes char *buf; 7941558Srgrimes long size; 7951558Srgrimes{ 7961558Srgrimes 79723685Speter memmove(map, buf, size); 7981558Srgrimes map += size; 7991558Srgrimes} 8001558Srgrimes 8011558Srgrimes/* 8021558Srgrimes * Skip over a hole in a bit map (should never happen). 8031558Srgrimes */ 8041558Srgrimes/* ARGSUSED */ 8051558Srgrimesstatic void 8061558Srgrimesxtrmapskip(buf, size) 8071558Srgrimes char *buf; 8081558Srgrimes long size; 8091558Srgrimes{ 8101558Srgrimes 8111558Srgrimes panic("hole in map\n"); 8121558Srgrimes map += size; 8131558Srgrimes} 8141558Srgrimes 8151558Srgrimes/* 8161558Srgrimes * Noop, when an extraction function is not needed. 8171558Srgrimes */ 8181558Srgrimes/* ARGSUSED */ 8191558Srgrimesvoid 8201558Srgrimesxtrnull(buf, size) 8211558Srgrimes char *buf; 8221558Srgrimes long size; 8231558Srgrimes{ 8241558Srgrimes 8251558Srgrimes return; 8261558Srgrimes} 8271558Srgrimes 8281558Srgrimes/* 8291558Srgrimes * Read TP_BSIZE blocks from the input. 8301558Srgrimes * Handle read errors, and end of media. 8311558Srgrimes */ 8321558Srgrimesstatic void 8331558Srgrimesreadtape(buf) 8341558Srgrimes char *buf; 8351558Srgrimes{ 8361558Srgrimes long rd, newvol, i; 8371558Srgrimes int cnt, seek_failed; 8381558Srgrimes 8391558Srgrimes if (blkcnt < numtrec) { 84023685Speter memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 8411558Srgrimes blksread++; 8421558Srgrimes tpblksread++; 8431558Srgrimes return; 8441558Srgrimes } 8451558Srgrimes for (i = 0; i < ntrec; i++) 8461558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 8471558Srgrimes if (numtrec == 0) 8481558Srgrimes numtrec = ntrec; 8491558Srgrimes cnt = ntrec * TP_BSIZE; 8501558Srgrimes rd = 0; 8511558Srgrimesgetmore: 8521558Srgrimes#ifdef RRESTORE 8531558Srgrimes if (host) 8541558Srgrimes i = rmtread(&tapebuf[rd], cnt); 8551558Srgrimes else 8561558Srgrimes#endif 8571558Srgrimes i = read(mt, &tapebuf[rd], cnt); 8581558Srgrimes /* 8591558Srgrimes * Check for mid-tape short read error. 8601558Srgrimes * If found, skip rest of buffer and start with the next. 8611558Srgrimes */ 8621558Srgrimes if (!pipein && numtrec < ntrec && i > 0) { 8631558Srgrimes dprintf(stdout, "mid-media short read error.\n"); 8641558Srgrimes numtrec = ntrec; 8651558Srgrimes } 8661558Srgrimes /* 8671558Srgrimes * Handle partial block read. 8681558Srgrimes */ 8691558Srgrimes if (pipein && i == 0 && rd > 0) 8701558Srgrimes i = rd; 8711558Srgrimes else if (i > 0 && i != ntrec * TP_BSIZE) { 8721558Srgrimes if (pipein) { 8731558Srgrimes rd += i; 8741558Srgrimes cnt -= i; 8751558Srgrimes if (cnt > 0) 8761558Srgrimes goto getmore; 8771558Srgrimes i = rd; 8781558Srgrimes } else { 8791558Srgrimes /* 8801558Srgrimes * Short read. Process the blocks read. 8811558Srgrimes */ 8821558Srgrimes if (i % TP_BSIZE != 0) 8831558Srgrimes vprintf(stdout, 8841558Srgrimes "partial block read: %d should be %d\n", 8851558Srgrimes i, ntrec * TP_BSIZE); 8861558Srgrimes numtrec = i / TP_BSIZE; 8871558Srgrimes } 8881558Srgrimes } 8891558Srgrimes /* 8901558Srgrimes * Handle read error. 8911558Srgrimes */ 8921558Srgrimes if (i < 0) { 8931558Srgrimes fprintf(stderr, "Tape read error while "); 8941558Srgrimes switch (curfile.action) { 8951558Srgrimes default: 8961558Srgrimes fprintf(stderr, "trying to set up tape\n"); 8971558Srgrimes break; 8981558Srgrimes case UNKNOWN: 8991558Srgrimes fprintf(stderr, "trying to resynchronize\n"); 9001558Srgrimes break; 9011558Srgrimes case USING: 9021558Srgrimes fprintf(stderr, "restoring %s\n", curfile.name); 9031558Srgrimes break; 9041558Srgrimes case SKIP: 9051558Srgrimes fprintf(stderr, "skipping over inode %d\n", 9061558Srgrimes curfile.ino); 9071558Srgrimes break; 9081558Srgrimes } 9091558Srgrimes if (!yflag && !reply("continue")) 9101558Srgrimes done(1); 9111558Srgrimes i = ntrec * TP_BSIZE; 91223685Speter memset(tapebuf, 0, i); 9131558Srgrimes#ifdef RRESTORE 9141558Srgrimes if (host) 9151558Srgrimes seek_failed = (rmtseek(i, 1) < 0); 9161558Srgrimes else 9171558Srgrimes#endif 9181558Srgrimes seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 9191558Srgrimes 9201558Srgrimes if (seek_failed) { 9211558Srgrimes fprintf(stderr, 9221558Srgrimes "continuation failed: %s\n", strerror(errno)); 9231558Srgrimes done(1); 9241558Srgrimes } 9251558Srgrimes } 9261558Srgrimes /* 9271558Srgrimes * Handle end of tape. 9281558Srgrimes */ 9291558Srgrimes if (i == 0) { 9301558Srgrimes vprintf(stdout, "End-of-tape encountered\n"); 9311558Srgrimes if (!pipein) { 9321558Srgrimes newvol = volno + 1; 9331558Srgrimes volno = 0; 9341558Srgrimes numtrec = 0; 9351558Srgrimes getvol(newvol); 9361558Srgrimes readtape(buf); 9371558Srgrimes return; 9381558Srgrimes } 9391558Srgrimes if (rd % TP_BSIZE != 0) 9401558Srgrimes panic("partial block read: %d should be %d\n", 9411558Srgrimes rd, ntrec * TP_BSIZE); 9421558Srgrimes terminateinput(); 94323685Speter memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 9441558Srgrimes } 9451558Srgrimes blkcnt = 0; 94623685Speter memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 9471558Srgrimes blksread++; 9481558Srgrimes tpblksread++; 9491558Srgrimes} 9501558Srgrimes 9511558Srgrimesstatic void 9521558Srgrimesfindtapeblksize() 9531558Srgrimes{ 9541558Srgrimes register long i; 9551558Srgrimes 9561558Srgrimes for (i = 0; i < ntrec; i++) 9571558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 9581558Srgrimes blkcnt = 0; 9591558Srgrimes#ifdef RRESTORE 9601558Srgrimes if (host) 9611558Srgrimes i = rmtread(tapebuf, ntrec * TP_BSIZE); 9621558Srgrimes else 9631558Srgrimes#endif 9641558Srgrimes i = read(mt, tapebuf, ntrec * TP_BSIZE); 9651558Srgrimes 9661558Srgrimes if (i <= 0) { 9671558Srgrimes fprintf(stderr, "tape read error: %s\n", strerror(errno)); 9681558Srgrimes done(1); 9691558Srgrimes } 9701558Srgrimes if (i % TP_BSIZE != 0) { 9711558Srgrimes fprintf(stderr, "Tape block size (%d) %s (%d)\n", 9721558Srgrimes i, "is not a multiple of dump block size", TP_BSIZE); 9731558Srgrimes done(1); 9741558Srgrimes } 9751558Srgrimes ntrec = i / TP_BSIZE; 9761558Srgrimes numtrec = ntrec; 9771558Srgrimes vprintf(stdout, "Tape block size is %d\n", ntrec); 9781558Srgrimes} 9791558Srgrimes 9801558Srgrimesvoid 9811558Srgrimesclosemt() 9821558Srgrimes{ 9831558Srgrimes 9841558Srgrimes if (mt < 0) 9851558Srgrimes return; 9861558Srgrimes#ifdef RRESTORE 9871558Srgrimes if (host) 9881558Srgrimes rmtclose(); 9891558Srgrimes else 9901558Srgrimes#endif 9911558Srgrimes (void) close(mt); 9921558Srgrimes} 9931558Srgrimes 9941558Srgrimes/* 9951558Srgrimes * Read the next block from the tape. 9961558Srgrimes * Check to see if it is one of several vintage headers. 9971558Srgrimes * If it is an old style header, convert it to a new style header. 9981558Srgrimes * If it is not any valid header, return an error. 9991558Srgrimes */ 10001558Srgrimesstatic int 10011558Srgrimesgethead(buf) 10021558Srgrimes struct s_spcl *buf; 10031558Srgrimes{ 10041558Srgrimes long i; 10051558Srgrimes union { 10061558Srgrimes quad_t qval; 10071558Srgrimes long val[2]; 10081558Srgrimes } qcvt; 10091558Srgrimes union u_ospcl { 10101558Srgrimes char dummy[TP_BSIZE]; 10111558Srgrimes struct s_ospcl { 10121558Srgrimes long c_type; 10131558Srgrimes long c_date; 10141558Srgrimes long c_ddate; 10151558Srgrimes long c_volume; 10161558Srgrimes long c_tapea; 10171558Srgrimes u_short c_inumber; 10181558Srgrimes long c_magic; 10191558Srgrimes long c_checksum; 10201558Srgrimes struct odinode { 10211558Srgrimes unsigned short odi_mode; 10221558Srgrimes u_short odi_nlink; 10231558Srgrimes u_short odi_uid; 10241558Srgrimes u_short odi_gid; 10251558Srgrimes long odi_size; 10261558Srgrimes long odi_rdev; 10271558Srgrimes char odi_addr[36]; 10281558Srgrimes long odi_atime; 10291558Srgrimes long odi_mtime; 10301558Srgrimes long odi_ctime; 10311558Srgrimes } c_dinode; 10321558Srgrimes long c_count; 10331558Srgrimes char c_addr[256]; 10341558Srgrimes } s_ospcl; 10351558Srgrimes } u_ospcl; 10361558Srgrimes 10371558Srgrimes if (!cvtflag) { 10381558Srgrimes readtape((char *)buf); 10391558Srgrimes if (buf->c_magic != NFS_MAGIC) { 10401558Srgrimes if (swabl(buf->c_magic) != NFS_MAGIC) 10411558Srgrimes return (FAIL); 10421558Srgrimes if (!Bcvt) { 10431558Srgrimes vprintf(stdout, "Note: Doing Byte swapping\n"); 10441558Srgrimes Bcvt = 1; 10451558Srgrimes } 10461558Srgrimes } 10471558Srgrimes if (checksum((int *)buf) == FAIL) 10481558Srgrimes return (FAIL); 104923096Simp if (Bcvt) { 10501558Srgrimes swabst((u_char *)"8l4s31l", (u_char *)buf); 105123096Simp swabst((u_char *)"l",(u_char *) &buf->c_level); 105223096Simp swabst((u_char *)"2l",(u_char *) &buf->c_flags); 105323096Simp } 10541558Srgrimes goto good; 10551558Srgrimes } 10561558Srgrimes readtape((char *)(&u_ospcl.s_ospcl)); 105723685Speter memset(buf, 0, (long)TP_BSIZE); 10581558Srgrimes buf->c_type = u_ospcl.s_ospcl.c_type; 10591558Srgrimes buf->c_date = u_ospcl.s_ospcl.c_date; 10601558Srgrimes buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 10611558Srgrimes buf->c_volume = u_ospcl.s_ospcl.c_volume; 10621558Srgrimes buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 10631558Srgrimes buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 10641558Srgrimes buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 10651558Srgrimes buf->c_magic = u_ospcl.s_ospcl.c_magic; 10661558Srgrimes buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 10671558Srgrimes buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 10681558Srgrimes buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 10691558Srgrimes buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 10701558Srgrimes buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; 10711558Srgrimes buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 107223685Speter buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; 107323685Speter buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; 107423685Speter buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; 10751558Srgrimes buf->c_count = u_ospcl.s_ospcl.c_count; 107623685Speter memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256); 10771558Srgrimes if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || 10781558Srgrimes checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) 10791558Srgrimes return(FAIL); 10801558Srgrimes buf->c_magic = NFS_MAGIC; 10811558Srgrimes 10821558Srgrimesgood: 10831558Srgrimes if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) && 10841558Srgrimes (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) { 10851558Srgrimes qcvt.qval = buf->c_dinode.di_size; 10861558Srgrimes if (qcvt.val[0] || qcvt.val[1]) { 10871558Srgrimes printf("Note: Doing Quad swapping\n"); 10881558Srgrimes Qcvt = 1; 10891558Srgrimes } 10901558Srgrimes } 10911558Srgrimes if (Qcvt) { 10921558Srgrimes qcvt.qval = buf->c_dinode.di_size; 10931558Srgrimes i = qcvt.val[1]; 10941558Srgrimes qcvt.val[1] = qcvt.val[0]; 10951558Srgrimes qcvt.val[0] = i; 10961558Srgrimes buf->c_dinode.di_size = qcvt.qval; 10971558Srgrimes } 10981558Srgrimes 10991558Srgrimes switch (buf->c_type) { 11001558Srgrimes 11011558Srgrimes case TS_CLRI: 11021558Srgrimes case TS_BITS: 11031558Srgrimes /* 11041558Srgrimes * Have to patch up missing information in bit map headers 11051558Srgrimes */ 11061558Srgrimes buf->c_inumber = 0; 11071558Srgrimes buf->c_dinode.di_size = buf->c_count * TP_BSIZE; 11081558Srgrimes for (i = 0; i < buf->c_count; i++) 11091558Srgrimes buf->c_addr[i]++; 11101558Srgrimes break; 11111558Srgrimes 11121558Srgrimes case TS_TAPE: 11131558Srgrimes if ((buf->c_flags & DR_NEWINODEFMT) == 0) 11141558Srgrimes oldinofmt = 1; 11151558Srgrimes /* fall through */ 11161558Srgrimes case TS_END: 11171558Srgrimes buf->c_inumber = 0; 11181558Srgrimes break; 11191558Srgrimes 11201558Srgrimes case TS_INODE: 11211558Srgrimes case TS_ADDR: 11221558Srgrimes break; 11231558Srgrimes 11241558Srgrimes default: 11251558Srgrimes panic("gethead: unknown inode type %d\n", buf->c_type); 11261558Srgrimes break; 11271558Srgrimes } 11281558Srgrimes /* 11298871Srgrimes * If we are restoring a filesystem with old format inodes, 11301558Srgrimes * copy the uid/gid to the new location. 11311558Srgrimes */ 11321558Srgrimes if (oldinofmt) { 11331558Srgrimes buf->c_dinode.di_uid = buf->c_dinode.di_ouid; 11341558Srgrimes buf->c_dinode.di_gid = buf->c_dinode.di_ogid; 11351558Srgrimes } 11361558Srgrimes if (dflag) 11371558Srgrimes accthdr(buf); 11381558Srgrimes return(GOOD); 11391558Srgrimes} 11401558Srgrimes 11411558Srgrimes/* 11421558Srgrimes * Check that a header is where it belongs and predict the next header 11431558Srgrimes */ 11441558Srgrimesstatic void 11451558Srgrimesaccthdr(header) 11461558Srgrimes struct s_spcl *header; 11471558Srgrimes{ 11481558Srgrimes static ino_t previno = 0x7fffffff; 11491558Srgrimes static int prevtype; 11501558Srgrimes static long predict; 11511558Srgrimes long blks, i; 11521558Srgrimes 11531558Srgrimes if (header->c_type == TS_TAPE) { 11541558Srgrimes fprintf(stderr, "Volume header (%s inode format) ", 11551558Srgrimes oldinofmt ? "old" : "new"); 11561558Srgrimes if (header->c_firstrec) 11571558Srgrimes fprintf(stderr, "begins with record %d", 11581558Srgrimes header->c_firstrec); 11591558Srgrimes fprintf(stderr, "\n"); 11601558Srgrimes previno = 0x7fffffff; 11611558Srgrimes return; 11621558Srgrimes } 11631558Srgrimes if (previno == 0x7fffffff) 11641558Srgrimes goto newcalc; 11651558Srgrimes switch (prevtype) { 11661558Srgrimes case TS_BITS: 116723685Speter fprintf(stderr, "Dumped inodes map header"); 11681558Srgrimes break; 11691558Srgrimes case TS_CLRI: 117023685Speter fprintf(stderr, "Used inodes map header"); 11711558Srgrimes break; 11721558Srgrimes case TS_INODE: 11731558Srgrimes fprintf(stderr, "File header, ino %d", previno); 11741558Srgrimes break; 11751558Srgrimes case TS_ADDR: 11761558Srgrimes fprintf(stderr, "File continuation header, ino %d", previno); 11771558Srgrimes break; 11781558Srgrimes case TS_END: 11791558Srgrimes fprintf(stderr, "End of tape header"); 11801558Srgrimes break; 11811558Srgrimes } 11821558Srgrimes if (predict != blksread - 1) 11831558Srgrimes fprintf(stderr, "; predicted %d blocks, got %d blocks", 11841558Srgrimes predict, blksread - 1); 11851558Srgrimes fprintf(stderr, "\n"); 11861558Srgrimesnewcalc: 11871558Srgrimes blks = 0; 11881558Srgrimes if (header->c_type != TS_END) 11891558Srgrimes for (i = 0; i < header->c_count; i++) 11901558Srgrimes if (header->c_addr[i] != 0) 11911558Srgrimes blks++; 11921558Srgrimes predict = blks; 11931558Srgrimes blksread = 0; 11941558Srgrimes prevtype = header->c_type; 11951558Srgrimes previno = header->c_inumber; 11961558Srgrimes} 11971558Srgrimes 11981558Srgrimes/* 11991558Srgrimes * Find an inode header. 12001558Srgrimes * Complain if had to skip, and complain is set. 12011558Srgrimes */ 12021558Srgrimesstatic void 12031558Srgrimesfindinode(header) 12041558Srgrimes struct s_spcl *header; 12051558Srgrimes{ 12061558Srgrimes static long skipcnt = 0; 12071558Srgrimes long i; 12081558Srgrimes char buf[TP_BSIZE]; 12091558Srgrimes 12101558Srgrimes curfile.name = "<name unknown>"; 12111558Srgrimes curfile.action = UNKNOWN; 12121558Srgrimes curfile.dip = NULL; 12131558Srgrimes curfile.ino = 0; 12141558Srgrimes do { 12151558Srgrimes if (header->c_magic != NFS_MAGIC) { 12161558Srgrimes skipcnt++; 12171558Srgrimes while (gethead(header) == FAIL || 12181558Srgrimes header->c_date != dumpdate) 12191558Srgrimes skipcnt++; 12201558Srgrimes } 12211558Srgrimes switch (header->c_type) { 12221558Srgrimes 12231558Srgrimes case TS_ADDR: 12241558Srgrimes /* 12251558Srgrimes * Skip up to the beginning of the next record 12261558Srgrimes */ 12271558Srgrimes for (i = 0; i < header->c_count; i++) 12281558Srgrimes if (header->c_addr[i]) 12291558Srgrimes readtape(buf); 12301558Srgrimes while (gethead(header) == FAIL || 12311558Srgrimes header->c_date != dumpdate) 12321558Srgrimes skipcnt++; 12331558Srgrimes break; 12341558Srgrimes 12351558Srgrimes case TS_INODE: 12361558Srgrimes curfile.dip = &header->c_dinode; 12371558Srgrimes curfile.ino = header->c_inumber; 12381558Srgrimes break; 12391558Srgrimes 12401558Srgrimes case TS_END: 12411558Srgrimes curfile.ino = maxino; 12421558Srgrimes break; 12431558Srgrimes 12441558Srgrimes case TS_CLRI: 12451558Srgrimes curfile.name = "<file removal list>"; 12461558Srgrimes break; 12471558Srgrimes 12481558Srgrimes case TS_BITS: 12491558Srgrimes curfile.name = "<file dump list>"; 12501558Srgrimes break; 12511558Srgrimes 12521558Srgrimes case TS_TAPE: 12531558Srgrimes panic("unexpected tape header\n"); 12541558Srgrimes /* NOTREACHED */ 12551558Srgrimes 12561558Srgrimes default: 12571558Srgrimes panic("unknown tape header type %d\n", spcl.c_type); 12581558Srgrimes /* NOTREACHED */ 12591558Srgrimes 12601558Srgrimes } 12611558Srgrimes } while (header->c_type == TS_ADDR); 12621558Srgrimes if (skipcnt > 0) 12631558Srgrimes fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt); 12641558Srgrimes skipcnt = 0; 12651558Srgrimes} 12661558Srgrimes 12671558Srgrimesstatic int 12681558Srgrimeschecksum(buf) 12691558Srgrimes register int *buf; 12701558Srgrimes{ 12711558Srgrimes register int i, j; 12721558Srgrimes 12731558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 12741558Srgrimes i = 0; 12751558Srgrimes if(!Bcvt) { 12761558Srgrimes do 12771558Srgrimes i += *buf++; 12781558Srgrimes while (--j); 12791558Srgrimes } else { 12801558Srgrimes /* What happens if we want to read restore tapes 12811558Srgrimes for a 16bit int machine??? */ 12828871Srgrimes do 12831558Srgrimes i += swabl(*buf++); 12841558Srgrimes while (--j); 12851558Srgrimes } 12868871Srgrimes 12871558Srgrimes if (i != CHECKSUM) { 12881558Srgrimes fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 12891558Srgrimes curfile.ino, curfile.name); 12901558Srgrimes return(FAIL); 12911558Srgrimes } 12921558Srgrimes return(GOOD); 12931558Srgrimes} 12941558Srgrimes 12951558Srgrimes#ifdef RRESTORE 12961558Srgrimes#if __STDC__ 12971558Srgrimes#include <stdarg.h> 12981558Srgrimes#else 12991558Srgrimes#include <varargs.h> 13001558Srgrimes#endif 13011558Srgrimes 13021558Srgrimesvoid 13031558Srgrimes#if __STDC__ 13041558Srgrimesmsg(const char *fmt, ...) 13051558Srgrimes#else 13061558Srgrimesmsg(fmt, va_alist) 13071558Srgrimes char *fmt; 13081558Srgrimes va_dcl 13091558Srgrimes#endif 13101558Srgrimes{ 13111558Srgrimes va_list ap; 13121558Srgrimes#if __STDC__ 13131558Srgrimes va_start(ap, fmt); 13141558Srgrimes#else 13151558Srgrimes va_start(ap); 13161558Srgrimes#endif 13171558Srgrimes (void)vfprintf(stderr, fmt, ap); 13181558Srgrimes va_end(ap); 13191558Srgrimes} 13201558Srgrimes#endif /* RRESTORE */ 13211558Srgrimes 13221558Srgrimesstatic u_char * 13231558Srgrimesswabshort(sp, n) 13241558Srgrimes register u_char *sp; 13251558Srgrimes register int n; 13261558Srgrimes{ 13271558Srgrimes char c; 13281558Srgrimes 13291558Srgrimes while (--n >= 0) { 13301558Srgrimes c = sp[0]; sp[0] = sp[1]; sp[1] = c; 13311558Srgrimes sp += 2; 13321558Srgrimes } 13331558Srgrimes return (sp); 13341558Srgrimes} 13351558Srgrimes 13361558Srgrimesstatic u_char * 13371558Srgrimesswablong(sp, n) 13381558Srgrimes register u_char *sp; 13391558Srgrimes register int n; 13401558Srgrimes{ 13411558Srgrimes char c; 13421558Srgrimes 13431558Srgrimes while (--n >= 0) { 13441558Srgrimes c = sp[0]; sp[0] = sp[3]; sp[3] = c; 13451558Srgrimes c = sp[2]; sp[2] = sp[1]; sp[1] = c; 13461558Srgrimes sp += 4; 13471558Srgrimes } 13481558Srgrimes return (sp); 13491558Srgrimes} 13501558Srgrimes 13511558Srgrimesvoid 13521558Srgrimesswabst(cp, sp) 13531558Srgrimes register u_char *cp, *sp; 13541558Srgrimes{ 13551558Srgrimes int n = 0; 13561558Srgrimes 13571558Srgrimes while (*cp) { 13581558Srgrimes switch (*cp) { 13591558Srgrimes case '0': case '1': case '2': case '3': case '4': 13601558Srgrimes case '5': case '6': case '7': case '8': case '9': 13611558Srgrimes n = (n * 10) + (*cp++ - '0'); 13621558Srgrimes continue; 13638871Srgrimes 13641558Srgrimes case 's': case 'w': case 'h': 13651558Srgrimes if (n == 0) 13661558Srgrimes n = 1; 13671558Srgrimes sp = swabshort(sp, n); 13681558Srgrimes break; 13691558Srgrimes 13701558Srgrimes case 'l': 13711558Srgrimes if (n == 0) 13721558Srgrimes n = 1; 13731558Srgrimes sp = swablong(sp, n); 13741558Srgrimes break; 13751558Srgrimes 13761558Srgrimes default: /* Any other character, like 'b' counts as byte. */ 13771558Srgrimes if (n == 0) 13781558Srgrimes n = 1; 13791558Srgrimes sp += n; 13801558Srgrimes break; 13811558Srgrimes } 13821558Srgrimes cp++; 13831558Srgrimes n = 0; 13841558Srgrimes } 13851558Srgrimes} 13861558Srgrimes 13871558Srgrimesstatic u_long 13881558Srgrimesswabl(x) 13891558Srgrimes u_long x; 13901558Srgrimes{ 13911558Srgrimes swabst((u_char *)"l", (u_char *)&x); 13921558Srgrimes return (x); 13931558Srgrimes} 1394