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 } 167241848Seadler /* no longer need or want root privileges */ 168241848Seadler if (setuid(getuid()) != 0) { 169241848Seadler fprintf(stderr, "setuid failed\n"); 170241848Seadler done(1); 171241848Seadler } 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; 263269651Smckusick if (((TP_BSIZE - 1) & stbuf.st_blksize) != 0) { 264269651Smckusick fprintf(stderr, "Warning: filesystem with non-multiple-of-%d " 265269651Smckusick "blocksize (%d);\n", TP_BSIZE, stbuf.st_blksize); 266269651Smckusick fssize = roundup(fssize, TP_BSIZE); 267269651Smckusick fprintf(stderr, "\twriting using blocksize %ld\n", fssize); 2681558Srgrimes } 2691558Srgrimes if (spcl.c_volume != 1) { 2701558Srgrimes fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2711558Srgrimes done(1); 2721558Srgrimes } 2731558Srgrimes if (gethead(&spcl) == FAIL) { 27437240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 2751558Srgrimes panic("no header after volume mark!\n"); 2761558Srgrimes } 2771558Srgrimes findinode(&spcl); 2781558Srgrimes if (spcl.c_type != TS_CLRI) { 2791558Srgrimes fprintf(stderr, "Cannot find file removal list\n"); 2801558Srgrimes done(1); 2811558Srgrimes } 2821558Srgrimes maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 283241013Smdf dprintf(stdout, "maxino = %ju\n", (uintmax_t)maxino); 2841558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2851558Srgrimes if (map == NULL) 28623685Speter panic("no memory for active inode map\n"); 28723685Speter usedinomap = map; 2881558Srgrimes curfile.action = USING; 289167011Smckusick getfile(xtrmap, xtrmapskip, xtrmapskip); 2901558Srgrimes if (spcl.c_type != TS_BITS) { 2911558Srgrimes fprintf(stderr, "Cannot find file dump list\n"); 2921558Srgrimes done(1); 2931558Srgrimes } 2941558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2951558Srgrimes if (map == (char *)NULL) 2961558Srgrimes panic("no memory for file dump list\n"); 2971558Srgrimes dumpmap = map; 2981558Srgrimes curfile.action = USING; 299167011Smckusick getfile(xtrmap, xtrmapskip, xtrmapskip); 30023685Speter /* 30123685Speter * If there may be whiteout entries on the tape, pretend that the 30223685Speter * whiteout inode exists, so that the whiteout entries can be 30323685Speter * extracted. 30423685Speter */ 30598542Smckusick SETINO(WINO, dumpmap); 30690820Siedowse /* 'r' restores don't call getvol() for tape 1, so mark it as read. */ 30790820Siedowse if (command == 'r') 30890820Siedowse tapesread = 1; 3091558Srgrimes} 3101558Srgrimes 3111558Srgrimes/* 3121558Srgrimes * Prompt user to load a new dump volume. 3131558Srgrimes * "Nextvol" is the next suggested volume to use. 3141558Srgrimes * This suggested volume is enforced when doing full 31537906Scharnier * or incremental restores, but can be overridden by 3161558Srgrimes * the user when only extracting a subset of the files. 3171558Srgrimes */ 3181558Srgrimesvoid 31992837Simpgetvol(long nextvol) 3201558Srgrimes{ 32198542Smckusick int64_t prevtapea; 32298542Smckusick long i, newvol, savecnt; 3231558Srgrimes union u_spcl tmpspcl; 3241558Srgrimes# define tmpbuf tmpspcl.s_spcl 3251558Srgrimes char buf[TP_BSIZE]; 3261558Srgrimes 3271558Srgrimes if (nextvol == 1) { 3281558Srgrimes tapesread = 0; 3291558Srgrimes gettingfile = 0; 3301558Srgrimes } 33190827Siedowse prevtapea = tapeaddr; 33290827Siedowse savecnt = blksread; 3331558Srgrimes if (pipein) { 33469906Siedowse if (nextvol != 1) { 3351558Srgrimes panic("Changing volumes on pipe input?\n"); 33669906Siedowse /* Avoid looping if we couldn't ask the user. */ 33769906Siedowse if (yflag || ferror(terminal) || feof(terminal)) 33869906Siedowse done(1); 33969906Siedowse } 3401558Srgrimes if (volno == 1) 3411558Srgrimes return; 3421558Srgrimes goto gethdr; 3431558Srgrimes } 3441558Srgrimesagain: 3451558Srgrimes if (pipein) 3461558Srgrimes done(1); /* pipes do not get a second chance */ 34790608Siedowse if (command == 'R' || command == 'r' || curfile.action != SKIP) 3481558Srgrimes newvol = nextvol; 34990608Siedowse else 3501558Srgrimes newvol = 0; 3511558Srgrimes while (newvol <= 0) { 3521558Srgrimes if (tapesread == 0) { 35390820Siedowse fprintf(stderr, "%s%s%s%s%s%s%s", 3541558Srgrimes "You have not read any tapes yet.\n", 35590820Siedowse "If you are extracting just a few files,", 35690820Siedowse " start with the last volume\n", 35790820Siedowse "and work towards the first; restore", 35890820Siedowse " can quickly skip tapes that\n", 35990820Siedowse "have no further files to extract.", 36090820Siedowse " Otherwise, begin with volume 1.\n"); 3611558Srgrimes } else { 3621558Srgrimes fprintf(stderr, "You have read volumes"); 3631558Srgrimes strcpy(buf, ": "); 36490820Siedowse for (i = 0; i < 32; i++) 3651558Srgrimes if (tapesread & (1 << i)) { 36690820Siedowse fprintf(stderr, "%s%ld", buf, i + 1); 3671558Srgrimes strcpy(buf, ", "); 3681558Srgrimes } 3691558Srgrimes fprintf(stderr, "\n"); 3701558Srgrimes } 3711558Srgrimes do { 3721558Srgrimes fprintf(stderr, "Specify next volume #: "); 3731558Srgrimes (void) fflush(stderr); 37469906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 37569906Siedowse done(1); 37669906Siedowse } while (buf[0] == '\n'); 3771558Srgrimes newvol = atoi(buf); 3781558Srgrimes if (newvol <= 0) { 3791558Srgrimes fprintf(stderr, 3801558Srgrimes "Volume numbers are positive numerics\n"); 3811558Srgrimes } 3821558Srgrimes } 3831558Srgrimes if (newvol == volno) { 38490820Siedowse tapesread |= 1 << (volno - 1); 3851558Srgrimes return; 3861558Srgrimes } 3871558Srgrimes closemt(); 38837240Sbde fprintf(stderr, "Mount tape volume %ld\n", newvol); 3891558Srgrimes fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 3901558Srgrimes fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 3911558Srgrimes (void) fflush(stderr); 39269906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 3931558Srgrimes done(1); 3941558Srgrimes if (!strcmp(buf, "none\n")) { 3951558Srgrimes terminateinput(); 3961558Srgrimes return; 3971558Srgrimes } 3981558Srgrimes if (buf[0] != '\n') { 3991558Srgrimes (void) strcpy(magtape, buf); 4001558Srgrimes magtape[strlen(magtape) - 1] = '\0'; 4011558Srgrimes } 402128175Sgreen if (pipecmdin) { 403128175Sgreen char volno[sizeof("2147483647")]; 404128175Sgreen 405203155Sjh (void)sprintf(volno, "%ld", newvol); 406128175Sgreen if (setenv("RESTORE_VOLUME", volno, 1) == -1) { 407128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 408128175Sgreen strerror(errno)); 409128175Sgreen done(1); 410128175Sgreen } 411128175Sgreen popenfp = popen(magtape, "r"); 412128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 413128175Sgreen } else 4141558Srgrimes#ifdef RRESTORE 4151558Srgrimes if (host) 4161558Srgrimes mt = rmtopen(magtape, 0); 4171558Srgrimes else 4181558Srgrimes#endif 4191558Srgrimes mt = open(magtape, O_RDONLY, 0); 4201558Srgrimes 4211558Srgrimes if (mt == -1) { 4221558Srgrimes fprintf(stderr, "Cannot open %s\n", magtape); 4231558Srgrimes volno = -1; 4241558Srgrimes goto again; 4251558Srgrimes } 4261558Srgrimesgethdr: 4271558Srgrimes volno = newvol; 4281558Srgrimes setdumpnum(); 4291558Srgrimes FLUSHTAPEBUF(); 4301558Srgrimes if (gethead(&tmpbuf) == FAIL) { 43137240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 4321558Srgrimes fprintf(stderr, "tape is not dump tape\n"); 4331558Srgrimes volno = 0; 4341558Srgrimes goto again; 4351558Srgrimes } 4361558Srgrimes if (tmpbuf.c_volume != volno) { 437203155Sjh fprintf(stderr, "Wrong volume (%jd)\n", 438203155Sjh (intmax_t)tmpbuf.c_volume); 4391558Srgrimes volno = 0; 4401558Srgrimes goto again; 4411558Srgrimes } 44298542Smckusick if (_time64_to_time(tmpbuf.c_date) != dumpdate || 44398542Smckusick _time64_to_time(tmpbuf.c_ddate) != dumptime) { 44498542Smckusick time_t t = _time64_to_time(tmpbuf.c_date); 44585635Sdillon fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t)); 4461558Srgrimes fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 4471558Srgrimes volno = 0; 4481558Srgrimes goto again; 4491558Srgrimes } 45090820Siedowse tapesread |= 1 << (volno - 1); 4511558Srgrimes blksread = savecnt; 4521558Srgrimes /* 4531558Srgrimes * If continuing from the previous volume, skip over any 4541558Srgrimes * blocks read already at the end of the previous volume. 4551558Srgrimes * 4561558Srgrimes * If coming to this volume at random, skip to the beginning 4571558Srgrimes * of the next record. 4581558Srgrimes */ 459203155Sjh dprintf(stdout, "last rec %jd, tape starts with %jd\n", 460203155Sjh (intmax_t)prevtapea, (intmax_t)tmpbuf.c_tapea); 46198542Smckusick if (tmpbuf.c_type == TS_TAPE) { 46290608Siedowse if (curfile.action != USING) { 46390608Siedowse /* 46490608Siedowse * XXX Dump incorrectly sets c_count to 1 in the 46590608Siedowse * volume header of the first tape, so ignore 46690608Siedowse * c_count when volno == 1. 46790608Siedowse */ 46890608Siedowse if (volno != 1) 46990608Siedowse for (i = tmpbuf.c_count; i > 0; i--) 47090608Siedowse readtape(buf); 47190827Siedowse } else if (tmpbuf.c_tapea <= prevtapea) { 4721558Srgrimes /* 47390827Siedowse * Normally the value of c_tapea in the volume 47490827Siedowse * header is the record number of the header itself. 47590827Siedowse * However in the volume header following an EOT- 47690827Siedowse * terminated tape, it is the record number of the 47790827Siedowse * first continuation data block (dump bug?). 47890827Siedowse * 47990827Siedowse * The next record we want is `prevtapea + 1'. 4801558Srgrimes */ 48190827Siedowse i = prevtapea + 1 - tmpbuf.c_tapea; 48237240Sbde dprintf(stderr, "Skipping %ld duplicate record%s.\n", 4831558Srgrimes i, i > 1 ? "s" : ""); 4841558Srgrimes while (--i >= 0) 4851558Srgrimes readtape(buf); 4861558Srgrimes } 4871558Srgrimes } 48890608Siedowse if (curfile.action == USING) { 4891558Srgrimes if (volno == 1) 4901558Srgrimes panic("active file into volume 1\n"); 4911558Srgrimes return; 4921558Srgrimes } 4931558Srgrimes (void) gethead(&spcl); 4941558Srgrimes findinode(&spcl); 4951558Srgrimes if (gettingfile) { 4961558Srgrimes gettingfile = 0; 4971558Srgrimes longjmp(restart, 1); 4981558Srgrimes } 4991558Srgrimes} 5001558Srgrimes 5011558Srgrimes/* 5021558Srgrimes * Handle unexpected EOF. 5031558Srgrimes */ 5041558Srgrimesstatic void 50592837Simpterminateinput(void) 5061558Srgrimes{ 5071558Srgrimes 5081558Srgrimes if (gettingfile && curfile.action == USING) { 5091558Srgrimes printf("Warning: %s %s\n", 5101558Srgrimes "End-of-input encountered while extracting", curfile.name); 5111558Srgrimes } 5121558Srgrimes curfile.name = "<name unknown>"; 5131558Srgrimes curfile.action = UNKNOWN; 51498542Smckusick curfile.mode = 0; 5151558Srgrimes curfile.ino = maxino; 5161558Srgrimes if (gettingfile) { 5171558Srgrimes gettingfile = 0; 5181558Srgrimes longjmp(restart, 1); 5191558Srgrimes } 5201558Srgrimes} 5211558Srgrimes 5221558Srgrimes/* 5231558Srgrimes * handle multiple dumps per tape by skipping forward to the 5241558Srgrimes * appropriate one. 5251558Srgrimes */ 5261558Srgrimesstatic void 52792837Simpsetdumpnum(void) 5281558Srgrimes{ 5291558Srgrimes struct mtop tcom; 5301558Srgrimes 5311558Srgrimes if (dumpnum == 1 || volno != 1) 5321558Srgrimes return; 5331558Srgrimes if (pipein) { 5341558Srgrimes fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 5351558Srgrimes done(1); 5361558Srgrimes } 5371558Srgrimes tcom.mt_op = MTFSF; 5381558Srgrimes tcom.mt_count = dumpnum - 1; 5391558Srgrimes#ifdef RRESTORE 5401558Srgrimes if (host) 5411558Srgrimes rmtioctl(MTFSF, dumpnum - 1); 5428871Srgrimes else 5431558Srgrimes#endif 544128175Sgreen if (!pipecmdin && ioctl(mt, MTIOCTOP, (char *)&tcom) < 0) 5451558Srgrimes fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 5461558Srgrimes} 5471558Srgrimes 5481558Srgrimesvoid 54992837Simpprintdumpinfo(void) 5501558Srgrimes{ 55185635Sdillon time_t t; 55298542Smckusick t = _time64_to_time(spcl.c_date); 55385635Sdillon fprintf(stdout, "Dump date: %s", ctime(&t)); 55498542Smckusick t = _time64_to_time(spcl.c_ddate); 5551558Srgrimes fprintf(stdout, "Dumped from: %s", 55685635Sdillon (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t)); 5571558Srgrimes if (spcl.c_host[0] == '\0') 5581558Srgrimes return; 559203155Sjh fprintf(stderr, "Level %jd dump of %s on %s:%s\n", 560203155Sjh (intmax_t)spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 5611558Srgrimes fprintf(stderr, "Label: %s\n", spcl.c_label); 5621558Srgrimes} 5631558Srgrimes 5641558Srgrimesint 56592837Simpextractfile(char *name) 5661558Srgrimes{ 56723685Speter int flags; 568161598Smaxim uid_t uid; 569161598Smaxim gid_t gid; 57023685Speter mode_t mode; 571167011Smckusick int extsize; 572100207Smckusick struct timeval mtimep[2], ctimep[2]; 5731558Srgrimes struct entry *ep; 574167011Smckusick char *buf; 5751558Srgrimes 5761558Srgrimes curfile.name = name; 5771558Srgrimes curfile.action = USING; 578100207Smckusick mtimep[0].tv_sec = curfile.atime_sec; 579100207Smckusick mtimep[0].tv_usec = curfile.atime_nsec / 1000; 580100207Smckusick mtimep[1].tv_sec = curfile.mtime_sec; 581100207Smckusick mtimep[1].tv_usec = curfile.mtime_nsec / 1000; 582100207Smckusick ctimep[0].tv_sec = curfile.atime_sec; 583100207Smckusick ctimep[0].tv_usec = curfile.atime_nsec / 1000; 584100207Smckusick ctimep[1].tv_sec = curfile.birthtime_sec; 585100207Smckusick ctimep[1].tv_usec = curfile.birthtime_nsec / 1000; 586167011Smckusick extsize = curfile.extsize; 587178125Smckusick uid = getuid(); 588178125Smckusick if (uid == 0) 589178125Smckusick uid = curfile.uid; 590161598Smaxim gid = curfile.gid; 59198542Smckusick mode = curfile.mode; 59298542Smckusick flags = curfile.file_flags; 5931558Srgrimes switch (mode & IFMT) { 5941558Srgrimes 5951558Srgrimes default: 5961558Srgrimes fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 5971558Srgrimes skipfile(); 5981558Srgrimes return (FAIL); 5991558Srgrimes 6001558Srgrimes case IFSOCK: 6011558Srgrimes vprintf(stdout, "skipped socket %s\n", name); 6021558Srgrimes skipfile(); 6031558Srgrimes return (GOOD); 6041558Srgrimes 6051558Srgrimes case IFDIR: 6061558Srgrimes if (mflag) { 6071558Srgrimes ep = lookupname(name); 6081558Srgrimes if (ep == NULL || ep->e_flags & EXTRACT) 6091558Srgrimes panic("unextracted directory %s\n", name); 6101558Srgrimes skipfile(); 6111558Srgrimes return (GOOD); 6121558Srgrimes } 6131558Srgrimes vprintf(stdout, "extract file %s\n", name); 6141558Srgrimes return (genliteraldir(name, curfile.ino)); 6151558Srgrimes 6161558Srgrimes case IFLNK: 6171558Srgrimes lnkbuf[0] = '\0'; 6181558Srgrimes pathlen = 0; 619167011Smckusick buf = setupextattr(extsize); 620167011Smckusick getfile(xtrlnkfile, xtrattr, xtrlnkskip); 6211558Srgrimes if (pathlen == 0) { 6221558Srgrimes vprintf(stdout, 6231558Srgrimes "%s: zero length symbolic link (ignored)\n", name); 6241558Srgrimes return (GOOD); 6251558Srgrimes } 62696113Siedowse if (linkit(lnkbuf, name, SYMLINK) == GOOD) { 627167011Smckusick if (extsize > 0) 628167011Smckusick set_extattr_link(name, buf, extsize); 629161598Smaxim (void) lchown(name, uid, gid); 63096113Siedowse (void) lchmod(name, mode); 631100207Smckusick (void) lutimes(name, ctimep); 632100207Smckusick (void) lutimes(name, mtimep); 633161598Smaxim (void) lchflags(name, flags); 63496113Siedowse return (GOOD); 63595943Siedowse } 63696113Siedowse return (FAIL); 6371558Srgrimes 6386305Smartin case IFIFO: 63923685Speter vprintf(stdout, "extract fifo %s\n", name); 64023685Speter if (Nflag) { 64123685Speter skipfile(); 64223685Speter return (GOOD); 64323685Speter } 644161598Smaxim if (uflag) 645161598Smaxim (void) unlink(name); 646161598Smaxim if (mkfifo(name, 0600) < 0) { 64723685Speter fprintf(stderr, "%s: cannot create fifo: %s\n", 64823685Speter name, strerror(errno)); 6496305Smartin skipfile(); 6506305Smartin return (FAIL); 6516305Smartin } 652167011Smckusick if (extsize == 0) { 653167011Smckusick skipfile(); 654167011Smckusick } else { 655167011Smckusick buf = setupextattr(extsize); 656167011Smckusick getfile(xtrnull, xtrattr, xtrnull); 657167011Smckusick set_extattr_file(name, buf, extsize); 658167011Smckusick } 659161598Smaxim (void) chown(name, uid, gid); 6606305Smartin (void) chmod(name, mode); 661100207Smckusick (void) utimes(name, ctimep); 662100207Smckusick (void) utimes(name, mtimep); 66323685Speter (void) chflags(name, flags); 6646305Smartin return (GOOD); 6656305Smartin 6661558Srgrimes case IFCHR: 6671558Srgrimes case IFBLK: 6681558Srgrimes vprintf(stdout, "extract special file %s\n", name); 6691558Srgrimes if (Nflag) { 6701558Srgrimes skipfile(); 6711558Srgrimes return (GOOD); 6721558Srgrimes } 67335852Sjkh if (uflag) 674161598Smaxim (void) unlink(name); 675161598Smaxim if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600, 676161605Smaxim (int)curfile.rdev) < 0) { 6771558Srgrimes fprintf(stderr, "%s: cannot create special file: %s\n", 6781558Srgrimes name, strerror(errno)); 6791558Srgrimes skipfile(); 6801558Srgrimes return (FAIL); 6811558Srgrimes } 682167011Smckusick if (extsize == 0) { 683167011Smckusick skipfile(); 684167011Smckusick } else { 685167011Smckusick buf = setupextattr(extsize); 686167011Smckusick getfile(xtrnull, xtrattr, xtrnull); 687167011Smckusick set_extattr_file(name, buf, extsize); 688167011Smckusick } 689161598Smaxim (void) chown(name, uid, gid); 6901558Srgrimes (void) chmod(name, mode); 691100207Smckusick (void) utimes(name, ctimep); 692100207Smckusick (void) utimes(name, mtimep); 69323685Speter (void) chflags(name, flags); 6941558Srgrimes return (GOOD); 6951558Srgrimes 6961558Srgrimes case IFREG: 6971558Srgrimes vprintf(stdout, "extract file %s\n", name); 6981558Srgrimes if (Nflag) { 6991558Srgrimes skipfile(); 7001558Srgrimes return (GOOD); 7011558Srgrimes } 70235852Sjkh if (uflag) 703161598Smaxim (void) unlink(name); 70421149Simp if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 705161598Smaxim 0600)) < 0) { 7061558Srgrimes fprintf(stderr, "%s: cannot create file: %s\n", 7071558Srgrimes name, strerror(errno)); 7081558Srgrimes skipfile(); 7091558Srgrimes return (FAIL); 7101558Srgrimes } 711167011Smckusick buf = setupextattr(extsize); 712167011Smckusick getfile(xtrfile, xtrattr, xtrskip); 713167011Smckusick if (extsize > 0) 714167011Smckusick set_extattr_fd(ofile, name, buf, extsize); 715161598Smaxim (void) fchown(ofile, uid, gid); 7161558Srgrimes (void) fchmod(ofile, mode); 717161598Smaxim (void) futimes(ofile, ctimep); 718161598Smaxim (void) futimes(ofile, mtimep); 719161598Smaxim (void) fchflags(ofile, flags); 7201558Srgrimes (void) close(ofile); 7211558Srgrimes return (GOOD); 7221558Srgrimes } 7231558Srgrimes /* NOTREACHED */ 7241558Srgrimes} 7251558Srgrimes 7261558Srgrimes/* 727167011Smckusick * Set attributes for a file. 728167011Smckusick */ 729167011Smckusickvoid 730167011Smckusickset_extattr_file(char *name, void *buf, int size) 731167011Smckusick{ 732167011Smckusick struct extattr *eap, *eaend; 733167011Smckusick 734167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 735167011Smckusick eaend = buf + size; 736167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 737167011Smckusick /* 738167011Smckusick * Make sure this entry is complete. 739167011Smckusick */ 740167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 741167011Smckusick dprintf(stdout, "\n\t%scorrupted", 742167011Smckusick eap == buf ? "" : "remainder "); 743167011Smckusick break; 744167011Smckusick } 745167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 746167011Smckusick continue; 747167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 748167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 749167011Smckusick eap->ea_namelength, eap->ea_name); 750167011Smckusick /* 751167011Smckusick * First we try the general attribute setting interface. 752167011Smckusick * However, some attributes can only be set by root or 753167011Smckusick * by using special interfaces (for example, ACLs). 754167011Smckusick */ 755167011Smckusick if (extattr_set_file(name, eap->ea_namespace, eap->ea_name, 756167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 757167011Smckusick dprintf(stdout, " (set using extattr_set_file)"); 758167011Smckusick continue; 759167011Smckusick } 760167011Smckusick /* 761167011Smckusick * If the general interface refuses to set the attribute, 762167011Smckusick * then we try all the specialized interfaces that we 763167011Smckusick * know about. 764167011Smckusick */ 765167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 766167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 767167011Smckusick if (acl_set_file(name, ACL_TYPE_ACCESS, 768167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 769167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 770167011Smckusick continue; 771167011Smckusick } 772167011Smckusick } 773167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 774167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 775167011Smckusick if (acl_set_file(name, ACL_TYPE_DEFAULT, 776167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 777167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 778167011Smckusick continue; 779167011Smckusick } 780167011Smckusick } 781167011Smckusick vprintf(stdout, " (unable to set)"); 782167011Smckusick } 783167011Smckusick vprintf(stdout, "\n"); 784167011Smckusick} 785167011Smckusick 786167011Smckusick/* 787167011Smckusick * Set attributes for a symbolic link. 788167011Smckusick */ 789167011Smckusickstatic void 790167011Smckusickset_extattr_link(char *name, void *buf, int size) 791167011Smckusick{ 792167011Smckusick struct extattr *eap, *eaend; 793167011Smckusick 794167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 795167011Smckusick eaend = buf + size; 796167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 797167011Smckusick /* 798167011Smckusick * Make sure this entry is complete. 799167011Smckusick */ 800167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 801167011Smckusick dprintf(stdout, "\n\t%scorrupted", 802167011Smckusick eap == buf ? "" : "remainder "); 803167011Smckusick break; 804167011Smckusick } 805167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 806167011Smckusick continue; 807167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 808167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 809167011Smckusick eap->ea_namelength, eap->ea_name); 810167011Smckusick /* 811167011Smckusick * First we try the general attribute setting interface. 812167011Smckusick * However, some attributes can only be set by root or 813167011Smckusick * by using special interfaces (for example, ACLs). 814167011Smckusick */ 815167011Smckusick if (extattr_set_link(name, eap->ea_namespace, eap->ea_name, 816167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 817167011Smckusick dprintf(stdout, " (set using extattr_set_link)"); 818167011Smckusick continue; 819167011Smckusick } 820167011Smckusick /* 821167011Smckusick * If the general interface refuses to set the attribute, 822167011Smckusick * then we try all the specialized interfaces that we 823167011Smckusick * know about. 824167011Smckusick */ 825167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 826167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 827167011Smckusick if (acl_set_link_np(name, ACL_TYPE_ACCESS, 828167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 829167011Smckusick dprintf(stdout, " (set using acl_set_link_np)"); 830167011Smckusick continue; 831167011Smckusick } 832167011Smckusick } 833167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 834167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 835167011Smckusick if (acl_set_link_np(name, ACL_TYPE_DEFAULT, 836167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 837167011Smckusick dprintf(stdout, " (set using acl_set_link_np)"); 838167011Smckusick continue; 839167011Smckusick } 840167011Smckusick } 841167011Smckusick vprintf(stdout, " (unable to set)"); 842167011Smckusick } 843167011Smckusick vprintf(stdout, "\n"); 844167011Smckusick} 845167011Smckusick 846167011Smckusick/* 847167011Smckusick * Set attributes on a file descriptor. 848167011Smckusick */ 849167011Smckusickstatic void 850167011Smckusickset_extattr_fd(int fd, char *name, void *buf, int size) 851167011Smckusick{ 852167011Smckusick struct extattr *eap, *eaend; 853167011Smckusick 854167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 855167011Smckusick eaend = buf + size; 856167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 857167011Smckusick /* 858167011Smckusick * Make sure this entry is complete. 859167011Smckusick */ 860167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 861167011Smckusick dprintf(stdout, "\n\t%scorrupted", 862167011Smckusick eap == buf ? "" : "remainder "); 863167011Smckusick break; 864167011Smckusick } 865167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 866167011Smckusick continue; 867167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 868167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 869167011Smckusick eap->ea_namelength, eap->ea_name); 870167011Smckusick /* 871167011Smckusick * First we try the general attribute setting interface. 872167011Smckusick * However, some attributes can only be set by root or 873167011Smckusick * by using special interfaces (for example, ACLs). 874167011Smckusick */ 875167011Smckusick if (extattr_set_fd(fd, eap->ea_namespace, eap->ea_name, 876167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 877167011Smckusick dprintf(stdout, " (set using extattr_set_fd)"); 878167011Smckusick continue; 879167011Smckusick } 880167011Smckusick /* 881167011Smckusick * If the general interface refuses to set the attribute, 882167011Smckusick * then we try all the specialized interfaces that we 883167011Smckusick * know about. 884167011Smckusick */ 885167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 886167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 887167011Smckusick if (acl_set_fd(fd, EXTATTR_CONTENT(eap)) != -1) { 888167011Smckusick dprintf(stdout, " (set using acl_set_fd)"); 889167011Smckusick continue; 890167011Smckusick } 891167011Smckusick } 892167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 893167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 894167011Smckusick if (acl_set_file(name, ACL_TYPE_DEFAULT, 895167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 896167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 897167011Smckusick continue; 898167011Smckusick } 899167011Smckusick } 900167011Smckusick vprintf(stdout, " (unable to set)"); 901167011Smckusick } 902167011Smckusick vprintf(stdout, "\n"); 903167011Smckusick} 904167011Smckusick 905167011Smckusick/* 9061558Srgrimes * skip over bit maps on the tape 9071558Srgrimes */ 9081558Srgrimesvoid 90992837Simpskipmaps(void) 9101558Srgrimes{ 9111558Srgrimes 9121558Srgrimes while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 9131558Srgrimes skipfile(); 9141558Srgrimes} 9151558Srgrimes 9161558Srgrimes/* 9171558Srgrimes * skip over a file on the tape 9181558Srgrimes */ 9191558Srgrimesvoid 92092837Simpskipfile(void) 9211558Srgrimes{ 9221558Srgrimes 9231558Srgrimes curfile.action = SKIP; 924167011Smckusick getfile(xtrnull, xtrnull, xtrnull); 9251558Srgrimes} 9261558Srgrimes 9271558Srgrimes/* 9281558Srgrimes * Extract a file from the tape. 9291558Srgrimes * When an allocated block is found it is passed to the fill function; 9301558Srgrimes * when an unallocated block (hole) is found, a zeroed buffer is passed 9311558Srgrimes * to the skip function. 9321558Srgrimes */ 9331558Srgrimesvoid 934167011Smckusickgetfile(void (*datafill)(char *, long), void (*attrfill)(char *, long), 935167011Smckusick void (*skip)(char *, long)) 9361558Srgrimes{ 93792806Sobrien int i; 938167011Smckusick off_t size; 939167011Smckusick int curblk, attrsize; 940167011Smckusick void (*fillit)(char *, long); 9411558Srgrimes static char clearedbuf[MAXBSIZE]; 9421558Srgrimes char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 9431558Srgrimes char junk[TP_BSIZE]; 9441558Srgrimes 945167011Smckusick curblk = 0; 946167011Smckusick size = spcl.c_size; 947167011Smckusick attrsize = spcl.c_extsize; 9481558Srgrimes if (spcl.c_type == TS_END) 9491558Srgrimes panic("ran off end of tape\n"); 95098542Smckusick if (spcl.c_magic != FS_UFS2_MAGIC) 9511558Srgrimes panic("not at beginning of a file\n"); 9521558Srgrimes if (!gettingfile && setjmp(restart) != 0) 9531558Srgrimes return; 9541558Srgrimes gettingfile++; 955167011Smckusick fillit = datafill; 956167011Smckusick if (size == 0 && attrsize > 0) { 957167011Smckusick fillit = attrfill; 958167011Smckusick size = attrsize; 959167011Smckusick attrsize = 0; 960167011Smckusick } 9611558Srgrimesloop: 9621558Srgrimes for (i = 0; i < spcl.c_count; i++) { 963164911Sdwmalone if (!readmapflag && i > TP_NINDIR) { 964164911Sdwmalone if (Dflag) { 965164911Sdwmalone fprintf(stderr, "spcl.c_count = %jd\n", 966164911Sdwmalone (intmax_t)spcl.c_count); 967164911Sdwmalone break; 968164911Sdwmalone } else 969164911Sdwmalone panic("spcl.c_count = %jd\n", 970164911Sdwmalone (intmax_t)spcl.c_count); 971164911Sdwmalone } 97237923Simp if (readmapflag || spcl.c_addr[i]) { 9731558Srgrimes readtape(&buf[curblk++][0]); 9741558Srgrimes if (curblk == fssize / TP_BSIZE) { 975167011Smckusick (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 97623685Speter fssize : (curblk - 1) * TP_BSIZE + size)); 9771558Srgrimes curblk = 0; 9781558Srgrimes } 9791558Srgrimes } else { 9801558Srgrimes if (curblk > 0) { 981167011Smckusick (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 98223685Speter curblk * TP_BSIZE : 98323685Speter (curblk - 1) * TP_BSIZE + size)); 9841558Srgrimes curblk = 0; 9851558Srgrimes } 98623685Speter (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 98723685Speter TP_BSIZE : size)); 9881558Srgrimes } 9891558Srgrimes if ((size -= TP_BSIZE) <= 0) { 990167011Smckusick if (size > -TP_BSIZE && curblk > 0) { 991167011Smckusick (*fillit)((char *)buf, 992167011Smckusick (long)((curblk * TP_BSIZE) + size)); 993167011Smckusick curblk = 0; 994167011Smckusick } 995167011Smckusick if (attrsize > 0) { 996167011Smckusick fillit = attrfill; 997167011Smckusick size = attrsize; 998167011Smckusick attrsize = 0; 999167011Smckusick continue; 1000167011Smckusick } 1001167011Smckusick if (spcl.c_count - i > 1) 1002167011Smckusick dprintf(stdout, "skipping %d junk block(s)\n", 1003167011Smckusick spcl.c_count - i - 1); 1004164911Sdwmalone for (i++; i < spcl.c_count; i++) { 1005164911Sdwmalone if (!readmapflag && i > TP_NINDIR) { 1006164911Sdwmalone if (Dflag) { 1007164911Sdwmalone fprintf(stderr, 1008164911Sdwmalone "spcl.c_count = %jd\n", 1009164911Sdwmalone (intmax_t)spcl.c_count); 1010164911Sdwmalone break; 1011164911Sdwmalone } else 1012164911Sdwmalone panic("spcl.c_count = %jd\n", 1013164911Sdwmalone (intmax_t)spcl.c_count); 1014164911Sdwmalone } 101537923Simp if (readmapflag || spcl.c_addr[i]) 10161558Srgrimes readtape(junk); 1017164911Sdwmalone } 10181558Srgrimes break; 10191558Srgrimes } 10201558Srgrimes } 10211558Srgrimes if (gethead(&spcl) == GOOD && size > 0) { 10221558Srgrimes if (spcl.c_type == TS_ADDR) 10231558Srgrimes goto loop; 10241558Srgrimes dprintf(stdout, 102537240Sbde "Missing address (header) block for %s at %ld blocks\n", 10261558Srgrimes curfile.name, blksread); 10271558Srgrimes } 10281558Srgrimes if (curblk > 0) 1029167011Smckusick panic("getfile: lost data\n"); 10301558Srgrimes findinode(&spcl); 10311558Srgrimes gettingfile = 0; 10321558Srgrimes} 10331558Srgrimes 10341558Srgrimes/* 1035167011Smckusick * These variables are shared between the next two functions. 1036167011Smckusick */ 1037167011Smckusickstatic int extbufsize = 0; 1038167011Smckusickstatic char *extbuf; 1039167011Smckusickstatic int extloc; 1040167011Smckusick 1041167011Smckusick/* 1042167011Smckusick * Allocate a buffer into which to extract extended attributes. 1043167011Smckusick */ 1044167011Smckusickstatic char * 1045167011Smckusicksetupextattr(int extsize) 1046167011Smckusick{ 1047167011Smckusick 1048167011Smckusick extloc = 0; 1049167011Smckusick if (extsize <= extbufsize) 1050167011Smckusick return (extbuf); 1051167011Smckusick if (extbufsize > 0) 1052167011Smckusick free(extbuf); 1053167011Smckusick if ((extbuf = malloc(extsize)) != NULL) { 1054167011Smckusick extbufsize = extsize; 1055167011Smckusick return (extbuf); 1056167011Smckusick } 1057167011Smckusick extbufsize = 0; 1058167011Smckusick extbuf = NULL; 1059241013Smdf fprintf(stderr, "Cannot extract %d bytes %s for inode %ju, name %s\n", 1060241013Smdf extsize, "of extended attributes", (uintmax_t)curfile.ino, 1061241013Smdf curfile.name); 1062167011Smckusick return (NULL); 1063167011Smckusick} 1064167011Smckusick 1065167011Smckusick/* 1066167011Smckusick * Extract the next block of extended attributes. 1067167011Smckusick */ 1068167011Smckusickstatic void 1069167011Smckusickxtrattr(char *buf, long size) 1070167011Smckusick{ 1071167011Smckusick 1072167011Smckusick if (extloc + size > extbufsize) 1073167011Smckusick panic("overrun attribute buffer\n"); 1074167011Smckusick memmove(&extbuf[extloc], buf, size); 1075167011Smckusick extloc += size; 1076167011Smckusick} 1077167011Smckusick 1078167011Smckusick/* 10791558Srgrimes * Write out the next block of a file. 10801558Srgrimes */ 10811558Srgrimesstatic void 108292837Simpxtrfile(char *buf, long size) 10831558Srgrimes{ 10841558Srgrimes 10851558Srgrimes if (Nflag) 10861558Srgrimes return; 10871558Srgrimes if (write(ofile, buf, (int) size) == -1) { 10881558Srgrimes fprintf(stderr, 1089241013Smdf "write error extracting inode %ju, name %s\nwrite: %s\n", 1090241013Smdf (uintmax_t)curfile.ino, curfile.name, strerror(errno)); 10911558Srgrimes } 10921558Srgrimes} 10931558Srgrimes 10941558Srgrimes/* 10951558Srgrimes * Skip over a hole in a file. 10961558Srgrimes */ 10971558Srgrimes/* ARGSUSED */ 10981558Srgrimesstatic void 109992837Simpxtrskip(char *buf, long size) 11001558Srgrimes{ 11011558Srgrimes 11021558Srgrimes if (lseek(ofile, size, SEEK_CUR) == -1) { 11031558Srgrimes fprintf(stderr, 1104241013Smdf "seek error extracting inode %ju, name %s\nlseek: %s\n", 1105241013Smdf (uintmax_t)curfile.ino, curfile.name, strerror(errno)); 11061558Srgrimes done(1); 11071558Srgrimes } 11081558Srgrimes} 11091558Srgrimes 11101558Srgrimes/* 11111558Srgrimes * Collect the next block of a symbolic link. 11121558Srgrimes */ 11131558Srgrimesstatic void 111492837Simpxtrlnkfile(char *buf, long size) 11151558Srgrimes{ 11161558Srgrimes 11171558Srgrimes pathlen += size; 11181558Srgrimes if (pathlen > MAXPATHLEN) { 11191558Srgrimes fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 11201558Srgrimes curfile.name, lnkbuf, buf, pathlen); 11211558Srgrimes done(1); 11221558Srgrimes } 11231558Srgrimes (void) strcat(lnkbuf, buf); 11241558Srgrimes} 11251558Srgrimes 11261558Srgrimes/* 11271558Srgrimes * Skip over a hole in a symbolic link (should never happen). 11281558Srgrimes */ 11291558Srgrimes/* ARGSUSED */ 11301558Srgrimesstatic void 113192837Simpxtrlnkskip(char *buf, long size) 11321558Srgrimes{ 11331558Srgrimes 11341558Srgrimes fprintf(stderr, "unallocated block in symbolic link %s\n", 11351558Srgrimes curfile.name); 11361558Srgrimes done(1); 11371558Srgrimes} 11381558Srgrimes 11391558Srgrimes/* 11401558Srgrimes * Collect the next block of a bit map. 11411558Srgrimes */ 11421558Srgrimesstatic void 114392837Simpxtrmap(char *buf, long size) 11441558Srgrimes{ 11451558Srgrimes 114623685Speter memmove(map, buf, size); 11471558Srgrimes map += size; 11481558Srgrimes} 11491558Srgrimes 11501558Srgrimes/* 11511558Srgrimes * Skip over a hole in a bit map (should never happen). 11521558Srgrimes */ 11531558Srgrimes/* ARGSUSED */ 11541558Srgrimesstatic void 115592837Simpxtrmapskip(char *buf, long size) 11561558Srgrimes{ 11571558Srgrimes 11581558Srgrimes panic("hole in map\n"); 11591558Srgrimes map += size; 11601558Srgrimes} 11611558Srgrimes 11621558Srgrimes/* 11631558Srgrimes * Noop, when an extraction function is not needed. 11641558Srgrimes */ 11651558Srgrimes/* ARGSUSED */ 11661558Srgrimesvoid 116792837Simpxtrnull(char *buf, long size) 11681558Srgrimes{ 11691558Srgrimes 11701558Srgrimes return; 11711558Srgrimes} 11721558Srgrimes 11731558Srgrimes/* 11741558Srgrimes * Read TP_BSIZE blocks from the input. 11751558Srgrimes * Handle read errors, and end of media. 11761558Srgrimes */ 11771558Srgrimesstatic void 117892837Simpreadtape(char *buf) 11791558Srgrimes{ 1180164911Sdwmalone long rd, newvol, i, oldnumtrec; 11811558Srgrimes int cnt, seek_failed; 11821558Srgrimes 1183164911Sdwmalone if (blkcnt + (byteslide > 0) < numtrec) { 1184164911Sdwmalone memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE); 11851558Srgrimes blksread++; 118690827Siedowse tapeaddr++; 11871558Srgrimes return; 11881558Srgrimes } 1189164911Sdwmalone if (numtrec > 0) 1190164911Sdwmalone memmove(&tapebuf[-TP_BSIZE], 1191164911Sdwmalone &tapebuf[(numtrec-1) * TP_BSIZE], (long)TP_BSIZE); 1192164911Sdwmalone oldnumtrec = numtrec; 11931558Srgrimes for (i = 0; i < ntrec; i++) 11941558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 11951558Srgrimes if (numtrec == 0) 11961558Srgrimes numtrec = ntrec; 11971558Srgrimes cnt = ntrec * TP_BSIZE; 11981558Srgrimes rd = 0; 11991558Srgrimesgetmore: 12001558Srgrimes#ifdef RRESTORE 12011558Srgrimes if (host) 12021558Srgrimes i = rmtread(&tapebuf[rd], cnt); 12031558Srgrimes else 12041558Srgrimes#endif 12051558Srgrimes i = read(mt, &tapebuf[rd], cnt); 12061558Srgrimes /* 12071558Srgrimes * Check for mid-tape short read error. 12081558Srgrimes * If found, skip rest of buffer and start with the next. 12091558Srgrimes */ 1210203157Sjh if (!pipein && !pipecmdin && numtrec < ntrec && i > 0) { 12111558Srgrimes dprintf(stdout, "mid-media short read error.\n"); 12121558Srgrimes numtrec = ntrec; 12131558Srgrimes } 12141558Srgrimes /* 12151558Srgrimes * Handle partial block read. 12161558Srgrimes */ 1217203157Sjh if ((pipein || pipecmdin) && i == 0 && rd > 0) 12181558Srgrimes i = rd; 12191558Srgrimes else if (i > 0 && i != ntrec * TP_BSIZE) { 1220203157Sjh if (pipein || pipecmdin) { 12211558Srgrimes rd += i; 12221558Srgrimes cnt -= i; 12231558Srgrimes if (cnt > 0) 12241558Srgrimes goto getmore; 12251558Srgrimes i = rd; 12261558Srgrimes } else { 12271558Srgrimes /* 12281558Srgrimes * Short read. Process the blocks read. 12291558Srgrimes */ 12301558Srgrimes if (i % TP_BSIZE != 0) 12311558Srgrimes vprintf(stdout, 123237240Sbde "partial block read: %ld should be %ld\n", 12331558Srgrimes i, ntrec * TP_BSIZE); 12341558Srgrimes numtrec = i / TP_BSIZE; 12351558Srgrimes } 12361558Srgrimes } 12371558Srgrimes /* 12381558Srgrimes * Handle read error. 12391558Srgrimes */ 12401558Srgrimes if (i < 0) { 12411558Srgrimes fprintf(stderr, "Tape read error while "); 12421558Srgrimes switch (curfile.action) { 12431558Srgrimes default: 12441558Srgrimes fprintf(stderr, "trying to set up tape\n"); 12451558Srgrimes break; 12461558Srgrimes case UNKNOWN: 12471558Srgrimes fprintf(stderr, "trying to resynchronize\n"); 12481558Srgrimes break; 12491558Srgrimes case USING: 12501558Srgrimes fprintf(stderr, "restoring %s\n", curfile.name); 12511558Srgrimes break; 12521558Srgrimes case SKIP: 1253241013Smdf fprintf(stderr, "skipping over inode %ju\n", 1254241013Smdf (uintmax_t)curfile.ino); 12551558Srgrimes break; 12561558Srgrimes } 12571558Srgrimes if (!yflag && !reply("continue")) 12581558Srgrimes done(1); 12591558Srgrimes i = ntrec * TP_BSIZE; 126023685Speter memset(tapebuf, 0, i); 12611558Srgrimes#ifdef RRESTORE 12621558Srgrimes if (host) 12631558Srgrimes seek_failed = (rmtseek(i, 1) < 0); 12641558Srgrimes else 12651558Srgrimes#endif 12661558Srgrimes seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 12671558Srgrimes 12681558Srgrimes if (seek_failed) { 12691558Srgrimes fprintf(stderr, 12701558Srgrimes "continuation failed: %s\n", strerror(errno)); 12711558Srgrimes done(1); 12721558Srgrimes } 12731558Srgrimes } 12741558Srgrimes /* 12751558Srgrimes * Handle end of tape. 12761558Srgrimes */ 12771558Srgrimes if (i == 0) { 12781558Srgrimes vprintf(stdout, "End-of-tape encountered\n"); 12791558Srgrimes if (!pipein) { 12801558Srgrimes newvol = volno + 1; 12811558Srgrimes volno = 0; 12821558Srgrimes numtrec = 0; 12831558Srgrimes getvol(newvol); 12841558Srgrimes readtape(buf); 12851558Srgrimes return; 12861558Srgrimes } 12871558Srgrimes if (rd % TP_BSIZE != 0) 1288203155Sjh panic("partial block read: %ld should be %ld\n", 12891558Srgrimes rd, ntrec * TP_BSIZE); 12901558Srgrimes terminateinput(); 129123685Speter memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 12921558Srgrimes } 1293164911Sdwmalone if (oldnumtrec == 0) 1294164911Sdwmalone blkcnt = 0; 1295164911Sdwmalone else 1296164911Sdwmalone blkcnt -= oldnumtrec; 1297164911Sdwmalone memmove(buf, 1298164911Sdwmalone &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE); 12991558Srgrimes blksread++; 130090827Siedowse tapeaddr++; 13011558Srgrimes} 13021558Srgrimes 13031558Srgrimesstatic void 130492837Simpfindtapeblksize(void) 13051558Srgrimes{ 130692806Sobrien long i; 13071558Srgrimes 13081558Srgrimes for (i = 0; i < ntrec; i++) 13091558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 13101558Srgrimes blkcnt = 0; 13111558Srgrimes#ifdef RRESTORE 13121558Srgrimes if (host) 13131558Srgrimes i = rmtread(tapebuf, ntrec * TP_BSIZE); 13141558Srgrimes else 13151558Srgrimes#endif 13161558Srgrimes i = read(mt, tapebuf, ntrec * TP_BSIZE); 13171558Srgrimes 13181558Srgrimes if (i <= 0) { 13191558Srgrimes fprintf(stderr, "tape read error: %s\n", strerror(errno)); 13201558Srgrimes done(1); 13211558Srgrimes } 13221558Srgrimes if (i % TP_BSIZE != 0) { 132337240Sbde fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 13241558Srgrimes i, "is not a multiple of dump block size", TP_BSIZE); 13251558Srgrimes done(1); 13261558Srgrimes } 13271558Srgrimes ntrec = i / TP_BSIZE; 13281558Srgrimes numtrec = ntrec; 132937240Sbde vprintf(stdout, "Tape block size is %ld\n", ntrec); 13301558Srgrimes} 13311558Srgrimes 13321558Srgrimesvoid 133392837Simpclosemt(void) 13341558Srgrimes{ 13351558Srgrimes 13361558Srgrimes if (mt < 0) 13371558Srgrimes return; 1338128175Sgreen if (pipecmdin) { 1339128175Sgreen pclose(popenfp); 1340128175Sgreen popenfp = NULL; 1341128175Sgreen } else 13421558Srgrimes#ifdef RRESTORE 13431558Srgrimes if (host) 13441558Srgrimes rmtclose(); 13451558Srgrimes else 13461558Srgrimes#endif 13471558Srgrimes (void) close(mt); 13481558Srgrimes} 13491558Srgrimes 13501558Srgrimes/* 13511558Srgrimes * Read the next block from the tape. 13521558Srgrimes * If it is not any valid header, return an error. 13531558Srgrimes */ 13541558Srgrimesstatic int 135592837Simpgethead(struct s_spcl *buf) 13561558Srgrimes{ 13571558Srgrimes long i; 13581558Srgrimes 135998542Smckusick readtape((char *)buf); 136098542Smckusick if (buf->c_magic != FS_UFS2_MAGIC && buf->c_magic != NFS_MAGIC) { 136198542Smckusick if (buf->c_magic == OFS_MAGIC) { 136298542Smckusick fprintf(stderr, 136398542Smckusick "Format of dump tape is too old. Must use\n"); 136498542Smckusick fprintf(stderr, 136598542Smckusick "a version of restore from before 2002.\n"); 136698542Smckusick return (FAIL); 136798542Smckusick } 136898542Smckusick if (swabl(buf->c_magic) != FS_UFS2_MAGIC && 136998542Smckusick buf->c_magic != NFS_MAGIC) { 137098542Smckusick if (buf->c_magic == OFS_MAGIC) { 137198542Smckusick fprintf(stderr, 137298542Smckusick "Format of dump tape is too old. Must use\n"); 137398542Smckusick fprintf(stderr, 137498542Smckusick "a version of restore from before 2002.\n"); 13751558Srgrimes } 13761558Srgrimes return (FAIL); 137723096Simp } 137898542Smckusick if (!Bcvt) { 137998542Smckusick vprintf(stdout, "Note: Doing Byte swapping\n"); 138098542Smckusick Bcvt = 1; 13811558Srgrimes } 13821558Srgrimes } 138398542Smckusick if (checksum((int *)buf) == FAIL) 138498542Smckusick return (FAIL); 138598542Smckusick if (Bcvt) { 138698542Smckusick swabst((u_char *)"8l4s1q8l2q17l", (u_char *)buf); 138798542Smckusick swabst((u_char *)"l",(u_char *) &buf->c_level); 138898542Smckusick swabst((u_char *)"2l4q",(u_char *) &buf->c_flags); 13891558Srgrimes } 139037923Simp readmapflag = 0; 13911558Srgrimes 13921558Srgrimes switch (buf->c_type) { 13931558Srgrimes 13941558Srgrimes case TS_CLRI: 13951558Srgrimes case TS_BITS: 13961558Srgrimes /* 13971558Srgrimes * Have to patch up missing information in bit map headers 13981558Srgrimes */ 139998542Smckusick buf->c_size = buf->c_count * TP_BSIZE; 140037923Simp if (buf->c_count > TP_NINDIR) 140137923Simp readmapflag = 1; 140237923Simp else 140337923Simp for (i = 0; i < buf->c_count; i++) 140437923Simp buf->c_addr[i]++; 1405179218Smckusick /* FALL THROUGH */ 14061558Srgrimes 14071558Srgrimes case TS_TAPE: 1408179218Smckusick if (buf->c_magic == NFS_MAGIC && 1409179218Smckusick (buf->c_flags & NFS_DR_NEWINODEFMT) == 0) 1410179218Smckusick oldinofmt = 1; 1411179218Smckusick /* FALL THROUGH */ 1412179218Smckusick 14131558Srgrimes case TS_END: 14141558Srgrimes buf->c_inumber = 0; 1415179218Smckusick /* FALL THROUGH */ 14161558Srgrimes 1417179218Smckusick case TS_ADDR: 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); 1430179219Smckusick buf->c_birthtime = 0; 1431179219Smckusick buf->c_birthtimensec = 0; 1432179219Smckusick buf->c_extsize = 0; 143398542Smckusick } 143498542Smckusick break; 143598542Smckusick 14361558Srgrimes default: 14371558Srgrimes panic("gethead: unknown inode type %d\n", buf->c_type); 14381558Srgrimes break; 14391558Srgrimes } 1440179218Smckusick if (dumpdate != 0 && _time64_to_time(buf->c_date) != dumpdate) 1441179218Smckusick fprintf(stderr, "Header with wrong dumpdate.\n"); 1442144099Simp /* 1443144099Simp * If we're restoring a filesystem with the old (FreeBSD 1) 1444144099Simp * format inodes, copy the uid/gid to the new location 1445144099Simp */ 1446144099Simp if (oldinofmt) { 1447144099Simp buf->c_uid = buf->c_spare1[1]; 1448144099Simp buf->c_gid = buf->c_spare1[2]; 1449144099Simp } 145098542Smckusick buf->c_magic = FS_UFS2_MAGIC; 145190827Siedowse tapeaddr = buf->c_tapea; 14521558Srgrimes if (dflag) 14531558Srgrimes accthdr(buf); 14541558Srgrimes return(GOOD); 14551558Srgrimes} 14561558Srgrimes 14571558Srgrimes/* 14581558Srgrimes * Check that a header is where it belongs and predict the next header 14591558Srgrimes */ 14601558Srgrimesstatic void 146192837Simpaccthdr(struct s_spcl *header) 14621558Srgrimes{ 14631558Srgrimes static ino_t previno = 0x7fffffff; 14641558Srgrimes static int prevtype; 14651558Srgrimes static long predict; 14661558Srgrimes long blks, i; 14671558Srgrimes 14681558Srgrimes if (header->c_type == TS_TAPE) { 146998542Smckusick fprintf(stderr, "Volume header "); 14701558Srgrimes if (header->c_firstrec) 1471203155Sjh fprintf(stderr, "begins with record %jd", 1472203155Sjh (intmax_t)header->c_firstrec); 14731558Srgrimes fprintf(stderr, "\n"); 14741558Srgrimes previno = 0x7fffffff; 14751558Srgrimes return; 14761558Srgrimes } 14771558Srgrimes if (previno == 0x7fffffff) 14781558Srgrimes goto newcalc; 14791558Srgrimes switch (prevtype) { 14801558Srgrimes case TS_BITS: 148123685Speter fprintf(stderr, "Dumped inodes map header"); 14821558Srgrimes break; 14831558Srgrimes case TS_CLRI: 148423685Speter fprintf(stderr, "Used inodes map header"); 14851558Srgrimes break; 14861558Srgrimes case TS_INODE: 1487241013Smdf fprintf(stderr, "File header, ino %ju", (uintmax_t)previno); 14881558Srgrimes break; 14891558Srgrimes case TS_ADDR: 1490241013Smdf fprintf(stderr, "File continuation header, ino %ju", 1491241013Smdf (uintmax_t)previno); 14921558Srgrimes break; 14931558Srgrimes case TS_END: 14941558Srgrimes fprintf(stderr, "End of tape header"); 14951558Srgrimes break; 14961558Srgrimes } 14971558Srgrimes if (predict != blksread - 1) 149837240Sbde fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 14991558Srgrimes predict, blksread - 1); 15001558Srgrimes fprintf(stderr, "\n"); 15011558Srgrimesnewcalc: 15021558Srgrimes blks = 0; 15031558Srgrimes if (header->c_type != TS_END) 15041558Srgrimes for (i = 0; i < header->c_count; i++) 150537923Simp if (readmapflag || header->c_addr[i] != 0) 15061558Srgrimes blks++; 15071558Srgrimes predict = blks; 15081558Srgrimes blksread = 0; 15091558Srgrimes prevtype = header->c_type; 15101558Srgrimes previno = header->c_inumber; 15111558Srgrimes} 15121558Srgrimes 15131558Srgrimes/* 15141558Srgrimes * Find an inode header. 151590573Siedowse * Complain if had to skip. 15161558Srgrimes */ 15171558Srgrimesstatic void 151892837Simpfindinode(struct s_spcl *header) 15191558Srgrimes{ 15201558Srgrimes static long skipcnt = 0; 15211558Srgrimes long i; 15221558Srgrimes char buf[TP_BSIZE]; 152390608Siedowse int htype; 15241558Srgrimes 15251558Srgrimes curfile.name = "<name unknown>"; 15261558Srgrimes curfile.action = UNKNOWN; 152798542Smckusick curfile.mode = 0; 15281558Srgrimes curfile.ino = 0; 15291558Srgrimes do { 153090608Siedowse htype = header->c_type; 153190608Siedowse switch (htype) { 15321558Srgrimes 15331558Srgrimes case TS_ADDR: 15341558Srgrimes /* 15351558Srgrimes * Skip up to the beginning of the next record 15361558Srgrimes */ 15371558Srgrimes for (i = 0; i < header->c_count; i++) 15381558Srgrimes if (header->c_addr[i]) 15391558Srgrimes readtape(buf); 15401558Srgrimes while (gethead(header) == FAIL || 1541164911Sdwmalone _time64_to_time(header->c_date) != dumpdate) { 15421558Srgrimes skipcnt++; 1543164911Sdwmalone if (Dflag) { 1544164911Sdwmalone byteslide++; 1545164911Sdwmalone if (byteslide < TP_BSIZE) { 1546164911Sdwmalone blkcnt--; 1547164911Sdwmalone blksread--; 1548164911Sdwmalone } else 1549164911Sdwmalone byteslide = 0; 1550164911Sdwmalone } 1551164911Sdwmalone } 15521558Srgrimes break; 15531558Srgrimes 15541558Srgrimes case TS_INODE: 155598542Smckusick curfile.mode = header->c_mode; 155698542Smckusick curfile.uid = header->c_uid; 155798542Smckusick curfile.gid = header->c_gid; 155898542Smckusick curfile.file_flags = header->c_file_flags; 155998542Smckusick curfile.rdev = header->c_rdev; 156098542Smckusick curfile.atime_sec = header->c_atime; 156198542Smckusick curfile.atime_nsec = header->c_atimensec; 156298542Smckusick curfile.mtime_sec = header->c_mtime; 156398542Smckusick curfile.mtime_nsec = header->c_mtimensec; 1564100207Smckusick curfile.birthtime_sec = header->c_birthtime; 1565100207Smckusick curfile.birthtime_nsec = header->c_birthtimensec; 1566167011Smckusick curfile.extsize = header->c_extsize; 156798542Smckusick curfile.size = header->c_size; 15681558Srgrimes curfile.ino = header->c_inumber; 15691558Srgrimes break; 15701558Srgrimes 15711558Srgrimes case TS_END: 157290820Siedowse /* If we missed some tapes, get another volume. */ 157390820Siedowse if (tapesread & (tapesread + 1)) { 157490820Siedowse getvol(0); 157590820Siedowse continue; 157690820Siedowse } 15771558Srgrimes curfile.ino = maxino; 15781558Srgrimes break; 15791558Srgrimes 15801558Srgrimes case TS_CLRI: 15811558Srgrimes curfile.name = "<file removal list>"; 15821558Srgrimes break; 15831558Srgrimes 15841558Srgrimes case TS_BITS: 15851558Srgrimes curfile.name = "<file dump list>"; 15861558Srgrimes break; 15871558Srgrimes 15881558Srgrimes case TS_TAPE: 1589164911Sdwmalone if (Dflag) 1590164911Sdwmalone fprintf(stderr, "unexpected tape header\n"); 1591164911Sdwmalone else 1592164911Sdwmalone panic("unexpected tape header\n"); 15931558Srgrimes 15941558Srgrimes default: 1595164911Sdwmalone if (Dflag) 1596164911Sdwmalone fprintf(stderr, "unknown tape header type %d\n", 1597164911Sdwmalone spcl.c_type); 1598164911Sdwmalone else 1599164911Sdwmalone panic("unknown tape header type %d\n", 1600164911Sdwmalone spcl.c_type); 1601164911Sdwmalone while (gethead(header) == FAIL || 1602164911Sdwmalone _time64_to_time(header->c_date) != dumpdate) { 1603164911Sdwmalone skipcnt++; 1604164911Sdwmalone if (Dflag) { 1605164911Sdwmalone byteslide++; 1606164911Sdwmalone if (byteslide < TP_BSIZE) { 1607164911Sdwmalone blkcnt--; 1608164911Sdwmalone blksread--; 1609164911Sdwmalone } else 1610164911Sdwmalone byteslide = 0; 1611164911Sdwmalone } 1612164911Sdwmalone } 16131558Srgrimes 16141558Srgrimes } 161590608Siedowse } while (htype == TS_ADDR); 16161558Srgrimes if (skipcnt > 0) 1617164911Sdwmalone fprintf(stderr, "resync restore, skipped %ld %s\n", 1618164911Sdwmalone skipcnt, Dflag ? "bytes" : "blocks"); 16191558Srgrimes skipcnt = 0; 16201558Srgrimes} 16211558Srgrimes 16221558Srgrimesstatic int 162392837Simpchecksum(int *buf) 16241558Srgrimes{ 162592806Sobrien int i, j; 16261558Srgrimes 16271558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 16281558Srgrimes i = 0; 162998542Smckusick if (!Bcvt) { 16301558Srgrimes do 16311558Srgrimes i += *buf++; 16321558Srgrimes while (--j); 16331558Srgrimes } else { 16341558Srgrimes /* What happens if we want to read restore tapes 16351558Srgrimes for a 16bit int machine??? */ 16368871Srgrimes do 16371558Srgrimes i += swabl(*buf++); 16381558Srgrimes while (--j); 16391558Srgrimes } 16408871Srgrimes 16411558Srgrimes if (i != CHECKSUM) { 1642241013Smdf fprintf(stderr, "Checksum error %o, inode %ju file %s\n", i, 1643241013Smdf (uintmax_t)curfile.ino, curfile.name); 16441558Srgrimes return(FAIL); 16451558Srgrimes } 16461558Srgrimes return(GOOD); 16471558Srgrimes} 16481558Srgrimes 16491558Srgrimes#ifdef RRESTORE 16501558Srgrimes#include <stdarg.h> 16511558Srgrimes 16521558Srgrimesvoid 16531558Srgrimesmsg(const char *fmt, ...) 16541558Srgrimes{ 16551558Srgrimes va_list ap; 16561558Srgrimes va_start(ap, fmt); 16571558Srgrimes (void)vfprintf(stderr, fmt, ap); 16581558Srgrimes va_end(ap); 16591558Srgrimes} 16601558Srgrimes#endif /* RRESTORE */ 16611558Srgrimes 16621558Srgrimesstatic u_char * 166392837Simpswabshort(u_char *sp, int n) 16641558Srgrimes{ 16651558Srgrimes char c; 16661558Srgrimes 16671558Srgrimes while (--n >= 0) { 16681558Srgrimes c = sp[0]; sp[0] = sp[1]; sp[1] = c; 16691558Srgrimes sp += 2; 16701558Srgrimes } 16711558Srgrimes return (sp); 16721558Srgrimes} 16731558Srgrimes 16741558Srgrimesstatic u_char * 167592837Simpswablong(u_char *sp, int n) 16761558Srgrimes{ 16771558Srgrimes char c; 16781558Srgrimes 16791558Srgrimes while (--n >= 0) { 16801558Srgrimes c = sp[0]; sp[0] = sp[3]; sp[3] = c; 16811558Srgrimes c = sp[2]; sp[2] = sp[1]; sp[1] = c; 16821558Srgrimes sp += 4; 16831558Srgrimes } 16841558Srgrimes return (sp); 16851558Srgrimes} 16861558Srgrimes 168798542Smckusickstatic u_char * 168898542Smckusickswabquad(u_char *sp, int n) 168998542Smckusick{ 169098542Smckusick char c; 169198542Smckusick 169298542Smckusick while (--n >= 0) { 169398542Smckusick c = sp[0]; sp[0] = sp[7]; sp[7] = c; 169498542Smckusick c = sp[1]; sp[1] = sp[6]; sp[6] = c; 169598542Smckusick c = sp[2]; sp[2] = sp[5]; sp[5] = c; 169698542Smckusick c = sp[3]; sp[3] = sp[4]; sp[4] = c; 169798542Smckusick sp += 8; 169898542Smckusick } 169998542Smckusick return (sp); 170098542Smckusick} 170198542Smckusick 17021558Srgrimesvoid 170392837Simpswabst(u_char *cp, u_char *sp) 17041558Srgrimes{ 17051558Srgrimes int n = 0; 17061558Srgrimes 17071558Srgrimes while (*cp) { 17081558Srgrimes switch (*cp) { 17091558Srgrimes case '0': case '1': case '2': case '3': case '4': 17101558Srgrimes case '5': case '6': case '7': case '8': case '9': 17111558Srgrimes n = (n * 10) + (*cp++ - '0'); 17121558Srgrimes continue; 17138871Srgrimes 17141558Srgrimes case 's': case 'w': case 'h': 17151558Srgrimes if (n == 0) 17161558Srgrimes n = 1; 17171558Srgrimes sp = swabshort(sp, n); 17181558Srgrimes break; 17191558Srgrimes 17201558Srgrimes case 'l': 17211558Srgrimes if (n == 0) 17221558Srgrimes n = 1; 17231558Srgrimes sp = swablong(sp, n); 17241558Srgrimes break; 17251558Srgrimes 172698542Smckusick case 'q': 17271558Srgrimes if (n == 0) 17281558Srgrimes n = 1; 172998542Smckusick sp = swabquad(sp, n); 173098542Smckusick break; 173198542Smckusick 173298542Smckusick case 'b': 173398542Smckusick if (n == 0) 173498542Smckusick n = 1; 17351558Srgrimes sp += n; 17361558Srgrimes break; 173798542Smckusick 173898542Smckusick default: 173998542Smckusick fprintf(stderr, "Unknown conversion character: %c\n", 174098542Smckusick *cp); 174198542Smckusick done(0); 174298542Smckusick break; 17431558Srgrimes } 17441558Srgrimes cp++; 17451558Srgrimes n = 0; 17461558Srgrimes } 17471558Srgrimes} 17481558Srgrimes 17491558Srgrimesstatic u_long 175092837Simpswabl(u_long x) 17511558Srgrimes{ 17521558Srgrimes swabst((u_char *)"l", (u_char *)&x); 17531558Srgrimes return (x); 17541558Srgrimes} 1755