tape.c revision 90573
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1983, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * (c) UNIX System Laboratories, Inc. 51558Srgrimes * All or some portions of this file are derived from material licensed 61558Srgrimes * to the University of California by American Telephone and Telegraph 71558Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 81558Srgrimes * the permission of UNIX System Laboratories, Inc. 91558Srgrimes * 101558Srgrimes * Redistribution and use in source and binary forms, with or without 111558Srgrimes * modification, are permitted provided that the following conditions 121558Srgrimes * are met: 131558Srgrimes * 1. Redistributions of source code must retain the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer. 151558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161558Srgrimes * notice, this list of conditions and the following disclaimer in the 171558Srgrimes * documentation and/or other materials provided with the distribution. 181558Srgrimes * 3. All advertising materials mentioning features or use of this software 191558Srgrimes * must display the following acknowledgement: 201558Srgrimes * This product includes software developed by the University of 211558Srgrimes * California, Berkeley and its contributors. 221558Srgrimes * 4. Neither the name of the University nor the names of its contributors 231558Srgrimes * may be used to endorse or promote products derived from this software 241558Srgrimes * without specific prior written permission. 251558Srgrimes * 261558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361558Srgrimes * SUCH DAMAGE. 371558Srgrimes */ 381558Srgrimes 391558Srgrimes#ifndef lint 4037906Scharnier#if 0 4123685Speterstatic char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; 4237906Scharnier#endif 4337906Scharnierstatic const char rcsid[] = 4450476Speter "$FreeBSD: head/sbin/restore/tape.c 90573 2002-02-12 17:15:45Z iedowse $"; 451558Srgrimes#endif /* not lint */ 461558Srgrimes 471558Srgrimes#include <sys/param.h> 481558Srgrimes#include <sys/file.h> 491558Srgrimes#include <sys/mtio.h> 501558Srgrimes#include <sys/stat.h> 5166907Swollman#include <sys/time.h> 521558Srgrimes 531558Srgrimes#include <ufs/ufs/dinode.h> 541558Srgrimes#include <protocols/dumprestore.h> 551558Srgrimes 561558Srgrimes#include <errno.h> 5773986Sobrien#include <paths.h> 581558Srgrimes#include <setjmp.h> 591558Srgrimes#include <stdio.h> 601558Srgrimes#include <stdlib.h> 611558Srgrimes#include <string.h> 6266907Swollman#include <time.h> 631558Srgrimes#include <unistd.h> 641558Srgrimes 651558Srgrimes#include "restore.h" 661558Srgrimes#include "extern.h" 671558Srgrimes 681558Srgrimesstatic long fssize = MAXBSIZE; 691558Srgrimesstatic int mt = -1; 701558Srgrimesstatic int pipein = 0; 7121174Sguidostatic char *magtape; 721558Srgrimesstatic int blkcnt; 731558Srgrimesstatic int numtrec; 741558Srgrimesstatic char *tapebuf; 751558Srgrimesstatic union u_spcl endoftapemark; 761558Srgrimesstatic long blksread; /* blocks read since last header */ 771558Srgrimesstatic long tpblksread = 0; /* TP_BSIZE blocks read */ 781558Srgrimesstatic long tapesread; 791558Srgrimesstatic jmp_buf restart; 801558Srgrimesstatic int gettingfile = 0; /* restart has a valid frame */ 811558Srgrimesstatic char *host = NULL; 821558Srgrimes 831558Srgrimesstatic int ofile; 841558Srgrimesstatic char *map; 851558Srgrimesstatic char lnkbuf[MAXPATHLEN + 1]; 861558Srgrimesstatic int pathlen; 871558Srgrimes 881558Srgrimesint oldinofmt; /* old inode format conversion required */ 891558Srgrimesint Bcvt; /* Swap Bytes (for CCI or sun) */ 901558Srgrimesstatic int Qcvt; /* Swap quads (for sun) */ 911558Srgrimes 921558Srgrimes#define FLUSHTAPEBUF() blkcnt = ntrec + 1 931558Srgrimes 941558Srgrimesstatic void accthdr __P((struct s_spcl *)); 951558Srgrimesstatic int checksum __P((int *)); 961558Srgrimesstatic void findinode __P((struct s_spcl *)); 971558Srgrimesstatic void findtapeblksize __P((void)); 981558Srgrimesstatic int gethead __P((struct s_spcl *)); 991558Srgrimesstatic void readtape __P((char *)); 1001558Srgrimesstatic void setdumpnum __P((void)); 1011558Srgrimesstatic u_long swabl __P((u_long)); 1021558Srgrimesstatic u_char *swablong __P((u_char *, int)); 1031558Srgrimesstatic u_char *swabshort __P((u_char *, int)); 1041558Srgrimesstatic void terminateinput __P((void)); 1051558Srgrimesstatic void xtrfile __P((char *, long)); 1061558Srgrimesstatic void xtrlnkfile __P((char *, long)); 1071558Srgrimesstatic void xtrlnkskip __P((char *, long)); 1081558Srgrimesstatic void xtrmap __P((char *, long)); 1091558Srgrimesstatic void xtrmapskip __P((char *, long)); 1101558Srgrimesstatic void xtrskip __P((char *, long)); 1111558Srgrimes 11237923Simpstatic int readmapflag; 11337923Simp 1141558Srgrimes/* 1151558Srgrimes * Set up an input source 1161558Srgrimes */ 1171558Srgrimesvoid 1181558Srgrimessetinput(source) 1191558Srgrimes char *source; 1201558Srgrimes{ 1211558Srgrimes FLUSHTAPEBUF(); 1221558Srgrimes if (bflag) 1231558Srgrimes newtapebuf(ntrec); 1241558Srgrimes else 1251558Srgrimes newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 1261558Srgrimes terminal = stdin; 1271558Srgrimes 1281558Srgrimes#ifdef RRESTORE 12923685Speter if (strchr(source, ':')) { 1301558Srgrimes host = source; 13123685Speter source = strchr(host, ':'); 1321558Srgrimes *source++ = '\0'; 1331558Srgrimes if (rmthost(host) == 0) 1341558Srgrimes done(1); 1351558Srgrimes } else 1361558Srgrimes#endif 1371558Srgrimes if (strcmp(source, "-") == 0) { 1381558Srgrimes /* 1391558Srgrimes * Since input is coming from a pipe we must establish 1401558Srgrimes * our own connection to the terminal. 1411558Srgrimes */ 1421558Srgrimes terminal = fopen(_PATH_TTY, "r"); 1431558Srgrimes if (terminal == NULL) { 1441558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1451558Srgrimes _PATH_TTY, strerror(errno)); 1461558Srgrimes terminal = fopen(_PATH_DEVNULL, "r"); 1471558Srgrimes if (terminal == NULL) { 1481558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1491558Srgrimes _PATH_DEVNULL, strerror(errno)); 1501558Srgrimes done(1); 1511558Srgrimes } 1521558Srgrimes } 1531558Srgrimes pipein++; 1541558Srgrimes } 1551558Srgrimes setuid(getuid()); /* no longer need or want root privileges */ 15621174Sguido magtape = strdup(source); 15721174Sguido if (magtape == NULL) { 15821174Sguido fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 15921174Sguido done(1); 16021174Sguido } 1611558Srgrimes} 1621558Srgrimes 1631558Srgrimesvoid 1641558Srgrimesnewtapebuf(size) 1651558Srgrimes long size; 1661558Srgrimes{ 1671558Srgrimes static 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 1871558Srgrimessetup() 1881558Srgrimes{ 1891558Srgrimes int i, j, *ip; 1901558Srgrimes struct stat stbuf; 1911558Srgrimes 1921558Srgrimes vprintf(stdout, "Verify tape and initialize maps\n"); 1931558Srgrimes#ifdef RRESTORE 1941558Srgrimes if (host) 1951558Srgrimes mt = rmtopen(magtape, 0); 1961558Srgrimes else 1971558Srgrimes#endif 1981558Srgrimes if (pipein) 1991558Srgrimes mt = 0; 2001558Srgrimes else 2011558Srgrimes mt = open(magtape, O_RDONLY, 0); 2021558Srgrimes if (mt < 0) { 2031558Srgrimes fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 2041558Srgrimes done(1); 2051558Srgrimes } 2061558Srgrimes volno = 1; 2071558Srgrimes setdumpnum(); 2081558Srgrimes FLUSHTAPEBUF(); 2091558Srgrimes if (!pipein && !bflag) 2101558Srgrimes findtapeblksize(); 2111558Srgrimes if (gethead(&spcl) == FAIL) { 2121558Srgrimes blkcnt--; /* push back this block */ 2131558Srgrimes blksread--; 2141558Srgrimes tpblksread--; 2151558Srgrimes cvtflag++; 2161558Srgrimes if (gethead(&spcl) == FAIL) { 2171558Srgrimes fprintf(stderr, "Tape is not a dump tape\n"); 2181558Srgrimes done(1); 2191558Srgrimes } 2201558Srgrimes fprintf(stderr, "Converting to new file system format.\n"); 2211558Srgrimes } 2221558Srgrimes if (pipein) { 2231558Srgrimes endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; 2241558Srgrimes endoftapemark.s_spcl.c_type = TS_END; 2251558Srgrimes ip = (int *)&endoftapemark; 2261558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 2271558Srgrimes i = 0; 2281558Srgrimes do 2291558Srgrimes i += *ip++; 2301558Srgrimes while (--j); 2311558Srgrimes endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 2321558Srgrimes } 2331558Srgrimes if (vflag || command == 't') 2341558Srgrimes printdumpinfo(); 23589572Sdillon dumptime = _time32_to_time(spcl.c_ddate); 23689572Sdillon dumpdate = _time32_to_time(spcl.c_date); 2371558Srgrimes if (stat(".", &stbuf) < 0) { 2381558Srgrimes fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 2391558Srgrimes done(1); 2401558Srgrimes } 24134851Sjkh if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 24234851Sjkh fssize = TP_BSIZE; 24334851Sjkh if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 2441558Srgrimes fssize = stbuf.st_blksize; 2451558Srgrimes if (((fssize - 1) & fssize) != 0) { 24637240Sbde fprintf(stderr, "bad block size %ld\n", fssize); 2471558Srgrimes done(1); 2481558Srgrimes } 2491558Srgrimes if (spcl.c_volume != 1) { 2501558Srgrimes fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2511558Srgrimes done(1); 2521558Srgrimes } 2531558Srgrimes if (gethead(&spcl) == FAIL) { 25437240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 2551558Srgrimes panic("no header after volume mark!\n"); 2561558Srgrimes } 2571558Srgrimes findinode(&spcl); 2581558Srgrimes if (spcl.c_type != TS_CLRI) { 2591558Srgrimes fprintf(stderr, "Cannot find file removal list\n"); 2601558Srgrimes done(1); 2611558Srgrimes } 2621558Srgrimes maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 2631558Srgrimes dprintf(stdout, "maxino = %d\n", maxino); 2641558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2651558Srgrimes if (map == NULL) 26623685Speter panic("no memory for active inode map\n"); 26723685Speter usedinomap = map; 2681558Srgrimes curfile.action = USING; 2691558Srgrimes getfile(xtrmap, xtrmapskip); 2701558Srgrimes if (spcl.c_type != TS_BITS) { 2711558Srgrimes fprintf(stderr, "Cannot find file dump list\n"); 2721558Srgrimes done(1); 2731558Srgrimes } 2741558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2751558Srgrimes if (map == (char *)NULL) 2761558Srgrimes panic("no memory for file dump list\n"); 2771558Srgrimes dumpmap = map; 2781558Srgrimes curfile.action = USING; 2791558Srgrimes getfile(xtrmap, xtrmapskip); 28023685Speter /* 28123685Speter * If there may be whiteout entries on the tape, pretend that the 28223685Speter * whiteout inode exists, so that the whiteout entries can be 28323685Speter * extracted. 28423685Speter */ 28523685Speter if (oldinofmt == 0) 28623685Speter SETINO(WINO, dumpmap); 2871558Srgrimes} 2881558Srgrimes 2891558Srgrimes/* 2901558Srgrimes * Prompt user to load a new dump volume. 2911558Srgrimes * "Nextvol" is the next suggested volume to use. 2921558Srgrimes * This suggested volume is enforced when doing full 29337906Scharnier * or incremental restores, but can be overridden by 2941558Srgrimes * the user when only extracting a subset of the files. 2951558Srgrimes */ 2961558Srgrimesvoid 2971558Srgrimesgetvol(nextvol) 2981558Srgrimes long nextvol; 2991558Srgrimes{ 3001558Srgrimes long newvol, savecnt, wantnext, i; 3011558Srgrimes union u_spcl tmpspcl; 3021558Srgrimes# define tmpbuf tmpspcl.s_spcl 3031558Srgrimes char buf[TP_BSIZE]; 3041558Srgrimes 3051558Srgrimes if (nextvol == 1) { 3061558Srgrimes tapesread = 0; 3071558Srgrimes gettingfile = 0; 3081558Srgrimes } 3091558Srgrimes if (pipein) { 31069906Siedowse if (nextvol != 1) { 3111558Srgrimes panic("Changing volumes on pipe input?\n"); 31269906Siedowse /* Avoid looping if we couldn't ask the user. */ 31369906Siedowse if (yflag || ferror(terminal) || feof(terminal)) 31469906Siedowse done(1); 31569906Siedowse } 3161558Srgrimes if (volno == 1) 3171558Srgrimes return; 3181558Srgrimes goto gethdr; 3191558Srgrimes } 3201558Srgrimes savecnt = blksread; 3211558Srgrimesagain: 3221558Srgrimes if (pipein) 3231558Srgrimes done(1); /* pipes do not get a second chance */ 3241558Srgrimes if (command == 'R' || command == 'r' || curfile.action != SKIP) { 3251558Srgrimes newvol = nextvol; 3261558Srgrimes wantnext = 1; 3278871Srgrimes } else { 3281558Srgrimes newvol = 0; 3291558Srgrimes wantnext = 0; 3301558Srgrimes } 3311558Srgrimes while (newvol <= 0) { 3321558Srgrimes if (tapesread == 0) { 3331558Srgrimes fprintf(stderr, "%s%s%s%s%s", 3341558Srgrimes "You have not read any tapes yet.\n", 3351558Srgrimes "Unless you know which volume your", 3361558Srgrimes " file(s) are on you should start\n", 3371558Srgrimes "with the last volume and work", 33831925Smax " towards the first.\n"); 3391558Srgrimes } else { 3401558Srgrimes fprintf(stderr, "You have read volumes"); 3411558Srgrimes strcpy(buf, ": "); 3421558Srgrimes for (i = 1; i < 32; i++) 3431558Srgrimes if (tapesread & (1 << i)) { 34437240Sbde fprintf(stderr, "%s%ld", buf, i); 3451558Srgrimes strcpy(buf, ", "); 3461558Srgrimes } 3471558Srgrimes fprintf(stderr, "\n"); 3481558Srgrimes } 3491558Srgrimes do { 3501558Srgrimes fprintf(stderr, "Specify next volume #: "); 3511558Srgrimes (void) fflush(stderr); 35269906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 35369906Siedowse done(1); 35469906Siedowse } while (buf[0] == '\n'); 3551558Srgrimes newvol = atoi(buf); 3561558Srgrimes if (newvol <= 0) { 3571558Srgrimes fprintf(stderr, 3581558Srgrimes "Volume numbers are positive numerics\n"); 3591558Srgrimes } 3601558Srgrimes } 3611558Srgrimes if (newvol == volno) { 3621558Srgrimes tapesread |= 1 << volno; 3631558Srgrimes return; 3641558Srgrimes } 3651558Srgrimes closemt(); 36637240Sbde fprintf(stderr, "Mount tape volume %ld\n", newvol); 3671558Srgrimes fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 3681558Srgrimes fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 3691558Srgrimes (void) fflush(stderr); 37069906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 3711558Srgrimes done(1); 3721558Srgrimes if (!strcmp(buf, "none\n")) { 3731558Srgrimes terminateinput(); 3741558Srgrimes return; 3751558Srgrimes } 3761558Srgrimes if (buf[0] != '\n') { 3771558Srgrimes (void) strcpy(magtape, buf); 3781558Srgrimes magtape[strlen(magtape) - 1] = '\0'; 3791558Srgrimes } 3801558Srgrimes#ifdef RRESTORE 3811558Srgrimes if (host) 3821558Srgrimes mt = rmtopen(magtape, 0); 3831558Srgrimes else 3841558Srgrimes#endif 3851558Srgrimes mt = open(magtape, O_RDONLY, 0); 3861558Srgrimes 3871558Srgrimes if (mt == -1) { 3881558Srgrimes fprintf(stderr, "Cannot open %s\n", magtape); 3891558Srgrimes volno = -1; 3901558Srgrimes goto again; 3911558Srgrimes } 3921558Srgrimesgethdr: 3931558Srgrimes volno = newvol; 3941558Srgrimes setdumpnum(); 3951558Srgrimes FLUSHTAPEBUF(); 3961558Srgrimes if (gethead(&tmpbuf) == FAIL) { 39737240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 3981558Srgrimes fprintf(stderr, "tape is not dump tape\n"); 3991558Srgrimes volno = 0; 4001558Srgrimes goto again; 4011558Srgrimes } 4021558Srgrimes if (tmpbuf.c_volume != volno) { 40337240Sbde fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume); 4041558Srgrimes volno = 0; 4051558Srgrimes goto again; 4061558Srgrimes } 40789572Sdillon if (_time32_to_time(tmpbuf.c_date) != dumpdate || 40889572Sdillon _time32_to_time(tmpbuf.c_ddate) != dumptime) { 40989572Sdillon time_t t = _time32_to_time(tmpbuf.c_date); 41085635Sdillon fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t)); 4111558Srgrimes fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 4121558Srgrimes volno = 0; 4131558Srgrimes goto again; 4141558Srgrimes } 4151558Srgrimes tapesread |= 1 << volno; 4161558Srgrimes blksread = savecnt; 4171558Srgrimes /* 4181558Srgrimes * If continuing from the previous volume, skip over any 4191558Srgrimes * blocks read already at the end of the previous volume. 4201558Srgrimes * 4211558Srgrimes * If coming to this volume at random, skip to the beginning 4221558Srgrimes * of the next record. 4231558Srgrimes */ 4248871Srgrimes dprintf(stdout, "read %ld recs, tape starts with %ld\n", 4251558Srgrimes tpblksread, tmpbuf.c_firstrec); 4261558Srgrimes if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { 4271558Srgrimes if (!wantnext) { 4281558Srgrimes tpblksread = tmpbuf.c_firstrec; 4291558Srgrimes for (i = tmpbuf.c_count; i > 0; i--) 4301558Srgrimes readtape(buf); 4311558Srgrimes } else if (tmpbuf.c_firstrec > 0 && 4321558Srgrimes tmpbuf.c_firstrec < tpblksread - 1) { 4331558Srgrimes /* 4341558Srgrimes * -1 since we've read the volume header 4351558Srgrimes */ 4361558Srgrimes i = tpblksread - tmpbuf.c_firstrec - 1; 43737240Sbde dprintf(stderr, "Skipping %ld duplicate record%s.\n", 4381558Srgrimes i, i > 1 ? "s" : ""); 4391558Srgrimes while (--i >= 0) 4401558Srgrimes readtape(buf); 4411558Srgrimes } 4421558Srgrimes } 44378039Smjacob if (curfile.action == USING || curfile.action == SKIP) { 4441558Srgrimes if (volno == 1) 4451558Srgrimes panic("active file into volume 1\n"); 4461558Srgrimes return; 4471558Srgrimes } 4481558Srgrimes /* 4491558Srgrimes * Skip up to the beginning of the next record 4501558Srgrimes */ 4511558Srgrimes if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) 4521558Srgrimes for (i = tmpbuf.c_count; i > 0; i--) 4531558Srgrimes readtape(buf); 4541558Srgrimes (void) gethead(&spcl); 4551558Srgrimes findinode(&spcl); 4561558Srgrimes if (gettingfile) { 4571558Srgrimes gettingfile = 0; 4581558Srgrimes longjmp(restart, 1); 4591558Srgrimes } 4601558Srgrimes} 4611558Srgrimes 4621558Srgrimes/* 4631558Srgrimes * Handle unexpected EOF. 4641558Srgrimes */ 4651558Srgrimesstatic void 4661558Srgrimesterminateinput() 4671558Srgrimes{ 4681558Srgrimes 4691558Srgrimes if (gettingfile && curfile.action == USING) { 4701558Srgrimes printf("Warning: %s %s\n", 4711558Srgrimes "End-of-input encountered while extracting", curfile.name); 4721558Srgrimes } 4731558Srgrimes curfile.name = "<name unknown>"; 4741558Srgrimes curfile.action = UNKNOWN; 4751558Srgrimes curfile.dip = NULL; 4761558Srgrimes curfile.ino = maxino; 4771558Srgrimes if (gettingfile) { 4781558Srgrimes gettingfile = 0; 4791558Srgrimes longjmp(restart, 1); 4801558Srgrimes } 4811558Srgrimes} 4821558Srgrimes 4831558Srgrimes/* 4841558Srgrimes * handle multiple dumps per tape by skipping forward to the 4851558Srgrimes * appropriate one. 4861558Srgrimes */ 4871558Srgrimesstatic void 4881558Srgrimessetdumpnum() 4891558Srgrimes{ 4901558Srgrimes struct mtop tcom; 4911558Srgrimes 4921558Srgrimes if (dumpnum == 1 || volno != 1) 4931558Srgrimes return; 4941558Srgrimes if (pipein) { 4951558Srgrimes fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 4961558Srgrimes done(1); 4971558Srgrimes } 4981558Srgrimes tcom.mt_op = MTFSF; 4991558Srgrimes tcom.mt_count = dumpnum - 1; 5001558Srgrimes#ifdef RRESTORE 5011558Srgrimes if (host) 5021558Srgrimes rmtioctl(MTFSF, dumpnum - 1); 5038871Srgrimes else 5041558Srgrimes#endif 50565786Smjacob if (ioctl(mt, MTIOCTOP, (char *)&tcom) < 0) 5061558Srgrimes fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 5071558Srgrimes} 5081558Srgrimes 5091558Srgrimesvoid 5101558Srgrimesprintdumpinfo() 5111558Srgrimes{ 51285635Sdillon time_t t; 51389572Sdillon t = _time32_to_time(spcl.c_date); 51485635Sdillon fprintf(stdout, "Dump date: %s", ctime(&t)); 51589572Sdillon t = _time32_to_time(spcl.c_ddate); 5161558Srgrimes fprintf(stdout, "Dumped from: %s", 51785635Sdillon (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t)); 5181558Srgrimes if (spcl.c_host[0] == '\0') 5191558Srgrimes return; 52037240Sbde fprintf(stderr, "Level %ld dump of %s on %s:%s\n", 5211558Srgrimes spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 5221558Srgrimes fprintf(stderr, "Label: %s\n", spcl.c_label); 5231558Srgrimes} 5241558Srgrimes 5251558Srgrimesint 5261558Srgrimesextractfile(name) 5271558Srgrimes char *name; 5281558Srgrimes{ 52923685Speter int flags; 53023685Speter mode_t mode; 5311558Srgrimes struct timeval timep[2]; 5321558Srgrimes struct entry *ep; 5331558Srgrimes 5341558Srgrimes curfile.name = name; 5351558Srgrimes curfile.action = USING; 53623685Speter timep[0].tv_sec = curfile.dip->di_atime; 53723685Speter timep[0].tv_usec = curfile.dip->di_atimensec / 1000; 53823685Speter timep[1].tv_sec = curfile.dip->di_mtime; 53923685Speter timep[1].tv_usec = curfile.dip->di_mtimensec / 1000; 5401558Srgrimes mode = curfile.dip->di_mode; 54123685Speter flags = curfile.dip->di_flags; 5421558Srgrimes switch (mode & IFMT) { 5431558Srgrimes 5441558Srgrimes default: 5451558Srgrimes fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 5461558Srgrimes skipfile(); 5471558Srgrimes return (FAIL); 5481558Srgrimes 5491558Srgrimes case IFSOCK: 5501558Srgrimes vprintf(stdout, "skipped socket %s\n", name); 5511558Srgrimes skipfile(); 5521558Srgrimes return (GOOD); 5531558Srgrimes 5541558Srgrimes case IFDIR: 5551558Srgrimes if (mflag) { 5561558Srgrimes ep = lookupname(name); 5571558Srgrimes if (ep == NULL || ep->e_flags & EXTRACT) 5581558Srgrimes panic("unextracted directory %s\n", name); 5591558Srgrimes skipfile(); 5601558Srgrimes return (GOOD); 5611558Srgrimes } 5621558Srgrimes vprintf(stdout, "extract file %s\n", name); 5631558Srgrimes return (genliteraldir(name, curfile.ino)); 5641558Srgrimes 5651558Srgrimes case IFLNK: 5661558Srgrimes lnkbuf[0] = '\0'; 5671558Srgrimes pathlen = 0; 5681558Srgrimes getfile(xtrlnkfile, xtrlnkskip); 5691558Srgrimes if (pathlen == 0) { 5701558Srgrimes vprintf(stdout, 5711558Srgrimes "%s: zero length symbolic link (ignored)\n", name); 5721558Srgrimes return (GOOD); 5731558Srgrimes } 5741558Srgrimes return (linkit(lnkbuf, name, SYMLINK)); 5751558Srgrimes 5766305Smartin case IFIFO: 57723685Speter vprintf(stdout, "extract fifo %s\n", name); 57823685Speter if (Nflag) { 57923685Speter skipfile(); 58023685Speter return (GOOD); 58123685Speter } 58235852Sjkh if (uflag && !Nflag) 58335852Sjkh (void)unlink(name); 5846305Smartin if (mkfifo(name, mode) < 0) { 58523685Speter fprintf(stderr, "%s: cannot create fifo: %s\n", 58623685Speter name, strerror(errno)); 5876305Smartin skipfile(); 5886305Smartin return (FAIL); 5896305Smartin } 5906305Smartin (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 5916305Smartin (void) chmod(name, mode); 59263283Sdwmalone utimes(name, timep); 59323685Speter (void) chflags(name, flags); 5946305Smartin skipfile(); 5956305Smartin return (GOOD); 5966305Smartin 5971558Srgrimes case IFCHR: 5981558Srgrimes case IFBLK: 5991558Srgrimes vprintf(stdout, "extract special file %s\n", name); 6001558Srgrimes if (Nflag) { 6011558Srgrimes skipfile(); 6021558Srgrimes return (GOOD); 6031558Srgrimes } 60435852Sjkh if (uflag) 60535852Sjkh (void)unlink(name); 6061558Srgrimes if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { 6071558Srgrimes fprintf(stderr, "%s: cannot create special file: %s\n", 6081558Srgrimes name, strerror(errno)); 6091558Srgrimes skipfile(); 6101558Srgrimes return (FAIL); 6111558Srgrimes } 6121558Srgrimes (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 6131558Srgrimes (void) chmod(name, mode); 61463283Sdwmalone utimes(name, timep); 61523685Speter (void) chflags(name, flags); 6161558Srgrimes skipfile(); 6171558Srgrimes return (GOOD); 6181558Srgrimes 6191558Srgrimes case IFREG: 6201558Srgrimes vprintf(stdout, "extract file %s\n", name); 6211558Srgrimes if (Nflag) { 6221558Srgrimes skipfile(); 6231558Srgrimes return (GOOD); 6241558Srgrimes } 62535852Sjkh if (uflag) 62635852Sjkh (void)unlink(name); 62721149Simp if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 62821149Simp 0666)) < 0) { 6291558Srgrimes fprintf(stderr, "%s: cannot create file: %s\n", 6301558Srgrimes name, strerror(errno)); 6311558Srgrimes skipfile(); 6321558Srgrimes return (FAIL); 6331558Srgrimes } 6341558Srgrimes (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); 6351558Srgrimes (void) fchmod(ofile, mode); 6361558Srgrimes getfile(xtrfile, xtrskip); 6371558Srgrimes (void) close(ofile); 6381558Srgrimes utimes(name, timep); 63963283Sdwmalone (void) chflags(name, flags); 6401558Srgrimes return (GOOD); 6411558Srgrimes } 6421558Srgrimes /* NOTREACHED */ 6431558Srgrimes} 6441558Srgrimes 6451558Srgrimes/* 6461558Srgrimes * skip over bit maps on the tape 6471558Srgrimes */ 6481558Srgrimesvoid 6491558Srgrimesskipmaps() 6501558Srgrimes{ 6511558Srgrimes 6521558Srgrimes while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 6531558Srgrimes skipfile(); 6541558Srgrimes} 6551558Srgrimes 6561558Srgrimes/* 6571558Srgrimes * skip over a file on the tape 6581558Srgrimes */ 6591558Srgrimesvoid 6601558Srgrimesskipfile() 6611558Srgrimes{ 6621558Srgrimes 6631558Srgrimes curfile.action = SKIP; 6641558Srgrimes getfile(xtrnull, xtrnull); 6651558Srgrimes} 6661558Srgrimes 6671558Srgrimes/* 6681558Srgrimes * Extract a file from the tape. 6691558Srgrimes * When an allocated block is found it is passed to the fill function; 6701558Srgrimes * when an unallocated block (hole) is found, a zeroed buffer is passed 6711558Srgrimes * to the skip function. 6721558Srgrimes */ 6731558Srgrimesvoid 6741558Srgrimesgetfile(fill, skip) 6751558Srgrimes void (*fill) __P((char *, long)); 6761558Srgrimes void (*skip) __P((char *, long)); 6771558Srgrimes{ 6781558Srgrimes register int i; 6791558Srgrimes int curblk = 0; 68023685Speter quad_t size = spcl.c_dinode.di_size; 6811558Srgrimes static char clearedbuf[MAXBSIZE]; 6821558Srgrimes char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 6831558Srgrimes char junk[TP_BSIZE]; 6841558Srgrimes 6851558Srgrimes if (spcl.c_type == TS_END) 6861558Srgrimes panic("ran off end of tape\n"); 6871558Srgrimes if (spcl.c_magic != NFS_MAGIC) 6881558Srgrimes panic("not at beginning of a file\n"); 6891558Srgrimes if (!gettingfile && setjmp(restart) != 0) 6901558Srgrimes return; 6911558Srgrimes gettingfile++; 6921558Srgrimesloop: 6931558Srgrimes for (i = 0; i < spcl.c_count; i++) { 69437923Simp if (readmapflag || spcl.c_addr[i]) { 6951558Srgrimes readtape(&buf[curblk++][0]); 6961558Srgrimes if (curblk == fssize / TP_BSIZE) { 69723685Speter (*fill)((char *)buf, (long)(size > TP_BSIZE ? 69823685Speter fssize : (curblk - 1) * TP_BSIZE + size)); 6991558Srgrimes curblk = 0; 7001558Srgrimes } 7011558Srgrimes } else { 7021558Srgrimes if (curblk > 0) { 70323685Speter (*fill)((char *)buf, (long)(size > TP_BSIZE ? 70423685Speter curblk * TP_BSIZE : 70523685Speter (curblk - 1) * TP_BSIZE + size)); 7061558Srgrimes curblk = 0; 7071558Srgrimes } 70823685Speter (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 70923685Speter TP_BSIZE : size)); 7101558Srgrimes } 7111558Srgrimes if ((size -= TP_BSIZE) <= 0) { 7121558Srgrimes for (i++; i < spcl.c_count; i++) 71337923Simp if (readmapflag || spcl.c_addr[i]) 7141558Srgrimes readtape(junk); 7151558Srgrimes break; 7161558Srgrimes } 7171558Srgrimes } 7181558Srgrimes if (gethead(&spcl) == GOOD && size > 0) { 7191558Srgrimes if (spcl.c_type == TS_ADDR) 7201558Srgrimes goto loop; 7211558Srgrimes dprintf(stdout, 72237240Sbde "Missing address (header) block for %s at %ld blocks\n", 7231558Srgrimes curfile.name, blksread); 7241558Srgrimes } 7251558Srgrimes if (curblk > 0) 72623685Speter (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size)); 7271558Srgrimes findinode(&spcl); 7281558Srgrimes gettingfile = 0; 7291558Srgrimes} 7301558Srgrimes 7311558Srgrimes/* 7321558Srgrimes * Write out the next block of a file. 7331558Srgrimes */ 7341558Srgrimesstatic void 7351558Srgrimesxtrfile(buf, size) 7361558Srgrimes char *buf; 7371558Srgrimes long size; 7381558Srgrimes{ 7391558Srgrimes 7401558Srgrimes if (Nflag) 7411558Srgrimes return; 7421558Srgrimes if (write(ofile, buf, (int) size) == -1) { 7431558Srgrimes fprintf(stderr, 7441558Srgrimes "write error extracting inode %d, name %s\nwrite: %s\n", 7451558Srgrimes curfile.ino, curfile.name, strerror(errno)); 7461558Srgrimes } 7471558Srgrimes} 7481558Srgrimes 7491558Srgrimes/* 7501558Srgrimes * Skip over a hole in a file. 7511558Srgrimes */ 7521558Srgrimes/* ARGSUSED */ 7531558Srgrimesstatic void 7541558Srgrimesxtrskip(buf, size) 7551558Srgrimes char *buf; 7561558Srgrimes long size; 7571558Srgrimes{ 7581558Srgrimes 7591558Srgrimes if (lseek(ofile, size, SEEK_CUR) == -1) { 7601558Srgrimes fprintf(stderr, 7611558Srgrimes "seek error extracting inode %d, name %s\nlseek: %s\n", 7621558Srgrimes curfile.ino, curfile.name, strerror(errno)); 7631558Srgrimes done(1); 7641558Srgrimes } 7651558Srgrimes} 7661558Srgrimes 7671558Srgrimes/* 7681558Srgrimes * Collect the next block of a symbolic link. 7691558Srgrimes */ 7701558Srgrimesstatic void 7711558Srgrimesxtrlnkfile(buf, size) 7721558Srgrimes char *buf; 7731558Srgrimes long size; 7741558Srgrimes{ 7751558Srgrimes 7761558Srgrimes pathlen += size; 7771558Srgrimes if (pathlen > MAXPATHLEN) { 7781558Srgrimes fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 7791558Srgrimes curfile.name, lnkbuf, buf, pathlen); 7801558Srgrimes done(1); 7811558Srgrimes } 7821558Srgrimes (void) strcat(lnkbuf, buf); 7831558Srgrimes} 7841558Srgrimes 7851558Srgrimes/* 7861558Srgrimes * Skip over a hole in a symbolic link (should never happen). 7871558Srgrimes */ 7881558Srgrimes/* ARGSUSED */ 7891558Srgrimesstatic void 7901558Srgrimesxtrlnkskip(buf, size) 7911558Srgrimes char *buf; 7921558Srgrimes long size; 7931558Srgrimes{ 7941558Srgrimes 7951558Srgrimes fprintf(stderr, "unallocated block in symbolic link %s\n", 7961558Srgrimes curfile.name); 7971558Srgrimes done(1); 7981558Srgrimes} 7991558Srgrimes 8001558Srgrimes/* 8011558Srgrimes * Collect the next block of a bit map. 8021558Srgrimes */ 8031558Srgrimesstatic void 8041558Srgrimesxtrmap(buf, size) 8051558Srgrimes char *buf; 8061558Srgrimes long size; 8071558Srgrimes{ 8081558Srgrimes 80923685Speter memmove(map, buf, size); 8101558Srgrimes map += size; 8111558Srgrimes} 8121558Srgrimes 8131558Srgrimes/* 8141558Srgrimes * Skip over a hole in a bit map (should never happen). 8151558Srgrimes */ 8161558Srgrimes/* ARGSUSED */ 8171558Srgrimesstatic void 8181558Srgrimesxtrmapskip(buf, size) 8191558Srgrimes char *buf; 8201558Srgrimes long size; 8211558Srgrimes{ 8221558Srgrimes 8231558Srgrimes panic("hole in map\n"); 8241558Srgrimes map += size; 8251558Srgrimes} 8261558Srgrimes 8271558Srgrimes/* 8281558Srgrimes * Noop, when an extraction function is not needed. 8291558Srgrimes */ 8301558Srgrimes/* ARGSUSED */ 8311558Srgrimesvoid 8321558Srgrimesxtrnull(buf, size) 8331558Srgrimes char *buf; 8341558Srgrimes long size; 8351558Srgrimes{ 8361558Srgrimes 8371558Srgrimes return; 8381558Srgrimes} 8391558Srgrimes 8401558Srgrimes/* 8411558Srgrimes * Read TP_BSIZE blocks from the input. 8421558Srgrimes * Handle read errors, and end of media. 8431558Srgrimes */ 8441558Srgrimesstatic void 8451558Srgrimesreadtape(buf) 8461558Srgrimes char *buf; 8471558Srgrimes{ 8481558Srgrimes long rd, newvol, i; 8491558Srgrimes int cnt, seek_failed; 8501558Srgrimes 8511558Srgrimes if (blkcnt < numtrec) { 85223685Speter memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 8531558Srgrimes blksread++; 8541558Srgrimes tpblksread++; 8551558Srgrimes return; 8561558Srgrimes } 8571558Srgrimes for (i = 0; i < ntrec; i++) 8581558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 8591558Srgrimes if (numtrec == 0) 8601558Srgrimes numtrec = ntrec; 8611558Srgrimes cnt = ntrec * TP_BSIZE; 8621558Srgrimes rd = 0; 8631558Srgrimesgetmore: 8641558Srgrimes#ifdef RRESTORE 8651558Srgrimes if (host) 8661558Srgrimes i = rmtread(&tapebuf[rd], cnt); 8671558Srgrimes else 8681558Srgrimes#endif 8691558Srgrimes i = read(mt, &tapebuf[rd], cnt); 8701558Srgrimes /* 8711558Srgrimes * Check for mid-tape short read error. 8721558Srgrimes * If found, skip rest of buffer and start with the next. 8731558Srgrimes */ 8741558Srgrimes if (!pipein && numtrec < ntrec && i > 0) { 8751558Srgrimes dprintf(stdout, "mid-media short read error.\n"); 8761558Srgrimes numtrec = ntrec; 8771558Srgrimes } 8781558Srgrimes /* 8791558Srgrimes * Handle partial block read. 8801558Srgrimes */ 8811558Srgrimes if (pipein && i == 0 && rd > 0) 8821558Srgrimes i = rd; 8831558Srgrimes else if (i > 0 && i != ntrec * TP_BSIZE) { 8841558Srgrimes if (pipein) { 8851558Srgrimes rd += i; 8861558Srgrimes cnt -= i; 8871558Srgrimes if (cnt > 0) 8881558Srgrimes goto getmore; 8891558Srgrimes i = rd; 8901558Srgrimes } else { 8911558Srgrimes /* 8921558Srgrimes * Short read. Process the blocks read. 8931558Srgrimes */ 8941558Srgrimes if (i % TP_BSIZE != 0) 8951558Srgrimes vprintf(stdout, 89637240Sbde "partial block read: %ld should be %ld\n", 8971558Srgrimes i, ntrec * TP_BSIZE); 8981558Srgrimes numtrec = i / TP_BSIZE; 8991558Srgrimes } 9001558Srgrimes } 9011558Srgrimes /* 9021558Srgrimes * Handle read error. 9031558Srgrimes */ 9041558Srgrimes if (i < 0) { 9051558Srgrimes fprintf(stderr, "Tape read error while "); 9061558Srgrimes switch (curfile.action) { 9071558Srgrimes default: 9081558Srgrimes fprintf(stderr, "trying to set up tape\n"); 9091558Srgrimes break; 9101558Srgrimes case UNKNOWN: 9111558Srgrimes fprintf(stderr, "trying to resynchronize\n"); 9121558Srgrimes break; 9131558Srgrimes case USING: 9141558Srgrimes fprintf(stderr, "restoring %s\n", curfile.name); 9151558Srgrimes break; 9161558Srgrimes case SKIP: 9171558Srgrimes fprintf(stderr, "skipping over inode %d\n", 9181558Srgrimes curfile.ino); 9191558Srgrimes break; 9201558Srgrimes } 9211558Srgrimes if (!yflag && !reply("continue")) 9221558Srgrimes done(1); 9231558Srgrimes i = ntrec * TP_BSIZE; 92423685Speter memset(tapebuf, 0, i); 9251558Srgrimes#ifdef RRESTORE 9261558Srgrimes if (host) 9271558Srgrimes seek_failed = (rmtseek(i, 1) < 0); 9281558Srgrimes else 9291558Srgrimes#endif 9301558Srgrimes seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 9311558Srgrimes 9321558Srgrimes if (seek_failed) { 9331558Srgrimes fprintf(stderr, 9341558Srgrimes "continuation failed: %s\n", strerror(errno)); 9351558Srgrimes done(1); 9361558Srgrimes } 9371558Srgrimes } 9381558Srgrimes /* 9391558Srgrimes * Handle end of tape. 9401558Srgrimes */ 9411558Srgrimes if (i == 0) { 9421558Srgrimes vprintf(stdout, "End-of-tape encountered\n"); 9431558Srgrimes if (!pipein) { 9441558Srgrimes newvol = volno + 1; 9451558Srgrimes volno = 0; 9461558Srgrimes numtrec = 0; 9471558Srgrimes getvol(newvol); 9481558Srgrimes readtape(buf); 9491558Srgrimes return; 9501558Srgrimes } 9511558Srgrimes if (rd % TP_BSIZE != 0) 9521558Srgrimes panic("partial block read: %d should be %d\n", 9531558Srgrimes rd, ntrec * TP_BSIZE); 9541558Srgrimes terminateinput(); 95523685Speter memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 9561558Srgrimes } 9571558Srgrimes blkcnt = 0; 95823685Speter memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 9591558Srgrimes blksread++; 9601558Srgrimes tpblksread++; 9611558Srgrimes} 9621558Srgrimes 9631558Srgrimesstatic void 9641558Srgrimesfindtapeblksize() 9651558Srgrimes{ 9661558Srgrimes register long i; 9671558Srgrimes 9681558Srgrimes for (i = 0; i < ntrec; i++) 9691558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 9701558Srgrimes blkcnt = 0; 9711558Srgrimes#ifdef RRESTORE 9721558Srgrimes if (host) 9731558Srgrimes i = rmtread(tapebuf, ntrec * TP_BSIZE); 9741558Srgrimes else 9751558Srgrimes#endif 9761558Srgrimes i = read(mt, tapebuf, ntrec * TP_BSIZE); 9771558Srgrimes 9781558Srgrimes if (i <= 0) { 9791558Srgrimes fprintf(stderr, "tape read error: %s\n", strerror(errno)); 9801558Srgrimes done(1); 9811558Srgrimes } 9821558Srgrimes if (i % TP_BSIZE != 0) { 98337240Sbde fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 9841558Srgrimes i, "is not a multiple of dump block size", TP_BSIZE); 9851558Srgrimes done(1); 9861558Srgrimes } 9871558Srgrimes ntrec = i / TP_BSIZE; 9881558Srgrimes numtrec = ntrec; 98937240Sbde vprintf(stdout, "Tape block size is %ld\n", ntrec); 9901558Srgrimes} 9911558Srgrimes 9921558Srgrimesvoid 9931558Srgrimesclosemt() 9941558Srgrimes{ 9951558Srgrimes 9961558Srgrimes if (mt < 0) 9971558Srgrimes return; 9981558Srgrimes#ifdef RRESTORE 9991558Srgrimes if (host) 10001558Srgrimes rmtclose(); 10011558Srgrimes else 10021558Srgrimes#endif 10031558Srgrimes (void) close(mt); 10041558Srgrimes} 10051558Srgrimes 10061558Srgrimes/* 10071558Srgrimes * Read the next block from the tape. 10081558Srgrimes * Check to see if it is one of several vintage headers. 10091558Srgrimes * If it is an old style header, convert it to a new style header. 10101558Srgrimes * If it is not any valid header, return an error. 10111558Srgrimes */ 10121558Srgrimesstatic int 10131558Srgrimesgethead(buf) 10141558Srgrimes struct s_spcl *buf; 10151558Srgrimes{ 10161558Srgrimes long i; 10171558Srgrimes union { 10181558Srgrimes quad_t qval; 101940668Sdima int32_t val[2]; 10201558Srgrimes } qcvt; 10211558Srgrimes union u_ospcl { 10221558Srgrimes char dummy[TP_BSIZE]; 10231558Srgrimes struct s_ospcl { 102440668Sdima int32_t c_type; 102540668Sdima int32_t c_date; 102640668Sdima int32_t c_ddate; 102740668Sdima int32_t c_volume; 102840668Sdima int32_t c_tapea; 10291558Srgrimes u_short c_inumber; 103040668Sdima int32_t c_magic; 103140668Sdima int32_t c_checksum; 10321558Srgrimes struct odinode { 10331558Srgrimes unsigned short odi_mode; 10341558Srgrimes u_short odi_nlink; 10351558Srgrimes u_short odi_uid; 10361558Srgrimes u_short odi_gid; 103740668Sdima int32_t odi_size; 103840668Sdima int32_t odi_rdev; 10391558Srgrimes char odi_addr[36]; 104040668Sdima int32_t odi_atime; 104140668Sdima int32_t odi_mtime; 104240668Sdima int32_t odi_ctime; 10431558Srgrimes } c_dinode; 104440668Sdima int32_t c_count; 10451558Srgrimes char c_addr[256]; 10461558Srgrimes } s_ospcl; 10471558Srgrimes } u_ospcl; 10481558Srgrimes 10491558Srgrimes if (!cvtflag) { 10501558Srgrimes readtape((char *)buf); 10511558Srgrimes if (buf->c_magic != NFS_MAGIC) { 10521558Srgrimes if (swabl(buf->c_magic) != NFS_MAGIC) 10531558Srgrimes return (FAIL); 10541558Srgrimes if (!Bcvt) { 10551558Srgrimes vprintf(stdout, "Note: Doing Byte swapping\n"); 10561558Srgrimes Bcvt = 1; 10571558Srgrimes } 10581558Srgrimes } 10591558Srgrimes if (checksum((int *)buf) == FAIL) 10601558Srgrimes return (FAIL); 106123096Simp if (Bcvt) { 10621558Srgrimes swabst((u_char *)"8l4s31l", (u_char *)buf); 106323096Simp swabst((u_char *)"l",(u_char *) &buf->c_level); 106423096Simp swabst((u_char *)"2l",(u_char *) &buf->c_flags); 106523096Simp } 10661558Srgrimes goto good; 10671558Srgrimes } 10681558Srgrimes readtape((char *)(&u_ospcl.s_ospcl)); 106923685Speter memset(buf, 0, (long)TP_BSIZE); 10701558Srgrimes buf->c_type = u_ospcl.s_ospcl.c_type; 10711558Srgrimes buf->c_date = u_ospcl.s_ospcl.c_date; 10721558Srgrimes buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 10731558Srgrimes buf->c_volume = u_ospcl.s_ospcl.c_volume; 10741558Srgrimes buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 10751558Srgrimes buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 10761558Srgrimes buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 10771558Srgrimes buf->c_magic = u_ospcl.s_ospcl.c_magic; 10781558Srgrimes buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 10791558Srgrimes buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 10801558Srgrimes buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 10811558Srgrimes buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 10821558Srgrimes buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; 10831558Srgrimes buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 108423685Speter buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; 108523685Speter buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; 108623685Speter buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; 10871558Srgrimes buf->c_count = u_ospcl.s_ospcl.c_count; 108823685Speter memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256); 10891558Srgrimes if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || 10901558Srgrimes checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) 10911558Srgrimes return(FAIL); 10921558Srgrimes buf->c_magic = NFS_MAGIC; 10931558Srgrimes 10941558Srgrimesgood: 10951558Srgrimes if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) && 10961558Srgrimes (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) { 10971558Srgrimes qcvt.qval = buf->c_dinode.di_size; 10981558Srgrimes if (qcvt.val[0] || qcvt.val[1]) { 10991558Srgrimes printf("Note: Doing Quad swapping\n"); 11001558Srgrimes Qcvt = 1; 11011558Srgrimes } 11021558Srgrimes } 11031558Srgrimes if (Qcvt) { 11041558Srgrimes qcvt.qval = buf->c_dinode.di_size; 11051558Srgrimes i = qcvt.val[1]; 11061558Srgrimes qcvt.val[1] = qcvt.val[0]; 11071558Srgrimes qcvt.val[0] = i; 11081558Srgrimes buf->c_dinode.di_size = qcvt.qval; 11091558Srgrimes } 111037923Simp readmapflag = 0; 11111558Srgrimes 11121558Srgrimes switch (buf->c_type) { 11131558Srgrimes 11141558Srgrimes case TS_CLRI: 11151558Srgrimes case TS_BITS: 11161558Srgrimes /* 11171558Srgrimes * Have to patch up missing information in bit map headers 11181558Srgrimes */ 11191558Srgrimes buf->c_inumber = 0; 11201558Srgrimes buf->c_dinode.di_size = buf->c_count * TP_BSIZE; 112137923Simp if (buf->c_count > TP_NINDIR) 112237923Simp readmapflag = 1; 112337923Simp else 112437923Simp for (i = 0; i < buf->c_count; i++) 112537923Simp buf->c_addr[i]++; 11261558Srgrimes break; 11271558Srgrimes 11281558Srgrimes case TS_TAPE: 11291558Srgrimes if ((buf->c_flags & DR_NEWINODEFMT) == 0) 11301558Srgrimes oldinofmt = 1; 11311558Srgrimes /* fall through */ 11321558Srgrimes case TS_END: 11331558Srgrimes buf->c_inumber = 0; 11341558Srgrimes break; 11351558Srgrimes 11361558Srgrimes case TS_INODE: 11371558Srgrimes case TS_ADDR: 11381558Srgrimes break; 11391558Srgrimes 11401558Srgrimes default: 11411558Srgrimes panic("gethead: unknown inode type %d\n", buf->c_type); 11421558Srgrimes break; 11431558Srgrimes } 11441558Srgrimes /* 11458871Srgrimes * If we are restoring a filesystem with old format inodes, 11461558Srgrimes * copy the uid/gid to the new location. 11471558Srgrimes */ 11481558Srgrimes if (oldinofmt) { 11491558Srgrimes buf->c_dinode.di_uid = buf->c_dinode.di_ouid; 11501558Srgrimes buf->c_dinode.di_gid = buf->c_dinode.di_ogid; 11511558Srgrimes } 11521558Srgrimes if (dflag) 11531558Srgrimes accthdr(buf); 11541558Srgrimes return(GOOD); 11551558Srgrimes} 11561558Srgrimes 11571558Srgrimes/* 11581558Srgrimes * Check that a header is where it belongs and predict the next header 11591558Srgrimes */ 11601558Srgrimesstatic void 11611558Srgrimesaccthdr(header) 11621558Srgrimes struct s_spcl *header; 11631558Srgrimes{ 11641558Srgrimes static ino_t previno = 0x7fffffff; 11651558Srgrimes static int prevtype; 11661558Srgrimes static long predict; 11671558Srgrimes long blks, i; 11681558Srgrimes 11691558Srgrimes if (header->c_type == TS_TAPE) { 11701558Srgrimes fprintf(stderr, "Volume header (%s inode format) ", 11711558Srgrimes oldinofmt ? "old" : "new"); 11721558Srgrimes if (header->c_firstrec) 117337240Sbde fprintf(stderr, "begins with record %ld", 11741558Srgrimes header->c_firstrec); 11751558Srgrimes fprintf(stderr, "\n"); 11761558Srgrimes previno = 0x7fffffff; 11771558Srgrimes return; 11781558Srgrimes } 11791558Srgrimes if (previno == 0x7fffffff) 11801558Srgrimes goto newcalc; 11811558Srgrimes switch (prevtype) { 11821558Srgrimes case TS_BITS: 118323685Speter fprintf(stderr, "Dumped inodes map header"); 11841558Srgrimes break; 11851558Srgrimes case TS_CLRI: 118623685Speter fprintf(stderr, "Used inodes map header"); 11871558Srgrimes break; 11881558Srgrimes case TS_INODE: 11891558Srgrimes fprintf(stderr, "File header, ino %d", previno); 11901558Srgrimes break; 11911558Srgrimes case TS_ADDR: 11921558Srgrimes fprintf(stderr, "File continuation header, ino %d", previno); 11931558Srgrimes break; 11941558Srgrimes case TS_END: 11951558Srgrimes fprintf(stderr, "End of tape header"); 11961558Srgrimes break; 11971558Srgrimes } 11981558Srgrimes if (predict != blksread - 1) 119937240Sbde fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 12001558Srgrimes predict, blksread - 1); 12011558Srgrimes fprintf(stderr, "\n"); 12021558Srgrimesnewcalc: 12031558Srgrimes blks = 0; 12041558Srgrimes if (header->c_type != TS_END) 12051558Srgrimes for (i = 0; i < header->c_count; i++) 120637923Simp if (readmapflag || header->c_addr[i] != 0) 12071558Srgrimes blks++; 12081558Srgrimes predict = blks; 12091558Srgrimes blksread = 0; 12101558Srgrimes prevtype = header->c_type; 12111558Srgrimes previno = header->c_inumber; 12121558Srgrimes} 12131558Srgrimes 12141558Srgrimes/* 12151558Srgrimes * Find an inode header. 121690573Siedowse * Complain if had to skip. 12171558Srgrimes */ 12181558Srgrimesstatic void 12191558Srgrimesfindinode(header) 12201558Srgrimes struct s_spcl *header; 12211558Srgrimes{ 12221558Srgrimes static long skipcnt = 0; 12231558Srgrimes long i; 12241558Srgrimes char buf[TP_BSIZE]; 12251558Srgrimes 12261558Srgrimes curfile.name = "<name unknown>"; 12271558Srgrimes curfile.action = UNKNOWN; 12281558Srgrimes curfile.dip = NULL; 12291558Srgrimes curfile.ino = 0; 12301558Srgrimes do { 12311558Srgrimes if (header->c_magic != NFS_MAGIC) { 12321558Srgrimes skipcnt++; 12331558Srgrimes while (gethead(header) == FAIL || 123489572Sdillon _time32_to_time(header->c_date) != dumpdate) 12351558Srgrimes skipcnt++; 12361558Srgrimes } 12371558Srgrimes switch (header->c_type) { 12381558Srgrimes 12391558Srgrimes case TS_ADDR: 12401558Srgrimes /* 12411558Srgrimes * Skip up to the beginning of the next record 12421558Srgrimes */ 12431558Srgrimes for (i = 0; i < header->c_count; i++) 12441558Srgrimes if (header->c_addr[i]) 12451558Srgrimes readtape(buf); 12461558Srgrimes while (gethead(header) == FAIL || 124789572Sdillon _time32_to_time(header->c_date) != dumpdate) 12481558Srgrimes skipcnt++; 12491558Srgrimes break; 12501558Srgrimes 12511558Srgrimes case TS_INODE: 12521558Srgrimes curfile.dip = &header->c_dinode; 12531558Srgrimes curfile.ino = header->c_inumber; 12541558Srgrimes break; 12551558Srgrimes 12561558Srgrimes case TS_END: 12571558Srgrimes curfile.ino = maxino; 12581558Srgrimes break; 12591558Srgrimes 12601558Srgrimes case TS_CLRI: 12611558Srgrimes curfile.name = "<file removal list>"; 12621558Srgrimes break; 12631558Srgrimes 12641558Srgrimes case TS_BITS: 12651558Srgrimes curfile.name = "<file dump list>"; 12661558Srgrimes break; 12671558Srgrimes 12681558Srgrimes case TS_TAPE: 12691558Srgrimes panic("unexpected tape header\n"); 12701558Srgrimes /* NOTREACHED */ 12711558Srgrimes 12721558Srgrimes default: 12731558Srgrimes panic("unknown tape header type %d\n", spcl.c_type); 12741558Srgrimes /* NOTREACHED */ 12751558Srgrimes 12761558Srgrimes } 12771558Srgrimes } while (header->c_type == TS_ADDR); 12781558Srgrimes if (skipcnt > 0) 127937240Sbde fprintf(stderr, "resync restore, skipped %ld blocks\n", 128037240Sbde skipcnt); 12811558Srgrimes skipcnt = 0; 12821558Srgrimes} 12831558Srgrimes 12841558Srgrimesstatic int 12851558Srgrimeschecksum(buf) 12861558Srgrimes register int *buf; 12871558Srgrimes{ 12881558Srgrimes register int i, j; 12891558Srgrimes 12901558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 12911558Srgrimes i = 0; 12921558Srgrimes if(!Bcvt) { 12931558Srgrimes do 12941558Srgrimes i += *buf++; 12951558Srgrimes while (--j); 12961558Srgrimes } else { 12971558Srgrimes /* What happens if we want to read restore tapes 12981558Srgrimes for a 16bit int machine??? */ 12998871Srgrimes do 13001558Srgrimes i += swabl(*buf++); 13011558Srgrimes while (--j); 13021558Srgrimes } 13038871Srgrimes 13041558Srgrimes if (i != CHECKSUM) { 13051558Srgrimes fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 13061558Srgrimes curfile.ino, curfile.name); 13071558Srgrimes return(FAIL); 13081558Srgrimes } 13091558Srgrimes return(GOOD); 13101558Srgrimes} 13111558Srgrimes 13121558Srgrimes#ifdef RRESTORE 13131558Srgrimes#if __STDC__ 13141558Srgrimes#include <stdarg.h> 13151558Srgrimes#else 13161558Srgrimes#include <varargs.h> 13171558Srgrimes#endif 13181558Srgrimes 13191558Srgrimesvoid 13201558Srgrimes#if __STDC__ 13211558Srgrimesmsg(const char *fmt, ...) 13221558Srgrimes#else 13231558Srgrimesmsg(fmt, va_alist) 13241558Srgrimes char *fmt; 13251558Srgrimes va_dcl 13261558Srgrimes#endif 13271558Srgrimes{ 13281558Srgrimes va_list ap; 13291558Srgrimes#if __STDC__ 13301558Srgrimes va_start(ap, fmt); 13311558Srgrimes#else 13321558Srgrimes va_start(ap); 13331558Srgrimes#endif 13341558Srgrimes (void)vfprintf(stderr, fmt, ap); 13351558Srgrimes va_end(ap); 13361558Srgrimes} 13371558Srgrimes#endif /* RRESTORE */ 13381558Srgrimes 13391558Srgrimesstatic u_char * 13401558Srgrimesswabshort(sp, n) 13411558Srgrimes register u_char *sp; 13421558Srgrimes register int n; 13431558Srgrimes{ 13441558Srgrimes char c; 13451558Srgrimes 13461558Srgrimes while (--n >= 0) { 13471558Srgrimes c = sp[0]; sp[0] = sp[1]; sp[1] = c; 13481558Srgrimes sp += 2; 13491558Srgrimes } 13501558Srgrimes return (sp); 13511558Srgrimes} 13521558Srgrimes 13531558Srgrimesstatic u_char * 13541558Srgrimesswablong(sp, n) 13551558Srgrimes register u_char *sp; 13561558Srgrimes register int n; 13571558Srgrimes{ 13581558Srgrimes char c; 13591558Srgrimes 13601558Srgrimes while (--n >= 0) { 13611558Srgrimes c = sp[0]; sp[0] = sp[3]; sp[3] = c; 13621558Srgrimes c = sp[2]; sp[2] = sp[1]; sp[1] = c; 13631558Srgrimes sp += 4; 13641558Srgrimes } 13651558Srgrimes return (sp); 13661558Srgrimes} 13671558Srgrimes 13681558Srgrimesvoid 13691558Srgrimesswabst(cp, sp) 13701558Srgrimes register u_char *cp, *sp; 13711558Srgrimes{ 13721558Srgrimes int n = 0; 13731558Srgrimes 13741558Srgrimes while (*cp) { 13751558Srgrimes switch (*cp) { 13761558Srgrimes case '0': case '1': case '2': case '3': case '4': 13771558Srgrimes case '5': case '6': case '7': case '8': case '9': 13781558Srgrimes n = (n * 10) + (*cp++ - '0'); 13791558Srgrimes continue; 13808871Srgrimes 13811558Srgrimes case 's': case 'w': case 'h': 13821558Srgrimes if (n == 0) 13831558Srgrimes n = 1; 13841558Srgrimes sp = swabshort(sp, n); 13851558Srgrimes break; 13861558Srgrimes 13871558Srgrimes case 'l': 13881558Srgrimes if (n == 0) 13891558Srgrimes n = 1; 13901558Srgrimes sp = swablong(sp, n); 13911558Srgrimes break; 13921558Srgrimes 13931558Srgrimes default: /* Any other character, like 'b' counts as byte. */ 13941558Srgrimes if (n == 0) 13951558Srgrimes n = 1; 13961558Srgrimes sp += n; 13971558Srgrimes break; 13981558Srgrimes } 13991558Srgrimes cp++; 14001558Srgrimes n = 0; 14011558Srgrimes } 14021558Srgrimes} 14031558Srgrimes 14041558Srgrimesstatic u_long 14051558Srgrimesswabl(x) 14061558Srgrimes u_long x; 14071558Srgrimes{ 14081558Srgrimes swabst((u_char *)"l", (u_char *)&x); 14091558Srgrimes return (x); 14101558Srgrimes} 1411