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$"); 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 } 167242166Seadler /* no longer need or want root privileges */ 168242166Seadler if (setuid(getuid()) != 0) { 169242166Seadler fprintf(stderr, "setuid failed\n"); 170242166Seadler done(1); 171242166Seadler } 17221174Sguido magtape = strdup(source); 17321174Sguido if (magtape == NULL) { 17421174Sguido fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 17521174Sguido done(1); 17621174Sguido } 1771558Srgrimes} 1781558Srgrimes 1791558Srgrimesvoid 18092837Simpnewtapebuf(long size) 1811558Srgrimes{ 18292837Simp static int tapebufsize = -1; 1831558Srgrimes 1841558Srgrimes ntrec = size; 1851558Srgrimes if (size <= tapebufsize) 1861558Srgrimes return; 1871558Srgrimes if (tapebuf != NULL) 188164911Sdwmalone free(tapebuf - TP_BSIZE); 189164911Sdwmalone tapebuf = malloc((size+1) * TP_BSIZE); 1901558Srgrimes if (tapebuf == NULL) { 1911558Srgrimes fprintf(stderr, "Cannot allocate space for tape buffer\n"); 1921558Srgrimes done(1); 1931558Srgrimes } 194164911Sdwmalone tapebuf += TP_BSIZE; 1951558Srgrimes tapebufsize = size; 1961558Srgrimes} 1971558Srgrimes 1981558Srgrimes/* 1991558Srgrimes * Verify that the tape drive can be accessed and 2001558Srgrimes * that it actually is a dump tape. 2011558Srgrimes */ 2021558Srgrimesvoid 20392837Simpsetup(void) 2041558Srgrimes{ 2051558Srgrimes int i, j, *ip; 2061558Srgrimes struct stat stbuf; 2071558Srgrimes 2081558Srgrimes vprintf(stdout, "Verify tape and initialize maps\n"); 209128175Sgreen if (pipecmdin) { 210128175Sgreen if (setenv("RESTORE_VOLUME", "1", 1) == -1) { 211128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 212128175Sgreen strerror(errno)); 213128175Sgreen done(1); 214128175Sgreen } 215128175Sgreen popenfp = popen(magtape, "r"); 216128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 217128175Sgreen } else 2181558Srgrimes#ifdef RRESTORE 2191558Srgrimes if (host) 2201558Srgrimes mt = rmtopen(magtape, 0); 2211558Srgrimes else 2221558Srgrimes#endif 2231558Srgrimes if (pipein) 2241558Srgrimes mt = 0; 2251558Srgrimes else 2261558Srgrimes mt = open(magtape, O_RDONLY, 0); 2271558Srgrimes if (mt < 0) { 2281558Srgrimes fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 2291558Srgrimes done(1); 2301558Srgrimes } 2311558Srgrimes volno = 1; 2321558Srgrimes setdumpnum(); 2331558Srgrimes FLUSHTAPEBUF(); 234203816Sjh if (!pipein && !pipecmdin && !bflag) 2351558Srgrimes findtapeblksize(); 2361558Srgrimes if (gethead(&spcl) == FAIL) { 23798542Smckusick fprintf(stderr, "Tape is not a dump tape\n"); 23898542Smckusick done(1); 2391558Srgrimes } 2401558Srgrimes if (pipein) { 24198542Smckusick endoftapemark.s_spcl.c_magic = FS_UFS2_MAGIC; 2421558Srgrimes endoftapemark.s_spcl.c_type = TS_END; 2431558Srgrimes ip = (int *)&endoftapemark; 2441558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 2451558Srgrimes i = 0; 2461558Srgrimes do 2471558Srgrimes i += *ip++; 2481558Srgrimes while (--j); 2491558Srgrimes endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 2501558Srgrimes } 2511558Srgrimes if (vflag || command == 't') 2521558Srgrimes printdumpinfo(); 25398542Smckusick dumptime = _time64_to_time(spcl.c_ddate); 25498542Smckusick dumpdate = _time64_to_time(spcl.c_date); 2551558Srgrimes if (stat(".", &stbuf) < 0) { 2561558Srgrimes fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 2571558Srgrimes done(1); 2581558Srgrimes } 25934851Sjkh if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 26034851Sjkh fssize = TP_BSIZE; 26134851Sjkh if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 2621558Srgrimes fssize = stbuf.st_blksize; 2631558Srgrimes if (((fssize - 1) & fssize) != 0) { 26437240Sbde fprintf(stderr, "bad block size %ld\n", fssize); 2651558Srgrimes done(1); 2661558Srgrimes } 2671558Srgrimes if (spcl.c_volume != 1) { 2681558Srgrimes fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2691558Srgrimes done(1); 2701558Srgrimes } 2711558Srgrimes if (gethead(&spcl) == FAIL) { 27237240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 2731558Srgrimes panic("no header after volume mark!\n"); 2741558Srgrimes } 2751558Srgrimes findinode(&spcl); 2761558Srgrimes if (spcl.c_type != TS_CLRI) { 2771558Srgrimes fprintf(stderr, "Cannot find file removal list\n"); 2781558Srgrimes done(1); 2791558Srgrimes } 2801558Srgrimes maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 2811558Srgrimes dprintf(stdout, "maxino = %d\n", maxino); 2821558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2831558Srgrimes if (map == NULL) 28423685Speter panic("no memory for active inode map\n"); 28523685Speter usedinomap = map; 2861558Srgrimes curfile.action = USING; 287167011Smckusick getfile(xtrmap, xtrmapskip, xtrmapskip); 2881558Srgrimes if (spcl.c_type != TS_BITS) { 2891558Srgrimes fprintf(stderr, "Cannot find file dump list\n"); 2901558Srgrimes done(1); 2911558Srgrimes } 2921558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2931558Srgrimes if (map == (char *)NULL) 2941558Srgrimes panic("no memory for file dump list\n"); 2951558Srgrimes dumpmap = map; 2961558Srgrimes curfile.action = USING; 297167011Smckusick getfile(xtrmap, xtrmapskip, xtrmapskip); 29823685Speter /* 29923685Speter * If there may be whiteout entries on the tape, pretend that the 30023685Speter * whiteout inode exists, so that the whiteout entries can be 30123685Speter * extracted. 30223685Speter */ 30398542Smckusick SETINO(WINO, dumpmap); 30490820Siedowse /* 'r' restores don't call getvol() for tape 1, so mark it as read. */ 30590820Siedowse if (command == 'r') 30690820Siedowse tapesread = 1; 3071558Srgrimes} 3081558Srgrimes 3091558Srgrimes/* 3101558Srgrimes * Prompt user to load a new dump volume. 3111558Srgrimes * "Nextvol" is the next suggested volume to use. 3121558Srgrimes * This suggested volume is enforced when doing full 31337906Scharnier * or incremental restores, but can be overridden by 3141558Srgrimes * the user when only extracting a subset of the files. 3151558Srgrimes */ 3161558Srgrimesvoid 31792837Simpgetvol(long nextvol) 3181558Srgrimes{ 31998542Smckusick int64_t prevtapea; 32098542Smckusick long i, newvol, savecnt; 3211558Srgrimes union u_spcl tmpspcl; 3221558Srgrimes# define tmpbuf tmpspcl.s_spcl 3231558Srgrimes char buf[TP_BSIZE]; 3241558Srgrimes 3251558Srgrimes if (nextvol == 1) { 3261558Srgrimes tapesread = 0; 3271558Srgrimes gettingfile = 0; 3281558Srgrimes } 32990827Siedowse prevtapea = tapeaddr; 33090827Siedowse savecnt = blksread; 3311558Srgrimes if (pipein) { 33269906Siedowse if (nextvol != 1) { 3331558Srgrimes panic("Changing volumes on pipe input?\n"); 33469906Siedowse /* Avoid looping if we couldn't ask the user. */ 33569906Siedowse if (yflag || ferror(terminal) || feof(terminal)) 33669906Siedowse done(1); 33769906Siedowse } 3381558Srgrimes if (volno == 1) 3391558Srgrimes return; 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 403203155Sjh (void)sprintf(volno, "%ld", newvol); 404128175Sgreen if (setenv("RESTORE_VOLUME", volno, 1) == -1) { 405128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 406128175Sgreen strerror(errno)); 407128175Sgreen done(1); 408128175Sgreen } 409128175Sgreen popenfp = popen(magtape, "r"); 410128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 411128175Sgreen } else 4121558Srgrimes#ifdef RRESTORE 4131558Srgrimes if (host) 4141558Srgrimes mt = rmtopen(magtape, 0); 4151558Srgrimes else 4161558Srgrimes#endif 4171558Srgrimes mt = open(magtape, O_RDONLY, 0); 4181558Srgrimes 4191558Srgrimes if (mt == -1) { 4201558Srgrimes fprintf(stderr, "Cannot open %s\n", magtape); 4211558Srgrimes volno = -1; 4221558Srgrimes goto again; 4231558Srgrimes } 4241558Srgrimesgethdr: 4251558Srgrimes volno = newvol; 4261558Srgrimes setdumpnum(); 4271558Srgrimes FLUSHTAPEBUF(); 4281558Srgrimes if (gethead(&tmpbuf) == FAIL) { 42937240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 4301558Srgrimes fprintf(stderr, "tape is not dump tape\n"); 4311558Srgrimes volno = 0; 4321558Srgrimes goto again; 4331558Srgrimes } 4341558Srgrimes if (tmpbuf.c_volume != volno) { 435203155Sjh fprintf(stderr, "Wrong volume (%jd)\n", 436203155Sjh (intmax_t)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 */ 457203155Sjh dprintf(stdout, "last rec %jd, tape starts with %jd\n", 458203155Sjh (intmax_t)prevtapea, (intmax_t)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; 557203155Sjh fprintf(stderr, "Level %jd dump of %s on %s:%s\n", 558203155Sjh (intmax_t)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; 585178125Smckusick uid = getuid(); 586178125Smckusick if (uid == 0) 587178125Smckusick uid = curfile.uid; 588161598Smaxim gid = curfile.gid; 58998542Smckusick mode = curfile.mode; 59098542Smckusick flags = curfile.file_flags; 5911558Srgrimes switch (mode & IFMT) { 5921558Srgrimes 5931558Srgrimes default: 5941558Srgrimes fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 5951558Srgrimes skipfile(); 5961558Srgrimes return (FAIL); 5971558Srgrimes 5981558Srgrimes case IFSOCK: 5991558Srgrimes vprintf(stdout, "skipped socket %s\n", name); 6001558Srgrimes skipfile(); 6011558Srgrimes return (GOOD); 6021558Srgrimes 6031558Srgrimes case IFDIR: 6041558Srgrimes if (mflag) { 6051558Srgrimes ep = lookupname(name); 6061558Srgrimes if (ep == NULL || ep->e_flags & EXTRACT) 6071558Srgrimes panic("unextracted directory %s\n", name); 6081558Srgrimes skipfile(); 6091558Srgrimes return (GOOD); 6101558Srgrimes } 6111558Srgrimes vprintf(stdout, "extract file %s\n", name); 6121558Srgrimes return (genliteraldir(name, curfile.ino)); 6131558Srgrimes 6141558Srgrimes case IFLNK: 6151558Srgrimes lnkbuf[0] = '\0'; 6161558Srgrimes pathlen = 0; 617167011Smckusick buf = setupextattr(extsize); 618167011Smckusick getfile(xtrlnkfile, xtrattr, xtrlnkskip); 6191558Srgrimes if (pathlen == 0) { 6201558Srgrimes vprintf(stdout, 6211558Srgrimes "%s: zero length symbolic link (ignored)\n", name); 6221558Srgrimes return (GOOD); 6231558Srgrimes } 62496113Siedowse if (linkit(lnkbuf, name, SYMLINK) == GOOD) { 625167011Smckusick if (extsize > 0) 626167011Smckusick set_extattr_link(name, buf, extsize); 627161598Smaxim (void) lchown(name, uid, gid); 62896113Siedowse (void) lchmod(name, mode); 629100207Smckusick (void) lutimes(name, ctimep); 630100207Smckusick (void) lutimes(name, mtimep); 631161598Smaxim (void) lchflags(name, flags); 63296113Siedowse return (GOOD); 63395943Siedowse } 63496113Siedowse return (FAIL); 6351558Srgrimes 6366305Smartin case IFIFO: 63723685Speter vprintf(stdout, "extract fifo %s\n", name); 63823685Speter if (Nflag) { 63923685Speter skipfile(); 64023685Speter return (GOOD); 64123685Speter } 642161598Smaxim if (uflag) 643161598Smaxim (void) unlink(name); 644161598Smaxim if (mkfifo(name, 0600) < 0) { 64523685Speter fprintf(stderr, "%s: cannot create fifo: %s\n", 64623685Speter name, strerror(errno)); 6476305Smartin skipfile(); 6486305Smartin return (FAIL); 6496305Smartin } 650167011Smckusick if (extsize == 0) { 651167011Smckusick skipfile(); 652167011Smckusick } else { 653167011Smckusick buf = setupextattr(extsize); 654167011Smckusick getfile(xtrnull, xtrattr, xtrnull); 655167011Smckusick set_extattr_file(name, buf, extsize); 656167011Smckusick } 657161598Smaxim (void) chown(name, uid, gid); 6586305Smartin (void) chmod(name, mode); 659100207Smckusick (void) utimes(name, ctimep); 660100207Smckusick (void) utimes(name, mtimep); 66123685Speter (void) chflags(name, flags); 6626305Smartin return (GOOD); 6636305Smartin 6641558Srgrimes case IFCHR: 6651558Srgrimes case IFBLK: 6661558Srgrimes vprintf(stdout, "extract special file %s\n", name); 6671558Srgrimes if (Nflag) { 6681558Srgrimes skipfile(); 6691558Srgrimes return (GOOD); 6701558Srgrimes } 67135852Sjkh if (uflag) 672161598Smaxim (void) unlink(name); 673161598Smaxim if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600, 674161605Smaxim (int)curfile.rdev) < 0) { 6751558Srgrimes fprintf(stderr, "%s: cannot create special file: %s\n", 6761558Srgrimes name, strerror(errno)); 6771558Srgrimes skipfile(); 6781558Srgrimes return (FAIL); 6791558Srgrimes } 680167011Smckusick if (extsize == 0) { 681167011Smckusick skipfile(); 682167011Smckusick } else { 683167011Smckusick buf = setupextattr(extsize); 684167011Smckusick getfile(xtrnull, xtrattr, xtrnull); 685167011Smckusick set_extattr_file(name, buf, extsize); 686167011Smckusick } 687161598Smaxim (void) chown(name, uid, gid); 6881558Srgrimes (void) chmod(name, mode); 689100207Smckusick (void) utimes(name, ctimep); 690100207Smckusick (void) utimes(name, mtimep); 69123685Speter (void) chflags(name, flags); 6921558Srgrimes return (GOOD); 6931558Srgrimes 6941558Srgrimes case IFREG: 6951558Srgrimes vprintf(stdout, "extract file %s\n", name); 6961558Srgrimes if (Nflag) { 6971558Srgrimes skipfile(); 6981558Srgrimes return (GOOD); 6991558Srgrimes } 70035852Sjkh if (uflag) 701161598Smaxim (void) unlink(name); 70221149Simp if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 703161598Smaxim 0600)) < 0) { 7041558Srgrimes fprintf(stderr, "%s: cannot create file: %s\n", 7051558Srgrimes name, strerror(errno)); 7061558Srgrimes skipfile(); 7071558Srgrimes return (FAIL); 7081558Srgrimes } 709167011Smckusick buf = setupextattr(extsize); 710167011Smckusick getfile(xtrfile, xtrattr, xtrskip); 711167011Smckusick if (extsize > 0) 712167011Smckusick set_extattr_fd(ofile, name, buf, extsize); 713161598Smaxim (void) fchown(ofile, uid, gid); 7141558Srgrimes (void) fchmod(ofile, mode); 715161598Smaxim (void) futimes(ofile, ctimep); 716161598Smaxim (void) futimes(ofile, mtimep); 717161598Smaxim (void) fchflags(ofile, flags); 7181558Srgrimes (void) close(ofile); 7191558Srgrimes return (GOOD); 7201558Srgrimes } 7211558Srgrimes /* NOTREACHED */ 7221558Srgrimes} 7231558Srgrimes 7241558Srgrimes/* 725167011Smckusick * Set attributes for a file. 726167011Smckusick */ 727167011Smckusickvoid 728167011Smckusickset_extattr_file(char *name, void *buf, int size) 729167011Smckusick{ 730167011Smckusick struct extattr *eap, *eaend; 731167011Smckusick 732167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 733167011Smckusick eaend = buf + size; 734167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 735167011Smckusick /* 736167011Smckusick * Make sure this entry is complete. 737167011Smckusick */ 738167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 739167011Smckusick dprintf(stdout, "\n\t%scorrupted", 740167011Smckusick eap == buf ? "" : "remainder "); 741167011Smckusick break; 742167011Smckusick } 743167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 744167011Smckusick continue; 745167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 746167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 747167011Smckusick eap->ea_namelength, eap->ea_name); 748167011Smckusick /* 749167011Smckusick * First we try the general attribute setting interface. 750167011Smckusick * However, some attributes can only be set by root or 751167011Smckusick * by using special interfaces (for example, ACLs). 752167011Smckusick */ 753167011Smckusick if (extattr_set_file(name, eap->ea_namespace, eap->ea_name, 754167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 755167011Smckusick dprintf(stdout, " (set using extattr_set_file)"); 756167011Smckusick continue; 757167011Smckusick } 758167011Smckusick /* 759167011Smckusick * If the general interface refuses to set the attribute, 760167011Smckusick * then we try all the specialized interfaces that we 761167011Smckusick * know about. 762167011Smckusick */ 763167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 764167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 765167011Smckusick if (acl_set_file(name, ACL_TYPE_ACCESS, 766167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 767167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 768167011Smckusick continue; 769167011Smckusick } 770167011Smckusick } 771167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 772167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 773167011Smckusick if (acl_set_file(name, ACL_TYPE_DEFAULT, 774167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 775167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 776167011Smckusick continue; 777167011Smckusick } 778167011Smckusick } 779167011Smckusick vprintf(stdout, " (unable to set)"); 780167011Smckusick } 781167011Smckusick vprintf(stdout, "\n"); 782167011Smckusick} 783167011Smckusick 784167011Smckusick/* 785167011Smckusick * Set attributes for a symbolic link. 786167011Smckusick */ 787167011Smckusickstatic void 788167011Smckusickset_extattr_link(char *name, void *buf, int size) 789167011Smckusick{ 790167011Smckusick struct extattr *eap, *eaend; 791167011Smckusick 792167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 793167011Smckusick eaend = buf + size; 794167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 795167011Smckusick /* 796167011Smckusick * Make sure this entry is complete. 797167011Smckusick */ 798167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 799167011Smckusick dprintf(stdout, "\n\t%scorrupted", 800167011Smckusick eap == buf ? "" : "remainder "); 801167011Smckusick break; 802167011Smckusick } 803167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 804167011Smckusick continue; 805167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 806167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 807167011Smckusick eap->ea_namelength, eap->ea_name); 808167011Smckusick /* 809167011Smckusick * First we try the general attribute setting interface. 810167011Smckusick * However, some attributes can only be set by root or 811167011Smckusick * by using special interfaces (for example, ACLs). 812167011Smckusick */ 813167011Smckusick if (extattr_set_link(name, eap->ea_namespace, eap->ea_name, 814167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 815167011Smckusick dprintf(stdout, " (set using extattr_set_link)"); 816167011Smckusick continue; 817167011Smckusick } 818167011Smckusick /* 819167011Smckusick * If the general interface refuses to set the attribute, 820167011Smckusick * then we try all the specialized interfaces that we 821167011Smckusick * know about. 822167011Smckusick */ 823167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 824167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 825167011Smckusick if (acl_set_link_np(name, ACL_TYPE_ACCESS, 826167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 827167011Smckusick dprintf(stdout, " (set using acl_set_link_np)"); 828167011Smckusick continue; 829167011Smckusick } 830167011Smckusick } 831167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 832167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 833167011Smckusick if (acl_set_link_np(name, ACL_TYPE_DEFAULT, 834167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 835167011Smckusick dprintf(stdout, " (set using acl_set_link_np)"); 836167011Smckusick continue; 837167011Smckusick } 838167011Smckusick } 839167011Smckusick vprintf(stdout, " (unable to set)"); 840167011Smckusick } 841167011Smckusick vprintf(stdout, "\n"); 842167011Smckusick} 843167011Smckusick 844167011Smckusick/* 845167011Smckusick * Set attributes on a file descriptor. 846167011Smckusick */ 847167011Smckusickstatic void 848167011Smckusickset_extattr_fd(int fd, char *name, void *buf, int size) 849167011Smckusick{ 850167011Smckusick struct extattr *eap, *eaend; 851167011Smckusick 852167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 853167011Smckusick eaend = buf + size; 854167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 855167011Smckusick /* 856167011Smckusick * Make sure this entry is complete. 857167011Smckusick */ 858167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 859167011Smckusick dprintf(stdout, "\n\t%scorrupted", 860167011Smckusick eap == buf ? "" : "remainder "); 861167011Smckusick break; 862167011Smckusick } 863167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 864167011Smckusick continue; 865167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 866167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 867167011Smckusick eap->ea_namelength, eap->ea_name); 868167011Smckusick /* 869167011Smckusick * First we try the general attribute setting interface. 870167011Smckusick * However, some attributes can only be set by root or 871167011Smckusick * by using special interfaces (for example, ACLs). 872167011Smckusick */ 873167011Smckusick if (extattr_set_fd(fd, eap->ea_namespace, eap->ea_name, 874167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 875167011Smckusick dprintf(stdout, " (set using extattr_set_fd)"); 876167011Smckusick continue; 877167011Smckusick } 878167011Smckusick /* 879167011Smckusick * If the general interface refuses to set the attribute, 880167011Smckusick * then we try all the specialized interfaces that we 881167011Smckusick * know about. 882167011Smckusick */ 883167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 884167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 885167011Smckusick if (acl_set_fd(fd, EXTATTR_CONTENT(eap)) != -1) { 886167011Smckusick dprintf(stdout, " (set using acl_set_fd)"); 887167011Smckusick continue; 888167011Smckusick } 889167011Smckusick } 890167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 891167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 892167011Smckusick if (acl_set_file(name, ACL_TYPE_DEFAULT, 893167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 894167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 895167011Smckusick continue; 896167011Smckusick } 897167011Smckusick } 898167011Smckusick vprintf(stdout, " (unable to set)"); 899167011Smckusick } 900167011Smckusick vprintf(stdout, "\n"); 901167011Smckusick} 902167011Smckusick 903167011Smckusick/* 9041558Srgrimes * skip over bit maps on the tape 9051558Srgrimes */ 9061558Srgrimesvoid 90792837Simpskipmaps(void) 9081558Srgrimes{ 9091558Srgrimes 9101558Srgrimes while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 9111558Srgrimes skipfile(); 9121558Srgrimes} 9131558Srgrimes 9141558Srgrimes/* 9151558Srgrimes * skip over a file on the tape 9161558Srgrimes */ 9171558Srgrimesvoid 91892837Simpskipfile(void) 9191558Srgrimes{ 9201558Srgrimes 9211558Srgrimes curfile.action = SKIP; 922167011Smckusick getfile(xtrnull, xtrnull, xtrnull); 9231558Srgrimes} 9241558Srgrimes 9251558Srgrimes/* 9261558Srgrimes * Extract a file from the tape. 9271558Srgrimes * When an allocated block is found it is passed to the fill function; 9281558Srgrimes * when an unallocated block (hole) is found, a zeroed buffer is passed 9291558Srgrimes * to the skip function. 9301558Srgrimes */ 9311558Srgrimesvoid 932167011Smckusickgetfile(void (*datafill)(char *, long), void (*attrfill)(char *, long), 933167011Smckusick void (*skip)(char *, long)) 9341558Srgrimes{ 93592806Sobrien int i; 936167011Smckusick off_t size; 937167011Smckusick int curblk, attrsize; 938167011Smckusick void (*fillit)(char *, long); 9391558Srgrimes static char clearedbuf[MAXBSIZE]; 9401558Srgrimes char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 9411558Srgrimes char junk[TP_BSIZE]; 9421558Srgrimes 943167011Smckusick curblk = 0; 944167011Smckusick size = spcl.c_size; 945167011Smckusick attrsize = spcl.c_extsize; 9461558Srgrimes if (spcl.c_type == TS_END) 9471558Srgrimes panic("ran off end of tape\n"); 94898542Smckusick if (spcl.c_magic != FS_UFS2_MAGIC) 9491558Srgrimes panic("not at beginning of a file\n"); 9501558Srgrimes if (!gettingfile && setjmp(restart) != 0) 9511558Srgrimes return; 9521558Srgrimes gettingfile++; 953167011Smckusick fillit = datafill; 954167011Smckusick if (size == 0 && attrsize > 0) { 955167011Smckusick fillit = attrfill; 956167011Smckusick size = attrsize; 957167011Smckusick attrsize = 0; 958167011Smckusick } 9591558Srgrimesloop: 9601558Srgrimes for (i = 0; i < spcl.c_count; i++) { 961164911Sdwmalone if (!readmapflag && i > TP_NINDIR) { 962164911Sdwmalone if (Dflag) { 963164911Sdwmalone fprintf(stderr, "spcl.c_count = %jd\n", 964164911Sdwmalone (intmax_t)spcl.c_count); 965164911Sdwmalone break; 966164911Sdwmalone } else 967164911Sdwmalone panic("spcl.c_count = %jd\n", 968164911Sdwmalone (intmax_t)spcl.c_count); 969164911Sdwmalone } 97037923Simp if (readmapflag || spcl.c_addr[i]) { 9711558Srgrimes readtape(&buf[curblk++][0]); 9721558Srgrimes if (curblk == fssize / TP_BSIZE) { 973167011Smckusick (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 97423685Speter fssize : (curblk - 1) * TP_BSIZE + size)); 9751558Srgrimes curblk = 0; 9761558Srgrimes } 9771558Srgrimes } else { 9781558Srgrimes if (curblk > 0) { 979167011Smckusick (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 98023685Speter curblk * TP_BSIZE : 98123685Speter (curblk - 1) * TP_BSIZE + size)); 9821558Srgrimes curblk = 0; 9831558Srgrimes } 98423685Speter (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 98523685Speter TP_BSIZE : size)); 9861558Srgrimes } 9871558Srgrimes if ((size -= TP_BSIZE) <= 0) { 988167011Smckusick if (size > -TP_BSIZE && curblk > 0) { 989167011Smckusick (*fillit)((char *)buf, 990167011Smckusick (long)((curblk * TP_BSIZE) + size)); 991167011Smckusick curblk = 0; 992167011Smckusick } 993167011Smckusick if (attrsize > 0) { 994167011Smckusick fillit = attrfill; 995167011Smckusick size = attrsize; 996167011Smckusick attrsize = 0; 997167011Smckusick continue; 998167011Smckusick } 999167011Smckusick if (spcl.c_count - i > 1) 1000167011Smckusick dprintf(stdout, "skipping %d junk block(s)\n", 1001167011Smckusick spcl.c_count - i - 1); 1002164911Sdwmalone for (i++; i < spcl.c_count; i++) { 1003164911Sdwmalone if (!readmapflag && i > TP_NINDIR) { 1004164911Sdwmalone if (Dflag) { 1005164911Sdwmalone fprintf(stderr, 1006164911Sdwmalone "spcl.c_count = %jd\n", 1007164911Sdwmalone (intmax_t)spcl.c_count); 1008164911Sdwmalone break; 1009164911Sdwmalone } else 1010164911Sdwmalone panic("spcl.c_count = %jd\n", 1011164911Sdwmalone (intmax_t)spcl.c_count); 1012164911Sdwmalone } 101337923Simp if (readmapflag || spcl.c_addr[i]) 10141558Srgrimes readtape(junk); 1015164911Sdwmalone } 10161558Srgrimes break; 10171558Srgrimes } 10181558Srgrimes } 10191558Srgrimes if (gethead(&spcl) == GOOD && size > 0) { 10201558Srgrimes if (spcl.c_type == TS_ADDR) 10211558Srgrimes goto loop; 10221558Srgrimes dprintf(stdout, 102337240Sbde "Missing address (header) block for %s at %ld blocks\n", 10241558Srgrimes curfile.name, blksread); 10251558Srgrimes } 10261558Srgrimes if (curblk > 0) 1027167011Smckusick panic("getfile: lost data\n"); 10281558Srgrimes findinode(&spcl); 10291558Srgrimes gettingfile = 0; 10301558Srgrimes} 10311558Srgrimes 10321558Srgrimes/* 1033167011Smckusick * These variables are shared between the next two functions. 1034167011Smckusick */ 1035167011Smckusickstatic int extbufsize = 0; 1036167011Smckusickstatic char *extbuf; 1037167011Smckusickstatic int extloc; 1038167011Smckusick 1039167011Smckusick/* 1040167011Smckusick * Allocate a buffer into which to extract extended attributes. 1041167011Smckusick */ 1042167011Smckusickstatic char * 1043167011Smckusicksetupextattr(int extsize) 1044167011Smckusick{ 1045167011Smckusick 1046167011Smckusick extloc = 0; 1047167011Smckusick if (extsize <= extbufsize) 1048167011Smckusick return (extbuf); 1049167011Smckusick if (extbufsize > 0) 1050167011Smckusick free(extbuf); 1051167011Smckusick if ((extbuf = malloc(extsize)) != NULL) { 1052167011Smckusick extbufsize = extsize; 1053167011Smckusick return (extbuf); 1054167011Smckusick } 1055167011Smckusick extbufsize = 0; 1056167011Smckusick extbuf = NULL; 1057167011Smckusick fprintf(stderr, "Cannot extract %d bytes %s for inode %d, name %s\n", 1058167011Smckusick extsize, "of extended attributes", curfile.ino, curfile.name); 1059167011Smckusick return (NULL); 1060167011Smckusick} 1061167011Smckusick 1062167011Smckusick/* 1063167011Smckusick * Extract the next block of extended attributes. 1064167011Smckusick */ 1065167011Smckusickstatic void 1066167011Smckusickxtrattr(char *buf, long size) 1067167011Smckusick{ 1068167011Smckusick 1069167011Smckusick if (extloc + size > extbufsize) 1070167011Smckusick panic("overrun attribute buffer\n"); 1071167011Smckusick memmove(&extbuf[extloc], buf, size); 1072167011Smckusick extloc += size; 1073167011Smckusick} 1074167011Smckusick 1075167011Smckusick/* 10761558Srgrimes * Write out the next block of a file. 10771558Srgrimes */ 10781558Srgrimesstatic void 107992837Simpxtrfile(char *buf, long size) 10801558Srgrimes{ 10811558Srgrimes 10821558Srgrimes if (Nflag) 10831558Srgrimes return; 10841558Srgrimes if (write(ofile, buf, (int) size) == -1) { 10851558Srgrimes fprintf(stderr, 10861558Srgrimes "write error extracting inode %d, name %s\nwrite: %s\n", 10871558Srgrimes curfile.ino, curfile.name, strerror(errno)); 10881558Srgrimes } 10891558Srgrimes} 10901558Srgrimes 10911558Srgrimes/* 10921558Srgrimes * Skip over a hole in a file. 10931558Srgrimes */ 10941558Srgrimes/* ARGSUSED */ 10951558Srgrimesstatic void 109692837Simpxtrskip(char *buf, long size) 10971558Srgrimes{ 10981558Srgrimes 10991558Srgrimes if (lseek(ofile, size, SEEK_CUR) == -1) { 11001558Srgrimes fprintf(stderr, 11011558Srgrimes "seek error extracting inode %d, name %s\nlseek: %s\n", 11021558Srgrimes curfile.ino, curfile.name, strerror(errno)); 11031558Srgrimes done(1); 11041558Srgrimes } 11051558Srgrimes} 11061558Srgrimes 11071558Srgrimes/* 11081558Srgrimes * Collect the next block of a symbolic link. 11091558Srgrimes */ 11101558Srgrimesstatic void 111192837Simpxtrlnkfile(char *buf, long size) 11121558Srgrimes{ 11131558Srgrimes 11141558Srgrimes pathlen += size; 11151558Srgrimes if (pathlen > MAXPATHLEN) { 11161558Srgrimes fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 11171558Srgrimes curfile.name, lnkbuf, buf, pathlen); 11181558Srgrimes done(1); 11191558Srgrimes } 11201558Srgrimes (void) strcat(lnkbuf, buf); 11211558Srgrimes} 11221558Srgrimes 11231558Srgrimes/* 11241558Srgrimes * Skip over a hole in a symbolic link (should never happen). 11251558Srgrimes */ 11261558Srgrimes/* ARGSUSED */ 11271558Srgrimesstatic void 112892837Simpxtrlnkskip(char *buf, long size) 11291558Srgrimes{ 11301558Srgrimes 11311558Srgrimes fprintf(stderr, "unallocated block in symbolic link %s\n", 11321558Srgrimes curfile.name); 11331558Srgrimes done(1); 11341558Srgrimes} 11351558Srgrimes 11361558Srgrimes/* 11371558Srgrimes * Collect the next block of a bit map. 11381558Srgrimes */ 11391558Srgrimesstatic void 114092837Simpxtrmap(char *buf, long size) 11411558Srgrimes{ 11421558Srgrimes 114323685Speter memmove(map, buf, size); 11441558Srgrimes map += size; 11451558Srgrimes} 11461558Srgrimes 11471558Srgrimes/* 11481558Srgrimes * Skip over a hole in a bit map (should never happen). 11491558Srgrimes */ 11501558Srgrimes/* ARGSUSED */ 11511558Srgrimesstatic void 115292837Simpxtrmapskip(char *buf, long size) 11531558Srgrimes{ 11541558Srgrimes 11551558Srgrimes panic("hole in map\n"); 11561558Srgrimes map += size; 11571558Srgrimes} 11581558Srgrimes 11591558Srgrimes/* 11601558Srgrimes * Noop, when an extraction function is not needed. 11611558Srgrimes */ 11621558Srgrimes/* ARGSUSED */ 11631558Srgrimesvoid 116492837Simpxtrnull(char *buf, long size) 11651558Srgrimes{ 11661558Srgrimes 11671558Srgrimes return; 11681558Srgrimes} 11691558Srgrimes 11701558Srgrimes/* 11711558Srgrimes * Read TP_BSIZE blocks from the input. 11721558Srgrimes * Handle read errors, and end of media. 11731558Srgrimes */ 11741558Srgrimesstatic void 117592837Simpreadtape(char *buf) 11761558Srgrimes{ 1177164911Sdwmalone long rd, newvol, i, oldnumtrec; 11781558Srgrimes int cnt, seek_failed; 11791558Srgrimes 1180164911Sdwmalone if (blkcnt + (byteslide > 0) < numtrec) { 1181164911Sdwmalone memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE); 11821558Srgrimes blksread++; 118390827Siedowse tapeaddr++; 11841558Srgrimes return; 11851558Srgrimes } 1186164911Sdwmalone if (numtrec > 0) 1187164911Sdwmalone memmove(&tapebuf[-TP_BSIZE], 1188164911Sdwmalone &tapebuf[(numtrec-1) * TP_BSIZE], (long)TP_BSIZE); 1189164911Sdwmalone oldnumtrec = numtrec; 11901558Srgrimes for (i = 0; i < ntrec; i++) 11911558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 11921558Srgrimes if (numtrec == 0) 11931558Srgrimes numtrec = ntrec; 11941558Srgrimes cnt = ntrec * TP_BSIZE; 11951558Srgrimes rd = 0; 11961558Srgrimesgetmore: 11971558Srgrimes#ifdef RRESTORE 11981558Srgrimes if (host) 11991558Srgrimes i = rmtread(&tapebuf[rd], cnt); 12001558Srgrimes else 12011558Srgrimes#endif 12021558Srgrimes i = read(mt, &tapebuf[rd], cnt); 12031558Srgrimes /* 12041558Srgrimes * Check for mid-tape short read error. 12051558Srgrimes * If found, skip rest of buffer and start with the next. 12061558Srgrimes */ 1207203157Sjh if (!pipein && !pipecmdin && numtrec < ntrec && i > 0) { 12081558Srgrimes dprintf(stdout, "mid-media short read error.\n"); 12091558Srgrimes numtrec = ntrec; 12101558Srgrimes } 12111558Srgrimes /* 12121558Srgrimes * Handle partial block read. 12131558Srgrimes */ 1214203157Sjh if ((pipein || pipecmdin) && i == 0 && rd > 0) 12151558Srgrimes i = rd; 12161558Srgrimes else if (i > 0 && i != ntrec * TP_BSIZE) { 1217203157Sjh if (pipein || pipecmdin) { 12181558Srgrimes rd += i; 12191558Srgrimes cnt -= i; 12201558Srgrimes if (cnt > 0) 12211558Srgrimes goto getmore; 12221558Srgrimes i = rd; 12231558Srgrimes } else { 12241558Srgrimes /* 12251558Srgrimes * Short read. Process the blocks read. 12261558Srgrimes */ 12271558Srgrimes if (i % TP_BSIZE != 0) 12281558Srgrimes vprintf(stdout, 122937240Sbde "partial block read: %ld should be %ld\n", 12301558Srgrimes i, ntrec * TP_BSIZE); 12311558Srgrimes numtrec = i / TP_BSIZE; 12321558Srgrimes } 12331558Srgrimes } 12341558Srgrimes /* 12351558Srgrimes * Handle read error. 12361558Srgrimes */ 12371558Srgrimes if (i < 0) { 12381558Srgrimes fprintf(stderr, "Tape read error while "); 12391558Srgrimes switch (curfile.action) { 12401558Srgrimes default: 12411558Srgrimes fprintf(stderr, "trying to set up tape\n"); 12421558Srgrimes break; 12431558Srgrimes case UNKNOWN: 12441558Srgrimes fprintf(stderr, "trying to resynchronize\n"); 12451558Srgrimes break; 12461558Srgrimes case USING: 12471558Srgrimes fprintf(stderr, "restoring %s\n", curfile.name); 12481558Srgrimes break; 12491558Srgrimes case SKIP: 12501558Srgrimes fprintf(stderr, "skipping over inode %d\n", 12511558Srgrimes curfile.ino); 12521558Srgrimes break; 12531558Srgrimes } 12541558Srgrimes if (!yflag && !reply("continue")) 12551558Srgrimes done(1); 12561558Srgrimes i = ntrec * TP_BSIZE; 125723685Speter memset(tapebuf, 0, i); 12581558Srgrimes#ifdef RRESTORE 12591558Srgrimes if (host) 12601558Srgrimes seek_failed = (rmtseek(i, 1) < 0); 12611558Srgrimes else 12621558Srgrimes#endif 12631558Srgrimes seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 12641558Srgrimes 12651558Srgrimes if (seek_failed) { 12661558Srgrimes fprintf(stderr, 12671558Srgrimes "continuation failed: %s\n", strerror(errno)); 12681558Srgrimes done(1); 12691558Srgrimes } 12701558Srgrimes } 12711558Srgrimes /* 12721558Srgrimes * Handle end of tape. 12731558Srgrimes */ 12741558Srgrimes if (i == 0) { 12751558Srgrimes vprintf(stdout, "End-of-tape encountered\n"); 12761558Srgrimes if (!pipein) { 12771558Srgrimes newvol = volno + 1; 12781558Srgrimes volno = 0; 12791558Srgrimes numtrec = 0; 12801558Srgrimes getvol(newvol); 12811558Srgrimes readtape(buf); 12821558Srgrimes return; 12831558Srgrimes } 12841558Srgrimes if (rd % TP_BSIZE != 0) 1285203155Sjh panic("partial block read: %ld should be %ld\n", 12861558Srgrimes rd, ntrec * TP_BSIZE); 12871558Srgrimes terminateinput(); 128823685Speter memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 12891558Srgrimes } 1290164911Sdwmalone if (oldnumtrec == 0) 1291164911Sdwmalone blkcnt = 0; 1292164911Sdwmalone else 1293164911Sdwmalone blkcnt -= oldnumtrec; 1294164911Sdwmalone memmove(buf, 1295164911Sdwmalone &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE); 12961558Srgrimes blksread++; 129790827Siedowse tapeaddr++; 12981558Srgrimes} 12991558Srgrimes 13001558Srgrimesstatic void 130192837Simpfindtapeblksize(void) 13021558Srgrimes{ 130392806Sobrien long i; 13041558Srgrimes 13051558Srgrimes for (i = 0; i < ntrec; i++) 13061558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 13071558Srgrimes blkcnt = 0; 13081558Srgrimes#ifdef RRESTORE 13091558Srgrimes if (host) 13101558Srgrimes i = rmtread(tapebuf, ntrec * TP_BSIZE); 13111558Srgrimes else 13121558Srgrimes#endif 13131558Srgrimes i = read(mt, tapebuf, ntrec * TP_BSIZE); 13141558Srgrimes 13151558Srgrimes if (i <= 0) { 13161558Srgrimes fprintf(stderr, "tape read error: %s\n", strerror(errno)); 13171558Srgrimes done(1); 13181558Srgrimes } 13191558Srgrimes if (i % TP_BSIZE != 0) { 132037240Sbde fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 13211558Srgrimes i, "is not a multiple of dump block size", TP_BSIZE); 13221558Srgrimes done(1); 13231558Srgrimes } 13241558Srgrimes ntrec = i / TP_BSIZE; 13251558Srgrimes numtrec = ntrec; 132637240Sbde vprintf(stdout, "Tape block size is %ld\n", ntrec); 13271558Srgrimes} 13281558Srgrimes 13291558Srgrimesvoid 133092837Simpclosemt(void) 13311558Srgrimes{ 13321558Srgrimes 13331558Srgrimes if (mt < 0) 13341558Srgrimes return; 1335128175Sgreen if (pipecmdin) { 1336128175Sgreen pclose(popenfp); 1337128175Sgreen popenfp = NULL; 1338128175Sgreen } else 13391558Srgrimes#ifdef RRESTORE 13401558Srgrimes if (host) 13411558Srgrimes rmtclose(); 13421558Srgrimes else 13431558Srgrimes#endif 13441558Srgrimes (void) close(mt); 13451558Srgrimes} 13461558Srgrimes 13471558Srgrimes/* 13481558Srgrimes * Read the next block from the tape. 13491558Srgrimes * If it is not any valid header, return an error. 13501558Srgrimes */ 13511558Srgrimesstatic int 135292837Simpgethead(struct s_spcl *buf) 13531558Srgrimes{ 13541558Srgrimes long i; 13551558Srgrimes 135698542Smckusick readtape((char *)buf); 135798542Smckusick if (buf->c_magic != FS_UFS2_MAGIC && buf->c_magic != NFS_MAGIC) { 135898542Smckusick if (buf->c_magic == OFS_MAGIC) { 135998542Smckusick fprintf(stderr, 136098542Smckusick "Format of dump tape is too old. Must use\n"); 136198542Smckusick fprintf(stderr, 136298542Smckusick "a version of restore from before 2002.\n"); 136398542Smckusick return (FAIL); 136498542Smckusick } 136598542Smckusick if (swabl(buf->c_magic) != FS_UFS2_MAGIC && 136698542Smckusick buf->c_magic != NFS_MAGIC) { 136798542Smckusick if (buf->c_magic == OFS_MAGIC) { 136898542Smckusick fprintf(stderr, 136998542Smckusick "Format of dump tape is too old. Must use\n"); 137098542Smckusick fprintf(stderr, 137198542Smckusick "a version of restore from before 2002.\n"); 13721558Srgrimes } 13731558Srgrimes return (FAIL); 137423096Simp } 137598542Smckusick if (!Bcvt) { 137698542Smckusick vprintf(stdout, "Note: Doing Byte swapping\n"); 137798542Smckusick Bcvt = 1; 13781558Srgrimes } 13791558Srgrimes } 138098542Smckusick if (checksum((int *)buf) == FAIL) 138198542Smckusick return (FAIL); 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 */ 139698542Smckusick buf->c_size = buf->c_count * TP_BSIZE; 139737923Simp if (buf->c_count > TP_NINDIR) 139837923Simp readmapflag = 1; 139937923Simp else 140037923Simp for (i = 0; i < buf->c_count; i++) 140137923Simp buf->c_addr[i]++; 1402179218Smckusick /* FALL THROUGH */ 14031558Srgrimes 14041558Srgrimes case TS_TAPE: 1405179218Smckusick if (buf->c_magic == NFS_MAGIC && 1406179218Smckusick (buf->c_flags & NFS_DR_NEWINODEFMT) == 0) 1407179218Smckusick oldinofmt = 1; 1408179218Smckusick /* FALL THROUGH */ 1409179218Smckusick 14101558Srgrimes case TS_END: 14111558Srgrimes buf->c_inumber = 0; 1412179218Smckusick /* FALL THROUGH */ 14131558Srgrimes 1414179218Smckusick case TS_ADDR: 14151558Srgrimes case TS_INODE: 141698542Smckusick /* 141798542Smckusick * For old dump tapes, have to copy up old fields to 141898542Smckusick * new locations. 141998542Smckusick */ 142098542Smckusick if (buf->c_magic == NFS_MAGIC) { 142198542Smckusick buf->c_tapea = buf->c_old_tapea; 142298542Smckusick buf->c_firstrec = buf->c_old_firstrec; 142398542Smckusick buf->c_date = _time32_to_time(buf->c_old_date); 142498542Smckusick buf->c_ddate = _time32_to_time(buf->c_old_ddate); 142598542Smckusick buf->c_atime = _time32_to_time(buf->c_old_atime); 142698542Smckusick buf->c_mtime = _time32_to_time(buf->c_old_mtime); 1427179219Smckusick buf->c_birthtime = 0; 1428179219Smckusick buf->c_birthtimensec = 0; 1429179219Smckusick buf->c_extsize = 0; 143098542Smckusick } 143198542Smckusick break; 143298542Smckusick 14331558Srgrimes default: 14341558Srgrimes panic("gethead: unknown inode type %d\n", buf->c_type); 14351558Srgrimes break; 14361558Srgrimes } 1437179218Smckusick if (dumpdate != 0 && _time64_to_time(buf->c_date) != dumpdate) 1438179218Smckusick fprintf(stderr, "Header with wrong dumpdate.\n"); 1439144099Simp /* 1440144099Simp * If we're restoring a filesystem with the old (FreeBSD 1) 1441144099Simp * format inodes, copy the uid/gid to the new location 1442144099Simp */ 1443144099Simp if (oldinofmt) { 1444144099Simp buf->c_uid = buf->c_spare1[1]; 1445144099Simp buf->c_gid = buf->c_spare1[2]; 1446144099Simp } 144798542Smckusick buf->c_magic = FS_UFS2_MAGIC; 144890827Siedowse tapeaddr = buf->c_tapea; 14491558Srgrimes if (dflag) 14501558Srgrimes accthdr(buf); 14511558Srgrimes return(GOOD); 14521558Srgrimes} 14531558Srgrimes 14541558Srgrimes/* 14551558Srgrimes * Check that a header is where it belongs and predict the next header 14561558Srgrimes */ 14571558Srgrimesstatic void 145892837Simpaccthdr(struct s_spcl *header) 14591558Srgrimes{ 14601558Srgrimes static ino_t previno = 0x7fffffff; 14611558Srgrimes static int prevtype; 14621558Srgrimes static long predict; 14631558Srgrimes long blks, i; 14641558Srgrimes 14651558Srgrimes if (header->c_type == TS_TAPE) { 146698542Smckusick fprintf(stderr, "Volume header "); 14671558Srgrimes if (header->c_firstrec) 1468203155Sjh fprintf(stderr, "begins with record %jd", 1469203155Sjh (intmax_t)header->c_firstrec); 14701558Srgrimes fprintf(stderr, "\n"); 14711558Srgrimes previno = 0x7fffffff; 14721558Srgrimes return; 14731558Srgrimes } 14741558Srgrimes if (previno == 0x7fffffff) 14751558Srgrimes goto newcalc; 14761558Srgrimes switch (prevtype) { 14771558Srgrimes case TS_BITS: 147823685Speter fprintf(stderr, "Dumped inodes map header"); 14791558Srgrimes break; 14801558Srgrimes case TS_CLRI: 148123685Speter fprintf(stderr, "Used inodes map header"); 14821558Srgrimes break; 14831558Srgrimes case TS_INODE: 14841558Srgrimes fprintf(stderr, "File header, ino %d", previno); 14851558Srgrimes break; 14861558Srgrimes case TS_ADDR: 14871558Srgrimes fprintf(stderr, "File continuation header, ino %d", previno); 14881558Srgrimes break; 14891558Srgrimes case TS_END: 14901558Srgrimes fprintf(stderr, "End of tape header"); 14911558Srgrimes break; 14921558Srgrimes } 14931558Srgrimes if (predict != blksread - 1) 149437240Sbde fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 14951558Srgrimes predict, blksread - 1); 14961558Srgrimes fprintf(stderr, "\n"); 14971558Srgrimesnewcalc: 14981558Srgrimes blks = 0; 14991558Srgrimes if (header->c_type != TS_END) 15001558Srgrimes for (i = 0; i < header->c_count; i++) 150137923Simp if (readmapflag || header->c_addr[i] != 0) 15021558Srgrimes blks++; 15031558Srgrimes predict = blks; 15041558Srgrimes blksread = 0; 15051558Srgrimes prevtype = header->c_type; 15061558Srgrimes previno = header->c_inumber; 15071558Srgrimes} 15081558Srgrimes 15091558Srgrimes/* 15101558Srgrimes * Find an inode header. 151190573Siedowse * Complain if had to skip. 15121558Srgrimes */ 15131558Srgrimesstatic void 151492837Simpfindinode(struct s_spcl *header) 15151558Srgrimes{ 15161558Srgrimes static long skipcnt = 0; 15171558Srgrimes long i; 15181558Srgrimes char buf[TP_BSIZE]; 151990608Siedowse int htype; 15201558Srgrimes 15211558Srgrimes curfile.name = "<name unknown>"; 15221558Srgrimes curfile.action = UNKNOWN; 152398542Smckusick curfile.mode = 0; 15241558Srgrimes curfile.ino = 0; 15251558Srgrimes do { 152690608Siedowse htype = header->c_type; 152790608Siedowse switch (htype) { 15281558Srgrimes 15291558Srgrimes case TS_ADDR: 15301558Srgrimes /* 15311558Srgrimes * Skip up to the beginning of the next record 15321558Srgrimes */ 15331558Srgrimes for (i = 0; i < header->c_count; i++) 15341558Srgrimes if (header->c_addr[i]) 15351558Srgrimes readtape(buf); 15361558Srgrimes while (gethead(header) == FAIL || 1537164911Sdwmalone _time64_to_time(header->c_date) != dumpdate) { 15381558Srgrimes skipcnt++; 1539164911Sdwmalone if (Dflag) { 1540164911Sdwmalone byteslide++; 1541164911Sdwmalone if (byteslide < TP_BSIZE) { 1542164911Sdwmalone blkcnt--; 1543164911Sdwmalone blksread--; 1544164911Sdwmalone } else 1545164911Sdwmalone byteslide = 0; 1546164911Sdwmalone } 1547164911Sdwmalone } 15481558Srgrimes break; 15491558Srgrimes 15501558Srgrimes case TS_INODE: 155198542Smckusick curfile.mode = header->c_mode; 155298542Smckusick curfile.uid = header->c_uid; 155398542Smckusick curfile.gid = header->c_gid; 155498542Smckusick curfile.file_flags = header->c_file_flags; 155598542Smckusick curfile.rdev = header->c_rdev; 155698542Smckusick curfile.atime_sec = header->c_atime; 155798542Smckusick curfile.atime_nsec = header->c_atimensec; 155898542Smckusick curfile.mtime_sec = header->c_mtime; 155998542Smckusick curfile.mtime_nsec = header->c_mtimensec; 1560100207Smckusick curfile.birthtime_sec = header->c_birthtime; 1561100207Smckusick curfile.birthtime_nsec = header->c_birthtimensec; 1562167011Smckusick curfile.extsize = header->c_extsize; 156398542Smckusick curfile.size = header->c_size; 15641558Srgrimes curfile.ino = header->c_inumber; 15651558Srgrimes break; 15661558Srgrimes 15671558Srgrimes case TS_END: 156890820Siedowse /* If we missed some tapes, get another volume. */ 156990820Siedowse if (tapesread & (tapesread + 1)) { 157090820Siedowse getvol(0); 157190820Siedowse continue; 157290820Siedowse } 15731558Srgrimes curfile.ino = maxino; 15741558Srgrimes break; 15751558Srgrimes 15761558Srgrimes case TS_CLRI: 15771558Srgrimes curfile.name = "<file removal list>"; 15781558Srgrimes break; 15791558Srgrimes 15801558Srgrimes case TS_BITS: 15811558Srgrimes curfile.name = "<file dump list>"; 15821558Srgrimes break; 15831558Srgrimes 15841558Srgrimes case TS_TAPE: 1585164911Sdwmalone if (Dflag) 1586164911Sdwmalone fprintf(stderr, "unexpected tape header\n"); 1587164911Sdwmalone else 1588164911Sdwmalone panic("unexpected tape header\n"); 15891558Srgrimes 15901558Srgrimes default: 1591164911Sdwmalone if (Dflag) 1592164911Sdwmalone fprintf(stderr, "unknown tape header type %d\n", 1593164911Sdwmalone spcl.c_type); 1594164911Sdwmalone else 1595164911Sdwmalone panic("unknown tape header type %d\n", 1596164911Sdwmalone spcl.c_type); 1597164911Sdwmalone while (gethead(header) == FAIL || 1598164911Sdwmalone _time64_to_time(header->c_date) != dumpdate) { 1599164911Sdwmalone skipcnt++; 1600164911Sdwmalone if (Dflag) { 1601164911Sdwmalone byteslide++; 1602164911Sdwmalone if (byteslide < TP_BSIZE) { 1603164911Sdwmalone blkcnt--; 1604164911Sdwmalone blksread--; 1605164911Sdwmalone } else 1606164911Sdwmalone byteslide = 0; 1607164911Sdwmalone } 1608164911Sdwmalone } 16091558Srgrimes 16101558Srgrimes } 161190608Siedowse } while (htype == TS_ADDR); 16121558Srgrimes if (skipcnt > 0) 1613164911Sdwmalone fprintf(stderr, "resync restore, skipped %ld %s\n", 1614164911Sdwmalone skipcnt, Dflag ? "bytes" : "blocks"); 16151558Srgrimes skipcnt = 0; 16161558Srgrimes} 16171558Srgrimes 16181558Srgrimesstatic int 161992837Simpchecksum(int *buf) 16201558Srgrimes{ 162192806Sobrien int i, j; 16221558Srgrimes 16231558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 16241558Srgrimes i = 0; 162598542Smckusick if (!Bcvt) { 16261558Srgrimes do 16271558Srgrimes i += *buf++; 16281558Srgrimes while (--j); 16291558Srgrimes } else { 16301558Srgrimes /* What happens if we want to read restore tapes 16311558Srgrimes for a 16bit int machine??? */ 16328871Srgrimes do 16331558Srgrimes i += swabl(*buf++); 16341558Srgrimes while (--j); 16351558Srgrimes } 16368871Srgrimes 16371558Srgrimes if (i != CHECKSUM) { 16381558Srgrimes fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 16391558Srgrimes curfile.ino, curfile.name); 16401558Srgrimes return(FAIL); 16411558Srgrimes } 16421558Srgrimes return(GOOD); 16431558Srgrimes} 16441558Srgrimes 16451558Srgrimes#ifdef RRESTORE 16461558Srgrimes#include <stdarg.h> 16471558Srgrimes 16481558Srgrimesvoid 16491558Srgrimesmsg(const char *fmt, ...) 16501558Srgrimes{ 16511558Srgrimes va_list ap; 16521558Srgrimes va_start(ap, fmt); 16531558Srgrimes (void)vfprintf(stderr, fmt, ap); 16541558Srgrimes va_end(ap); 16551558Srgrimes} 16561558Srgrimes#endif /* RRESTORE */ 16571558Srgrimes 16581558Srgrimesstatic u_char * 165992837Simpswabshort(u_char *sp, int n) 16601558Srgrimes{ 16611558Srgrimes char c; 16621558Srgrimes 16631558Srgrimes while (--n >= 0) { 16641558Srgrimes c = sp[0]; sp[0] = sp[1]; sp[1] = c; 16651558Srgrimes sp += 2; 16661558Srgrimes } 16671558Srgrimes return (sp); 16681558Srgrimes} 16691558Srgrimes 16701558Srgrimesstatic u_char * 167192837Simpswablong(u_char *sp, int n) 16721558Srgrimes{ 16731558Srgrimes char c; 16741558Srgrimes 16751558Srgrimes while (--n >= 0) { 16761558Srgrimes c = sp[0]; sp[0] = sp[3]; sp[3] = c; 16771558Srgrimes c = sp[2]; sp[2] = sp[1]; sp[1] = c; 16781558Srgrimes sp += 4; 16791558Srgrimes } 16801558Srgrimes return (sp); 16811558Srgrimes} 16821558Srgrimes 168398542Smckusickstatic u_char * 168498542Smckusickswabquad(u_char *sp, int n) 168598542Smckusick{ 168698542Smckusick char c; 168798542Smckusick 168898542Smckusick while (--n >= 0) { 168998542Smckusick c = sp[0]; sp[0] = sp[7]; sp[7] = c; 169098542Smckusick c = sp[1]; sp[1] = sp[6]; sp[6] = c; 169198542Smckusick c = sp[2]; sp[2] = sp[5]; sp[5] = c; 169298542Smckusick c = sp[3]; sp[3] = sp[4]; sp[4] = c; 169398542Smckusick sp += 8; 169498542Smckusick } 169598542Smckusick return (sp); 169698542Smckusick} 169798542Smckusick 16981558Srgrimesvoid 169992837Simpswabst(u_char *cp, u_char *sp) 17001558Srgrimes{ 17011558Srgrimes int n = 0; 17021558Srgrimes 17031558Srgrimes while (*cp) { 17041558Srgrimes switch (*cp) { 17051558Srgrimes case '0': case '1': case '2': case '3': case '4': 17061558Srgrimes case '5': case '6': case '7': case '8': case '9': 17071558Srgrimes n = (n * 10) + (*cp++ - '0'); 17081558Srgrimes continue; 17098871Srgrimes 17101558Srgrimes case 's': case 'w': case 'h': 17111558Srgrimes if (n == 0) 17121558Srgrimes n = 1; 17131558Srgrimes sp = swabshort(sp, n); 17141558Srgrimes break; 17151558Srgrimes 17161558Srgrimes case 'l': 17171558Srgrimes if (n == 0) 17181558Srgrimes n = 1; 17191558Srgrimes sp = swablong(sp, n); 17201558Srgrimes break; 17211558Srgrimes 172298542Smckusick case 'q': 17231558Srgrimes if (n == 0) 17241558Srgrimes n = 1; 172598542Smckusick sp = swabquad(sp, n); 172698542Smckusick break; 172798542Smckusick 172898542Smckusick case 'b': 172998542Smckusick if (n == 0) 173098542Smckusick n = 1; 17311558Srgrimes sp += n; 17321558Srgrimes break; 173398542Smckusick 173498542Smckusick default: 173598542Smckusick fprintf(stderr, "Unknown conversion character: %c\n", 173698542Smckusick *cp); 173798542Smckusick done(0); 173898542Smckusick break; 17391558Srgrimes } 17401558Srgrimes cp++; 17411558Srgrimes n = 0; 17421558Srgrimes } 17431558Srgrimes} 17441558Srgrimes 17451558Srgrimesstatic u_long 174692837Simpswabl(u_long x) 17471558Srgrimes{ 17481558Srgrimes swabst((u_char *)"l", (u_char *)&x); 17491558Srgrimes return (x); 17501558Srgrimes} 1751