xref: /original-bsd/sbin/restore/tape.c (revision 7123cb22)
16426961fSdist /*
25f8b5756Sbostic  * Copyright (c) 1983, 1993
35f8b5756Sbostic  *	The Regents of the University of California.  All rights reserved.
42d438a85Sbostic  * (c) UNIX System Laboratories, Inc.
52d438a85Sbostic  * All or some portions of this file are derived from material licensed
62d438a85Sbostic  * to the University of California by American Telephone and Telegraph
72d438a85Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
82d438a85Sbostic  * the permission of UNIX System Laboratories, Inc.
9179758f1Sbostic  *
10fb448fe7Sbostic  * %sccs.include.redist.c%
116426961fSdist  */
12711b0b98Smckusick 
136426961fSdist #ifndef lint
14*7123cb22Smckusick static char sccsid[] = "@(#)tape.c	8.9 (Berkeley) 05/01/95";
15179758f1Sbostic #endif /* not lint */
16150f930bSsam 
17e786d8ceSbostic #include <sys/param.h>
18e786d8ceSbostic #include <sys/file.h>
19711b0b98Smckusick #include <sys/ioctl.h>
20711b0b98Smckusick #include <sys/mtio.h>
218eb28771Ssam #include <sys/stat.h>
22e786d8ceSbostic 
23e786d8ceSbostic #include <ufs/ufs/dinode.h>
24e786d8ceSbostic #include <protocols/dumprestore.h>
25e786d8ceSbostic 
26e786d8ceSbostic #include <errno.h>
27e786d8ceSbostic #include <setjmp.h>
28e786d8ceSbostic #include <stdio.h>
29e786d8ceSbostic #include <stdlib.h>
30e786d8ceSbostic #include <string.h>
31e786d8ceSbostic #include <unistd.h>
32e786d8ceSbostic 
33e786d8ceSbostic #include "restore.h"
34e786d8ceSbostic #include "extern.h"
3503b38d59Sbostic #include "pathnames.h"
36711b0b98Smckusick 
37167a9d62Smckusick static long	fssize = MAXBSIZE;
383c0c659fSmckusick static int	mt = -1;
393c0c659fSmckusick static int	pipein = 0;
4091b7679cSmckusick static char	magtape[BUFSIZ];
4144d805ceSmckusick static int	blkcnt;
423c778ad6Smckusick static int	numtrec;
4344d805ceSmckusick static char	*tapebuf;
443c0c659fSmckusick static union	u_spcl endoftapemark;
45aad233d8Smckusick static long	blksread;		/* blocks read since last header */
4652a32e52Smckusick static long	tpblksread = 0;		/* TP_BSIZE blocks read */
47f0f93cf0Smckusick static long	tapesread;
483c0c659fSmckusick static jmp_buf	restart;
493c0c659fSmckusick static int	gettingfile = 0;	/* restart has a valid frame */
50aad233d8Smckusick static char	*host = NULL;
51711b0b98Smckusick 
523c0c659fSmckusick static int	ofile;
533c0c659fSmckusick static char	*map;
543c0c659fSmckusick static char	lnkbuf[MAXPATHLEN + 1];
553c0c659fSmckusick static int	pathlen;
56711b0b98Smckusick 
5724259a59Smckusick int		oldinofmt;	/* old inode format conversion required */
58f7e6f5f8Ssklower int		Bcvt;		/* Swap Bytes (for CCI or sun) */
59f7e6f5f8Ssklower static int	Qcvt;		/* Swap quads (for sun) */
60aad233d8Smckusick 
6144d805ceSmckusick #define	FLUSHTAPEBUF()	blkcnt = ntrec + 1
6244d805ceSmckusick 
63e786d8ceSbostic static void	 accthdr __P((struct s_spcl *));
64e786d8ceSbostic static int	 checksum __P((int *));
65e786d8ceSbostic static void	 findinode __P((struct s_spcl *));
66e786d8ceSbostic static void	 findtapeblksize __P((void));
67e786d8ceSbostic static int	 gethead __P((struct s_spcl *));
68e786d8ceSbostic static void	 readtape __P((char *));
69e786d8ceSbostic static void	 setdumpnum __P((void));
70e786d8ceSbostic static u_long	 swabl __P((u_long));
71e786d8ceSbostic static u_char	*swablong __P((u_char *, int));
72e786d8ceSbostic static u_char	*swabshort __P((u_char *, int));
73e786d8ceSbostic static void	 terminateinput __P((void));
74e786d8ceSbostic static void	 xtrfile __P((char *, long));
75e786d8ceSbostic static void	 xtrlnkfile __P((char *, long));
76e786d8ceSbostic static void	 xtrlnkskip __P((char *, long));
77e786d8ceSbostic static void	 xtrmap __P((char *, long));
78e786d8ceSbostic static void	 xtrmapskip __P((char *, long));
79e786d8ceSbostic static void	 xtrskip __P((char *, long));
80e786d8ceSbostic 
81711b0b98Smckusick /*
82711b0b98Smckusick  * Set up an input source
83711b0b98Smckusick  */
84e786d8ceSbostic void
setinput(source)85711b0b98Smckusick setinput(source)
86711b0b98Smckusick 	char *source;
87711b0b98Smckusick {
8844d805ceSmckusick 	FLUSHTAPEBUF();
8964b996e7Smckusick 	if (bflag)
9064b996e7Smckusick 		newtapebuf(ntrec);
9164b996e7Smckusick 	else
9264b996e7Smckusick 		newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
93213e2460Smckusick 	terminal = stdin;
94aad233d8Smckusick 
952e472962Smckusick #ifdef RRESTORE
96608bde00Sbostic 	if (strchr(source, ':')) {
97711b0b98Smckusick 		host = source;
98608bde00Sbostic 		source = strchr(host, ':');
99aad233d8Smckusick 		*source++ = '\0';
100711b0b98Smckusick 		if (rmthost(host) == 0)
101711b0b98Smckusick 			done(1);
102aad233d8Smckusick 	} else
103aad233d8Smckusick #endif
104213e2460Smckusick 	if (strcmp(source, "-") == 0) {
105103ba4deSmckusick 		/*
106103ba4deSmckusick 		 * Since input is coming from a pipe we must establish
107103ba4deSmckusick 		 * our own connection to the terminal.
108103ba4deSmckusick 		 */
10903b38d59Sbostic 		terminal = fopen(_PATH_TTY, "r");
110103ba4deSmckusick 		if (terminal == NULL) {
111e786d8ceSbostic 			(void)fprintf(stderr, "cannot open %s: %s\n",
11203b38d59Sbostic 			    _PATH_TTY, strerror(errno));
11303b38d59Sbostic 			terminal = fopen(_PATH_DEVNULL, "r");
114e40fb7ddSmckusick 			if (terminal == NULL) {
115e786d8ceSbostic 				(void)fprintf(stderr, "cannot open %s: %s\n",
11603b38d59Sbostic 				    _PATH_DEVNULL, strerror(errno));
117103ba4deSmckusick 				done(1);
118103ba4deSmckusick 			}
119e40fb7ddSmckusick 		}
1203c0c659fSmckusick 		pipein++;
1213c0c659fSmckusick 	}
122aad233d8Smckusick 	setuid(getuid());	/* no longer need or want root privileges */
12391b7679cSmckusick 	(void) strcpy(magtape, source);
124711b0b98Smckusick }
125711b0b98Smckusick 
126e786d8ceSbostic void
newtapebuf(size)12764b996e7Smckusick newtapebuf(size)
12864b996e7Smckusick 	long size;
12964b996e7Smckusick {
13044d805ceSmckusick 	static tapebufsize = -1;
13164b996e7Smckusick 
13264b996e7Smckusick 	ntrec = size;
13344d805ceSmckusick 	if (size <= tapebufsize)
13464b996e7Smckusick 		return;
13544d805ceSmckusick 	if (tapebuf != NULL)
13644d805ceSmckusick 		free(tapebuf);
137e786d8ceSbostic 	tapebuf = malloc(size * TP_BSIZE);
13844d805ceSmckusick 	if (tapebuf == NULL) {
13964b996e7Smckusick 		fprintf(stderr, "Cannot allocate space for tape buffer\n");
14064b996e7Smckusick 		done(1);
14164b996e7Smckusick 	}
14244d805ceSmckusick 	tapebufsize = size;
14364b996e7Smckusick }
14464b996e7Smckusick 
145711b0b98Smckusick /*
146711b0b98Smckusick  * Verify that the tape drive can be accessed and
147711b0b98Smckusick  * that it actually is a dump tape.
148711b0b98Smckusick  */
149e786d8ceSbostic void
setup()150711b0b98Smckusick setup()
151711b0b98Smckusick {
1523c0c659fSmckusick 	int i, j, *ip;
153711b0b98Smckusick 	struct stat stbuf;
154711b0b98Smckusick 
155711b0b98Smckusick 	vprintf(stdout, "Verify tape and initialize maps\n");
1562e472962Smckusick #ifdef RRESTORE
157aad233d8Smckusick 	if (host)
158086b8d64Sbostic 		mt = rmtopen(magtape, 0);
159aad233d8Smckusick 	else
160aad233d8Smckusick #endif
1613c0c659fSmckusick 	if (pipein)
1623c0c659fSmckusick 		mt = 0;
163aad233d8Smckusick 	else
164e786d8ceSbostic 		mt = open(magtape, O_RDONLY, 0);
165aad233d8Smckusick 	if (mt < 0) {
166e786d8ceSbostic 		fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
167711b0b98Smckusick 		done(1);
168711b0b98Smckusick 	}
1692c6546ceSmckusick 	volno = 1;
1702c6546ceSmckusick 	setdumpnum();
17144d805ceSmckusick 	FLUSHTAPEBUF();
17264b996e7Smckusick 	if (!pipein && !bflag)
17364b996e7Smckusick 		findtapeblksize();
174e6690a1dSmckusick 	if (gethead(&spcl) == FAIL) {
17544d805ceSmckusick 		blkcnt--; /* push back this block */
176aad233d8Smckusick 		blksread--;
17752a32e52Smckusick 		tpblksread--;
178711b0b98Smckusick 		cvtflag++;
179e6690a1dSmckusick 		if (gethead(&spcl) == FAIL) {
180711b0b98Smckusick 			fprintf(stderr, "Tape is not a dump tape\n");
181711b0b98Smckusick 			done(1);
182711b0b98Smckusick 		}
183711b0b98Smckusick 		fprintf(stderr, "Converting to new file system format.\n");
184711b0b98Smckusick 	}
1853c0c659fSmckusick 	if (pipein) {
1863c0c659fSmckusick 		endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
1873c0c659fSmckusick 		endoftapemark.s_spcl.c_type = TS_END;
1883c0c659fSmckusick 		ip = (int *)&endoftapemark;
1893c0c659fSmckusick 		j = sizeof(union u_spcl) / sizeof(int);
1903c0c659fSmckusick 		i = 0;
1913c0c659fSmckusick 		do
1923c0c659fSmckusick 			i += *ip++;
1933c0c659fSmckusick 		while (--j);
1943c0c659fSmckusick 		endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
1953c0c659fSmckusick 	}
1966591ccf8Smckusick 	if (vflag || command == 't')
1976591ccf8Smckusick 		printdumpinfo();
198711b0b98Smckusick 	dumptime = spcl.c_ddate;
1993c0c659fSmckusick 	dumpdate = spcl.c_date;
200711b0b98Smckusick 	if (stat(".", &stbuf) < 0) {
201e786d8ceSbostic 		fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
202711b0b98Smckusick 		done(1);
203711b0b98Smckusick 	}
204167a9d62Smckusick 	if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
205711b0b98Smckusick 		fssize = stbuf.st_blksize;
206167a9d62Smckusick 	if (((fssize - 1) & fssize) != 0) {
207711b0b98Smckusick 		fprintf(stderr, "bad block size %d\n", fssize);
208711b0b98Smckusick 		done(1);
209711b0b98Smckusick 	}
21044d805ceSmckusick 	if (spcl.c_volume != 1) {
211711b0b98Smckusick 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
212711b0b98Smckusick 		done(1);
213711b0b98Smckusick 	}
21444d805ceSmckusick 	if (gethead(&spcl) == FAIL) {
21544d805ceSmckusick 		dprintf(stdout, "header read failed at %d blocks\n", blksread);
2163c0c659fSmckusick 		panic("no header after volume mark!\n");
21744d805ceSmckusick 	}
2186591ccf8Smckusick 	findinode(&spcl);
21944d805ceSmckusick 	if (spcl.c_type != TS_CLRI) {
220711b0b98Smckusick 		fprintf(stderr, "Cannot find file removal list\n");
221711b0b98Smckusick 		done(1);
222711b0b98Smckusick 	}
2233c0c659fSmckusick 	maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
2242c6546ceSmckusick 	dprintf(stdout, "maxino = %d\n", maxino);
22566947ca7Smckusick 	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
226e786d8ceSbostic 	if (map == NULL)
2273b2bb250Smckusick 		panic("no memory for active inode map\n");
2283b2bb250Smckusick 	usedinomap = map;
229711b0b98Smckusick 	curfile.action = USING;
230711b0b98Smckusick 	getfile(xtrmap, xtrmapskip);
23144d805ceSmckusick 	if (spcl.c_type != TS_BITS) {
232711b0b98Smckusick 		fprintf(stderr, "Cannot find file dump list\n");
233711b0b98Smckusick 		done(1);
234711b0b98Smckusick 	}
23566947ca7Smckusick 	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
236711b0b98Smckusick 	if (map == (char *)NULL)
237711b0b98Smckusick 		panic("no memory for file dump list\n");
238877a77f3Smckusick 	dumpmap = map;
239711b0b98Smckusick 	curfile.action = USING;
240711b0b98Smckusick 	getfile(xtrmap, xtrmapskip);
24119b02dc7Smckusick 	/*
24219b02dc7Smckusick 	 * If there may be whiteout entries on the tape, pretend that the
24319b02dc7Smckusick 	 * whiteout inode exists, so that the whiteout entries can be
24419b02dc7Smckusick 	 * extracted.
24519b02dc7Smckusick 	 */
24619b02dc7Smckusick 	if (oldinofmt == 0)
24719b02dc7Smckusick 		SETINO(WINO, dumpmap);
248711b0b98Smckusick }
249711b0b98Smckusick 
250f0f93cf0Smckusick /*
251f0f93cf0Smckusick  * Prompt user to load a new dump volume.
252f0f93cf0Smckusick  * "Nextvol" is the next suggested volume to use.
253f0f93cf0Smckusick  * This suggested volume is enforced when doing full
254f0f93cf0Smckusick  * or incremental restores, but can be overrridden by
255f0f93cf0Smckusick  * the user when only extracting a subset of the files.
256f0f93cf0Smckusick  */
257e786d8ceSbostic void
getvol(nextvol)258711b0b98Smckusick getvol(nextvol)
259711b0b98Smckusick 	long nextvol;
260711b0b98Smckusick {
26152a32e52Smckusick 	long newvol, savecnt, wantnext, i;
262711b0b98Smckusick 	union u_spcl tmpspcl;
263711b0b98Smckusick #	define tmpbuf tmpspcl.s_spcl
2646591ccf8Smckusick 	char buf[TP_BSIZE];
265711b0b98Smckusick 
266dbf6ba0aSmckusick 	if (nextvol == 1) {
267f0f93cf0Smckusick 		tapesread = 0;
268dbf6ba0aSmckusick 		gettingfile = 0;
269dbf6ba0aSmckusick 	}
2703c0c659fSmckusick 	if (pipein) {
2716370a777Smckusick 		if (nextvol != 1)
2723c0c659fSmckusick 			panic("Changing volumes on pipe input?\n");
2736370a777Smckusick 		if (volno == 1)
2743c0c659fSmckusick 			return;
2756370a777Smckusick 		goto gethdr;
2763c0c659fSmckusick 	}
2773c0c659fSmckusick 	savecnt = blksread;
278711b0b98Smckusick again:
2796370a777Smckusick 	if (pipein)
2806370a777Smckusick 		done(1); /* pipes do not get a second chance */
28152a32e52Smckusick 	if (command == 'R' || command == 'r' || curfile.action != SKIP) {
282711b0b98Smckusick 		newvol = nextvol;
28352a32e52Smckusick 		wantnext = 1;
28452a32e52Smckusick 	} else {
285711b0b98Smckusick 		newvol = 0;
28652a32e52Smckusick 		wantnext = 0;
28752a32e52Smckusick 	}
288711b0b98Smckusick 	while (newvol <= 0) {
289f0f93cf0Smckusick 		if (tapesread == 0) {
290f0f93cf0Smckusick 			fprintf(stderr, "%s%s%s%s%s",
291f0f93cf0Smckusick 			    "You have not read any tapes yet.\n",
292f0f93cf0Smckusick 			    "Unless you know which volume your",
293f0f93cf0Smckusick 			    " file(s) are on you should start\n",
294f0f93cf0Smckusick 			    "with the last volume and work",
295f7e6f5f8Ssklower 			    " towards towards the first.\n");
296f0f93cf0Smckusick 		} else {
297f0f93cf0Smckusick 			fprintf(stderr, "You have read volumes");
29844d805ceSmckusick 			strcpy(buf, ": ");
299f0f93cf0Smckusick 			for (i = 1; i < 32; i++)
300f0f93cf0Smckusick 				if (tapesread & (1 << i)) {
30144d805ceSmckusick 					fprintf(stderr, "%s%d", buf, i);
30244d805ceSmckusick 					strcpy(buf, ", ");
303f0f93cf0Smckusick 				}
304f0f93cf0Smckusick 			fprintf(stderr, "\n");
305f0f93cf0Smckusick 		}
306f73bbb4eSmckusick 		do	{
307103ba4deSmckusick 			fprintf(stderr, "Specify next volume #: ");
308103ba4deSmckusick 			(void) fflush(stderr);
30944d805ceSmckusick 			(void) fgets(buf, BUFSIZ, terminal);
31044d805ceSmckusick 		} while (!feof(terminal) && buf[0] == '\n');
311103ba4deSmckusick 		if (feof(terminal))
312f73bbb4eSmckusick 			done(1);
31344d805ceSmckusick 		newvol = atoi(buf);
314711b0b98Smckusick 		if (newvol <= 0) {
315711b0b98Smckusick 			fprintf(stderr,
316711b0b98Smckusick 			    "Volume numbers are positive numerics\n");
317711b0b98Smckusick 		}
318711b0b98Smckusick 	}
319f0f93cf0Smckusick 	if (newvol == volno) {
320f0f93cf0Smckusick 		tapesread |= 1 << volno;
321711b0b98Smckusick 		return;
322f0f93cf0Smckusick 	}
323711b0b98Smckusick 	closemt();
32491b7679cSmckusick 	fprintf(stderr, "Mount tape volume %d\n", newvol);
325135f3f2dSmckusick 	fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
326135f3f2dSmckusick 	fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
327103ba4deSmckusick 	(void) fflush(stderr);
32844d805ceSmckusick 	(void) fgets(buf, BUFSIZ, terminal);
329e40fb7ddSmckusick 	if (feof(terminal))
330e40fb7ddSmckusick 		done(1);
33144d805ceSmckusick 	if (!strcmp(buf, "none\n")) {
332fcea58adSmckusick 		terminateinput();
333fcea58adSmckusick 		return;
334135f3f2dSmckusick 	}
33544d805ceSmckusick 	if (buf[0] != '\n') {
33644d805ceSmckusick 		(void) strcpy(magtape, buf);
33791b7679cSmckusick 		magtape[strlen(magtape) - 1] = '\0';
33891b7679cSmckusick 	}
3392e472962Smckusick #ifdef RRESTORE
340aad233d8Smckusick 	if (host)
341aad233d8Smckusick 		mt = rmtopen(magtape, 0);
342aad233d8Smckusick 	else
343711b0b98Smckusick #endif
344e786d8ceSbostic 		mt = open(magtape, O_RDONLY, 0);
345aad233d8Smckusick 
346aad233d8Smckusick 	if (mt == -1) {
34791b7679cSmckusick 		fprintf(stderr, "Cannot open %s\n", magtape);
34891b7679cSmckusick 		volno = -1;
349711b0b98Smckusick 		goto again;
350711b0b98Smckusick 	}
3516370a777Smckusick gethdr:
352711b0b98Smckusick 	volno = newvol;
3532c6546ceSmckusick 	setdumpnum();
35444d805ceSmckusick 	FLUSHTAPEBUF();
35544d805ceSmckusick 	if (gethead(&tmpbuf) == FAIL) {
35644d805ceSmckusick 		dprintf(stdout, "header read failed at %d blocks\n", blksread);
357711b0b98Smckusick 		fprintf(stderr, "tape is not dump tape\n");
358711b0b98Smckusick 		volno = 0;
359711b0b98Smckusick 		goto again;
360711b0b98Smckusick 	}
361ad52e9c7Smckusick 	if (tmpbuf.c_volume != volno) {
362711b0b98Smckusick 		fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
363711b0b98Smckusick 		volno = 0;
364711b0b98Smckusick 		goto again;
365711b0b98Smckusick 	}
3663c0c659fSmckusick 	if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
36711931016Smckusick 		fprintf(stderr, "Wrong dump date\n\tgot: %s",
36811931016Smckusick 			ctime(&tmpbuf.c_date));
36911931016Smckusick 		fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
3703c0c659fSmckusick 		volno = 0;
3713c0c659fSmckusick 		goto again;
3723c0c659fSmckusick 	}
373f0f93cf0Smckusick 	tapesread |= 1 << volno;
374e6690a1dSmckusick 	blksread = savecnt;
37552a32e52Smckusick  	/*
37652a32e52Smckusick  	 * If continuing from the previous volume, skip over any
37752a32e52Smckusick  	 * blocks read already at the end of the previous volume.
37852a32e52Smckusick  	 *
37952a32e52Smckusick  	 * If coming to this volume at random, skip to the beginning
38052a32e52Smckusick  	 * of the next record.
38152a32e52Smckusick  	 */
38252a32e52Smckusick 	dprintf(stdout, "read %ld recs, tape starts with %ld\n",
38352a32e52Smckusick 		tpblksread, tmpbuf.c_firstrec);
38452a32e52Smckusick  	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
38552a32e52Smckusick  		if (!wantnext) {
38652a32e52Smckusick  			tpblksread = tmpbuf.c_firstrec;
38752a32e52Smckusick  			for (i = tmpbuf.c_count; i > 0; i--)
38852a32e52Smckusick  				readtape(buf);
38952a32e52Smckusick  		} else if (tmpbuf.c_firstrec > 0 &&
39052a32e52Smckusick 			   tmpbuf.c_firstrec < tpblksread - 1) {
39152a32e52Smckusick 			/*
39252a32e52Smckusick 			 * -1 since we've read the volume header
39352a32e52Smckusick 			 */
39452a32e52Smckusick  			i = tpblksread - tmpbuf.c_firstrec - 1;
39552a32e52Smckusick 			dprintf(stderr, "Skipping %d duplicate record%s.\n",
39652a32e52Smckusick 				i, i > 1 ? "s" : "");
39752a32e52Smckusick  			while (--i >= 0)
39852a32e52Smckusick  				readtape(buf);
39952a32e52Smckusick  		}
40052a32e52Smckusick  	}
401711b0b98Smckusick 	if (curfile.action == USING) {
402711b0b98Smckusick 		if (volno == 1)
403711b0b98Smckusick 			panic("active file into volume 1\n");
404711b0b98Smckusick 		return;
405711b0b98Smckusick 	}
4066591ccf8Smckusick 	/*
4076591ccf8Smckusick 	 * Skip up to the beginning of the next record
4086591ccf8Smckusick 	 */
4090b0d351eSmckusick 	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
4106591ccf8Smckusick 		for (i = tmpbuf.c_count; i > 0; i--)
4116591ccf8Smckusick 			readtape(buf);
412e6690a1dSmckusick 	(void) gethead(&spcl);
4136591ccf8Smckusick 	findinode(&spcl);
414711b0b98Smckusick 	if (gettingfile) {
415711b0b98Smckusick 		gettingfile = 0;
416711b0b98Smckusick 		longjmp(restart, 1);
417711b0b98Smckusick 	}
418711b0b98Smckusick }
419711b0b98Smckusick 
4202c6546ceSmckusick /*
421fcea58adSmckusick  * Handle unexpected EOF.
422fcea58adSmckusick  */
423e786d8ceSbostic static void
terminateinput()424fcea58adSmckusick terminateinput()
425fcea58adSmckusick {
426fcea58adSmckusick 
427fcea58adSmckusick 	if (gettingfile && curfile.action == USING) {
428fcea58adSmckusick 		printf("Warning: %s %s\n",
429fcea58adSmckusick 		    "End-of-input encountered while extracting", curfile.name);
430fcea58adSmckusick 	}
431fcea58adSmckusick 	curfile.name = "<name unknown>";
432fcea58adSmckusick 	curfile.action = UNKNOWN;
433e786d8ceSbostic 	curfile.dip = NULL;
434fcea58adSmckusick 	curfile.ino = maxino;
435fcea58adSmckusick 	if (gettingfile) {
436fcea58adSmckusick 		gettingfile = 0;
437fcea58adSmckusick 		longjmp(restart, 1);
438fcea58adSmckusick 	}
439fcea58adSmckusick }
440fcea58adSmckusick 
441fcea58adSmckusick /*
4422c6546ceSmckusick  * handle multiple dumps per tape by skipping forward to the
4432c6546ceSmckusick  * appropriate one.
4442c6546ceSmckusick  */
445e786d8ceSbostic static void
setdumpnum()4462c6546ceSmckusick setdumpnum()
4472c6546ceSmckusick {
4482c6546ceSmckusick 	struct mtop tcom;
4492c6546ceSmckusick 
4502c6546ceSmckusick 	if (dumpnum == 1 || volno != 1)
4512c6546ceSmckusick 		return;
4522c6546ceSmckusick 	if (pipein) {
4532c6546ceSmckusick 		fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
4542c6546ceSmckusick 		done(1);
4552c6546ceSmckusick 	}
4562c6546ceSmckusick 	tcom.mt_op = MTFSF;
4572c6546ceSmckusick 	tcom.mt_count = dumpnum - 1;
4582e472962Smckusick #ifdef RRESTORE
459aad233d8Smckusick 	if (host)
4602c6546ceSmckusick 		rmtioctl(MTFSF, dumpnum - 1);
461aad233d8Smckusick 	else
462aad233d8Smckusick #endif
463f73bbb4eSmckusick 		if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
464e786d8ceSbostic 			fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
4652c6546ceSmckusick }
4662c6546ceSmckusick 
467e786d8ceSbostic void
printdumpinfo()4686591ccf8Smckusick printdumpinfo()
4696591ccf8Smckusick {
4706591ccf8Smckusick 	fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
471655e2ee3Smckusick 	fprintf(stdout, "Dumped from: %s",
472655e2ee3Smckusick 	    (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
4736591ccf8Smckusick 	if (spcl.c_host[0] == '\0')
4746591ccf8Smckusick 		return;
4756591ccf8Smckusick 	fprintf(stderr, "Level %d dump of %s on %s:%s\n",
4766591ccf8Smckusick 		spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
4776591ccf8Smckusick 	fprintf(stderr, "Label: %s\n", spcl.c_label);
4786591ccf8Smckusick }
4796591ccf8Smckusick 
480e786d8ceSbostic int
extractfile(name)481711b0b98Smckusick extractfile(name)
482711b0b98Smckusick 	char *name;
483711b0b98Smckusick {
484af59b353Smckusick 	int flags;
485af59b353Smckusick 	mode_t mode;
48663cb96feSmckusick 	struct timeval timep[2];
487711b0b98Smckusick 	struct entry *ep;
488711b0b98Smckusick 
489711b0b98Smckusick 	curfile.name = name;
490711b0b98Smckusick 	curfile.action = USING;
491*7123cb22Smckusick 	timep[0].tv_sec = curfile.dip->di_atime;
492*7123cb22Smckusick 	timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
493*7123cb22Smckusick 	timep[1].tv_sec = curfile.dip->di_mtime;
494*7123cb22Smckusick 	timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
495711b0b98Smckusick 	mode = curfile.dip->di_mode;
496af59b353Smckusick 	flags = curfile.dip->di_flags;
497711b0b98Smckusick 	switch (mode & IFMT) {
498711b0b98Smckusick 
499711b0b98Smckusick 	default:
500711b0b98Smckusick 		fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
501711b0b98Smckusick 		skipfile();
502711b0b98Smckusick 		return (FAIL);
503711b0b98Smckusick 
504670a5108Smckusick 	case IFSOCK:
505670a5108Smckusick 		vprintf(stdout, "skipped socket %s\n", name);
506670a5108Smckusick 		skipfile();
507670a5108Smckusick 		return (GOOD);
508670a5108Smckusick 
509711b0b98Smckusick 	case IFDIR:
510711b0b98Smckusick 		if (mflag) {
511711b0b98Smckusick 			ep = lookupname(name);
512e786d8ceSbostic 			if (ep == NULL || ep->e_flags & EXTRACT)
513711b0b98Smckusick 				panic("unextracted directory %s\n", name);
514711b0b98Smckusick 			skipfile();
515711b0b98Smckusick 			return (GOOD);
516711b0b98Smckusick 		}
517711b0b98Smckusick 		vprintf(stdout, "extract file %s\n", name);
518711b0b98Smckusick 		return (genliteraldir(name, curfile.ino));
519711b0b98Smckusick 
520711b0b98Smckusick 	case IFLNK:
521711b0b98Smckusick 		lnkbuf[0] = '\0';
522711b0b98Smckusick 		pathlen = 0;
523711b0b98Smckusick 		getfile(xtrlnkfile, xtrlnkskip);
524711b0b98Smckusick 		if (pathlen == 0) {
525711b0b98Smckusick 			vprintf(stdout,
526711b0b98Smckusick 			    "%s: zero length symbolic link (ignored)\n", name);
527711b0b98Smckusick 			return (GOOD);
528167a9d62Smckusick 		}
529167a9d62Smckusick 		return (linkit(lnkbuf, name, SYMLINK));
530711b0b98Smckusick 
531711b0b98Smckusick 	case IFCHR:
532711b0b98Smckusick 	case IFBLK:
533711b0b98Smckusick 		vprintf(stdout, "extract special file %s\n", name);
534677df798Smckusick 		if (Nflag) {
535677df798Smckusick 			skipfile();
536677df798Smckusick 			return (GOOD);
537677df798Smckusick 		}
538711b0b98Smckusick 		if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
539e786d8ceSbostic 			fprintf(stderr, "%s: cannot create special file: %s\n",
540e786d8ceSbostic 			    name, strerror(errno));
541711b0b98Smckusick 			skipfile();
542711b0b98Smckusick 			return (FAIL);
543711b0b98Smckusick 		}
5442c6546ceSmckusick 		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
5452c6546ceSmckusick 		(void) chmod(name, mode);
546af59b353Smckusick 		(void) chflags(name, flags);
547af59b353Smckusick 		skipfile();
548af59b353Smckusick 		utimes(name, timep);
549af59b353Smckusick 		return (GOOD);
550af59b353Smckusick 
551af59b353Smckusick 	case IFIFO:
552af59b353Smckusick 		vprintf(stdout, "extract fifo %s\n", name);
553af59b353Smckusick 		if (Nflag) {
554af59b353Smckusick 			skipfile();
555af59b353Smckusick 			return (GOOD);
556af59b353Smckusick 		}
557af59b353Smckusick 		if (mkfifo(name, mode) < 0) {
558af59b353Smckusick 			fprintf(stderr, "%s: cannot create fifo: %s\n",
559af59b353Smckusick 			    name, strerror(errno));
560af59b353Smckusick 			skipfile();
561af59b353Smckusick 			return (FAIL);
562af59b353Smckusick 		}
563af59b353Smckusick 		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
564af59b353Smckusick 		(void) chmod(name, mode);
565af59b353Smckusick 		(void) chflags(name, flags);
566711b0b98Smckusick 		skipfile();
56763cb96feSmckusick 		utimes(name, timep);
568711b0b98Smckusick 		return (GOOD);
569711b0b98Smckusick 
570711b0b98Smckusick 	case IFREG:
571711b0b98Smckusick 		vprintf(stdout, "extract file %s\n", name);
572677df798Smckusick 		if (Nflag) {
573677df798Smckusick 			skipfile();
574677df798Smckusick 			return (GOOD);
575677df798Smckusick 		}
576608bde00Sbostic 		if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
577608bde00Sbostic 		    0666)) < 0) {
578e786d8ceSbostic 			fprintf(stderr, "%s: cannot create file: %s\n",
579e786d8ceSbostic 			    name, strerror(errno));
580711b0b98Smckusick 			skipfile();
581711b0b98Smckusick 			return (FAIL);
582711b0b98Smckusick 		}
5832c6546ceSmckusick 		(void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
5842c6546ceSmckusick 		(void) fchmod(ofile, mode);
585af59b353Smckusick 		(void) fchflags(ofile, flags);
586711b0b98Smckusick 		getfile(xtrfile, xtrskip);
5872c6546ceSmckusick 		(void) close(ofile);
58863cb96feSmckusick 		utimes(name, timep);
589711b0b98Smckusick 		return (GOOD);
590711b0b98Smckusick 	}
591711b0b98Smckusick 	/* NOTREACHED */
592711b0b98Smckusick }
593711b0b98Smckusick 
5946370a777Smckusick /*
5956370a777Smckusick  * skip over bit maps on the tape
5966370a777Smckusick  */
597e786d8ceSbostic void
skipmaps()5986370a777Smckusick skipmaps()
5996370a777Smckusick {
6006370a777Smckusick 
60144d805ceSmckusick 	while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
6026370a777Smckusick 		skipfile();
6036370a777Smckusick }
6046370a777Smckusick 
6056370a777Smckusick /*
6066370a777Smckusick  * skip over a file on the tape
6076370a777Smckusick  */
608e786d8ceSbostic void
skipfile()609711b0b98Smckusick skipfile()
610711b0b98Smckusick {
611711b0b98Smckusick 
612711b0b98Smckusick 	curfile.action = SKIP;
61344d805ceSmckusick 	getfile(xtrnull, xtrnull);
614711b0b98Smckusick }
615711b0b98Smckusick 
616711b0b98Smckusick /*
61744d805ceSmckusick  * Extract a file from the tape.
61844d805ceSmckusick  * When an allocated block is found it is passed to the fill function;
61944d805ceSmckusick  * when an unallocated block (hole) is found, a zeroed buffer is passed
62044d805ceSmckusick  * to the skip function.
621711b0b98Smckusick  */
622e786d8ceSbostic void
62344d805ceSmckusick getfile(fill, skip)
624e786d8ceSbostic 	void	(*fill) __P((char *, long));
625e786d8ceSbostic 	void	(*skip) __P((char *, long));
626711b0b98Smckusick {
627711b0b98Smckusick 	register int i;
628711b0b98Smckusick 	int curblk = 0;
6290f2a59f8Smckusick 	quad_t size = spcl.c_dinode.di_size;
630711b0b98Smckusick 	static char clearedbuf[MAXBSIZE];
631711b0b98Smckusick 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
63280f15c7fSmckusick 	char junk[TP_BSIZE];
633711b0b98Smckusick 
63444d805ceSmckusick 	if (spcl.c_type == TS_END)
635711b0b98Smckusick 		panic("ran off end of tape\n");
63644d805ceSmckusick 	if (spcl.c_magic != NFS_MAGIC)
637711b0b98Smckusick 		panic("not at beginning of a file\n");
6386370a777Smckusick 	if (!gettingfile && setjmp(restart) != 0)
639711b0b98Smckusick 		return;
640711b0b98Smckusick 	gettingfile++;
641711b0b98Smckusick loop:
642711b0b98Smckusick 	for (i = 0; i < spcl.c_count; i++) {
643711b0b98Smckusick 		if (spcl.c_addr[i]) {
644711b0b98Smckusick 			readtape(&buf[curblk++][0]);
645711b0b98Smckusick 			if (curblk == fssize / TP_BSIZE) {
6460f2a59f8Smckusick 				(*fill)((char *)buf, (long)(size > TP_BSIZE ?
6470f2a59f8Smckusick 				     fssize : (curblk - 1) * TP_BSIZE + size));
648711b0b98Smckusick 				curblk = 0;
649711b0b98Smckusick 			}
650711b0b98Smckusick 		} else {
651711b0b98Smckusick 			if (curblk > 0) {
6520f2a59f8Smckusick 				(*fill)((char *)buf, (long)(size > TP_BSIZE ?
6530f2a59f8Smckusick 				     curblk * TP_BSIZE :
6540f2a59f8Smckusick 				     (curblk - 1) * TP_BSIZE + size));
655711b0b98Smckusick 				curblk = 0;
656711b0b98Smckusick 			}
6570f2a59f8Smckusick 			(*skip)(clearedbuf, (long)(size > TP_BSIZE ?
6580f2a59f8Smckusick 				TP_BSIZE : size));
659711b0b98Smckusick 		}
66080f15c7fSmckusick 		if ((size -= TP_BSIZE) <= 0) {
66180f15c7fSmckusick 			for (i++; i < spcl.c_count; i++)
66280f15c7fSmckusick 				if (spcl.c_addr[i])
66380f15c7fSmckusick 					readtape(junk);
66461d42042Smckusick 			break;
665711b0b98Smckusick 		}
66680f15c7fSmckusick 	}
66744d805ceSmckusick 	if (gethead(&spcl) == GOOD && size > 0) {
66844d805ceSmckusick 		if (spcl.c_type == TS_ADDR)
66961d42042Smckusick 			goto loop;
67044d805ceSmckusick 		dprintf(stdout,
67144d805ceSmckusick 			"Missing address (header) block for %s at %d blocks\n",
67244d805ceSmckusick 			curfile.name, blksread);
673711b0b98Smckusick 	}
67461d42042Smckusick 	if (curblk > 0)
6750f2a59f8Smckusick 		(*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
6766591ccf8Smckusick 	findinode(&spcl);
677711b0b98Smckusick 	gettingfile = 0;
678711b0b98Smckusick }
679711b0b98Smckusick 
680711b0b98Smckusick /*
68144d805ceSmckusick  * Write out the next block of a file.
682711b0b98Smckusick  */
683e786d8ceSbostic static void
xtrfile(buf,size)684711b0b98Smckusick xtrfile(buf, size)
685711b0b98Smckusick 	char	*buf;
686711b0b98Smckusick 	long	size;
687711b0b98Smckusick {
688711b0b98Smckusick 
689677df798Smckusick 	if (Nflag)
690677df798Smckusick 		return;
691711b0b98Smckusick 	if (write(ofile, buf, (int) size) == -1) {
692e786d8ceSbostic 		fprintf(stderr,
693e786d8ceSbostic 		    "write error extracting inode %d, name %s\nwrite: %s\n",
694e786d8ceSbostic 			curfile.ino, curfile.name, strerror(errno));
695711b0b98Smckusick 		done(1);
696711b0b98Smckusick 	}
697711b0b98Smckusick }
698711b0b98Smckusick 
69944d805ceSmckusick /*
70044d805ceSmckusick  * Skip over a hole in a file.
70144d805ceSmckusick  */
70244d805ceSmckusick /* ARGSUSED */
703e786d8ceSbostic static void
xtrskip(buf,size)704711b0b98Smckusick xtrskip(buf, size)
705711b0b98Smckusick 	char *buf;
706711b0b98Smckusick 	long size;
707711b0b98Smckusick {
708711b0b98Smckusick 
7098b833fe8Sbostic 	if (lseek(ofile, size, SEEK_CUR) == -1) {
710e786d8ceSbostic 		fprintf(stderr,
711e786d8ceSbostic 		    "seek error extracting inode %d, name %s\nlseek: %s\n",
712e786d8ceSbostic 			curfile.ino, curfile.name, strerror(errno));
713711b0b98Smckusick 		done(1);
714711b0b98Smckusick 	}
715711b0b98Smckusick }
716711b0b98Smckusick 
71744d805ceSmckusick /*
71844d805ceSmckusick  * Collect the next block of a symbolic link.
71944d805ceSmckusick  */
720e786d8ceSbostic static void
xtrlnkfile(buf,size)721711b0b98Smckusick xtrlnkfile(buf, size)
722711b0b98Smckusick 	char	*buf;
723711b0b98Smckusick 	long	size;
724711b0b98Smckusick {
725711b0b98Smckusick 
726711b0b98Smckusick 	pathlen += size;
727711b0b98Smckusick 	if (pathlen > MAXPATHLEN) {
728711b0b98Smckusick 		fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
729711b0b98Smckusick 		    curfile.name, lnkbuf, buf, pathlen);
730711b0b98Smckusick 		done(1);
731711b0b98Smckusick 	}
732f73bbb4eSmckusick 	(void) strcat(lnkbuf, buf);
733711b0b98Smckusick }
734711b0b98Smckusick 
73544d805ceSmckusick /*
73644d805ceSmckusick  * Skip over a hole in a symbolic link (should never happen).
73744d805ceSmckusick  */
73844d805ceSmckusick /* ARGSUSED */
739e786d8ceSbostic static void
xtrlnkskip(buf,size)740711b0b98Smckusick xtrlnkskip(buf, size)
741711b0b98Smckusick 	char *buf;
742711b0b98Smckusick 	long size;
743711b0b98Smckusick {
744711b0b98Smckusick 
745711b0b98Smckusick 	fprintf(stderr, "unallocated block in symbolic link %s\n",
746711b0b98Smckusick 		curfile.name);
747711b0b98Smckusick 	done(1);
748711b0b98Smckusick }
749711b0b98Smckusick 
75044d805ceSmckusick /*
75144d805ceSmckusick  * Collect the next block of a bit map.
75244d805ceSmckusick  */
753e786d8ceSbostic static void
xtrmap(buf,size)754711b0b98Smckusick xtrmap(buf, size)
755711b0b98Smckusick 	char	*buf;
756711b0b98Smckusick 	long	size;
757711b0b98Smckusick {
758711b0b98Smckusick 
759608bde00Sbostic 	memmove(map, buf, size);
760877a77f3Smckusick 	map += size;
761711b0b98Smckusick }
762711b0b98Smckusick 
76344d805ceSmckusick /*
76444d805ceSmckusick  * Skip over a hole in a bit map (should never happen).
76544d805ceSmckusick  */
76644d805ceSmckusick /* ARGSUSED */
767e786d8ceSbostic static void
xtrmapskip(buf,size)768711b0b98Smckusick xtrmapskip(buf, size)
769711b0b98Smckusick 	char *buf;
770711b0b98Smckusick 	long size;
771711b0b98Smckusick {
772711b0b98Smckusick 
773711b0b98Smckusick 	panic("hole in map\n");
774877a77f3Smckusick 	map += size;
775711b0b98Smckusick }
776711b0b98Smckusick 
77744d805ceSmckusick /*
77844d805ceSmckusick  * Noop, when an extraction function is not needed.
77944d805ceSmckusick  */
78044d805ceSmckusick /* ARGSUSED */
781e786d8ceSbostic void
xtrnull(buf,size)78244d805ceSmckusick xtrnull(buf, size)
78344d805ceSmckusick 	char *buf;
78444d805ceSmckusick 	long size;
78544d805ceSmckusick {
78644d805ceSmckusick 
78744d805ceSmckusick 	return;
78844d805ceSmckusick }
789711b0b98Smckusick 
790711b0b98Smckusick /*
79144d805ceSmckusick  * Read TP_BSIZE blocks from the input.
79244d805ceSmckusick  * Handle read errors, and end of media.
793711b0b98Smckusick  */
794e786d8ceSbostic static void
readtape(buf)79544d805ceSmckusick readtape(buf)
79644d805ceSmckusick 	char *buf;
797711b0b98Smckusick {
79844d805ceSmckusick 	long rd, newvol, i;
79944d805ceSmckusick 	int cnt, seek_failed;
800711b0b98Smckusick 
80144d805ceSmckusick 	if (blkcnt < numtrec) {
802608bde00Sbostic 		memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
80364b996e7Smckusick 		blksread++;
80452a32e52Smckusick 		tpblksread++;
80564b996e7Smckusick 		return;
80664b996e7Smckusick 	}
807181ffc32Smckusick 	for (i = 0; i < ntrec; i++)
80844d805ceSmckusick 		((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
8093c778ad6Smckusick 	if (numtrec == 0)
8103c778ad6Smckusick 		numtrec = ntrec;
811181ffc32Smckusick 	cnt = ntrec * TP_BSIZE;
8120b027efeSmckusick 	rd = 0;
8130b027efeSmckusick getmore:
8142e472962Smckusick #ifdef RRESTORE
815aad233d8Smckusick 	if (host)
81644d805ceSmckusick 		i = rmtread(&tapebuf[rd], cnt);
817aad233d8Smckusick 	else
818711b0b98Smckusick #endif
81944d805ceSmckusick 		i = read(mt, &tapebuf[rd], cnt);
8203c778ad6Smckusick 	/*
8213c778ad6Smckusick 	 * Check for mid-tape short read error.
822aad233d8Smckusick 	 * If found, skip rest of buffer and start with the next.
8233c778ad6Smckusick 	 */
824aad233d8Smckusick 	if (!pipein && numtrec < ntrec && i > 0) {
825aad233d8Smckusick 		dprintf(stdout, "mid-media short read error.\n");
8263c778ad6Smckusick 		numtrec = ntrec;
8273c778ad6Smckusick 	}
8283c778ad6Smckusick 	/*
8293c778ad6Smckusick 	 * Handle partial block read.
8303c778ad6Smckusick 	 */
8319f0d31b3Smckusick 	if (pipein && i == 0 && rd > 0)
8329f0d31b3Smckusick 		i = rd;
8339f0d31b3Smckusick 	else if (i > 0 && i != ntrec * TP_BSIZE) {
83464b996e7Smckusick 		if (pipein) {
8350b027efeSmckusick 			rd += i;
8360b027efeSmckusick 			cnt -= i;
8370b027efeSmckusick 			if (cnt > 0)
8380b027efeSmckusick 				goto getmore;
8390b027efeSmckusick 			i = rd;
84064b996e7Smckusick 		} else {
841aad233d8Smckusick 			/*
842aad233d8Smckusick 			 * Short read. Process the blocks read.
843aad233d8Smckusick 			 */
84464b996e7Smckusick 			if (i % TP_BSIZE != 0)
845aad233d8Smckusick 				vprintf(stdout,
846aad233d8Smckusick 				    "partial block read: %d should be %d\n",
84764b996e7Smckusick 				    i, ntrec * TP_BSIZE);
8483c778ad6Smckusick 			numtrec = i / TP_BSIZE;
84964b996e7Smckusick 		}
8500b027efeSmckusick 	}
8513c778ad6Smckusick 	/*
8523c778ad6Smckusick 	 * Handle read error.
8533c778ad6Smckusick 	 */
8540b027efeSmckusick 	if (i < 0) {
855711b0b98Smckusick 		fprintf(stderr, "Tape read error while ");
856711b0b98Smckusick 		switch (curfile.action) {
8570b027efeSmckusick 		default:
8580b027efeSmckusick 			fprintf(stderr, "trying to set up tape\n");
8590b027efeSmckusick 			break;
860711b0b98Smckusick 		case UNKNOWN:
861295dbe20Smckusick 			fprintf(stderr, "trying to resynchronize\n");
862711b0b98Smckusick 			break;
863711b0b98Smckusick 		case USING:
864711b0b98Smckusick 			fprintf(stderr, "restoring %s\n", curfile.name);
865711b0b98Smckusick 			break;
866711b0b98Smckusick 		case SKIP:
867711b0b98Smckusick 			fprintf(stderr, "skipping over inode %d\n",
868711b0b98Smckusick 				curfile.ino);
869711b0b98Smckusick 			break;
870711b0b98Smckusick 		}
871711b0b98Smckusick 		if (!yflag && !reply("continue"))
872711b0b98Smckusick 			done(1);
873181ffc32Smckusick 		i = ntrec * TP_BSIZE;
874608bde00Sbostic 		memset(tapebuf, 0, i);
8752e472962Smckusick #ifdef RRESTORE
876aad233d8Smckusick 		if (host)
877aad233d8Smckusick 			seek_failed = (rmtseek(i, 1) < 0);
878aad233d8Smckusick 		else
879711b0b98Smckusick #endif
880e786d8ceSbostic 			seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
881aad233d8Smckusick 
882aad233d8Smckusick 		if (seek_failed) {
883e786d8ceSbostic 			fprintf(stderr,
884e786d8ceSbostic 			    "continuation failed: %s\n", strerror(errno));
885711b0b98Smckusick 			done(1);
886711b0b98Smckusick 		}
887711b0b98Smckusick 	}
8883c778ad6Smckusick 	/*
8893c778ad6Smckusick 	 * Handle end of tape.
8903c778ad6Smckusick 	 */
891711b0b98Smckusick 	if (i == 0) {
892aad233d8Smckusick 		vprintf(stdout, "End-of-tape encountered\n");
89331fed6adSmckusick 		if (!pipein) {
894711b0b98Smckusick 			newvol = volno + 1;
895711b0b98Smckusick 			volno = 0;
8963c778ad6Smckusick 			numtrec = 0;
897711b0b98Smckusick 			getvol(newvol);
89844d805ceSmckusick 			readtape(buf);
899711b0b98Smckusick 			return;
900711b0b98Smckusick 		}
90131fed6adSmckusick 		if (rd % TP_BSIZE != 0)
90231fed6adSmckusick 			panic("partial block read: %d should be %d\n",
90331fed6adSmckusick 				rd, ntrec * TP_BSIZE);
904fcea58adSmckusick 		terminateinput();
905608bde00Sbostic 		memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
90631fed6adSmckusick 	}
90744d805ceSmckusick 	blkcnt = 0;
908608bde00Sbostic 	memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
9093c0c659fSmckusick 	blksread++;
91052a32e52Smckusick 	tpblksread++;
911711b0b98Smckusick }
912711b0b98Smckusick 
913e786d8ceSbostic static void
findtapeblksize()91464b996e7Smckusick findtapeblksize()
91564b996e7Smckusick {
91664b996e7Smckusick 	register long i;
91764b996e7Smckusick 
91864b996e7Smckusick 	for (i = 0; i < ntrec; i++)
91944d805ceSmckusick 		((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
92044d805ceSmckusick 	blkcnt = 0;
92164b996e7Smckusick #ifdef RRESTORE
922aad233d8Smckusick 	if (host)
92344d805ceSmckusick 		i = rmtread(tapebuf, ntrec * TP_BSIZE);
924aad233d8Smckusick 	else
92564b996e7Smckusick #endif
92644d805ceSmckusick 		i = read(mt, tapebuf, ntrec * TP_BSIZE);
927aad233d8Smckusick 
92864b996e7Smckusick 	if (i <= 0) {
929e786d8ceSbostic 		fprintf(stderr, "tape read error: %s\n", strerror(errno));
93064b996e7Smckusick 		done(1);
93164b996e7Smckusick 	}
93264b996e7Smckusick 	if (i % TP_BSIZE != 0) {
93364b996e7Smckusick 		fprintf(stderr, "Tape block size (%d) %s (%d)\n",
93464b996e7Smckusick 			i, "is not a multiple of dump block size", TP_BSIZE);
93564b996e7Smckusick 		done(1);
93664b996e7Smckusick 	}
93764b996e7Smckusick 	ntrec = i / TP_BSIZE;
9383c778ad6Smckusick 	numtrec = ntrec;
93964b996e7Smckusick 	vprintf(stdout, "Tape block size is %d\n", ntrec);
94064b996e7Smckusick }
94164b996e7Smckusick 
942e786d8ceSbostic void
closemt()943711b0b98Smckusick closemt()
944711b0b98Smckusick {
94544d805ceSmckusick 
946711b0b98Smckusick 	if (mt < 0)
947711b0b98Smckusick 		return;
9482e472962Smckusick #ifdef RRESTORE
949aad233d8Smckusick 	if (host)
950711b0b98Smckusick 		rmtclose();
951aad233d8Smckusick 	else
952711b0b98Smckusick #endif
953aad233d8Smckusick 		(void) close(mt);
954711b0b98Smckusick }
955711b0b98Smckusick 
956711b0b98Smckusick /*
95744d805ceSmckusick  * Read the next block from the tape.
95844d805ceSmckusick  * Check to see if it is one of several vintage headers.
95944d805ceSmckusick  * If it is an old style header, convert it to a new style header.
96044d805ceSmckusick  * If it is not any valid header, return an error.
961711b0b98Smckusick  */
962e786d8ceSbostic static int
gethead(buf)963711b0b98Smckusick gethead(buf)
964711b0b98Smckusick 	struct s_spcl *buf;
965711b0b98Smckusick {
966135f3f2dSmckusick 	long i;
96704c26334Smckusick 	union {
96804c26334Smckusick 		quad_t	qval;
96904c26334Smckusick 		long	val[2];
97004c26334Smckusick 	} qcvt;
971711b0b98Smckusick 	union u_ospcl {
972711b0b98Smckusick 		char dummy[TP_BSIZE];
973711b0b98Smckusick 		struct	s_ospcl {
9743c0c659fSmckusick 			long	c_type;
9753c0c659fSmckusick 			long	c_date;
9763c0c659fSmckusick 			long	c_ddate;
9773c0c659fSmckusick 			long	c_volume;
9783c0c659fSmckusick 			long	c_tapea;
979877a77f3Smckusick 			u_short	c_inumber;
9803c0c659fSmckusick 			long	c_magic;
9813c0c659fSmckusick 			long	c_checksum;
982711b0b98Smckusick 			struct odinode {
983711b0b98Smckusick 				unsigned short odi_mode;
984877a77f3Smckusick 				u_short	odi_nlink;
985877a77f3Smckusick 				u_short	odi_uid;
986877a77f3Smckusick 				u_short	odi_gid;
9873c0c659fSmckusick 				long	odi_size;
9883c0c659fSmckusick 				long	odi_rdev;
989711b0b98Smckusick 				char	odi_addr[36];
9903c0c659fSmckusick 				long	odi_atime;
9913c0c659fSmckusick 				long	odi_mtime;
9923c0c659fSmckusick 				long	odi_ctime;
993711b0b98Smckusick 			} c_dinode;
9943c0c659fSmckusick 			long	c_count;
9953c0c659fSmckusick 			char	c_addr[256];
996711b0b98Smckusick 		} s_ospcl;
997711b0b98Smckusick 	} u_ospcl;
998711b0b98Smckusick 
999711b0b98Smckusick 	if (!cvtflag) {
1000711b0b98Smckusick 		readtape((char *)buf);
1001f7e6f5f8Ssklower 		if (buf->c_magic != NFS_MAGIC) {
1002f7e6f5f8Ssklower 			if (swabl(buf->c_magic) != NFS_MAGIC)
10033c0c659fSmckusick 				return (FAIL);
1004f7e6f5f8Ssklower 			if (!Bcvt) {
1005f7e6f5f8Ssklower 				vprintf(stdout, "Note: Doing Byte swapping\n");
1006f7e6f5f8Ssklower 				Bcvt = 1;
1007f7e6f5f8Ssklower 			}
1008f7e6f5f8Ssklower 		}
1009f7e6f5f8Ssklower 		if (checksum((int *)buf) == FAIL)
1010f7e6f5f8Ssklower 			return (FAIL);
1011f7e6f5f8Ssklower 		if (Bcvt)
1012e786d8ceSbostic 			swabst((u_char *)"8l4s31l", (u_char *)buf);
1013e6690a1dSmckusick 		goto good;
1014711b0b98Smckusick 	}
1015711b0b98Smckusick 	readtape((char *)(&u_ospcl.s_ospcl));
1016608bde00Sbostic 	memset(buf, 0, (long)TP_BSIZE);
1017711b0b98Smckusick 	buf->c_type = u_ospcl.s_ospcl.c_type;
1018711b0b98Smckusick 	buf->c_date = u_ospcl.s_ospcl.c_date;
1019711b0b98Smckusick 	buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1020711b0b98Smckusick 	buf->c_volume = u_ospcl.s_ospcl.c_volume;
1021711b0b98Smckusick 	buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1022711b0b98Smckusick 	buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1023711b0b98Smckusick 	buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1024711b0b98Smckusick 	buf->c_magic = u_ospcl.s_ospcl.c_magic;
1025711b0b98Smckusick 	buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1026711b0b98Smckusick 	buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1027711b0b98Smckusick 	buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1028711b0b98Smckusick 	buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1029711b0b98Smckusick 	buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1030711b0b98Smckusick 	buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1031*7123cb22Smckusick 	buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1032*7123cb22Smckusick 	buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1033*7123cb22Smckusick 	buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1034711b0b98Smckusick 	buf->c_count = u_ospcl.s_ospcl.c_count;
1035608bde00Sbostic 	memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1036711b0b98Smckusick 	if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1037e6690a1dSmckusick 	    checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
10383c0c659fSmckusick 		return(FAIL);
1039711b0b98Smckusick 	buf->c_magic = NFS_MAGIC;
1040e6690a1dSmckusick 
1041e6690a1dSmckusick good:
10420b80bffbSmckusick 	if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1043f7e6f5f8Ssklower 	    (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
104404c26334Smckusick 		qcvt.qval = buf->c_dinode.di_size;
104504c26334Smckusick 		if (qcvt.val[0] || qcvt.val[1]) {
1046f7e6f5f8Ssklower 			printf("Note: Doing Quad swapping\n");
1047f7e6f5f8Ssklower 			Qcvt = 1;
1048f7e6f5f8Ssklower 		}
1049f7e6f5f8Ssklower 	}
1050f7e6f5f8Ssklower 	if (Qcvt) {
105104c26334Smckusick 		qcvt.qval = buf->c_dinode.di_size;
105204c26334Smckusick 		i = qcvt.val[1];
105304c26334Smckusick 		qcvt.val[1] = qcvt.val[0];
105404c26334Smckusick 		qcvt.val[0] = i;
1055a7a62901Smckusick 		buf->c_dinode.di_size = qcvt.qval;
1056f7e6f5f8Ssklower 	}
1057aad233d8Smckusick 
1058e6690a1dSmckusick 	switch (buf->c_type) {
1059e6690a1dSmckusick 
1060e6690a1dSmckusick 	case TS_CLRI:
1061e6690a1dSmckusick 	case TS_BITS:
1062e6690a1dSmckusick 		/*
1063e6690a1dSmckusick 		 * Have to patch up missing information in bit map headers
1064e6690a1dSmckusick 		 */
1065e6690a1dSmckusick 		buf->c_inumber = 0;
1066e6690a1dSmckusick 		buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1067e6690a1dSmckusick 		for (i = 0; i < buf->c_count; i++)
1068e6690a1dSmckusick 			buf->c_addr[i]++;
1069e6690a1dSmckusick 		break;
1070e6690a1dSmckusick 
1071e6690a1dSmckusick 	case TS_TAPE:
107224259a59Smckusick 		if ((buf->c_flags & DR_NEWINODEFMT) == 0)
107324259a59Smckusick 			oldinofmt = 1;
107424259a59Smckusick 		/* fall through */
1075e6690a1dSmckusick 	case TS_END:
1076e6690a1dSmckusick 		buf->c_inumber = 0;
1077e6690a1dSmckusick 		break;
1078e6690a1dSmckusick 
1079e6690a1dSmckusick 	case TS_INODE:
1080e6690a1dSmckusick 	case TS_ADDR:
1081e6690a1dSmckusick 		break;
1082e6690a1dSmckusick 
1083e6690a1dSmckusick 	default:
1084e6690a1dSmckusick 		panic("gethead: unknown inode type %d\n", buf->c_type);
1085e6690a1dSmckusick 		break;
1086e6690a1dSmckusick 	}
108724259a59Smckusick 	/*
108824259a59Smckusick 	 * If we are restoring a filesystem with old format inodes,
108924259a59Smckusick 	 * copy the uid/gid to the new location.
109024259a59Smckusick 	 */
109124259a59Smckusick 	if (oldinofmt) {
109224259a59Smckusick 		buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
109324259a59Smckusick 		buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
109424259a59Smckusick 	}
10953c0c659fSmckusick 	if (dflag)
10963c0c659fSmckusick 		accthdr(buf);
10973c0c659fSmckusick 	return(GOOD);
10983c0c659fSmckusick }
10993c0c659fSmckusick 
11003c0c659fSmckusick /*
11013c0c659fSmckusick  * Check that a header is where it belongs and predict the next header
11023c0c659fSmckusick  */
1103e786d8ceSbostic static void
accthdr(header)11043c0c659fSmckusick accthdr(header)
11053c0c659fSmckusick 	struct s_spcl *header;
11063c0c659fSmckusick {
110766947ca7Smckusick 	static ino_t previno = 0x7fffffff;
11083c0c659fSmckusick 	static int prevtype;
11093c0c659fSmckusick 	static long predict;
11103c0c659fSmckusick 	long blks, i;
11113c0c659fSmckusick 
11120b0d351eSmckusick 	if (header->c_type == TS_TAPE) {
11134ad48669Smckusick 		fprintf(stderr, "Volume header (%s inode format) ",
11144ad48669Smckusick 		    oldinofmt ? "old" : "new");
111552a32e52Smckusick  		if (header->c_firstrec)
111652a32e52Smckusick  			fprintf(stderr, "begins with record %d",
111752a32e52Smckusick  				header->c_firstrec);
111852a32e52Smckusick  		fprintf(stderr, "\n");
1119ad8f41e5Smckusick 		previno = 0x7fffffff;
1120e6690a1dSmckusick 		return;
1121e6690a1dSmckusick 	}
112266947ca7Smckusick 	if (previno == 0x7fffffff)
11233c0c659fSmckusick 		goto newcalc;
11243c0c659fSmckusick 	switch (prevtype) {
11253c0c659fSmckusick 	case TS_BITS:
11263b2bb250Smckusick 		fprintf(stderr, "Dumped inodes map header");
11273c0c659fSmckusick 		break;
11283c0c659fSmckusick 	case TS_CLRI:
11293b2bb250Smckusick 		fprintf(stderr, "Used inodes map header");
11303c0c659fSmckusick 		break;
11313c0c659fSmckusick 	case TS_INODE:
1132e6690a1dSmckusick 		fprintf(stderr, "File header, ino %d", previno);
11333c0c659fSmckusick 		break;
11343c0c659fSmckusick 	case TS_ADDR:
1135e6690a1dSmckusick 		fprintf(stderr, "File continuation header, ino %d", previno);
11363c0c659fSmckusick 		break;
11373c0c659fSmckusick 	case TS_END:
1138e6690a1dSmckusick 		fprintf(stderr, "End of tape header");
11393c0c659fSmckusick 		break;
11403c0c659fSmckusick 	}
11413c0c659fSmckusick 	if (predict != blksread - 1)
11423c0c659fSmckusick 		fprintf(stderr, "; predicted %d blocks, got %d blocks",
11433c0c659fSmckusick 			predict, blksread - 1);
11443c0c659fSmckusick 	fprintf(stderr, "\n");
11453c0c659fSmckusick newcalc:
11463c0c659fSmckusick 	blks = 0;
1147e6690a1dSmckusick 	if (header->c_type != TS_END)
11483c0c659fSmckusick 		for (i = 0; i < header->c_count; i++)
11493c0c659fSmckusick 			if (header->c_addr[i] != 0)
11503c0c659fSmckusick 				blks++;
11513c0c659fSmckusick 	predict = blks;
11523c0c659fSmckusick 	blksread = 0;
11533c0c659fSmckusick 	prevtype = header->c_type;
11543c0c659fSmckusick 	previno = header->c_inumber;
1155711b0b98Smckusick }
1156711b0b98Smckusick 
1157711b0b98Smckusick /*
1158711b0b98Smckusick  * Find an inode header.
1159711b0b98Smckusick  * Complain if had to skip, and complain is set.
1160711b0b98Smckusick  */
1161e786d8ceSbostic static void
findinode(header)11626591ccf8Smckusick findinode(header)
1163711b0b98Smckusick 	struct s_spcl *header;
1164711b0b98Smckusick {
11653c0c659fSmckusick 	static long skipcnt = 0;
1166ad8f41e5Smckusick 	long i;
1167ad8f41e5Smckusick 	char buf[TP_BSIZE];
1168711b0b98Smckusick 
1169711b0b98Smckusick 	curfile.name = "<name unknown>";
1170711b0b98Smckusick 	curfile.action = UNKNOWN;
1171e786d8ceSbostic 	curfile.dip = NULL;
1172711b0b98Smckusick 	curfile.ino = 0;
117344d805ceSmckusick 	do {
117444d805ceSmckusick 		if (header->c_magic != NFS_MAGIC) {
1175711b0b98Smckusick 			skipcnt++;
117644d805ceSmckusick 			while (gethead(header) == FAIL ||
117744d805ceSmckusick 			    header->c_date != dumpdate)
11783c0c659fSmckusick 				skipcnt++;
11793c0c659fSmckusick 		}
118044d805ceSmckusick 		switch (header->c_type) {
118144d805ceSmckusick 
118244d805ceSmckusick 		case TS_ADDR:
1183ad8f41e5Smckusick 			/*
1184ad8f41e5Smckusick 			 * Skip up to the beginning of the next record
1185ad8f41e5Smckusick 			 */
1186ad8f41e5Smckusick 			for (i = 0; i < header->c_count; i++)
1187ad8f41e5Smckusick 				if (header->c_addr[i])
1188ad8f41e5Smckusick 					readtape(buf);
118944d805ceSmckusick 			while (gethead(header) == FAIL ||
119044d805ceSmckusick 			    header->c_date != dumpdate)
119144d805ceSmckusick 				skipcnt++;
119244d805ceSmckusick 			break;
119344d805ceSmckusick 
119444d805ceSmckusick 		case TS_INODE:
1195711b0b98Smckusick 			curfile.dip = &header->c_dinode;
1196711b0b98Smckusick 			curfile.ino = header->c_inumber;
1197711b0b98Smckusick 			break;
119844d805ceSmckusick 
119944d805ceSmckusick 		case TS_END:
1200711b0b98Smckusick 			curfile.ino = maxino;
1201711b0b98Smckusick 			break;
120244d805ceSmckusick 
120344d805ceSmckusick 		case TS_CLRI:
1204711b0b98Smckusick 			curfile.name = "<file removal list>";
1205711b0b98Smckusick 			break;
120644d805ceSmckusick 
120744d805ceSmckusick 		case TS_BITS:
1208711b0b98Smckusick 			curfile.name = "<file dump list>";
1209711b0b98Smckusick 			break;
121044d805ceSmckusick 
121144d805ceSmckusick 		case TS_TAPE:
121244d805ceSmckusick 			panic("unexpected tape header\n");
121344d805ceSmckusick 			/* NOTREACHED */
121444d805ceSmckusick 
121544d805ceSmckusick 		default:
121644d805ceSmckusick 			panic("unknown tape header type %d\n", spcl.c_type);
121744d805ceSmckusick 			/* NOTREACHED */
121844d805ceSmckusick 
1219711b0b98Smckusick 		}
122044d805ceSmckusick 	} while (header->c_type == TS_ADDR);
12216591ccf8Smckusick 	if (skipcnt > 0)
1222fc5757e5Smckusick 		fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
1223711b0b98Smckusick 	skipcnt = 0;
1224711b0b98Smckusick }
1225711b0b98Smckusick 
1226e786d8ceSbostic static int
checksum(buf)122744d805ceSmckusick checksum(buf)
122844d805ceSmckusick 	register int *buf;
1229711b0b98Smckusick {
1230711b0b98Smckusick 	register int i, j;
1231711b0b98Smckusick 
1232711b0b98Smckusick 	j = sizeof(union u_spcl) / sizeof(int);
1233711b0b98Smckusick 	i = 0;
1234f7e6f5f8Ssklower 	if(!Bcvt) {
1235711b0b98Smckusick 		do
123644d805ceSmckusick 			i += *buf++;
1237711b0b98Smckusick 		while (--j);
1238f7e6f5f8Ssklower 	} else {
1239f7e6f5f8Ssklower 		/* What happens if we want to read restore tapes
1240f7e6f5f8Ssklower 			for a 16bit int machine??? */
1241f7e6f5f8Ssklower 		do
124244d805ceSmckusick 			i += swabl(*buf++);
1243f7e6f5f8Ssklower 		while (--j);
1244f7e6f5f8Ssklower 	}
1245f7e6f5f8Ssklower 
1246711b0b98Smckusick 	if (i != CHECKSUM) {
1247711b0b98Smckusick 		fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1248711b0b98Smckusick 			curfile.ino, curfile.name);
12493c0c659fSmckusick 		return(FAIL);
1250711b0b98Smckusick 	}
12513c0c659fSmckusick 	return(GOOD);
1252711b0b98Smckusick }
1253711b0b98Smckusick 
12542e472962Smckusick #ifdef RRESTORE
1255e786d8ceSbostic #if __STDC__
1256e786d8ceSbostic #include <stdarg.h>
1257e786d8ceSbostic #else
1258e786d8ceSbostic #include <varargs.h>
1259e786d8ceSbostic #endif
1260711b0b98Smckusick 
1261e786d8ceSbostic void
1262e786d8ceSbostic #if __STDC__
msg(const char * fmt,...)1263e786d8ceSbostic msg(const char *fmt, ...)
1264e786d8ceSbostic #else
1265e786d8ceSbostic msg(fmt, va_alist)
1266e786d8ceSbostic 	char *fmt;
1267e786d8ceSbostic 	va_dcl
1268e786d8ceSbostic #endif
1269e786d8ceSbostic {
1270e786d8ceSbostic 	va_list ap;
1271e786d8ceSbostic #if __STDC__
1272e786d8ceSbostic 	va_start(ap, fmt);
1273e786d8ceSbostic #else
1274e786d8ceSbostic 	va_start(ap);
1275e786d8ceSbostic #endif
1276e786d8ceSbostic 	(void)vfprintf(stderr, fmt, ap);
1277e786d8ceSbostic 	va_end(ap);
1278711b0b98Smckusick }
1279aad233d8Smckusick #endif /* RRESTORE */
1280f7e6f5f8Ssklower 
1281e786d8ceSbostic static u_char *
swabshort(sp,n)12820062352bSmckusick swabshort(sp, n)
12830062352bSmckusick 	register u_char *sp;
12840062352bSmckusick 	register int n;
12850062352bSmckusick {
12860062352bSmckusick 	char c;
12870062352bSmckusick 
12880062352bSmckusick 	while (--n >= 0) {
12890062352bSmckusick 		c = sp[0]; sp[0] = sp[1]; sp[1] = c;
12900062352bSmckusick 		sp += 2;
12910062352bSmckusick 	}
12920062352bSmckusick 	return (sp);
12930062352bSmckusick }
12940062352bSmckusick 
1295e786d8ceSbostic static u_char *
swablong(sp,n)12960062352bSmckusick swablong(sp, n)
12970062352bSmckusick 	register u_char *sp;
12980062352bSmckusick 	register int n;
12990062352bSmckusick {
13000062352bSmckusick 	char c;
13010062352bSmckusick 
13020062352bSmckusick 	while (--n >= 0) {
13030062352bSmckusick 		c = sp[0]; sp[0] = sp[3]; sp[3] = c;
13040062352bSmckusick 		c = sp[2]; sp[2] = sp[1]; sp[1] = c;
13050062352bSmckusick 		sp += 4;
13060062352bSmckusick 	}
13070062352bSmckusick 	return (sp);
13080062352bSmckusick }
13090062352bSmckusick 
1310e786d8ceSbostic void
swabst(cp,sp)1311f7e6f5f8Ssklower swabst(cp, sp)
13120062352bSmckusick 	register u_char *cp, *sp;
1313f7e6f5f8Ssklower {
1314f7e6f5f8Ssklower 	int n = 0;
13150062352bSmckusick 
1316f7e6f5f8Ssklower 	while (*cp) {
1317f7e6f5f8Ssklower 		switch (*cp) {
1318f7e6f5f8Ssklower 		case '0': case '1': case '2': case '3': case '4':
1319f7e6f5f8Ssklower 		case '5': case '6': case '7': case '8': case '9':
1320f7e6f5f8Ssklower 			n = (n * 10) + (*cp++ - '0');
1321f7e6f5f8Ssklower 			continue;
1322f7e6f5f8Ssklower 
1323f7e6f5f8Ssklower 		case 's': case 'w': case 'h':
13240062352bSmckusick 			if (n == 0)
13250062352bSmckusick 				n = 1;
13260062352bSmckusick 			sp = swabshort(sp, n);
1327f7e6f5f8Ssklower 			break;
1328f7e6f5f8Ssklower 
1329f7e6f5f8Ssklower 		case 'l':
13300062352bSmckusick 			if (n == 0)
13310062352bSmckusick 				n = 1;
13320062352bSmckusick 			sp = swablong(sp, n);
13330062352bSmckusick 			break;
13340062352bSmckusick 
13350062352bSmckusick 		default: /* Any other character, like 'b' counts as byte. */
13360062352bSmckusick 			if (n == 0)
13370062352bSmckusick 				n = 1;
13380062352bSmckusick 			sp += n;
13390062352bSmckusick 			break;
1340f7e6f5f8Ssklower 		}
13410062352bSmckusick 		cp++;
13420062352bSmckusick 		n = 0;
1343f7e6f5f8Ssklower 	}
1344f7e6f5f8Ssklower }
13450062352bSmckusick 
1346e786d8ceSbostic static u_long
swabl(x)13470062352bSmckusick swabl(x)
13480062352bSmckusick 	u_long x;
13490062352bSmckusick {
1350e786d8ceSbostic 	swabst((u_char *)"l", (u_char *)&x);
13510062352bSmckusick 	return (x);
13520062352bSmckusick }
1353