tape.c revision 167259
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 167259 2007-03-06 08:13:21Z mckusick $"); 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> 49167011Smckusick#include <sys/extattr.h> 50167011Smckusick#include <sys/acl.h> 511558Srgrimes 52167259Smckusick#include <ufs/ufs/extattr.h> 531558Srgrimes#include <ufs/ufs/dinode.h> 541558Srgrimes#include <protocols/dumprestore.h> 551558Srgrimes 561558Srgrimes#include <errno.h> 57103949Smike#include <limits.h> 5873986Sobrien#include <paths.h> 591558Srgrimes#include <setjmp.h> 60164911Sdwmalone#include <stdint.h> 611558Srgrimes#include <stdio.h> 621558Srgrimes#include <stdlib.h> 631558Srgrimes#include <string.h> 6466907Swollman#include <time.h> 65129665Sstefanf#include <timeconv.h> 661558Srgrimes#include <unistd.h> 671558Srgrimes 681558Srgrimes#include "restore.h" 691558Srgrimes#include "extern.h" 701558Srgrimes 711558Srgrimesstatic long fssize = MAXBSIZE; 721558Srgrimesstatic int mt = -1; 731558Srgrimesstatic int pipein = 0; 74128175Sgreenstatic int pipecmdin = 0; 75128175Sgreenstatic FILE *popenfp = NULL; 7621174Sguidostatic char *magtape; 771558Srgrimesstatic int blkcnt; 781558Srgrimesstatic int numtrec; 791558Srgrimesstatic char *tapebuf; 801558Srgrimesstatic union u_spcl endoftapemark; 81164911Sdwmalonestatic long byteslide = 0; 821558Srgrimesstatic long blksread; /* blocks read since last header */ 8398542Smckusickstatic int64_t tapeaddr = 0; /* current TP_BSIZE tape record */ 841558Srgrimesstatic long tapesread; 851558Srgrimesstatic jmp_buf restart; 861558Srgrimesstatic int gettingfile = 0; /* restart has a valid frame */ 871558Srgrimesstatic char *host = NULL; 8898542Smckusickstatic int readmapflag; 891558Srgrimes 901558Srgrimesstatic int ofile; 911558Srgrimesstatic char *map; 921558Srgrimesstatic char lnkbuf[MAXPATHLEN + 1]; 931558Srgrimesstatic int pathlen; 941558Srgrimes 9598542Smckusickint Bcvt; /* Swap Bytes */ 96144099Simpint oldinofmt; /* FreeBSD 1 inode format needs cvt */ 971558Srgrimes 981558Srgrimes#define FLUSHTAPEBUF() blkcnt = ntrec + 1 991558Srgrimes 100167011Smckusickchar *namespace_names[] = EXTATTR_NAMESPACE_NAMES; 101167011Smckusick 10292837Simpstatic void accthdr(struct s_spcl *); 10392837Simpstatic int checksum(int *); 10492837Simpstatic void findinode(struct s_spcl *); 10592837Simpstatic void findtapeblksize(void); 106167011Smckusickstatic char *setupextattr(int); 107167011Smckusickstatic void xtrattr(char *, long); 108167011Smckusickstatic void set_extattr_link(char *, void *, int); 109167011Smckusickstatic void set_extattr_fd(int, char *, void *, int); 11092837Simpstatic int gethead(struct s_spcl *); 11192837Simpstatic void readtape(char *); 11292837Simpstatic void setdumpnum(void); 11392837Simpstatic u_long swabl(u_long); 11492837Simpstatic u_char *swablong(u_char *, int); 11592837Simpstatic u_char *swabshort(u_char *, int); 11692837Simpstatic void terminateinput(void); 11792837Simpstatic void xtrfile(char *, long); 11892837Simpstatic void xtrlnkfile(char *, long); 11992837Simpstatic void xtrlnkskip(char *, long); 12092837Simpstatic void xtrmap(char *, long); 12192837Simpstatic void xtrmapskip(char *, long); 12292837Simpstatic void xtrskip(char *, long); 1231558Srgrimes 1241558Srgrimes/* 1251558Srgrimes * Set up an input source 1261558Srgrimes */ 1271558Srgrimesvoid 128128175Sgreensetinput(char *source, int ispipecommand) 1291558Srgrimes{ 1301558Srgrimes FLUSHTAPEBUF(); 1311558Srgrimes if (bflag) 1321558Srgrimes newtapebuf(ntrec); 1331558Srgrimes else 1341558Srgrimes newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 1351558Srgrimes terminal = stdin; 1361558Srgrimes 137128175Sgreen if (ispipecommand) 138128175Sgreen pipecmdin++; 139128175Sgreen else 1401558Srgrimes#ifdef RRESTORE 14123685Speter if (strchr(source, ':')) { 1421558Srgrimes host = source; 14323685Speter source = strchr(host, ':'); 1441558Srgrimes *source++ = '\0'; 1451558Srgrimes if (rmthost(host) == 0) 1461558Srgrimes done(1); 1471558Srgrimes } else 1481558Srgrimes#endif 1491558Srgrimes if (strcmp(source, "-") == 0) { 1501558Srgrimes /* 1511558Srgrimes * Since input is coming from a pipe we must establish 1521558Srgrimes * our own connection to the terminal. 1531558Srgrimes */ 1541558Srgrimes terminal = fopen(_PATH_TTY, "r"); 1551558Srgrimes if (terminal == NULL) { 1561558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1571558Srgrimes _PATH_TTY, strerror(errno)); 1581558Srgrimes terminal = fopen(_PATH_DEVNULL, "r"); 1591558Srgrimes if (terminal == NULL) { 1601558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1611558Srgrimes _PATH_DEVNULL, strerror(errno)); 1621558Srgrimes done(1); 1631558Srgrimes } 1641558Srgrimes } 1651558Srgrimes pipein++; 1661558Srgrimes } 1671558Srgrimes setuid(getuid()); /* no longer need or want root privileges */ 16821174Sguido magtape = strdup(source); 16921174Sguido if (magtape == NULL) { 17021174Sguido fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 17121174Sguido done(1); 17221174Sguido } 1731558Srgrimes} 1741558Srgrimes 1751558Srgrimesvoid 17692837Simpnewtapebuf(long size) 1771558Srgrimes{ 17892837Simp static int tapebufsize = -1; 1791558Srgrimes 1801558Srgrimes ntrec = size; 1811558Srgrimes if (size <= tapebufsize) 1821558Srgrimes return; 1831558Srgrimes if (tapebuf != NULL) 184164911Sdwmalone free(tapebuf - TP_BSIZE); 185164911Sdwmalone tapebuf = malloc((size+1) * TP_BSIZE); 1861558Srgrimes if (tapebuf == NULL) { 1871558Srgrimes fprintf(stderr, "Cannot allocate space for tape buffer\n"); 1881558Srgrimes done(1); 1891558Srgrimes } 190164911Sdwmalone tapebuf += TP_BSIZE; 1911558Srgrimes tapebufsize = size; 1921558Srgrimes} 1931558Srgrimes 1941558Srgrimes/* 1951558Srgrimes * Verify that the tape drive can be accessed and 1961558Srgrimes * that it actually is a dump tape. 1971558Srgrimes */ 1981558Srgrimesvoid 19992837Simpsetup(void) 2001558Srgrimes{ 2011558Srgrimes int i, j, *ip; 2021558Srgrimes struct stat stbuf; 2031558Srgrimes 2041558Srgrimes vprintf(stdout, "Verify tape and initialize maps\n"); 205128175Sgreen if (pipecmdin) { 206128175Sgreen if (setenv("RESTORE_VOLUME", "1", 1) == -1) { 207128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 208128175Sgreen strerror(errno)); 209128175Sgreen done(1); 210128175Sgreen } 211128175Sgreen popenfp = popen(magtape, "r"); 212128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 213128175Sgreen } else 2141558Srgrimes#ifdef RRESTORE 2151558Srgrimes if (host) 2161558Srgrimes mt = rmtopen(magtape, 0); 2171558Srgrimes else 2181558Srgrimes#endif 2191558Srgrimes if (pipein) 2201558Srgrimes mt = 0; 2211558Srgrimes else 2221558Srgrimes mt = open(magtape, O_RDONLY, 0); 2231558Srgrimes if (mt < 0) { 2241558Srgrimes fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 2251558Srgrimes done(1); 2261558Srgrimes } 2271558Srgrimes volno = 1; 2281558Srgrimes setdumpnum(); 2291558Srgrimes FLUSHTAPEBUF(); 2301558Srgrimes if (!pipein && !bflag) 2311558Srgrimes findtapeblksize(); 2321558Srgrimes if (gethead(&spcl) == FAIL) { 23398542Smckusick fprintf(stderr, "Tape is not a dump tape\n"); 23498542Smckusick done(1); 2351558Srgrimes } 2361558Srgrimes if (pipein) { 23798542Smckusick endoftapemark.s_spcl.c_magic = FS_UFS2_MAGIC; 2381558Srgrimes endoftapemark.s_spcl.c_type = TS_END; 2391558Srgrimes ip = (int *)&endoftapemark; 2401558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 2411558Srgrimes i = 0; 2421558Srgrimes do 2431558Srgrimes i += *ip++; 2441558Srgrimes while (--j); 2451558Srgrimes endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 2461558Srgrimes } 2471558Srgrimes if (vflag || command == 't') 2481558Srgrimes printdumpinfo(); 24998542Smckusick dumptime = _time64_to_time(spcl.c_ddate); 25098542Smckusick dumpdate = _time64_to_time(spcl.c_date); 2511558Srgrimes if (stat(".", &stbuf) < 0) { 2521558Srgrimes fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 2531558Srgrimes done(1); 2541558Srgrimes } 25534851Sjkh if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 25634851Sjkh fssize = TP_BSIZE; 25734851Sjkh if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 2581558Srgrimes fssize = stbuf.st_blksize; 2591558Srgrimes if (((fssize - 1) & fssize) != 0) { 26037240Sbde fprintf(stderr, "bad block size %ld\n", fssize); 2611558Srgrimes done(1); 2621558Srgrimes } 2631558Srgrimes if (spcl.c_volume != 1) { 2641558Srgrimes fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2651558Srgrimes done(1); 2661558Srgrimes } 2671558Srgrimes if (gethead(&spcl) == FAIL) { 26837240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 2691558Srgrimes panic("no header after volume mark!\n"); 2701558Srgrimes } 2711558Srgrimes findinode(&spcl); 2721558Srgrimes if (spcl.c_type != TS_CLRI) { 2731558Srgrimes fprintf(stderr, "Cannot find file removal list\n"); 2741558Srgrimes done(1); 2751558Srgrimes } 2761558Srgrimes maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 2771558Srgrimes dprintf(stdout, "maxino = %d\n", maxino); 2781558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2791558Srgrimes if (map == NULL) 28023685Speter panic("no memory for active inode map\n"); 28123685Speter usedinomap = map; 2821558Srgrimes curfile.action = USING; 283167011Smckusick getfile(xtrmap, xtrmapskip, xtrmapskip); 2841558Srgrimes if (spcl.c_type != TS_BITS) { 2851558Srgrimes fprintf(stderr, "Cannot find file dump list\n"); 2861558Srgrimes done(1); 2871558Srgrimes } 2881558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2891558Srgrimes if (map == (char *)NULL) 2901558Srgrimes panic("no memory for file dump list\n"); 2911558Srgrimes dumpmap = map; 2921558Srgrimes curfile.action = USING; 293167011Smckusick getfile(xtrmap, xtrmapskip, xtrmapskip); 29423685Speter /* 29523685Speter * If there may be whiteout entries on the tape, pretend that the 29623685Speter * whiteout inode exists, so that the whiteout entries can be 29723685Speter * extracted. 29823685Speter */ 29998542Smckusick SETINO(WINO, dumpmap); 30090820Siedowse /* 'r' restores don't call getvol() for tape 1, so mark it as read. */ 30190820Siedowse if (command == 'r') 30290820Siedowse tapesread = 1; 3031558Srgrimes} 3041558Srgrimes 3051558Srgrimes/* 3061558Srgrimes * Prompt user to load a new dump volume. 3071558Srgrimes * "Nextvol" is the next suggested volume to use. 3081558Srgrimes * This suggested volume is enforced when doing full 30937906Scharnier * or incremental restores, but can be overridden by 3101558Srgrimes * the user when only extracting a subset of the files. 3111558Srgrimes */ 3121558Srgrimesvoid 31392837Simpgetvol(long nextvol) 3141558Srgrimes{ 31598542Smckusick int64_t prevtapea; 31698542Smckusick long i, newvol, savecnt; 3171558Srgrimes union u_spcl tmpspcl; 3181558Srgrimes# define tmpbuf tmpspcl.s_spcl 3191558Srgrimes char buf[TP_BSIZE]; 3201558Srgrimes 3211558Srgrimes if (nextvol == 1) { 3221558Srgrimes tapesread = 0; 3231558Srgrimes gettingfile = 0; 3241558Srgrimes } 32590827Siedowse prevtapea = tapeaddr; 32690827Siedowse savecnt = blksread; 3271558Srgrimes if (pipein) { 32869906Siedowse if (nextvol != 1) { 3291558Srgrimes panic("Changing volumes on pipe input?\n"); 33069906Siedowse /* Avoid looping if we couldn't ask the user. */ 33169906Siedowse if (yflag || ferror(terminal) || feof(terminal)) 33269906Siedowse done(1); 33369906Siedowse } 3341558Srgrimes if (volno == 1) 3351558Srgrimes return; 336128175Sgreen if (pipecmdin) { 337128175Sgreen closemt(); 338128175Sgreen goto getpipecmdhdr; 339128175Sgreen } 3401558Srgrimes goto gethdr; 3411558Srgrimes } 3421558Srgrimesagain: 3431558Srgrimes if (pipein) 3441558Srgrimes done(1); /* pipes do not get a second chance */ 34590608Siedowse if (command == 'R' || command == 'r' || curfile.action != SKIP) 3461558Srgrimes newvol = nextvol; 34790608Siedowse else 3481558Srgrimes newvol = 0; 3491558Srgrimes while (newvol <= 0) { 3501558Srgrimes if (tapesread == 0) { 35190820Siedowse fprintf(stderr, "%s%s%s%s%s%s%s", 3521558Srgrimes "You have not read any tapes yet.\n", 35390820Siedowse "If you are extracting just a few files,", 35490820Siedowse " start with the last volume\n", 35590820Siedowse "and work towards the first; restore", 35690820Siedowse " can quickly skip tapes that\n", 35790820Siedowse "have no further files to extract.", 35890820Siedowse " Otherwise, begin with volume 1.\n"); 3591558Srgrimes } else { 3601558Srgrimes fprintf(stderr, "You have read volumes"); 3611558Srgrimes strcpy(buf, ": "); 36290820Siedowse for (i = 0; i < 32; i++) 3631558Srgrimes if (tapesread & (1 << i)) { 36490820Siedowse fprintf(stderr, "%s%ld", buf, i + 1); 3651558Srgrimes strcpy(buf, ", "); 3661558Srgrimes } 3671558Srgrimes fprintf(stderr, "\n"); 3681558Srgrimes } 3691558Srgrimes do { 3701558Srgrimes fprintf(stderr, "Specify next volume #: "); 3711558Srgrimes (void) fflush(stderr); 37269906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 37369906Siedowse done(1); 37469906Siedowse } while (buf[0] == '\n'); 3751558Srgrimes newvol = atoi(buf); 3761558Srgrimes if (newvol <= 0) { 3771558Srgrimes fprintf(stderr, 3781558Srgrimes "Volume numbers are positive numerics\n"); 3791558Srgrimes } 3801558Srgrimes } 3811558Srgrimes if (newvol == volno) { 38290820Siedowse tapesread |= 1 << (volno - 1); 3831558Srgrimes return; 3841558Srgrimes } 3851558Srgrimes closemt(); 38637240Sbde fprintf(stderr, "Mount tape volume %ld\n", newvol); 3871558Srgrimes fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 3881558Srgrimes fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 3891558Srgrimes (void) fflush(stderr); 39069906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 3911558Srgrimes done(1); 3921558Srgrimes if (!strcmp(buf, "none\n")) { 3931558Srgrimes terminateinput(); 3941558Srgrimes return; 3951558Srgrimes } 3961558Srgrimes if (buf[0] != '\n') { 3971558Srgrimes (void) strcpy(magtape, buf); 3981558Srgrimes magtape[strlen(magtape) - 1] = '\0'; 3991558Srgrimes } 400128175Sgreen if (pipecmdin) { 401128175Sgreen char volno[sizeof("2147483647")]; 402128175Sgreen 403128175Sgreengetpipecmdhdr: 404128175Sgreen (void)sprintf(volno, "%d", newvol); 405128175Sgreen if (setenv("RESTORE_VOLUME", volno, 1) == -1) { 406128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 407128175Sgreen strerror(errno)); 408128175Sgreen done(1); 409128175Sgreen } 410128175Sgreen popenfp = popen(magtape, "r"); 411128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 412128175Sgreen } else 4131558Srgrimes#ifdef RRESTORE 4141558Srgrimes if (host) 4151558Srgrimes mt = rmtopen(magtape, 0); 4161558Srgrimes else 4171558Srgrimes#endif 4181558Srgrimes mt = open(magtape, O_RDONLY, 0); 4191558Srgrimes 4201558Srgrimes if (mt == -1) { 4211558Srgrimes fprintf(stderr, "Cannot open %s\n", magtape); 4221558Srgrimes volno = -1; 4231558Srgrimes goto again; 4241558Srgrimes } 4251558Srgrimesgethdr: 4261558Srgrimes volno = newvol; 4271558Srgrimes setdumpnum(); 4281558Srgrimes FLUSHTAPEBUF(); 4291558Srgrimes if (gethead(&tmpbuf) == FAIL) { 43037240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 4311558Srgrimes fprintf(stderr, "tape is not dump tape\n"); 4321558Srgrimes volno = 0; 4331558Srgrimes goto again; 4341558Srgrimes } 4351558Srgrimes if (tmpbuf.c_volume != volno) { 43637240Sbde fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume); 4371558Srgrimes volno = 0; 4381558Srgrimes goto again; 4391558Srgrimes } 44098542Smckusick if (_time64_to_time(tmpbuf.c_date) != dumpdate || 44198542Smckusick _time64_to_time(tmpbuf.c_ddate) != dumptime) { 44298542Smckusick time_t t = _time64_to_time(tmpbuf.c_date); 44385635Sdillon fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t)); 4441558Srgrimes fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 4451558Srgrimes volno = 0; 4461558Srgrimes goto again; 4471558Srgrimes } 44890820Siedowse tapesread |= 1 << (volno - 1); 4491558Srgrimes blksread = savecnt; 4501558Srgrimes /* 4511558Srgrimes * If continuing from the previous volume, skip over any 4521558Srgrimes * blocks read already at the end of the previous volume. 4531558Srgrimes * 4541558Srgrimes * If coming to this volume at random, skip to the beginning 4551558Srgrimes * of the next record. 4561558Srgrimes */ 45798542Smckusick dprintf(stdout, "last rec %qd, tape starts with %qd\n", prevtapea, 45890827Siedowse tmpbuf.c_tapea); 45998542Smckusick if (tmpbuf.c_type == TS_TAPE) { 46090608Siedowse if (curfile.action != USING) { 46190608Siedowse /* 46290608Siedowse * XXX Dump incorrectly sets c_count to 1 in the 46390608Siedowse * volume header of the first tape, so ignore 46490608Siedowse * c_count when volno == 1. 46590608Siedowse */ 46690608Siedowse if (volno != 1) 46790608Siedowse for (i = tmpbuf.c_count; i > 0; i--) 46890608Siedowse readtape(buf); 46990827Siedowse } else if (tmpbuf.c_tapea <= prevtapea) { 4701558Srgrimes /* 47190827Siedowse * Normally the value of c_tapea in the volume 47290827Siedowse * header is the record number of the header itself. 47390827Siedowse * However in the volume header following an EOT- 47490827Siedowse * terminated tape, it is the record number of the 47590827Siedowse * first continuation data block (dump bug?). 47690827Siedowse * 47790827Siedowse * The next record we want is `prevtapea + 1'. 4781558Srgrimes */ 47990827Siedowse i = prevtapea + 1 - tmpbuf.c_tapea; 48037240Sbde dprintf(stderr, "Skipping %ld duplicate record%s.\n", 4811558Srgrimes i, i > 1 ? "s" : ""); 4821558Srgrimes while (--i >= 0) 4831558Srgrimes readtape(buf); 4841558Srgrimes } 4851558Srgrimes } 48690608Siedowse if (curfile.action == USING) { 4871558Srgrimes if (volno == 1) 4881558Srgrimes panic("active file into volume 1\n"); 4891558Srgrimes return; 4901558Srgrimes } 4911558Srgrimes (void) gethead(&spcl); 4921558Srgrimes findinode(&spcl); 4931558Srgrimes if (gettingfile) { 4941558Srgrimes gettingfile = 0; 4951558Srgrimes longjmp(restart, 1); 4961558Srgrimes } 4971558Srgrimes} 4981558Srgrimes 4991558Srgrimes/* 5001558Srgrimes * Handle unexpected EOF. 5011558Srgrimes */ 5021558Srgrimesstatic void 50392837Simpterminateinput(void) 5041558Srgrimes{ 5051558Srgrimes 5061558Srgrimes if (gettingfile && curfile.action == USING) { 5071558Srgrimes printf("Warning: %s %s\n", 5081558Srgrimes "End-of-input encountered while extracting", curfile.name); 5091558Srgrimes } 5101558Srgrimes curfile.name = "<name unknown>"; 5111558Srgrimes curfile.action = UNKNOWN; 51298542Smckusick curfile.mode = 0; 5131558Srgrimes curfile.ino = maxino; 5141558Srgrimes if (gettingfile) { 5151558Srgrimes gettingfile = 0; 5161558Srgrimes longjmp(restart, 1); 5171558Srgrimes } 5181558Srgrimes} 5191558Srgrimes 5201558Srgrimes/* 5211558Srgrimes * handle multiple dumps per tape by skipping forward to the 5221558Srgrimes * appropriate one. 5231558Srgrimes */ 5241558Srgrimesstatic void 52592837Simpsetdumpnum(void) 5261558Srgrimes{ 5271558Srgrimes struct mtop tcom; 5281558Srgrimes 5291558Srgrimes if (dumpnum == 1 || volno != 1) 5301558Srgrimes return; 5311558Srgrimes if (pipein) { 5321558Srgrimes fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 5331558Srgrimes done(1); 5341558Srgrimes } 5351558Srgrimes tcom.mt_op = MTFSF; 5361558Srgrimes tcom.mt_count = dumpnum - 1; 5371558Srgrimes#ifdef RRESTORE 5381558Srgrimes if (host) 5391558Srgrimes rmtioctl(MTFSF, dumpnum - 1); 5408871Srgrimes else 5411558Srgrimes#endif 542128175Sgreen if (!pipecmdin && ioctl(mt, MTIOCTOP, (char *)&tcom) < 0) 5431558Srgrimes fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 5441558Srgrimes} 5451558Srgrimes 5461558Srgrimesvoid 54792837Simpprintdumpinfo(void) 5481558Srgrimes{ 54985635Sdillon time_t t; 55098542Smckusick t = _time64_to_time(spcl.c_date); 55185635Sdillon fprintf(stdout, "Dump date: %s", ctime(&t)); 55298542Smckusick t = _time64_to_time(spcl.c_ddate); 5531558Srgrimes fprintf(stdout, "Dumped from: %s", 55485635Sdillon (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t)); 5551558Srgrimes if (spcl.c_host[0] == '\0') 5561558Srgrimes return; 55737240Sbde fprintf(stderr, "Level %ld dump of %s on %s:%s\n", 5581558Srgrimes spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 5591558Srgrimes fprintf(stderr, "Label: %s\n", spcl.c_label); 5601558Srgrimes} 5611558Srgrimes 5621558Srgrimesint 56392837Simpextractfile(char *name) 5641558Srgrimes{ 56523685Speter int flags; 566161598Smaxim uid_t uid; 567161598Smaxim gid_t gid; 56823685Speter mode_t mode; 569167011Smckusick int extsize; 570100207Smckusick struct timeval mtimep[2], ctimep[2]; 5711558Srgrimes struct entry *ep; 572167011Smckusick char *buf; 5731558Srgrimes 5741558Srgrimes curfile.name = name; 5751558Srgrimes curfile.action = USING; 576100207Smckusick mtimep[0].tv_sec = curfile.atime_sec; 577100207Smckusick mtimep[0].tv_usec = curfile.atime_nsec / 1000; 578100207Smckusick mtimep[1].tv_sec = curfile.mtime_sec; 579100207Smckusick mtimep[1].tv_usec = curfile.mtime_nsec / 1000; 580100207Smckusick ctimep[0].tv_sec = curfile.atime_sec; 581100207Smckusick ctimep[0].tv_usec = curfile.atime_nsec / 1000; 582100207Smckusick ctimep[1].tv_sec = curfile.birthtime_sec; 583100207Smckusick ctimep[1].tv_usec = curfile.birthtime_nsec / 1000; 584167011Smckusick extsize = curfile.extsize; 585161598Smaxim uid = curfile.uid; 586161598Smaxim gid = curfile.gid; 58798542Smckusick mode = curfile.mode; 58898542Smckusick flags = curfile.file_flags; 5891558Srgrimes switch (mode & IFMT) { 5901558Srgrimes 5911558Srgrimes default: 5921558Srgrimes fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 5931558Srgrimes skipfile(); 5941558Srgrimes return (FAIL); 5951558Srgrimes 5961558Srgrimes case IFSOCK: 5971558Srgrimes vprintf(stdout, "skipped socket %s\n", name); 5981558Srgrimes skipfile(); 5991558Srgrimes return (GOOD); 6001558Srgrimes 6011558Srgrimes case IFDIR: 6021558Srgrimes if (mflag) { 6031558Srgrimes ep = lookupname(name); 6041558Srgrimes if (ep == NULL || ep->e_flags & EXTRACT) 6051558Srgrimes panic("unextracted directory %s\n", name); 6061558Srgrimes skipfile(); 6071558Srgrimes return (GOOD); 6081558Srgrimes } 6091558Srgrimes vprintf(stdout, "extract file %s\n", name); 6101558Srgrimes return (genliteraldir(name, curfile.ino)); 6111558Srgrimes 6121558Srgrimes case IFLNK: 6131558Srgrimes lnkbuf[0] = '\0'; 6141558Srgrimes pathlen = 0; 615167011Smckusick buf = setupextattr(extsize); 616167011Smckusick getfile(xtrlnkfile, xtrattr, xtrlnkskip); 6171558Srgrimes if (pathlen == 0) { 6181558Srgrimes vprintf(stdout, 6191558Srgrimes "%s: zero length symbolic link (ignored)\n", name); 6201558Srgrimes return (GOOD); 6211558Srgrimes } 62296113Siedowse if (linkit(lnkbuf, name, SYMLINK) == GOOD) { 623167011Smckusick if (extsize > 0) 624167011Smckusick set_extattr_link(name, buf, extsize); 625161598Smaxim (void) lchown(name, uid, gid); 62696113Siedowse (void) lchmod(name, mode); 627100207Smckusick (void) lutimes(name, ctimep); 628100207Smckusick (void) lutimes(name, mtimep); 629161598Smaxim (void) lchflags(name, flags); 63096113Siedowse return (GOOD); 63195943Siedowse } 63296113Siedowse return (FAIL); 6331558Srgrimes 6346305Smartin case IFIFO: 63523685Speter vprintf(stdout, "extract fifo %s\n", name); 63623685Speter if (Nflag) { 63723685Speter skipfile(); 63823685Speter return (GOOD); 63923685Speter } 640161598Smaxim if (uflag) 641161598Smaxim (void) unlink(name); 642161598Smaxim if (mkfifo(name, 0600) < 0) { 64323685Speter fprintf(stderr, "%s: cannot create fifo: %s\n", 64423685Speter name, strerror(errno)); 6456305Smartin skipfile(); 6466305Smartin return (FAIL); 6476305Smartin } 648167011Smckusick if (extsize == 0) { 649167011Smckusick skipfile(); 650167011Smckusick } else { 651167011Smckusick buf = setupextattr(extsize); 652167011Smckusick getfile(xtrnull, xtrattr, xtrnull); 653167011Smckusick set_extattr_file(name, buf, extsize); 654167011Smckusick } 655161598Smaxim (void) chown(name, uid, gid); 6566305Smartin (void) chmod(name, mode); 657100207Smckusick (void) utimes(name, ctimep); 658100207Smckusick (void) utimes(name, mtimep); 65923685Speter (void) chflags(name, flags); 6606305Smartin return (GOOD); 6616305Smartin 6621558Srgrimes case IFCHR: 6631558Srgrimes case IFBLK: 6641558Srgrimes vprintf(stdout, "extract special file %s\n", name); 6651558Srgrimes if (Nflag) { 6661558Srgrimes skipfile(); 6671558Srgrimes return (GOOD); 6681558Srgrimes } 66935852Sjkh if (uflag) 670161598Smaxim (void) unlink(name); 671161598Smaxim if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600, 672161605Smaxim (int)curfile.rdev) < 0) { 6731558Srgrimes fprintf(stderr, "%s: cannot create special file: %s\n", 6741558Srgrimes name, strerror(errno)); 6751558Srgrimes skipfile(); 6761558Srgrimes return (FAIL); 6771558Srgrimes } 678167011Smckusick if (extsize == 0) { 679167011Smckusick skipfile(); 680167011Smckusick } else { 681167011Smckusick buf = setupextattr(extsize); 682167011Smckusick getfile(xtrnull, xtrattr, xtrnull); 683167011Smckusick set_extattr_file(name, buf, extsize); 684167011Smckusick } 685161598Smaxim (void) chown(name, uid, gid); 6861558Srgrimes (void) chmod(name, mode); 687100207Smckusick (void) utimes(name, ctimep); 688100207Smckusick (void) utimes(name, mtimep); 68923685Speter (void) chflags(name, flags); 6901558Srgrimes return (GOOD); 6911558Srgrimes 6921558Srgrimes case IFREG: 6931558Srgrimes vprintf(stdout, "extract file %s\n", name); 6941558Srgrimes if (Nflag) { 6951558Srgrimes skipfile(); 6961558Srgrimes return (GOOD); 6971558Srgrimes } 69835852Sjkh if (uflag) 699161598Smaxim (void) unlink(name); 70021149Simp if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 701161598Smaxim 0600)) < 0) { 7021558Srgrimes fprintf(stderr, "%s: cannot create file: %s\n", 7031558Srgrimes name, strerror(errno)); 7041558Srgrimes skipfile(); 7051558Srgrimes return (FAIL); 7061558Srgrimes } 707167011Smckusick buf = setupextattr(extsize); 708167011Smckusick getfile(xtrfile, xtrattr, xtrskip); 709167011Smckusick if (extsize > 0) 710167011Smckusick set_extattr_fd(ofile, name, buf, extsize); 711161598Smaxim (void) fchown(ofile, uid, gid); 7121558Srgrimes (void) fchmod(ofile, mode); 713161598Smaxim (void) futimes(ofile, ctimep); 714161598Smaxim (void) futimes(ofile, mtimep); 715161598Smaxim (void) fchflags(ofile, flags); 7161558Srgrimes (void) close(ofile); 7171558Srgrimes return (GOOD); 7181558Srgrimes } 7191558Srgrimes /* NOTREACHED */ 7201558Srgrimes} 7211558Srgrimes 7221558Srgrimes/* 723167011Smckusick * Set attributes for a file. 724167011Smckusick */ 725167011Smckusickvoid 726167011Smckusickset_extattr_file(char *name, void *buf, int size) 727167011Smckusick{ 728167011Smckusick struct extattr *eap, *eaend; 729167011Smckusick 730167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 731167011Smckusick eaend = buf + size; 732167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 733167011Smckusick /* 734167011Smckusick * Make sure this entry is complete. 735167011Smckusick */ 736167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 737167011Smckusick dprintf(stdout, "\n\t%scorrupted", 738167011Smckusick eap == buf ? "" : "remainder "); 739167011Smckusick break; 740167011Smckusick } 741167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 742167011Smckusick continue; 743167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 744167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 745167011Smckusick eap->ea_namelength, eap->ea_name); 746167011Smckusick /* 747167011Smckusick * First we try the general attribute setting interface. 748167011Smckusick * However, some attributes can only be set by root or 749167011Smckusick * by using special interfaces (for example, ACLs). 750167011Smckusick */ 751167011Smckusick if (extattr_set_file(name, eap->ea_namespace, eap->ea_name, 752167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 753167011Smckusick dprintf(stdout, " (set using extattr_set_file)"); 754167011Smckusick continue; 755167011Smckusick } 756167011Smckusick /* 757167011Smckusick * If the general interface refuses to set the attribute, 758167011Smckusick * then we try all the specialized interfaces that we 759167011Smckusick * know about. 760167011Smckusick */ 761167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 762167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 763167011Smckusick if (acl_set_file(name, ACL_TYPE_ACCESS, 764167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 765167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 766167011Smckusick continue; 767167011Smckusick } 768167011Smckusick } 769167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 770167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 771167011Smckusick if (acl_set_file(name, ACL_TYPE_DEFAULT, 772167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 773167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 774167011Smckusick continue; 775167011Smckusick } 776167011Smckusick } 777167011Smckusick vprintf(stdout, " (unable to set)"); 778167011Smckusick } 779167011Smckusick vprintf(stdout, "\n"); 780167011Smckusick} 781167011Smckusick 782167011Smckusick/* 783167011Smckusick * Set attributes for a symbolic link. 784167011Smckusick */ 785167011Smckusickstatic void 786167011Smckusickset_extattr_link(char *name, void *buf, int size) 787167011Smckusick{ 788167011Smckusick struct extattr *eap, *eaend; 789167011Smckusick 790167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 791167011Smckusick eaend = buf + size; 792167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 793167011Smckusick /* 794167011Smckusick * Make sure this entry is complete. 795167011Smckusick */ 796167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 797167011Smckusick dprintf(stdout, "\n\t%scorrupted", 798167011Smckusick eap == buf ? "" : "remainder "); 799167011Smckusick break; 800167011Smckusick } 801167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 802167011Smckusick continue; 803167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 804167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 805167011Smckusick eap->ea_namelength, eap->ea_name); 806167011Smckusick /* 807167011Smckusick * First we try the general attribute setting interface. 808167011Smckusick * However, some attributes can only be set by root or 809167011Smckusick * by using special interfaces (for example, ACLs). 810167011Smckusick */ 811167011Smckusick if (extattr_set_link(name, eap->ea_namespace, eap->ea_name, 812167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 813167011Smckusick dprintf(stdout, " (set using extattr_set_link)"); 814167011Smckusick continue; 815167011Smckusick } 816167011Smckusick /* 817167011Smckusick * If the general interface refuses to set the attribute, 818167011Smckusick * then we try all the specialized interfaces that we 819167011Smckusick * know about. 820167011Smckusick */ 821167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 822167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 823167011Smckusick if (acl_set_link_np(name, ACL_TYPE_ACCESS, 824167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 825167011Smckusick dprintf(stdout, " (set using acl_set_link_np)"); 826167011Smckusick continue; 827167011Smckusick } 828167011Smckusick } 829167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 830167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 831167011Smckusick if (acl_set_link_np(name, ACL_TYPE_DEFAULT, 832167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 833167011Smckusick dprintf(stdout, " (set using acl_set_link_np)"); 834167011Smckusick continue; 835167011Smckusick } 836167011Smckusick } 837167011Smckusick vprintf(stdout, " (unable to set)"); 838167011Smckusick } 839167011Smckusick vprintf(stdout, "\n"); 840167011Smckusick} 841167011Smckusick 842167011Smckusick/* 843167011Smckusick * Set attributes on a file descriptor. 844167011Smckusick */ 845167011Smckusickstatic void 846167011Smckusickset_extattr_fd(int fd, char *name, void *buf, int size) 847167011Smckusick{ 848167011Smckusick struct extattr *eap, *eaend; 849167011Smckusick 850167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 851167011Smckusick eaend = buf + size; 852167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 853167011Smckusick /* 854167011Smckusick * Make sure this entry is complete. 855167011Smckusick */ 856167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 857167011Smckusick dprintf(stdout, "\n\t%scorrupted", 858167011Smckusick eap == buf ? "" : "remainder "); 859167011Smckusick break; 860167011Smckusick } 861167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 862167011Smckusick continue; 863167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 864167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 865167011Smckusick eap->ea_namelength, eap->ea_name); 866167011Smckusick /* 867167011Smckusick * First we try the general attribute setting interface. 868167011Smckusick * However, some attributes can only be set by root or 869167011Smckusick * by using special interfaces (for example, ACLs). 870167011Smckusick */ 871167011Smckusick if (extattr_set_fd(fd, eap->ea_namespace, eap->ea_name, 872167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 873167011Smckusick dprintf(stdout, " (set using extattr_set_fd)"); 874167011Smckusick continue; 875167011Smckusick } 876167011Smckusick /* 877167011Smckusick * If the general interface refuses to set the attribute, 878167011Smckusick * then we try all the specialized interfaces that we 879167011Smckusick * know about. 880167011Smckusick */ 881167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 882167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 883167011Smckusick if (acl_set_fd(fd, EXTATTR_CONTENT(eap)) != -1) { 884167011Smckusick dprintf(stdout, " (set using acl_set_fd)"); 885167011Smckusick continue; 886167011Smckusick } 887167011Smckusick } 888167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 889167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 890167011Smckusick if (acl_set_file(name, ACL_TYPE_DEFAULT, 891167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 892167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 893167011Smckusick continue; 894167011Smckusick } 895167011Smckusick } 896167011Smckusick vprintf(stdout, " (unable to set)"); 897167011Smckusick } 898167011Smckusick vprintf(stdout, "\n"); 899167011Smckusick} 900167011Smckusick 901167011Smckusick/* 9021558Srgrimes * skip over bit maps on the tape 9031558Srgrimes */ 9041558Srgrimesvoid 90592837Simpskipmaps(void) 9061558Srgrimes{ 9071558Srgrimes 9081558Srgrimes while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 9091558Srgrimes skipfile(); 9101558Srgrimes} 9111558Srgrimes 9121558Srgrimes/* 9131558Srgrimes * skip over a file on the tape 9141558Srgrimes */ 9151558Srgrimesvoid 91692837Simpskipfile(void) 9171558Srgrimes{ 9181558Srgrimes 9191558Srgrimes curfile.action = SKIP; 920167011Smckusick getfile(xtrnull, xtrnull, xtrnull); 9211558Srgrimes} 9221558Srgrimes 9231558Srgrimes/* 9241558Srgrimes * Extract a file from the tape. 9251558Srgrimes * When an allocated block is found it is passed to the fill function; 9261558Srgrimes * when an unallocated block (hole) is found, a zeroed buffer is passed 9271558Srgrimes * to the skip function. 9281558Srgrimes */ 9291558Srgrimesvoid 930167011Smckusickgetfile(void (*datafill)(char *, long), void (*attrfill)(char *, long), 931167011Smckusick void (*skip)(char *, long)) 9321558Srgrimes{ 93392806Sobrien int i; 934167011Smckusick off_t size; 935167011Smckusick int curblk, attrsize; 936167011Smckusick void (*fillit)(char *, long); 9371558Srgrimes static char clearedbuf[MAXBSIZE]; 9381558Srgrimes char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 9391558Srgrimes char junk[TP_BSIZE]; 9401558Srgrimes 941167011Smckusick curblk = 0; 942167011Smckusick size = spcl.c_size; 943167011Smckusick attrsize = spcl.c_extsize; 9441558Srgrimes if (spcl.c_type == TS_END) 9451558Srgrimes panic("ran off end of tape\n"); 94698542Smckusick if (spcl.c_magic != FS_UFS2_MAGIC) 9471558Srgrimes panic("not at beginning of a file\n"); 9481558Srgrimes if (!gettingfile && setjmp(restart) != 0) 9491558Srgrimes return; 9501558Srgrimes gettingfile++; 951167011Smckusick fillit = datafill; 952167011Smckusick if (size == 0 && attrsize > 0) { 953167011Smckusick fillit = attrfill; 954167011Smckusick size = attrsize; 955167011Smckusick attrsize = 0; 956167011Smckusick } 9571558Srgrimesloop: 9581558Srgrimes for (i = 0; i < spcl.c_count; i++) { 959164911Sdwmalone if (!readmapflag && i > TP_NINDIR) { 960164911Sdwmalone if (Dflag) { 961164911Sdwmalone fprintf(stderr, "spcl.c_count = %jd\n", 962164911Sdwmalone (intmax_t)spcl.c_count); 963164911Sdwmalone break; 964164911Sdwmalone } else 965164911Sdwmalone panic("spcl.c_count = %jd\n", 966164911Sdwmalone (intmax_t)spcl.c_count); 967164911Sdwmalone } 96837923Simp if (readmapflag || spcl.c_addr[i]) { 9691558Srgrimes readtape(&buf[curblk++][0]); 9701558Srgrimes if (curblk == fssize / TP_BSIZE) { 971167011Smckusick (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 97223685Speter fssize : (curblk - 1) * TP_BSIZE + size)); 9731558Srgrimes curblk = 0; 9741558Srgrimes } 9751558Srgrimes } else { 9761558Srgrimes if (curblk > 0) { 977167011Smckusick (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 97823685Speter curblk * TP_BSIZE : 97923685Speter (curblk - 1) * TP_BSIZE + size)); 9801558Srgrimes curblk = 0; 9811558Srgrimes } 98223685Speter (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 98323685Speter TP_BSIZE : size)); 9841558Srgrimes } 9851558Srgrimes if ((size -= TP_BSIZE) <= 0) { 986167011Smckusick if (size > -TP_BSIZE && curblk > 0) { 987167011Smckusick (*fillit)((char *)buf, 988167011Smckusick (long)((curblk * TP_BSIZE) + size)); 989167011Smckusick curblk = 0; 990167011Smckusick } 991167011Smckusick if (attrsize > 0) { 992167011Smckusick fillit = attrfill; 993167011Smckusick size = attrsize; 994167011Smckusick attrsize = 0; 995167011Smckusick continue; 996167011Smckusick } 997167011Smckusick if (spcl.c_count - i > 1) 998167011Smckusick dprintf(stdout, "skipping %d junk block(s)\n", 999167011Smckusick spcl.c_count - i - 1); 1000164911Sdwmalone for (i++; i < spcl.c_count; i++) { 1001164911Sdwmalone if (!readmapflag && i > TP_NINDIR) { 1002164911Sdwmalone if (Dflag) { 1003164911Sdwmalone fprintf(stderr, 1004164911Sdwmalone "spcl.c_count = %jd\n", 1005164911Sdwmalone (intmax_t)spcl.c_count); 1006164911Sdwmalone break; 1007164911Sdwmalone } else 1008164911Sdwmalone panic("spcl.c_count = %jd\n", 1009164911Sdwmalone (intmax_t)spcl.c_count); 1010164911Sdwmalone } 101137923Simp if (readmapflag || spcl.c_addr[i]) 10121558Srgrimes readtape(junk); 1013164911Sdwmalone } 10141558Srgrimes break; 10151558Srgrimes } 10161558Srgrimes } 10171558Srgrimes if (gethead(&spcl) == GOOD && size > 0) { 10181558Srgrimes if (spcl.c_type == TS_ADDR) 10191558Srgrimes goto loop; 10201558Srgrimes dprintf(stdout, 102137240Sbde "Missing address (header) block for %s at %ld blocks\n", 10221558Srgrimes curfile.name, blksread); 10231558Srgrimes } 10241558Srgrimes if (curblk > 0) 1025167011Smckusick panic("getfile: lost data\n"); 10261558Srgrimes findinode(&spcl); 10271558Srgrimes gettingfile = 0; 10281558Srgrimes} 10291558Srgrimes 10301558Srgrimes/* 1031167011Smckusick * These variables are shared between the next two functions. 1032167011Smckusick */ 1033167011Smckusickstatic int extbufsize = 0; 1034167011Smckusickstatic char *extbuf; 1035167011Smckusickstatic int extloc; 1036167011Smckusick 1037167011Smckusick/* 1038167011Smckusick * Allocate a buffer into which to extract extended attributes. 1039167011Smckusick */ 1040167011Smckusickstatic char * 1041167011Smckusicksetupextattr(int extsize) 1042167011Smckusick{ 1043167011Smckusick 1044167011Smckusick extloc = 0; 1045167011Smckusick if (extsize <= extbufsize) 1046167011Smckusick return (extbuf); 1047167011Smckusick if (extbufsize > 0) 1048167011Smckusick free(extbuf); 1049167011Smckusick if ((extbuf = malloc(extsize)) != NULL) { 1050167011Smckusick extbufsize = extsize; 1051167011Smckusick return (extbuf); 1052167011Smckusick } 1053167011Smckusick extbufsize = 0; 1054167011Smckusick extbuf = NULL; 1055167011Smckusick fprintf(stderr, "Cannot extract %d bytes %s for inode %d, name %s\n", 1056167011Smckusick extsize, "of extended attributes", curfile.ino, curfile.name); 1057167011Smckusick return (NULL); 1058167011Smckusick} 1059167011Smckusick 1060167011Smckusick/* 1061167011Smckusick * Extract the next block of extended attributes. 1062167011Smckusick */ 1063167011Smckusickstatic void 1064167011Smckusickxtrattr(char *buf, long size) 1065167011Smckusick{ 1066167011Smckusick 1067167011Smckusick if (extloc + size > extbufsize) 1068167011Smckusick panic("overrun attribute buffer\n"); 1069167011Smckusick memmove(&extbuf[extloc], buf, size); 1070167011Smckusick extloc += size; 1071167011Smckusick} 1072167011Smckusick 1073167011Smckusick/* 10741558Srgrimes * Write out the next block of a file. 10751558Srgrimes */ 10761558Srgrimesstatic void 107792837Simpxtrfile(char *buf, long size) 10781558Srgrimes{ 10791558Srgrimes 10801558Srgrimes if (Nflag) 10811558Srgrimes return; 10821558Srgrimes if (write(ofile, buf, (int) size) == -1) { 10831558Srgrimes fprintf(stderr, 10841558Srgrimes "write error extracting inode %d, name %s\nwrite: %s\n", 10851558Srgrimes curfile.ino, curfile.name, strerror(errno)); 10861558Srgrimes } 10871558Srgrimes} 10881558Srgrimes 10891558Srgrimes/* 10901558Srgrimes * Skip over a hole in a file. 10911558Srgrimes */ 10921558Srgrimes/* ARGSUSED */ 10931558Srgrimesstatic void 109492837Simpxtrskip(char *buf, long size) 10951558Srgrimes{ 10961558Srgrimes 10971558Srgrimes if (lseek(ofile, size, SEEK_CUR) == -1) { 10981558Srgrimes fprintf(stderr, 10991558Srgrimes "seek error extracting inode %d, name %s\nlseek: %s\n", 11001558Srgrimes curfile.ino, curfile.name, strerror(errno)); 11011558Srgrimes done(1); 11021558Srgrimes } 11031558Srgrimes} 11041558Srgrimes 11051558Srgrimes/* 11061558Srgrimes * Collect the next block of a symbolic link. 11071558Srgrimes */ 11081558Srgrimesstatic void 110992837Simpxtrlnkfile(char *buf, long size) 11101558Srgrimes{ 11111558Srgrimes 11121558Srgrimes pathlen += size; 11131558Srgrimes if (pathlen > MAXPATHLEN) { 11141558Srgrimes fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 11151558Srgrimes curfile.name, lnkbuf, buf, pathlen); 11161558Srgrimes done(1); 11171558Srgrimes } 11181558Srgrimes (void) strcat(lnkbuf, buf); 11191558Srgrimes} 11201558Srgrimes 11211558Srgrimes/* 11221558Srgrimes * Skip over a hole in a symbolic link (should never happen). 11231558Srgrimes */ 11241558Srgrimes/* ARGSUSED */ 11251558Srgrimesstatic void 112692837Simpxtrlnkskip(char *buf, long size) 11271558Srgrimes{ 11281558Srgrimes 11291558Srgrimes fprintf(stderr, "unallocated block in symbolic link %s\n", 11301558Srgrimes curfile.name); 11311558Srgrimes done(1); 11321558Srgrimes} 11331558Srgrimes 11341558Srgrimes/* 11351558Srgrimes * Collect the next block of a bit map. 11361558Srgrimes */ 11371558Srgrimesstatic void 113892837Simpxtrmap(char *buf, long size) 11391558Srgrimes{ 11401558Srgrimes 114123685Speter memmove(map, buf, size); 11421558Srgrimes map += size; 11431558Srgrimes} 11441558Srgrimes 11451558Srgrimes/* 11461558Srgrimes * Skip over a hole in a bit map (should never happen). 11471558Srgrimes */ 11481558Srgrimes/* ARGSUSED */ 11491558Srgrimesstatic void 115092837Simpxtrmapskip(char *buf, long size) 11511558Srgrimes{ 11521558Srgrimes 11531558Srgrimes panic("hole in map\n"); 11541558Srgrimes map += size; 11551558Srgrimes} 11561558Srgrimes 11571558Srgrimes/* 11581558Srgrimes * Noop, when an extraction function is not needed. 11591558Srgrimes */ 11601558Srgrimes/* ARGSUSED */ 11611558Srgrimesvoid 116292837Simpxtrnull(char *buf, long size) 11631558Srgrimes{ 11641558Srgrimes 11651558Srgrimes return; 11661558Srgrimes} 11671558Srgrimes 11681558Srgrimes/* 11691558Srgrimes * Read TP_BSIZE blocks from the input. 11701558Srgrimes * Handle read errors, and end of media. 11711558Srgrimes */ 11721558Srgrimesstatic void 117392837Simpreadtape(char *buf) 11741558Srgrimes{ 1175164911Sdwmalone long rd, newvol, i, oldnumtrec; 11761558Srgrimes int cnt, seek_failed; 11771558Srgrimes 1178164911Sdwmalone if (blkcnt + (byteslide > 0) < numtrec) { 1179164911Sdwmalone memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE); 11801558Srgrimes blksread++; 118190827Siedowse tapeaddr++; 11821558Srgrimes return; 11831558Srgrimes } 1184164911Sdwmalone if (numtrec > 0) 1185164911Sdwmalone memmove(&tapebuf[-TP_BSIZE], 1186164911Sdwmalone &tapebuf[(numtrec-1) * TP_BSIZE], (long)TP_BSIZE); 1187164911Sdwmalone oldnumtrec = numtrec; 11881558Srgrimes for (i = 0; i < ntrec; i++) 11891558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 11901558Srgrimes if (numtrec == 0) 11911558Srgrimes numtrec = ntrec; 11921558Srgrimes cnt = ntrec * TP_BSIZE; 11931558Srgrimes rd = 0; 11941558Srgrimesgetmore: 11951558Srgrimes#ifdef RRESTORE 11961558Srgrimes if (host) 11971558Srgrimes i = rmtread(&tapebuf[rd], cnt); 11981558Srgrimes else 11991558Srgrimes#endif 12001558Srgrimes i = read(mt, &tapebuf[rd], cnt); 12011558Srgrimes /* 12021558Srgrimes * Check for mid-tape short read error. 12031558Srgrimes * If found, skip rest of buffer and start with the next. 12041558Srgrimes */ 12051558Srgrimes if (!pipein && numtrec < ntrec && i > 0) { 12061558Srgrimes dprintf(stdout, "mid-media short read error.\n"); 12071558Srgrimes numtrec = ntrec; 12081558Srgrimes } 12091558Srgrimes /* 12101558Srgrimes * Handle partial block read. 12111558Srgrimes */ 12121558Srgrimes if (pipein && i == 0 && rd > 0) 12131558Srgrimes i = rd; 12141558Srgrimes else if (i > 0 && i != ntrec * TP_BSIZE) { 12151558Srgrimes if (pipein) { 12161558Srgrimes rd += i; 12171558Srgrimes cnt -= i; 12181558Srgrimes if (cnt > 0) 12191558Srgrimes goto getmore; 12201558Srgrimes i = rd; 12211558Srgrimes } else { 12221558Srgrimes /* 12231558Srgrimes * Short read. Process the blocks read. 12241558Srgrimes */ 12251558Srgrimes if (i % TP_BSIZE != 0) 12261558Srgrimes vprintf(stdout, 122737240Sbde "partial block read: %ld should be %ld\n", 12281558Srgrimes i, ntrec * TP_BSIZE); 12291558Srgrimes numtrec = i / TP_BSIZE; 12301558Srgrimes } 12311558Srgrimes } 12321558Srgrimes /* 12331558Srgrimes * Handle read error. 12341558Srgrimes */ 12351558Srgrimes if (i < 0) { 12361558Srgrimes fprintf(stderr, "Tape read error while "); 12371558Srgrimes switch (curfile.action) { 12381558Srgrimes default: 12391558Srgrimes fprintf(stderr, "trying to set up tape\n"); 12401558Srgrimes break; 12411558Srgrimes case UNKNOWN: 12421558Srgrimes fprintf(stderr, "trying to resynchronize\n"); 12431558Srgrimes break; 12441558Srgrimes case USING: 12451558Srgrimes fprintf(stderr, "restoring %s\n", curfile.name); 12461558Srgrimes break; 12471558Srgrimes case SKIP: 12481558Srgrimes fprintf(stderr, "skipping over inode %d\n", 12491558Srgrimes curfile.ino); 12501558Srgrimes break; 12511558Srgrimes } 12521558Srgrimes if (!yflag && !reply("continue")) 12531558Srgrimes done(1); 12541558Srgrimes i = ntrec * TP_BSIZE; 125523685Speter memset(tapebuf, 0, i); 12561558Srgrimes#ifdef RRESTORE 12571558Srgrimes if (host) 12581558Srgrimes seek_failed = (rmtseek(i, 1) < 0); 12591558Srgrimes else 12601558Srgrimes#endif 12611558Srgrimes seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 12621558Srgrimes 12631558Srgrimes if (seek_failed) { 12641558Srgrimes fprintf(stderr, 12651558Srgrimes "continuation failed: %s\n", strerror(errno)); 12661558Srgrimes done(1); 12671558Srgrimes } 12681558Srgrimes } 12691558Srgrimes /* 12701558Srgrimes * Handle end of tape. 12711558Srgrimes */ 12721558Srgrimes if (i == 0) { 12731558Srgrimes vprintf(stdout, "End-of-tape encountered\n"); 12741558Srgrimes if (!pipein) { 12751558Srgrimes newvol = volno + 1; 12761558Srgrimes volno = 0; 12771558Srgrimes numtrec = 0; 12781558Srgrimes getvol(newvol); 12791558Srgrimes readtape(buf); 12801558Srgrimes return; 12811558Srgrimes } 12821558Srgrimes if (rd % TP_BSIZE != 0) 12831558Srgrimes panic("partial block read: %d should be %d\n", 12841558Srgrimes rd, ntrec * TP_BSIZE); 12851558Srgrimes terminateinput(); 128623685Speter memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 12871558Srgrimes } 1288164911Sdwmalone if (oldnumtrec == 0) 1289164911Sdwmalone blkcnt = 0; 1290164911Sdwmalone else 1291164911Sdwmalone blkcnt -= oldnumtrec; 1292164911Sdwmalone memmove(buf, 1293164911Sdwmalone &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE); 12941558Srgrimes blksread++; 129590827Siedowse tapeaddr++; 12961558Srgrimes} 12971558Srgrimes 12981558Srgrimesstatic void 129992837Simpfindtapeblksize(void) 13001558Srgrimes{ 130192806Sobrien long i; 13021558Srgrimes 13031558Srgrimes for (i = 0; i < ntrec; i++) 13041558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 13051558Srgrimes blkcnt = 0; 13061558Srgrimes#ifdef RRESTORE 13071558Srgrimes if (host) 13081558Srgrimes i = rmtread(tapebuf, ntrec * TP_BSIZE); 13091558Srgrimes else 13101558Srgrimes#endif 13111558Srgrimes i = read(mt, tapebuf, ntrec * TP_BSIZE); 13121558Srgrimes 13131558Srgrimes if (i <= 0) { 13141558Srgrimes fprintf(stderr, "tape read error: %s\n", strerror(errno)); 13151558Srgrimes done(1); 13161558Srgrimes } 13171558Srgrimes if (i % TP_BSIZE != 0) { 131837240Sbde fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 13191558Srgrimes i, "is not a multiple of dump block size", TP_BSIZE); 13201558Srgrimes done(1); 13211558Srgrimes } 13221558Srgrimes ntrec = i / TP_BSIZE; 13231558Srgrimes numtrec = ntrec; 132437240Sbde vprintf(stdout, "Tape block size is %ld\n", ntrec); 13251558Srgrimes} 13261558Srgrimes 13271558Srgrimesvoid 132892837Simpclosemt(void) 13291558Srgrimes{ 13301558Srgrimes 13311558Srgrimes if (mt < 0) 13321558Srgrimes return; 1333128175Sgreen if (pipecmdin) { 1334128175Sgreen pclose(popenfp); 1335128175Sgreen popenfp = NULL; 1336128175Sgreen } else 13371558Srgrimes#ifdef RRESTORE 13381558Srgrimes if (host) 13391558Srgrimes rmtclose(); 13401558Srgrimes else 13411558Srgrimes#endif 13421558Srgrimes (void) close(mt); 13431558Srgrimes} 13441558Srgrimes 13451558Srgrimes/* 13461558Srgrimes * Read the next block from the tape. 13471558Srgrimes * If it is not any valid header, return an error. 13481558Srgrimes */ 13491558Srgrimesstatic int 135092837Simpgethead(struct s_spcl *buf) 13511558Srgrimes{ 13521558Srgrimes long i; 13531558Srgrimes 135498542Smckusick readtape((char *)buf); 135598542Smckusick if (buf->c_magic != FS_UFS2_MAGIC && buf->c_magic != NFS_MAGIC) { 135698542Smckusick if (buf->c_magic == OFS_MAGIC) { 135798542Smckusick fprintf(stderr, 135898542Smckusick "Format of dump tape is too old. Must use\n"); 135998542Smckusick fprintf(stderr, 136098542Smckusick "a version of restore from before 2002.\n"); 136198542Smckusick return (FAIL); 136298542Smckusick } 136398542Smckusick if (swabl(buf->c_magic) != FS_UFS2_MAGIC && 136498542Smckusick buf->c_magic != NFS_MAGIC) { 136598542Smckusick if (buf->c_magic == OFS_MAGIC) { 136698542Smckusick fprintf(stderr, 136798542Smckusick "Format of dump tape is too old. Must use\n"); 136898542Smckusick fprintf(stderr, 136998542Smckusick "a version of restore from before 2002.\n"); 13701558Srgrimes } 13711558Srgrimes return (FAIL); 137223096Simp } 137398542Smckusick if (!Bcvt) { 137498542Smckusick vprintf(stdout, "Note: Doing Byte swapping\n"); 137598542Smckusick Bcvt = 1; 13761558Srgrimes } 13771558Srgrimes } 137898542Smckusick if (checksum((int *)buf) == FAIL) 137998542Smckusick return (FAIL); 1380164911Sdwmalone if (_time64_to_time(buf->c_date) != dumpdate) 1381164911Sdwmalone fprintf(stderr, "Header with wrong dumpdate.\n"); 138298542Smckusick if (Bcvt) { 138398542Smckusick swabst((u_char *)"8l4s1q8l2q17l", (u_char *)buf); 138498542Smckusick swabst((u_char *)"l",(u_char *) &buf->c_level); 138598542Smckusick swabst((u_char *)"2l4q",(u_char *) &buf->c_flags); 13861558Srgrimes } 138737923Simp readmapflag = 0; 13881558Srgrimes 13891558Srgrimes switch (buf->c_type) { 13901558Srgrimes 13911558Srgrimes case TS_CLRI: 13921558Srgrimes case TS_BITS: 13931558Srgrimes /* 13941558Srgrimes * Have to patch up missing information in bit map headers 13951558Srgrimes */ 13961558Srgrimes buf->c_inumber = 0; 139798542Smckusick buf->c_size = buf->c_count * TP_BSIZE; 139837923Simp if (buf->c_count > TP_NINDIR) 139937923Simp readmapflag = 1; 140037923Simp else 140137923Simp for (i = 0; i < buf->c_count; i++) 140237923Simp buf->c_addr[i]++; 14031558Srgrimes break; 14041558Srgrimes 14051558Srgrimes case TS_TAPE: 1406143819Simp if (buf->c_magic == NFS_MAGIC) { 1407144099Simp if ((buf->c_flags & NFS_DR_NEWINODEFMT) == 0) 1408144099Simp oldinofmt = 1; 1409143819Simp buf->c_date = _time32_to_time(buf->c_old_date); 1410143819Simp buf->c_ddate = _time32_to_time(buf->c_old_ddate); 1411144093Simp buf->c_tapea = buf->c_old_tapea; 1412144093Simp buf->c_firstrec = buf->c_old_firstrec; 1413143819Simp } 14141558Srgrimes case TS_END: 14151558Srgrimes buf->c_inumber = 0; 14161558Srgrimes break; 14171558Srgrimes 14181558Srgrimes case TS_INODE: 141998542Smckusick /* 142098542Smckusick * For old dump tapes, have to copy up old fields to 142198542Smckusick * new locations. 142298542Smckusick */ 142398542Smckusick if (buf->c_magic == NFS_MAGIC) { 142498542Smckusick buf->c_tapea = buf->c_old_tapea; 142598542Smckusick buf->c_firstrec = buf->c_old_firstrec; 142698542Smckusick buf->c_date = _time32_to_time(buf->c_old_date); 142798542Smckusick buf->c_ddate = _time32_to_time(buf->c_old_ddate); 142898542Smckusick buf->c_atime = _time32_to_time(buf->c_old_atime); 142998542Smckusick buf->c_mtime = _time32_to_time(buf->c_old_mtime); 143098542Smckusick } 143198542Smckusick break; 143298542Smckusick 14331558Srgrimes case TS_ADDR: 14341558Srgrimes break; 14351558Srgrimes 14361558Srgrimes default: 14371558Srgrimes panic("gethead: unknown inode type %d\n", buf->c_type); 14381558Srgrimes break; 14391558Srgrimes } 1440144099Simp /* 1441144099Simp * If we're restoring a filesystem with the old (FreeBSD 1) 1442144099Simp * format inodes, copy the uid/gid to the new location 1443144099Simp */ 1444144099Simp if (oldinofmt) { 1445144099Simp buf->c_uid = buf->c_spare1[1]; 1446144099Simp buf->c_gid = buf->c_spare1[2]; 1447144099Simp } 144898542Smckusick buf->c_magic = FS_UFS2_MAGIC; 144990827Siedowse tapeaddr = buf->c_tapea; 14501558Srgrimes if (dflag) 14511558Srgrimes accthdr(buf); 14521558Srgrimes return(GOOD); 14531558Srgrimes} 14541558Srgrimes 14551558Srgrimes/* 14561558Srgrimes * Check that a header is where it belongs and predict the next header 14571558Srgrimes */ 14581558Srgrimesstatic void 145992837Simpaccthdr(struct s_spcl *header) 14601558Srgrimes{ 14611558Srgrimes static ino_t previno = 0x7fffffff; 14621558Srgrimes static int prevtype; 14631558Srgrimes static long predict; 14641558Srgrimes long blks, i; 14651558Srgrimes 14661558Srgrimes if (header->c_type == TS_TAPE) { 146798542Smckusick fprintf(stderr, "Volume header "); 14681558Srgrimes if (header->c_firstrec) 146998542Smckusick fprintf(stderr, "begins with record %qd", 14701558Srgrimes header->c_firstrec); 14711558Srgrimes fprintf(stderr, "\n"); 14721558Srgrimes previno = 0x7fffffff; 14731558Srgrimes return; 14741558Srgrimes } 14751558Srgrimes if (previno == 0x7fffffff) 14761558Srgrimes goto newcalc; 14771558Srgrimes switch (prevtype) { 14781558Srgrimes case TS_BITS: 147923685Speter fprintf(stderr, "Dumped inodes map header"); 14801558Srgrimes break; 14811558Srgrimes case TS_CLRI: 148223685Speter fprintf(stderr, "Used inodes map header"); 14831558Srgrimes break; 14841558Srgrimes case TS_INODE: 14851558Srgrimes fprintf(stderr, "File header, ino %d", previno); 14861558Srgrimes break; 14871558Srgrimes case TS_ADDR: 14881558Srgrimes fprintf(stderr, "File continuation header, ino %d", previno); 14891558Srgrimes break; 14901558Srgrimes case TS_END: 14911558Srgrimes fprintf(stderr, "End of tape header"); 14921558Srgrimes break; 14931558Srgrimes } 14941558Srgrimes if (predict != blksread - 1) 149537240Sbde fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 14961558Srgrimes predict, blksread - 1); 14971558Srgrimes fprintf(stderr, "\n"); 14981558Srgrimesnewcalc: 14991558Srgrimes blks = 0; 15001558Srgrimes if (header->c_type != TS_END) 15011558Srgrimes for (i = 0; i < header->c_count; i++) 150237923Simp if (readmapflag || header->c_addr[i] != 0) 15031558Srgrimes blks++; 15041558Srgrimes predict = blks; 15051558Srgrimes blksread = 0; 15061558Srgrimes prevtype = header->c_type; 15071558Srgrimes previno = header->c_inumber; 15081558Srgrimes} 15091558Srgrimes 15101558Srgrimes/* 15111558Srgrimes * Find an inode header. 151290573Siedowse * Complain if had to skip. 15131558Srgrimes */ 15141558Srgrimesstatic void 151592837Simpfindinode(struct s_spcl *header) 15161558Srgrimes{ 15171558Srgrimes static long skipcnt = 0; 15181558Srgrimes long i; 15191558Srgrimes char buf[TP_BSIZE]; 152090608Siedowse int htype; 15211558Srgrimes 15221558Srgrimes curfile.name = "<name unknown>"; 15231558Srgrimes curfile.action = UNKNOWN; 152498542Smckusick curfile.mode = 0; 15251558Srgrimes curfile.ino = 0; 15261558Srgrimes do { 152790608Siedowse htype = header->c_type; 152890608Siedowse switch (htype) { 15291558Srgrimes 15301558Srgrimes case TS_ADDR: 15311558Srgrimes /* 15321558Srgrimes * Skip up to the beginning of the next record 15331558Srgrimes */ 15341558Srgrimes for (i = 0; i < header->c_count; i++) 15351558Srgrimes if (header->c_addr[i]) 15361558Srgrimes readtape(buf); 15371558Srgrimes while (gethead(header) == FAIL || 1538164911Sdwmalone _time64_to_time(header->c_date) != dumpdate) { 15391558Srgrimes skipcnt++; 1540164911Sdwmalone if (Dflag) { 1541164911Sdwmalone byteslide++; 1542164911Sdwmalone if (byteslide < TP_BSIZE) { 1543164911Sdwmalone blkcnt--; 1544164911Sdwmalone blksread--; 1545164911Sdwmalone } else 1546164911Sdwmalone byteslide = 0; 1547164911Sdwmalone } 1548164911Sdwmalone } 15491558Srgrimes break; 15501558Srgrimes 15511558Srgrimes case TS_INODE: 155298542Smckusick curfile.mode = header->c_mode; 155398542Smckusick curfile.uid = header->c_uid; 155498542Smckusick curfile.gid = header->c_gid; 155598542Smckusick curfile.file_flags = header->c_file_flags; 155698542Smckusick curfile.rdev = header->c_rdev; 155798542Smckusick curfile.atime_sec = header->c_atime; 155898542Smckusick curfile.atime_nsec = header->c_atimensec; 155998542Smckusick curfile.mtime_sec = header->c_mtime; 156098542Smckusick curfile.mtime_nsec = header->c_mtimensec; 1561100207Smckusick curfile.birthtime_sec = header->c_birthtime; 1562100207Smckusick curfile.birthtime_nsec = header->c_birthtimensec; 1563167011Smckusick curfile.extsize = header->c_extsize; 156498542Smckusick curfile.size = header->c_size; 15651558Srgrimes curfile.ino = header->c_inumber; 15661558Srgrimes break; 15671558Srgrimes 15681558Srgrimes case TS_END: 156990820Siedowse /* If we missed some tapes, get another volume. */ 157090820Siedowse if (tapesread & (tapesread + 1)) { 157190820Siedowse getvol(0); 157290820Siedowse continue; 157390820Siedowse } 15741558Srgrimes curfile.ino = maxino; 15751558Srgrimes break; 15761558Srgrimes 15771558Srgrimes case TS_CLRI: 15781558Srgrimes curfile.name = "<file removal list>"; 15791558Srgrimes break; 15801558Srgrimes 15811558Srgrimes case TS_BITS: 15821558Srgrimes curfile.name = "<file dump list>"; 15831558Srgrimes break; 15841558Srgrimes 15851558Srgrimes case TS_TAPE: 1586164911Sdwmalone if (Dflag) 1587164911Sdwmalone fprintf(stderr, "unexpected tape header\n"); 1588164911Sdwmalone else 1589164911Sdwmalone panic("unexpected tape header\n"); 15901558Srgrimes 15911558Srgrimes default: 1592164911Sdwmalone if (Dflag) 1593164911Sdwmalone fprintf(stderr, "unknown tape header type %d\n", 1594164911Sdwmalone spcl.c_type); 1595164911Sdwmalone else 1596164911Sdwmalone panic("unknown tape header type %d\n", 1597164911Sdwmalone spcl.c_type); 1598164911Sdwmalone while (gethead(header) == FAIL || 1599164911Sdwmalone _time64_to_time(header->c_date) != dumpdate) { 1600164911Sdwmalone skipcnt++; 1601164911Sdwmalone if (Dflag) { 1602164911Sdwmalone byteslide++; 1603164911Sdwmalone if (byteslide < TP_BSIZE) { 1604164911Sdwmalone blkcnt--; 1605164911Sdwmalone blksread--; 1606164911Sdwmalone } else 1607164911Sdwmalone byteslide = 0; 1608164911Sdwmalone } 1609164911Sdwmalone } 16101558Srgrimes 16111558Srgrimes } 161290608Siedowse } while (htype == TS_ADDR); 16131558Srgrimes if (skipcnt > 0) 1614164911Sdwmalone fprintf(stderr, "resync restore, skipped %ld %s\n", 1615164911Sdwmalone skipcnt, Dflag ? "bytes" : "blocks"); 16161558Srgrimes skipcnt = 0; 16171558Srgrimes} 16181558Srgrimes 16191558Srgrimesstatic int 162092837Simpchecksum(int *buf) 16211558Srgrimes{ 162292806Sobrien int i, j; 16231558Srgrimes 16241558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 16251558Srgrimes i = 0; 162698542Smckusick if (!Bcvt) { 16271558Srgrimes do 16281558Srgrimes i += *buf++; 16291558Srgrimes while (--j); 16301558Srgrimes } else { 16311558Srgrimes /* What happens if we want to read restore tapes 16321558Srgrimes for a 16bit int machine??? */ 16338871Srgrimes do 16341558Srgrimes i += swabl(*buf++); 16351558Srgrimes while (--j); 16361558Srgrimes } 16378871Srgrimes 16381558Srgrimes if (i != CHECKSUM) { 16391558Srgrimes fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 16401558Srgrimes curfile.ino, curfile.name); 16411558Srgrimes return(FAIL); 16421558Srgrimes } 16431558Srgrimes return(GOOD); 16441558Srgrimes} 16451558Srgrimes 16461558Srgrimes#ifdef RRESTORE 16471558Srgrimes#include <stdarg.h> 16481558Srgrimes 16491558Srgrimesvoid 16501558Srgrimesmsg(const char *fmt, ...) 16511558Srgrimes{ 16521558Srgrimes va_list ap; 16531558Srgrimes va_start(ap, fmt); 16541558Srgrimes (void)vfprintf(stderr, fmt, ap); 16551558Srgrimes va_end(ap); 16561558Srgrimes} 16571558Srgrimes#endif /* RRESTORE */ 16581558Srgrimes 16591558Srgrimesstatic u_char * 166092837Simpswabshort(u_char *sp, int n) 16611558Srgrimes{ 16621558Srgrimes char c; 16631558Srgrimes 16641558Srgrimes while (--n >= 0) { 16651558Srgrimes c = sp[0]; sp[0] = sp[1]; sp[1] = c; 16661558Srgrimes sp += 2; 16671558Srgrimes } 16681558Srgrimes return (sp); 16691558Srgrimes} 16701558Srgrimes 16711558Srgrimesstatic u_char * 167292837Simpswablong(u_char *sp, int n) 16731558Srgrimes{ 16741558Srgrimes char c; 16751558Srgrimes 16761558Srgrimes while (--n >= 0) { 16771558Srgrimes c = sp[0]; sp[0] = sp[3]; sp[3] = c; 16781558Srgrimes c = sp[2]; sp[2] = sp[1]; sp[1] = c; 16791558Srgrimes sp += 4; 16801558Srgrimes } 16811558Srgrimes return (sp); 16821558Srgrimes} 16831558Srgrimes 168498542Smckusickstatic u_char * 168598542Smckusickswabquad(u_char *sp, int n) 168698542Smckusick{ 168798542Smckusick char c; 168898542Smckusick 168998542Smckusick while (--n >= 0) { 169098542Smckusick c = sp[0]; sp[0] = sp[7]; sp[7] = c; 169198542Smckusick c = sp[1]; sp[1] = sp[6]; sp[6] = c; 169298542Smckusick c = sp[2]; sp[2] = sp[5]; sp[5] = c; 169398542Smckusick c = sp[3]; sp[3] = sp[4]; sp[4] = c; 169498542Smckusick sp += 8; 169598542Smckusick } 169698542Smckusick return (sp); 169798542Smckusick} 169898542Smckusick 16991558Srgrimesvoid 170092837Simpswabst(u_char *cp, u_char *sp) 17011558Srgrimes{ 17021558Srgrimes int n = 0; 17031558Srgrimes 17041558Srgrimes while (*cp) { 17051558Srgrimes switch (*cp) { 17061558Srgrimes case '0': case '1': case '2': case '3': case '4': 17071558Srgrimes case '5': case '6': case '7': case '8': case '9': 17081558Srgrimes n = (n * 10) + (*cp++ - '0'); 17091558Srgrimes continue; 17108871Srgrimes 17111558Srgrimes case 's': case 'w': case 'h': 17121558Srgrimes if (n == 0) 17131558Srgrimes n = 1; 17141558Srgrimes sp = swabshort(sp, n); 17151558Srgrimes break; 17161558Srgrimes 17171558Srgrimes case 'l': 17181558Srgrimes if (n == 0) 17191558Srgrimes n = 1; 17201558Srgrimes sp = swablong(sp, n); 17211558Srgrimes break; 17221558Srgrimes 172398542Smckusick case 'q': 17241558Srgrimes if (n == 0) 17251558Srgrimes n = 1; 172698542Smckusick sp = swabquad(sp, n); 172798542Smckusick break; 172898542Smckusick 172998542Smckusick case 'b': 173098542Smckusick if (n == 0) 173198542Smckusick n = 1; 17321558Srgrimes sp += n; 17331558Srgrimes break; 173498542Smckusick 173598542Smckusick default: 173698542Smckusick fprintf(stderr, "Unknown conversion character: %c\n", 173798542Smckusick *cp); 173898542Smckusick done(0); 173998542Smckusick break; 17401558Srgrimes } 17411558Srgrimes cp++; 17421558Srgrimes n = 0; 17431558Srgrimes } 17441558Srgrimes} 17451558Srgrimes 17461558Srgrimesstatic u_long 174792837Simpswabl(u_long x) 17481558Srgrimes{ 17491558Srgrimes swabst((u_char *)"l", (u_char *)&x); 17501558Srgrimes return (x); 17511558Srgrimes} 1752