tape.c revision 146754
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 391558Srgrimes#endif /* not lint */ 401558Srgrimes 41146754Scharnier#include <sys/cdefs.h> 42146754Scharnier__FBSDID("$FreeBSD: head/sbin/restore/tape.c 146754 2005-05-29 15:57:00Z charnier $"); 43146754Scharnier 441558Srgrimes#include <sys/param.h> 451558Srgrimes#include <sys/file.h> 461558Srgrimes#include <sys/mtio.h> 471558Srgrimes#include <sys/stat.h> 4866907Swollman#include <sys/time.h> 491558Srgrimes 501558Srgrimes#include <ufs/ufs/dinode.h> 511558Srgrimes#include <protocols/dumprestore.h> 521558Srgrimes 531558Srgrimes#include <errno.h> 54103949Smike#include <limits.h> 5573986Sobrien#include <paths.h> 561558Srgrimes#include <setjmp.h> 571558Srgrimes#include <stdio.h> 581558Srgrimes#include <stdlib.h> 591558Srgrimes#include <string.h> 6066907Swollman#include <time.h> 61129665Sstefanf#include <timeconv.h> 621558Srgrimes#include <unistd.h> 631558Srgrimes 641558Srgrimes#include "restore.h" 651558Srgrimes#include "extern.h" 661558Srgrimes 671558Srgrimesstatic long fssize = MAXBSIZE; 681558Srgrimesstatic int mt = -1; 691558Srgrimesstatic int pipein = 0; 70128175Sgreenstatic int pipecmdin = 0; 71128175Sgreenstatic FILE *popenfp = NULL; 7221174Sguidostatic char *magtape; 731558Srgrimesstatic int blkcnt; 741558Srgrimesstatic int numtrec; 751558Srgrimesstatic char *tapebuf; 761558Srgrimesstatic union u_spcl endoftapemark; 771558Srgrimesstatic long blksread; /* blocks read since last header */ 7898542Smckusickstatic int64_t tapeaddr = 0; /* current TP_BSIZE tape record */ 791558Srgrimesstatic long tapesread; 801558Srgrimesstatic jmp_buf restart; 811558Srgrimesstatic int gettingfile = 0; /* restart has a valid frame */ 821558Srgrimesstatic char *host = NULL; 8398542Smckusickstatic int readmapflag; 841558Srgrimes 851558Srgrimesstatic int ofile; 861558Srgrimesstatic char *map; 871558Srgrimesstatic char lnkbuf[MAXPATHLEN + 1]; 881558Srgrimesstatic int pathlen; 891558Srgrimes 9098542Smckusickint Bcvt; /* Swap Bytes */ 91144099Simpint oldinofmt; /* FreeBSD 1 inode format needs cvt */ 921558Srgrimes 931558Srgrimes#define FLUSHTAPEBUF() blkcnt = ntrec + 1 941558Srgrimes 9592837Simpstatic void accthdr(struct s_spcl *); 9692837Simpstatic int checksum(int *); 9792837Simpstatic void findinode(struct s_spcl *); 9892837Simpstatic void findtapeblksize(void); 9992837Simpstatic int gethead(struct s_spcl *); 10092837Simpstatic void readtape(char *); 10192837Simpstatic void setdumpnum(void); 10292837Simpstatic u_long swabl(u_long); 10392837Simpstatic u_char *swablong(u_char *, int); 10492837Simpstatic u_char *swabshort(u_char *, int); 10592837Simpstatic void terminateinput(void); 10692837Simpstatic void xtrfile(char *, long); 10792837Simpstatic void xtrlnkfile(char *, long); 10892837Simpstatic void xtrlnkskip(char *, long); 10992837Simpstatic void xtrmap(char *, long); 11092837Simpstatic void xtrmapskip(char *, long); 11192837Simpstatic void xtrskip(char *, long); 1121558Srgrimes 1131558Srgrimes/* 1141558Srgrimes * Set up an input source 1151558Srgrimes */ 1161558Srgrimesvoid 117128175Sgreensetinput(char *source, int ispipecommand) 1181558Srgrimes{ 1191558Srgrimes FLUSHTAPEBUF(); 1201558Srgrimes if (bflag) 1211558Srgrimes newtapebuf(ntrec); 1221558Srgrimes else 1231558Srgrimes newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 1241558Srgrimes terminal = stdin; 1251558Srgrimes 126128175Sgreen if (ispipecommand) 127128175Sgreen pipecmdin++; 128128175Sgreen else 1291558Srgrimes#ifdef RRESTORE 13023685Speter if (strchr(source, ':')) { 1311558Srgrimes host = source; 13223685Speter source = strchr(host, ':'); 1331558Srgrimes *source++ = '\0'; 1341558Srgrimes if (rmthost(host) == 0) 1351558Srgrimes done(1); 1361558Srgrimes } else 1371558Srgrimes#endif 1381558Srgrimes if (strcmp(source, "-") == 0) { 1391558Srgrimes /* 1401558Srgrimes * Since input is coming from a pipe we must establish 1411558Srgrimes * our own connection to the terminal. 1421558Srgrimes */ 1431558Srgrimes terminal = fopen(_PATH_TTY, "r"); 1441558Srgrimes if (terminal == NULL) { 1451558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1461558Srgrimes _PATH_TTY, strerror(errno)); 1471558Srgrimes terminal = fopen(_PATH_DEVNULL, "r"); 1481558Srgrimes if (terminal == NULL) { 1491558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1501558Srgrimes _PATH_DEVNULL, strerror(errno)); 1511558Srgrimes done(1); 1521558Srgrimes } 1531558Srgrimes } 1541558Srgrimes pipein++; 1551558Srgrimes } 1561558Srgrimes setuid(getuid()); /* no longer need or want root privileges */ 15721174Sguido magtape = strdup(source); 15821174Sguido if (magtape == NULL) { 15921174Sguido fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 16021174Sguido done(1); 16121174Sguido } 1621558Srgrimes} 1631558Srgrimes 1641558Srgrimesvoid 16592837Simpnewtapebuf(long size) 1661558Srgrimes{ 16792837Simp static int tapebufsize = -1; 1681558Srgrimes 1691558Srgrimes ntrec = size; 1701558Srgrimes if (size <= tapebufsize) 1711558Srgrimes return; 1721558Srgrimes if (tapebuf != NULL) 1731558Srgrimes free(tapebuf); 1741558Srgrimes tapebuf = malloc(size * TP_BSIZE); 1751558Srgrimes if (tapebuf == NULL) { 1761558Srgrimes fprintf(stderr, "Cannot allocate space for tape buffer\n"); 1771558Srgrimes done(1); 1781558Srgrimes } 1791558Srgrimes tapebufsize = size; 1801558Srgrimes} 1811558Srgrimes 1821558Srgrimes/* 1831558Srgrimes * Verify that the tape drive can be accessed and 1841558Srgrimes * that it actually is a dump tape. 1851558Srgrimes */ 1861558Srgrimesvoid 18792837Simpsetup(void) 1881558Srgrimes{ 1891558Srgrimes int i, j, *ip; 1901558Srgrimes struct stat stbuf; 1911558Srgrimes 1921558Srgrimes vprintf(stdout, "Verify tape and initialize maps\n"); 193128175Sgreen if (pipecmdin) { 194128175Sgreen if (setenv("RESTORE_VOLUME", "1", 1) == -1) { 195128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 196128175Sgreen strerror(errno)); 197128175Sgreen done(1); 198128175Sgreen } 199128175Sgreen popenfp = popen(magtape, "r"); 200128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 201128175Sgreen } else 2021558Srgrimes#ifdef RRESTORE 2031558Srgrimes if (host) 2041558Srgrimes mt = rmtopen(magtape, 0); 2051558Srgrimes else 2061558Srgrimes#endif 2071558Srgrimes if (pipein) 2081558Srgrimes mt = 0; 2091558Srgrimes else 2101558Srgrimes mt = open(magtape, O_RDONLY, 0); 2111558Srgrimes if (mt < 0) { 2121558Srgrimes fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 2131558Srgrimes done(1); 2141558Srgrimes } 2151558Srgrimes volno = 1; 2161558Srgrimes setdumpnum(); 2171558Srgrimes FLUSHTAPEBUF(); 2181558Srgrimes if (!pipein && !bflag) 2191558Srgrimes findtapeblksize(); 2201558Srgrimes if (gethead(&spcl) == FAIL) { 22198542Smckusick fprintf(stderr, "Tape is not a dump tape\n"); 22298542Smckusick done(1); 2231558Srgrimes } 2241558Srgrimes if (pipein) { 22598542Smckusick endoftapemark.s_spcl.c_magic = FS_UFS2_MAGIC; 2261558Srgrimes endoftapemark.s_spcl.c_type = TS_END; 2271558Srgrimes ip = (int *)&endoftapemark; 2281558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 2291558Srgrimes i = 0; 2301558Srgrimes do 2311558Srgrimes i += *ip++; 2321558Srgrimes while (--j); 2331558Srgrimes endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 2341558Srgrimes } 2351558Srgrimes if (vflag || command == 't') 2361558Srgrimes printdumpinfo(); 23798542Smckusick dumptime = _time64_to_time(spcl.c_ddate); 23898542Smckusick dumpdate = _time64_to_time(spcl.c_date); 2391558Srgrimes if (stat(".", &stbuf) < 0) { 2401558Srgrimes fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 2411558Srgrimes done(1); 2421558Srgrimes } 24334851Sjkh if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 24434851Sjkh fssize = TP_BSIZE; 24534851Sjkh if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 2461558Srgrimes fssize = stbuf.st_blksize; 2471558Srgrimes if (((fssize - 1) & fssize) != 0) { 24837240Sbde fprintf(stderr, "bad block size %ld\n", fssize); 2491558Srgrimes done(1); 2501558Srgrimes } 2511558Srgrimes if (spcl.c_volume != 1) { 2521558Srgrimes fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2531558Srgrimes done(1); 2541558Srgrimes } 2551558Srgrimes if (gethead(&spcl) == FAIL) { 25637240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 2571558Srgrimes panic("no header after volume mark!\n"); 2581558Srgrimes } 2591558Srgrimes findinode(&spcl); 2601558Srgrimes if (spcl.c_type != TS_CLRI) { 2611558Srgrimes fprintf(stderr, "Cannot find file removal list\n"); 2621558Srgrimes done(1); 2631558Srgrimes } 2641558Srgrimes maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 2651558Srgrimes dprintf(stdout, "maxino = %d\n", maxino); 2661558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2671558Srgrimes if (map == NULL) 26823685Speter panic("no memory for active inode map\n"); 26923685Speter usedinomap = map; 2701558Srgrimes curfile.action = USING; 2711558Srgrimes getfile(xtrmap, xtrmapskip); 2721558Srgrimes if (spcl.c_type != TS_BITS) { 2731558Srgrimes fprintf(stderr, "Cannot find file dump list\n"); 2741558Srgrimes done(1); 2751558Srgrimes } 2761558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2771558Srgrimes if (map == (char *)NULL) 2781558Srgrimes panic("no memory for file dump list\n"); 2791558Srgrimes dumpmap = map; 2801558Srgrimes curfile.action = USING; 2811558Srgrimes getfile(xtrmap, xtrmapskip); 28223685Speter /* 28323685Speter * If there may be whiteout entries on the tape, pretend that the 28423685Speter * whiteout inode exists, so that the whiteout entries can be 28523685Speter * extracted. 28623685Speter */ 28798542Smckusick SETINO(WINO, dumpmap); 28890820Siedowse /* 'r' restores don't call getvol() for tape 1, so mark it as read. */ 28990820Siedowse if (command == 'r') 29090820Siedowse tapesread = 1; 2911558Srgrimes} 2921558Srgrimes 2931558Srgrimes/* 2941558Srgrimes * Prompt user to load a new dump volume. 2951558Srgrimes * "Nextvol" is the next suggested volume to use. 2961558Srgrimes * This suggested volume is enforced when doing full 29737906Scharnier * or incremental restores, but can be overridden by 2981558Srgrimes * the user when only extracting a subset of the files. 2991558Srgrimes */ 3001558Srgrimesvoid 30192837Simpgetvol(long nextvol) 3021558Srgrimes{ 30398542Smckusick int64_t prevtapea; 30498542Smckusick long i, newvol, savecnt; 3051558Srgrimes union u_spcl tmpspcl; 3061558Srgrimes# define tmpbuf tmpspcl.s_spcl 3071558Srgrimes char buf[TP_BSIZE]; 3081558Srgrimes 3091558Srgrimes if (nextvol == 1) { 3101558Srgrimes tapesread = 0; 3111558Srgrimes gettingfile = 0; 3121558Srgrimes } 31390827Siedowse prevtapea = tapeaddr; 31490827Siedowse savecnt = blksread; 3151558Srgrimes if (pipein) { 31669906Siedowse if (nextvol != 1) { 3171558Srgrimes panic("Changing volumes on pipe input?\n"); 31869906Siedowse /* Avoid looping if we couldn't ask the user. */ 31969906Siedowse if (yflag || ferror(terminal) || feof(terminal)) 32069906Siedowse done(1); 32169906Siedowse } 3221558Srgrimes if (volno == 1) 3231558Srgrimes return; 324128175Sgreen if (pipecmdin) { 325128175Sgreen closemt(); 326128175Sgreen goto getpipecmdhdr; 327128175Sgreen } 3281558Srgrimes goto gethdr; 3291558Srgrimes } 3301558Srgrimesagain: 3311558Srgrimes if (pipein) 3321558Srgrimes done(1); /* pipes do not get a second chance */ 33390608Siedowse if (command == 'R' || command == 'r' || curfile.action != SKIP) 3341558Srgrimes newvol = nextvol; 33590608Siedowse else 3361558Srgrimes newvol = 0; 3371558Srgrimes while (newvol <= 0) { 3381558Srgrimes if (tapesread == 0) { 33990820Siedowse fprintf(stderr, "%s%s%s%s%s%s%s", 3401558Srgrimes "You have not read any tapes yet.\n", 34190820Siedowse "If you are extracting just a few files,", 34290820Siedowse " start with the last volume\n", 34390820Siedowse "and work towards the first; restore", 34490820Siedowse " can quickly skip tapes that\n", 34590820Siedowse "have no further files to extract.", 34690820Siedowse " Otherwise, begin with volume 1.\n"); 3471558Srgrimes } else { 3481558Srgrimes fprintf(stderr, "You have read volumes"); 3491558Srgrimes strcpy(buf, ": "); 35090820Siedowse for (i = 0; i < 32; i++) 3511558Srgrimes if (tapesread & (1 << i)) { 35290820Siedowse fprintf(stderr, "%s%ld", buf, i + 1); 3531558Srgrimes strcpy(buf, ", "); 3541558Srgrimes } 3551558Srgrimes fprintf(stderr, "\n"); 3561558Srgrimes } 3571558Srgrimes do { 3581558Srgrimes fprintf(stderr, "Specify next volume #: "); 3591558Srgrimes (void) fflush(stderr); 36069906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 36169906Siedowse done(1); 36269906Siedowse } while (buf[0] == '\n'); 3631558Srgrimes newvol = atoi(buf); 3641558Srgrimes if (newvol <= 0) { 3651558Srgrimes fprintf(stderr, 3661558Srgrimes "Volume numbers are positive numerics\n"); 3671558Srgrimes } 3681558Srgrimes } 3691558Srgrimes if (newvol == volno) { 37090820Siedowse tapesread |= 1 << (volno - 1); 3711558Srgrimes return; 3721558Srgrimes } 3731558Srgrimes closemt(); 37437240Sbde fprintf(stderr, "Mount tape volume %ld\n", newvol); 3751558Srgrimes fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 3761558Srgrimes fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 3771558Srgrimes (void) fflush(stderr); 37869906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 3791558Srgrimes done(1); 3801558Srgrimes if (!strcmp(buf, "none\n")) { 3811558Srgrimes terminateinput(); 3821558Srgrimes return; 3831558Srgrimes } 3841558Srgrimes if (buf[0] != '\n') { 3851558Srgrimes (void) strcpy(magtape, buf); 3861558Srgrimes magtape[strlen(magtape) - 1] = '\0'; 3871558Srgrimes } 388128175Sgreen if (pipecmdin) { 389128175Sgreen char volno[sizeof("2147483647")]; 390128175Sgreen 391128175Sgreengetpipecmdhdr: 392128175Sgreen (void)sprintf(volno, "%d", newvol); 393128175Sgreen if (setenv("RESTORE_VOLUME", volno, 1) == -1) { 394128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 395128175Sgreen strerror(errno)); 396128175Sgreen done(1); 397128175Sgreen } 398128175Sgreen popenfp = popen(magtape, "r"); 399128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 400128175Sgreen } else 4011558Srgrimes#ifdef RRESTORE 4021558Srgrimes if (host) 4031558Srgrimes mt = rmtopen(magtape, 0); 4041558Srgrimes else 4051558Srgrimes#endif 4061558Srgrimes mt = open(magtape, O_RDONLY, 0); 4071558Srgrimes 4081558Srgrimes if (mt == -1) { 4091558Srgrimes fprintf(stderr, "Cannot open %s\n", magtape); 4101558Srgrimes volno = -1; 4111558Srgrimes goto again; 4121558Srgrimes } 4131558Srgrimesgethdr: 4141558Srgrimes volno = newvol; 4151558Srgrimes setdumpnum(); 4161558Srgrimes FLUSHTAPEBUF(); 4171558Srgrimes if (gethead(&tmpbuf) == FAIL) { 41837240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 4191558Srgrimes fprintf(stderr, "tape is not dump tape\n"); 4201558Srgrimes volno = 0; 4211558Srgrimes goto again; 4221558Srgrimes } 4231558Srgrimes if (tmpbuf.c_volume != volno) { 42437240Sbde fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume); 4251558Srgrimes volno = 0; 4261558Srgrimes goto again; 4271558Srgrimes } 42898542Smckusick if (_time64_to_time(tmpbuf.c_date) != dumpdate || 42998542Smckusick _time64_to_time(tmpbuf.c_ddate) != dumptime) { 43098542Smckusick time_t t = _time64_to_time(tmpbuf.c_date); 43185635Sdillon fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t)); 4321558Srgrimes fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 4331558Srgrimes volno = 0; 4341558Srgrimes goto again; 4351558Srgrimes } 43690820Siedowse tapesread |= 1 << (volno - 1); 4371558Srgrimes blksread = savecnt; 4381558Srgrimes /* 4391558Srgrimes * If continuing from the previous volume, skip over any 4401558Srgrimes * blocks read already at the end of the previous volume. 4411558Srgrimes * 4421558Srgrimes * If coming to this volume at random, skip to the beginning 4431558Srgrimes * of the next record. 4441558Srgrimes */ 44598542Smckusick dprintf(stdout, "last rec %qd, tape starts with %qd\n", prevtapea, 44690827Siedowse tmpbuf.c_tapea); 44798542Smckusick if (tmpbuf.c_type == TS_TAPE) { 44890608Siedowse if (curfile.action != USING) { 44990608Siedowse /* 45090608Siedowse * XXX Dump incorrectly sets c_count to 1 in the 45190608Siedowse * volume header of the first tape, so ignore 45290608Siedowse * c_count when volno == 1. 45390608Siedowse */ 45490608Siedowse if (volno != 1) 45590608Siedowse for (i = tmpbuf.c_count; i > 0; i--) 45690608Siedowse readtape(buf); 45790827Siedowse } else if (tmpbuf.c_tapea <= prevtapea) { 4581558Srgrimes /* 45990827Siedowse * Normally the value of c_tapea in the volume 46090827Siedowse * header is the record number of the header itself. 46190827Siedowse * However in the volume header following an EOT- 46290827Siedowse * terminated tape, it is the record number of the 46390827Siedowse * first continuation data block (dump bug?). 46490827Siedowse * 46590827Siedowse * The next record we want is `prevtapea + 1'. 4661558Srgrimes */ 46790827Siedowse i = prevtapea + 1 - tmpbuf.c_tapea; 46837240Sbde dprintf(stderr, "Skipping %ld duplicate record%s.\n", 4691558Srgrimes i, i > 1 ? "s" : ""); 4701558Srgrimes while (--i >= 0) 4711558Srgrimes readtape(buf); 4721558Srgrimes } 4731558Srgrimes } 47490608Siedowse if (curfile.action == USING) { 4751558Srgrimes if (volno == 1) 4761558Srgrimes panic("active file into volume 1\n"); 4771558Srgrimes return; 4781558Srgrimes } 4791558Srgrimes (void) gethead(&spcl); 4801558Srgrimes findinode(&spcl); 4811558Srgrimes if (gettingfile) { 4821558Srgrimes gettingfile = 0; 4831558Srgrimes longjmp(restart, 1); 4841558Srgrimes } 4851558Srgrimes} 4861558Srgrimes 4871558Srgrimes/* 4881558Srgrimes * Handle unexpected EOF. 4891558Srgrimes */ 4901558Srgrimesstatic void 49192837Simpterminateinput(void) 4921558Srgrimes{ 4931558Srgrimes 4941558Srgrimes if (gettingfile && curfile.action == USING) { 4951558Srgrimes printf("Warning: %s %s\n", 4961558Srgrimes "End-of-input encountered while extracting", curfile.name); 4971558Srgrimes } 4981558Srgrimes curfile.name = "<name unknown>"; 4991558Srgrimes curfile.action = UNKNOWN; 50098542Smckusick curfile.mode = 0; 5011558Srgrimes curfile.ino = maxino; 5021558Srgrimes if (gettingfile) { 5031558Srgrimes gettingfile = 0; 5041558Srgrimes longjmp(restart, 1); 5051558Srgrimes } 5061558Srgrimes} 5071558Srgrimes 5081558Srgrimes/* 5091558Srgrimes * handle multiple dumps per tape by skipping forward to the 5101558Srgrimes * appropriate one. 5111558Srgrimes */ 5121558Srgrimesstatic void 51392837Simpsetdumpnum(void) 5141558Srgrimes{ 5151558Srgrimes struct mtop tcom; 5161558Srgrimes 5171558Srgrimes if (dumpnum == 1 || volno != 1) 5181558Srgrimes return; 5191558Srgrimes if (pipein) { 5201558Srgrimes fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 5211558Srgrimes done(1); 5221558Srgrimes } 5231558Srgrimes tcom.mt_op = MTFSF; 5241558Srgrimes tcom.mt_count = dumpnum - 1; 5251558Srgrimes#ifdef RRESTORE 5261558Srgrimes if (host) 5271558Srgrimes rmtioctl(MTFSF, dumpnum - 1); 5288871Srgrimes else 5291558Srgrimes#endif 530128175Sgreen if (!pipecmdin && ioctl(mt, MTIOCTOP, (char *)&tcom) < 0) 5311558Srgrimes fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 5321558Srgrimes} 5331558Srgrimes 5341558Srgrimesvoid 53592837Simpprintdumpinfo(void) 5361558Srgrimes{ 53785635Sdillon time_t t; 53898542Smckusick t = _time64_to_time(spcl.c_date); 53985635Sdillon fprintf(stdout, "Dump date: %s", ctime(&t)); 54098542Smckusick t = _time64_to_time(spcl.c_ddate); 5411558Srgrimes fprintf(stdout, "Dumped from: %s", 54285635Sdillon (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t)); 5431558Srgrimes if (spcl.c_host[0] == '\0') 5441558Srgrimes return; 54537240Sbde fprintf(stderr, "Level %ld dump of %s on %s:%s\n", 5461558Srgrimes spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 5471558Srgrimes fprintf(stderr, "Label: %s\n", spcl.c_label); 5481558Srgrimes} 5491558Srgrimes 5501558Srgrimesint 55192837Simpextractfile(char *name) 5521558Srgrimes{ 55323685Speter int flags; 55423685Speter mode_t mode; 555100207Smckusick struct timeval mtimep[2], ctimep[2]; 5561558Srgrimes struct entry *ep; 5571558Srgrimes 5581558Srgrimes curfile.name = name; 5591558Srgrimes curfile.action = USING; 560100207Smckusick mtimep[0].tv_sec = curfile.atime_sec; 561100207Smckusick mtimep[0].tv_usec = curfile.atime_nsec / 1000; 562100207Smckusick mtimep[1].tv_sec = curfile.mtime_sec; 563100207Smckusick mtimep[1].tv_usec = curfile.mtime_nsec / 1000; 564100207Smckusick ctimep[0].tv_sec = curfile.atime_sec; 565100207Smckusick ctimep[0].tv_usec = curfile.atime_nsec / 1000; 566100207Smckusick ctimep[1].tv_sec = curfile.birthtime_sec; 567100207Smckusick ctimep[1].tv_usec = curfile.birthtime_nsec / 1000; 56898542Smckusick mode = curfile.mode; 56998542Smckusick flags = curfile.file_flags; 5701558Srgrimes switch (mode & IFMT) { 5711558Srgrimes 5721558Srgrimes default: 5731558Srgrimes fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 5741558Srgrimes skipfile(); 5751558Srgrimes return (FAIL); 5761558Srgrimes 5771558Srgrimes case IFSOCK: 5781558Srgrimes vprintf(stdout, "skipped socket %s\n", name); 5791558Srgrimes skipfile(); 5801558Srgrimes return (GOOD); 5811558Srgrimes 5821558Srgrimes case IFDIR: 5831558Srgrimes if (mflag) { 5841558Srgrimes ep = lookupname(name); 5851558Srgrimes if (ep == NULL || ep->e_flags & EXTRACT) 5861558Srgrimes panic("unextracted directory %s\n", name); 5871558Srgrimes skipfile(); 5881558Srgrimes return (GOOD); 5891558Srgrimes } 5901558Srgrimes vprintf(stdout, "extract file %s\n", name); 5911558Srgrimes return (genliteraldir(name, curfile.ino)); 5921558Srgrimes 5931558Srgrimes case IFLNK: 5941558Srgrimes lnkbuf[0] = '\0'; 5951558Srgrimes pathlen = 0; 5961558Srgrimes getfile(xtrlnkfile, xtrlnkskip); 5971558Srgrimes if (pathlen == 0) { 5981558Srgrimes vprintf(stdout, 5991558Srgrimes "%s: zero length symbolic link (ignored)\n", name); 6001558Srgrimes return (GOOD); 6011558Srgrimes } 60296113Siedowse if (linkit(lnkbuf, name, SYMLINK) == GOOD) { 60398542Smckusick (void) lchown(name, curfile.uid, curfile.gid); 60496113Siedowse (void) lchmod(name, mode); 605100207Smckusick (void) lutimes(name, ctimep); 606100207Smckusick (void) lutimes(name, mtimep); 60796113Siedowse return (GOOD); 60895943Siedowse } 60996113Siedowse return (FAIL); 6101558Srgrimes 6116305Smartin case IFIFO: 61223685Speter vprintf(stdout, "extract fifo %s\n", name); 61323685Speter if (Nflag) { 61423685Speter skipfile(); 61523685Speter return (GOOD); 61623685Speter } 61735852Sjkh if (uflag && !Nflag) 61835852Sjkh (void)unlink(name); 6196305Smartin if (mkfifo(name, mode) < 0) { 62023685Speter fprintf(stderr, "%s: cannot create fifo: %s\n", 62123685Speter name, strerror(errno)); 6226305Smartin skipfile(); 6236305Smartin return (FAIL); 6246305Smartin } 62598542Smckusick (void) chown(name, curfile.uid, curfile.gid); 6266305Smartin (void) chmod(name, mode); 627100207Smckusick (void) utimes(name, ctimep); 628100207Smckusick (void) utimes(name, mtimep); 62923685Speter (void) chflags(name, flags); 6306305Smartin skipfile(); 6316305Smartin return (GOOD); 6326305Smartin 6331558Srgrimes case IFCHR: 6341558Srgrimes case IFBLK: 6351558Srgrimes vprintf(stdout, "extract special file %s\n", name); 6361558Srgrimes if (Nflag) { 6371558Srgrimes skipfile(); 6381558Srgrimes return (GOOD); 6391558Srgrimes } 64035852Sjkh if (uflag) 64135852Sjkh (void)unlink(name); 64298542Smckusick if (mknod(name, mode, (int)curfile.rdev) < 0) { 6431558Srgrimes fprintf(stderr, "%s: cannot create special file: %s\n", 6441558Srgrimes name, strerror(errno)); 6451558Srgrimes skipfile(); 6461558Srgrimes return (FAIL); 6471558Srgrimes } 64898542Smckusick (void) chown(name, curfile.uid, curfile.gid); 6491558Srgrimes (void) chmod(name, mode); 650100207Smckusick (void) utimes(name, ctimep); 651100207Smckusick (void) utimes(name, mtimep); 65223685Speter (void) chflags(name, flags); 6531558Srgrimes skipfile(); 6541558Srgrimes return (GOOD); 6551558Srgrimes 6561558Srgrimes case IFREG: 6571558Srgrimes vprintf(stdout, "extract file %s\n", name); 6581558Srgrimes if (Nflag) { 6591558Srgrimes skipfile(); 6601558Srgrimes return (GOOD); 6611558Srgrimes } 66235852Sjkh if (uflag) 66335852Sjkh (void)unlink(name); 66421149Simp if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 66521149Simp 0666)) < 0) { 6661558Srgrimes fprintf(stderr, "%s: cannot create file: %s\n", 6671558Srgrimes name, strerror(errno)); 6681558Srgrimes skipfile(); 6691558Srgrimes return (FAIL); 6701558Srgrimes } 67198542Smckusick (void) fchown(ofile, curfile.uid, curfile.gid); 6721558Srgrimes (void) fchmod(ofile, mode); 6731558Srgrimes getfile(xtrfile, xtrskip); 6741558Srgrimes (void) close(ofile); 675100207Smckusick (void) utimes(name, ctimep); 676100207Smckusick (void) utimes(name, mtimep); 67763283Sdwmalone (void) chflags(name, flags); 6781558Srgrimes return (GOOD); 6791558Srgrimes } 6801558Srgrimes /* NOTREACHED */ 6811558Srgrimes} 6821558Srgrimes 6831558Srgrimes/* 6841558Srgrimes * skip over bit maps on the tape 6851558Srgrimes */ 6861558Srgrimesvoid 68792837Simpskipmaps(void) 6881558Srgrimes{ 6891558Srgrimes 6901558Srgrimes while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 6911558Srgrimes skipfile(); 6921558Srgrimes} 6931558Srgrimes 6941558Srgrimes/* 6951558Srgrimes * skip over a file on the tape 6961558Srgrimes */ 6971558Srgrimesvoid 69892837Simpskipfile(void) 6991558Srgrimes{ 7001558Srgrimes 7011558Srgrimes curfile.action = SKIP; 7021558Srgrimes getfile(xtrnull, xtrnull); 7031558Srgrimes} 7041558Srgrimes 7051558Srgrimes/* 7061558Srgrimes * Extract a file from the tape. 7071558Srgrimes * When an allocated block is found it is passed to the fill function; 7081558Srgrimes * when an unallocated block (hole) is found, a zeroed buffer is passed 7091558Srgrimes * to the skip function. 7101558Srgrimes */ 7111558Srgrimesvoid 71292837Simpgetfile(void (*fill)(char *, long), void (*skip)(char *, long)) 7131558Srgrimes{ 71492806Sobrien int i; 7151558Srgrimes int curblk = 0; 71698542Smckusick quad_t size = spcl.c_size; 7171558Srgrimes static char clearedbuf[MAXBSIZE]; 7181558Srgrimes char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 7191558Srgrimes char junk[TP_BSIZE]; 7201558Srgrimes 7211558Srgrimes if (spcl.c_type == TS_END) 7221558Srgrimes panic("ran off end of tape\n"); 72398542Smckusick if (spcl.c_magic != FS_UFS2_MAGIC) 7241558Srgrimes panic("not at beginning of a file\n"); 7251558Srgrimes if (!gettingfile && setjmp(restart) != 0) 7261558Srgrimes return; 7271558Srgrimes gettingfile++; 7281558Srgrimesloop: 7291558Srgrimes for (i = 0; i < spcl.c_count; i++) { 73037923Simp if (readmapflag || spcl.c_addr[i]) { 7311558Srgrimes readtape(&buf[curblk++][0]); 7321558Srgrimes if (curblk == fssize / TP_BSIZE) { 73323685Speter (*fill)((char *)buf, (long)(size > TP_BSIZE ? 73423685Speter fssize : (curblk - 1) * TP_BSIZE + size)); 7351558Srgrimes curblk = 0; 7361558Srgrimes } 7371558Srgrimes } else { 7381558Srgrimes if (curblk > 0) { 73923685Speter (*fill)((char *)buf, (long)(size > TP_BSIZE ? 74023685Speter curblk * TP_BSIZE : 74123685Speter (curblk - 1) * TP_BSIZE + size)); 7421558Srgrimes curblk = 0; 7431558Srgrimes } 74423685Speter (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 74523685Speter TP_BSIZE : size)); 7461558Srgrimes } 7471558Srgrimes if ((size -= TP_BSIZE) <= 0) { 7481558Srgrimes for (i++; i < spcl.c_count; i++) 74937923Simp if (readmapflag || spcl.c_addr[i]) 7501558Srgrimes readtape(junk); 7511558Srgrimes break; 7521558Srgrimes } 7531558Srgrimes } 7541558Srgrimes if (gethead(&spcl) == GOOD && size > 0) { 7551558Srgrimes if (spcl.c_type == TS_ADDR) 7561558Srgrimes goto loop; 7571558Srgrimes dprintf(stdout, 75837240Sbde "Missing address (header) block for %s at %ld blocks\n", 7591558Srgrimes curfile.name, blksread); 7601558Srgrimes } 7611558Srgrimes if (curblk > 0) 76223685Speter (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size)); 7631558Srgrimes findinode(&spcl); 7641558Srgrimes gettingfile = 0; 7651558Srgrimes} 7661558Srgrimes 7671558Srgrimes/* 7681558Srgrimes * Write out the next block of a file. 7691558Srgrimes */ 7701558Srgrimesstatic void 77192837Simpxtrfile(char *buf, long size) 7721558Srgrimes{ 7731558Srgrimes 7741558Srgrimes if (Nflag) 7751558Srgrimes return; 7761558Srgrimes if (write(ofile, buf, (int) size) == -1) { 7771558Srgrimes fprintf(stderr, 7781558Srgrimes "write error extracting inode %d, name %s\nwrite: %s\n", 7791558Srgrimes curfile.ino, curfile.name, strerror(errno)); 7801558Srgrimes } 7811558Srgrimes} 7821558Srgrimes 7831558Srgrimes/* 7841558Srgrimes * Skip over a hole in a file. 7851558Srgrimes */ 7861558Srgrimes/* ARGSUSED */ 7871558Srgrimesstatic void 78892837Simpxtrskip(char *buf, long size) 7891558Srgrimes{ 7901558Srgrimes 7911558Srgrimes if (lseek(ofile, size, SEEK_CUR) == -1) { 7921558Srgrimes fprintf(stderr, 7931558Srgrimes "seek error extracting inode %d, name %s\nlseek: %s\n", 7941558Srgrimes curfile.ino, curfile.name, strerror(errno)); 7951558Srgrimes done(1); 7961558Srgrimes } 7971558Srgrimes} 7981558Srgrimes 7991558Srgrimes/* 8001558Srgrimes * Collect the next block of a symbolic link. 8011558Srgrimes */ 8021558Srgrimesstatic void 80392837Simpxtrlnkfile(char *buf, long size) 8041558Srgrimes{ 8051558Srgrimes 8061558Srgrimes pathlen += size; 8071558Srgrimes if (pathlen > MAXPATHLEN) { 8081558Srgrimes fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 8091558Srgrimes curfile.name, lnkbuf, buf, pathlen); 8101558Srgrimes done(1); 8111558Srgrimes } 8121558Srgrimes (void) strcat(lnkbuf, buf); 8131558Srgrimes} 8141558Srgrimes 8151558Srgrimes/* 8161558Srgrimes * Skip over a hole in a symbolic link (should never happen). 8171558Srgrimes */ 8181558Srgrimes/* ARGSUSED */ 8191558Srgrimesstatic void 82092837Simpxtrlnkskip(char *buf, long size) 8211558Srgrimes{ 8221558Srgrimes 8231558Srgrimes fprintf(stderr, "unallocated block in symbolic link %s\n", 8241558Srgrimes curfile.name); 8251558Srgrimes done(1); 8261558Srgrimes} 8271558Srgrimes 8281558Srgrimes/* 8291558Srgrimes * Collect the next block of a bit map. 8301558Srgrimes */ 8311558Srgrimesstatic void 83292837Simpxtrmap(char *buf, long size) 8331558Srgrimes{ 8341558Srgrimes 83523685Speter memmove(map, buf, size); 8361558Srgrimes map += size; 8371558Srgrimes} 8381558Srgrimes 8391558Srgrimes/* 8401558Srgrimes * Skip over a hole in a bit map (should never happen). 8411558Srgrimes */ 8421558Srgrimes/* ARGSUSED */ 8431558Srgrimesstatic void 84492837Simpxtrmapskip(char *buf, long size) 8451558Srgrimes{ 8461558Srgrimes 8471558Srgrimes panic("hole in map\n"); 8481558Srgrimes map += size; 8491558Srgrimes} 8501558Srgrimes 8511558Srgrimes/* 8521558Srgrimes * Noop, when an extraction function is not needed. 8531558Srgrimes */ 8541558Srgrimes/* ARGSUSED */ 8551558Srgrimesvoid 85692837Simpxtrnull(char *buf, long size) 8571558Srgrimes{ 8581558Srgrimes 8591558Srgrimes return; 8601558Srgrimes} 8611558Srgrimes 8621558Srgrimes/* 8631558Srgrimes * Read TP_BSIZE blocks from the input. 8641558Srgrimes * Handle read errors, and end of media. 8651558Srgrimes */ 8661558Srgrimesstatic void 86792837Simpreadtape(char *buf) 8681558Srgrimes{ 8691558Srgrimes long rd, newvol, i; 8701558Srgrimes int cnt, seek_failed; 8711558Srgrimes 8721558Srgrimes if (blkcnt < numtrec) { 87323685Speter memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 8741558Srgrimes blksread++; 87590827Siedowse tapeaddr++; 8761558Srgrimes return; 8771558Srgrimes } 8781558Srgrimes for (i = 0; i < ntrec; i++) 8791558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 8801558Srgrimes if (numtrec == 0) 8811558Srgrimes numtrec = ntrec; 8821558Srgrimes cnt = ntrec * TP_BSIZE; 8831558Srgrimes rd = 0; 8841558Srgrimesgetmore: 8851558Srgrimes#ifdef RRESTORE 8861558Srgrimes if (host) 8871558Srgrimes i = rmtread(&tapebuf[rd], cnt); 8881558Srgrimes else 8891558Srgrimes#endif 8901558Srgrimes i = read(mt, &tapebuf[rd], cnt); 8911558Srgrimes /* 8921558Srgrimes * Check for mid-tape short read error. 8931558Srgrimes * If found, skip rest of buffer and start with the next. 8941558Srgrimes */ 8951558Srgrimes if (!pipein && numtrec < ntrec && i > 0) { 8961558Srgrimes dprintf(stdout, "mid-media short read error.\n"); 8971558Srgrimes numtrec = ntrec; 8981558Srgrimes } 8991558Srgrimes /* 9001558Srgrimes * Handle partial block read. 9011558Srgrimes */ 9021558Srgrimes if (pipein && i == 0 && rd > 0) 9031558Srgrimes i = rd; 9041558Srgrimes else if (i > 0 && i != ntrec * TP_BSIZE) { 9051558Srgrimes if (pipein) { 9061558Srgrimes rd += i; 9071558Srgrimes cnt -= i; 9081558Srgrimes if (cnt > 0) 9091558Srgrimes goto getmore; 9101558Srgrimes i = rd; 9111558Srgrimes } else { 9121558Srgrimes /* 9131558Srgrimes * Short read. Process the blocks read. 9141558Srgrimes */ 9151558Srgrimes if (i % TP_BSIZE != 0) 9161558Srgrimes vprintf(stdout, 91737240Sbde "partial block read: %ld should be %ld\n", 9181558Srgrimes i, ntrec * TP_BSIZE); 9191558Srgrimes numtrec = i / TP_BSIZE; 9201558Srgrimes } 9211558Srgrimes } 9221558Srgrimes /* 9231558Srgrimes * Handle read error. 9241558Srgrimes */ 9251558Srgrimes if (i < 0) { 9261558Srgrimes fprintf(stderr, "Tape read error while "); 9271558Srgrimes switch (curfile.action) { 9281558Srgrimes default: 9291558Srgrimes fprintf(stderr, "trying to set up tape\n"); 9301558Srgrimes break; 9311558Srgrimes case UNKNOWN: 9321558Srgrimes fprintf(stderr, "trying to resynchronize\n"); 9331558Srgrimes break; 9341558Srgrimes case USING: 9351558Srgrimes fprintf(stderr, "restoring %s\n", curfile.name); 9361558Srgrimes break; 9371558Srgrimes case SKIP: 9381558Srgrimes fprintf(stderr, "skipping over inode %d\n", 9391558Srgrimes curfile.ino); 9401558Srgrimes break; 9411558Srgrimes } 9421558Srgrimes if (!yflag && !reply("continue")) 9431558Srgrimes done(1); 9441558Srgrimes i = ntrec * TP_BSIZE; 94523685Speter memset(tapebuf, 0, i); 9461558Srgrimes#ifdef RRESTORE 9471558Srgrimes if (host) 9481558Srgrimes seek_failed = (rmtseek(i, 1) < 0); 9491558Srgrimes else 9501558Srgrimes#endif 9511558Srgrimes seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 9521558Srgrimes 9531558Srgrimes if (seek_failed) { 9541558Srgrimes fprintf(stderr, 9551558Srgrimes "continuation failed: %s\n", strerror(errno)); 9561558Srgrimes done(1); 9571558Srgrimes } 9581558Srgrimes } 9591558Srgrimes /* 9601558Srgrimes * Handle end of tape. 9611558Srgrimes */ 9621558Srgrimes if (i == 0) { 9631558Srgrimes vprintf(stdout, "End-of-tape encountered\n"); 9641558Srgrimes if (!pipein) { 9651558Srgrimes newvol = volno + 1; 9661558Srgrimes volno = 0; 9671558Srgrimes numtrec = 0; 9681558Srgrimes getvol(newvol); 9691558Srgrimes readtape(buf); 9701558Srgrimes return; 9711558Srgrimes } 9721558Srgrimes if (rd % TP_BSIZE != 0) 9731558Srgrimes panic("partial block read: %d should be %d\n", 9741558Srgrimes rd, ntrec * TP_BSIZE); 9751558Srgrimes terminateinput(); 97623685Speter memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 9771558Srgrimes } 9781558Srgrimes blkcnt = 0; 97923685Speter memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 9801558Srgrimes blksread++; 98190827Siedowse tapeaddr++; 9821558Srgrimes} 9831558Srgrimes 9841558Srgrimesstatic void 98592837Simpfindtapeblksize(void) 9861558Srgrimes{ 98792806Sobrien long i; 9881558Srgrimes 9891558Srgrimes for (i = 0; i < ntrec; i++) 9901558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 9911558Srgrimes blkcnt = 0; 9921558Srgrimes#ifdef RRESTORE 9931558Srgrimes if (host) 9941558Srgrimes i = rmtread(tapebuf, ntrec * TP_BSIZE); 9951558Srgrimes else 9961558Srgrimes#endif 9971558Srgrimes i = read(mt, tapebuf, ntrec * TP_BSIZE); 9981558Srgrimes 9991558Srgrimes if (i <= 0) { 10001558Srgrimes fprintf(stderr, "tape read error: %s\n", strerror(errno)); 10011558Srgrimes done(1); 10021558Srgrimes } 10031558Srgrimes if (i % TP_BSIZE != 0) { 100437240Sbde fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 10051558Srgrimes i, "is not a multiple of dump block size", TP_BSIZE); 10061558Srgrimes done(1); 10071558Srgrimes } 10081558Srgrimes ntrec = i / TP_BSIZE; 10091558Srgrimes numtrec = ntrec; 101037240Sbde vprintf(stdout, "Tape block size is %ld\n", ntrec); 10111558Srgrimes} 10121558Srgrimes 10131558Srgrimesvoid 101492837Simpclosemt(void) 10151558Srgrimes{ 10161558Srgrimes 10171558Srgrimes if (mt < 0) 10181558Srgrimes return; 1019128175Sgreen if (pipecmdin) { 1020128175Sgreen pclose(popenfp); 1021128175Sgreen popenfp = NULL; 1022128175Sgreen } else 10231558Srgrimes#ifdef RRESTORE 10241558Srgrimes if (host) 10251558Srgrimes rmtclose(); 10261558Srgrimes else 10271558Srgrimes#endif 10281558Srgrimes (void) close(mt); 10291558Srgrimes} 10301558Srgrimes 10311558Srgrimes/* 10321558Srgrimes * Read the next block from the tape. 10331558Srgrimes * If it is not any valid header, return an error. 10341558Srgrimes */ 10351558Srgrimesstatic int 103692837Simpgethead(struct s_spcl *buf) 10371558Srgrimes{ 10381558Srgrimes long i; 10391558Srgrimes 104098542Smckusick readtape((char *)buf); 104198542Smckusick if (buf->c_magic != FS_UFS2_MAGIC && buf->c_magic != NFS_MAGIC) { 104298542Smckusick if (buf->c_magic == OFS_MAGIC) { 104398542Smckusick fprintf(stderr, 104498542Smckusick "Format of dump tape is too old. Must use\n"); 104598542Smckusick fprintf(stderr, 104698542Smckusick "a version of restore from before 2002.\n"); 104798542Smckusick return (FAIL); 104898542Smckusick } 104998542Smckusick if (swabl(buf->c_magic) != FS_UFS2_MAGIC && 105098542Smckusick buf->c_magic != NFS_MAGIC) { 105198542Smckusick if (buf->c_magic == OFS_MAGIC) { 105298542Smckusick fprintf(stderr, 105398542Smckusick "Format of dump tape is too old. Must use\n"); 105498542Smckusick fprintf(stderr, 105598542Smckusick "a version of restore from before 2002.\n"); 10561558Srgrimes } 10571558Srgrimes return (FAIL); 105823096Simp } 105998542Smckusick if (!Bcvt) { 106098542Smckusick vprintf(stdout, "Note: Doing Byte swapping\n"); 106198542Smckusick Bcvt = 1; 10621558Srgrimes } 10631558Srgrimes } 106498542Smckusick if (checksum((int *)buf) == FAIL) 106598542Smckusick return (FAIL); 106698542Smckusick if (Bcvt) { 106798542Smckusick swabst((u_char *)"8l4s1q8l2q17l", (u_char *)buf); 106898542Smckusick swabst((u_char *)"l",(u_char *) &buf->c_level); 106998542Smckusick swabst((u_char *)"2l4q",(u_char *) &buf->c_flags); 10701558Srgrimes } 107137923Simp readmapflag = 0; 10721558Srgrimes 10731558Srgrimes switch (buf->c_type) { 10741558Srgrimes 10751558Srgrimes case TS_CLRI: 10761558Srgrimes case TS_BITS: 10771558Srgrimes /* 10781558Srgrimes * Have to patch up missing information in bit map headers 10791558Srgrimes */ 10801558Srgrimes buf->c_inumber = 0; 108198542Smckusick buf->c_size = buf->c_count * TP_BSIZE; 108237923Simp if (buf->c_count > TP_NINDIR) 108337923Simp readmapflag = 1; 108437923Simp else 108537923Simp for (i = 0; i < buf->c_count; i++) 108637923Simp buf->c_addr[i]++; 10871558Srgrimes break; 10881558Srgrimes 10891558Srgrimes case TS_TAPE: 1090143819Simp if (buf->c_magic == NFS_MAGIC) { 1091144099Simp if ((buf->c_flags & NFS_DR_NEWINODEFMT) == 0) 1092144099Simp oldinofmt = 1; 1093143819Simp buf->c_date = _time32_to_time(buf->c_old_date); 1094143819Simp buf->c_ddate = _time32_to_time(buf->c_old_ddate); 1095144093Simp buf->c_tapea = buf->c_old_tapea; 1096144093Simp buf->c_firstrec = buf->c_old_firstrec; 1097143819Simp } 10981558Srgrimes case TS_END: 10991558Srgrimes buf->c_inumber = 0; 11001558Srgrimes break; 11011558Srgrimes 11021558Srgrimes case TS_INODE: 110398542Smckusick /* 110498542Smckusick * For old dump tapes, have to copy up old fields to 110598542Smckusick * new locations. 110698542Smckusick */ 110798542Smckusick if (buf->c_magic == NFS_MAGIC) { 110898542Smckusick buf->c_tapea = buf->c_old_tapea; 110998542Smckusick buf->c_firstrec = buf->c_old_firstrec; 111098542Smckusick buf->c_date = _time32_to_time(buf->c_old_date); 111198542Smckusick buf->c_ddate = _time32_to_time(buf->c_old_ddate); 111298542Smckusick buf->c_atime = _time32_to_time(buf->c_old_atime); 111398542Smckusick buf->c_mtime = _time32_to_time(buf->c_old_mtime); 111498542Smckusick } 111598542Smckusick break; 111698542Smckusick 11171558Srgrimes case TS_ADDR: 11181558Srgrimes break; 11191558Srgrimes 11201558Srgrimes default: 11211558Srgrimes panic("gethead: unknown inode type %d\n", buf->c_type); 11221558Srgrimes break; 11231558Srgrimes } 1124144099Simp /* 1125144099Simp * If we're restoring a filesystem with the old (FreeBSD 1) 1126144099Simp * format inodes, copy the uid/gid to the new location 1127144099Simp */ 1128144099Simp if (oldinofmt) { 1129144099Simp buf->c_uid = buf->c_spare1[1]; 1130144099Simp buf->c_gid = buf->c_spare1[2]; 1131144099Simp } 113298542Smckusick buf->c_magic = FS_UFS2_MAGIC; 113390827Siedowse tapeaddr = buf->c_tapea; 11341558Srgrimes if (dflag) 11351558Srgrimes accthdr(buf); 11361558Srgrimes return(GOOD); 11371558Srgrimes} 11381558Srgrimes 11391558Srgrimes/* 11401558Srgrimes * Check that a header is where it belongs and predict the next header 11411558Srgrimes */ 11421558Srgrimesstatic void 114392837Simpaccthdr(struct s_spcl *header) 11441558Srgrimes{ 11451558Srgrimes static ino_t previno = 0x7fffffff; 11461558Srgrimes static int prevtype; 11471558Srgrimes static long predict; 11481558Srgrimes long blks, i; 11491558Srgrimes 11501558Srgrimes if (header->c_type == TS_TAPE) { 115198542Smckusick fprintf(stderr, "Volume header "); 11521558Srgrimes if (header->c_firstrec) 115398542Smckusick fprintf(stderr, "begins with record %qd", 11541558Srgrimes header->c_firstrec); 11551558Srgrimes fprintf(stderr, "\n"); 11561558Srgrimes previno = 0x7fffffff; 11571558Srgrimes return; 11581558Srgrimes } 11591558Srgrimes if (previno == 0x7fffffff) 11601558Srgrimes goto newcalc; 11611558Srgrimes switch (prevtype) { 11621558Srgrimes case TS_BITS: 116323685Speter fprintf(stderr, "Dumped inodes map header"); 11641558Srgrimes break; 11651558Srgrimes case TS_CLRI: 116623685Speter fprintf(stderr, "Used inodes map header"); 11671558Srgrimes break; 11681558Srgrimes case TS_INODE: 11691558Srgrimes fprintf(stderr, "File header, ino %d", previno); 11701558Srgrimes break; 11711558Srgrimes case TS_ADDR: 11721558Srgrimes fprintf(stderr, "File continuation header, ino %d", previno); 11731558Srgrimes break; 11741558Srgrimes case TS_END: 11751558Srgrimes fprintf(stderr, "End of tape header"); 11761558Srgrimes break; 11771558Srgrimes } 11781558Srgrimes if (predict != blksread - 1) 117937240Sbde fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 11801558Srgrimes predict, blksread - 1); 11811558Srgrimes fprintf(stderr, "\n"); 11821558Srgrimesnewcalc: 11831558Srgrimes blks = 0; 11841558Srgrimes if (header->c_type != TS_END) 11851558Srgrimes for (i = 0; i < header->c_count; i++) 118637923Simp if (readmapflag || header->c_addr[i] != 0) 11871558Srgrimes blks++; 11881558Srgrimes predict = blks; 11891558Srgrimes blksread = 0; 11901558Srgrimes prevtype = header->c_type; 11911558Srgrimes previno = header->c_inumber; 11921558Srgrimes} 11931558Srgrimes 11941558Srgrimes/* 11951558Srgrimes * Find an inode header. 119690573Siedowse * Complain if had to skip. 11971558Srgrimes */ 11981558Srgrimesstatic void 119992837Simpfindinode(struct s_spcl *header) 12001558Srgrimes{ 12011558Srgrimes static long skipcnt = 0; 12021558Srgrimes long i; 12031558Srgrimes char buf[TP_BSIZE]; 120490608Siedowse int htype; 12051558Srgrimes 12061558Srgrimes curfile.name = "<name unknown>"; 12071558Srgrimes curfile.action = UNKNOWN; 120898542Smckusick curfile.mode = 0; 12091558Srgrimes curfile.ino = 0; 12101558Srgrimes do { 121190608Siedowse htype = header->c_type; 121290608Siedowse switch (htype) { 12131558Srgrimes 12141558Srgrimes case TS_ADDR: 12151558Srgrimes /* 12161558Srgrimes * Skip up to the beginning of the next record 12171558Srgrimes */ 12181558Srgrimes for (i = 0; i < header->c_count; i++) 12191558Srgrimes if (header->c_addr[i]) 12201558Srgrimes readtape(buf); 12211558Srgrimes while (gethead(header) == FAIL || 122298542Smckusick _time64_to_time(header->c_date) != dumpdate) 12231558Srgrimes skipcnt++; 12241558Srgrimes break; 12251558Srgrimes 12261558Srgrimes case TS_INODE: 122798542Smckusick curfile.mode = header->c_mode; 122898542Smckusick curfile.uid = header->c_uid; 122998542Smckusick curfile.gid = header->c_gid; 123098542Smckusick curfile.file_flags = header->c_file_flags; 123198542Smckusick curfile.rdev = header->c_rdev; 123298542Smckusick curfile.atime_sec = header->c_atime; 123398542Smckusick curfile.atime_nsec = header->c_atimensec; 123498542Smckusick curfile.mtime_sec = header->c_mtime; 123598542Smckusick curfile.mtime_nsec = header->c_mtimensec; 1236100207Smckusick curfile.birthtime_sec = header->c_birthtime; 1237100207Smckusick curfile.birthtime_nsec = header->c_birthtimensec; 123898542Smckusick curfile.size = header->c_size; 12391558Srgrimes curfile.ino = header->c_inumber; 12401558Srgrimes break; 12411558Srgrimes 12421558Srgrimes case TS_END: 124390820Siedowse /* If we missed some tapes, get another volume. */ 124490820Siedowse if (tapesread & (tapesread + 1)) { 124590820Siedowse getvol(0); 124690820Siedowse continue; 124790820Siedowse } 12481558Srgrimes curfile.ino = maxino; 12491558Srgrimes break; 12501558Srgrimes 12511558Srgrimes case TS_CLRI: 12521558Srgrimes curfile.name = "<file removal list>"; 12531558Srgrimes break; 12541558Srgrimes 12551558Srgrimes case TS_BITS: 12561558Srgrimes curfile.name = "<file dump list>"; 12571558Srgrimes break; 12581558Srgrimes 12591558Srgrimes case TS_TAPE: 12601558Srgrimes panic("unexpected tape header\n"); 12611558Srgrimes /* NOTREACHED */ 12621558Srgrimes 12631558Srgrimes default: 12641558Srgrimes panic("unknown tape header type %d\n", spcl.c_type); 12651558Srgrimes /* NOTREACHED */ 12661558Srgrimes 12671558Srgrimes } 126890608Siedowse } while (htype == TS_ADDR); 12691558Srgrimes if (skipcnt > 0) 127037240Sbde fprintf(stderr, "resync restore, skipped %ld blocks\n", 127137240Sbde skipcnt); 12721558Srgrimes skipcnt = 0; 12731558Srgrimes} 12741558Srgrimes 12751558Srgrimesstatic int 127692837Simpchecksum(int *buf) 12771558Srgrimes{ 127892806Sobrien int i, j; 12791558Srgrimes 12801558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 12811558Srgrimes i = 0; 128298542Smckusick if (!Bcvt) { 12831558Srgrimes do 12841558Srgrimes i += *buf++; 12851558Srgrimes while (--j); 12861558Srgrimes } else { 12871558Srgrimes /* What happens if we want to read restore tapes 12881558Srgrimes for a 16bit int machine??? */ 12898871Srgrimes do 12901558Srgrimes i += swabl(*buf++); 12911558Srgrimes while (--j); 12921558Srgrimes } 12938871Srgrimes 12941558Srgrimes if (i != CHECKSUM) { 12951558Srgrimes fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 12961558Srgrimes curfile.ino, curfile.name); 12971558Srgrimes return(FAIL); 12981558Srgrimes } 12991558Srgrimes return(GOOD); 13001558Srgrimes} 13011558Srgrimes 13021558Srgrimes#ifdef RRESTORE 13031558Srgrimes#include <stdarg.h> 13041558Srgrimes 13051558Srgrimesvoid 13061558Srgrimesmsg(const char *fmt, ...) 13071558Srgrimes{ 13081558Srgrimes va_list ap; 13091558Srgrimes va_start(ap, fmt); 13101558Srgrimes (void)vfprintf(stderr, fmt, ap); 13111558Srgrimes va_end(ap); 13121558Srgrimes} 13131558Srgrimes#endif /* RRESTORE */ 13141558Srgrimes 13151558Srgrimesstatic u_char * 131692837Simpswabshort(u_char *sp, int n) 13171558Srgrimes{ 13181558Srgrimes char c; 13191558Srgrimes 13201558Srgrimes while (--n >= 0) { 13211558Srgrimes c = sp[0]; sp[0] = sp[1]; sp[1] = c; 13221558Srgrimes sp += 2; 13231558Srgrimes } 13241558Srgrimes return (sp); 13251558Srgrimes} 13261558Srgrimes 13271558Srgrimesstatic u_char * 132892837Simpswablong(u_char *sp, int n) 13291558Srgrimes{ 13301558Srgrimes char c; 13311558Srgrimes 13321558Srgrimes while (--n >= 0) { 13331558Srgrimes c = sp[0]; sp[0] = sp[3]; sp[3] = c; 13341558Srgrimes c = sp[2]; sp[2] = sp[1]; sp[1] = c; 13351558Srgrimes sp += 4; 13361558Srgrimes } 13371558Srgrimes return (sp); 13381558Srgrimes} 13391558Srgrimes 134098542Smckusickstatic u_char * 134198542Smckusickswabquad(u_char *sp, int n) 134298542Smckusick{ 134398542Smckusick char c; 134498542Smckusick 134598542Smckusick while (--n >= 0) { 134698542Smckusick c = sp[0]; sp[0] = sp[7]; sp[7] = c; 134798542Smckusick c = sp[1]; sp[1] = sp[6]; sp[6] = c; 134898542Smckusick c = sp[2]; sp[2] = sp[5]; sp[5] = c; 134998542Smckusick c = sp[3]; sp[3] = sp[4]; sp[4] = c; 135098542Smckusick sp += 8; 135198542Smckusick } 135298542Smckusick return (sp); 135398542Smckusick} 135498542Smckusick 13551558Srgrimesvoid 135692837Simpswabst(u_char *cp, u_char *sp) 13571558Srgrimes{ 13581558Srgrimes int n = 0; 13591558Srgrimes 13601558Srgrimes while (*cp) { 13611558Srgrimes switch (*cp) { 13621558Srgrimes case '0': case '1': case '2': case '3': case '4': 13631558Srgrimes case '5': case '6': case '7': case '8': case '9': 13641558Srgrimes n = (n * 10) + (*cp++ - '0'); 13651558Srgrimes continue; 13668871Srgrimes 13671558Srgrimes case 's': case 'w': case 'h': 13681558Srgrimes if (n == 0) 13691558Srgrimes n = 1; 13701558Srgrimes sp = swabshort(sp, n); 13711558Srgrimes break; 13721558Srgrimes 13731558Srgrimes case 'l': 13741558Srgrimes if (n == 0) 13751558Srgrimes n = 1; 13761558Srgrimes sp = swablong(sp, n); 13771558Srgrimes break; 13781558Srgrimes 137998542Smckusick case 'q': 13801558Srgrimes if (n == 0) 13811558Srgrimes n = 1; 138298542Smckusick sp = swabquad(sp, n); 138398542Smckusick break; 138498542Smckusick 138598542Smckusick case 'b': 138698542Smckusick if (n == 0) 138798542Smckusick n = 1; 13881558Srgrimes sp += n; 13891558Srgrimes break; 139098542Smckusick 139198542Smckusick default: 139298542Smckusick fprintf(stderr, "Unknown conversion character: %c\n", 139398542Smckusick *cp); 139498542Smckusick done(0); 139598542Smckusick break; 13961558Srgrimes } 13971558Srgrimes cp++; 13981558Srgrimes n = 0; 13991558Srgrimes } 14001558Srgrimes} 14011558Srgrimes 14021558Srgrimesstatic u_long 140392837Simpswabl(u_long x) 14041558Srgrimes{ 14051558Srgrimes swabst((u_char *)"l", (u_char *)&x); 14061558Srgrimes return (x); 14071558Srgrimes} 1408