tape.c revision 128175
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 * 4. Neither the name of the University nor the names of its contributors 191558Srgrimes * may be used to endorse or promote products derived from this software 201558Srgrimes * without specific prior written permission. 211558Srgrimes * 221558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321558Srgrimes * SUCH DAMAGE. 331558Srgrimes */ 341558Srgrimes 351558Srgrimes#ifndef lint 3637906Scharnier#if 0 3723685Speterstatic char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; 3837906Scharnier#endif 3937906Scharnierstatic const char rcsid[] = 4050476Speter "$FreeBSD: head/sbin/restore/tape.c 128175 2004-04-13 02:58:06Z green $"; 411558Srgrimes#endif /* not lint */ 421558Srgrimes 431558Srgrimes#include <sys/param.h> 441558Srgrimes#include <sys/file.h> 451558Srgrimes#include <sys/mtio.h> 461558Srgrimes#include <sys/stat.h> 4766907Swollman#include <sys/time.h> 481558Srgrimes 491558Srgrimes#include <ufs/ufs/dinode.h> 501558Srgrimes#include <protocols/dumprestore.h> 511558Srgrimes 521558Srgrimes#include <errno.h> 53103949Smike#include <limits.h> 5473986Sobrien#include <paths.h> 551558Srgrimes#include <setjmp.h> 561558Srgrimes#include <stdio.h> 571558Srgrimes#include <stdlib.h> 581558Srgrimes#include <string.h> 5966907Swollman#include <time.h> 601558Srgrimes#include <unistd.h> 611558Srgrimes 621558Srgrimes#include "restore.h" 631558Srgrimes#include "extern.h" 641558Srgrimes 651558Srgrimesstatic long fssize = MAXBSIZE; 661558Srgrimesstatic int mt = -1; 671558Srgrimesstatic int pipein = 0; 68128175Sgreenstatic int pipecmdin = 0; 69128175Sgreenstatic FILE *popenfp = NULL; 7021174Sguidostatic char *magtape; 711558Srgrimesstatic int blkcnt; 721558Srgrimesstatic int numtrec; 731558Srgrimesstatic char *tapebuf; 741558Srgrimesstatic union u_spcl endoftapemark; 751558Srgrimesstatic long blksread; /* blocks read since last header */ 7698542Smckusickstatic int64_t tapeaddr = 0; /* current TP_BSIZE tape record */ 771558Srgrimesstatic long tapesread; 781558Srgrimesstatic jmp_buf restart; 791558Srgrimesstatic int gettingfile = 0; /* restart has a valid frame */ 801558Srgrimesstatic char *host = NULL; 8198542Smckusickstatic int readmapflag; 821558Srgrimes 831558Srgrimesstatic int ofile; 841558Srgrimesstatic char *map; 851558Srgrimesstatic char lnkbuf[MAXPATHLEN + 1]; 861558Srgrimesstatic int pathlen; 871558Srgrimes 8898542Smckusickint Bcvt; /* Swap Bytes */ 891558Srgrimes 901558Srgrimes#define FLUSHTAPEBUF() blkcnt = ntrec + 1 911558Srgrimes 9292837Simpstatic void accthdr(struct s_spcl *); 9392837Simpstatic int checksum(int *); 9492837Simpstatic void findinode(struct s_spcl *); 9592837Simpstatic void findtapeblksize(void); 9692837Simpstatic int gethead(struct s_spcl *); 9792837Simpstatic void readtape(char *); 9892837Simpstatic void setdumpnum(void); 9992837Simpstatic u_long swabl(u_long); 10092837Simpstatic u_char *swablong(u_char *, int); 10192837Simpstatic u_char *swabshort(u_char *, int); 10292837Simpstatic void terminateinput(void); 10392837Simpstatic void xtrfile(char *, long); 10492837Simpstatic void xtrlnkfile(char *, long); 10592837Simpstatic void xtrlnkskip(char *, long); 10692837Simpstatic void xtrmap(char *, long); 10792837Simpstatic void xtrmapskip(char *, long); 10892837Simpstatic void xtrskip(char *, long); 1091558Srgrimes 1101558Srgrimes/* 1111558Srgrimes * Set up an input source 1121558Srgrimes */ 1131558Srgrimesvoid 114128175Sgreensetinput(char *source, int ispipecommand) 1151558Srgrimes{ 1161558Srgrimes FLUSHTAPEBUF(); 1171558Srgrimes if (bflag) 1181558Srgrimes newtapebuf(ntrec); 1191558Srgrimes else 1201558Srgrimes newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 1211558Srgrimes terminal = stdin; 1221558Srgrimes 123128175Sgreen if (ispipecommand) 124128175Sgreen pipecmdin++; 125128175Sgreen else 1261558Srgrimes#ifdef RRESTORE 12723685Speter if (strchr(source, ':')) { 1281558Srgrimes host = source; 12923685Speter source = strchr(host, ':'); 1301558Srgrimes *source++ = '\0'; 1311558Srgrimes if (rmthost(host) == 0) 1321558Srgrimes done(1); 1331558Srgrimes } else 1341558Srgrimes#endif 1351558Srgrimes if (strcmp(source, "-") == 0) { 1361558Srgrimes /* 1371558Srgrimes * Since input is coming from a pipe we must establish 1381558Srgrimes * our own connection to the terminal. 1391558Srgrimes */ 1401558Srgrimes terminal = fopen(_PATH_TTY, "r"); 1411558Srgrimes if (terminal == NULL) { 1421558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1431558Srgrimes _PATH_TTY, strerror(errno)); 1441558Srgrimes terminal = fopen(_PATH_DEVNULL, "r"); 1451558Srgrimes if (terminal == NULL) { 1461558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1471558Srgrimes _PATH_DEVNULL, strerror(errno)); 1481558Srgrimes done(1); 1491558Srgrimes } 1501558Srgrimes } 1511558Srgrimes pipein++; 1521558Srgrimes } 1531558Srgrimes setuid(getuid()); /* no longer need or want root privileges */ 15421174Sguido magtape = strdup(source); 15521174Sguido if (magtape == NULL) { 15621174Sguido fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 15721174Sguido done(1); 15821174Sguido } 1591558Srgrimes} 1601558Srgrimes 1611558Srgrimesvoid 16292837Simpnewtapebuf(long size) 1631558Srgrimes{ 16492837Simp static int tapebufsize = -1; 1651558Srgrimes 1661558Srgrimes ntrec = size; 1671558Srgrimes if (size <= tapebufsize) 1681558Srgrimes return; 1691558Srgrimes if (tapebuf != NULL) 1701558Srgrimes free(tapebuf); 1711558Srgrimes tapebuf = malloc(size * TP_BSIZE); 1721558Srgrimes if (tapebuf == NULL) { 1731558Srgrimes fprintf(stderr, "Cannot allocate space for tape buffer\n"); 1741558Srgrimes done(1); 1751558Srgrimes } 1761558Srgrimes tapebufsize = size; 1771558Srgrimes} 1781558Srgrimes 1791558Srgrimes/* 1801558Srgrimes * Verify that the tape drive can be accessed and 1811558Srgrimes * that it actually is a dump tape. 1821558Srgrimes */ 1831558Srgrimesvoid 18492837Simpsetup(void) 1851558Srgrimes{ 1861558Srgrimes int i, j, *ip; 1871558Srgrimes struct stat stbuf; 1881558Srgrimes 1891558Srgrimes vprintf(stdout, "Verify tape and initialize maps\n"); 190128175Sgreen if (pipecmdin) { 191128175Sgreen if (setenv("RESTORE_VOLUME", "1", 1) == -1) { 192128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 193128175Sgreen strerror(errno)); 194128175Sgreen done(1); 195128175Sgreen } 196128175Sgreen popenfp = popen(magtape, "r"); 197128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 198128175Sgreen } else 1991558Srgrimes#ifdef RRESTORE 2001558Srgrimes if (host) 2011558Srgrimes mt = rmtopen(magtape, 0); 2021558Srgrimes else 2031558Srgrimes#endif 2041558Srgrimes if (pipein) 2051558Srgrimes mt = 0; 2061558Srgrimes else 2071558Srgrimes mt = open(magtape, O_RDONLY, 0); 2081558Srgrimes if (mt < 0) { 2091558Srgrimes fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 2101558Srgrimes done(1); 2111558Srgrimes } 2121558Srgrimes volno = 1; 2131558Srgrimes setdumpnum(); 2141558Srgrimes FLUSHTAPEBUF(); 2151558Srgrimes if (!pipein && !bflag) 2161558Srgrimes findtapeblksize(); 2171558Srgrimes if (gethead(&spcl) == FAIL) { 21898542Smckusick fprintf(stderr, "Tape is not a dump tape\n"); 21998542Smckusick done(1); 2201558Srgrimes } 2211558Srgrimes if (pipein) { 22298542Smckusick endoftapemark.s_spcl.c_magic = FS_UFS2_MAGIC; 2231558Srgrimes endoftapemark.s_spcl.c_type = TS_END; 2241558Srgrimes ip = (int *)&endoftapemark; 2251558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 2261558Srgrimes i = 0; 2271558Srgrimes do 2281558Srgrimes i += *ip++; 2291558Srgrimes while (--j); 2301558Srgrimes endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 2311558Srgrimes } 2321558Srgrimes if (vflag || command == 't') 2331558Srgrimes printdumpinfo(); 23498542Smckusick dumptime = _time64_to_time(spcl.c_ddate); 23598542Smckusick dumpdate = _time64_to_time(spcl.c_date); 2361558Srgrimes if (stat(".", &stbuf) < 0) { 2371558Srgrimes fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 2381558Srgrimes done(1); 2391558Srgrimes } 24034851Sjkh if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 24134851Sjkh fssize = TP_BSIZE; 24234851Sjkh if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 2431558Srgrimes fssize = stbuf.st_blksize; 2441558Srgrimes if (((fssize - 1) & fssize) != 0) { 24537240Sbde fprintf(stderr, "bad block size %ld\n", fssize); 2461558Srgrimes done(1); 2471558Srgrimes } 2481558Srgrimes if (spcl.c_volume != 1) { 2491558Srgrimes fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2501558Srgrimes done(1); 2511558Srgrimes } 2521558Srgrimes if (gethead(&spcl) == FAIL) { 25337240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 2541558Srgrimes panic("no header after volume mark!\n"); 2551558Srgrimes } 2561558Srgrimes findinode(&spcl); 2571558Srgrimes if (spcl.c_type != TS_CLRI) { 2581558Srgrimes fprintf(stderr, "Cannot find file removal list\n"); 2591558Srgrimes done(1); 2601558Srgrimes } 2611558Srgrimes maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 2621558Srgrimes dprintf(stdout, "maxino = %d\n", maxino); 2631558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2641558Srgrimes if (map == NULL) 26523685Speter panic("no memory for active inode map\n"); 26623685Speter usedinomap = map; 2671558Srgrimes curfile.action = USING; 2681558Srgrimes getfile(xtrmap, xtrmapskip); 2691558Srgrimes if (spcl.c_type != TS_BITS) { 2701558Srgrimes fprintf(stderr, "Cannot find file dump list\n"); 2711558Srgrimes done(1); 2721558Srgrimes } 2731558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2741558Srgrimes if (map == (char *)NULL) 2751558Srgrimes panic("no memory for file dump list\n"); 2761558Srgrimes dumpmap = map; 2771558Srgrimes curfile.action = USING; 2781558Srgrimes getfile(xtrmap, xtrmapskip); 27923685Speter /* 28023685Speter * If there may be whiteout entries on the tape, pretend that the 28123685Speter * whiteout inode exists, so that the whiteout entries can be 28223685Speter * extracted. 28323685Speter */ 28498542Smckusick SETINO(WINO, dumpmap); 28590820Siedowse /* 'r' restores don't call getvol() for tape 1, so mark it as read. */ 28690820Siedowse if (command == 'r') 28790820Siedowse tapesread = 1; 2881558Srgrimes} 2891558Srgrimes 2901558Srgrimes/* 2911558Srgrimes * Prompt user to load a new dump volume. 2921558Srgrimes * "Nextvol" is the next suggested volume to use. 2931558Srgrimes * This suggested volume is enforced when doing full 29437906Scharnier * or incremental restores, but can be overridden by 2951558Srgrimes * the user when only extracting a subset of the files. 2961558Srgrimes */ 2971558Srgrimesvoid 29892837Simpgetvol(long nextvol) 2991558Srgrimes{ 30098542Smckusick int64_t prevtapea; 30198542Smckusick long i, newvol, savecnt; 3021558Srgrimes union u_spcl tmpspcl; 3031558Srgrimes# define tmpbuf tmpspcl.s_spcl 3041558Srgrimes char buf[TP_BSIZE]; 3051558Srgrimes 3061558Srgrimes if (nextvol == 1) { 3071558Srgrimes tapesread = 0; 3081558Srgrimes gettingfile = 0; 3091558Srgrimes } 31090827Siedowse prevtapea = tapeaddr; 31190827Siedowse savecnt = blksread; 3121558Srgrimes if (pipein) { 31369906Siedowse if (nextvol != 1) { 3141558Srgrimes panic("Changing volumes on pipe input?\n"); 31569906Siedowse /* Avoid looping if we couldn't ask the user. */ 31669906Siedowse if (yflag || ferror(terminal) || feof(terminal)) 31769906Siedowse done(1); 31869906Siedowse } 3191558Srgrimes if (volno == 1) 3201558Srgrimes return; 321128175Sgreen if (pipecmdin) { 322128175Sgreen closemt(); 323128175Sgreen goto getpipecmdhdr; 324128175Sgreen } 3251558Srgrimes goto gethdr; 3261558Srgrimes } 3271558Srgrimesagain: 3281558Srgrimes if (pipein) 3291558Srgrimes done(1); /* pipes do not get a second chance */ 33090608Siedowse if (command == 'R' || command == 'r' || curfile.action != SKIP) 3311558Srgrimes newvol = nextvol; 33290608Siedowse else 3331558Srgrimes newvol = 0; 3341558Srgrimes while (newvol <= 0) { 3351558Srgrimes if (tapesread == 0) { 33690820Siedowse fprintf(stderr, "%s%s%s%s%s%s%s", 3371558Srgrimes "You have not read any tapes yet.\n", 33890820Siedowse "If you are extracting just a few files,", 33990820Siedowse " start with the last volume\n", 34090820Siedowse "and work towards the first; restore", 34190820Siedowse " can quickly skip tapes that\n", 34290820Siedowse "have no further files to extract.", 34390820Siedowse " Otherwise, begin with volume 1.\n"); 3441558Srgrimes } else { 3451558Srgrimes fprintf(stderr, "You have read volumes"); 3461558Srgrimes strcpy(buf, ": "); 34790820Siedowse for (i = 0; i < 32; i++) 3481558Srgrimes if (tapesread & (1 << i)) { 34990820Siedowse fprintf(stderr, "%s%ld", buf, i + 1); 3501558Srgrimes strcpy(buf, ", "); 3511558Srgrimes } 3521558Srgrimes fprintf(stderr, "\n"); 3531558Srgrimes } 3541558Srgrimes do { 3551558Srgrimes fprintf(stderr, "Specify next volume #: "); 3561558Srgrimes (void) fflush(stderr); 35769906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 35869906Siedowse done(1); 35969906Siedowse } while (buf[0] == '\n'); 3601558Srgrimes newvol = atoi(buf); 3611558Srgrimes if (newvol <= 0) { 3621558Srgrimes fprintf(stderr, 3631558Srgrimes "Volume numbers are positive numerics\n"); 3641558Srgrimes } 3651558Srgrimes } 3661558Srgrimes if (newvol == volno) { 36790820Siedowse tapesread |= 1 << (volno - 1); 3681558Srgrimes return; 3691558Srgrimes } 3701558Srgrimes closemt(); 37137240Sbde fprintf(stderr, "Mount tape volume %ld\n", newvol); 3721558Srgrimes fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 3731558Srgrimes fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 3741558Srgrimes (void) fflush(stderr); 37569906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 3761558Srgrimes done(1); 3771558Srgrimes if (!strcmp(buf, "none\n")) { 3781558Srgrimes terminateinput(); 3791558Srgrimes return; 3801558Srgrimes } 3811558Srgrimes if (buf[0] != '\n') { 3821558Srgrimes (void) strcpy(magtape, buf); 3831558Srgrimes magtape[strlen(magtape) - 1] = '\0'; 3841558Srgrimes } 385128175Sgreen if (pipecmdin) { 386128175Sgreen char volno[sizeof("2147483647")]; 387128175Sgreen 388128175Sgreengetpipecmdhdr: 389128175Sgreen (void)sprintf(volno, "%d", newvol); 390128175Sgreen if (setenv("RESTORE_VOLUME", volno, 1) == -1) { 391128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 392128175Sgreen strerror(errno)); 393128175Sgreen done(1); 394128175Sgreen } 395128175Sgreen popenfp = popen(magtape, "r"); 396128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 397128175Sgreen } else 3981558Srgrimes#ifdef RRESTORE 3991558Srgrimes if (host) 4001558Srgrimes mt = rmtopen(magtape, 0); 4011558Srgrimes else 4021558Srgrimes#endif 4031558Srgrimes mt = open(magtape, O_RDONLY, 0); 4041558Srgrimes 4051558Srgrimes if (mt == -1) { 4061558Srgrimes fprintf(stderr, "Cannot open %s\n", magtape); 4071558Srgrimes volno = -1; 4081558Srgrimes goto again; 4091558Srgrimes } 4101558Srgrimesgethdr: 4111558Srgrimes volno = newvol; 4121558Srgrimes setdumpnum(); 4131558Srgrimes FLUSHTAPEBUF(); 4141558Srgrimes if (gethead(&tmpbuf) == FAIL) { 41537240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 4161558Srgrimes fprintf(stderr, "tape is not dump tape\n"); 4171558Srgrimes volno = 0; 4181558Srgrimes goto again; 4191558Srgrimes } 4201558Srgrimes if (tmpbuf.c_volume != volno) { 42137240Sbde fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume); 4221558Srgrimes volno = 0; 4231558Srgrimes goto again; 4241558Srgrimes } 42598542Smckusick if (_time64_to_time(tmpbuf.c_date) != dumpdate || 42698542Smckusick _time64_to_time(tmpbuf.c_ddate) != dumptime) { 42798542Smckusick time_t t = _time64_to_time(tmpbuf.c_date); 42885635Sdillon fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t)); 4291558Srgrimes fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 4301558Srgrimes volno = 0; 4311558Srgrimes goto again; 4321558Srgrimes } 43390820Siedowse tapesread |= 1 << (volno - 1); 4341558Srgrimes blksread = savecnt; 4351558Srgrimes /* 4361558Srgrimes * If continuing from the previous volume, skip over any 4371558Srgrimes * blocks read already at the end of the previous volume. 4381558Srgrimes * 4391558Srgrimes * If coming to this volume at random, skip to the beginning 4401558Srgrimes * of the next record. 4411558Srgrimes */ 44298542Smckusick dprintf(stdout, "last rec %qd, tape starts with %qd\n", prevtapea, 44390827Siedowse tmpbuf.c_tapea); 44498542Smckusick if (tmpbuf.c_type == TS_TAPE) { 44590608Siedowse if (curfile.action != USING) { 44690608Siedowse /* 44790608Siedowse * XXX Dump incorrectly sets c_count to 1 in the 44890608Siedowse * volume header of the first tape, so ignore 44990608Siedowse * c_count when volno == 1. 45090608Siedowse */ 45190608Siedowse if (volno != 1) 45290608Siedowse for (i = tmpbuf.c_count; i > 0; i--) 45390608Siedowse readtape(buf); 45490827Siedowse } else if (tmpbuf.c_tapea <= prevtapea) { 4551558Srgrimes /* 45690827Siedowse * Normally the value of c_tapea in the volume 45790827Siedowse * header is the record number of the header itself. 45890827Siedowse * However in the volume header following an EOT- 45990827Siedowse * terminated tape, it is the record number of the 46090827Siedowse * first continuation data block (dump bug?). 46190827Siedowse * 46290827Siedowse * The next record we want is `prevtapea + 1'. 4631558Srgrimes */ 46490827Siedowse i = prevtapea + 1 - tmpbuf.c_tapea; 46537240Sbde dprintf(stderr, "Skipping %ld duplicate record%s.\n", 4661558Srgrimes i, i > 1 ? "s" : ""); 4671558Srgrimes while (--i >= 0) 4681558Srgrimes readtape(buf); 4691558Srgrimes } 4701558Srgrimes } 47190608Siedowse if (curfile.action == USING) { 4721558Srgrimes if (volno == 1) 4731558Srgrimes panic("active file into volume 1\n"); 4741558Srgrimes return; 4751558Srgrimes } 4761558Srgrimes (void) gethead(&spcl); 4771558Srgrimes findinode(&spcl); 4781558Srgrimes if (gettingfile) { 4791558Srgrimes gettingfile = 0; 4801558Srgrimes longjmp(restart, 1); 4811558Srgrimes } 4821558Srgrimes} 4831558Srgrimes 4841558Srgrimes/* 4851558Srgrimes * Handle unexpected EOF. 4861558Srgrimes */ 4871558Srgrimesstatic void 48892837Simpterminateinput(void) 4891558Srgrimes{ 4901558Srgrimes 4911558Srgrimes if (gettingfile && curfile.action == USING) { 4921558Srgrimes printf("Warning: %s %s\n", 4931558Srgrimes "End-of-input encountered while extracting", curfile.name); 4941558Srgrimes } 4951558Srgrimes curfile.name = "<name unknown>"; 4961558Srgrimes curfile.action = UNKNOWN; 49798542Smckusick curfile.mode = 0; 4981558Srgrimes curfile.ino = maxino; 4991558Srgrimes if (gettingfile) { 5001558Srgrimes gettingfile = 0; 5011558Srgrimes longjmp(restart, 1); 5021558Srgrimes } 5031558Srgrimes} 5041558Srgrimes 5051558Srgrimes/* 5061558Srgrimes * handle multiple dumps per tape by skipping forward to the 5071558Srgrimes * appropriate one. 5081558Srgrimes */ 5091558Srgrimesstatic void 51092837Simpsetdumpnum(void) 5111558Srgrimes{ 5121558Srgrimes struct mtop tcom; 5131558Srgrimes 5141558Srgrimes if (dumpnum == 1 || volno != 1) 5151558Srgrimes return; 5161558Srgrimes if (pipein) { 5171558Srgrimes fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 5181558Srgrimes done(1); 5191558Srgrimes } 5201558Srgrimes tcom.mt_op = MTFSF; 5211558Srgrimes tcom.mt_count = dumpnum - 1; 5221558Srgrimes#ifdef RRESTORE 5231558Srgrimes if (host) 5241558Srgrimes rmtioctl(MTFSF, dumpnum - 1); 5258871Srgrimes else 5261558Srgrimes#endif 527128175Sgreen if (!pipecmdin && ioctl(mt, MTIOCTOP, (char *)&tcom) < 0) 5281558Srgrimes fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 5291558Srgrimes} 5301558Srgrimes 5311558Srgrimesvoid 53292837Simpprintdumpinfo(void) 5331558Srgrimes{ 53485635Sdillon time_t t; 53598542Smckusick t = _time64_to_time(spcl.c_date); 53685635Sdillon fprintf(stdout, "Dump date: %s", ctime(&t)); 53798542Smckusick t = _time64_to_time(spcl.c_ddate); 5381558Srgrimes fprintf(stdout, "Dumped from: %s", 53985635Sdillon (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t)); 5401558Srgrimes if (spcl.c_host[0] == '\0') 5411558Srgrimes return; 54237240Sbde fprintf(stderr, "Level %ld dump of %s on %s:%s\n", 5431558Srgrimes spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 5441558Srgrimes fprintf(stderr, "Label: %s\n", spcl.c_label); 5451558Srgrimes} 5461558Srgrimes 5471558Srgrimesint 54892837Simpextractfile(char *name) 5491558Srgrimes{ 55023685Speter int flags; 55123685Speter mode_t mode; 552100207Smckusick struct timeval mtimep[2], ctimep[2]; 5531558Srgrimes struct entry *ep; 5541558Srgrimes 5551558Srgrimes curfile.name = name; 5561558Srgrimes curfile.action = USING; 557100207Smckusick mtimep[0].tv_sec = curfile.atime_sec; 558100207Smckusick mtimep[0].tv_usec = curfile.atime_nsec / 1000; 559100207Smckusick mtimep[1].tv_sec = curfile.mtime_sec; 560100207Smckusick mtimep[1].tv_usec = curfile.mtime_nsec / 1000; 561100207Smckusick ctimep[0].tv_sec = curfile.atime_sec; 562100207Smckusick ctimep[0].tv_usec = curfile.atime_nsec / 1000; 563100207Smckusick ctimep[1].tv_sec = curfile.birthtime_sec; 564100207Smckusick ctimep[1].tv_usec = curfile.birthtime_nsec / 1000; 56598542Smckusick mode = curfile.mode; 56698542Smckusick flags = curfile.file_flags; 5671558Srgrimes switch (mode & IFMT) { 5681558Srgrimes 5691558Srgrimes default: 5701558Srgrimes fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 5711558Srgrimes skipfile(); 5721558Srgrimes return (FAIL); 5731558Srgrimes 5741558Srgrimes case IFSOCK: 5751558Srgrimes vprintf(stdout, "skipped socket %s\n", name); 5761558Srgrimes skipfile(); 5771558Srgrimes return (GOOD); 5781558Srgrimes 5791558Srgrimes case IFDIR: 5801558Srgrimes if (mflag) { 5811558Srgrimes ep = lookupname(name); 5821558Srgrimes if (ep == NULL || ep->e_flags & EXTRACT) 5831558Srgrimes panic("unextracted directory %s\n", name); 5841558Srgrimes skipfile(); 5851558Srgrimes return (GOOD); 5861558Srgrimes } 5871558Srgrimes vprintf(stdout, "extract file %s\n", name); 5881558Srgrimes return (genliteraldir(name, curfile.ino)); 5891558Srgrimes 5901558Srgrimes case IFLNK: 5911558Srgrimes lnkbuf[0] = '\0'; 5921558Srgrimes pathlen = 0; 5931558Srgrimes getfile(xtrlnkfile, xtrlnkskip); 5941558Srgrimes if (pathlen == 0) { 5951558Srgrimes vprintf(stdout, 5961558Srgrimes "%s: zero length symbolic link (ignored)\n", name); 5971558Srgrimes return (GOOD); 5981558Srgrimes } 59996113Siedowse if (linkit(lnkbuf, name, SYMLINK) == GOOD) { 60098542Smckusick (void) lchown(name, curfile.uid, curfile.gid); 60196113Siedowse (void) lchmod(name, mode); 602100207Smckusick (void) lutimes(name, ctimep); 603100207Smckusick (void) lutimes(name, mtimep); 60496113Siedowse return (GOOD); 60595943Siedowse } 60696113Siedowse return (FAIL); 6071558Srgrimes 6086305Smartin case IFIFO: 60923685Speter vprintf(stdout, "extract fifo %s\n", name); 61023685Speter if (Nflag) { 61123685Speter skipfile(); 61223685Speter return (GOOD); 61323685Speter } 61435852Sjkh if (uflag && !Nflag) 61535852Sjkh (void)unlink(name); 6166305Smartin if (mkfifo(name, mode) < 0) { 61723685Speter fprintf(stderr, "%s: cannot create fifo: %s\n", 61823685Speter name, strerror(errno)); 6196305Smartin skipfile(); 6206305Smartin return (FAIL); 6216305Smartin } 62298542Smckusick (void) chown(name, curfile.uid, curfile.gid); 6236305Smartin (void) chmod(name, mode); 624100207Smckusick (void) utimes(name, ctimep); 625100207Smckusick (void) utimes(name, mtimep); 62623685Speter (void) chflags(name, flags); 6276305Smartin skipfile(); 6286305Smartin return (GOOD); 6296305Smartin 6301558Srgrimes case IFCHR: 6311558Srgrimes case IFBLK: 6321558Srgrimes vprintf(stdout, "extract special file %s\n", name); 6331558Srgrimes if (Nflag) { 6341558Srgrimes skipfile(); 6351558Srgrimes return (GOOD); 6361558Srgrimes } 63735852Sjkh if (uflag) 63835852Sjkh (void)unlink(name); 63998542Smckusick if (mknod(name, mode, (int)curfile.rdev) < 0) { 6401558Srgrimes fprintf(stderr, "%s: cannot create special file: %s\n", 6411558Srgrimes name, strerror(errno)); 6421558Srgrimes skipfile(); 6431558Srgrimes return (FAIL); 6441558Srgrimes } 64598542Smckusick (void) chown(name, curfile.uid, curfile.gid); 6461558Srgrimes (void) chmod(name, mode); 647100207Smckusick (void) utimes(name, ctimep); 648100207Smckusick (void) utimes(name, mtimep); 64923685Speter (void) chflags(name, flags); 6501558Srgrimes skipfile(); 6511558Srgrimes return (GOOD); 6521558Srgrimes 6531558Srgrimes case IFREG: 6541558Srgrimes vprintf(stdout, "extract file %s\n", name); 6551558Srgrimes if (Nflag) { 6561558Srgrimes skipfile(); 6571558Srgrimes return (GOOD); 6581558Srgrimes } 65935852Sjkh if (uflag) 66035852Sjkh (void)unlink(name); 66121149Simp if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 66221149Simp 0666)) < 0) { 6631558Srgrimes fprintf(stderr, "%s: cannot create file: %s\n", 6641558Srgrimes name, strerror(errno)); 6651558Srgrimes skipfile(); 6661558Srgrimes return (FAIL); 6671558Srgrimes } 66898542Smckusick (void) fchown(ofile, curfile.uid, curfile.gid); 6691558Srgrimes (void) fchmod(ofile, mode); 6701558Srgrimes getfile(xtrfile, xtrskip); 6711558Srgrimes (void) close(ofile); 672100207Smckusick (void) utimes(name, ctimep); 673100207Smckusick (void) utimes(name, mtimep); 67463283Sdwmalone (void) chflags(name, flags); 6751558Srgrimes return (GOOD); 6761558Srgrimes } 6771558Srgrimes /* NOTREACHED */ 6781558Srgrimes} 6791558Srgrimes 6801558Srgrimes/* 6811558Srgrimes * skip over bit maps on the tape 6821558Srgrimes */ 6831558Srgrimesvoid 68492837Simpskipmaps(void) 6851558Srgrimes{ 6861558Srgrimes 6871558Srgrimes while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 6881558Srgrimes skipfile(); 6891558Srgrimes} 6901558Srgrimes 6911558Srgrimes/* 6921558Srgrimes * skip over a file on the tape 6931558Srgrimes */ 6941558Srgrimesvoid 69592837Simpskipfile(void) 6961558Srgrimes{ 6971558Srgrimes 6981558Srgrimes curfile.action = SKIP; 6991558Srgrimes getfile(xtrnull, xtrnull); 7001558Srgrimes} 7011558Srgrimes 7021558Srgrimes/* 7031558Srgrimes * Extract a file from the tape. 7041558Srgrimes * When an allocated block is found it is passed to the fill function; 7051558Srgrimes * when an unallocated block (hole) is found, a zeroed buffer is passed 7061558Srgrimes * to the skip function. 7071558Srgrimes */ 7081558Srgrimesvoid 70992837Simpgetfile(void (*fill)(char *, long), void (*skip)(char *, long)) 7101558Srgrimes{ 71192806Sobrien int i; 7121558Srgrimes int curblk = 0; 71398542Smckusick quad_t size = spcl.c_size; 7141558Srgrimes static char clearedbuf[MAXBSIZE]; 7151558Srgrimes char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 7161558Srgrimes char junk[TP_BSIZE]; 7171558Srgrimes 7181558Srgrimes if (spcl.c_type == TS_END) 7191558Srgrimes panic("ran off end of tape\n"); 72098542Smckusick if (spcl.c_magic != FS_UFS2_MAGIC) 7211558Srgrimes panic("not at beginning of a file\n"); 7221558Srgrimes if (!gettingfile && setjmp(restart) != 0) 7231558Srgrimes return; 7241558Srgrimes gettingfile++; 7251558Srgrimesloop: 7261558Srgrimes for (i = 0; i < spcl.c_count; i++) { 72737923Simp if (readmapflag || spcl.c_addr[i]) { 7281558Srgrimes readtape(&buf[curblk++][0]); 7291558Srgrimes if (curblk == fssize / TP_BSIZE) { 73023685Speter (*fill)((char *)buf, (long)(size > TP_BSIZE ? 73123685Speter fssize : (curblk - 1) * TP_BSIZE + size)); 7321558Srgrimes curblk = 0; 7331558Srgrimes } 7341558Srgrimes } else { 7351558Srgrimes if (curblk > 0) { 73623685Speter (*fill)((char *)buf, (long)(size > TP_BSIZE ? 73723685Speter curblk * TP_BSIZE : 73823685Speter (curblk - 1) * TP_BSIZE + size)); 7391558Srgrimes curblk = 0; 7401558Srgrimes } 74123685Speter (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 74223685Speter TP_BSIZE : size)); 7431558Srgrimes } 7441558Srgrimes if ((size -= TP_BSIZE) <= 0) { 7451558Srgrimes for (i++; i < spcl.c_count; i++) 74637923Simp if (readmapflag || spcl.c_addr[i]) 7471558Srgrimes readtape(junk); 7481558Srgrimes break; 7491558Srgrimes } 7501558Srgrimes } 7511558Srgrimes if (gethead(&spcl) == GOOD && size > 0) { 7521558Srgrimes if (spcl.c_type == TS_ADDR) 7531558Srgrimes goto loop; 7541558Srgrimes dprintf(stdout, 75537240Sbde "Missing address (header) block for %s at %ld blocks\n", 7561558Srgrimes curfile.name, blksread); 7571558Srgrimes } 7581558Srgrimes if (curblk > 0) 75923685Speter (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size)); 7601558Srgrimes findinode(&spcl); 7611558Srgrimes gettingfile = 0; 7621558Srgrimes} 7631558Srgrimes 7641558Srgrimes/* 7651558Srgrimes * Write out the next block of a file. 7661558Srgrimes */ 7671558Srgrimesstatic void 76892837Simpxtrfile(char *buf, long size) 7691558Srgrimes{ 7701558Srgrimes 7711558Srgrimes if (Nflag) 7721558Srgrimes return; 7731558Srgrimes if (write(ofile, buf, (int) size) == -1) { 7741558Srgrimes fprintf(stderr, 7751558Srgrimes "write error extracting inode %d, name %s\nwrite: %s\n", 7761558Srgrimes curfile.ino, curfile.name, strerror(errno)); 7771558Srgrimes } 7781558Srgrimes} 7791558Srgrimes 7801558Srgrimes/* 7811558Srgrimes * Skip over a hole in a file. 7821558Srgrimes */ 7831558Srgrimes/* ARGSUSED */ 7841558Srgrimesstatic void 78592837Simpxtrskip(char *buf, long size) 7861558Srgrimes{ 7871558Srgrimes 7881558Srgrimes if (lseek(ofile, size, SEEK_CUR) == -1) { 7891558Srgrimes fprintf(stderr, 7901558Srgrimes "seek error extracting inode %d, name %s\nlseek: %s\n", 7911558Srgrimes curfile.ino, curfile.name, strerror(errno)); 7921558Srgrimes done(1); 7931558Srgrimes } 7941558Srgrimes} 7951558Srgrimes 7961558Srgrimes/* 7971558Srgrimes * Collect the next block of a symbolic link. 7981558Srgrimes */ 7991558Srgrimesstatic void 80092837Simpxtrlnkfile(char *buf, long size) 8011558Srgrimes{ 8021558Srgrimes 8031558Srgrimes pathlen += size; 8041558Srgrimes if (pathlen > MAXPATHLEN) { 8051558Srgrimes fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 8061558Srgrimes curfile.name, lnkbuf, buf, pathlen); 8071558Srgrimes done(1); 8081558Srgrimes } 8091558Srgrimes (void) strcat(lnkbuf, buf); 8101558Srgrimes} 8111558Srgrimes 8121558Srgrimes/* 8131558Srgrimes * Skip over a hole in a symbolic link (should never happen). 8141558Srgrimes */ 8151558Srgrimes/* ARGSUSED */ 8161558Srgrimesstatic void 81792837Simpxtrlnkskip(char *buf, long size) 8181558Srgrimes{ 8191558Srgrimes 8201558Srgrimes fprintf(stderr, "unallocated block in symbolic link %s\n", 8211558Srgrimes curfile.name); 8221558Srgrimes done(1); 8231558Srgrimes} 8241558Srgrimes 8251558Srgrimes/* 8261558Srgrimes * Collect the next block of a bit map. 8271558Srgrimes */ 8281558Srgrimesstatic void 82992837Simpxtrmap(char *buf, long size) 8301558Srgrimes{ 8311558Srgrimes 83223685Speter memmove(map, buf, size); 8331558Srgrimes map += size; 8341558Srgrimes} 8351558Srgrimes 8361558Srgrimes/* 8371558Srgrimes * Skip over a hole in a bit map (should never happen). 8381558Srgrimes */ 8391558Srgrimes/* ARGSUSED */ 8401558Srgrimesstatic void 84192837Simpxtrmapskip(char *buf, long size) 8421558Srgrimes{ 8431558Srgrimes 8441558Srgrimes panic("hole in map\n"); 8451558Srgrimes map += size; 8461558Srgrimes} 8471558Srgrimes 8481558Srgrimes/* 8491558Srgrimes * Noop, when an extraction function is not needed. 8501558Srgrimes */ 8511558Srgrimes/* ARGSUSED */ 8521558Srgrimesvoid 85392837Simpxtrnull(char *buf, long size) 8541558Srgrimes{ 8551558Srgrimes 8561558Srgrimes return; 8571558Srgrimes} 8581558Srgrimes 8591558Srgrimes/* 8601558Srgrimes * Read TP_BSIZE blocks from the input. 8611558Srgrimes * Handle read errors, and end of media. 8621558Srgrimes */ 8631558Srgrimesstatic void 86492837Simpreadtape(char *buf) 8651558Srgrimes{ 8661558Srgrimes long rd, newvol, i; 8671558Srgrimes int cnt, seek_failed; 8681558Srgrimes 8691558Srgrimes if (blkcnt < numtrec) { 87023685Speter memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 8711558Srgrimes blksread++; 87290827Siedowse tapeaddr++; 8731558Srgrimes return; 8741558Srgrimes } 8751558Srgrimes for (i = 0; i < ntrec; i++) 8761558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 8771558Srgrimes if (numtrec == 0) 8781558Srgrimes numtrec = ntrec; 8791558Srgrimes cnt = ntrec * TP_BSIZE; 8801558Srgrimes rd = 0; 8811558Srgrimesgetmore: 8821558Srgrimes#ifdef RRESTORE 8831558Srgrimes if (host) 8841558Srgrimes i = rmtread(&tapebuf[rd], cnt); 8851558Srgrimes else 8861558Srgrimes#endif 8871558Srgrimes i = read(mt, &tapebuf[rd], cnt); 8881558Srgrimes /* 8891558Srgrimes * Check for mid-tape short read error. 8901558Srgrimes * If found, skip rest of buffer and start with the next. 8911558Srgrimes */ 8921558Srgrimes if (!pipein && numtrec < ntrec && i > 0) { 8931558Srgrimes dprintf(stdout, "mid-media short read error.\n"); 8941558Srgrimes numtrec = ntrec; 8951558Srgrimes } 8961558Srgrimes /* 8971558Srgrimes * Handle partial block read. 8981558Srgrimes */ 8991558Srgrimes if (pipein && i == 0 && rd > 0) 9001558Srgrimes i = rd; 9011558Srgrimes else if (i > 0 && i != ntrec * TP_BSIZE) { 9021558Srgrimes if (pipein) { 9031558Srgrimes rd += i; 9041558Srgrimes cnt -= i; 9051558Srgrimes if (cnt > 0) 9061558Srgrimes goto getmore; 9071558Srgrimes i = rd; 9081558Srgrimes } else { 9091558Srgrimes /* 9101558Srgrimes * Short read. Process the blocks read. 9111558Srgrimes */ 9121558Srgrimes if (i % TP_BSIZE != 0) 9131558Srgrimes vprintf(stdout, 91437240Sbde "partial block read: %ld should be %ld\n", 9151558Srgrimes i, ntrec * TP_BSIZE); 9161558Srgrimes numtrec = i / TP_BSIZE; 9171558Srgrimes } 9181558Srgrimes } 9191558Srgrimes /* 9201558Srgrimes * Handle read error. 9211558Srgrimes */ 9221558Srgrimes if (i < 0) { 9231558Srgrimes fprintf(stderr, "Tape read error while "); 9241558Srgrimes switch (curfile.action) { 9251558Srgrimes default: 9261558Srgrimes fprintf(stderr, "trying to set up tape\n"); 9271558Srgrimes break; 9281558Srgrimes case UNKNOWN: 9291558Srgrimes fprintf(stderr, "trying to resynchronize\n"); 9301558Srgrimes break; 9311558Srgrimes case USING: 9321558Srgrimes fprintf(stderr, "restoring %s\n", curfile.name); 9331558Srgrimes break; 9341558Srgrimes case SKIP: 9351558Srgrimes fprintf(stderr, "skipping over inode %d\n", 9361558Srgrimes curfile.ino); 9371558Srgrimes break; 9381558Srgrimes } 9391558Srgrimes if (!yflag && !reply("continue")) 9401558Srgrimes done(1); 9411558Srgrimes i = ntrec * TP_BSIZE; 94223685Speter memset(tapebuf, 0, i); 9431558Srgrimes#ifdef RRESTORE 9441558Srgrimes if (host) 9451558Srgrimes seek_failed = (rmtseek(i, 1) < 0); 9461558Srgrimes else 9471558Srgrimes#endif 9481558Srgrimes seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 9491558Srgrimes 9501558Srgrimes if (seek_failed) { 9511558Srgrimes fprintf(stderr, 9521558Srgrimes "continuation failed: %s\n", strerror(errno)); 9531558Srgrimes done(1); 9541558Srgrimes } 9551558Srgrimes } 9561558Srgrimes /* 9571558Srgrimes * Handle end of tape. 9581558Srgrimes */ 9591558Srgrimes if (i == 0) { 9601558Srgrimes vprintf(stdout, "End-of-tape encountered\n"); 9611558Srgrimes if (!pipein) { 9621558Srgrimes newvol = volno + 1; 9631558Srgrimes volno = 0; 9641558Srgrimes numtrec = 0; 9651558Srgrimes getvol(newvol); 9661558Srgrimes readtape(buf); 9671558Srgrimes return; 9681558Srgrimes } 9691558Srgrimes if (rd % TP_BSIZE != 0) 9701558Srgrimes panic("partial block read: %d should be %d\n", 9711558Srgrimes rd, ntrec * TP_BSIZE); 9721558Srgrimes terminateinput(); 97323685Speter memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 9741558Srgrimes } 9751558Srgrimes blkcnt = 0; 97623685Speter memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 9771558Srgrimes blksread++; 97890827Siedowse tapeaddr++; 9791558Srgrimes} 9801558Srgrimes 9811558Srgrimesstatic void 98292837Simpfindtapeblksize(void) 9831558Srgrimes{ 98492806Sobrien long i; 9851558Srgrimes 9861558Srgrimes for (i = 0; i < ntrec; i++) 9871558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 9881558Srgrimes blkcnt = 0; 9891558Srgrimes#ifdef RRESTORE 9901558Srgrimes if (host) 9911558Srgrimes i = rmtread(tapebuf, ntrec * TP_BSIZE); 9921558Srgrimes else 9931558Srgrimes#endif 9941558Srgrimes i = read(mt, tapebuf, ntrec * TP_BSIZE); 9951558Srgrimes 9961558Srgrimes if (i <= 0) { 9971558Srgrimes fprintf(stderr, "tape read error: %s\n", strerror(errno)); 9981558Srgrimes done(1); 9991558Srgrimes } 10001558Srgrimes if (i % TP_BSIZE != 0) { 100137240Sbde fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 10021558Srgrimes i, "is not a multiple of dump block size", TP_BSIZE); 10031558Srgrimes done(1); 10041558Srgrimes } 10051558Srgrimes ntrec = i / TP_BSIZE; 10061558Srgrimes numtrec = ntrec; 100737240Sbde vprintf(stdout, "Tape block size is %ld\n", ntrec); 10081558Srgrimes} 10091558Srgrimes 10101558Srgrimesvoid 101192837Simpclosemt(void) 10121558Srgrimes{ 10131558Srgrimes 10141558Srgrimes if (mt < 0) 10151558Srgrimes return; 1016128175Sgreen if (pipecmdin) { 1017128175Sgreen pclose(popenfp); 1018128175Sgreen popenfp = NULL; 1019128175Sgreen } else 10201558Srgrimes#ifdef RRESTORE 10211558Srgrimes if (host) 10221558Srgrimes rmtclose(); 10231558Srgrimes else 10241558Srgrimes#endif 10251558Srgrimes (void) close(mt); 10261558Srgrimes} 10271558Srgrimes 10281558Srgrimes/* 10291558Srgrimes * Read the next block from the tape. 10301558Srgrimes * If it is not any valid header, return an error. 10311558Srgrimes */ 10321558Srgrimesstatic int 103392837Simpgethead(struct s_spcl *buf) 10341558Srgrimes{ 10351558Srgrimes long i; 10361558Srgrimes 103798542Smckusick readtape((char *)buf); 103898542Smckusick if (buf->c_magic != FS_UFS2_MAGIC && buf->c_magic != NFS_MAGIC) { 103998542Smckusick if (buf->c_magic == OFS_MAGIC) { 104098542Smckusick fprintf(stderr, 104198542Smckusick "Format of dump tape is too old. Must use\n"); 104298542Smckusick fprintf(stderr, 104398542Smckusick "a version of restore from before 2002.\n"); 104498542Smckusick return (FAIL); 104598542Smckusick } 104698542Smckusick if (swabl(buf->c_magic) != FS_UFS2_MAGIC && 104798542Smckusick buf->c_magic != NFS_MAGIC) { 104898542Smckusick if (buf->c_magic == OFS_MAGIC) { 104998542Smckusick fprintf(stderr, 105098542Smckusick "Format of dump tape is too old. Must use\n"); 105198542Smckusick fprintf(stderr, 105298542Smckusick "a version of restore from before 2002.\n"); 10531558Srgrimes } 10541558Srgrimes return (FAIL); 105523096Simp } 105698542Smckusick if (!Bcvt) { 105798542Smckusick vprintf(stdout, "Note: Doing Byte swapping\n"); 105898542Smckusick Bcvt = 1; 10591558Srgrimes } 10601558Srgrimes } 106198542Smckusick if (checksum((int *)buf) == FAIL) 106298542Smckusick return (FAIL); 106398542Smckusick if (Bcvt) { 106498542Smckusick swabst((u_char *)"8l4s1q8l2q17l", (u_char *)buf); 106598542Smckusick swabst((u_char *)"l",(u_char *) &buf->c_level); 106698542Smckusick swabst((u_char *)"2l4q",(u_char *) &buf->c_flags); 10671558Srgrimes } 106837923Simp readmapflag = 0; 10691558Srgrimes 10701558Srgrimes switch (buf->c_type) { 10711558Srgrimes 10721558Srgrimes case TS_CLRI: 10731558Srgrimes case TS_BITS: 10741558Srgrimes /* 10751558Srgrimes * Have to patch up missing information in bit map headers 10761558Srgrimes */ 10771558Srgrimes buf->c_inumber = 0; 107898542Smckusick buf->c_size = buf->c_count * TP_BSIZE; 107937923Simp if (buf->c_count > TP_NINDIR) 108037923Simp readmapflag = 1; 108137923Simp else 108237923Simp for (i = 0; i < buf->c_count; i++) 108337923Simp buf->c_addr[i]++; 10841558Srgrimes break; 10851558Srgrimes 10861558Srgrimes case TS_TAPE: 10871558Srgrimes case TS_END: 10881558Srgrimes buf->c_inumber = 0; 10891558Srgrimes break; 10901558Srgrimes 10911558Srgrimes case TS_INODE: 109298542Smckusick /* 109398542Smckusick * For old dump tapes, have to copy up old fields to 109498542Smckusick * new locations. 109598542Smckusick */ 109698542Smckusick if (buf->c_magic == NFS_MAGIC) { 109798542Smckusick buf->c_tapea = buf->c_old_tapea; 109898542Smckusick buf->c_firstrec = buf->c_old_firstrec; 109998542Smckusick buf->c_date = _time32_to_time(buf->c_old_date); 110098542Smckusick buf->c_ddate = _time32_to_time(buf->c_old_ddate); 110198542Smckusick buf->c_atime = _time32_to_time(buf->c_old_atime); 110298542Smckusick buf->c_mtime = _time32_to_time(buf->c_old_mtime); 110398542Smckusick } 110498542Smckusick break; 110598542Smckusick 11061558Srgrimes case TS_ADDR: 11071558Srgrimes break; 11081558Srgrimes 11091558Srgrimes default: 11101558Srgrimes panic("gethead: unknown inode type %d\n", buf->c_type); 11111558Srgrimes break; 11121558Srgrimes } 111398542Smckusick buf->c_magic = FS_UFS2_MAGIC; 111490827Siedowse tapeaddr = buf->c_tapea; 11151558Srgrimes if (dflag) 11161558Srgrimes accthdr(buf); 11171558Srgrimes return(GOOD); 11181558Srgrimes} 11191558Srgrimes 11201558Srgrimes/* 11211558Srgrimes * Check that a header is where it belongs and predict the next header 11221558Srgrimes */ 11231558Srgrimesstatic void 112492837Simpaccthdr(struct s_spcl *header) 11251558Srgrimes{ 11261558Srgrimes static ino_t previno = 0x7fffffff; 11271558Srgrimes static int prevtype; 11281558Srgrimes static long predict; 11291558Srgrimes long blks, i; 11301558Srgrimes 11311558Srgrimes if (header->c_type == TS_TAPE) { 113298542Smckusick fprintf(stderr, "Volume header "); 11331558Srgrimes if (header->c_firstrec) 113498542Smckusick fprintf(stderr, "begins with record %qd", 11351558Srgrimes header->c_firstrec); 11361558Srgrimes fprintf(stderr, "\n"); 11371558Srgrimes previno = 0x7fffffff; 11381558Srgrimes return; 11391558Srgrimes } 11401558Srgrimes if (previno == 0x7fffffff) 11411558Srgrimes goto newcalc; 11421558Srgrimes switch (prevtype) { 11431558Srgrimes case TS_BITS: 114423685Speter fprintf(stderr, "Dumped inodes map header"); 11451558Srgrimes break; 11461558Srgrimes case TS_CLRI: 114723685Speter fprintf(stderr, "Used inodes map header"); 11481558Srgrimes break; 11491558Srgrimes case TS_INODE: 11501558Srgrimes fprintf(stderr, "File header, ino %d", previno); 11511558Srgrimes break; 11521558Srgrimes case TS_ADDR: 11531558Srgrimes fprintf(stderr, "File continuation header, ino %d", previno); 11541558Srgrimes break; 11551558Srgrimes case TS_END: 11561558Srgrimes fprintf(stderr, "End of tape header"); 11571558Srgrimes break; 11581558Srgrimes } 11591558Srgrimes if (predict != blksread - 1) 116037240Sbde fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 11611558Srgrimes predict, blksread - 1); 11621558Srgrimes fprintf(stderr, "\n"); 11631558Srgrimesnewcalc: 11641558Srgrimes blks = 0; 11651558Srgrimes if (header->c_type != TS_END) 11661558Srgrimes for (i = 0; i < header->c_count; i++) 116737923Simp if (readmapflag || header->c_addr[i] != 0) 11681558Srgrimes blks++; 11691558Srgrimes predict = blks; 11701558Srgrimes blksread = 0; 11711558Srgrimes prevtype = header->c_type; 11721558Srgrimes previno = header->c_inumber; 11731558Srgrimes} 11741558Srgrimes 11751558Srgrimes/* 11761558Srgrimes * Find an inode header. 117790573Siedowse * Complain if had to skip. 11781558Srgrimes */ 11791558Srgrimesstatic void 118092837Simpfindinode(struct s_spcl *header) 11811558Srgrimes{ 11821558Srgrimes static long skipcnt = 0; 11831558Srgrimes long i; 11841558Srgrimes char buf[TP_BSIZE]; 118590608Siedowse int htype; 11861558Srgrimes 11871558Srgrimes curfile.name = "<name unknown>"; 11881558Srgrimes curfile.action = UNKNOWN; 118998542Smckusick curfile.mode = 0; 11901558Srgrimes curfile.ino = 0; 11911558Srgrimes do { 119290608Siedowse htype = header->c_type; 119390608Siedowse switch (htype) { 11941558Srgrimes 11951558Srgrimes case TS_ADDR: 11961558Srgrimes /* 11971558Srgrimes * Skip up to the beginning of the next record 11981558Srgrimes */ 11991558Srgrimes for (i = 0; i < header->c_count; i++) 12001558Srgrimes if (header->c_addr[i]) 12011558Srgrimes readtape(buf); 12021558Srgrimes while (gethead(header) == FAIL || 120398542Smckusick _time64_to_time(header->c_date) != dumpdate) 12041558Srgrimes skipcnt++; 12051558Srgrimes break; 12061558Srgrimes 12071558Srgrimes case TS_INODE: 120898542Smckusick curfile.mode = header->c_mode; 120998542Smckusick curfile.uid = header->c_uid; 121098542Smckusick curfile.gid = header->c_gid; 121198542Smckusick curfile.file_flags = header->c_file_flags; 121298542Smckusick curfile.rdev = header->c_rdev; 121398542Smckusick curfile.atime_sec = header->c_atime; 121498542Smckusick curfile.atime_nsec = header->c_atimensec; 121598542Smckusick curfile.mtime_sec = header->c_mtime; 121698542Smckusick curfile.mtime_nsec = header->c_mtimensec; 1217100207Smckusick curfile.birthtime_sec = header->c_birthtime; 1218100207Smckusick curfile.birthtime_nsec = header->c_birthtimensec; 121998542Smckusick curfile.size = header->c_size; 12201558Srgrimes curfile.ino = header->c_inumber; 12211558Srgrimes break; 12221558Srgrimes 12231558Srgrimes case TS_END: 122490820Siedowse /* If we missed some tapes, get another volume. */ 122590820Siedowse if (tapesread & (tapesread + 1)) { 122690820Siedowse getvol(0); 122790820Siedowse continue; 122890820Siedowse } 12291558Srgrimes curfile.ino = maxino; 12301558Srgrimes break; 12311558Srgrimes 12321558Srgrimes case TS_CLRI: 12331558Srgrimes curfile.name = "<file removal list>"; 12341558Srgrimes break; 12351558Srgrimes 12361558Srgrimes case TS_BITS: 12371558Srgrimes curfile.name = "<file dump list>"; 12381558Srgrimes break; 12391558Srgrimes 12401558Srgrimes case TS_TAPE: 12411558Srgrimes panic("unexpected tape header\n"); 12421558Srgrimes /* NOTREACHED */ 12431558Srgrimes 12441558Srgrimes default: 12451558Srgrimes panic("unknown tape header type %d\n", spcl.c_type); 12461558Srgrimes /* NOTREACHED */ 12471558Srgrimes 12481558Srgrimes } 124990608Siedowse } while (htype == TS_ADDR); 12501558Srgrimes if (skipcnt > 0) 125137240Sbde fprintf(stderr, "resync restore, skipped %ld blocks\n", 125237240Sbde skipcnt); 12531558Srgrimes skipcnt = 0; 12541558Srgrimes} 12551558Srgrimes 12561558Srgrimesstatic int 125792837Simpchecksum(int *buf) 12581558Srgrimes{ 125992806Sobrien int i, j; 12601558Srgrimes 12611558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 12621558Srgrimes i = 0; 126398542Smckusick if (!Bcvt) { 12641558Srgrimes do 12651558Srgrimes i += *buf++; 12661558Srgrimes while (--j); 12671558Srgrimes } else { 12681558Srgrimes /* What happens if we want to read restore tapes 12691558Srgrimes for a 16bit int machine??? */ 12708871Srgrimes do 12711558Srgrimes i += swabl(*buf++); 12721558Srgrimes while (--j); 12731558Srgrimes } 12748871Srgrimes 12751558Srgrimes if (i != CHECKSUM) { 12761558Srgrimes fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 12771558Srgrimes curfile.ino, curfile.name); 12781558Srgrimes return(FAIL); 12791558Srgrimes } 12801558Srgrimes return(GOOD); 12811558Srgrimes} 12821558Srgrimes 12831558Srgrimes#ifdef RRESTORE 12841558Srgrimes#include <stdarg.h> 12851558Srgrimes 12861558Srgrimesvoid 12871558Srgrimesmsg(const char *fmt, ...) 12881558Srgrimes{ 12891558Srgrimes va_list ap; 12901558Srgrimes va_start(ap, fmt); 12911558Srgrimes (void)vfprintf(stderr, fmt, ap); 12921558Srgrimes va_end(ap); 12931558Srgrimes} 12941558Srgrimes#endif /* RRESTORE */ 12951558Srgrimes 12961558Srgrimesstatic u_char * 129792837Simpswabshort(u_char *sp, int n) 12981558Srgrimes{ 12991558Srgrimes char c; 13001558Srgrimes 13011558Srgrimes while (--n >= 0) { 13021558Srgrimes c = sp[0]; sp[0] = sp[1]; sp[1] = c; 13031558Srgrimes sp += 2; 13041558Srgrimes } 13051558Srgrimes return (sp); 13061558Srgrimes} 13071558Srgrimes 13081558Srgrimesstatic u_char * 130992837Simpswablong(u_char *sp, int n) 13101558Srgrimes{ 13111558Srgrimes char c; 13121558Srgrimes 13131558Srgrimes while (--n >= 0) { 13141558Srgrimes c = sp[0]; sp[0] = sp[3]; sp[3] = c; 13151558Srgrimes c = sp[2]; sp[2] = sp[1]; sp[1] = c; 13161558Srgrimes sp += 4; 13171558Srgrimes } 13181558Srgrimes return (sp); 13191558Srgrimes} 13201558Srgrimes 132198542Smckusickstatic u_char * 132298542Smckusickswabquad(u_char *sp, int n) 132398542Smckusick{ 132498542Smckusick char c; 132598542Smckusick 132698542Smckusick while (--n >= 0) { 132798542Smckusick c = sp[0]; sp[0] = sp[7]; sp[7] = c; 132898542Smckusick c = sp[1]; sp[1] = sp[6]; sp[6] = c; 132998542Smckusick c = sp[2]; sp[2] = sp[5]; sp[5] = c; 133098542Smckusick c = sp[3]; sp[3] = sp[4]; sp[4] = c; 133198542Smckusick sp += 8; 133298542Smckusick } 133398542Smckusick return (sp); 133498542Smckusick} 133598542Smckusick 13361558Srgrimesvoid 133792837Simpswabst(u_char *cp, u_char *sp) 13381558Srgrimes{ 13391558Srgrimes int n = 0; 13401558Srgrimes 13411558Srgrimes while (*cp) { 13421558Srgrimes switch (*cp) { 13431558Srgrimes case '0': case '1': case '2': case '3': case '4': 13441558Srgrimes case '5': case '6': case '7': case '8': case '9': 13451558Srgrimes n = (n * 10) + (*cp++ - '0'); 13461558Srgrimes continue; 13478871Srgrimes 13481558Srgrimes case 's': case 'w': case 'h': 13491558Srgrimes if (n == 0) 13501558Srgrimes n = 1; 13511558Srgrimes sp = swabshort(sp, n); 13521558Srgrimes break; 13531558Srgrimes 13541558Srgrimes case 'l': 13551558Srgrimes if (n == 0) 13561558Srgrimes n = 1; 13571558Srgrimes sp = swablong(sp, n); 13581558Srgrimes break; 13591558Srgrimes 136098542Smckusick case 'q': 13611558Srgrimes if (n == 0) 13621558Srgrimes n = 1; 136398542Smckusick sp = swabquad(sp, n); 136498542Smckusick break; 136598542Smckusick 136698542Smckusick case 'b': 136798542Smckusick if (n == 0) 136898542Smckusick n = 1; 13691558Srgrimes sp += n; 13701558Srgrimes break; 137198542Smckusick 137298542Smckusick default: 137398542Smckusick fprintf(stderr, "Unknown conversion character: %c\n", 137498542Smckusick *cp); 137598542Smckusick done(0); 137698542Smckusick break; 13771558Srgrimes } 13781558Srgrimes cp++; 13791558Srgrimes n = 0; 13801558Srgrimes } 13811558Srgrimes} 13821558Srgrimes 13831558Srgrimesstatic u_long 138492837Simpswabl(u_long x) 13851558Srgrimes{ 13861558Srgrimes swabst((u_char *)"l", (u_char *)&x); 13871558Srgrimes return (x); 13881558Srgrimes} 1389