tape.c revision 73986
10SN/A/* 214882SN/A * Copyright (c) 1983, 1993 30SN/A * The Regents of the University of California. All rights reserved. 40SN/A * (c) UNIX System Laboratories, Inc. 50SN/A * All or some portions of this file are derived from material licensed 60SN/A * to the University of California by American Telephone and Telegraph 70SN/A * Co. or Unix System Laboratories, Inc. and are reproduced herein with 80SN/A * the permission of UNIX System Laboratories, Inc. 90SN/A * 100SN/A * Redistribution and use in source and binary forms, with or without 110SN/A * modification, are permitted provided that the following conditions 120SN/A * are met: 130SN/A * 1. Redistributions of source code must retain the above copyright 140SN/A * notice, this list of conditions and the following disclaimer. 150SN/A * 2. Redistributions in binary form must reproduce the above copyright 160SN/A * notice, this list of conditions and the following disclaimer in the 170SN/A * documentation and/or other materials provided with the distribution. 180SN/A * 3. All advertising materials mentioning features or use of this software 190SN/A * must display the following acknowledgement: 200SN/A * This product includes software developed by the University of 210SN/A * California, Berkeley and its contributors. 220SN/A * 4. Neither the name of the University nor the names of its contributors 230SN/A * may be used to endorse or promote products derived from this software 240SN/A * without specific prior written permission. 250SN/A * 260SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 270SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 280SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 290SN/A * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 300SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 310SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 320SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 330SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 340SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 350SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 360SN/A * SUCH DAMAGE. 370SN/A */ 380SN/A 390SN/A#ifndef lint 400SN/A#if 0 410SN/Astatic char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; 420SN/A#endif 430SN/Astatic const char rcsid[] = 440SN/A "$FreeBSD: head/sbin/restore/tape.c 73986 2001-03-08 09:04:40Z obrien $"; 450SN/A#endif /* not lint */ 460SN/A 470SN/A#include <sys/param.h> 480SN/A#include <sys/file.h> 490SN/A#include <sys/mtio.h> 500SN/A#include <sys/stat.h> 510SN/A#include <sys/time.h> 520SN/A 530SN/A#include <ufs/ufs/dinode.h> 540SN/A#include <protocols/dumprestore.h> 550SN/A 560SN/A#include <errno.h> 570SN/A#include <paths.h> 589284SN/A#include <setjmp.h> 599284SN/A#include <stdio.h> 609284SN/A#include <stdlib.h> 610SN/A#include <string.h> 620SN/A#include <time.h> 630SN/A#include <unistd.h> 640SN/A 650SN/A#include "restore.h" 660SN/A#include "extern.h" 670SN/A 680SN/Astatic long fssize = MAXBSIZE; 690SN/Astatic int mt = -1; 700SN/Astatic int pipein = 0; 710SN/Astatic char *magtape; 720SN/Astatic int blkcnt; 730SN/Astatic int numtrec; 740SN/Astatic char *tapebuf; 750SN/Astatic union u_spcl endoftapemark; 760SN/Astatic long blksread; /* blocks read since last header */ 770SN/Astatic long tpblksread = 0; /* TP_BSIZE blocks read */ 780SN/Astatic long tapesread; 790SN/Astatic jmp_buf restart; 800SN/Astatic int gettingfile = 0; /* restart has a valid frame */ 810SN/Astatic char *host = NULL; 820SN/A 830SN/Astatic int ofile; 840SN/Astatic char *map; 850SN/Astatic char lnkbuf[MAXPATHLEN + 1]; 860SN/Astatic int pathlen; 870SN/A 880SN/Aint oldinofmt; /* old inode format conversion required */ 890SN/Aint Bcvt; /* Swap Bytes (for CCI or sun) */ 900SN/Astatic int Qcvt; /* Swap quads (for sun) */ 910SN/A 920SN/A#define FLUSHTAPEBUF() blkcnt = ntrec + 1 930SN/A 940SN/Astatic void accthdr __P((struct s_spcl *)); 950SN/Astatic int checksum __P((int *)); 960SN/Astatic void findinode __P((struct s_spcl *)); 970SN/Astatic void findtapeblksize __P((void)); 980SN/Astatic int gethead __P((struct s_spcl *)); 990SN/Astatic void readtape __P((char *)); 1000SN/Astatic void setdumpnum __P((void)); 1010SN/Astatic u_long swabl __P((u_long)); 1024908SN/Astatic u_char *swablong __P((u_char *, int)); 1034908SN/Astatic u_char *swabshort __P((u_char *, int)); 1040SN/Astatic void terminateinput __P((void)); 1050SN/Astatic void xtrfile __P((char *, long)); 1060SN/Astatic void xtrlnkfile __P((char *, long)); 1070SN/Astatic void xtrlnkskip __P((char *, long)); 1080SN/Astatic void xtrmap __P((char *, long)); 1090SN/Astatic void xtrmapskip __P((char *, long)); 1100SN/Astatic void xtrskip __P((char *, long)); 1110SN/A 1120SN/Astatic int readmapflag; 1130SN/A 1140SN/A/* 1150SN/A * Set up an input source 1160SN/A */ 1170SN/Avoid 1180SN/Asetinput(source) 1190SN/A char *source; 1200SN/A{ 1210SN/A FLUSHTAPEBUF(); 1220SN/A if (bflag) 1230SN/A newtapebuf(ntrec); 1240SN/A else 1250SN/A newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 1260SN/A terminal = stdin; 1270SN/A 1280SN/A#ifdef RRESTORE 1290SN/A if (strchr(source, ':')) { 1300SN/A host = source; 1310SN/A source = strchr(host, ':'); 1320SN/A *source++ = '\0'; 1330SN/A if (rmthost(host) == 0) 1340SN/A done(1); 1350SN/A } else 1360SN/A#endif 1370SN/A if (strcmp(source, "-") == 0) { 1380SN/A /* 1390SN/A * Since input is coming from a pipe we must establish 1400SN/A * our own connection to the terminal. 1410SN/A */ 1420SN/A terminal = fopen(_PATH_TTY, "r"); 1430SN/A if (terminal == NULL) { 1440SN/A (void)fprintf(stderr, "cannot open %s: %s\n", 1450SN/A _PATH_TTY, strerror(errno)); 1460SN/A terminal = fopen(_PATH_DEVNULL, "r"); 1470SN/A if (terminal == NULL) { 1480SN/A (void)fprintf(stderr, "cannot open %s: %s\n", 1490SN/A _PATH_DEVNULL, strerror(errno)); 1500SN/A done(1); 1510SN/A } 1520SN/A } 1530SN/A pipein++; 1540SN/A } 1550SN/A setuid(getuid()); /* no longer need or want root privileges */ 1560SN/A magtape = strdup(source); 1570SN/A if (magtape == NULL) { 1580SN/A fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 1593645SN/A done(1); 1600SN/A } 161936SN/A} 16214882SN/A 1630SN/Avoid 1640SN/Anewtapebuf(size) 1650SN/A long size; 1660SN/A{ 1670SN/A static tapebufsize = -1; 1680SN/A 1690SN/A ntrec = size; 1700SN/A if (size <= tapebufsize) 1710SN/A return; 1720SN/A if (tapebuf != NULL) 1730SN/A free(tapebuf); 1740SN/A tapebuf = malloc(size * TP_BSIZE); 1750SN/A if (tapebuf == NULL) { 1760SN/A fprintf(stderr, "Cannot allocate space for tape buffer\n"); 1770SN/A done(1); 1780SN/A } 1790SN/A tapebufsize = size; 1800SN/A} 1810SN/A 1820SN/A/* 1830SN/A * Verify that the tape drive can be accessed and 1840SN/A * that it actually is a dump tape. 1850SN/A */ 1860SN/Avoid 1870SN/Asetup() 1880SN/A{ 1890SN/A int i, j, *ip; 1900SN/A struct stat stbuf; 1910SN/A 1920SN/A vprintf(stdout, "Verify tape and initialize maps\n"); 1930SN/A#ifdef RRESTORE 1940SN/A if (host) 1950SN/A mt = rmtopen(magtape, 0); 1960SN/A else 1970SN/A#endif 1980SN/A if (pipein) 1990SN/A mt = 0; 2000SN/A else 2010SN/A mt = open(magtape, O_RDONLY, 0); 2020SN/A if (mt < 0) { 2030SN/A fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 2040SN/A done(1); 2050SN/A } 2060SN/A volno = 1; 2070SN/A setdumpnum(); 2080SN/A FLUSHTAPEBUF(); 2090SN/A if (!pipein && !bflag) 2100SN/A findtapeblksize(); 2110SN/A if (gethead(&spcl) == FAIL) { 2120SN/A blkcnt--; /* push back this block */ 2130SN/A blksread--; 2140SN/A tpblksread--; 2150SN/A cvtflag++; 2160SN/A if (gethead(&spcl) == FAIL) { 2170SN/A fprintf(stderr, "Tape is not a dump tape\n"); 2180SN/A done(1); 2190SN/A } 2200SN/A fprintf(stderr, "Converting to new file system format.\n"); 22114882SN/A } 22214882SN/A if (pipein) { 22314882SN/A endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; 22414882SN/A endoftapemark.s_spcl.c_type = TS_END; 2250SN/A ip = (int *)&endoftapemark; 2260SN/A j = sizeof(union u_spcl) / sizeof(int); 2270SN/A i = 0; 2280SN/A do 2290SN/A i += *ip++; 2300SN/A while (--j); 2310SN/A endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 2320SN/A } 2330SN/A if (vflag || command == 't') 2340SN/A printdumpinfo(); 2350SN/A dumptime = spcl.c_ddate; 2360SN/A dumpdate = spcl.c_date; 2370SN/A if (stat(".", &stbuf) < 0) { 2380SN/A fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 2390SN/A done(1); 2400SN/A } 2410SN/A if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 2420SN/A fssize = TP_BSIZE; 2430SN/A if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 2440SN/A fssize = stbuf.st_blksize; 2450SN/A if (((fssize - 1) & fssize) != 0) { 2460SN/A fprintf(stderr, "bad block size %ld\n", fssize); 2470SN/A done(1); 2480SN/A } 2490SN/A if (spcl.c_volume != 1) { 2500SN/A fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2510SN/A done(1); 2520SN/A } 2530SN/A if (gethead(&spcl) == FAIL) { 2540SN/A dprintf(stdout, "header read failed at %ld blocks\n", blksread); 2550SN/A panic("no header after volume mark!\n"); 2560SN/A } 2570SN/A findinode(&spcl); 2580SN/A if (spcl.c_type != TS_CLRI) { 2590SN/A fprintf(stderr, "Cannot find file removal list\n"); 2600SN/A done(1); 2610SN/A } 2620SN/A maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 2630SN/A dprintf(stdout, "maxino = %d\n", maxino); 2640SN/A map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2650SN/A if (map == NULL) 2660SN/A panic("no memory for active inode map\n"); 2670SN/A usedinomap = map; 2680SN/A curfile.action = USING; 2690SN/A getfile(xtrmap, xtrmapskip); 2700SN/A if (spcl.c_type != TS_BITS) { 2710SN/A fprintf(stderr, "Cannot find file dump list\n"); 2720SN/A done(1); 2730SN/A } 2740SN/A map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 2750SN/A if (map == (char *)NULL) 2760SN/A panic("no memory for file dump list\n"); 2770SN/A dumpmap = map; 2780SN/A curfile.action = USING; 2790SN/A getfile(xtrmap, xtrmapskip); 2800SN/A /* 2810SN/A * If there may be whiteout entries on the tape, pretend that the 2820SN/A * whiteout inode exists, so that the whiteout entries can be 2833645SN/A * extracted. 2840SN/A */ 2850SN/A if (oldinofmt == 0) 2860SN/A SETINO(WINO, dumpmap); 2870SN/A} 2880SN/A 2890SN/A/* 2904660SN/A * Prompt user to load a new dump volume. 2914660SN/A * "Nextvol" is the next suggested volume to use. 2920SN/A * This suggested volume is enforced when doing full 293936SN/A * or incremental restores, but can be overridden by 2940SN/A * the user when only extracting a subset of the files. 2950SN/A */ 296936SN/Avoid 297936SN/Agetvol(nextvol) 298936SN/A long nextvol; 299936SN/A{ 3000SN/A long newvol, savecnt, wantnext, i; 3010SN/A union u_spcl tmpspcl; 3020SN/A# define tmpbuf tmpspcl.s_spcl 3030SN/A char buf[TP_BSIZE]; 3040SN/A 3050SN/A if (nextvol == 1) { 3060SN/A tapesread = 0; 3070SN/A gettingfile = 0; 3080SN/A } 3090SN/A if (pipein) { 3100SN/A if (nextvol != 1) { 3110SN/A panic("Changing volumes on pipe input?\n"); 3120SN/A /* Avoid looping if we couldn't ask the user. */ 3130SN/A if (yflag || ferror(terminal) || feof(terminal)) 3141428SN/A done(1); 3150SN/A } 3160SN/A if (volno == 1) 3170SN/A return; 3180SN/A goto gethdr; 3190SN/A } 3200SN/A savecnt = blksread; 3210SN/Aagain: 3220SN/A if (pipein) 3230SN/A done(1); /* pipes do not get a second chance */ 3240SN/A if (command == 'R' || command == 'r' || curfile.action != SKIP) { 3250SN/A newvol = nextvol; 3260SN/A wantnext = 1; 3270SN/A } else { 3280SN/A newvol = 0; 3290SN/A wantnext = 0; 3300SN/A } 3310SN/A while (newvol <= 0) { 3320SN/A if (tapesread == 0) { 3330SN/A fprintf(stderr, "%s%s%s%s%s", 3340SN/A "You have not read any tapes yet.\n", 3350SN/A "Unless you know which volume your", 3360SN/A " file(s) are on you should start\n", 3370SN/A "with the last volume and work", 3380SN/A " towards the first.\n"); 3390SN/A } else { 3400SN/A fprintf(stderr, "You have read volumes"); 3410SN/A strcpy(buf, ": "); 3420SN/A for (i = 1; i < 32; i++) 3430SN/A if (tapesread & (1 << i)) { 3440SN/A fprintf(stderr, "%s%ld", buf, i); 3450SN/A strcpy(buf, ", "); 3460SN/A } 3470SN/A fprintf(stderr, "\n"); 3480SN/A } 3490SN/A do { 3500SN/A fprintf(stderr, "Specify next volume #: "); 3510SN/A (void) fflush(stderr); 3520SN/A if (fgets(buf, BUFSIZ, terminal) == NULL) 3530SN/A done(1); 3540SN/A } while (buf[0] == '\n'); 3550SN/A newvol = atoi(buf); 3560SN/A if (newvol <= 0) { 3570SN/A fprintf(stderr, 3580SN/A "Volume numbers are positive numerics\n"); 3590SN/A } 3600SN/A } 3610SN/A if (newvol == volno) { 3620SN/A tapesread |= 1 << volno; 3630SN/A return; 3640SN/A } 3650SN/A closemt(); 3660SN/A fprintf(stderr, "Mount tape volume %ld\n", newvol); 3670SN/A fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 3680SN/A fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 3690SN/A (void) fflush(stderr); 3700SN/A if (fgets(buf, BUFSIZ, terminal) == NULL) 3710SN/A done(1); 3720SN/A if (!strcmp(buf, "none\n")) { 3730SN/A terminateinput(); 3740SN/A return; 3750SN/A } 3760SN/A if (buf[0] != '\n') { 3770SN/A (void) strcpy(magtape, buf); 3780SN/A magtape[strlen(magtape) - 1] = '\0'; 3790SN/A } 3800SN/A#ifdef RRESTORE 3810SN/A if (host) 3820SN/A mt = rmtopen(magtape, 0); 3830SN/A else 3840SN/A#endif 3850SN/A mt = open(magtape, O_RDONLY, 0); 3860SN/A 3870SN/A if (mt == -1) { 3880SN/A fprintf(stderr, "Cannot open %s\n", magtape); 3890SN/A volno = -1; 3900SN/A goto again; 3910SN/A } 3920SN/Agethdr: 3930SN/A volno = newvol; 3940SN/A setdumpnum(); 3950SN/A FLUSHTAPEBUF(); 3960SN/A if (gethead(&tmpbuf) == FAIL) { 3970SN/A dprintf(stdout, "header read failed at %ld blocks\n", blksread); 3980SN/A fprintf(stderr, "tape is not dump tape\n"); 3990SN/A volno = 0; 4000SN/A goto again; 4010SN/A } 4020SN/A if (tmpbuf.c_volume != volno) { 4030SN/A fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume); 4040SN/A volno = 0; 4050SN/A goto again; 4060SN/A } 4070SN/A if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { 4080SN/A fprintf(stderr, "Wrong dump date\n\tgot: %s", 4090SN/A ctime(&tmpbuf.c_date)); 4100SN/A fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 4110SN/A volno = 0; 4120SN/A goto again; 4130SN/A } 4140SN/A tapesread |= 1 << volno; 4150SN/A blksread = savecnt; 4160SN/A /* 4170SN/A * If continuing from the previous volume, skip over any 4180SN/A * blocks read already at the end of the previous volume. 4190SN/A * 4200SN/A * If coming to this volume at random, skip to the beginning 4210SN/A * of the next record. 4220SN/A */ 4230SN/A dprintf(stdout, "read %ld recs, tape starts with %ld\n", 4240SN/A tpblksread, tmpbuf.c_firstrec); 4250SN/A if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { 4260SN/A if (!wantnext) { 4270SN/A tpblksread = tmpbuf.c_firstrec; 4280SN/A for (i = tmpbuf.c_count; i > 0; i--) 4290SN/A readtape(buf); 4300SN/A } else if (tmpbuf.c_firstrec > 0 && 4310SN/A tmpbuf.c_firstrec < tpblksread - 1) { 4320SN/A /* 4330SN/A * -1 since we've read the volume header 4340SN/A */ 4350SN/A i = tpblksread - tmpbuf.c_firstrec - 1; 4360SN/A dprintf(stderr, "Skipping %ld duplicate record%s.\n", 4370SN/A i, i > 1 ? "s" : ""); 4380SN/A while (--i >= 0) 4390SN/A readtape(buf); 4400SN/A } 4410SN/A } 4420SN/A if (curfile.action == USING) { 4430SN/A if (volno == 1) 4440SN/A panic("active file into volume 1\n"); 4450SN/A return; 4460SN/A } 4470SN/A /* 4480SN/A * Skip up to the beginning of the next record 4490SN/A */ 4500SN/A if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) 4510SN/A for (i = tmpbuf.c_count; i > 0; i--) 4520SN/A readtape(buf); 4530SN/A (void) gethead(&spcl); 4540SN/A findinode(&spcl); 455936SN/A if (gettingfile) { 456936SN/A gettingfile = 0; 457936SN/A longjmp(restart, 1); 458936SN/A } 459936SN/A} 460936SN/A 461936SN/A/* 462936SN/A * Handle unexpected EOF. 4635815SN/A */ 4645815SN/Astatic void 4655815SN/Aterminateinput() 4665815SN/A{ 4675815SN/A 4685815SN/A if (gettingfile && curfile.action == USING) { 4695815SN/A printf("Warning: %s %s\n", 470936SN/A "End-of-input encountered while extracting", curfile.name); 471936SN/A } 4729284SN/A curfile.name = "<name unknown>"; 4739284SN/A curfile.action = UNKNOWN; 474 curfile.dip = NULL; 475 curfile.ino = maxino; 476 if (gettingfile) { 477 gettingfile = 0; 478 longjmp(restart, 1); 479 } 480} 481 482/* 483 * handle multiple dumps per tape by skipping forward to the 484 * appropriate one. 485 */ 486static void 487setdumpnum() 488{ 489 struct mtop tcom; 490 491 if (dumpnum == 1 || volno != 1) 492 return; 493 if (pipein) { 494 fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 495 done(1); 496 } 497 tcom.mt_op = MTFSF; 498 tcom.mt_count = dumpnum - 1; 499#ifdef RRESTORE 500 if (host) 501 rmtioctl(MTFSF, dumpnum - 1); 502 else 503#endif 504 if (ioctl(mt, MTIOCTOP, (char *)&tcom) < 0) 505 fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 506} 507 508void 509printdumpinfo() 510{ 511 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); 512 fprintf(stdout, "Dumped from: %s", 513 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate)); 514 if (spcl.c_host[0] == '\0') 515 return; 516 fprintf(stderr, "Level %ld dump of %s on %s:%s\n", 517 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 518 fprintf(stderr, "Label: %s\n", spcl.c_label); 519} 520 521int 522extractfile(name) 523 char *name; 524{ 525 int flags; 526 mode_t mode; 527 struct timeval timep[2]; 528 struct entry *ep; 529 530 curfile.name = name; 531 curfile.action = USING; 532 timep[0].tv_sec = curfile.dip->di_atime; 533 timep[0].tv_usec = curfile.dip->di_atimensec / 1000; 534 timep[1].tv_sec = curfile.dip->di_mtime; 535 timep[1].tv_usec = curfile.dip->di_mtimensec / 1000; 536 mode = curfile.dip->di_mode; 537 flags = curfile.dip->di_flags; 538 switch (mode & IFMT) { 539 540 default: 541 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 542 skipfile(); 543 return (FAIL); 544 545 case IFSOCK: 546 vprintf(stdout, "skipped socket %s\n", name); 547 skipfile(); 548 return (GOOD); 549 550 case IFDIR: 551 if (mflag) { 552 ep = lookupname(name); 553 if (ep == NULL || ep->e_flags & EXTRACT) 554 panic("unextracted directory %s\n", name); 555 skipfile(); 556 return (GOOD); 557 } 558 vprintf(stdout, "extract file %s\n", name); 559 return (genliteraldir(name, curfile.ino)); 560 561 case IFLNK: 562 lnkbuf[0] = '\0'; 563 pathlen = 0; 564 getfile(xtrlnkfile, xtrlnkskip); 565 if (pathlen == 0) { 566 vprintf(stdout, 567 "%s: zero length symbolic link (ignored)\n", name); 568 return (GOOD); 569 } 570 return (linkit(lnkbuf, name, SYMLINK)); 571 572 case IFIFO: 573 vprintf(stdout, "extract fifo %s\n", name); 574 if (Nflag) { 575 skipfile(); 576 return (GOOD); 577 } 578 if (uflag && !Nflag) 579 (void)unlink(name); 580 if (mkfifo(name, mode) < 0) { 581 fprintf(stderr, "%s: cannot create fifo: %s\n", 582 name, strerror(errno)); 583 skipfile(); 584 return (FAIL); 585 } 586 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 587 (void) chmod(name, mode); 588 utimes(name, timep); 589 (void) chflags(name, flags); 590 skipfile(); 591 return (GOOD); 592 593 case IFCHR: 594 case IFBLK: 595 vprintf(stdout, "extract special file %s\n", name); 596 if (Nflag) { 597 skipfile(); 598 return (GOOD); 599 } 600 if (uflag) 601 (void)unlink(name); 602 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { 603 fprintf(stderr, "%s: cannot create special file: %s\n", 604 name, strerror(errno)); 605 skipfile(); 606 return (FAIL); 607 } 608 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 609 (void) chmod(name, mode); 610 utimes(name, timep); 611 (void) chflags(name, flags); 612 skipfile(); 613 return (GOOD); 614 615 case IFREG: 616 vprintf(stdout, "extract file %s\n", name); 617 if (Nflag) { 618 skipfile(); 619 return (GOOD); 620 } 621 if (uflag) 622 (void)unlink(name); 623 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 624 0666)) < 0) { 625 fprintf(stderr, "%s: cannot create file: %s\n", 626 name, strerror(errno)); 627 skipfile(); 628 return (FAIL); 629 } 630 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); 631 (void) fchmod(ofile, mode); 632 getfile(xtrfile, xtrskip); 633 (void) close(ofile); 634 utimes(name, timep); 635 (void) chflags(name, flags); 636 return (GOOD); 637 } 638 /* NOTREACHED */ 639} 640 641/* 642 * skip over bit maps on the tape 643 */ 644void 645skipmaps() 646{ 647 648 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 649 skipfile(); 650} 651 652/* 653 * skip over a file on the tape 654 */ 655void 656skipfile() 657{ 658 659 curfile.action = SKIP; 660 getfile(xtrnull, xtrnull); 661} 662 663/* 664 * Extract a file from the tape. 665 * When an allocated block is found it is passed to the fill function; 666 * when an unallocated block (hole) is found, a zeroed buffer is passed 667 * to the skip function. 668 */ 669void 670getfile(fill, skip) 671 void (*fill) __P((char *, long)); 672 void (*skip) __P((char *, long)); 673{ 674 register int i; 675 int curblk = 0; 676 quad_t size = spcl.c_dinode.di_size; 677 static char clearedbuf[MAXBSIZE]; 678 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 679 char junk[TP_BSIZE]; 680 681 if (spcl.c_type == TS_END) 682 panic("ran off end of tape\n"); 683 if (spcl.c_magic != NFS_MAGIC) 684 panic("not at beginning of a file\n"); 685 if (!gettingfile && setjmp(restart) != 0) 686 return; 687 gettingfile++; 688loop: 689 for (i = 0; i < spcl.c_count; i++) { 690 if (readmapflag || spcl.c_addr[i]) { 691 readtape(&buf[curblk++][0]); 692 if (curblk == fssize / TP_BSIZE) { 693 (*fill)((char *)buf, (long)(size > TP_BSIZE ? 694 fssize : (curblk - 1) * TP_BSIZE + size)); 695 curblk = 0; 696 } 697 } else { 698 if (curblk > 0) { 699 (*fill)((char *)buf, (long)(size > TP_BSIZE ? 700 curblk * TP_BSIZE : 701 (curblk - 1) * TP_BSIZE + size)); 702 curblk = 0; 703 } 704 (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 705 TP_BSIZE : size)); 706 } 707 if ((size -= TP_BSIZE) <= 0) { 708 for (i++; i < spcl.c_count; i++) 709 if (readmapflag || spcl.c_addr[i]) 710 readtape(junk); 711 break; 712 } 713 } 714 if (gethead(&spcl) == GOOD && size > 0) { 715 if (spcl.c_type == TS_ADDR) 716 goto loop; 717 dprintf(stdout, 718 "Missing address (header) block for %s at %ld blocks\n", 719 curfile.name, blksread); 720 } 721 if (curblk > 0) 722 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size)); 723 findinode(&spcl); 724 gettingfile = 0; 725} 726 727/* 728 * Write out the next block of a file. 729 */ 730static void 731xtrfile(buf, size) 732 char *buf; 733 long size; 734{ 735 736 if (Nflag) 737 return; 738 if (write(ofile, buf, (int) size) == -1) { 739 fprintf(stderr, 740 "write error extracting inode %d, name %s\nwrite: %s\n", 741 curfile.ino, curfile.name, strerror(errno)); 742 } 743} 744 745/* 746 * Skip over a hole in a file. 747 */ 748/* ARGSUSED */ 749static void 750xtrskip(buf, size) 751 char *buf; 752 long size; 753{ 754 755 if (lseek(ofile, size, SEEK_CUR) == -1) { 756 fprintf(stderr, 757 "seek error extracting inode %d, name %s\nlseek: %s\n", 758 curfile.ino, curfile.name, strerror(errno)); 759 done(1); 760 } 761} 762 763/* 764 * Collect the next block of a symbolic link. 765 */ 766static void 767xtrlnkfile(buf, size) 768 char *buf; 769 long size; 770{ 771 772 pathlen += size; 773 if (pathlen > MAXPATHLEN) { 774 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 775 curfile.name, lnkbuf, buf, pathlen); 776 done(1); 777 } 778 (void) strcat(lnkbuf, buf); 779} 780 781/* 782 * Skip over a hole in a symbolic link (should never happen). 783 */ 784/* ARGSUSED */ 785static void 786xtrlnkskip(buf, size) 787 char *buf; 788 long size; 789{ 790 791 fprintf(stderr, "unallocated block in symbolic link %s\n", 792 curfile.name); 793 done(1); 794} 795 796/* 797 * Collect the next block of a bit map. 798 */ 799static void 800xtrmap(buf, size) 801 char *buf; 802 long size; 803{ 804 805 memmove(map, buf, size); 806 map += size; 807} 808 809/* 810 * Skip over a hole in a bit map (should never happen). 811 */ 812/* ARGSUSED */ 813static void 814xtrmapskip(buf, size) 815 char *buf; 816 long size; 817{ 818 819 panic("hole in map\n"); 820 map += size; 821} 822 823/* 824 * Noop, when an extraction function is not needed. 825 */ 826/* ARGSUSED */ 827void 828xtrnull(buf, size) 829 char *buf; 830 long size; 831{ 832 833 return; 834} 835 836/* 837 * Read TP_BSIZE blocks from the input. 838 * Handle read errors, and end of media. 839 */ 840static void 841readtape(buf) 842 char *buf; 843{ 844 long rd, newvol, i; 845 int cnt, seek_failed; 846 847 if (blkcnt < numtrec) { 848 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 849 blksread++; 850 tpblksread++; 851 return; 852 } 853 for (i = 0; i < ntrec; i++) 854 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 855 if (numtrec == 0) 856 numtrec = ntrec; 857 cnt = ntrec * TP_BSIZE; 858 rd = 0; 859getmore: 860#ifdef RRESTORE 861 if (host) 862 i = rmtread(&tapebuf[rd], cnt); 863 else 864#endif 865 i = read(mt, &tapebuf[rd], cnt); 866 /* 867 * Check for mid-tape short read error. 868 * If found, skip rest of buffer and start with the next. 869 */ 870 if (!pipein && numtrec < ntrec && i > 0) { 871 dprintf(stdout, "mid-media short read error.\n"); 872 numtrec = ntrec; 873 } 874 /* 875 * Handle partial block read. 876 */ 877 if (pipein && i == 0 && rd > 0) 878 i = rd; 879 else if (i > 0 && i != ntrec * TP_BSIZE) { 880 if (pipein) { 881 rd += i; 882 cnt -= i; 883 if (cnt > 0) 884 goto getmore; 885 i = rd; 886 } else { 887 /* 888 * Short read. Process the blocks read. 889 */ 890 if (i % TP_BSIZE != 0) 891 vprintf(stdout, 892 "partial block read: %ld should be %ld\n", 893 i, ntrec * TP_BSIZE); 894 numtrec = i / TP_BSIZE; 895 } 896 } 897 /* 898 * Handle read error. 899 */ 900 if (i < 0) { 901 fprintf(stderr, "Tape read error while "); 902 switch (curfile.action) { 903 default: 904 fprintf(stderr, "trying to set up tape\n"); 905 break; 906 case UNKNOWN: 907 fprintf(stderr, "trying to resynchronize\n"); 908 break; 909 case USING: 910 fprintf(stderr, "restoring %s\n", curfile.name); 911 break; 912 case SKIP: 913 fprintf(stderr, "skipping over inode %d\n", 914 curfile.ino); 915 break; 916 } 917 if (!yflag && !reply("continue")) 918 done(1); 919 i = ntrec * TP_BSIZE; 920 memset(tapebuf, 0, i); 921#ifdef RRESTORE 922 if (host) 923 seek_failed = (rmtseek(i, 1) < 0); 924 else 925#endif 926 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 927 928 if (seek_failed) { 929 fprintf(stderr, 930 "continuation failed: %s\n", strerror(errno)); 931 done(1); 932 } 933 } 934 /* 935 * Handle end of tape. 936 */ 937 if (i == 0) { 938 vprintf(stdout, "End-of-tape encountered\n"); 939 if (!pipein) { 940 newvol = volno + 1; 941 volno = 0; 942 numtrec = 0; 943 getvol(newvol); 944 readtape(buf); 945 return; 946 } 947 if (rd % TP_BSIZE != 0) 948 panic("partial block read: %d should be %d\n", 949 rd, ntrec * TP_BSIZE); 950 terminateinput(); 951 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 952 } 953 blkcnt = 0; 954 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 955 blksread++; 956 tpblksread++; 957} 958 959static void 960findtapeblksize() 961{ 962 register long i; 963 964 for (i = 0; i < ntrec; i++) 965 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 966 blkcnt = 0; 967#ifdef RRESTORE 968 if (host) 969 i = rmtread(tapebuf, ntrec * TP_BSIZE); 970 else 971#endif 972 i = read(mt, tapebuf, ntrec * TP_BSIZE); 973 974 if (i <= 0) { 975 fprintf(stderr, "tape read error: %s\n", strerror(errno)); 976 done(1); 977 } 978 if (i % TP_BSIZE != 0) { 979 fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 980 i, "is not a multiple of dump block size", TP_BSIZE); 981 done(1); 982 } 983 ntrec = i / TP_BSIZE; 984 numtrec = ntrec; 985 vprintf(stdout, "Tape block size is %ld\n", ntrec); 986} 987 988void 989closemt() 990{ 991 992 if (mt < 0) 993 return; 994#ifdef RRESTORE 995 if (host) 996 rmtclose(); 997 else 998#endif 999 (void) close(mt); 1000} 1001 1002/* 1003 * Read the next block from the tape. 1004 * Check to see if it is one of several vintage headers. 1005 * If it is an old style header, convert it to a new style header. 1006 * If it is not any valid header, return an error. 1007 */ 1008static int 1009gethead(buf) 1010 struct s_spcl *buf; 1011{ 1012 long i; 1013 union { 1014 quad_t qval; 1015 int32_t val[2]; 1016 } qcvt; 1017 union u_ospcl { 1018 char dummy[TP_BSIZE]; 1019 struct s_ospcl { 1020 int32_t c_type; 1021 int32_t c_date; 1022 int32_t c_ddate; 1023 int32_t c_volume; 1024 int32_t c_tapea; 1025 u_short c_inumber; 1026 int32_t c_magic; 1027 int32_t c_checksum; 1028 struct odinode { 1029 unsigned short odi_mode; 1030 u_short odi_nlink; 1031 u_short odi_uid; 1032 u_short odi_gid; 1033 int32_t odi_size; 1034 int32_t odi_rdev; 1035 char odi_addr[36]; 1036 int32_t odi_atime; 1037 int32_t odi_mtime; 1038 int32_t odi_ctime; 1039 } c_dinode; 1040 int32_t c_count; 1041 char c_addr[256]; 1042 } s_ospcl; 1043 } u_ospcl; 1044 1045 if (!cvtflag) { 1046 readtape((char *)buf); 1047 if (buf->c_magic != NFS_MAGIC) { 1048 if (swabl(buf->c_magic) != NFS_MAGIC) 1049 return (FAIL); 1050 if (!Bcvt) { 1051 vprintf(stdout, "Note: Doing Byte swapping\n"); 1052 Bcvt = 1; 1053 } 1054 } 1055 if (checksum((int *)buf) == FAIL) 1056 return (FAIL); 1057 if (Bcvt) { 1058 swabst((u_char *)"8l4s31l", (u_char *)buf); 1059 swabst((u_char *)"l",(u_char *) &buf->c_level); 1060 swabst((u_char *)"2l",(u_char *) &buf->c_flags); 1061 } 1062 goto good; 1063 } 1064 readtape((char *)(&u_ospcl.s_ospcl)); 1065 memset(buf, 0, (long)TP_BSIZE); 1066 buf->c_type = u_ospcl.s_ospcl.c_type; 1067 buf->c_date = u_ospcl.s_ospcl.c_date; 1068 buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 1069 buf->c_volume = u_ospcl.s_ospcl.c_volume; 1070 buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 1071 buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 1072 buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 1073 buf->c_magic = u_ospcl.s_ospcl.c_magic; 1074 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 1075 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 1076 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 1077 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 1078 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; 1079 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 1080 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; 1081 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; 1082 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; 1083 buf->c_count = u_ospcl.s_ospcl.c_count; 1084 memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256); 1085 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || 1086 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) 1087 return(FAIL); 1088 buf->c_magic = NFS_MAGIC; 1089 1090good: 1091 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) && 1092 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) { 1093 qcvt.qval = buf->c_dinode.di_size; 1094 if (qcvt.val[0] || qcvt.val[1]) { 1095 printf("Note: Doing Quad swapping\n"); 1096 Qcvt = 1; 1097 } 1098 } 1099 if (Qcvt) { 1100 qcvt.qval = buf->c_dinode.di_size; 1101 i = qcvt.val[1]; 1102 qcvt.val[1] = qcvt.val[0]; 1103 qcvt.val[0] = i; 1104 buf->c_dinode.di_size = qcvt.qval; 1105 } 1106 readmapflag = 0; 1107 1108 switch (buf->c_type) { 1109 1110 case TS_CLRI: 1111 case TS_BITS: 1112 /* 1113 * Have to patch up missing information in bit map headers 1114 */ 1115 buf->c_inumber = 0; 1116 buf->c_dinode.di_size = buf->c_count * TP_BSIZE; 1117 if (buf->c_count > TP_NINDIR) 1118 readmapflag = 1; 1119 else 1120 for (i = 0; i < buf->c_count; i++) 1121 buf->c_addr[i]++; 1122 break; 1123 1124 case TS_TAPE: 1125 if ((buf->c_flags & DR_NEWINODEFMT) == 0) 1126 oldinofmt = 1; 1127 /* fall through */ 1128 case TS_END: 1129 buf->c_inumber = 0; 1130 break; 1131 1132 case TS_INODE: 1133 case TS_ADDR: 1134 break; 1135 1136 default: 1137 panic("gethead: unknown inode type %d\n", buf->c_type); 1138 break; 1139 } 1140 /* 1141 * If we are restoring a filesystem with old format inodes, 1142 * copy the uid/gid to the new location. 1143 */ 1144 if (oldinofmt) { 1145 buf->c_dinode.di_uid = buf->c_dinode.di_ouid; 1146 buf->c_dinode.di_gid = buf->c_dinode.di_ogid; 1147 } 1148 if (dflag) 1149 accthdr(buf); 1150 return(GOOD); 1151} 1152 1153/* 1154 * Check that a header is where it belongs and predict the next header 1155 */ 1156static void 1157accthdr(header) 1158 struct s_spcl *header; 1159{ 1160 static ino_t previno = 0x7fffffff; 1161 static int prevtype; 1162 static long predict; 1163 long blks, i; 1164 1165 if (header->c_type == TS_TAPE) { 1166 fprintf(stderr, "Volume header (%s inode format) ", 1167 oldinofmt ? "old" : "new"); 1168 if (header->c_firstrec) 1169 fprintf(stderr, "begins with record %ld", 1170 header->c_firstrec); 1171 fprintf(stderr, "\n"); 1172 previno = 0x7fffffff; 1173 return; 1174 } 1175 if (previno == 0x7fffffff) 1176 goto newcalc; 1177 switch (prevtype) { 1178 case TS_BITS: 1179 fprintf(stderr, "Dumped inodes map header"); 1180 break; 1181 case TS_CLRI: 1182 fprintf(stderr, "Used inodes map header"); 1183 break; 1184 case TS_INODE: 1185 fprintf(stderr, "File header, ino %d", previno); 1186 break; 1187 case TS_ADDR: 1188 fprintf(stderr, "File continuation header, ino %d", previno); 1189 break; 1190 case TS_END: 1191 fprintf(stderr, "End of tape header"); 1192 break; 1193 } 1194 if (predict != blksread - 1) 1195 fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 1196 predict, blksread - 1); 1197 fprintf(stderr, "\n"); 1198newcalc: 1199 blks = 0; 1200 if (header->c_type != TS_END) 1201 for (i = 0; i < header->c_count; i++) 1202 if (readmapflag || header->c_addr[i] != 0) 1203 blks++; 1204 predict = blks; 1205 blksread = 0; 1206 prevtype = header->c_type; 1207 previno = header->c_inumber; 1208} 1209 1210/* 1211 * Find an inode header. 1212 * Complain if had to skip, and complain is set. 1213 */ 1214static void 1215findinode(header) 1216 struct s_spcl *header; 1217{ 1218 static long skipcnt = 0; 1219 long i; 1220 char buf[TP_BSIZE]; 1221 1222 curfile.name = "<name unknown>"; 1223 curfile.action = UNKNOWN; 1224 curfile.dip = NULL; 1225 curfile.ino = 0; 1226 do { 1227 if (header->c_magic != NFS_MAGIC) { 1228 skipcnt++; 1229 while (gethead(header) == FAIL || 1230 header->c_date != dumpdate) 1231 skipcnt++; 1232 } 1233 switch (header->c_type) { 1234 1235 case TS_ADDR: 1236 /* 1237 * Skip up to the beginning of the next record 1238 */ 1239 for (i = 0; i < header->c_count; i++) 1240 if (header->c_addr[i]) 1241 readtape(buf); 1242 while (gethead(header) == FAIL || 1243 header->c_date != dumpdate) 1244 skipcnt++; 1245 break; 1246 1247 case TS_INODE: 1248 curfile.dip = &header->c_dinode; 1249 curfile.ino = header->c_inumber; 1250 break; 1251 1252 case TS_END: 1253 curfile.ino = maxino; 1254 break; 1255 1256 case TS_CLRI: 1257 curfile.name = "<file removal list>"; 1258 break; 1259 1260 case TS_BITS: 1261 curfile.name = "<file dump list>"; 1262 break; 1263 1264 case TS_TAPE: 1265 panic("unexpected tape header\n"); 1266 /* NOTREACHED */ 1267 1268 default: 1269 panic("unknown tape header type %d\n", spcl.c_type); 1270 /* NOTREACHED */ 1271 1272 } 1273 } while (header->c_type == TS_ADDR); 1274 if (skipcnt > 0) 1275 fprintf(stderr, "resync restore, skipped %ld blocks\n", 1276 skipcnt); 1277 skipcnt = 0; 1278} 1279 1280static int 1281checksum(buf) 1282 register int *buf; 1283{ 1284 register int i, j; 1285 1286 j = sizeof(union u_spcl) / sizeof(int); 1287 i = 0; 1288 if(!Bcvt) { 1289 do 1290 i += *buf++; 1291 while (--j); 1292 } else { 1293 /* What happens if we want to read restore tapes 1294 for a 16bit int machine??? */ 1295 do 1296 i += swabl(*buf++); 1297 while (--j); 1298 } 1299 1300 if (i != CHECKSUM) { 1301 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 1302 curfile.ino, curfile.name); 1303 return(FAIL); 1304 } 1305 return(GOOD); 1306} 1307 1308#ifdef RRESTORE 1309#if __STDC__ 1310#include <stdarg.h> 1311#else 1312#include <varargs.h> 1313#endif 1314 1315void 1316#if __STDC__ 1317msg(const char *fmt, ...) 1318#else 1319msg(fmt, va_alist) 1320 char *fmt; 1321 va_dcl 1322#endif 1323{ 1324 va_list ap; 1325#if __STDC__ 1326 va_start(ap, fmt); 1327#else 1328 va_start(ap); 1329#endif 1330 (void)vfprintf(stderr, fmt, ap); 1331 va_end(ap); 1332} 1333#endif /* RRESTORE */ 1334 1335static u_char * 1336swabshort(sp, n) 1337 register u_char *sp; 1338 register int n; 1339{ 1340 char c; 1341 1342 while (--n >= 0) { 1343 c = sp[0]; sp[0] = sp[1]; sp[1] = c; 1344 sp += 2; 1345 } 1346 return (sp); 1347} 1348 1349static u_char * 1350swablong(sp, n) 1351 register u_char *sp; 1352 register int n; 1353{ 1354 char c; 1355 1356 while (--n >= 0) { 1357 c = sp[0]; sp[0] = sp[3]; sp[3] = c; 1358 c = sp[2]; sp[2] = sp[1]; sp[1] = c; 1359 sp += 4; 1360 } 1361 return (sp); 1362} 1363 1364void 1365swabst(cp, sp) 1366 register u_char *cp, *sp; 1367{ 1368 int n = 0; 1369 1370 while (*cp) { 1371 switch (*cp) { 1372 case '0': case '1': case '2': case '3': case '4': 1373 case '5': case '6': case '7': case '8': case '9': 1374 n = (n * 10) + (*cp++ - '0'); 1375 continue; 1376 1377 case 's': case 'w': case 'h': 1378 if (n == 0) 1379 n = 1; 1380 sp = swabshort(sp, n); 1381 break; 1382 1383 case 'l': 1384 if (n == 0) 1385 n = 1; 1386 sp = swablong(sp, n); 1387 break; 1388 1389 default: /* Any other character, like 'b' counts as byte. */ 1390 if (n == 0) 1391 n = 1; 1392 sp += n; 1393 break; 1394 } 1395 cp++; 1396 n = 0; 1397 } 1398} 1399 1400static u_long 1401swabl(x) 1402 u_long x; 1403{ 1404 swabst((u_char *)"l", (u_char *)&x); 1405 return (x); 1406} 1407