tape.c revision 298901
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1983, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * (c) UNIX System Laboratories, Inc. 51558Srgrimes * All or some portions of this file are derived from material licensed 61558Srgrimes * to the University of California by American Telephone and Telegraph 71558Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 81558Srgrimes * the permission of UNIX System Laboratories, Inc. 91558Srgrimes * 101558Srgrimes * Redistribution and use in source and binary forms, with or without 111558Srgrimes * modification, are permitted provided that the following conditions 121558Srgrimes * are met: 131558Srgrimes * 1. Redistributions of source code must retain the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer. 151558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161558Srgrimes * notice, this list of conditions and the following disclaimer in the 171558Srgrimes * documentation and/or other materials provided with the distribution. 181558Srgrimes * 4. Neither the name of the University nor the names of its contributors 191558Srgrimes * may be used to endorse or promote products derived from this software 201558Srgrimes * without specific prior written permission. 211558Srgrimes * 221558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321558Srgrimes * SUCH DAMAGE. 331558Srgrimes */ 341558Srgrimes 351558Srgrimes#ifndef lint 3637906Scharnier#if 0 3723685Speterstatic char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; 3837906Scharnier#endif 391558Srgrimes#endif /* not lint */ 401558Srgrimes 41146754Scharnier#include <sys/cdefs.h> 42146754Scharnier__FBSDID("$FreeBSD: head/sbin/restore/tape.c 298901 2016-05-01 21:17:30Z pfg $"); 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); 107298901Spfgstatic void xtrattr(char *, size_t); 108167011Smckusickstatic void set_extattr_link(char *, void *, int); 109167011Smckusickstatic void set_extattr_fd(int, char *, void *, int); 110298901Spfgstatic void skiphole(void (*)(char *, size_t), size_t *); 11192837Simpstatic int gethead(struct s_spcl *); 11292837Simpstatic void readtape(char *); 11392837Simpstatic void setdumpnum(void); 11492837Simpstatic u_long swabl(u_long); 11592837Simpstatic u_char *swablong(u_char *, int); 11692837Simpstatic u_char *swabshort(u_char *, int); 11792837Simpstatic void terminateinput(void); 118298901Spfgstatic void xtrfile(char *, size_t); 119298901Spfgstatic void xtrlnkfile(char *, size_t); 120298901Spfgstatic void xtrlnkskip(char *, size_t); 121298901Spfgstatic void xtrmap(char *, size_t); 122298901Spfgstatic void xtrmapskip(char *, size_t); 123298901Spfgstatic void xtrskip(char *, size_t); 1241558Srgrimes 1251558Srgrimes/* 1261558Srgrimes * Set up an input source 1271558Srgrimes */ 1281558Srgrimesvoid 129128175Sgreensetinput(char *source, int ispipecommand) 1301558Srgrimes{ 1311558Srgrimes FLUSHTAPEBUF(); 1321558Srgrimes if (bflag) 1331558Srgrimes newtapebuf(ntrec); 1341558Srgrimes else 135298394Saraujo newtapebuf(MAX(NTREC, HIGHDENSITYTREC)); 1361558Srgrimes terminal = stdin; 1371558Srgrimes 138128175Sgreen if (ispipecommand) 139128175Sgreen pipecmdin++; 140128175Sgreen else 1411558Srgrimes#ifdef RRESTORE 14223685Speter if (strchr(source, ':')) { 1431558Srgrimes host = source; 14423685Speter source = strchr(host, ':'); 1451558Srgrimes *source++ = '\0'; 1461558Srgrimes if (rmthost(host) == 0) 1471558Srgrimes done(1); 1481558Srgrimes } else 1491558Srgrimes#endif 1501558Srgrimes if (strcmp(source, "-") == 0) { 1511558Srgrimes /* 1521558Srgrimes * Since input is coming from a pipe we must establish 1531558Srgrimes * our own connection to the terminal. 1541558Srgrimes */ 1551558Srgrimes terminal = fopen(_PATH_TTY, "r"); 1561558Srgrimes if (terminal == NULL) { 1571558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1581558Srgrimes _PATH_TTY, strerror(errno)); 1591558Srgrimes terminal = fopen(_PATH_DEVNULL, "r"); 1601558Srgrimes if (terminal == NULL) { 1611558Srgrimes (void)fprintf(stderr, "cannot open %s: %s\n", 1621558Srgrimes _PATH_DEVNULL, strerror(errno)); 1631558Srgrimes done(1); 1641558Srgrimes } 1651558Srgrimes } 1661558Srgrimes pipein++; 1671558Srgrimes } 168241848Seadler /* no longer need or want root privileges */ 169241848Seadler if (setuid(getuid()) != 0) { 170241848Seadler fprintf(stderr, "setuid failed\n"); 171241848Seadler done(1); 172241848Seadler } 17321174Sguido magtape = strdup(source); 17421174Sguido if (magtape == NULL) { 17521174Sguido fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 17621174Sguido done(1); 17721174Sguido } 1781558Srgrimes} 1791558Srgrimes 1801558Srgrimesvoid 18192837Simpnewtapebuf(long size) 1821558Srgrimes{ 18392837Simp static int tapebufsize = -1; 1841558Srgrimes 1851558Srgrimes ntrec = size; 1861558Srgrimes if (size <= tapebufsize) 1871558Srgrimes return; 1881558Srgrimes if (tapebuf != NULL) 189164911Sdwmalone free(tapebuf - TP_BSIZE); 190164911Sdwmalone tapebuf = malloc((size+1) * TP_BSIZE); 1911558Srgrimes if (tapebuf == NULL) { 1921558Srgrimes fprintf(stderr, "Cannot allocate space for tape buffer\n"); 1931558Srgrimes done(1); 1941558Srgrimes } 195164911Sdwmalone tapebuf += TP_BSIZE; 1961558Srgrimes tapebufsize = size; 1971558Srgrimes} 1981558Srgrimes 1991558Srgrimes/* 2001558Srgrimes * Verify that the tape drive can be accessed and 2011558Srgrimes * that it actually is a dump tape. 2021558Srgrimes */ 2031558Srgrimesvoid 20492837Simpsetup(void) 2051558Srgrimes{ 2061558Srgrimes int i, j, *ip; 2071558Srgrimes struct stat stbuf; 2081558Srgrimes 2091558Srgrimes vprintf(stdout, "Verify tape and initialize maps\n"); 210128175Sgreen if (pipecmdin) { 211128175Sgreen if (setenv("RESTORE_VOLUME", "1", 1) == -1) { 212128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 213128175Sgreen strerror(errno)); 214128175Sgreen done(1); 215128175Sgreen } 216128175Sgreen popenfp = popen(magtape, "r"); 217128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 218128175Sgreen } else 2191558Srgrimes#ifdef RRESTORE 2201558Srgrimes if (host) 2211558Srgrimes mt = rmtopen(magtape, 0); 2221558Srgrimes else 2231558Srgrimes#endif 2241558Srgrimes if (pipein) 2251558Srgrimes mt = 0; 2261558Srgrimes else 2271558Srgrimes mt = open(magtape, O_RDONLY, 0); 2281558Srgrimes if (mt < 0) { 2291558Srgrimes fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 2301558Srgrimes done(1); 2311558Srgrimes } 2321558Srgrimes volno = 1; 2331558Srgrimes setdumpnum(); 2341558Srgrimes FLUSHTAPEBUF(); 235203816Sjh if (!pipein && !pipecmdin && !bflag) 2361558Srgrimes findtapeblksize(); 2371558Srgrimes if (gethead(&spcl) == FAIL) { 23898542Smckusick fprintf(stderr, "Tape is not a dump tape\n"); 23998542Smckusick done(1); 2401558Srgrimes } 2411558Srgrimes if (pipein) { 24298542Smckusick endoftapemark.s_spcl.c_magic = FS_UFS2_MAGIC; 2431558Srgrimes endoftapemark.s_spcl.c_type = TS_END; 2441558Srgrimes ip = (int *)&endoftapemark; 2451558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 2461558Srgrimes i = 0; 2471558Srgrimes do 2481558Srgrimes i += *ip++; 2491558Srgrimes while (--j); 2501558Srgrimes endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 2511558Srgrimes } 2521558Srgrimes if (vflag || command == 't') 2531558Srgrimes printdumpinfo(); 25498542Smckusick dumptime = _time64_to_time(spcl.c_ddate); 25598542Smckusick dumpdate = _time64_to_time(spcl.c_date); 2561558Srgrimes if (stat(".", &stbuf) < 0) { 2571558Srgrimes fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 2581558Srgrimes done(1); 2591558Srgrimes } 26034851Sjkh if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 26134851Sjkh fssize = TP_BSIZE; 26234851Sjkh if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 2631558Srgrimes fssize = stbuf.st_blksize; 264269303Smckusick if (((TP_BSIZE - 1) & stbuf.st_blksize) != 0) { 265269303Smckusick fprintf(stderr, "Warning: filesystem with non-multiple-of-%d " 266269303Smckusick "blocksize (%d);\n", TP_BSIZE, stbuf.st_blksize); 267269303Smckusick fssize = roundup(fssize, TP_BSIZE); 268269303Smckusick fprintf(stderr, "\twriting using blocksize %ld\n", fssize); 2691558Srgrimes } 2701558Srgrimes if (spcl.c_volume != 1) { 2711558Srgrimes fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2721558Srgrimes done(1); 2731558Srgrimes } 2741558Srgrimes if (gethead(&spcl) == FAIL) { 27537240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 2761558Srgrimes panic("no header after volume mark!\n"); 2771558Srgrimes } 2781558Srgrimes findinode(&spcl); 2791558Srgrimes if (spcl.c_type != TS_CLRI) { 2801558Srgrimes fprintf(stderr, "Cannot find file removal list\n"); 2811558Srgrimes done(1); 2821558Srgrimes } 2831558Srgrimes maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 284241013Smdf dprintf(stdout, "maxino = %ju\n", (uintmax_t)maxino); 2851558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2861558Srgrimes if (map == NULL) 28723685Speter panic("no memory for active inode map\n"); 28823685Speter usedinomap = map; 2891558Srgrimes curfile.action = USING; 290167011Smckusick getfile(xtrmap, xtrmapskip, xtrmapskip); 2911558Srgrimes if (spcl.c_type != TS_BITS) { 2921558Srgrimes fprintf(stderr, "Cannot find file dump list\n"); 2931558Srgrimes done(1); 2941558Srgrimes } 2951558Srgrimes map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2961558Srgrimes if (map == (char *)NULL) 2971558Srgrimes panic("no memory for file dump list\n"); 2981558Srgrimes dumpmap = map; 2991558Srgrimes curfile.action = USING; 300167011Smckusick getfile(xtrmap, xtrmapskip, xtrmapskip); 30123685Speter /* 30223685Speter * If there may be whiteout entries on the tape, pretend that the 30323685Speter * whiteout inode exists, so that the whiteout entries can be 30423685Speter * extracted. 30523685Speter */ 30698542Smckusick SETINO(WINO, dumpmap); 30790820Siedowse /* 'r' restores don't call getvol() for tape 1, so mark it as read. */ 30890820Siedowse if (command == 'r') 30990820Siedowse tapesread = 1; 3101558Srgrimes} 3111558Srgrimes 3121558Srgrimes/* 3131558Srgrimes * Prompt user to load a new dump volume. 3141558Srgrimes * "Nextvol" is the next suggested volume to use. 3151558Srgrimes * This suggested volume is enforced when doing full 31637906Scharnier * or incremental restores, but can be overridden by 3171558Srgrimes * the user when only extracting a subset of the files. 3181558Srgrimes */ 3191558Srgrimesvoid 32092837Simpgetvol(long nextvol) 3211558Srgrimes{ 32298542Smckusick int64_t prevtapea; 32398542Smckusick long i, newvol, savecnt; 3241558Srgrimes union u_spcl tmpspcl; 3251558Srgrimes# define tmpbuf tmpspcl.s_spcl 3261558Srgrimes char buf[TP_BSIZE]; 3271558Srgrimes 3281558Srgrimes if (nextvol == 1) { 3291558Srgrimes tapesread = 0; 3301558Srgrimes gettingfile = 0; 3311558Srgrimes } 33290827Siedowse prevtapea = tapeaddr; 33390827Siedowse savecnt = blksread; 3341558Srgrimes if (pipein) { 33569906Siedowse if (nextvol != 1) { 3361558Srgrimes panic("Changing volumes on pipe input?\n"); 33769906Siedowse /* Avoid looping if we couldn't ask the user. */ 33869906Siedowse if (yflag || ferror(terminal) || feof(terminal)) 33969906Siedowse done(1); 34069906Siedowse } 3411558Srgrimes if (volno == 1) 3421558Srgrimes return; 343297441Spfg newvol = 0; 3441558Srgrimes goto gethdr; 3451558Srgrimes } 3461558Srgrimesagain: 3471558Srgrimes if (pipein) 3481558Srgrimes done(1); /* pipes do not get a second chance */ 34990608Siedowse if (command == 'R' || command == 'r' || curfile.action != SKIP) 3501558Srgrimes newvol = nextvol; 35190608Siedowse else 3521558Srgrimes newvol = 0; 3531558Srgrimes while (newvol <= 0) { 3541558Srgrimes if (tapesread == 0) { 35590820Siedowse fprintf(stderr, "%s%s%s%s%s%s%s", 3561558Srgrimes "You have not read any tapes yet.\n", 35790820Siedowse "If you are extracting just a few files,", 35890820Siedowse " start with the last volume\n", 35990820Siedowse "and work towards the first; restore", 36090820Siedowse " can quickly skip tapes that\n", 36190820Siedowse "have no further files to extract.", 36290820Siedowse " Otherwise, begin with volume 1.\n"); 3631558Srgrimes } else { 3641558Srgrimes fprintf(stderr, "You have read volumes"); 3651558Srgrimes strcpy(buf, ": "); 36690820Siedowse for (i = 0; i < 32; i++) 3671558Srgrimes if (tapesread & (1 << i)) { 36890820Siedowse fprintf(stderr, "%s%ld", buf, i + 1); 3691558Srgrimes strcpy(buf, ", "); 3701558Srgrimes } 3711558Srgrimes fprintf(stderr, "\n"); 3721558Srgrimes } 3731558Srgrimes do { 3741558Srgrimes fprintf(stderr, "Specify next volume #: "); 3751558Srgrimes (void) fflush(stderr); 37669906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 37769906Siedowse done(1); 37869906Siedowse } while (buf[0] == '\n'); 3791558Srgrimes newvol = atoi(buf); 3801558Srgrimes if (newvol <= 0) { 3811558Srgrimes fprintf(stderr, 3821558Srgrimes "Volume numbers are positive numerics\n"); 3831558Srgrimes } 3841558Srgrimes } 3851558Srgrimes if (newvol == volno) { 38690820Siedowse tapesread |= 1 << (volno - 1); 3871558Srgrimes return; 3881558Srgrimes } 3891558Srgrimes closemt(); 39037240Sbde fprintf(stderr, "Mount tape volume %ld\n", newvol); 3911558Srgrimes fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 3921558Srgrimes fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 3931558Srgrimes (void) fflush(stderr); 39469906Siedowse if (fgets(buf, BUFSIZ, terminal) == NULL) 3951558Srgrimes done(1); 3961558Srgrimes if (!strcmp(buf, "none\n")) { 3971558Srgrimes terminateinput(); 3981558Srgrimes return; 3991558Srgrimes } 4001558Srgrimes if (buf[0] != '\n') { 4011558Srgrimes (void) strcpy(magtape, buf); 4021558Srgrimes magtape[strlen(magtape) - 1] = '\0'; 4031558Srgrimes } 404128175Sgreen if (pipecmdin) { 405128175Sgreen char volno[sizeof("2147483647")]; 406128175Sgreen 407203155Sjh (void)sprintf(volno, "%ld", newvol); 408128175Sgreen if (setenv("RESTORE_VOLUME", volno, 1) == -1) { 409128175Sgreen fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 410128175Sgreen strerror(errno)); 411128175Sgreen done(1); 412128175Sgreen } 413128175Sgreen popenfp = popen(magtape, "r"); 414128175Sgreen mt = popenfp ? fileno(popenfp) : -1; 415128175Sgreen } else 4161558Srgrimes#ifdef RRESTORE 4171558Srgrimes if (host) 4181558Srgrimes mt = rmtopen(magtape, 0); 4191558Srgrimes else 4201558Srgrimes#endif 4211558Srgrimes mt = open(magtape, O_RDONLY, 0); 4221558Srgrimes 4231558Srgrimes if (mt == -1) { 4241558Srgrimes fprintf(stderr, "Cannot open %s\n", magtape); 4251558Srgrimes volno = -1; 4261558Srgrimes goto again; 4271558Srgrimes } 4281558Srgrimesgethdr: 4291558Srgrimes volno = newvol; 4301558Srgrimes setdumpnum(); 4311558Srgrimes FLUSHTAPEBUF(); 4321558Srgrimes if (gethead(&tmpbuf) == FAIL) { 43337240Sbde dprintf(stdout, "header read failed at %ld blocks\n", blksread); 4341558Srgrimes fprintf(stderr, "tape is not dump tape\n"); 4351558Srgrimes volno = 0; 4361558Srgrimes goto again; 4371558Srgrimes } 4381558Srgrimes if (tmpbuf.c_volume != volno) { 439203155Sjh fprintf(stderr, "Wrong volume (%jd)\n", 440203155Sjh (intmax_t)tmpbuf.c_volume); 4411558Srgrimes volno = 0; 4421558Srgrimes goto again; 4431558Srgrimes } 44498542Smckusick if (_time64_to_time(tmpbuf.c_date) != dumpdate || 44598542Smckusick _time64_to_time(tmpbuf.c_ddate) != dumptime) { 44698542Smckusick time_t t = _time64_to_time(tmpbuf.c_date); 44785635Sdillon fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t)); 4481558Srgrimes fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 4491558Srgrimes volno = 0; 4501558Srgrimes goto again; 4511558Srgrimes } 45290820Siedowse tapesread |= 1 << (volno - 1); 4531558Srgrimes blksread = savecnt; 4541558Srgrimes /* 4551558Srgrimes * If continuing from the previous volume, skip over any 4561558Srgrimes * blocks read already at the end of the previous volume. 4571558Srgrimes * 4581558Srgrimes * If coming to this volume at random, skip to the beginning 4591558Srgrimes * of the next record. 4601558Srgrimes */ 461203155Sjh dprintf(stdout, "last rec %jd, tape starts with %jd\n", 462203155Sjh (intmax_t)prevtapea, (intmax_t)tmpbuf.c_tapea); 46398542Smckusick if (tmpbuf.c_type == TS_TAPE) { 46490608Siedowse if (curfile.action != USING) { 46590608Siedowse /* 46690608Siedowse * XXX Dump incorrectly sets c_count to 1 in the 46790608Siedowse * volume header of the first tape, so ignore 46890608Siedowse * c_count when volno == 1. 46990608Siedowse */ 47090608Siedowse if (volno != 1) 47190608Siedowse for (i = tmpbuf.c_count; i > 0; i--) 47290608Siedowse readtape(buf); 47390827Siedowse } else if (tmpbuf.c_tapea <= prevtapea) { 4741558Srgrimes /* 47590827Siedowse * Normally the value of c_tapea in the volume 47690827Siedowse * header is the record number of the header itself. 47790827Siedowse * However in the volume header following an EOT- 47890827Siedowse * terminated tape, it is the record number of the 47990827Siedowse * first continuation data block (dump bug?). 48090827Siedowse * 48190827Siedowse * The next record we want is `prevtapea + 1'. 4821558Srgrimes */ 48390827Siedowse i = prevtapea + 1 - tmpbuf.c_tapea; 48437240Sbde dprintf(stderr, "Skipping %ld duplicate record%s.\n", 4851558Srgrimes i, i > 1 ? "s" : ""); 4861558Srgrimes while (--i >= 0) 4871558Srgrimes readtape(buf); 4881558Srgrimes } 4891558Srgrimes } 49090608Siedowse if (curfile.action == USING) { 4911558Srgrimes if (volno == 1) 4921558Srgrimes panic("active file into volume 1\n"); 4931558Srgrimes return; 4941558Srgrimes } 4951558Srgrimes (void) gethead(&spcl); 4961558Srgrimes findinode(&spcl); 4971558Srgrimes if (gettingfile) { 4981558Srgrimes gettingfile = 0; 4991558Srgrimes longjmp(restart, 1); 5001558Srgrimes } 5011558Srgrimes} 5021558Srgrimes 5031558Srgrimes/* 5041558Srgrimes * Handle unexpected EOF. 5051558Srgrimes */ 5061558Srgrimesstatic void 50792837Simpterminateinput(void) 5081558Srgrimes{ 5091558Srgrimes 5101558Srgrimes if (gettingfile && curfile.action == USING) { 5111558Srgrimes printf("Warning: %s %s\n", 5121558Srgrimes "End-of-input encountered while extracting", curfile.name); 5131558Srgrimes } 5141558Srgrimes curfile.name = "<name unknown>"; 5151558Srgrimes curfile.action = UNKNOWN; 51698542Smckusick curfile.mode = 0; 5171558Srgrimes curfile.ino = maxino; 5181558Srgrimes if (gettingfile) { 5191558Srgrimes gettingfile = 0; 5201558Srgrimes longjmp(restart, 1); 5211558Srgrimes } 5221558Srgrimes} 5231558Srgrimes 5241558Srgrimes/* 5251558Srgrimes * handle multiple dumps per tape by skipping forward to the 5261558Srgrimes * appropriate one. 5271558Srgrimes */ 5281558Srgrimesstatic void 52992837Simpsetdumpnum(void) 5301558Srgrimes{ 5311558Srgrimes struct mtop tcom; 5321558Srgrimes 5331558Srgrimes if (dumpnum == 1 || volno != 1) 5341558Srgrimes return; 5351558Srgrimes if (pipein) { 5361558Srgrimes fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 5371558Srgrimes done(1); 5381558Srgrimes } 5391558Srgrimes tcom.mt_op = MTFSF; 5401558Srgrimes tcom.mt_count = dumpnum - 1; 5411558Srgrimes#ifdef RRESTORE 5421558Srgrimes if (host) 5431558Srgrimes rmtioctl(MTFSF, dumpnum - 1); 5448871Srgrimes else 5451558Srgrimes#endif 546128175Sgreen if (!pipecmdin && ioctl(mt, MTIOCTOP, (char *)&tcom) < 0) 5471558Srgrimes fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 5481558Srgrimes} 5491558Srgrimes 5501558Srgrimesvoid 55192837Simpprintdumpinfo(void) 5521558Srgrimes{ 55385635Sdillon time_t t; 55498542Smckusick t = _time64_to_time(spcl.c_date); 55585635Sdillon fprintf(stdout, "Dump date: %s", ctime(&t)); 55698542Smckusick t = _time64_to_time(spcl.c_ddate); 5571558Srgrimes fprintf(stdout, "Dumped from: %s", 55885635Sdillon (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t)); 5591558Srgrimes if (spcl.c_host[0] == '\0') 5601558Srgrimes return; 561203155Sjh fprintf(stderr, "Level %jd dump of %s on %s:%s\n", 562203155Sjh (intmax_t)spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 5631558Srgrimes fprintf(stderr, "Label: %s\n", spcl.c_label); 5641558Srgrimes} 5651558Srgrimes 5661558Srgrimesint 56792837Simpextractfile(char *name) 5681558Srgrimes{ 569298901Spfg u_int flags; 570161598Smaxim uid_t uid; 571161598Smaxim gid_t gid; 57223685Speter mode_t mode; 573167011Smckusick int extsize; 574279986Sjilles struct timespec mtimep[2], ctimep[2]; 5751558Srgrimes struct entry *ep; 576167011Smckusick char *buf; 5771558Srgrimes 5781558Srgrimes curfile.name = name; 5791558Srgrimes curfile.action = USING; 580100207Smckusick mtimep[0].tv_sec = curfile.atime_sec; 581279986Sjilles mtimep[0].tv_nsec = curfile.atime_nsec; 582100207Smckusick mtimep[1].tv_sec = curfile.mtime_sec; 583279986Sjilles mtimep[1].tv_nsec = curfile.mtime_nsec; 584100207Smckusick ctimep[0].tv_sec = curfile.atime_sec; 585279986Sjilles ctimep[0].tv_nsec = curfile.atime_nsec; 586100207Smckusick ctimep[1].tv_sec = curfile.birthtime_sec; 587279986Sjilles ctimep[1].tv_nsec = curfile.birthtime_nsec; 588167011Smckusick extsize = curfile.extsize; 589178125Smckusick uid = getuid(); 590178125Smckusick if (uid == 0) 591178125Smckusick uid = curfile.uid; 592161598Smaxim gid = curfile.gid; 59398542Smckusick mode = curfile.mode; 59498542Smckusick flags = curfile.file_flags; 5951558Srgrimes switch (mode & IFMT) { 5961558Srgrimes 5971558Srgrimes default: 5981558Srgrimes fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 5991558Srgrimes skipfile(); 6001558Srgrimes return (FAIL); 6011558Srgrimes 6021558Srgrimes case IFSOCK: 6031558Srgrimes vprintf(stdout, "skipped socket %s\n", name); 6041558Srgrimes skipfile(); 6051558Srgrimes return (GOOD); 6061558Srgrimes 6071558Srgrimes case IFDIR: 6081558Srgrimes if (mflag) { 6091558Srgrimes ep = lookupname(name); 6101558Srgrimes if (ep == NULL || ep->e_flags & EXTRACT) 6111558Srgrimes panic("unextracted directory %s\n", name); 6121558Srgrimes skipfile(); 6131558Srgrimes return (GOOD); 6141558Srgrimes } 6151558Srgrimes vprintf(stdout, "extract file %s\n", name); 6161558Srgrimes return (genliteraldir(name, curfile.ino)); 6171558Srgrimes 6181558Srgrimes case IFLNK: 6191558Srgrimes lnkbuf[0] = '\0'; 6201558Srgrimes pathlen = 0; 621167011Smckusick buf = setupextattr(extsize); 622167011Smckusick getfile(xtrlnkfile, xtrattr, xtrlnkskip); 6231558Srgrimes if (pathlen == 0) { 6241558Srgrimes vprintf(stdout, 6251558Srgrimes "%s: zero length symbolic link (ignored)\n", name); 6261558Srgrimes return (GOOD); 6271558Srgrimes } 62896113Siedowse if (linkit(lnkbuf, name, SYMLINK) == GOOD) { 629167011Smckusick if (extsize > 0) 630167011Smckusick set_extattr_link(name, buf, extsize); 631161598Smaxim (void) lchown(name, uid, gid); 63296113Siedowse (void) lchmod(name, mode); 633279986Sjilles (void) utimensat(AT_FDCWD, name, ctimep, 634279986Sjilles AT_SYMLINK_NOFOLLOW); 635279986Sjilles (void) utimensat(AT_FDCWD, name, mtimep, 636279986Sjilles AT_SYMLINK_NOFOLLOW); 637161598Smaxim (void) lchflags(name, flags); 63896113Siedowse return (GOOD); 63995943Siedowse } 64096113Siedowse return (FAIL); 6411558Srgrimes 6426305Smartin case IFIFO: 64323685Speter vprintf(stdout, "extract fifo %s\n", name); 64423685Speter if (Nflag) { 64523685Speter skipfile(); 64623685Speter return (GOOD); 64723685Speter } 648161598Smaxim if (uflag) 649161598Smaxim (void) unlink(name); 650161598Smaxim if (mkfifo(name, 0600) < 0) { 65123685Speter fprintf(stderr, "%s: cannot create fifo: %s\n", 65223685Speter name, strerror(errno)); 6536305Smartin skipfile(); 6546305Smartin return (FAIL); 6556305Smartin } 656167011Smckusick if (extsize == 0) { 657167011Smckusick skipfile(); 658167011Smckusick } else { 659167011Smckusick buf = setupextattr(extsize); 660167011Smckusick getfile(xtrnull, xtrattr, xtrnull); 661167011Smckusick set_extattr_file(name, buf, extsize); 662167011Smckusick } 663161598Smaxim (void) chown(name, uid, gid); 6646305Smartin (void) chmod(name, mode); 665279986Sjilles (void) utimensat(AT_FDCWD, name, ctimep, 0); 666279986Sjilles (void) utimensat(AT_FDCWD, name, mtimep, 0); 66723685Speter (void) chflags(name, flags); 6686305Smartin return (GOOD); 6696305Smartin 6701558Srgrimes case IFCHR: 6711558Srgrimes case IFBLK: 6721558Srgrimes vprintf(stdout, "extract special file %s\n", name); 6731558Srgrimes if (Nflag) { 6741558Srgrimes skipfile(); 6751558Srgrimes return (GOOD); 6761558Srgrimes } 67735852Sjkh if (uflag) 678161598Smaxim (void) unlink(name); 679161598Smaxim if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600, 680161605Smaxim (int)curfile.rdev) < 0) { 6811558Srgrimes fprintf(stderr, "%s: cannot create special file: %s\n", 6821558Srgrimes name, strerror(errno)); 6831558Srgrimes skipfile(); 6841558Srgrimes return (FAIL); 6851558Srgrimes } 686167011Smckusick if (extsize == 0) { 687167011Smckusick skipfile(); 688167011Smckusick } else { 689167011Smckusick buf = setupextattr(extsize); 690167011Smckusick getfile(xtrnull, xtrattr, xtrnull); 691167011Smckusick set_extattr_file(name, buf, extsize); 692167011Smckusick } 693161598Smaxim (void) chown(name, uid, gid); 6941558Srgrimes (void) chmod(name, mode); 695279986Sjilles (void) utimensat(AT_FDCWD, name, ctimep, 0); 696279986Sjilles (void) utimensat(AT_FDCWD, name, mtimep, 0); 69723685Speter (void) chflags(name, flags); 6981558Srgrimes return (GOOD); 6991558Srgrimes 7001558Srgrimes case IFREG: 7011558Srgrimes vprintf(stdout, "extract file %s\n", name); 7021558Srgrimes if (Nflag) { 7031558Srgrimes skipfile(); 7041558Srgrimes return (GOOD); 7051558Srgrimes } 70635852Sjkh if (uflag) 707161598Smaxim (void) unlink(name); 70821149Simp if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 709161598Smaxim 0600)) < 0) { 7101558Srgrimes fprintf(stderr, "%s: cannot create file: %s\n", 7111558Srgrimes name, strerror(errno)); 7121558Srgrimes skipfile(); 7131558Srgrimes return (FAIL); 7141558Srgrimes } 715167011Smckusick buf = setupextattr(extsize); 716167011Smckusick getfile(xtrfile, xtrattr, xtrskip); 717167011Smckusick if (extsize > 0) 718167011Smckusick set_extattr_fd(ofile, name, buf, extsize); 719161598Smaxim (void) fchown(ofile, uid, gid); 7201558Srgrimes (void) fchmod(ofile, mode); 721279986Sjilles (void) futimens(ofile, ctimep); 722279986Sjilles (void) futimens(ofile, mtimep); 723161598Smaxim (void) fchflags(ofile, flags); 7241558Srgrimes (void) close(ofile); 7251558Srgrimes return (GOOD); 7261558Srgrimes } 7271558Srgrimes /* NOTREACHED */ 7281558Srgrimes} 7291558Srgrimes 7301558Srgrimes/* 731167011Smckusick * Set attributes for a file. 732167011Smckusick */ 733167011Smckusickvoid 734167011Smckusickset_extattr_file(char *name, void *buf, int size) 735167011Smckusick{ 736167011Smckusick struct extattr *eap, *eaend; 737167011Smckusick 738167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 739167011Smckusick eaend = buf + size; 740167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 741167011Smckusick /* 742167011Smckusick * Make sure this entry is complete. 743167011Smckusick */ 744167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 745167011Smckusick dprintf(stdout, "\n\t%scorrupted", 746167011Smckusick eap == buf ? "" : "remainder "); 747167011Smckusick break; 748167011Smckusick } 749167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 750167011Smckusick continue; 751167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 752167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 753167011Smckusick eap->ea_namelength, eap->ea_name); 754167011Smckusick /* 755167011Smckusick * First we try the general attribute setting interface. 756167011Smckusick * However, some attributes can only be set by root or 757167011Smckusick * by using special interfaces (for example, ACLs). 758167011Smckusick */ 759167011Smckusick if (extattr_set_file(name, eap->ea_namespace, eap->ea_name, 760167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 761167011Smckusick dprintf(stdout, " (set using extattr_set_file)"); 762167011Smckusick continue; 763167011Smckusick } 764167011Smckusick /* 765167011Smckusick * If the general interface refuses to set the attribute, 766167011Smckusick * then we try all the specialized interfaces that we 767167011Smckusick * know about. 768167011Smckusick */ 769167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 770167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 771167011Smckusick if (acl_set_file(name, ACL_TYPE_ACCESS, 772167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 773167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 774167011Smckusick continue; 775167011Smckusick } 776167011Smckusick } 777167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 778167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 779167011Smckusick if (acl_set_file(name, ACL_TYPE_DEFAULT, 780167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 781167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 782167011Smckusick continue; 783167011Smckusick } 784167011Smckusick } 785167011Smckusick vprintf(stdout, " (unable to set)"); 786167011Smckusick } 787167011Smckusick vprintf(stdout, "\n"); 788167011Smckusick} 789167011Smckusick 790167011Smckusick/* 791167011Smckusick * Set attributes for a symbolic link. 792167011Smckusick */ 793167011Smckusickstatic void 794167011Smckusickset_extattr_link(char *name, void *buf, int size) 795167011Smckusick{ 796167011Smckusick struct extattr *eap, *eaend; 797167011Smckusick 798167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 799167011Smckusick eaend = buf + size; 800167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 801167011Smckusick /* 802167011Smckusick * Make sure this entry is complete. 803167011Smckusick */ 804167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 805167011Smckusick dprintf(stdout, "\n\t%scorrupted", 806167011Smckusick eap == buf ? "" : "remainder "); 807167011Smckusick break; 808167011Smckusick } 809167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 810167011Smckusick continue; 811167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 812167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 813167011Smckusick eap->ea_namelength, eap->ea_name); 814167011Smckusick /* 815167011Smckusick * First we try the general attribute setting interface. 816167011Smckusick * However, some attributes can only be set by root or 817167011Smckusick * by using special interfaces (for example, ACLs). 818167011Smckusick */ 819167011Smckusick if (extattr_set_link(name, eap->ea_namespace, eap->ea_name, 820167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 821167011Smckusick dprintf(stdout, " (set using extattr_set_link)"); 822167011Smckusick continue; 823167011Smckusick } 824167011Smckusick /* 825167011Smckusick * If the general interface refuses to set the attribute, 826167011Smckusick * then we try all the specialized interfaces that we 827167011Smckusick * know about. 828167011Smckusick */ 829167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 830167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 831167011Smckusick if (acl_set_link_np(name, ACL_TYPE_ACCESS, 832167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 833167011Smckusick dprintf(stdout, " (set using acl_set_link_np)"); 834167011Smckusick continue; 835167011Smckusick } 836167011Smckusick } 837167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 838167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 839167011Smckusick if (acl_set_link_np(name, ACL_TYPE_DEFAULT, 840167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 841167011Smckusick dprintf(stdout, " (set using acl_set_link_np)"); 842167011Smckusick continue; 843167011Smckusick } 844167011Smckusick } 845167011Smckusick vprintf(stdout, " (unable to set)"); 846167011Smckusick } 847167011Smckusick vprintf(stdout, "\n"); 848167011Smckusick} 849167011Smckusick 850167011Smckusick/* 851167011Smckusick * Set attributes on a file descriptor. 852167011Smckusick */ 853167011Smckusickstatic void 854167011Smckusickset_extattr_fd(int fd, char *name, void *buf, int size) 855167011Smckusick{ 856167011Smckusick struct extattr *eap, *eaend; 857167011Smckusick 858167011Smckusick vprintf(stdout, "Set attributes for %s:", name); 859167011Smckusick eaend = buf + size; 860167011Smckusick for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 861167011Smckusick /* 862167011Smckusick * Make sure this entry is complete. 863167011Smckusick */ 864167011Smckusick if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 865167011Smckusick dprintf(stdout, "\n\t%scorrupted", 866167011Smckusick eap == buf ? "" : "remainder "); 867167011Smckusick break; 868167011Smckusick } 869167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 870167011Smckusick continue; 871167011Smckusick vprintf(stdout, "\n\t%s, (%d bytes), %*s", 872167011Smckusick namespace_names[eap->ea_namespace], eap->ea_length, 873167011Smckusick eap->ea_namelength, eap->ea_name); 874167011Smckusick /* 875167011Smckusick * First we try the general attribute setting interface. 876167011Smckusick * However, some attributes can only be set by root or 877167011Smckusick * by using special interfaces (for example, ACLs). 878167011Smckusick */ 879167011Smckusick if (extattr_set_fd(fd, eap->ea_namespace, eap->ea_name, 880167011Smckusick EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 881167011Smckusick dprintf(stdout, " (set using extattr_set_fd)"); 882167011Smckusick continue; 883167011Smckusick } 884167011Smckusick /* 885167011Smckusick * If the general interface refuses to set the attribute, 886167011Smckusick * then we try all the specialized interfaces that we 887167011Smckusick * know about. 888167011Smckusick */ 889167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 890167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 891167011Smckusick if (acl_set_fd(fd, EXTATTR_CONTENT(eap)) != -1) { 892167011Smckusick dprintf(stdout, " (set using acl_set_fd)"); 893167011Smckusick continue; 894167011Smckusick } 895167011Smckusick } 896167011Smckusick if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 897167011Smckusick !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 898167011Smckusick if (acl_set_file(name, ACL_TYPE_DEFAULT, 899167011Smckusick EXTATTR_CONTENT(eap)) != -1) { 900167011Smckusick dprintf(stdout, " (set using acl_set_file)"); 901167011Smckusick continue; 902167011Smckusick } 903167011Smckusick } 904167011Smckusick vprintf(stdout, " (unable to set)"); 905167011Smckusick } 906167011Smckusick vprintf(stdout, "\n"); 907167011Smckusick} 908167011Smckusick 909167011Smckusick/* 9101558Srgrimes * skip over bit maps on the tape 9111558Srgrimes */ 9121558Srgrimesvoid 91392837Simpskipmaps(void) 9141558Srgrimes{ 9151558Srgrimes 9161558Srgrimes while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 9171558Srgrimes skipfile(); 9181558Srgrimes} 9191558Srgrimes 9201558Srgrimes/* 9211558Srgrimes * skip over a file on the tape 9221558Srgrimes */ 9231558Srgrimesvoid 92492837Simpskipfile(void) 9251558Srgrimes{ 9261558Srgrimes 9271558Srgrimes curfile.action = SKIP; 928167011Smckusick getfile(xtrnull, xtrnull, xtrnull); 9291558Srgrimes} 9301558Srgrimes 9311558Srgrimes/* 932290900Sjmg * Skip a hole in an output file 933290900Sjmg */ 934290900Sjmgstatic void 935298901Spfgskiphole(void (*skip)(char *, size_t), size_t *seekpos) 936290900Sjmg{ 937290900Sjmg char buf[MAXBSIZE]; 938290900Sjmg 939290900Sjmg if (*seekpos > 0) { 940290900Sjmg (*skip)(buf, *seekpos); 941290900Sjmg *seekpos = 0; 942290900Sjmg } 943290900Sjmg} 944290900Sjmg 945290900Sjmg/* 9461558Srgrimes * Extract a file from the tape. 9471558Srgrimes * When an allocated block is found it is passed to the fill function; 9481558Srgrimes * when an unallocated block (hole) is found, a zeroed buffer is passed 9491558Srgrimes * to the skip function. 9501558Srgrimes */ 9511558Srgrimesvoid 952298901Spfggetfile(void (*datafill)(char *, size_t), void (*attrfill)(char *, size_t), 953298901Spfg void (*skip)(char *, size_t)) 9541558Srgrimes{ 95592806Sobrien int i; 956298901Spfg volatile off_t size; 957298901Spfg size_t seekpos; 958167011Smckusick int curblk, attrsize; 959298901Spfg void (*fillit)(char *, size_t); 9601558Srgrimes char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 9611558Srgrimes char junk[TP_BSIZE]; 9621558Srgrimes 963167011Smckusick curblk = 0; 964167011Smckusick size = spcl.c_size; 965290900Sjmg seekpos = 0; 966167011Smckusick attrsize = spcl.c_extsize; 9671558Srgrimes if (spcl.c_type == TS_END) 9681558Srgrimes panic("ran off end of tape\n"); 96998542Smckusick if (spcl.c_magic != FS_UFS2_MAGIC) 9701558Srgrimes panic("not at beginning of a file\n"); 9711558Srgrimes if (!gettingfile && setjmp(restart) != 0) 9721558Srgrimes return; 9731558Srgrimes gettingfile++; 974167011Smckusick fillit = datafill; 975167011Smckusick if (size == 0 && attrsize > 0) { 976167011Smckusick fillit = attrfill; 977167011Smckusick size = attrsize; 978167011Smckusick attrsize = 0; 979167011Smckusick } 9801558Srgrimesloop: 9811558Srgrimes for (i = 0; i < spcl.c_count; i++) { 982164911Sdwmalone if (!readmapflag && i > TP_NINDIR) { 983164911Sdwmalone if (Dflag) { 984164911Sdwmalone fprintf(stderr, "spcl.c_count = %jd\n", 985164911Sdwmalone (intmax_t)spcl.c_count); 986164911Sdwmalone break; 987164911Sdwmalone } else 988164911Sdwmalone panic("spcl.c_count = %jd\n", 989164911Sdwmalone (intmax_t)spcl.c_count); 990164911Sdwmalone } 99137923Simp if (readmapflag || spcl.c_addr[i]) { 9921558Srgrimes readtape(&buf[curblk++][0]); 9931558Srgrimes if (curblk == fssize / TP_BSIZE) { 994290900Sjmg skiphole(skip, &seekpos); 995167011Smckusick (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 99623685Speter fssize : (curblk - 1) * TP_BSIZE + size)); 9971558Srgrimes curblk = 0; 9981558Srgrimes } 9991558Srgrimes } else { 10001558Srgrimes if (curblk > 0) { 1001290900Sjmg skiphole(skip, &seekpos); 1002167011Smckusick (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 100323685Speter curblk * TP_BSIZE : 100423685Speter (curblk - 1) * TP_BSIZE + size)); 10051558Srgrimes curblk = 0; 10061558Srgrimes } 1007290900Sjmg /* 1008290900Sjmg * We have a block of a hole. Don't skip it 1009290900Sjmg * now, because there may be next adjacent 1010290900Sjmg * block of the hole in the file. Postpone the 1011290900Sjmg * seek until next file write. 1012290900Sjmg */ 1013298394Saraujo seekpos += (long)MIN(TP_BSIZE, size); 10141558Srgrimes } 10151558Srgrimes if ((size -= TP_BSIZE) <= 0) { 1016167011Smckusick if (size > -TP_BSIZE && curblk > 0) { 1017290900Sjmg skiphole(skip, &seekpos); 1018167011Smckusick (*fillit)((char *)buf, 1019167011Smckusick (long)((curblk * TP_BSIZE) + size)); 1020167011Smckusick curblk = 0; 1021167011Smckusick } 1022167011Smckusick if (attrsize > 0) { 1023167011Smckusick fillit = attrfill; 1024167011Smckusick size = attrsize; 1025167011Smckusick attrsize = 0; 1026167011Smckusick continue; 1027167011Smckusick } 1028167011Smckusick if (spcl.c_count - i > 1) 1029167011Smckusick dprintf(stdout, "skipping %d junk block(s)\n", 1030167011Smckusick spcl.c_count - i - 1); 1031164911Sdwmalone for (i++; i < spcl.c_count; i++) { 1032164911Sdwmalone if (!readmapflag && i > TP_NINDIR) { 1033164911Sdwmalone if (Dflag) { 1034164911Sdwmalone fprintf(stderr, 1035164911Sdwmalone "spcl.c_count = %jd\n", 1036164911Sdwmalone (intmax_t)spcl.c_count); 1037164911Sdwmalone break; 1038164911Sdwmalone } else 1039164911Sdwmalone panic("spcl.c_count = %jd\n", 1040164911Sdwmalone (intmax_t)spcl.c_count); 1041164911Sdwmalone } 104237923Simp if (readmapflag || spcl.c_addr[i]) 10431558Srgrimes readtape(junk); 1044164911Sdwmalone } 10451558Srgrimes break; 10461558Srgrimes } 10471558Srgrimes } 10481558Srgrimes if (gethead(&spcl) == GOOD && size > 0) { 10491558Srgrimes if (spcl.c_type == TS_ADDR) 10501558Srgrimes goto loop; 10511558Srgrimes dprintf(stdout, 105237240Sbde "Missing address (header) block for %s at %ld blocks\n", 10531558Srgrimes curfile.name, blksread); 10541558Srgrimes } 10551558Srgrimes if (curblk > 0) 1056167011Smckusick panic("getfile: lost data\n"); 10571558Srgrimes findinode(&spcl); 10581558Srgrimes gettingfile = 0; 10591558Srgrimes} 10601558Srgrimes 10611558Srgrimes/* 1062167011Smckusick * These variables are shared between the next two functions. 1063167011Smckusick */ 1064167011Smckusickstatic int extbufsize = 0; 1065167011Smckusickstatic char *extbuf; 1066167011Smckusickstatic int extloc; 1067167011Smckusick 1068167011Smckusick/* 1069167011Smckusick * Allocate a buffer into which to extract extended attributes. 1070167011Smckusick */ 1071167011Smckusickstatic char * 1072167011Smckusicksetupextattr(int extsize) 1073167011Smckusick{ 1074167011Smckusick 1075167011Smckusick extloc = 0; 1076167011Smckusick if (extsize <= extbufsize) 1077167011Smckusick return (extbuf); 1078167011Smckusick if (extbufsize > 0) 1079167011Smckusick free(extbuf); 1080167011Smckusick if ((extbuf = malloc(extsize)) != NULL) { 1081167011Smckusick extbufsize = extsize; 1082167011Smckusick return (extbuf); 1083167011Smckusick } 1084167011Smckusick extbufsize = 0; 1085167011Smckusick extbuf = NULL; 1086241013Smdf fprintf(stderr, "Cannot extract %d bytes %s for inode %ju, name %s\n", 1087241013Smdf extsize, "of extended attributes", (uintmax_t)curfile.ino, 1088241013Smdf curfile.name); 1089167011Smckusick return (NULL); 1090167011Smckusick} 1091167011Smckusick 1092167011Smckusick/* 1093167011Smckusick * Extract the next block of extended attributes. 1094167011Smckusick */ 1095167011Smckusickstatic void 1096298901Spfgxtrattr(char *buf, size_t size) 1097167011Smckusick{ 1098167011Smckusick 1099167011Smckusick if (extloc + size > extbufsize) 1100167011Smckusick panic("overrun attribute buffer\n"); 1101167011Smckusick memmove(&extbuf[extloc], buf, size); 1102167011Smckusick extloc += size; 1103167011Smckusick} 1104167011Smckusick 1105167011Smckusick/* 11061558Srgrimes * Write out the next block of a file. 11071558Srgrimes */ 11081558Srgrimesstatic void 1109298901Spfgxtrfile(char *buf, size_t size) 11101558Srgrimes{ 11111558Srgrimes 11121558Srgrimes if (Nflag) 11131558Srgrimes return; 11141558Srgrimes if (write(ofile, buf, (int) size) == -1) { 11151558Srgrimes fprintf(stderr, 1116241013Smdf "write error extracting inode %ju, name %s\nwrite: %s\n", 1117241013Smdf (uintmax_t)curfile.ino, curfile.name, strerror(errno)); 11181558Srgrimes } 11191558Srgrimes} 11201558Srgrimes 11211558Srgrimes/* 11221558Srgrimes * Skip over a hole in a file. 11231558Srgrimes */ 11241558Srgrimes/* ARGSUSED */ 11251558Srgrimesstatic void 1126298901Spfgxtrskip(char *buf, size_t size) 11271558Srgrimes{ 11281558Srgrimes 11291558Srgrimes if (lseek(ofile, size, SEEK_CUR) == -1) { 11301558Srgrimes fprintf(stderr, 1131241013Smdf "seek error extracting inode %ju, name %s\nlseek: %s\n", 1132241013Smdf (uintmax_t)curfile.ino, curfile.name, strerror(errno)); 11331558Srgrimes done(1); 11341558Srgrimes } 11351558Srgrimes} 11361558Srgrimes 11371558Srgrimes/* 11381558Srgrimes * Collect the next block of a symbolic link. 11391558Srgrimes */ 11401558Srgrimesstatic void 1141298901Spfgxtrlnkfile(char *buf, size_t size) 11421558Srgrimes{ 11431558Srgrimes 11441558Srgrimes pathlen += size; 11451558Srgrimes if (pathlen > MAXPATHLEN) { 11461558Srgrimes fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 11471558Srgrimes curfile.name, lnkbuf, buf, pathlen); 11481558Srgrimes done(1); 11491558Srgrimes } 11501558Srgrimes (void) strcat(lnkbuf, buf); 11511558Srgrimes} 11521558Srgrimes 11531558Srgrimes/* 11541558Srgrimes * Skip over a hole in a symbolic link (should never happen). 11551558Srgrimes */ 11561558Srgrimes/* ARGSUSED */ 11571558Srgrimesstatic void 1158298901Spfgxtrlnkskip(char *buf, size_t size) 11591558Srgrimes{ 11601558Srgrimes 11611558Srgrimes fprintf(stderr, "unallocated block in symbolic link %s\n", 11621558Srgrimes curfile.name); 11631558Srgrimes done(1); 11641558Srgrimes} 11651558Srgrimes 11661558Srgrimes/* 11671558Srgrimes * Collect the next block of a bit map. 11681558Srgrimes */ 11691558Srgrimesstatic void 1170298901Spfgxtrmap(char *buf, size_t size) 11711558Srgrimes{ 11721558Srgrimes 117323685Speter memmove(map, buf, size); 11741558Srgrimes map += size; 11751558Srgrimes} 11761558Srgrimes 11771558Srgrimes/* 11781558Srgrimes * Skip over a hole in a bit map (should never happen). 11791558Srgrimes */ 11801558Srgrimes/* ARGSUSED */ 11811558Srgrimesstatic void 1182298901Spfgxtrmapskip(char *buf, size_t size) 11831558Srgrimes{ 11841558Srgrimes 11851558Srgrimes panic("hole in map\n"); 11861558Srgrimes map += size; 11871558Srgrimes} 11881558Srgrimes 11891558Srgrimes/* 11901558Srgrimes * Noop, when an extraction function is not needed. 11911558Srgrimes */ 11921558Srgrimes/* ARGSUSED */ 11931558Srgrimesvoid 1194298901Spfgxtrnull(char *buf, size_t size) 11951558Srgrimes{ 11961558Srgrimes 11971558Srgrimes return; 11981558Srgrimes} 11991558Srgrimes 12001558Srgrimes/* 12011558Srgrimes * Read TP_BSIZE blocks from the input. 12021558Srgrimes * Handle read errors, and end of media. 12031558Srgrimes */ 12041558Srgrimesstatic void 120592837Simpreadtape(char *buf) 12061558Srgrimes{ 1207164911Sdwmalone long rd, newvol, i, oldnumtrec; 12081558Srgrimes int cnt, seek_failed; 12091558Srgrimes 1210164911Sdwmalone if (blkcnt + (byteslide > 0) < numtrec) { 1211164911Sdwmalone memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE); 12121558Srgrimes blksread++; 121390827Siedowse tapeaddr++; 12141558Srgrimes return; 12151558Srgrimes } 1216164911Sdwmalone if (numtrec > 0) 1217164911Sdwmalone memmove(&tapebuf[-TP_BSIZE], 1218164911Sdwmalone &tapebuf[(numtrec-1) * TP_BSIZE], (long)TP_BSIZE); 1219164911Sdwmalone oldnumtrec = numtrec; 12201558Srgrimes for (i = 0; i < ntrec; i++) 12211558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 12221558Srgrimes if (numtrec == 0) 12231558Srgrimes numtrec = ntrec; 12241558Srgrimes cnt = ntrec * TP_BSIZE; 12251558Srgrimes rd = 0; 12261558Srgrimesgetmore: 12271558Srgrimes#ifdef RRESTORE 12281558Srgrimes if (host) 12291558Srgrimes i = rmtread(&tapebuf[rd], cnt); 12301558Srgrimes else 12311558Srgrimes#endif 12321558Srgrimes i = read(mt, &tapebuf[rd], cnt); 12331558Srgrimes /* 12341558Srgrimes * Check for mid-tape short read error. 12351558Srgrimes * If found, skip rest of buffer and start with the next. 12361558Srgrimes */ 1237203157Sjh if (!pipein && !pipecmdin && numtrec < ntrec && i > 0) { 12381558Srgrimes dprintf(stdout, "mid-media short read error.\n"); 12391558Srgrimes numtrec = ntrec; 12401558Srgrimes } 12411558Srgrimes /* 12421558Srgrimes * Handle partial block read. 12431558Srgrimes */ 1244203157Sjh if ((pipein || pipecmdin) && i == 0 && rd > 0) 12451558Srgrimes i = rd; 12461558Srgrimes else if (i > 0 && i != ntrec * TP_BSIZE) { 1247203157Sjh if (pipein || pipecmdin) { 12481558Srgrimes rd += i; 12491558Srgrimes cnt -= i; 12501558Srgrimes if (cnt > 0) 12511558Srgrimes goto getmore; 12521558Srgrimes i = rd; 12531558Srgrimes } else { 12541558Srgrimes /* 12551558Srgrimes * Short read. Process the blocks read. 12561558Srgrimes */ 12571558Srgrimes if (i % TP_BSIZE != 0) 12581558Srgrimes vprintf(stdout, 125937240Sbde "partial block read: %ld should be %ld\n", 12601558Srgrimes i, ntrec * TP_BSIZE); 12611558Srgrimes numtrec = i / TP_BSIZE; 12621558Srgrimes } 12631558Srgrimes } 12641558Srgrimes /* 12651558Srgrimes * Handle read error. 12661558Srgrimes */ 12671558Srgrimes if (i < 0) { 12681558Srgrimes fprintf(stderr, "Tape read error while "); 12691558Srgrimes switch (curfile.action) { 12701558Srgrimes default: 12711558Srgrimes fprintf(stderr, "trying to set up tape\n"); 12721558Srgrimes break; 12731558Srgrimes case UNKNOWN: 12741558Srgrimes fprintf(stderr, "trying to resynchronize\n"); 12751558Srgrimes break; 12761558Srgrimes case USING: 12771558Srgrimes fprintf(stderr, "restoring %s\n", curfile.name); 12781558Srgrimes break; 12791558Srgrimes case SKIP: 1280241013Smdf fprintf(stderr, "skipping over inode %ju\n", 1281241013Smdf (uintmax_t)curfile.ino); 12821558Srgrimes break; 12831558Srgrimes } 12841558Srgrimes if (!yflag && !reply("continue")) 12851558Srgrimes done(1); 12861558Srgrimes i = ntrec * TP_BSIZE; 128723685Speter memset(tapebuf, 0, i); 12881558Srgrimes#ifdef RRESTORE 12891558Srgrimes if (host) 12901558Srgrimes seek_failed = (rmtseek(i, 1) < 0); 12911558Srgrimes else 12921558Srgrimes#endif 12931558Srgrimes seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 12941558Srgrimes 12951558Srgrimes if (seek_failed) { 12961558Srgrimes fprintf(stderr, 12971558Srgrimes "continuation failed: %s\n", strerror(errno)); 12981558Srgrimes done(1); 12991558Srgrimes } 13001558Srgrimes } 13011558Srgrimes /* 13021558Srgrimes * Handle end of tape. 13031558Srgrimes */ 13041558Srgrimes if (i == 0) { 13051558Srgrimes vprintf(stdout, "End-of-tape encountered\n"); 13061558Srgrimes if (!pipein) { 13071558Srgrimes newvol = volno + 1; 13081558Srgrimes volno = 0; 13091558Srgrimes numtrec = 0; 13101558Srgrimes getvol(newvol); 13111558Srgrimes readtape(buf); 13121558Srgrimes return; 13131558Srgrimes } 13141558Srgrimes if (rd % TP_BSIZE != 0) 1315203155Sjh panic("partial block read: %ld should be %ld\n", 13161558Srgrimes rd, ntrec * TP_BSIZE); 13171558Srgrimes terminateinput(); 131823685Speter memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 13191558Srgrimes } 1320164911Sdwmalone if (oldnumtrec == 0) 1321164911Sdwmalone blkcnt = 0; 1322164911Sdwmalone else 1323164911Sdwmalone blkcnt -= oldnumtrec; 1324164911Sdwmalone memmove(buf, 1325164911Sdwmalone &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE); 13261558Srgrimes blksread++; 132790827Siedowse tapeaddr++; 13281558Srgrimes} 13291558Srgrimes 13301558Srgrimesstatic void 133192837Simpfindtapeblksize(void) 13321558Srgrimes{ 133392806Sobrien long i; 13341558Srgrimes 13351558Srgrimes for (i = 0; i < ntrec; i++) 13361558Srgrimes ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 13371558Srgrimes blkcnt = 0; 13381558Srgrimes#ifdef RRESTORE 13391558Srgrimes if (host) 13401558Srgrimes i = rmtread(tapebuf, ntrec * TP_BSIZE); 13411558Srgrimes else 13421558Srgrimes#endif 13431558Srgrimes i = read(mt, tapebuf, ntrec * TP_BSIZE); 13441558Srgrimes 13451558Srgrimes if (i <= 0) { 13461558Srgrimes fprintf(stderr, "tape read error: %s\n", strerror(errno)); 13471558Srgrimes done(1); 13481558Srgrimes } 13491558Srgrimes if (i % TP_BSIZE != 0) { 135037240Sbde fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 13511558Srgrimes i, "is not a multiple of dump block size", TP_BSIZE); 13521558Srgrimes done(1); 13531558Srgrimes } 13541558Srgrimes ntrec = i / TP_BSIZE; 13551558Srgrimes numtrec = ntrec; 135637240Sbde vprintf(stdout, "Tape block size is %ld\n", ntrec); 13571558Srgrimes} 13581558Srgrimes 13591558Srgrimesvoid 136092837Simpclosemt(void) 13611558Srgrimes{ 13621558Srgrimes 13631558Srgrimes if (mt < 0) 13641558Srgrimes return; 1365128175Sgreen if (pipecmdin) { 1366128175Sgreen pclose(popenfp); 1367128175Sgreen popenfp = NULL; 1368128175Sgreen } else 13691558Srgrimes#ifdef RRESTORE 13701558Srgrimes if (host) 13711558Srgrimes rmtclose(); 13721558Srgrimes else 13731558Srgrimes#endif 13741558Srgrimes (void) close(mt); 13751558Srgrimes} 13761558Srgrimes 13771558Srgrimes/* 13781558Srgrimes * Read the next block from the tape. 13791558Srgrimes * If it is not any valid header, return an error. 13801558Srgrimes */ 13811558Srgrimesstatic int 138292837Simpgethead(struct s_spcl *buf) 13831558Srgrimes{ 13841558Srgrimes long i; 13851558Srgrimes 138698542Smckusick readtape((char *)buf); 138798542Smckusick if (buf->c_magic != FS_UFS2_MAGIC && buf->c_magic != NFS_MAGIC) { 138898542Smckusick if (buf->c_magic == OFS_MAGIC) { 138998542Smckusick fprintf(stderr, 139098542Smckusick "Format of dump tape is too old. Must use\n"); 139198542Smckusick fprintf(stderr, 139298542Smckusick "a version of restore from before 2002.\n"); 139398542Smckusick return (FAIL); 139498542Smckusick } 139598542Smckusick if (swabl(buf->c_magic) != FS_UFS2_MAGIC && 139698542Smckusick buf->c_magic != NFS_MAGIC) { 139798542Smckusick if (buf->c_magic == OFS_MAGIC) { 139898542Smckusick fprintf(stderr, 139998542Smckusick "Format of dump tape is too old. Must use\n"); 140098542Smckusick fprintf(stderr, 140198542Smckusick "a version of restore from before 2002.\n"); 14021558Srgrimes } 14031558Srgrimes return (FAIL); 140423096Simp } 140598542Smckusick if (!Bcvt) { 140698542Smckusick vprintf(stdout, "Note: Doing Byte swapping\n"); 140798542Smckusick Bcvt = 1; 14081558Srgrimes } 14091558Srgrimes } 141098542Smckusick if (checksum((int *)buf) == FAIL) 141198542Smckusick return (FAIL); 141298542Smckusick if (Bcvt) { 141398542Smckusick swabst((u_char *)"8l4s1q8l2q17l", (u_char *)buf); 141498542Smckusick swabst((u_char *)"l",(u_char *) &buf->c_level); 141598542Smckusick swabst((u_char *)"2l4q",(u_char *) &buf->c_flags); 14161558Srgrimes } 141737923Simp readmapflag = 0; 14181558Srgrimes 14191558Srgrimes switch (buf->c_type) { 14201558Srgrimes 14211558Srgrimes case TS_CLRI: 14221558Srgrimes case TS_BITS: 14231558Srgrimes /* 14241558Srgrimes * Have to patch up missing information in bit map headers 14251558Srgrimes */ 142698542Smckusick buf->c_size = buf->c_count * TP_BSIZE; 142737923Simp if (buf->c_count > TP_NINDIR) 142837923Simp readmapflag = 1; 142937923Simp else 143037923Simp for (i = 0; i < buf->c_count; i++) 143137923Simp buf->c_addr[i]++; 1432179218Smckusick /* FALL THROUGH */ 14331558Srgrimes 14341558Srgrimes case TS_TAPE: 1435179218Smckusick if (buf->c_magic == NFS_MAGIC && 1436179218Smckusick (buf->c_flags & NFS_DR_NEWINODEFMT) == 0) 1437179218Smckusick oldinofmt = 1; 1438179218Smckusick /* FALL THROUGH */ 1439179218Smckusick 14401558Srgrimes case TS_END: 14411558Srgrimes buf->c_inumber = 0; 1442179218Smckusick /* FALL THROUGH */ 14431558Srgrimes 1444179218Smckusick case TS_ADDR: 14451558Srgrimes case TS_INODE: 144698542Smckusick /* 144798542Smckusick * For old dump tapes, have to copy up old fields to 144898542Smckusick * new locations. 144998542Smckusick */ 145098542Smckusick if (buf->c_magic == NFS_MAGIC) { 145198542Smckusick buf->c_tapea = buf->c_old_tapea; 145298542Smckusick buf->c_firstrec = buf->c_old_firstrec; 145398542Smckusick buf->c_date = _time32_to_time(buf->c_old_date); 145498542Smckusick buf->c_ddate = _time32_to_time(buf->c_old_ddate); 145598542Smckusick buf->c_atime = _time32_to_time(buf->c_old_atime); 145698542Smckusick buf->c_mtime = _time32_to_time(buf->c_old_mtime); 1457179219Smckusick buf->c_birthtime = 0; 1458179219Smckusick buf->c_birthtimensec = 0; 1459179219Smckusick buf->c_extsize = 0; 146098542Smckusick } 146198542Smckusick break; 146298542Smckusick 14631558Srgrimes default: 14641558Srgrimes panic("gethead: unknown inode type %d\n", buf->c_type); 14651558Srgrimes break; 14661558Srgrimes } 1467179218Smckusick if (dumpdate != 0 && _time64_to_time(buf->c_date) != dumpdate) 1468179218Smckusick fprintf(stderr, "Header with wrong dumpdate.\n"); 1469144099Simp /* 1470144099Simp * If we're restoring a filesystem with the old (FreeBSD 1) 1471144099Simp * format inodes, copy the uid/gid to the new location 1472144099Simp */ 1473144099Simp if (oldinofmt) { 1474144099Simp buf->c_uid = buf->c_spare1[1]; 1475144099Simp buf->c_gid = buf->c_spare1[2]; 1476144099Simp } 147798542Smckusick buf->c_magic = FS_UFS2_MAGIC; 147890827Siedowse tapeaddr = buf->c_tapea; 14791558Srgrimes if (dflag) 14801558Srgrimes accthdr(buf); 14811558Srgrimes return(GOOD); 14821558Srgrimes} 14831558Srgrimes 14841558Srgrimes/* 14851558Srgrimes * Check that a header is where it belongs and predict the next header 14861558Srgrimes */ 14871558Srgrimesstatic void 148892837Simpaccthdr(struct s_spcl *header) 14891558Srgrimes{ 14901558Srgrimes static ino_t previno = 0x7fffffff; 14911558Srgrimes static int prevtype; 14921558Srgrimes static long predict; 14931558Srgrimes long blks, i; 14941558Srgrimes 14951558Srgrimes if (header->c_type == TS_TAPE) { 149698542Smckusick fprintf(stderr, "Volume header "); 14971558Srgrimes if (header->c_firstrec) 1498203155Sjh fprintf(stderr, "begins with record %jd", 1499203155Sjh (intmax_t)header->c_firstrec); 15001558Srgrimes fprintf(stderr, "\n"); 15011558Srgrimes previno = 0x7fffffff; 15021558Srgrimes return; 15031558Srgrimes } 15041558Srgrimes if (previno == 0x7fffffff) 15051558Srgrimes goto newcalc; 15061558Srgrimes switch (prevtype) { 15071558Srgrimes case TS_BITS: 150823685Speter fprintf(stderr, "Dumped inodes map header"); 15091558Srgrimes break; 15101558Srgrimes case TS_CLRI: 151123685Speter fprintf(stderr, "Used inodes map header"); 15121558Srgrimes break; 15131558Srgrimes case TS_INODE: 1514241013Smdf fprintf(stderr, "File header, ino %ju", (uintmax_t)previno); 15151558Srgrimes break; 15161558Srgrimes case TS_ADDR: 1517241013Smdf fprintf(stderr, "File continuation header, ino %ju", 1518241013Smdf (uintmax_t)previno); 15191558Srgrimes break; 15201558Srgrimes case TS_END: 15211558Srgrimes fprintf(stderr, "End of tape header"); 15221558Srgrimes break; 15231558Srgrimes } 15241558Srgrimes if (predict != blksread - 1) 152537240Sbde fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 15261558Srgrimes predict, blksread - 1); 15271558Srgrimes fprintf(stderr, "\n"); 15281558Srgrimesnewcalc: 15291558Srgrimes blks = 0; 15301558Srgrimes if (header->c_type != TS_END) 15311558Srgrimes for (i = 0; i < header->c_count; i++) 153237923Simp if (readmapflag || header->c_addr[i] != 0) 15331558Srgrimes blks++; 15341558Srgrimes predict = blks; 15351558Srgrimes blksread = 0; 15361558Srgrimes prevtype = header->c_type; 15371558Srgrimes previno = header->c_inumber; 15381558Srgrimes} 15391558Srgrimes 15401558Srgrimes/* 15411558Srgrimes * Find an inode header. 154290573Siedowse * Complain if had to skip. 15431558Srgrimes */ 15441558Srgrimesstatic void 154592837Simpfindinode(struct s_spcl *header) 15461558Srgrimes{ 15471558Srgrimes static long skipcnt = 0; 15481558Srgrimes long i; 15491558Srgrimes char buf[TP_BSIZE]; 155090608Siedowse int htype; 15511558Srgrimes 15521558Srgrimes curfile.name = "<name unknown>"; 15531558Srgrimes curfile.action = UNKNOWN; 155498542Smckusick curfile.mode = 0; 15551558Srgrimes curfile.ino = 0; 15561558Srgrimes do { 155790608Siedowse htype = header->c_type; 155890608Siedowse switch (htype) { 15591558Srgrimes 15601558Srgrimes case TS_ADDR: 15611558Srgrimes /* 15621558Srgrimes * Skip up to the beginning of the next record 15631558Srgrimes */ 15641558Srgrimes for (i = 0; i < header->c_count; i++) 15651558Srgrimes if (header->c_addr[i]) 15661558Srgrimes readtape(buf); 15671558Srgrimes while (gethead(header) == FAIL || 1568164911Sdwmalone _time64_to_time(header->c_date) != dumpdate) { 15691558Srgrimes skipcnt++; 1570164911Sdwmalone if (Dflag) { 1571164911Sdwmalone byteslide++; 1572164911Sdwmalone if (byteslide < TP_BSIZE) { 1573164911Sdwmalone blkcnt--; 1574164911Sdwmalone blksread--; 1575164911Sdwmalone } else 1576164911Sdwmalone byteslide = 0; 1577164911Sdwmalone } 1578164911Sdwmalone } 15791558Srgrimes break; 15801558Srgrimes 15811558Srgrimes case TS_INODE: 158298542Smckusick curfile.mode = header->c_mode; 158398542Smckusick curfile.uid = header->c_uid; 158498542Smckusick curfile.gid = header->c_gid; 158598542Smckusick curfile.file_flags = header->c_file_flags; 158698542Smckusick curfile.rdev = header->c_rdev; 158798542Smckusick curfile.atime_sec = header->c_atime; 158898542Smckusick curfile.atime_nsec = header->c_atimensec; 158998542Smckusick curfile.mtime_sec = header->c_mtime; 159098542Smckusick curfile.mtime_nsec = header->c_mtimensec; 1591100207Smckusick curfile.birthtime_sec = header->c_birthtime; 1592100207Smckusick curfile.birthtime_nsec = header->c_birthtimensec; 1593167011Smckusick curfile.extsize = header->c_extsize; 159498542Smckusick curfile.size = header->c_size; 15951558Srgrimes curfile.ino = header->c_inumber; 15961558Srgrimes break; 15971558Srgrimes 15981558Srgrimes case TS_END: 159990820Siedowse /* If we missed some tapes, get another volume. */ 160090820Siedowse if (tapesread & (tapesread + 1)) { 160190820Siedowse getvol(0); 160290820Siedowse continue; 160390820Siedowse } 16041558Srgrimes curfile.ino = maxino; 16051558Srgrimes break; 16061558Srgrimes 16071558Srgrimes case TS_CLRI: 16081558Srgrimes curfile.name = "<file removal list>"; 16091558Srgrimes break; 16101558Srgrimes 16111558Srgrimes case TS_BITS: 16121558Srgrimes curfile.name = "<file dump list>"; 16131558Srgrimes break; 16141558Srgrimes 16151558Srgrimes case TS_TAPE: 1616164911Sdwmalone if (Dflag) 1617164911Sdwmalone fprintf(stderr, "unexpected tape header\n"); 1618164911Sdwmalone else 1619164911Sdwmalone panic("unexpected tape header\n"); 16201558Srgrimes 16211558Srgrimes default: 1622164911Sdwmalone if (Dflag) 1623164911Sdwmalone fprintf(stderr, "unknown tape header type %d\n", 1624164911Sdwmalone spcl.c_type); 1625164911Sdwmalone else 1626164911Sdwmalone panic("unknown tape header type %d\n", 1627164911Sdwmalone spcl.c_type); 1628164911Sdwmalone while (gethead(header) == FAIL || 1629164911Sdwmalone _time64_to_time(header->c_date) != dumpdate) { 1630164911Sdwmalone skipcnt++; 1631164911Sdwmalone if (Dflag) { 1632164911Sdwmalone byteslide++; 1633164911Sdwmalone if (byteslide < TP_BSIZE) { 1634164911Sdwmalone blkcnt--; 1635164911Sdwmalone blksread--; 1636164911Sdwmalone } else 1637164911Sdwmalone byteslide = 0; 1638164911Sdwmalone } 1639164911Sdwmalone } 16401558Srgrimes 16411558Srgrimes } 164290608Siedowse } while (htype == TS_ADDR); 16431558Srgrimes if (skipcnt > 0) 1644164911Sdwmalone fprintf(stderr, "resync restore, skipped %ld %s\n", 1645164911Sdwmalone skipcnt, Dflag ? "bytes" : "blocks"); 16461558Srgrimes skipcnt = 0; 16471558Srgrimes} 16481558Srgrimes 16491558Srgrimesstatic int 165092837Simpchecksum(int *buf) 16511558Srgrimes{ 165292806Sobrien int i, j; 16531558Srgrimes 16541558Srgrimes j = sizeof(union u_spcl) / sizeof(int); 16551558Srgrimes i = 0; 165698542Smckusick if (!Bcvt) { 16571558Srgrimes do 16581558Srgrimes i += *buf++; 16591558Srgrimes while (--j); 16601558Srgrimes } else { 16611558Srgrimes /* What happens if we want to read restore tapes 16621558Srgrimes for a 16bit int machine??? */ 16638871Srgrimes do 16641558Srgrimes i += swabl(*buf++); 16651558Srgrimes while (--j); 16661558Srgrimes } 16678871Srgrimes 16681558Srgrimes if (i != CHECKSUM) { 1669241013Smdf fprintf(stderr, "Checksum error %o, inode %ju file %s\n", i, 1670241013Smdf (uintmax_t)curfile.ino, curfile.name); 16711558Srgrimes return(FAIL); 16721558Srgrimes } 16731558Srgrimes return(GOOD); 16741558Srgrimes} 16751558Srgrimes 16761558Srgrimes#ifdef RRESTORE 16771558Srgrimes#include <stdarg.h> 16781558Srgrimes 16791558Srgrimesvoid 16801558Srgrimesmsg(const char *fmt, ...) 16811558Srgrimes{ 16821558Srgrimes va_list ap; 16831558Srgrimes va_start(ap, fmt); 16841558Srgrimes (void)vfprintf(stderr, fmt, ap); 16851558Srgrimes va_end(ap); 16861558Srgrimes} 16871558Srgrimes#endif /* RRESTORE */ 16881558Srgrimes 16891558Srgrimesstatic u_char * 169092837Simpswabshort(u_char *sp, int n) 16911558Srgrimes{ 16921558Srgrimes char c; 16931558Srgrimes 16941558Srgrimes while (--n >= 0) { 16951558Srgrimes c = sp[0]; sp[0] = sp[1]; sp[1] = c; 16961558Srgrimes sp += 2; 16971558Srgrimes } 16981558Srgrimes return (sp); 16991558Srgrimes} 17001558Srgrimes 17011558Srgrimesstatic u_char * 170292837Simpswablong(u_char *sp, int n) 17031558Srgrimes{ 17041558Srgrimes char c; 17051558Srgrimes 17061558Srgrimes while (--n >= 0) { 17071558Srgrimes c = sp[0]; sp[0] = sp[3]; sp[3] = c; 17081558Srgrimes c = sp[2]; sp[2] = sp[1]; sp[1] = c; 17091558Srgrimes sp += 4; 17101558Srgrimes } 17111558Srgrimes return (sp); 17121558Srgrimes} 17131558Srgrimes 171498542Smckusickstatic u_char * 171598542Smckusickswabquad(u_char *sp, int n) 171698542Smckusick{ 171798542Smckusick char c; 171898542Smckusick 171998542Smckusick while (--n >= 0) { 172098542Smckusick c = sp[0]; sp[0] = sp[7]; sp[7] = c; 172198542Smckusick c = sp[1]; sp[1] = sp[6]; sp[6] = c; 172298542Smckusick c = sp[2]; sp[2] = sp[5]; sp[5] = c; 172398542Smckusick c = sp[3]; sp[3] = sp[4]; sp[4] = c; 172498542Smckusick sp += 8; 172598542Smckusick } 172698542Smckusick return (sp); 172798542Smckusick} 172898542Smckusick 17291558Srgrimesvoid 173092837Simpswabst(u_char *cp, u_char *sp) 17311558Srgrimes{ 17321558Srgrimes int n = 0; 17331558Srgrimes 17341558Srgrimes while (*cp) { 17351558Srgrimes switch (*cp) { 17361558Srgrimes case '0': case '1': case '2': case '3': case '4': 17371558Srgrimes case '5': case '6': case '7': case '8': case '9': 17381558Srgrimes n = (n * 10) + (*cp++ - '0'); 17391558Srgrimes continue; 17408871Srgrimes 17411558Srgrimes case 's': case 'w': case 'h': 17421558Srgrimes if (n == 0) 17431558Srgrimes n = 1; 17441558Srgrimes sp = swabshort(sp, n); 17451558Srgrimes break; 17461558Srgrimes 17471558Srgrimes case 'l': 17481558Srgrimes if (n == 0) 17491558Srgrimes n = 1; 17501558Srgrimes sp = swablong(sp, n); 17511558Srgrimes break; 17521558Srgrimes 175398542Smckusick case 'q': 17541558Srgrimes if (n == 0) 17551558Srgrimes n = 1; 175698542Smckusick sp = swabquad(sp, n); 175798542Smckusick break; 175898542Smckusick 175998542Smckusick case 'b': 176098542Smckusick if (n == 0) 176198542Smckusick n = 1; 17621558Srgrimes sp += n; 17631558Srgrimes break; 176498542Smckusick 176598542Smckusick default: 176698542Smckusick fprintf(stderr, "Unknown conversion character: %c\n", 176798542Smckusick *cp); 176898542Smckusick done(0); 176998542Smckusick break; 17701558Srgrimes } 17711558Srgrimes cp++; 17721558Srgrimes n = 0; 17731558Srgrimes } 17741558Srgrimes} 17751558Srgrimes 17761558Srgrimesstatic u_long 177792837Simpswabl(u_long x) 17781558Srgrimes{ 17791558Srgrimes swabst((u_char *)"l", (u_char *)&x); 17801558Srgrimes return (x); 17811558Srgrimes} 1782