tape.c revision 96113
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 4037906Scharnier#if 0 4123685Speterstatic char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; 4237906Scharnier#endif 4337906Scharnierstatic const char rcsid[] = 4450476Speter "$FreeBSD: head/sbin/restore/tape.c 96113 2002-05-06 15:15:51Z iedowse $"; 451558Srgrimes#endif /* not lint */ 461558Srgrimes 471558Srgrimes#include <sys/param.h> 481558Srgrimes#include <sys/file.h> 491558Srgrimes#include <sys/mtio.h> 501558Srgrimes#include <sys/stat.h> 5166907Swollman#include <sys/time.h> 521558Srgrimes 531558Srgrimes#include <ufs/ufs/dinode.h> 541558Srgrimes#include <protocols/dumprestore.h> 551558Srgrimes 561558Srgrimes#include <errno.h> 5773986Sobrien#include <paths.h> 581558Srgrimes#include <setjmp.h> 591558Srgrimes#include <stdio.h> 601558Srgrimes#include <stdlib.h> 611558Srgrimes#include <string.h> 6266907Swollman#include <time.h> 631558Srgrimes#include <unistd.h> 641558Srgrimes 651558Srgrimes#include "restore.h" 661558Srgrimes#include "extern.h" 671558Srgrimes 681558Srgrimesstatic long fssize = MAXBSIZE; 691558Srgrimesstatic int mt = -1; 701558Srgrimesstatic int pipein = 0; 7121174Sguidostatic char *magtape; 721558Srgrimesstatic int blkcnt; 731558Srgrimesstatic int numtrec; 741558Srgrimesstatic char *tapebuf; 751558Srgrimesstatic union u_spcl endoftapemark; 761558Srgrimesstatic long blksread; /* blocks read since last header */ 7790827Siedowsestatic long tapeaddr = 0; /* current TP_BSIZE tape record */ 781558Srgrimesstatic long tapesread; 791558Srgrimesstatic jmp_buf restart; 801558Srgrimesstatic int gettingfile = 0; /* restart has a valid frame */ 811558Srgrimesstatic char *host = NULL; 821558Srgrimes 831558Srgrimesstatic int ofile; 841558Srgrimesstatic char *map; 851558Srgrimesstatic char lnkbuf[MAXPATHLEN + 1]; 861558Srgrimesstatic int pathlen; 871558Srgrimes 881558Srgrimesint oldinofmt; /* old inode format conversion required */ 891558Srgrimesint Bcvt; /* Swap Bytes (for CCI or sun) */ 901558Srgrimesstatic int Qcvt; /* Swap quads (for sun) */ 911558Srgrimes 921558Srgrimes#define FLUSHTAPEBUF() blkcnt = ntrec + 1 931558Srgrimes 9492837Simpstatic void accthdr(struct s_spcl *); 9592837Simpstatic int checksum(int *); 9692837Simpstatic void findinode(struct s_spcl *); 9792837Simpstatic void findtapeblksize(void); 9892837Simpstatic int gethead(struct s_spcl *); 9992837Simpstatic void readtape(char *); 10092837Simpstatic void setdumpnum(void); 10192837Simpstatic u_long swabl(u_long); 10292837Simpstatic u_char *swablong(u_char *, int); 10392837Simpstatic u_char *swabshort(u_char *, int); 10492837Simpstatic void terminateinput(void); 10592837Simpstatic void xtrfile(char *, long); 10692837Simpstatic void xtrlnkfile(char *, long); 10792837Simpstatic void xtrlnkskip(char *, long); 10892837Simpstatic void xtrmap(char *, long); 10992837Simpstatic void xtrmapskip(char *, long); 11092837Simpstatic void xtrskip(char *, long); 1111558Srgrimes 11237923Simpstatic int readmapflag; 11337923Simp 1141558Srgrimes/* 1151558Srgrimes * Set up an input source 1161558Srgrimes */ 1171558Srgrimesvoid 11892837Simpsetinput(char *source) 1191558Srgrimes{ 1201558Srgrimes FLUSHTAPEBUF(); 1211558Srgrimes if (bflag) 1221558Srgrimes newtapebuf(ntrec); 1231558Srgrimes else 1241558Srgrimes newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 1251558Srgrimes terminal = stdin; 1261558Srgrimes 1271558Srgrimes#ifdef RRESTORE 12823685Speter if (strchr(source, ':')) { 1291558Srgrimes host = source; 13023685Speter source = strchr(host, ':'); 1311558Srgrimes *source++ = '\0'; 1321558Srgrimes if (rmthost(host) == 0) 1331558Srgrimes done(1); 1341558Srgrimes } else 1351558Srgrimes#endif 1361558Srgrimes if (strcmp(source, "-") == 0) { 1371558Srgrimes /* 1381558Srgrimes * Since input is coming from a pipe we must establish 1391558Srgrimes * our own connection to the terminal. 1401558Srgrimes */ 1411558Srgrimes terminal = fopen(_PATH_TTY, "r"); 1421558Srgrimes if (terminal == NULL) { 1431558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1441558Srgrimes _PATH_TTY, strerror(errno)); 1451558Srgrimes terminal = fopen(_PATH_DEVNULL, "r"); 1461558Srgrimes if (terminal == NULL) { 1471558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1481558Srgrimes _PATH_DEVNULL, strerror(errno)); 1491558Srgrimes done(1); 1501558Srgrimes } 1511558Srgrimes } 1521558Srgrimes pipein++; 1531558Srgrimes } 1541558Srgrimes setuid(getuid()); /* no longer need or want root privileges */ 15521174Sguido magtape = strdup(source); 15621174Sguido if (magtape == NULL) { 15721174Sguido fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 15821174Sguido done(1); 15921174Sguido } 1601558Srgrimes} 1611558Srgrimes 1621558Srgrimesvoid 16392837Simpnewtapebuf(long size) 1641558Srgrimes{ 16592837Simp static int tapebufsize = -1; 1661558Srgrimes 1671558Srgrimes ntrec = size; 1681558Srgrimes if (size <= tapebufsize) 1691558Srgrimes return; 1701558Srgrimes if (tapebuf != NULL) 1711558Srgrimes free(tapebuf); 1721558Srgrimes tapebuf = malloc(size * TP_BSIZE); 1731558Srgrimes if (tapebuf == NULL) { 1741558Srgrimes fprintf(stderr, "Cannot allocate space for tape buffer\n"); 1751558Srgrimes done(1); 1761558Srgrimes } 1771558Srgrimes tapebufsize = size; 1781558Srgrimes} 1791558Srgrimes 1801558Srgrimes/* 1811558Srgrimes * Verify that the tape drive can be accessed and 1821558Srgrimes * that it actually is a dump tape. 1831558Srgrimes */ 1841558Srgrimesvoid 18592837Simpsetup(void) 1861558Srgrimes{ 1871558Srgrimes int i, j, *ip; 1881558Srgrimes struct stat stbuf; 1891558Srgrimes 1901558Srgrimes vprintf(stdout, "Verify tape and initialize maps\n"); 1911558Srgrimes#ifdef RRESTORE 1921558Srgrimes if (host) 1931558Srgrimes mt = rmtopen(magtape, 0); 1941558Srgrimes else 1951558Srgrimes#endif 1961558Srgrimes if (pipein) 1971558Srgrimes mt = 0; 1981558Srgrimes else 1991558Srgrimes mt = open(magtape, O_RDONLY, 0); 2001558Srgrimes if (mt < 0) { 2011558Srgrimes fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 2021558Srgrimes done(1); 2031558Srgrimes } 2041558Srgrimes volno = 1; 2051558Srgrimes setdumpnum(); 2061558Srgrimes FLUSHTAPEBUF(); 2071558Srgrimes if (!pipein && !bflag) 2081558Srgrimes findtapeblksize(); 2091558Srgrimes if (gethead(&spcl) == FAIL) { 2101558Srgrimes blkcnt--; /* push back this block */ 2111558Srgrimes blksread--; 2121558Srgrimes cvtflag++; 2131558Srgrimes if (gethead(&spcl) == FAIL) { 2141558Srgrimes fprintf(stderr, "Tape is not a dump tape\n"); 2151558Srgrimes done(1); 2161558Srgrimes } 2171558Srgrimes fprintf(stderr, "Converting to new file system format.\n"); 2181558Srgrimes } 2191558Srgrimes if (pipein) { 2201558Srgrimes endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; 2211558Srgrimes endoftapemark.s_spcl.c_type = TS_END; 2221558Srgrimes ip = (int *)&endoftapemark; 2231558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 2241558Srgrimes i = 0; 2251558Srgrimes do 2261558Srgrimes i += *ip++; 2271558Srgrimes while (--j); 2281558Srgrimes endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 2291558Srgrimes } 2301558Srgrimes if (vflag || command == 't') 2311558Srgrimes printdumpinfo(); 23289572Sdillon dumptime = _time32_to_time(spcl.c_ddate); 23389572Sdillon dumpdate = _time32_to_time(spcl.c_date); 2341558Srgrimes if (stat(".", &stbuf) < 0) { 2351558Srgrimes fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 2361558Srgrimes done(1); 2371558Srgrimes } 23834851Sjkh if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 23934851Sjkh fssize = TP_BSIZE; 24034851Sjkh if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 2411558Srgrimes fssize = stbuf.st_blksize; 2421558Srgrimes if (((fssize - 1) & fssize) != 0) { 24337240Sbde fprintf(stderr, "bad block size %ld\n", fssize); 2441558Srgrimes done(1); 2451558Srgrimes } 2461558Srgrimes if (spcl.c_volume != 1) { 2471558Srgrimes fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2481558Srgrimes done(1); 2491558Srgrimes } 2501558Srgrimes if (gethead(&spcl) == FAIL) { 25137240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 2521558Srgrimes panic("no header after volume mark!\n"); 2531558Srgrimes } 2541558Srgrimes findinode(&spcl); 2551558Srgrimes if (spcl.c_type != TS_CLRI) { 2561558Srgrimes fprintf(stderr, "Cannot find file removal list\n"); 2571558Srgrimes done(1); 2581558Srgrimes } 2591558Srgrimes maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 2601558Srgrimes dprintf(stdout, "maxino = %d\n", maxino); 2611558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2621558Srgrimes if (map == NULL) 26323685Speter panic("no memory for active inode map\n"); 26423685Speter usedinomap = map; 2651558Srgrimes curfile.action = USING; 2661558Srgrimes getfile(xtrmap, xtrmapskip); 2671558Srgrimes if (spcl.c_type != TS_BITS) { 2681558Srgrimes fprintf(stderr, "Cannot find file dump list\n"); 2691558Srgrimes done(1); 2701558Srgrimes } 2711558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2721558Srgrimes if (map == (char *)NULL) 2731558Srgrimes panic("no memory for file dump list\n"); 2741558Srgrimes dumpmap = map; 2751558Srgrimes curfile.action = USING; 2761558Srgrimes getfile(xtrmap, xtrmapskip); 27723685Speter /* 27823685Speter * If there may be whiteout entries on the tape, pretend that the 27923685Speter * whiteout inode exists, so that the whiteout entries can be 28023685Speter * extracted. 28123685Speter */ 28223685Speter if (oldinofmt == 0) 28323685Speter SETINO(WINO, dumpmap); 28490820Siedowse /* 'r' restores don't call getvol() for tape 1, so mark it as read. */ 28590820Siedowse if (command == 'r') 28690820Siedowse tapesread = 1; 2871558Srgrimes} 2881558Srgrimes 2891558Srgrimes/* 2901558Srgrimes * Prompt user to load a new dump volume. 2911558Srgrimes * "Nextvol" is the next suggested volume to use. 2921558Srgrimes * This suggested volume is enforced when doing full 29337906Scharnier * or incremental restores, but can be overridden by 2941558Srgrimes * the user when only extracting a subset of the files. 2951558Srgrimes */ 2961558Srgrimesvoid 29792837Simpgetvol(long nextvol) 2981558Srgrimes{ 29990827Siedowse long newvol, prevtapea, savecnt, i; 3001558Srgrimes union u_spcl tmpspcl; 3011558Srgrimes# define tmpbuf tmpspcl.s_spcl 3021558Srgrimes char buf[TP_BSIZE]; 3031558Srgrimes 3041558Srgrimes if (nextvol == 1) { 3051558Srgrimes tapesread = 0; 3061558Srgrimes gettingfile = 0; 3071558Srgrimes } 30890827Siedowse prevtapea = tapeaddr; 30990827Siedowse savecnt = blksread; 3101558Srgrimes if (pipein) { 31169906Siedowse if (nextvol != 1) { 3121558Srgrimes panic("Changing volumes on pipe input?\n"); 31369906Siedowse /* Avoid looping if we couldn't ask the user. */ 31469906Siedowse if (yflag || ferror(terminal) || feof(terminal)) 31569906Siedowse done(1); 31669906Siedowse } 3171558Srgrimes if (volno == 1) 3181558Srgrimes return; 3191558Srgrimes goto gethdr; 3201558Srgrimes } 3211558Srgrimesagain: 3221558Srgrimes if (pipein) 3231558Srgrimes done(1); /* pipes do not get a second chance */ 32490608Siedowse if (command == 'R' || command == 'r' || curfile.action != SKIP) 3251558Srgrimes newvol = nextvol; 32690608Siedowse else 3271558Srgrimes newvol = 0; 3281558Srgrimes while (newvol <= 0) { 3291558Srgrimes if (tapesread == 0) { 33090820Siedowse fprintf(stderr, "%s%s%s%s%s%s%s", 3311558Srgrimes "You have not read any tapes yet.\n", 33290820Siedowse "If you are extracting just a few files,", 33390820Siedowse " start with the last volume\n", 33490820Siedowse "and work towards the first; restore", 33590820Siedowse " can quickly skip tapes that\n", 33690820Siedowse "have no further files to extract.", 33790820Siedowse " Otherwise, begin with volume 1.\n"); 3381558Srgrimes } else { 3391558Srgrimes fprintf(stderr, "You have read volumes"); 3401558Srgrimes strcpy(buf, ": "); 34190820Siedowse for (i = 0; i < 32; i++) 3421558Srgrimes if (tapesread & (1 << i)) { 34390820Siedowse fprintf(stderr, "%s%ld", buf, i + 1); 3441558Srgrimes strcpy(buf, ", "); 3451558Srgrimes } 3461558Srgrimes fprintf(stderr, "\n"); 3471558Srgrimes } 3481558Srgrimes do { 3491558Srgrimes fprintf(stderr, "Specify next volume #: "); 3501558Srgrimes (void) fflush(stderr); 35169906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 35269906Siedowse done(1); 35369906Siedowse } while (buf[0] == '\n'); 3541558Srgrimes newvol = atoi(buf); 3551558Srgrimes if (newvol <= 0) { 3561558Srgrimes fprintf(stderr, 3571558Srgrimes "Volume numbers are positive numerics\n"); 3581558Srgrimes } 3591558Srgrimes } 3601558Srgrimes if (newvol == volno) { 36190820Siedowse tapesread |= 1 << (volno - 1); 3621558Srgrimes return; 3631558Srgrimes } 3641558Srgrimes closemt(); 36537240Sbde fprintf(stderr, "Mount tape volume %ld\n", newvol); 3661558Srgrimes fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 3671558Srgrimes fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 3681558Srgrimes (void) fflush(stderr); 36969906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 3701558Srgrimes done(1); 3711558Srgrimes if (!strcmp(buf, "none\n")) { 3721558Srgrimes terminateinput(); 3731558Srgrimes return; 3741558Srgrimes } 3751558Srgrimes if (buf[0] != '\n') { 3761558Srgrimes (void) strcpy(magtape, buf); 3771558Srgrimes magtape[strlen(magtape) - 1] = '\0'; 3781558Srgrimes } 3791558Srgrimes#ifdef RRESTORE 3801558Srgrimes if (host) 3811558Srgrimes mt = rmtopen(magtape, 0); 3821558Srgrimes else 3831558Srgrimes#endif 3841558Srgrimes mt = open(magtape, O_RDONLY, 0); 3851558Srgrimes 3861558Srgrimes if (mt == -1) { 3871558Srgrimes fprintf(stderr, "Cannot open %s\n", magtape); 3881558Srgrimes volno = -1; 3891558Srgrimes goto again; 3901558Srgrimes } 3911558Srgrimesgethdr: 3921558Srgrimes volno = newvol; 3931558Srgrimes setdumpnum(); 3941558Srgrimes FLUSHTAPEBUF(); 3951558Srgrimes if (gethead(&tmpbuf) == FAIL) { 39637240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 3971558Srgrimes fprintf(stderr, "tape is not dump tape\n"); 3981558Srgrimes volno = 0; 3991558Srgrimes goto again; 4001558Srgrimes } 4011558Srgrimes if (tmpbuf.c_volume != volno) { 40237240Sbde fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume); 4031558Srgrimes volno = 0; 4041558Srgrimes goto again; 4051558Srgrimes } 40689572Sdillon if (_time32_to_time(tmpbuf.c_date) != dumpdate || 40789572Sdillon _time32_to_time(tmpbuf.c_ddate) != dumptime) { 40889572Sdillon time_t t = _time32_to_time(tmpbuf.c_date); 40985635Sdillon fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t)); 4101558Srgrimes fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 4111558Srgrimes volno = 0; 4121558Srgrimes goto again; 4131558Srgrimes } 41490820Siedowse tapesread |= 1 << (volno - 1); 4151558Srgrimes blksread = savecnt; 4161558Srgrimes /* 4171558Srgrimes * If continuing from the previous volume, skip over any 4181558Srgrimes * blocks read already at the end of the previous volume. 4191558Srgrimes * 4201558Srgrimes * If coming to this volume at random, skip to the beginning 4211558Srgrimes * of the next record. 4221558Srgrimes */ 42390827Siedowse dprintf(stdout, "last rec %ld, tape starts with %ld\n", prevtapea, 42490827Siedowse tmpbuf.c_tapea); 4251558Srgrimes if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { 42690608Siedowse if (curfile.action != USING) { 42790608Siedowse /* 42890608Siedowse * XXX Dump incorrectly sets c_count to 1 in the 42990608Siedowse * volume header of the first tape, so ignore 43090608Siedowse * c_count when volno == 1. 43190608Siedowse */ 43290608Siedowse if (volno != 1) 43390608Siedowse for (i = tmpbuf.c_count; i > 0; i--) 43490608Siedowse readtape(buf); 43590827Siedowse } else if (tmpbuf.c_tapea <= prevtapea) { 4361558Srgrimes /* 43790827Siedowse * Normally the value of c_tapea in the volume 43890827Siedowse * header is the record number of the header itself. 43990827Siedowse * However in the volume header following an EOT- 44090827Siedowse * terminated tape, it is the record number of the 44190827Siedowse * first continuation data block (dump bug?). 44290827Siedowse * 44390827Siedowse * The next record we want is `prevtapea + 1'. 4441558Srgrimes */ 44590827Siedowse i = prevtapea + 1 - tmpbuf.c_tapea; 44637240Sbde dprintf(stderr, "Skipping %ld duplicate record%s.\n", 4471558Srgrimes i, i > 1 ? "s" : ""); 4481558Srgrimes while (--i >= 0) 4491558Srgrimes readtape(buf); 4501558Srgrimes } 4511558Srgrimes } 45290608Siedowse if (curfile.action == USING) { 4531558Srgrimes if (volno == 1) 4541558Srgrimes panic("active file into volume 1\n"); 4551558Srgrimes return; 4561558Srgrimes } 4571558Srgrimes (void) gethead(&spcl); 4581558Srgrimes findinode(&spcl); 4591558Srgrimes if (gettingfile) { 4601558Srgrimes gettingfile = 0; 4611558Srgrimes longjmp(restart, 1); 4621558Srgrimes } 4631558Srgrimes} 4641558Srgrimes 4651558Srgrimes/* 4661558Srgrimes * Handle unexpected EOF. 4671558Srgrimes */ 4681558Srgrimesstatic void 46992837Simpterminateinput(void) 4701558Srgrimes{ 4711558Srgrimes 4721558Srgrimes if (gettingfile && curfile.action == USING) { 4731558Srgrimes printf("Warning: %s %s\n", 4741558Srgrimes "End-of-input encountered while extracting", curfile.name); 4751558Srgrimes } 4761558Srgrimes curfile.name = "<name unknown>"; 4771558Srgrimes curfile.action = UNKNOWN; 4781558Srgrimes curfile.dip = NULL; 4791558Srgrimes curfile.ino = maxino; 4801558Srgrimes if (gettingfile) { 4811558Srgrimes gettingfile = 0; 4821558Srgrimes longjmp(restart, 1); 4831558Srgrimes } 4841558Srgrimes} 4851558Srgrimes 4861558Srgrimes/* 4871558Srgrimes * handle multiple dumps per tape by skipping forward to the 4881558Srgrimes * appropriate one. 4891558Srgrimes */ 4901558Srgrimesstatic void 49192837Simpsetdumpnum(void) 4921558Srgrimes{ 4931558Srgrimes struct mtop tcom; 4941558Srgrimes 4951558Srgrimes if (dumpnum == 1 || volno != 1) 4961558Srgrimes return; 4971558Srgrimes if (pipein) { 4981558Srgrimes fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 4991558Srgrimes done(1); 5001558Srgrimes } 5011558Srgrimes tcom.mt_op = MTFSF; 5021558Srgrimes tcom.mt_count = dumpnum - 1; 5031558Srgrimes#ifdef RRESTORE 5041558Srgrimes if (host) 5051558Srgrimes rmtioctl(MTFSF, dumpnum - 1); 5068871Srgrimes else 5071558Srgrimes#endif 50865786Smjacob if (ioctl(mt, MTIOCTOP, (char *)&tcom) < 0) 5091558Srgrimes fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 5101558Srgrimes} 5111558Srgrimes 5121558Srgrimesvoid 51392837Simpprintdumpinfo(void) 5141558Srgrimes{ 51585635Sdillon time_t t; 51689572Sdillon t = _time32_to_time(spcl.c_date); 51785635Sdillon fprintf(stdout, "Dump date: %s", ctime(&t)); 51889572Sdillon t = _time32_to_time(spcl.c_ddate); 5191558Srgrimes fprintf(stdout, "Dumped from: %s", 52085635Sdillon (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t)); 5211558Srgrimes if (spcl.c_host[0] == '\0') 5221558Srgrimes return; 52337240Sbde fprintf(stderr, "Level %ld dump of %s on %s:%s\n", 5241558Srgrimes spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 5251558Srgrimes fprintf(stderr, "Label: %s\n", spcl.c_label); 5261558Srgrimes} 5271558Srgrimes 5281558Srgrimesint 52992837Simpextractfile(char *name) 5301558Srgrimes{ 53123685Speter int flags; 53296113Siedowse uid_t uid; 53396113Siedowse gid_t gid; 53423685Speter mode_t mode; 5351558Srgrimes struct timeval timep[2]; 5361558Srgrimes struct entry *ep; 5371558Srgrimes 5381558Srgrimes curfile.name = name; 5391558Srgrimes curfile.action = USING; 54023685Speter timep[0].tv_sec = curfile.dip->di_atime; 54123685Speter timep[0].tv_usec = curfile.dip->di_atimensec / 1000; 54223685Speter timep[1].tv_sec = curfile.dip->di_mtime; 54323685Speter timep[1].tv_usec = curfile.dip->di_mtimensec / 1000; 54496113Siedowse uid = curfile.dip->di_uid; 54596113Siedowse gid = curfile.dip->di_gid; 5461558Srgrimes mode = curfile.dip->di_mode; 54723685Speter flags = curfile.dip->di_flags; 5481558Srgrimes switch (mode & IFMT) { 5491558Srgrimes 5501558Srgrimes default: 5511558Srgrimes fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 5521558Srgrimes skipfile(); 5531558Srgrimes return (FAIL); 5541558Srgrimes 5551558Srgrimes case IFSOCK: 5561558Srgrimes vprintf(stdout, "skipped socket %s\n", name); 5571558Srgrimes skipfile(); 5581558Srgrimes return (GOOD); 5591558Srgrimes 5601558Srgrimes case IFDIR: 5611558Srgrimes if (mflag) { 5621558Srgrimes ep = lookupname(name); 5631558Srgrimes if (ep == NULL || ep->e_flags & EXTRACT) 5641558Srgrimes panic("unextracted directory %s\n", name); 5651558Srgrimes skipfile(); 5661558Srgrimes return (GOOD); 5671558Srgrimes } 5681558Srgrimes vprintf(stdout, "extract file %s\n", name); 5691558Srgrimes return (genliteraldir(name, curfile.ino)); 5701558Srgrimes 5711558Srgrimes case IFLNK: 5721558Srgrimes lnkbuf[0] = '\0'; 5731558Srgrimes pathlen = 0; 5741558Srgrimes getfile(xtrlnkfile, xtrlnkskip); 5751558Srgrimes if (pathlen == 0) { 5761558Srgrimes vprintf(stdout, 5771558Srgrimes "%s: zero length symbolic link (ignored)\n", name); 5781558Srgrimes return (GOOD); 5791558Srgrimes } 58096113Siedowse if (linkit(lnkbuf, name, SYMLINK) == GOOD) { 58196113Siedowse (void) lchown(name, uid, gid); 58296113Siedowse (void) lchmod(name, mode); 58396113Siedowse (void) lutimes(name, timep); 58496113Siedowse return (GOOD); 58595943Siedowse } 58696113Siedowse return (FAIL); 5871558Srgrimes 5886305Smartin case IFIFO: 58923685Speter vprintf(stdout, "extract fifo %s\n", name); 59023685Speter if (Nflag) { 59123685Speter skipfile(); 59223685Speter return (GOOD); 59323685Speter } 59435852Sjkh if (uflag && !Nflag) 59535852Sjkh (void)unlink(name); 5966305Smartin if (mkfifo(name, mode) < 0) { 59723685Speter fprintf(stderr, "%s: cannot create fifo: %s\n", 59823685Speter name, strerror(errno)); 5996305Smartin skipfile(); 6006305Smartin return (FAIL); 6016305Smartin } 60296113Siedowse (void) chown(name, uid, gid); 6036305Smartin (void) chmod(name, mode); 60496113Siedowse (void) utimes(name, timep); 60523685Speter (void) chflags(name, flags); 6066305Smartin skipfile(); 6076305Smartin return (GOOD); 6086305Smartin 6091558Srgrimes case IFCHR: 6101558Srgrimes case IFBLK: 6111558Srgrimes vprintf(stdout, "extract special file %s\n", name); 6121558Srgrimes if (Nflag) { 6131558Srgrimes skipfile(); 6141558Srgrimes return (GOOD); 6151558Srgrimes } 61635852Sjkh if (uflag) 61735852Sjkh (void)unlink(name); 6181558Srgrimes if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { 6191558Srgrimes fprintf(stderr, "%s: cannot create special file: %s\n", 6201558Srgrimes name, strerror(errno)); 6211558Srgrimes skipfile(); 6221558Srgrimes return (FAIL); 6231558Srgrimes } 62496113Siedowse (void) chown(name, uid, gid); 6251558Srgrimes (void) chmod(name, mode); 62696113Siedowse (void) utimes(name, timep); 62723685Speter (void) chflags(name, flags); 6281558Srgrimes skipfile(); 6291558Srgrimes return (GOOD); 6301558Srgrimes 6311558Srgrimes case IFREG: 6321558Srgrimes vprintf(stdout, "extract file %s\n", name); 6331558Srgrimes if (Nflag) { 6341558Srgrimes skipfile(); 6351558Srgrimes return (GOOD); 6361558Srgrimes } 63735852Sjkh if (uflag) 63835852Sjkh (void)unlink(name); 63921149Simp if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 64021149Simp 0666)) < 0) { 6411558Srgrimes fprintf(stderr, "%s: cannot create file: %s\n", 6421558Srgrimes name, strerror(errno)); 6431558Srgrimes skipfile(); 6441558Srgrimes return (FAIL); 6451558Srgrimes } 64696113Siedowse (void) fchown(ofile, uid, gid); 6471558Srgrimes (void) fchmod(ofile, mode); 6481558Srgrimes getfile(xtrfile, xtrskip); 6491558Srgrimes (void) close(ofile); 6501558Srgrimes utimes(name, timep); 65163283Sdwmalone (void) chflags(name, flags); 6521558Srgrimes return (GOOD); 6531558Srgrimes } 6541558Srgrimes /* NOTREACHED */ 6551558Srgrimes} 6561558Srgrimes 6571558Srgrimes/* 6581558Srgrimes * skip over bit maps on the tape 6591558Srgrimes */ 6601558Srgrimesvoid 66192837Simpskipmaps(void) 6621558Srgrimes{ 6631558Srgrimes 6641558Srgrimes while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 6651558Srgrimes skipfile(); 6661558Srgrimes} 6671558Srgrimes 6681558Srgrimes/* 6691558Srgrimes * skip over a file on the tape 6701558Srgrimes */ 6711558Srgrimesvoid 67292837Simpskipfile(void) 6731558Srgrimes{ 6741558Srgrimes 6751558Srgrimes curfile.action = SKIP; 6761558Srgrimes getfile(xtrnull, xtrnull); 6771558Srgrimes} 6781558Srgrimes 6791558Srgrimes/* 6801558Srgrimes * Extract a file from the tape. 6811558Srgrimes * When an allocated block is found it is passed to the fill function; 6821558Srgrimes * when an unallocated block (hole) is found, a zeroed buffer is passed 6831558Srgrimes * to the skip function. 6841558Srgrimes */ 6851558Srgrimesvoid 68692837Simpgetfile(void (*fill)(char *, long), void (*skip)(char *, long)) 6871558Srgrimes{ 68892806Sobrien int i; 6891558Srgrimes int curblk = 0; 69023685Speter quad_t size = spcl.c_dinode.di_size; 6911558Srgrimes static char clearedbuf[MAXBSIZE]; 6921558Srgrimes char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 6931558Srgrimes char junk[TP_BSIZE]; 6941558Srgrimes 6951558Srgrimes if (spcl.c_type == TS_END) 6961558Srgrimes panic("ran off end of tape\n"); 6971558Srgrimes if (spcl.c_magic != NFS_MAGIC) 6981558Srgrimes panic("not at beginning of a file\n"); 6991558Srgrimes if (!gettingfile && setjmp(restart) != 0) 7001558Srgrimes return; 7011558Srgrimes gettingfile++; 7021558Srgrimesloop: 7031558Srgrimes for (i = 0; i < spcl.c_count; i++) { 70437923Simp if (readmapflag || spcl.c_addr[i]) { 7051558Srgrimes readtape(&buf[curblk++][0]); 7061558Srgrimes if (curblk == fssize / TP_BSIZE) { 70723685Speter (*fill)((char *)buf, (long)(size > TP_BSIZE ? 70823685Speter fssize : (curblk - 1) * TP_BSIZE + size)); 7091558Srgrimes curblk = 0; 7101558Srgrimes } 7111558Srgrimes } else { 7121558Srgrimes if (curblk > 0) { 71323685Speter (*fill)((char *)buf, (long)(size > TP_BSIZE ? 71423685Speter curblk * TP_BSIZE : 71523685Speter (curblk - 1) * TP_BSIZE + size)); 7161558Srgrimes curblk = 0; 7171558Srgrimes } 71823685Speter (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 71923685Speter TP_BSIZE : size)); 7201558Srgrimes } 7211558Srgrimes if ((size -= TP_BSIZE) <= 0) { 7221558Srgrimes for (i++; i < spcl.c_count; i++) 72337923Simp if (readmapflag || spcl.c_addr[i]) 7241558Srgrimes readtape(junk); 7251558Srgrimes break; 7261558Srgrimes } 7271558Srgrimes } 7281558Srgrimes if (gethead(&spcl) == GOOD && size > 0) { 7291558Srgrimes if (spcl.c_type == TS_ADDR) 7301558Srgrimes goto loop; 7311558Srgrimes dprintf(stdout, 73237240Sbde "Missing address (header) block for %s at %ld blocks\n", 7331558Srgrimes curfile.name, blksread); 7341558Srgrimes } 7351558Srgrimes if (curblk > 0) 73623685Speter (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size)); 7371558Srgrimes findinode(&spcl); 7381558Srgrimes gettingfile = 0; 7391558Srgrimes} 7401558Srgrimes 7411558Srgrimes/* 7421558Srgrimes * Write out the next block of a file. 7431558Srgrimes */ 7441558Srgrimesstatic void 74592837Simpxtrfile(char *buf, long size) 7461558Srgrimes{ 7471558Srgrimes 7481558Srgrimes if (Nflag) 7491558Srgrimes return; 7501558Srgrimes if (write(ofile, buf, (int) size) == -1) { 7511558Srgrimes fprintf(stderr, 7521558Srgrimes "write error extracting inode %d, name %s\nwrite: %s\n", 7531558Srgrimes curfile.ino, curfile.name, strerror(errno)); 7541558Srgrimes } 7551558Srgrimes} 7561558Srgrimes 7571558Srgrimes/* 7581558Srgrimes * Skip over a hole in a file. 7591558Srgrimes */ 7601558Srgrimes/* ARGSUSED */ 7611558Srgrimesstatic void 76292837Simpxtrskip(char *buf, long size) 7631558Srgrimes{ 7641558Srgrimes 7651558Srgrimes if (lseek(ofile, size, SEEK_CUR) == -1) { 7661558Srgrimes fprintf(stderr, 7671558Srgrimes "seek error extracting inode %d, name %s\nlseek: %s\n", 7681558Srgrimes curfile.ino, curfile.name, strerror(errno)); 7691558Srgrimes done(1); 7701558Srgrimes } 7711558Srgrimes} 7721558Srgrimes 7731558Srgrimes/* 7741558Srgrimes * Collect the next block of a symbolic link. 7751558Srgrimes */ 7761558Srgrimesstatic void 77792837Simpxtrlnkfile(char *buf, long size) 7781558Srgrimes{ 7791558Srgrimes 7801558Srgrimes pathlen += size; 7811558Srgrimes if (pathlen > MAXPATHLEN) { 7821558Srgrimes fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 7831558Srgrimes curfile.name, lnkbuf, buf, pathlen); 7841558Srgrimes done(1); 7851558Srgrimes } 7861558Srgrimes (void) strcat(lnkbuf, buf); 7871558Srgrimes} 7881558Srgrimes 7891558Srgrimes/* 7901558Srgrimes * Skip over a hole in a symbolic link (should never happen). 7911558Srgrimes */ 7921558Srgrimes/* ARGSUSED */ 7931558Srgrimesstatic void 79492837Simpxtrlnkskip(char *buf, long size) 7951558Srgrimes{ 7961558Srgrimes 7971558Srgrimes fprintf(stderr, "unallocated block in symbolic link %s\n", 7981558Srgrimes curfile.name); 7991558Srgrimes done(1); 8001558Srgrimes} 8011558Srgrimes 8021558Srgrimes/* 8031558Srgrimes * Collect the next block of a bit map. 8041558Srgrimes */ 8051558Srgrimesstatic void 80692837Simpxtrmap(char *buf, long size) 8071558Srgrimes{ 8081558Srgrimes 80923685Speter memmove(map, buf, size); 8101558Srgrimes map += size; 8111558Srgrimes} 8121558Srgrimes 8131558Srgrimes/* 8141558Srgrimes * Skip over a hole in a bit map (should never happen). 8151558Srgrimes */ 8161558Srgrimes/* ARGSUSED */ 8171558Srgrimesstatic void 81892837Simpxtrmapskip(char *buf, long size) 8191558Srgrimes{ 8201558Srgrimes 8211558Srgrimes panic("hole in map\n"); 8221558Srgrimes map += size; 8231558Srgrimes} 8241558Srgrimes 8251558Srgrimes/* 8261558Srgrimes * Noop, when an extraction function is not needed. 8271558Srgrimes */ 8281558Srgrimes/* ARGSUSED */ 8291558Srgrimesvoid 83092837Simpxtrnull(char *buf, long size) 8311558Srgrimes{ 8321558Srgrimes 8331558Srgrimes return; 8341558Srgrimes} 8351558Srgrimes 8361558Srgrimes/* 8371558Srgrimes * Read TP_BSIZE blocks from the input. 8381558Srgrimes * Handle read errors, and end of media. 8391558Srgrimes */ 8401558Srgrimesstatic void 84192837Simpreadtape(char *buf) 8421558Srgrimes{ 8431558Srgrimes long rd, newvol, i; 8441558Srgrimes int cnt, seek_failed; 8451558Srgrimes 8461558Srgrimes if (blkcnt < numtrec) { 84723685Speter memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 8481558Srgrimes blksread++; 84990827Siedowse tapeaddr++; 8501558Srgrimes return; 8511558Srgrimes } 8521558Srgrimes for (i = 0; i < ntrec; i++) 8531558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 8541558Srgrimes if (numtrec == 0) 8551558Srgrimes numtrec = ntrec; 8561558Srgrimes cnt = ntrec * TP_BSIZE; 8571558Srgrimes rd = 0; 8581558Srgrimesgetmore: 8591558Srgrimes#ifdef RRESTORE 8601558Srgrimes if (host) 8611558Srgrimes i = rmtread(&tapebuf[rd], cnt); 8621558Srgrimes else 8631558Srgrimes#endif 8641558Srgrimes i = read(mt, &tapebuf[rd], cnt); 8651558Srgrimes /* 8661558Srgrimes * Check for mid-tape short read error. 8671558Srgrimes * If found, skip rest of buffer and start with the next. 8681558Srgrimes */ 8691558Srgrimes if (!pipein && numtrec < ntrec && i > 0) { 8701558Srgrimes dprintf(stdout, "mid-media short read error.\n"); 8711558Srgrimes numtrec = ntrec; 8721558Srgrimes } 8731558Srgrimes /* 8741558Srgrimes * Handle partial block read. 8751558Srgrimes */ 8761558Srgrimes if (pipein && i == 0 && rd > 0) 8771558Srgrimes i = rd; 8781558Srgrimes else if (i > 0 && i != ntrec * TP_BSIZE) { 8791558Srgrimes if (pipein) { 8801558Srgrimes rd += i; 8811558Srgrimes cnt -= i; 8821558Srgrimes if (cnt > 0) 8831558Srgrimes goto getmore; 8841558Srgrimes i = rd; 8851558Srgrimes } else { 8861558Srgrimes /* 8871558Srgrimes * Short read. Process the blocks read. 8881558Srgrimes */ 8891558Srgrimes if (i % TP_BSIZE != 0) 8901558Srgrimes vprintf(stdout, 89137240Sbde "partial block read: %ld should be %ld\n", 8921558Srgrimes i, ntrec * TP_BSIZE); 8931558Srgrimes numtrec = i / TP_BSIZE; 8941558Srgrimes } 8951558Srgrimes } 8961558Srgrimes /* 8971558Srgrimes * Handle read error. 8981558Srgrimes */ 8991558Srgrimes if (i < 0) { 9001558Srgrimes fprintf(stderr, "Tape read error while "); 9011558Srgrimes switch (curfile.action) { 9021558Srgrimes default: 9031558Srgrimes fprintf(stderr, "trying to set up tape\n"); 9041558Srgrimes break; 9051558Srgrimes case UNKNOWN: 9061558Srgrimes fprintf(stderr, "trying to resynchronize\n"); 9071558Srgrimes break; 9081558Srgrimes case USING: 9091558Srgrimes fprintf(stderr, "restoring %s\n", curfile.name); 9101558Srgrimes break; 9111558Srgrimes case SKIP: 9121558Srgrimes fprintf(stderr, "skipping over inode %d\n", 9131558Srgrimes curfile.ino); 9141558Srgrimes break; 9151558Srgrimes } 9161558Srgrimes if (!yflag && !reply("continue")) 9171558Srgrimes done(1); 9181558Srgrimes i = ntrec * TP_BSIZE; 91923685Speter memset(tapebuf, 0, i); 9201558Srgrimes#ifdef RRESTORE 9211558Srgrimes if (host) 9221558Srgrimes seek_failed = (rmtseek(i, 1) < 0); 9231558Srgrimes else 9241558Srgrimes#endif 9251558Srgrimes seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 9261558Srgrimes 9271558Srgrimes if (seek_failed) { 9281558Srgrimes fprintf(stderr, 9291558Srgrimes "continuation failed: %s\n", strerror(errno)); 9301558Srgrimes done(1); 9311558Srgrimes } 9321558Srgrimes } 9331558Srgrimes /* 9341558Srgrimes * Handle end of tape. 9351558Srgrimes */ 9361558Srgrimes if (i == 0) { 9371558Srgrimes vprintf(stdout, "End-of-tape encountered\n"); 9381558Srgrimes if (!pipein) { 9391558Srgrimes newvol = volno + 1; 9401558Srgrimes volno = 0; 9411558Srgrimes numtrec = 0; 9421558Srgrimes getvol(newvol); 9431558Srgrimes readtape(buf); 9441558Srgrimes return; 9451558Srgrimes } 9461558Srgrimes if (rd % TP_BSIZE != 0) 9471558Srgrimes panic("partial block read: %d should be %d\n", 9481558Srgrimes rd, ntrec * TP_BSIZE); 9491558Srgrimes terminateinput(); 95023685Speter memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 9511558Srgrimes } 9521558Srgrimes blkcnt = 0; 95323685Speter memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 9541558Srgrimes blksread++; 95590827Siedowse tapeaddr++; 9561558Srgrimes} 9571558Srgrimes 9581558Srgrimesstatic void 95992837Simpfindtapeblksize(void) 9601558Srgrimes{ 96192806Sobrien long i; 9621558Srgrimes 9631558Srgrimes for (i = 0; i < ntrec; i++) 9641558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 9651558Srgrimes blkcnt = 0; 9661558Srgrimes#ifdef RRESTORE 9671558Srgrimes if (host) 9681558Srgrimes i = rmtread(tapebuf, ntrec * TP_BSIZE); 9691558Srgrimes else 9701558Srgrimes#endif 9711558Srgrimes i = read(mt, tapebuf, ntrec * TP_BSIZE); 9721558Srgrimes 9731558Srgrimes if (i <= 0) { 9741558Srgrimes fprintf(stderr, "tape read error: %s\n", strerror(errno)); 9751558Srgrimes done(1); 9761558Srgrimes } 9771558Srgrimes if (i % TP_BSIZE != 0) { 97837240Sbde fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 9791558Srgrimes i, "is not a multiple of dump block size", TP_BSIZE); 9801558Srgrimes done(1); 9811558Srgrimes } 9821558Srgrimes ntrec = i / TP_BSIZE; 9831558Srgrimes numtrec = ntrec; 98437240Sbde vprintf(stdout, "Tape block size is %ld\n", ntrec); 9851558Srgrimes} 9861558Srgrimes 9871558Srgrimesvoid 98892837Simpclosemt(void) 9891558Srgrimes{ 9901558Srgrimes 9911558Srgrimes if (mt < 0) 9921558Srgrimes return; 9931558Srgrimes#ifdef RRESTORE 9941558Srgrimes if (host) 9951558Srgrimes rmtclose(); 9961558Srgrimes else 9971558Srgrimes#endif 9981558Srgrimes (void) close(mt); 9991558Srgrimes} 10001558Srgrimes 10011558Srgrimes/* 10021558Srgrimes * Read the next block from the tape. 10031558Srgrimes * Check to see if it is one of several vintage headers. 10041558Srgrimes * If it is an old style header, convert it to a new style header. 10051558Srgrimes * If it is not any valid header, return an error. 10061558Srgrimes */ 10071558Srgrimesstatic int 100892837Simpgethead(struct s_spcl *buf) 10091558Srgrimes{ 10101558Srgrimes long i; 10111558Srgrimes union { 10121558Srgrimes quad_t qval; 101340668Sdima int32_t val[2]; 10141558Srgrimes } qcvt; 10151558Srgrimes union u_ospcl { 10161558Srgrimes char dummy[TP_BSIZE]; 10171558Srgrimes struct s_ospcl { 101840668Sdima int32_t c_type; 101940668Sdima int32_t c_date; 102040668Sdima int32_t c_ddate; 102140668Sdima int32_t c_volume; 102240668Sdima int32_t c_tapea; 10231558Srgrimes u_short c_inumber; 102440668Sdima int32_t c_magic; 102540668Sdima int32_t c_checksum; 10261558Srgrimes struct odinode { 10271558Srgrimes unsigned short odi_mode; 10281558Srgrimes u_short odi_nlink; 10291558Srgrimes u_short odi_uid; 10301558Srgrimes u_short odi_gid; 103140668Sdima int32_t odi_size; 103240668Sdima int32_t odi_rdev; 10331558Srgrimes char odi_addr[36]; 103440668Sdima int32_t odi_atime; 103540668Sdima int32_t odi_mtime; 103640668Sdima int32_t odi_ctime; 10371558Srgrimes } c_dinode; 103840668Sdima int32_t c_count; 10391558Srgrimes char c_addr[256]; 10401558Srgrimes } s_ospcl; 10411558Srgrimes } u_ospcl; 10421558Srgrimes 10431558Srgrimes if (!cvtflag) { 10441558Srgrimes readtape((char *)buf); 10451558Srgrimes if (buf->c_magic != NFS_MAGIC) { 10461558Srgrimes if (swabl(buf->c_magic) != NFS_MAGIC) 10471558Srgrimes return (FAIL); 10481558Srgrimes if (!Bcvt) { 10491558Srgrimes vprintf(stdout, "Note: Doing Byte swapping\n"); 10501558Srgrimes Bcvt = 1; 10511558Srgrimes } 10521558Srgrimes } 10531558Srgrimes if (checksum((int *)buf) == FAIL) 10541558Srgrimes return (FAIL); 105523096Simp if (Bcvt) { 10561558Srgrimes swabst((u_char *)"8l4s31l", (u_char *)buf); 105723096Simp swabst((u_char *)"l",(u_char *) &buf->c_level); 105823096Simp swabst((u_char *)"2l",(u_char *) &buf->c_flags); 105923096Simp } 10601558Srgrimes goto good; 10611558Srgrimes } 10621558Srgrimes readtape((char *)(&u_ospcl.s_ospcl)); 106323685Speter memset(buf, 0, (long)TP_BSIZE); 10641558Srgrimes buf->c_type = u_ospcl.s_ospcl.c_type; 10651558Srgrimes buf->c_date = u_ospcl.s_ospcl.c_date; 10661558Srgrimes buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 10671558Srgrimes buf->c_volume = u_ospcl.s_ospcl.c_volume; 10681558Srgrimes buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 10691558Srgrimes buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 10701558Srgrimes buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 10711558Srgrimes buf->c_magic = u_ospcl.s_ospcl.c_magic; 10721558Srgrimes buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 10731558Srgrimes buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 10741558Srgrimes buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 10751558Srgrimes buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 10761558Srgrimes buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; 10771558Srgrimes buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 107823685Speter buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; 107923685Speter buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; 108023685Speter buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; 10811558Srgrimes buf->c_count = u_ospcl.s_ospcl.c_count; 108223685Speter memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256); 10831558Srgrimes if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || 10841558Srgrimes checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) 10851558Srgrimes return(FAIL); 10861558Srgrimes buf->c_magic = NFS_MAGIC; 10871558Srgrimes 10881558Srgrimesgood: 10891558Srgrimes if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) && 10901558Srgrimes (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) { 10911558Srgrimes qcvt.qval = buf->c_dinode.di_size; 10921558Srgrimes if (qcvt.val[0] || qcvt.val[1]) { 10931558Srgrimes printf("Note: Doing Quad swapping\n"); 10941558Srgrimes Qcvt = 1; 10951558Srgrimes } 10961558Srgrimes } 10971558Srgrimes if (Qcvt) { 10981558Srgrimes qcvt.qval = buf->c_dinode.di_size; 10991558Srgrimes i = qcvt.val[1]; 11001558Srgrimes qcvt.val[1] = qcvt.val[0]; 11011558Srgrimes qcvt.val[0] = i; 11021558Srgrimes buf->c_dinode.di_size = qcvt.qval; 11031558Srgrimes } 110437923Simp readmapflag = 0; 11051558Srgrimes 11061558Srgrimes switch (buf->c_type) { 11071558Srgrimes 11081558Srgrimes case TS_CLRI: 11091558Srgrimes case TS_BITS: 11101558Srgrimes /* 11111558Srgrimes * Have to patch up missing information in bit map headers 11121558Srgrimes */ 11131558Srgrimes buf->c_inumber = 0; 11141558Srgrimes buf->c_dinode.di_size = buf->c_count * TP_BSIZE; 111537923Simp if (buf->c_count > TP_NINDIR) 111637923Simp readmapflag = 1; 111737923Simp else 111837923Simp for (i = 0; i < buf->c_count; i++) 111937923Simp buf->c_addr[i]++; 11201558Srgrimes break; 11211558Srgrimes 11221558Srgrimes case TS_TAPE: 11231558Srgrimes if ((buf->c_flags & DR_NEWINODEFMT) == 0) 11241558Srgrimes oldinofmt = 1; 11251558Srgrimes /* fall through */ 11261558Srgrimes case TS_END: 11271558Srgrimes buf->c_inumber = 0; 11281558Srgrimes break; 11291558Srgrimes 11301558Srgrimes case TS_INODE: 11311558Srgrimes case TS_ADDR: 11321558Srgrimes break; 11331558Srgrimes 11341558Srgrimes default: 11351558Srgrimes panic("gethead: unknown inode type %d\n", buf->c_type); 11361558Srgrimes break; 11371558Srgrimes } 11381558Srgrimes /* 11398871Srgrimes * If we are restoring a filesystem with old format inodes, 11401558Srgrimes * copy the uid/gid to the new location. 11411558Srgrimes */ 11421558Srgrimes if (oldinofmt) { 11431558Srgrimes buf->c_dinode.di_uid = buf->c_dinode.di_ouid; 11441558Srgrimes buf->c_dinode.di_gid = buf->c_dinode.di_ogid; 11451558Srgrimes } 114690827Siedowse tapeaddr = buf->c_tapea; 11471558Srgrimes if (dflag) 11481558Srgrimes accthdr(buf); 11491558Srgrimes return(GOOD); 11501558Srgrimes} 11511558Srgrimes 11521558Srgrimes/* 11531558Srgrimes * Check that a header is where it belongs and predict the next header 11541558Srgrimes */ 11551558Srgrimesstatic void 115692837Simpaccthdr(struct s_spcl *header) 11571558Srgrimes{ 11581558Srgrimes static ino_t previno = 0x7fffffff; 11591558Srgrimes static int prevtype; 11601558Srgrimes static long predict; 11611558Srgrimes long blks, i; 11621558Srgrimes 11631558Srgrimes if (header->c_type == TS_TAPE) { 11641558Srgrimes fprintf(stderr, "Volume header (%s inode format) ", 11651558Srgrimes oldinofmt ? "old" : "new"); 11661558Srgrimes if (header->c_firstrec) 116737240Sbde fprintf(stderr, "begins with record %ld", 11681558Srgrimes header->c_firstrec); 11691558Srgrimes fprintf(stderr, "\n"); 11701558Srgrimes previno = 0x7fffffff; 11711558Srgrimes return; 11721558Srgrimes } 11731558Srgrimes if (previno == 0x7fffffff) 11741558Srgrimes goto newcalc; 11751558Srgrimes switch (prevtype) { 11761558Srgrimes case TS_BITS: 117723685Speter fprintf(stderr, "Dumped inodes map header"); 11781558Srgrimes break; 11791558Srgrimes case TS_CLRI: 118023685Speter fprintf(stderr, "Used inodes map header"); 11811558Srgrimes break; 11821558Srgrimes case TS_INODE: 11831558Srgrimes fprintf(stderr, "File header, ino %d", previno); 11841558Srgrimes break; 11851558Srgrimes case TS_ADDR: 11861558Srgrimes fprintf(stderr, "File continuation header, ino %d", previno); 11871558Srgrimes break; 11881558Srgrimes case TS_END: 11891558Srgrimes fprintf(stderr, "End of tape header"); 11901558Srgrimes break; 11911558Srgrimes } 11921558Srgrimes if (predict != blksread - 1) 119337240Sbde fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 11941558Srgrimes predict, blksread - 1); 11951558Srgrimes fprintf(stderr, "\n"); 11961558Srgrimesnewcalc: 11971558Srgrimes blks = 0; 11981558Srgrimes if (header->c_type != TS_END) 11991558Srgrimes for (i = 0; i < header->c_count; i++) 120037923Simp if (readmapflag || header->c_addr[i] != 0) 12011558Srgrimes blks++; 12021558Srgrimes predict = blks; 12031558Srgrimes blksread = 0; 12041558Srgrimes prevtype = header->c_type; 12051558Srgrimes previno = header->c_inumber; 12061558Srgrimes} 12071558Srgrimes 12081558Srgrimes/* 12091558Srgrimes * Find an inode header. 121090573Siedowse * Complain if had to skip. 12111558Srgrimes */ 12121558Srgrimesstatic void 121392837Simpfindinode(struct s_spcl *header) 12141558Srgrimes{ 12151558Srgrimes static long skipcnt = 0; 12161558Srgrimes long i; 12171558Srgrimes char buf[TP_BSIZE]; 121890608Siedowse int htype; 12191558Srgrimes 12201558Srgrimes curfile.name = "<name unknown>"; 12211558Srgrimes curfile.action = UNKNOWN; 12221558Srgrimes curfile.dip = NULL; 12231558Srgrimes curfile.ino = 0; 12241558Srgrimes do { 12251558Srgrimes if (header->c_magic != NFS_MAGIC) { 12261558Srgrimes skipcnt++; 12271558Srgrimes while (gethead(header) == FAIL || 122889572Sdillon _time32_to_time(header->c_date) != dumpdate) 12291558Srgrimes skipcnt++; 12301558Srgrimes } 123190608Siedowse htype = header->c_type; 123290608Siedowse switch (htype) { 12331558Srgrimes 12341558Srgrimes case TS_ADDR: 12351558Srgrimes /* 12361558Srgrimes * Skip up to the beginning of the next record 12371558Srgrimes */ 12381558Srgrimes for (i = 0; i < header->c_count; i++) 12391558Srgrimes if (header->c_addr[i]) 12401558Srgrimes readtape(buf); 12411558Srgrimes while (gethead(header) == FAIL || 124289572Sdillon _time32_to_time(header->c_date) != dumpdate) 12431558Srgrimes skipcnt++; 12441558Srgrimes break; 12451558Srgrimes 12461558Srgrimes case TS_INODE: 12471558Srgrimes curfile.dip = &header->c_dinode; 12481558Srgrimes curfile.ino = header->c_inumber; 12491558Srgrimes break; 12501558Srgrimes 12511558Srgrimes case TS_END: 125290820Siedowse /* If we missed some tapes, get another volume. */ 125390820Siedowse if (tapesread & (tapesread + 1)) { 125490820Siedowse getvol(0); 125590820Siedowse continue; 125690820Siedowse } 12571558Srgrimes curfile.ino = maxino; 12581558Srgrimes break; 12591558Srgrimes 12601558Srgrimes case TS_CLRI: 12611558Srgrimes curfile.name = "<file removal list>"; 12621558Srgrimes break; 12631558Srgrimes 12641558Srgrimes case TS_BITS: 12651558Srgrimes curfile.name = "<file dump list>"; 12661558Srgrimes break; 12671558Srgrimes 12681558Srgrimes case TS_TAPE: 12691558Srgrimes panic("unexpected tape header\n"); 12701558Srgrimes /* NOTREACHED */ 12711558Srgrimes 12721558Srgrimes default: 12731558Srgrimes panic("unknown tape header type %d\n", spcl.c_type); 12741558Srgrimes /* NOTREACHED */ 12751558Srgrimes 12761558Srgrimes } 127790608Siedowse } while (htype == TS_ADDR); 12781558Srgrimes if (skipcnt > 0) 127937240Sbde fprintf(stderr, "resync restore, skipped %ld blocks\n", 128037240Sbde skipcnt); 12811558Srgrimes skipcnt = 0; 12821558Srgrimes} 12831558Srgrimes 12841558Srgrimesstatic int 128592837Simpchecksum(int *buf) 12861558Srgrimes{ 128792806Sobrien int i, j; 12881558Srgrimes 12891558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 12901558Srgrimes i = 0; 12911558Srgrimes if(!Bcvt) { 12921558Srgrimes do 12931558Srgrimes i += *buf++; 12941558Srgrimes while (--j); 12951558Srgrimes } else { 12961558Srgrimes /* What happens if we want to read restore tapes 12971558Srgrimes for a 16bit int machine??? */ 12988871Srgrimes do 12991558Srgrimes i += swabl(*buf++); 13001558Srgrimes while (--j); 13011558Srgrimes } 13028871Srgrimes 13031558Srgrimes if (i != CHECKSUM) { 13041558Srgrimes fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 13051558Srgrimes curfile.ino, curfile.name); 13061558Srgrimes return(FAIL); 13071558Srgrimes } 13081558Srgrimes return(GOOD); 13091558Srgrimes} 13101558Srgrimes 13111558Srgrimes#ifdef RRESTORE 13121558Srgrimes#include <stdarg.h> 13131558Srgrimes 13141558Srgrimesvoid 13151558Srgrimesmsg(const char *fmt, ...) 13161558Srgrimes{ 13171558Srgrimes va_list ap; 13181558Srgrimes va_start(ap, fmt); 13191558Srgrimes (void)vfprintf(stderr, fmt, ap); 13201558Srgrimes va_end(ap); 13211558Srgrimes} 13221558Srgrimes#endif /* RRESTORE */ 13231558Srgrimes 13241558Srgrimesstatic u_char * 132592837Simpswabshort(u_char *sp, 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 * 133792837Simpswablong(u_char *sp, int n) 13381558Srgrimes{ 13391558Srgrimes char c; 13401558Srgrimes 13411558Srgrimes while (--n >= 0) { 13421558Srgrimes c = sp[0]; sp[0] = sp[3]; sp[3] = c; 13431558Srgrimes c = sp[2]; sp[2] = sp[1]; sp[1] = c; 13441558Srgrimes sp += 4; 13451558Srgrimes } 13461558Srgrimes return (sp); 13471558Srgrimes} 13481558Srgrimes 13491558Srgrimesvoid 135092837Simpswabst(u_char *cp, u_char *sp) 13511558Srgrimes{ 13521558Srgrimes int n = 0; 13531558Srgrimes 13541558Srgrimes while (*cp) { 13551558Srgrimes switch (*cp) { 13561558Srgrimes case '0': case '1': case '2': case '3': case '4': 13571558Srgrimes case '5': case '6': case '7': case '8': case '9': 13581558Srgrimes n = (n * 10) + (*cp++ - '0'); 13591558Srgrimes continue; 13608871Srgrimes 13611558Srgrimes case 's': case 'w': case 'h': 13621558Srgrimes if (n == 0) 13631558Srgrimes n = 1; 13641558Srgrimes sp = swabshort(sp, n); 13651558Srgrimes break; 13661558Srgrimes 13671558Srgrimes case 'l': 13681558Srgrimes if (n == 0) 13691558Srgrimes n = 1; 13701558Srgrimes sp = swablong(sp, n); 13711558Srgrimes break; 13721558Srgrimes 13731558Srgrimes default: /* Any other character, like 'b' counts as byte. */ 13741558Srgrimes if (n == 0) 13751558Srgrimes n = 1; 13761558Srgrimes sp += n; 13771558Srgrimes break; 13781558Srgrimes } 13791558Srgrimes cp++; 13801558Srgrimes n = 0; 13811558Srgrimes } 13821558Srgrimes} 13831558Srgrimes 13841558Srgrimesstatic u_long 138592837Simpswabl(u_long x) 13861558Srgrimes{ 13871558Srgrimes swabst((u_char *)"l", (u_char *)&x); 13881558Srgrimes return (x); 13891558Srgrimes} 1390