tape.c revision 37906
1132718Skan/* 2132718Skan * Copyright (c) 1983, 1993 3132718Skan * The Regents of the University of California. All rights reserved. 4132718Skan * (c) UNIX System Laboratories, Inc. 5169689Skan * All or some portions of this file are derived from material licensed 6132718Skan * to the University of California by American Telephone and Telegraph 7132718Skan * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8132718Skan * the permission of UNIX System Laboratories, Inc. 9132718Skan * 10132718Skan * Redistribution and use in source and binary forms, with or without 11132718Skan * modification, are permitted provided that the following conditions 12132718Skan * are met: 13132718Skan * 1. Redistributions of source code must retain the above copyright 14132718Skan * notice, this list of conditions and the following disclaimer. 15132718Skan * 2. Redistributions in binary form must reproduce the above copyright 16132718Skan * notice, this list of conditions and the following disclaimer in the 17132718Skan * documentation and/or other materials provided with the distribution. 18132718Skan * 3. All advertising materials mentioning features or use of this software 19132718Skan * must display the following acknowledgement: 20132718Skan * This product includes software developed by the University of 21169689Skan * California, Berkeley and its contributors. 22169689Skan * 4. Neither the name of the University nor the names of its contributors 23132718Skan * may be used to endorse or promote products derived from this software 24132718Skan * without specific prior written permission. 25132718Skan * 26132718Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29132718Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32132718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33132718Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34132718Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35132718Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36132718Skan * SUCH DAMAGE. 37169689Skan */ 38132718Skan 39132718Skan#ifndef lint 40132718Skan#if 0 41132718Skanstatic char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; 42132718Skan#endif 43169689Skanstatic const char rcsid[] = 44132718Skan "$Id$"; 45132718Skan#endif /* not lint */ 46132718Skan 47132718Skan#include <sys/param.h> 48261188Spfg#include <sys/file.h> 49261188Spfg#include <sys/mtio.h> 50261188Spfg#include <sys/stat.h> 51261188Spfg 52261188Spfg#include <ufs/ufs/dinode.h> 53261188Spfg#include <protocols/dumprestore.h> 54261188Spfg 55132718Skan#include <errno.h> 56169689Skan#include <setjmp.h> 57132718Skan#include <stdio.h> 58169689Skan#include <stdlib.h> 59169689Skan#include <string.h> 60132718Skan#include <unistd.h> 61132718Skan 62132718Skan#include "restore.h" 63169689Skan#include "extern.h" 64132718Skan#include "pathnames.h" 65132718Skan 66261188Spfgstatic long fssize = MAXBSIZE; 67261188Spfgstatic int mt = -1; 68261188Spfgstatic int pipein = 0; 69261188Spfgstatic char *magtape; 70261188Spfgstatic int blkcnt; 71261188Spfgstatic int numtrec; 72261188Spfgstatic char *tapebuf; 73261188Spfgstatic union u_spcl endoftapemark; 74261188Spfgstatic long blksread; /* blocks read since last header */ 75261188Spfgstatic long tpblksread = 0; /* TP_BSIZE blocks read */ 76261188Spfgstatic long tapesread; 77261188Spfgstatic jmp_buf restart; 78261188Spfgstatic int gettingfile = 0; /* restart has a valid frame */ 79261188Spfgstatic char *host = NULL; 80261188Spfg 81261188Spfgstatic int ofile; 82261188Spfgstatic char *map; 83261188Spfgstatic char lnkbuf[MAXPATHLEN + 1]; 84261188Spfgstatic int pathlen; 85261188Spfg 86261188Spfgint oldinofmt; /* old inode format conversion required */ 87261188Spfgint Bcvt; /* Swap Bytes (for CCI or sun) */ 88132718Skanstatic int Qcvt; /* Swap quads (for sun) */ 89132718Skan 90169689Skan#define FLUSHTAPEBUF() blkcnt = ntrec + 1 91169689Skan 92169689Skanstatic void accthdr __P((struct s_spcl *)); 93132718Skanstatic int checksum __P((int *)); 94132718Skanstatic void findinode __P((struct s_spcl *)); 95261188Spfgstatic void findtapeblksize __P((void)); 96261188Spfgstatic int gethead __P((struct s_spcl *)); 97261188Spfgstatic void readtape __P((char *)); 98261188Spfgstatic void setdumpnum __P((void)); 99261188Spfgstatic u_long swabl __P((u_long)); 100261188Spfgstatic u_char *swablong __P((u_char *, int)); 101261188Spfgstatic u_char *swabshort __P((u_char *, int)); 102261188Spfgstatic void terminateinput __P((void)); 103169689Skanstatic void xtrfile __P((char *, long)); 104169689Skanstatic void xtrlnkfile __P((char *, long)); 105261188Spfgstatic void xtrlnkskip __P((char *, long)); 106261188Spfgstatic void xtrmap __P((char *, long)); 107261188Spfgstatic void xtrmapskip __P((char *, long)); 108261188Spfgstatic void xtrskip __P((char *, long)); 109169689Skan 110169689Skan/* 111169689Skan * Set up an input source 112169689Skan */ 113261188Spfgvoid 114261188Spfgsetinput(source) 115261188Spfg char *source; 116261188Spfg{ 117261188Spfg FLUSHTAPEBUF(); 118261188Spfg if (bflag) 119261188Spfg newtapebuf(ntrec); 120261188Spfg else 121261188Spfg newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 122261188Spfg terminal = stdin; 123169689Skan 124169689Skan#ifdef RRESTORE 125169689Skan if (strchr(source, ':')) { 126169689Skan host = source; 127169689Skan source = strchr(host, ':'); 128169689Skan *source++ = '\0'; 129169689Skan if (rmthost(host) == 0) 130169689Skan done(1); 131169689Skan } else 132169689Skan#endif 133169689Skan if (strcmp(source, "-") == 0) { 134132718Skan /* 135169689Skan * Since input is coming from a pipe we must establish 136169689Skan * our own connection to the terminal. 137169689Skan */ 138169689Skan terminal = fopen(_PATH_TTY, "r"); 139169689Skan if (terminal == NULL) { 140169689Skan (void)fprintf(stderr, "cannot open %s: %s\n", 141132718Skan _PATH_TTY, strerror(errno)); 142132718Skan terminal = fopen(_PATH_DEVNULL, "r"); 143132718Skan if (terminal == NULL) { 144132718Skan (void)fprintf(stderr, "cannot open %s: %s\n", 145132718Skan _PATH_DEVNULL, strerror(errno)); 146169689Skan done(1); 147169689Skan } 148169689Skan } 149169689Skan pipein++; 150169689Skan } 151169689Skan setuid(getuid()); /* no longer need or want root privileges */ 152169689Skan magtape = strdup(source); 153169689Skan if (magtape == NULL) { 154169689Skan fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 155169689Skan done(1); 156169689Skan } 157261188Spfg} 158261188Spfg 159169689Skanvoid 160169689Skannewtapebuf(size) 161169689Skan long size; 162169689Skan{ 163169689Skan static tapebufsize = -1; 164261188Spfg 165261188Spfg ntrec = size; 166169689Skan if (size <= tapebufsize) 167169689Skan return; 168261188Spfg if (tapebuf != NULL) 169169689Skan free(tapebuf); 170169689Skan tapebuf = malloc(size * TP_BSIZE); 171169689Skan if (tapebuf == NULL) { 172169689Skan fprintf(stderr, "Cannot allocate space for tape buffer\n"); 173261188Spfg done(1); 174261188Spfg } 175261188Spfg tapebufsize = size; 176261188Spfg} 177169689Skan 178169689Skan/* 179169689Skan * Verify that the tape drive can be accessed and 180169689Skan * that it actually is a dump tape. 181169689Skan */ 182169689Skanvoid 183169689Skansetup() 184169689Skan{ 185169689Skan int i, j, *ip; 186169689Skan struct stat stbuf; 187169689Skan 188169689Skan vprintf(stdout, "Verify tape and initialize maps\n"); 189169689Skan#ifdef RRESTORE 190169689Skan if (host) 191169689Skan mt = rmtopen(magtape, 0); 192169689Skan else 193169689Skan#endif 194169689Skan if (pipein) 195169689Skan mt = 0; 196169689Skan else 197169689Skan mt = open(magtape, O_RDONLY, 0); 198169689Skan if (mt < 0) { 199169689Skan fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 200169689Skan done(1); 201169689Skan } 202169689Skan volno = 1; 203169689Skan setdumpnum(); 204169689Skan FLUSHTAPEBUF(); 205169689Skan if (!pipein && !bflag) 206169689Skan findtapeblksize(); 207169689Skan if (gethead(&spcl) == FAIL) { 208169689Skan blkcnt--; /* push back this block */ 209169689Skan blksread--; 210169689Skan tpblksread--; 211169689Skan cvtflag++; 212169689Skan if (gethead(&spcl) == FAIL) { 213169689Skan fprintf(stderr, "Tape is not a dump tape\n"); 214169689Skan done(1); 215169689Skan } 216169689Skan fprintf(stderr, "Converting to new file system format.\n"); 217169689Skan } 218169689Skan if (pipein) { 219169689Skan endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; 220169689Skan endoftapemark.s_spcl.c_type = TS_END; 221169689Skan ip = (int *)&endoftapemark; 222169689Skan j = sizeof(union u_spcl) / sizeof(int); 223169689Skan i = 0; 224169689Skan do 225169689Skan i += *ip++; 226169689Skan while (--j); 227169689Skan endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 228169689Skan } 229169689Skan if (vflag || command == 't') 230169689Skan printdumpinfo(); 231169689Skan dumptime = spcl.c_ddate; 232169689Skan dumpdate = spcl.c_date; 233169689Skan if (stat(".", &stbuf) < 0) { 234169689Skan fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 235169689Skan done(1); 236169689Skan } 237169689Skan if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 238169689Skan fssize = TP_BSIZE; 239169689Skan if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 240261188Spfg fssize = stbuf.st_blksize; 241261188Spfg if (((fssize - 1) & fssize) != 0) { 242261188Spfg fprintf(stderr, "bad block size %ld\n", fssize); 243261188Spfg done(1); 244169689Skan } 245169689Skan if (spcl.c_volume != 1) { 246169689Skan fprintf(stderr, "Tape is not volume 1 of the dump\n"); 247169689Skan done(1); 248261188Spfg } 249261188Spfg if (gethead(&spcl) == FAIL) { 250261188Spfg dprintf(stdout, "header read failed at %ld blocks\n", blksread); 251261188Spfg panic("no header after volume mark!\n"); 252169689Skan } 253169689Skan findinode(&spcl); 254169689Skan if (spcl.c_type != TS_CLRI) { 255169689Skan fprintf(stderr, "Cannot find file removal list\n"); 256169689Skan done(1); 257169689Skan } 258169689Skan maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 259169689Skan dprintf(stdout, "maxino = %d\n", maxino); 260169689Skan map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 261169689Skan if (map == NULL) 262169689Skan panic("no memory for active inode map\n"); 263261188Spfg usedinomap = map; 264261188Spfg curfile.action = USING; 265261188Spfg getfile(xtrmap, xtrmapskip); 266261188Spfg if (spcl.c_type != TS_BITS) { 267169689Skan fprintf(stderr, "Cannot find file dump list\n"); 268169689Skan done(1); 269169689Skan } 270169689Skan map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 271169689Skan if (map == (char *)NULL) 272169689Skan panic("no memory for file dump list\n"); 273169689Skan dumpmap = map; 274169689Skan curfile.action = USING; 275169689Skan getfile(xtrmap, xtrmapskip); 276169689Skan /* 277169689Skan * If there may be whiteout entries on the tape, pretend that the 278169689Skan * whiteout inode exists, so that the whiteout entries can be 279169689Skan * extracted. 280169689Skan */ 281169689Skan if (oldinofmt == 0) 282169689Skan SETINO(WINO, dumpmap); 283169689Skan} 284169689Skan 285169689Skan/* 286169689Skan * Prompt user to load a new dump volume. 287169689Skan * "Nextvol" is the next suggested volume to use. 288169689Skan * This suggested volume is enforced when doing full 289169689Skan * or incremental restores, but can be overridden by 290169689Skan * the user when only extracting a subset of the files. 291169689Skan */ 292169689Skanvoid 293169689Skangetvol(nextvol) 294169689Skan long nextvol; 295169689Skan{ 296169689Skan long newvol, savecnt, wantnext, i; 297169689Skan union u_spcl tmpspcl; 298169689Skan# define tmpbuf tmpspcl.s_spcl 299169689Skan char buf[TP_BSIZE]; 300169689Skan 301169689Skan if (nextvol == 1) { 302169689Skan tapesread = 0; 303169689Skan gettingfile = 0; 304169689Skan } 305169689Skan if (pipein) { 306169689Skan if (nextvol != 1) 307169689Skan panic("Changing volumes on pipe input?\n"); 308169689Skan if (volno == 1) 309169689Skan return; 310169689Skan goto gethdr; 311169689Skan } 312169689Skan savecnt = blksread; 313169689Skanagain: 314169689Skan if (pipein) 315169689Skan done(1); /* pipes do not get a second chance */ 316261188Spfg if (command == 'R' || command == 'r' || curfile.action != SKIP) { 317169689Skan newvol = nextvol; 318261188Spfg wantnext = 1; 319261188Spfg } else { 320261188Spfg newvol = 0; 321261188Spfg wantnext = 0; 322261188Spfg } 323261188Spfg while (newvol <= 0) { 324261188Spfg if (tapesread == 0) { 325261188Spfg fprintf(stderr, "%s%s%s%s%s", 326261188Spfg "You have not read any tapes yet.\n", 327261188Spfg "Unless you know which volume your", 328261188Spfg " file(s) are on you should start\n", 329169689Skan "with the last volume and work", 330169689Skan " towards the first.\n"); 331169689Skan } else { 332169689Skan fprintf(stderr, "You have read volumes"); 333169689Skan strcpy(buf, ": "); 334169689Skan for (i = 1; i < 32; i++) 335169689Skan if (tapesread & (1 << i)) { 336169689Skan fprintf(stderr, "%s%ld", buf, i); 337169689Skan strcpy(buf, ", "); 338169689Skan } 339169689Skan fprintf(stderr, "\n"); 340169689Skan } 341169689Skan do { 342169689Skan fprintf(stderr, "Specify next volume #: "); 343169689Skan (void) fflush(stderr); 344169689Skan (void) fgets(buf, BUFSIZ, terminal); 345169689Skan } while (!feof(terminal) && buf[0] == '\n'); 346169689Skan if (feof(terminal)) 347169689Skan done(1); 348169689Skan newvol = atoi(buf); 349169689Skan if (newvol <= 0) { 350169689Skan fprintf(stderr, 351169689Skan "Volume numbers are positive numerics\n"); 352169689Skan } 353261188Spfg } 354261188Spfg if (newvol == volno) { 355261188Spfg tapesread |= 1 << volno; 356261188Spfg return; 357261188Spfg } 358261188Spfg closemt(); 359169689Skan fprintf(stderr, "Mount tape volume %ld\n", newvol); 360261188Spfg fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 361261188Spfg fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 362261188Spfg (void) fflush(stderr); 363261188Spfg (void) fgets(buf, BUFSIZ, terminal); 364261188Spfg if (feof(terminal)) 365261188Spfg done(1); 366261188Spfg if (!strcmp(buf, "none\n")) { 367261188Spfg terminateinput(); 368261188Spfg return; 369261188Spfg } 370261188Spfg if (buf[0] != '\n') { 371261188Spfg (void) strcpy(magtape, buf); 372261188Spfg magtape[strlen(magtape) - 1] = '\0'; 373261188Spfg } 374261188Spfg#ifdef RRESTORE 375261188Spfg if (host) 376261188Spfg mt = rmtopen(magtape, 0); 377261188Spfg else 378261188Spfg#endif 379261188Spfg mt = open(magtape, O_RDONLY, 0); 380261188Spfg 381261188Spfg if (mt == -1) { 382261188Spfg fprintf(stderr, "Cannot open %s\n", magtape); 383261188Spfg volno = -1; 384261188Spfg goto again; 385261188Spfg } 386261188Spfggethdr: 387261188Spfg volno = newvol; 388261188Spfg setdumpnum(); 389261188Spfg FLUSHTAPEBUF(); 390261188Spfg if (gethead(&tmpbuf) == FAIL) { 391261188Spfg dprintf(stdout, "header read failed at %ld blocks\n", blksread); 392261188Spfg fprintf(stderr, "tape is not dump tape\n"); 393261188Spfg volno = 0; 394261188Spfg goto again; 395261188Spfg } 396261188Spfg if (tmpbuf.c_volume != volno) { 397169689Skan fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume); 398169689Skan volno = 0; 399169689Skan goto again; 400169689Skan } 401169689Skan if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { 402169689Skan fprintf(stderr, "Wrong dump date\n\tgot: %s", 403169689Skan ctime(&tmpbuf.c_date)); 404169689Skan fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 405169689Skan volno = 0; 406169689Skan goto again; 407169689Skan } 408169689Skan tapesread |= 1 << volno; 409169689Skan blksread = savecnt; 410169689Skan /* 411169689Skan * If continuing from the previous volume, skip over any 412169689Skan * blocks read already at the end of the previous volume. 413169689Skan * 414169689Skan * If coming to this volume at random, skip to the beginning 415169689Skan * of the next record. 416169689Skan */ 417169689Skan dprintf(stdout, "read %ld recs, tape starts with %ld\n", 418169689Skan tpblksread, tmpbuf.c_firstrec); 419169689Skan if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { 420169689Skan if (!wantnext) { 421169689Skan tpblksread = tmpbuf.c_firstrec; 422169689Skan for (i = tmpbuf.c_count; i > 0; i--) 423169689Skan readtape(buf); 424169689Skan } else if (tmpbuf.c_firstrec > 0 && 425169689Skan tmpbuf.c_firstrec < tpblksread - 1) { 426169689Skan /* 427169689Skan * -1 since we've read the volume header 428169689Skan */ 429169689Skan i = tpblksread - tmpbuf.c_firstrec - 1; 430169689Skan dprintf(stderr, "Skipping %ld duplicate record%s.\n", 431169689Skan i, i > 1 ? "s" : ""); 432169689Skan while (--i >= 0) 433169689Skan readtape(buf); 434169689Skan } 435169689Skan } 436169689Skan if (curfile.action == USING) { 437169689Skan if (volno == 1) 438169689Skan panic("active file into volume 1\n"); 439169689Skan return; 440169689Skan } 441169689Skan /* 442169689Skan * Skip up to the beginning of the next record 443169689Skan */ 444169689Skan if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) 445169689Skan for (i = tmpbuf.c_count; i > 0; i--) 446169689Skan readtape(buf); 447169689Skan (void) gethead(&spcl); 448169689Skan findinode(&spcl); 449261188Spfg if (gettingfile) { 450261188Spfg gettingfile = 0; 451261188Spfg longjmp(restart, 1); 452261188Spfg } 453261188Spfg} 454261188Spfg 455261188Spfg/* 456261188Spfg * Handle unexpected EOF. 457261188Spfg */ 458261188Spfgstatic void 459261188Spfgterminateinput() 460261188Spfg{ 461261188Spfg 462261188Spfg if (gettingfile && curfile.action == USING) { 463261188Spfg printf("Warning: %s %s\n", 464261188Spfg "End-of-input encountered while extracting", curfile.name); 465261188Spfg } 466261188Spfg curfile.name = "<name unknown>"; 467261188Spfg curfile.action = UNKNOWN; 468261188Spfg curfile.dip = NULL; 469261188Spfg curfile.ino = maxino; 470261188Spfg if (gettingfile) { 471261188Spfg gettingfile = 0; 472261188Spfg longjmp(restart, 1); 473261188Spfg } 474261188Spfg} 475261188Spfg 476261188Spfg/* 477261188Spfg * handle multiple dumps per tape by skipping forward to the 478261188Spfg * appropriate one. 479261188Spfg */ 480261188Spfgstatic void 481261188Spfgsetdumpnum() 482261188Spfg{ 483261188Spfg struct mtop tcom; 484261188Spfg 485261188Spfg if (dumpnum == 1 || volno != 1) 486261188Spfg return; 487261188Spfg if (pipein) { 488261188Spfg fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 489261188Spfg done(1); 490261188Spfg } 491261188Spfg tcom.mt_op = MTFSF; 492261188Spfg tcom.mt_count = dumpnum - 1; 493261188Spfg#ifdef RRESTORE 494261188Spfg if (host) 495261188Spfg rmtioctl(MTFSF, dumpnum - 1); 496261188Spfg else 497261188Spfg#endif 498261188Spfg if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) 499261188Spfg fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 500261188Spfg} 501261188Spfg 502261188Spfgvoid 503261188Spfgprintdumpinfo() 504261188Spfg{ 505261188Spfg fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); 506261188Spfg fprintf(stdout, "Dumped from: %s", 507261188Spfg (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate)); 508261188Spfg if (spcl.c_host[0] == '\0') 509261188Spfg return; 510261188Spfg fprintf(stderr, "Level %ld dump of %s on %s:%s\n", 511261188Spfg spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 512261188Spfg fprintf(stderr, "Label: %s\n", spcl.c_label); 513261188Spfg} 514261188Spfg 515261188Spfgint 516261188Spfgextractfile(name) 517261188Spfg char *name; 518261188Spfg{ 519261188Spfg int flags; 520261188Spfg mode_t mode; 521261188Spfg struct timeval timep[2]; 522261188Spfg struct entry *ep; 523261188Spfg 524261188Spfg curfile.name = name; 525261188Spfg curfile.action = USING; 526261188Spfg timep[0].tv_sec = curfile.dip->di_atime; 527261188Spfg timep[0].tv_usec = curfile.dip->di_atimensec / 1000; 528261188Spfg timep[1].tv_sec = curfile.dip->di_mtime; 529261188Spfg timep[1].tv_usec = curfile.dip->di_mtimensec / 1000; 530261188Spfg mode = curfile.dip->di_mode; 531261188Spfg flags = curfile.dip->di_flags; 532261188Spfg switch (mode & IFMT) { 533261188Spfg 534261188Spfg default: 535261188Spfg fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 536261188Spfg skipfile(); 537261188Spfg return (FAIL); 538261188Spfg 539261188Spfg case IFSOCK: 540261188Spfg vprintf(stdout, "skipped socket %s\n", name); 541261188Spfg skipfile(); 542261188Spfg return (GOOD); 543261188Spfg 544261188Spfg case IFDIR: 545261188Spfg if (mflag) { 546261188Spfg ep = lookupname(name); 547261188Spfg if (ep == NULL || ep->e_flags & EXTRACT) 548261188Spfg panic("unextracted directory %s\n", name); 549261188Spfg skipfile(); 550261188Spfg return (GOOD); 551261188Spfg } 552261188Spfg vprintf(stdout, "extract file %s\n", name); 553261188Spfg return (genliteraldir(name, curfile.ino)); 554261188Spfg 555261188Spfg case IFLNK: 556261188Spfg lnkbuf[0] = '\0'; 557261188Spfg pathlen = 0; 558261188Spfg getfile(xtrlnkfile, xtrlnkskip); 559261188Spfg if (pathlen == 0) { 560261188Spfg vprintf(stdout, 561261188Spfg "%s: zero length symbolic link (ignored)\n", name); 562261188Spfg return (GOOD); 563261188Spfg } 564261188Spfg return (linkit(lnkbuf, name, SYMLINK)); 565261188Spfg 566261188Spfg case IFIFO: 567261188Spfg vprintf(stdout, "extract fifo %s\n", name); 568261188Spfg if (Nflag) { 569261188Spfg skipfile(); 570261188Spfg return (GOOD); 571261188Spfg } 572261188Spfg if (uflag && !Nflag) 573261188Spfg (void)unlink(name); 574261188Spfg if (mkfifo(name, mode) < 0) { 575261188Spfg fprintf(stderr, "%s: cannot create fifo: %s\n", 576261188Spfg name, strerror(errno)); 577261188Spfg skipfile(); 578261188Spfg return (FAIL); 579261188Spfg } 580261188Spfg (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 581261188Spfg (void) chmod(name, mode); 582261188Spfg (void) chflags(name, flags); 583261188Spfg skipfile(); 584261188Spfg utimes(name, timep); 585261188Spfg return (GOOD); 586261188Spfg 587261188Spfg case IFCHR: 588261188Spfg case IFBLK: 589 vprintf(stdout, "extract special file %s\n", name); 590 if (Nflag) { 591 skipfile(); 592 return (GOOD); 593 } 594 if (uflag) 595 (void)unlink(name); 596 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { 597 fprintf(stderr, "%s: cannot create special file: %s\n", 598 name, strerror(errno)); 599 skipfile(); 600 return (FAIL); 601 } 602 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 603 (void) chmod(name, mode); 604 (void) chflags(name, flags); 605 skipfile(); 606 utimes(name, timep); 607 return (GOOD); 608 609 case IFREG: 610 vprintf(stdout, "extract file %s\n", name); 611 if (Nflag) { 612 skipfile(); 613 return (GOOD); 614 } 615 if (uflag) 616 (void)unlink(name); 617 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 618 0666)) < 0) { 619 fprintf(stderr, "%s: cannot create file: %s\n", 620 name, strerror(errno)); 621 skipfile(); 622 return (FAIL); 623 } 624 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); 625 (void) fchmod(ofile, mode); 626 (void) fchflags(ofile, flags); 627 getfile(xtrfile, xtrskip); 628 (void) close(ofile); 629 utimes(name, timep); 630 return (GOOD); 631 } 632 /* NOTREACHED */ 633} 634 635/* 636 * skip over bit maps on the tape 637 */ 638void 639skipmaps() 640{ 641 642 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 643 skipfile(); 644} 645 646/* 647 * skip over a file on the tape 648 */ 649void 650skipfile() 651{ 652 653 curfile.action = SKIP; 654 getfile(xtrnull, xtrnull); 655} 656 657/* 658 * Extract a file from the tape. 659 * When an allocated block is found it is passed to the fill function; 660 * when an unallocated block (hole) is found, a zeroed buffer is passed 661 * to the skip function. 662 */ 663void 664getfile(fill, skip) 665 void (*fill) __P((char *, long)); 666 void (*skip) __P((char *, long)); 667{ 668 register int i; 669 int curblk = 0; 670 quad_t size = spcl.c_dinode.di_size; 671 static char clearedbuf[MAXBSIZE]; 672 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 673 char junk[TP_BSIZE]; 674 675 if (spcl.c_type == TS_END) 676 panic("ran off end of tape\n"); 677 if (spcl.c_magic != NFS_MAGIC) 678 panic("not at beginning of a file\n"); 679 if (!gettingfile && setjmp(restart) != 0) 680 return; 681 gettingfile++; 682loop: 683 for (i = 0; i < spcl.c_count; i++) { 684 if (spcl.c_addr[i]) { 685 readtape(&buf[curblk++][0]); 686 if (curblk == fssize / TP_BSIZE) { 687 (*fill)((char *)buf, (long)(size > TP_BSIZE ? 688 fssize : (curblk - 1) * TP_BSIZE + size)); 689 curblk = 0; 690 } 691 } else { 692 if (curblk > 0) { 693 (*fill)((char *)buf, (long)(size > TP_BSIZE ? 694 curblk * TP_BSIZE : 695 (curblk - 1) * TP_BSIZE + size)); 696 curblk = 0; 697 } 698 (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 699 TP_BSIZE : size)); 700 } 701 if ((size -= TP_BSIZE) <= 0) { 702 for (i++; i < spcl.c_count; i++) 703 if (spcl.c_addr[i]) 704 readtape(junk); 705 break; 706 } 707 } 708 if (gethead(&spcl) == GOOD && size > 0) { 709 if (spcl.c_type == TS_ADDR) 710 goto loop; 711 dprintf(stdout, 712 "Missing address (header) block for %s at %ld blocks\n", 713 curfile.name, blksread); 714 } 715 if (curblk > 0) 716 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size)); 717 findinode(&spcl); 718 gettingfile = 0; 719} 720 721/* 722 * Write out the next block of a file. 723 */ 724static void 725xtrfile(buf, size) 726 char *buf; 727 long size; 728{ 729 730 if (Nflag) 731 return; 732 if (write(ofile, buf, (int) size) == -1) { 733 fprintf(stderr, 734 "write error extracting inode %d, name %s\nwrite: %s\n", 735 curfile.ino, curfile.name, strerror(errno)); 736 done(1); 737 } 738} 739 740/* 741 * Skip over a hole in a file. 742 */ 743/* ARGSUSED */ 744static void 745xtrskip(buf, size) 746 char *buf; 747 long size; 748{ 749 750 if (lseek(ofile, size, SEEK_CUR) == -1) { 751 fprintf(stderr, 752 "seek error extracting inode %d, name %s\nlseek: %s\n", 753 curfile.ino, curfile.name, strerror(errno)); 754 done(1); 755 } 756} 757 758/* 759 * Collect the next block of a symbolic link. 760 */ 761static void 762xtrlnkfile(buf, size) 763 char *buf; 764 long size; 765{ 766 767 pathlen += size; 768 if (pathlen > MAXPATHLEN) { 769 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 770 curfile.name, lnkbuf, buf, pathlen); 771 done(1); 772 } 773 (void) strcat(lnkbuf, buf); 774} 775 776/* 777 * Skip over a hole in a symbolic link (should never happen). 778 */ 779/* ARGSUSED */ 780static void 781xtrlnkskip(buf, size) 782 char *buf; 783 long size; 784{ 785 786 fprintf(stderr, "unallocated block in symbolic link %s\n", 787 curfile.name); 788 done(1); 789} 790 791/* 792 * Collect the next block of a bit map. 793 */ 794static void 795xtrmap(buf, size) 796 char *buf; 797 long size; 798{ 799 800 memmove(map, buf, size); 801 map += size; 802} 803 804/* 805 * Skip over a hole in a bit map (should never happen). 806 */ 807/* ARGSUSED */ 808static void 809xtrmapskip(buf, size) 810 char *buf; 811 long size; 812{ 813 814 panic("hole in map\n"); 815 map += size; 816} 817 818/* 819 * Noop, when an extraction function is not needed. 820 */ 821/* ARGSUSED */ 822void 823xtrnull(buf, size) 824 char *buf; 825 long size; 826{ 827 828 return; 829} 830 831/* 832 * Read TP_BSIZE blocks from the input. 833 * Handle read errors, and end of media. 834 */ 835static void 836readtape(buf) 837 char *buf; 838{ 839 long rd, newvol, i; 840 int cnt, seek_failed; 841 842 if (blkcnt < numtrec) { 843 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 844 blksread++; 845 tpblksread++; 846 return; 847 } 848 for (i = 0; i < ntrec; i++) 849 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 850 if (numtrec == 0) 851 numtrec = ntrec; 852 cnt = ntrec * TP_BSIZE; 853 rd = 0; 854getmore: 855#ifdef RRESTORE 856 if (host) 857 i = rmtread(&tapebuf[rd], cnt); 858 else 859#endif 860 i = read(mt, &tapebuf[rd], cnt); 861 /* 862 * Check for mid-tape short read error. 863 * If found, skip rest of buffer and start with the next. 864 */ 865 if (!pipein && numtrec < ntrec && i > 0) { 866 dprintf(stdout, "mid-media short read error.\n"); 867 numtrec = ntrec; 868 } 869 /* 870 * Handle partial block read. 871 */ 872 if (pipein && i == 0 && rd > 0) 873 i = rd; 874 else if (i > 0 && i != ntrec * TP_BSIZE) { 875 if (pipein) { 876 rd += i; 877 cnt -= i; 878 if (cnt > 0) 879 goto getmore; 880 i = rd; 881 } else { 882 /* 883 * Short read. Process the blocks read. 884 */ 885 if (i % TP_BSIZE != 0) 886 vprintf(stdout, 887 "partial block read: %ld should be %ld\n", 888 i, ntrec * TP_BSIZE); 889 numtrec = i / TP_BSIZE; 890 } 891 } 892 /* 893 * Handle read error. 894 */ 895 if (i < 0) { 896 fprintf(stderr, "Tape read error while "); 897 switch (curfile.action) { 898 default: 899 fprintf(stderr, "trying to set up tape\n"); 900 break; 901 case UNKNOWN: 902 fprintf(stderr, "trying to resynchronize\n"); 903 break; 904 case USING: 905 fprintf(stderr, "restoring %s\n", curfile.name); 906 break; 907 case SKIP: 908 fprintf(stderr, "skipping over inode %d\n", 909 curfile.ino); 910 break; 911 } 912 if (!yflag && !reply("continue")) 913 done(1); 914 i = ntrec * TP_BSIZE; 915 memset(tapebuf, 0, i); 916#ifdef RRESTORE 917 if (host) 918 seek_failed = (rmtseek(i, 1) < 0); 919 else 920#endif 921 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 922 923 if (seek_failed) { 924 fprintf(stderr, 925 "continuation failed: %s\n", strerror(errno)); 926 done(1); 927 } 928 } 929 /* 930 * Handle end of tape. 931 */ 932 if (i == 0) { 933 vprintf(stdout, "End-of-tape encountered\n"); 934 if (!pipein) { 935 newvol = volno + 1; 936 volno = 0; 937 numtrec = 0; 938 getvol(newvol); 939 readtape(buf); 940 return; 941 } 942 if (rd % TP_BSIZE != 0) 943 panic("partial block read: %d should be %d\n", 944 rd, ntrec * TP_BSIZE); 945 terminateinput(); 946 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 947 } 948 blkcnt = 0; 949 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 950 blksread++; 951 tpblksread++; 952} 953 954static void 955findtapeblksize() 956{ 957 register long i; 958 959 for (i = 0; i < ntrec; i++) 960 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 961 blkcnt = 0; 962#ifdef RRESTORE 963 if (host) 964 i = rmtread(tapebuf, ntrec * TP_BSIZE); 965 else 966#endif 967 i = read(mt, tapebuf, ntrec * TP_BSIZE); 968 969 if (i <= 0) { 970 fprintf(stderr, "tape read error: %s\n", strerror(errno)); 971 done(1); 972 } 973 if (i % TP_BSIZE != 0) { 974 fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 975 i, "is not a multiple of dump block size", TP_BSIZE); 976 done(1); 977 } 978 ntrec = i / TP_BSIZE; 979 numtrec = ntrec; 980 vprintf(stdout, "Tape block size is %ld\n", ntrec); 981} 982 983void 984closemt() 985{ 986 987 if (mt < 0) 988 return; 989#ifdef RRESTORE 990 if (host) 991 rmtclose(); 992 else 993#endif 994 (void) close(mt); 995} 996 997/* 998 * Read the next block from the tape. 999 * Check to see if it is one of several vintage headers. 1000 * If it is an old style header, convert it to a new style header. 1001 * If it is not any valid header, return an error. 1002 */ 1003static int 1004gethead(buf) 1005 struct s_spcl *buf; 1006{ 1007 long i; 1008 union { 1009 quad_t qval; 1010 long val[2]; 1011 } qcvt; 1012 union u_ospcl { 1013 char dummy[TP_BSIZE]; 1014 struct s_ospcl { 1015 long c_type; 1016 long c_date; 1017 long c_ddate; 1018 long c_volume; 1019 long c_tapea; 1020 u_short c_inumber; 1021 long c_magic; 1022 long c_checksum; 1023 struct odinode { 1024 unsigned short odi_mode; 1025 u_short odi_nlink; 1026 u_short odi_uid; 1027 u_short odi_gid; 1028 long odi_size; 1029 long odi_rdev; 1030 char odi_addr[36]; 1031 long odi_atime; 1032 long odi_mtime; 1033 long odi_ctime; 1034 } c_dinode; 1035 long c_count; 1036 char c_addr[256]; 1037 } s_ospcl; 1038 } u_ospcl; 1039 1040 if (!cvtflag) { 1041 readtape((char *)buf); 1042 if (buf->c_magic != NFS_MAGIC) { 1043 if (swabl(buf->c_magic) != NFS_MAGIC) 1044 return (FAIL); 1045 if (!Bcvt) { 1046 vprintf(stdout, "Note: Doing Byte swapping\n"); 1047 Bcvt = 1; 1048 } 1049 } 1050 if (checksum((int *)buf) == FAIL) 1051 return (FAIL); 1052 if (Bcvt) { 1053 swabst((u_char *)"8l4s31l", (u_char *)buf); 1054 swabst((u_char *)"l",(u_char *) &buf->c_level); 1055 swabst((u_char *)"2l",(u_char *) &buf->c_flags); 1056 } 1057 goto good; 1058 } 1059 readtape((char *)(&u_ospcl.s_ospcl)); 1060 memset(buf, 0, (long)TP_BSIZE); 1061 buf->c_type = u_ospcl.s_ospcl.c_type; 1062 buf->c_date = u_ospcl.s_ospcl.c_date; 1063 buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 1064 buf->c_volume = u_ospcl.s_ospcl.c_volume; 1065 buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 1066 buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 1067 buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 1068 buf->c_magic = u_ospcl.s_ospcl.c_magic; 1069 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 1070 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 1071 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 1072 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 1073 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; 1074 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 1075 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; 1076 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; 1077 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; 1078 buf->c_count = u_ospcl.s_ospcl.c_count; 1079 memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256); 1080 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || 1081 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) 1082 return(FAIL); 1083 buf->c_magic = NFS_MAGIC; 1084 1085good: 1086 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) && 1087 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) { 1088 qcvt.qval = buf->c_dinode.di_size; 1089 if (qcvt.val[0] || qcvt.val[1]) { 1090 printf("Note: Doing Quad swapping\n"); 1091 Qcvt = 1; 1092 } 1093 } 1094 if (Qcvt) { 1095 qcvt.qval = buf->c_dinode.di_size; 1096 i = qcvt.val[1]; 1097 qcvt.val[1] = qcvt.val[0]; 1098 qcvt.val[0] = i; 1099 buf->c_dinode.di_size = qcvt.qval; 1100 } 1101 1102 switch (buf->c_type) { 1103 1104 case TS_CLRI: 1105 case TS_BITS: 1106 /* 1107 * Have to patch up missing information in bit map headers 1108 */ 1109 buf->c_inumber = 0; 1110 buf->c_dinode.di_size = buf->c_count * TP_BSIZE; 1111 for (i = 0; i < buf->c_count; i++) 1112 buf->c_addr[i]++; 1113 break; 1114 1115 case TS_TAPE: 1116 if ((buf->c_flags & DR_NEWINODEFMT) == 0) 1117 oldinofmt = 1; 1118 /* fall through */ 1119 case TS_END: 1120 buf->c_inumber = 0; 1121 break; 1122 1123 case TS_INODE: 1124 case TS_ADDR: 1125 break; 1126 1127 default: 1128 panic("gethead: unknown inode type %d\n", buf->c_type); 1129 break; 1130 } 1131 /* 1132 * If we are restoring a filesystem with old format inodes, 1133 * copy the uid/gid to the new location. 1134 */ 1135 if (oldinofmt) { 1136 buf->c_dinode.di_uid = buf->c_dinode.di_ouid; 1137 buf->c_dinode.di_gid = buf->c_dinode.di_ogid; 1138 } 1139 if (dflag) 1140 accthdr(buf); 1141 return(GOOD); 1142} 1143 1144/* 1145 * Check that a header is where it belongs and predict the next header 1146 */ 1147static void 1148accthdr(header) 1149 struct s_spcl *header; 1150{ 1151 static ino_t previno = 0x7fffffff; 1152 static int prevtype; 1153 static long predict; 1154 long blks, i; 1155 1156 if (header->c_type == TS_TAPE) { 1157 fprintf(stderr, "Volume header (%s inode format) ", 1158 oldinofmt ? "old" : "new"); 1159 if (header->c_firstrec) 1160 fprintf(stderr, "begins with record %ld", 1161 header->c_firstrec); 1162 fprintf(stderr, "\n"); 1163 previno = 0x7fffffff; 1164 return; 1165 } 1166 if (previno == 0x7fffffff) 1167 goto newcalc; 1168 switch (prevtype) { 1169 case TS_BITS: 1170 fprintf(stderr, "Dumped inodes map header"); 1171 break; 1172 case TS_CLRI: 1173 fprintf(stderr, "Used inodes map header"); 1174 break; 1175 case TS_INODE: 1176 fprintf(stderr, "File header, ino %d", previno); 1177 break; 1178 case TS_ADDR: 1179 fprintf(stderr, "File continuation header, ino %d", previno); 1180 break; 1181 case TS_END: 1182 fprintf(stderr, "End of tape header"); 1183 break; 1184 } 1185 if (predict != blksread - 1) 1186 fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 1187 predict, blksread - 1); 1188 fprintf(stderr, "\n"); 1189newcalc: 1190 blks = 0; 1191 if (header->c_type != TS_END) 1192 for (i = 0; i < header->c_count; i++) 1193 if (header->c_addr[i] != 0) 1194 blks++; 1195 predict = blks; 1196 blksread = 0; 1197 prevtype = header->c_type; 1198 previno = header->c_inumber; 1199} 1200 1201/* 1202 * Find an inode header. 1203 * Complain if had to skip, and complain is set. 1204 */ 1205static void 1206findinode(header) 1207 struct s_spcl *header; 1208{ 1209 static long skipcnt = 0; 1210 long i; 1211 char buf[TP_BSIZE]; 1212 1213 curfile.name = "<name unknown>"; 1214 curfile.action = UNKNOWN; 1215 curfile.dip = NULL; 1216 curfile.ino = 0; 1217 do { 1218 if (header->c_magic != NFS_MAGIC) { 1219 skipcnt++; 1220 while (gethead(header) == FAIL || 1221 header->c_date != dumpdate) 1222 skipcnt++; 1223 } 1224 switch (header->c_type) { 1225 1226 case TS_ADDR: 1227 /* 1228 * Skip up to the beginning of the next record 1229 */ 1230 for (i = 0; i < header->c_count; i++) 1231 if (header->c_addr[i]) 1232 readtape(buf); 1233 while (gethead(header) == FAIL || 1234 header->c_date != dumpdate) 1235 skipcnt++; 1236 break; 1237 1238 case TS_INODE: 1239 curfile.dip = &header->c_dinode; 1240 curfile.ino = header->c_inumber; 1241 break; 1242 1243 case TS_END: 1244 curfile.ino = maxino; 1245 break; 1246 1247 case TS_CLRI: 1248 curfile.name = "<file removal list>"; 1249 break; 1250 1251 case TS_BITS: 1252 curfile.name = "<file dump list>"; 1253 break; 1254 1255 case TS_TAPE: 1256 panic("unexpected tape header\n"); 1257 /* NOTREACHED */ 1258 1259 default: 1260 panic("unknown tape header type %d\n", spcl.c_type); 1261 /* NOTREACHED */ 1262 1263 } 1264 } while (header->c_type == TS_ADDR); 1265 if (skipcnt > 0) 1266 fprintf(stderr, "resync restore, skipped %ld blocks\n", 1267 skipcnt); 1268 skipcnt = 0; 1269} 1270 1271static int 1272checksum(buf) 1273 register int *buf; 1274{ 1275 register int i, j; 1276 1277 j = sizeof(union u_spcl) / sizeof(int); 1278 i = 0; 1279 if(!Bcvt) { 1280 do 1281 i += *buf++; 1282 while (--j); 1283 } else { 1284 /* What happens if we want to read restore tapes 1285 for a 16bit int machine??? */ 1286 do 1287 i += swabl(*buf++); 1288 while (--j); 1289 } 1290 1291 if (i != CHECKSUM) { 1292 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 1293 curfile.ino, curfile.name); 1294 return(FAIL); 1295 } 1296 return(GOOD); 1297} 1298 1299#ifdef RRESTORE 1300#if __STDC__ 1301#include <stdarg.h> 1302#else 1303#include <varargs.h> 1304#endif 1305 1306void 1307#if __STDC__ 1308msg(const char *fmt, ...) 1309#else 1310msg(fmt, va_alist) 1311 char *fmt; 1312 va_dcl 1313#endif 1314{ 1315 va_list ap; 1316#if __STDC__ 1317 va_start(ap, fmt); 1318#else 1319 va_start(ap); 1320#endif 1321 (void)vfprintf(stderr, fmt, ap); 1322 va_end(ap); 1323} 1324#endif /* RRESTORE */ 1325 1326static u_char * 1327swabshort(sp, n) 1328 register u_char *sp; 1329 register int n; 1330{ 1331 char c; 1332 1333 while (--n >= 0) { 1334 c = sp[0]; sp[0] = sp[1]; sp[1] = c; 1335 sp += 2; 1336 } 1337 return (sp); 1338} 1339 1340static u_char * 1341swablong(sp, n) 1342 register u_char *sp; 1343 register int n; 1344{ 1345 char c; 1346 1347 while (--n >= 0) { 1348 c = sp[0]; sp[0] = sp[3]; sp[3] = c; 1349 c = sp[2]; sp[2] = sp[1]; sp[1] = c; 1350 sp += 4; 1351 } 1352 return (sp); 1353} 1354 1355void 1356swabst(cp, sp) 1357 register u_char *cp, *sp; 1358{ 1359 int n = 0; 1360 1361 while (*cp) { 1362 switch (*cp) { 1363 case '0': case '1': case '2': case '3': case '4': 1364 case '5': case '6': case '7': case '8': case '9': 1365 n = (n * 10) + (*cp++ - '0'); 1366 continue; 1367 1368 case 's': case 'w': case 'h': 1369 if (n == 0) 1370 n = 1; 1371 sp = swabshort(sp, n); 1372 break; 1373 1374 case 'l': 1375 if (n == 0) 1376 n = 1; 1377 sp = swablong(sp, n); 1378 break; 1379 1380 default: /* Any other character, like 'b' counts as byte. */ 1381 if (n == 0) 1382 n = 1; 1383 sp += n; 1384 break; 1385 } 1386 cp++; 1387 n = 0; 1388 } 1389} 1390 1391static u_long 1392swabl(x) 1393 u_long x; 1394{ 1395 swabst((u_char *)"l", (u_char *)&x); 1396 return (x); 1397} 1398