Deleted Added
full compact
tape.c (90573) tape.c (90608)
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39#ifndef lint
40#if 0
41static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95";
42#endif
43static const char rcsid[] =
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39#ifndef lint
40#if 0
41static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95";
42#endif
43static const char rcsid[] =
44 "$FreeBSD: head/sbin/restore/tape.c 90573 2002-02-12 17:15:45Z iedowse $";
44 "$FreeBSD: head/sbin/restore/tape.c 90608 2002-02-13 12:06:58Z iedowse $";
45#endif /* not lint */
46
47#include <sys/param.h>
48#include <sys/file.h>
49#include <sys/mtio.h>
50#include <sys/stat.h>
51#include <sys/time.h>
52
53#include <ufs/ufs/dinode.h>
54#include <protocols/dumprestore.h>
55
56#include <errno.h>
57#include <paths.h>
58#include <setjmp.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <time.h>
63#include <unistd.h>
64
65#include "restore.h"
66#include "extern.h"
67
68static long fssize = MAXBSIZE;
69static int mt = -1;
70static int pipein = 0;
71static char *magtape;
72static int blkcnt;
73static int numtrec;
74static char *tapebuf;
75static union u_spcl endoftapemark;
76static long blksread; /* blocks read since last header */
77static long tpblksread = 0; /* TP_BSIZE blocks read */
78static long tapesread;
79static jmp_buf restart;
80static int gettingfile = 0; /* restart has a valid frame */
81static char *host = NULL;
82
83static int ofile;
84static char *map;
85static char lnkbuf[MAXPATHLEN + 1];
86static int pathlen;
87
88int oldinofmt; /* old inode format conversion required */
89int Bcvt; /* Swap Bytes (for CCI or sun) */
90static int Qcvt; /* Swap quads (for sun) */
91
92#define FLUSHTAPEBUF() blkcnt = ntrec + 1
93
94static void accthdr __P((struct s_spcl *));
95static int checksum __P((int *));
96static void findinode __P((struct s_spcl *));
97static void findtapeblksize __P((void));
98static int gethead __P((struct s_spcl *));
99static void readtape __P((char *));
100static void setdumpnum __P((void));
101static u_long swabl __P((u_long));
102static u_char *swablong __P((u_char *, int));
103static u_char *swabshort __P((u_char *, int));
104static void terminateinput __P((void));
105static void xtrfile __P((char *, long));
106static void xtrlnkfile __P((char *, long));
107static void xtrlnkskip __P((char *, long));
108static void xtrmap __P((char *, long));
109static void xtrmapskip __P((char *, long));
110static void xtrskip __P((char *, long));
111
112static int readmapflag;
113
114/*
115 * Set up an input source
116 */
117void
118setinput(source)
119 char *source;
120{
121 FLUSHTAPEBUF();
122 if (bflag)
123 newtapebuf(ntrec);
124 else
125 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
126 terminal = stdin;
127
128#ifdef RRESTORE
129 if (strchr(source, ':')) {
130 host = source;
131 source = strchr(host, ':');
132 *source++ = '\0';
133 if (rmthost(host) == 0)
134 done(1);
135 } else
136#endif
137 if (strcmp(source, "-") == 0) {
138 /*
139 * Since input is coming from a pipe we must establish
140 * our own connection to the terminal.
141 */
142 terminal = fopen(_PATH_TTY, "r");
143 if (terminal == NULL) {
144 (void)fprintf(stderr, "cannot open %s: %s\n",
145 _PATH_TTY, strerror(errno));
146 terminal = fopen(_PATH_DEVNULL, "r");
147 if (terminal == NULL) {
148 (void)fprintf(stderr, "cannot open %s: %s\n",
149 _PATH_DEVNULL, strerror(errno));
150 done(1);
151 }
152 }
153 pipein++;
154 }
155 setuid(getuid()); /* no longer need or want root privileges */
156 magtape = strdup(source);
157 if (magtape == NULL) {
158 fprintf(stderr, "Cannot allocate space for magtape buffer\n");
159 done(1);
160 }
161}
162
163void
164newtapebuf(size)
165 long size;
166{
167 static tapebufsize = -1;
168
169 ntrec = size;
170 if (size <= tapebufsize)
171 return;
172 if (tapebuf != NULL)
173 free(tapebuf);
174 tapebuf = malloc(size * TP_BSIZE);
175 if (tapebuf == NULL) {
176 fprintf(stderr, "Cannot allocate space for tape buffer\n");
177 done(1);
178 }
179 tapebufsize = size;
180}
181
182/*
183 * Verify that the tape drive can be accessed and
184 * that it actually is a dump tape.
185 */
186void
187setup()
188{
189 int i, j, *ip;
190 struct stat stbuf;
191
192 vprintf(stdout, "Verify tape and initialize maps\n");
193#ifdef RRESTORE
194 if (host)
195 mt = rmtopen(magtape, 0);
196 else
197#endif
198 if (pipein)
199 mt = 0;
200 else
201 mt = open(magtape, O_RDONLY, 0);
202 if (mt < 0) {
203 fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
204 done(1);
205 }
206 volno = 1;
207 setdumpnum();
208 FLUSHTAPEBUF();
209 if (!pipein && !bflag)
210 findtapeblksize();
211 if (gethead(&spcl) == FAIL) {
212 blkcnt--; /* push back this block */
213 blksread--;
214 tpblksread--;
215 cvtflag++;
216 if (gethead(&spcl) == FAIL) {
217 fprintf(stderr, "Tape is not a dump tape\n");
218 done(1);
219 }
220 fprintf(stderr, "Converting to new file system format.\n");
221 }
222 if (pipein) {
223 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
224 endoftapemark.s_spcl.c_type = TS_END;
225 ip = (int *)&endoftapemark;
226 j = sizeof(union u_spcl) / sizeof(int);
227 i = 0;
228 do
229 i += *ip++;
230 while (--j);
231 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
232 }
233 if (vflag || command == 't')
234 printdumpinfo();
235 dumptime = _time32_to_time(spcl.c_ddate);
236 dumpdate = _time32_to_time(spcl.c_date);
237 if (stat(".", &stbuf) < 0) {
238 fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
239 done(1);
240 }
241 if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
242 fssize = TP_BSIZE;
243 if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
244 fssize = stbuf.st_blksize;
245 if (((fssize - 1) & fssize) != 0) {
246 fprintf(stderr, "bad block size %ld\n", fssize);
247 done(1);
248 }
249 if (spcl.c_volume != 1) {
250 fprintf(stderr, "Tape is not volume 1 of the dump\n");
251 done(1);
252 }
253 if (gethead(&spcl) == FAIL) {
254 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
255 panic("no header after volume mark!\n");
256 }
257 findinode(&spcl);
258 if (spcl.c_type != TS_CLRI) {
259 fprintf(stderr, "Cannot find file removal list\n");
260 done(1);
261 }
262 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
263 dprintf(stdout, "maxino = %d\n", maxino);
264 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
265 if (map == NULL)
266 panic("no memory for active inode map\n");
267 usedinomap = map;
268 curfile.action = USING;
269 getfile(xtrmap, xtrmapskip);
270 if (spcl.c_type != TS_BITS) {
271 fprintf(stderr, "Cannot find file dump list\n");
272 done(1);
273 }
274 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
275 if (map == (char *)NULL)
276 panic("no memory for file dump list\n");
277 dumpmap = map;
278 curfile.action = USING;
279 getfile(xtrmap, xtrmapskip);
280 /*
281 * If there may be whiteout entries on the tape, pretend that the
282 * whiteout inode exists, so that the whiteout entries can be
283 * extracted.
284 */
285 if (oldinofmt == 0)
286 SETINO(WINO, dumpmap);
287}
288
289/*
290 * Prompt user to load a new dump volume.
291 * "Nextvol" is the next suggested volume to use.
292 * This suggested volume is enforced when doing full
293 * or incremental restores, but can be overridden by
294 * the user when only extracting a subset of the files.
295 */
296void
297getvol(nextvol)
298 long nextvol;
299{
45#endif /* not lint */
46
47#include <sys/param.h>
48#include <sys/file.h>
49#include <sys/mtio.h>
50#include <sys/stat.h>
51#include <sys/time.h>
52
53#include <ufs/ufs/dinode.h>
54#include <protocols/dumprestore.h>
55
56#include <errno.h>
57#include <paths.h>
58#include <setjmp.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <time.h>
63#include <unistd.h>
64
65#include "restore.h"
66#include "extern.h"
67
68static long fssize = MAXBSIZE;
69static int mt = -1;
70static int pipein = 0;
71static char *magtape;
72static int blkcnt;
73static int numtrec;
74static char *tapebuf;
75static union u_spcl endoftapemark;
76static long blksread; /* blocks read since last header */
77static long tpblksread = 0; /* TP_BSIZE blocks read */
78static long tapesread;
79static jmp_buf restart;
80static int gettingfile = 0; /* restart has a valid frame */
81static char *host = NULL;
82
83static int ofile;
84static char *map;
85static char lnkbuf[MAXPATHLEN + 1];
86static int pathlen;
87
88int oldinofmt; /* old inode format conversion required */
89int Bcvt; /* Swap Bytes (for CCI or sun) */
90static int Qcvt; /* Swap quads (for sun) */
91
92#define FLUSHTAPEBUF() blkcnt = ntrec + 1
93
94static void accthdr __P((struct s_spcl *));
95static int checksum __P((int *));
96static void findinode __P((struct s_spcl *));
97static void findtapeblksize __P((void));
98static int gethead __P((struct s_spcl *));
99static void readtape __P((char *));
100static void setdumpnum __P((void));
101static u_long swabl __P((u_long));
102static u_char *swablong __P((u_char *, int));
103static u_char *swabshort __P((u_char *, int));
104static void terminateinput __P((void));
105static void xtrfile __P((char *, long));
106static void xtrlnkfile __P((char *, long));
107static void xtrlnkskip __P((char *, long));
108static void xtrmap __P((char *, long));
109static void xtrmapskip __P((char *, long));
110static void xtrskip __P((char *, long));
111
112static int readmapflag;
113
114/*
115 * Set up an input source
116 */
117void
118setinput(source)
119 char *source;
120{
121 FLUSHTAPEBUF();
122 if (bflag)
123 newtapebuf(ntrec);
124 else
125 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
126 terminal = stdin;
127
128#ifdef RRESTORE
129 if (strchr(source, ':')) {
130 host = source;
131 source = strchr(host, ':');
132 *source++ = '\0';
133 if (rmthost(host) == 0)
134 done(1);
135 } else
136#endif
137 if (strcmp(source, "-") == 0) {
138 /*
139 * Since input is coming from a pipe we must establish
140 * our own connection to the terminal.
141 */
142 terminal = fopen(_PATH_TTY, "r");
143 if (terminal == NULL) {
144 (void)fprintf(stderr, "cannot open %s: %s\n",
145 _PATH_TTY, strerror(errno));
146 terminal = fopen(_PATH_DEVNULL, "r");
147 if (terminal == NULL) {
148 (void)fprintf(stderr, "cannot open %s: %s\n",
149 _PATH_DEVNULL, strerror(errno));
150 done(1);
151 }
152 }
153 pipein++;
154 }
155 setuid(getuid()); /* no longer need or want root privileges */
156 magtape = strdup(source);
157 if (magtape == NULL) {
158 fprintf(stderr, "Cannot allocate space for magtape buffer\n");
159 done(1);
160 }
161}
162
163void
164newtapebuf(size)
165 long size;
166{
167 static tapebufsize = -1;
168
169 ntrec = size;
170 if (size <= tapebufsize)
171 return;
172 if (tapebuf != NULL)
173 free(tapebuf);
174 tapebuf = malloc(size * TP_BSIZE);
175 if (tapebuf == NULL) {
176 fprintf(stderr, "Cannot allocate space for tape buffer\n");
177 done(1);
178 }
179 tapebufsize = size;
180}
181
182/*
183 * Verify that the tape drive can be accessed and
184 * that it actually is a dump tape.
185 */
186void
187setup()
188{
189 int i, j, *ip;
190 struct stat stbuf;
191
192 vprintf(stdout, "Verify tape and initialize maps\n");
193#ifdef RRESTORE
194 if (host)
195 mt = rmtopen(magtape, 0);
196 else
197#endif
198 if (pipein)
199 mt = 0;
200 else
201 mt = open(magtape, O_RDONLY, 0);
202 if (mt < 0) {
203 fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
204 done(1);
205 }
206 volno = 1;
207 setdumpnum();
208 FLUSHTAPEBUF();
209 if (!pipein && !bflag)
210 findtapeblksize();
211 if (gethead(&spcl) == FAIL) {
212 blkcnt--; /* push back this block */
213 blksread--;
214 tpblksread--;
215 cvtflag++;
216 if (gethead(&spcl) == FAIL) {
217 fprintf(stderr, "Tape is not a dump tape\n");
218 done(1);
219 }
220 fprintf(stderr, "Converting to new file system format.\n");
221 }
222 if (pipein) {
223 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
224 endoftapemark.s_spcl.c_type = TS_END;
225 ip = (int *)&endoftapemark;
226 j = sizeof(union u_spcl) / sizeof(int);
227 i = 0;
228 do
229 i += *ip++;
230 while (--j);
231 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
232 }
233 if (vflag || command == 't')
234 printdumpinfo();
235 dumptime = _time32_to_time(spcl.c_ddate);
236 dumpdate = _time32_to_time(spcl.c_date);
237 if (stat(".", &stbuf) < 0) {
238 fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
239 done(1);
240 }
241 if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
242 fssize = TP_BSIZE;
243 if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
244 fssize = stbuf.st_blksize;
245 if (((fssize - 1) & fssize) != 0) {
246 fprintf(stderr, "bad block size %ld\n", fssize);
247 done(1);
248 }
249 if (spcl.c_volume != 1) {
250 fprintf(stderr, "Tape is not volume 1 of the dump\n");
251 done(1);
252 }
253 if (gethead(&spcl) == FAIL) {
254 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
255 panic("no header after volume mark!\n");
256 }
257 findinode(&spcl);
258 if (spcl.c_type != TS_CLRI) {
259 fprintf(stderr, "Cannot find file removal list\n");
260 done(1);
261 }
262 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
263 dprintf(stdout, "maxino = %d\n", maxino);
264 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
265 if (map == NULL)
266 panic("no memory for active inode map\n");
267 usedinomap = map;
268 curfile.action = USING;
269 getfile(xtrmap, xtrmapskip);
270 if (spcl.c_type != TS_BITS) {
271 fprintf(stderr, "Cannot find file dump list\n");
272 done(1);
273 }
274 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
275 if (map == (char *)NULL)
276 panic("no memory for file dump list\n");
277 dumpmap = map;
278 curfile.action = USING;
279 getfile(xtrmap, xtrmapskip);
280 /*
281 * If there may be whiteout entries on the tape, pretend that the
282 * whiteout inode exists, so that the whiteout entries can be
283 * extracted.
284 */
285 if (oldinofmt == 0)
286 SETINO(WINO, dumpmap);
287}
288
289/*
290 * Prompt user to load a new dump volume.
291 * "Nextvol" is the next suggested volume to use.
292 * This suggested volume is enforced when doing full
293 * or incremental restores, but can be overridden by
294 * the user when only extracting a subset of the files.
295 */
296void
297getvol(nextvol)
298 long nextvol;
299{
300 long newvol, savecnt, wantnext, i;
300 long newvol, savecnt, savetpcnt, i;
301 union u_spcl tmpspcl;
302# define tmpbuf tmpspcl.s_spcl
303 char buf[TP_BSIZE];
304
305 if (nextvol == 1) {
306 tapesread = 0;
307 gettingfile = 0;
308 }
309 if (pipein) {
310 if (nextvol != 1) {
311 panic("Changing volumes on pipe input?\n");
312 /* Avoid looping if we couldn't ask the user. */
313 if (yflag || ferror(terminal) || feof(terminal))
314 done(1);
315 }
316 if (volno == 1)
317 return;
318 goto gethdr;
319 }
320 savecnt = blksread;
301 union u_spcl tmpspcl;
302# define tmpbuf tmpspcl.s_spcl
303 char buf[TP_BSIZE];
304
305 if (nextvol == 1) {
306 tapesread = 0;
307 gettingfile = 0;
308 }
309 if (pipein) {
310 if (nextvol != 1) {
311 panic("Changing volumes on pipe input?\n");
312 /* Avoid looping if we couldn't ask the user. */
313 if (yflag || ferror(terminal) || feof(terminal))
314 done(1);
315 }
316 if (volno == 1)
317 return;
318 goto gethdr;
319 }
320 savecnt = blksread;
321 savetpcnt = tpblksread;
321again:
322again:
323 tpblksread = savetpcnt;
322 if (pipein)
323 done(1); /* pipes do not get a second chance */
324 if (pipein)
325 done(1); /* pipes do not get a second chance */
324 if (command == 'R' || command == 'r' || curfile.action != SKIP) {
326 if (command == 'R' || command == 'r' || curfile.action != SKIP)
325 newvol = nextvol;
327 newvol = nextvol;
326 wantnext = 1;
327 } else {
328 else
328 newvol = 0;
329 newvol = 0;
329 wantnext = 0;
330 }
331 while (newvol <= 0) {
332 if (tapesread == 0) {
333 fprintf(stderr, "%s%s%s%s%s",
334 "You have not read any tapes yet.\n",
335 "Unless you know which volume your",
336 " file(s) are on you should start\n",
337 "with the last volume and work",
338 " towards the first.\n");
339 } else {
340 fprintf(stderr, "You have read volumes");
341 strcpy(buf, ": ");
342 for (i = 1; i < 32; i++)
343 if (tapesread & (1 << i)) {
344 fprintf(stderr, "%s%ld", buf, i);
345 strcpy(buf, ", ");
346 }
347 fprintf(stderr, "\n");
348 }
349 do {
350 fprintf(stderr, "Specify next volume #: ");
351 (void) fflush(stderr);
352 if (fgets(buf, BUFSIZ, terminal) == NULL)
353 done(1);
354 } while (buf[0] == '\n');
355 newvol = atoi(buf);
356 if (newvol <= 0) {
357 fprintf(stderr,
358 "Volume numbers are positive numerics\n");
359 }
360 }
361 if (newvol == volno) {
362 tapesread |= 1 << volno;
363 return;
364 }
365 closemt();
366 fprintf(stderr, "Mount tape volume %ld\n", newvol);
367 fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
368 fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
369 (void) fflush(stderr);
370 if (fgets(buf, BUFSIZ, terminal) == NULL)
371 done(1);
372 if (!strcmp(buf, "none\n")) {
373 terminateinput();
374 return;
375 }
376 if (buf[0] != '\n') {
377 (void) strcpy(magtape, buf);
378 magtape[strlen(magtape) - 1] = '\0';
379 }
380#ifdef RRESTORE
381 if (host)
382 mt = rmtopen(magtape, 0);
383 else
384#endif
385 mt = open(magtape, O_RDONLY, 0);
386
387 if (mt == -1) {
388 fprintf(stderr, "Cannot open %s\n", magtape);
389 volno = -1;
390 goto again;
391 }
392gethdr:
393 volno = newvol;
394 setdumpnum();
395 FLUSHTAPEBUF();
396 if (gethead(&tmpbuf) == FAIL) {
397 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
398 fprintf(stderr, "tape is not dump tape\n");
399 volno = 0;
400 goto again;
401 }
402 if (tmpbuf.c_volume != volno) {
403 fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume);
404 volno = 0;
405 goto again;
406 }
407 if (_time32_to_time(tmpbuf.c_date) != dumpdate ||
408 _time32_to_time(tmpbuf.c_ddate) != dumptime) {
409 time_t t = _time32_to_time(tmpbuf.c_date);
410 fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t));
411 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
412 volno = 0;
413 goto again;
414 }
415 tapesread |= 1 << volno;
416 blksread = savecnt;
417 /*
418 * If continuing from the previous volume, skip over any
419 * blocks read already at the end of the previous volume.
420 *
421 * If coming to this volume at random, skip to the beginning
422 * of the next record.
423 */
424 dprintf(stdout, "read %ld recs, tape starts with %ld\n",
425 tpblksread, tmpbuf.c_firstrec);
426 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
330 while (newvol <= 0) {
331 if (tapesread == 0) {
332 fprintf(stderr, "%s%s%s%s%s",
333 "You have not read any tapes yet.\n",
334 "Unless you know which volume your",
335 " file(s) are on you should start\n",
336 "with the last volume and work",
337 " towards the first.\n");
338 } else {
339 fprintf(stderr, "You have read volumes");
340 strcpy(buf, ": ");
341 for (i = 1; i < 32; i++)
342 if (tapesread & (1 << i)) {
343 fprintf(stderr, "%s%ld", buf, i);
344 strcpy(buf, ", ");
345 }
346 fprintf(stderr, "\n");
347 }
348 do {
349 fprintf(stderr, "Specify next volume #: ");
350 (void) fflush(stderr);
351 if (fgets(buf, BUFSIZ, terminal) == NULL)
352 done(1);
353 } while (buf[0] == '\n');
354 newvol = atoi(buf);
355 if (newvol <= 0) {
356 fprintf(stderr,
357 "Volume numbers are positive numerics\n");
358 }
359 }
360 if (newvol == volno) {
361 tapesread |= 1 << volno;
362 return;
363 }
364 closemt();
365 fprintf(stderr, "Mount tape volume %ld\n", newvol);
366 fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
367 fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
368 (void) fflush(stderr);
369 if (fgets(buf, BUFSIZ, terminal) == NULL)
370 done(1);
371 if (!strcmp(buf, "none\n")) {
372 terminateinput();
373 return;
374 }
375 if (buf[0] != '\n') {
376 (void) strcpy(magtape, buf);
377 magtape[strlen(magtape) - 1] = '\0';
378 }
379#ifdef RRESTORE
380 if (host)
381 mt = rmtopen(magtape, 0);
382 else
383#endif
384 mt = open(magtape, O_RDONLY, 0);
385
386 if (mt == -1) {
387 fprintf(stderr, "Cannot open %s\n", magtape);
388 volno = -1;
389 goto again;
390 }
391gethdr:
392 volno = newvol;
393 setdumpnum();
394 FLUSHTAPEBUF();
395 if (gethead(&tmpbuf) == FAIL) {
396 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
397 fprintf(stderr, "tape is not dump tape\n");
398 volno = 0;
399 goto again;
400 }
401 if (tmpbuf.c_volume != volno) {
402 fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume);
403 volno = 0;
404 goto again;
405 }
406 if (_time32_to_time(tmpbuf.c_date) != dumpdate ||
407 _time32_to_time(tmpbuf.c_ddate) != dumptime) {
408 time_t t = _time32_to_time(tmpbuf.c_date);
409 fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t));
410 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
411 volno = 0;
412 goto again;
413 }
414 tapesread |= 1 << volno;
415 blksread = savecnt;
416 /*
417 * If continuing from the previous volume, skip over any
418 * blocks read already at the end of the previous volume.
419 *
420 * If coming to this volume at random, skip to the beginning
421 * of the next record.
422 */
423 dprintf(stdout, "read %ld recs, tape starts with %ld\n",
424 tpblksread, tmpbuf.c_firstrec);
425 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
427 if (!wantnext) {
426 if (curfile.action != USING) {
428 tpblksread = tmpbuf.c_firstrec;
427 tpblksread = tmpbuf.c_firstrec;
429 for (i = tmpbuf.c_count; i > 0; i--)
430 readtape(buf);
428 /*
429 * XXX Dump incorrectly sets c_count to 1 in the
430 * volume header of the first tape, so ignore
431 * c_count when volno == 1.
432 */
433 if (volno != 1)
434 for (i = tmpbuf.c_count; i > 0; i--)
435 readtape(buf);
431 } else if (tmpbuf.c_firstrec > 0 &&
432 tmpbuf.c_firstrec < tpblksread - 1) {
433 /*
434 * -1 since we've read the volume header
435 */
436 i = tpblksread - tmpbuf.c_firstrec - 1;
437 dprintf(stderr, "Skipping %ld duplicate record%s.\n",
438 i, i > 1 ? "s" : "");
439 while (--i >= 0)
440 readtape(buf);
441 }
442 }
436 } else if (tmpbuf.c_firstrec > 0 &&
437 tmpbuf.c_firstrec < tpblksread - 1) {
438 /*
439 * -1 since we've read the volume header
440 */
441 i = tpblksread - tmpbuf.c_firstrec - 1;
442 dprintf(stderr, "Skipping %ld duplicate record%s.\n",
443 i, i > 1 ? "s" : "");
444 while (--i >= 0)
445 readtape(buf);
446 }
447 }
443 if (curfile.action == USING || curfile.action == SKIP) {
448 if (curfile.action == USING) {
444 if (volno == 1)
445 panic("active file into volume 1\n");
446 return;
447 }
449 if (volno == 1)
450 panic("active file into volume 1\n");
451 return;
452 }
448 /*
449 * Skip up to the beginning of the next record
450 */
451 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
452 for (i = tmpbuf.c_count; i > 0; i--)
453 readtape(buf);
454 (void) gethead(&spcl);
455 findinode(&spcl);
456 if (gettingfile) {
457 gettingfile = 0;
458 longjmp(restart, 1);
459 }
460}
461
462/*
463 * Handle unexpected EOF.
464 */
465static void
466terminateinput()
467{
468
469 if (gettingfile && curfile.action == USING) {
470 printf("Warning: %s %s\n",
471 "End-of-input encountered while extracting", curfile.name);
472 }
473 curfile.name = "<name unknown>";
474 curfile.action = UNKNOWN;
475 curfile.dip = NULL;
476 curfile.ino = maxino;
477 if (gettingfile) {
478 gettingfile = 0;
479 longjmp(restart, 1);
480 }
481}
482
483/*
484 * handle multiple dumps per tape by skipping forward to the
485 * appropriate one.
486 */
487static void
488setdumpnum()
489{
490 struct mtop tcom;
491
492 if (dumpnum == 1 || volno != 1)
493 return;
494 if (pipein) {
495 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
496 done(1);
497 }
498 tcom.mt_op = MTFSF;
499 tcom.mt_count = dumpnum - 1;
500#ifdef RRESTORE
501 if (host)
502 rmtioctl(MTFSF, dumpnum - 1);
503 else
504#endif
505 if (ioctl(mt, MTIOCTOP, (char *)&tcom) < 0)
506 fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
507}
508
509void
510printdumpinfo()
511{
512 time_t t;
513 t = _time32_to_time(spcl.c_date);
514 fprintf(stdout, "Dump date: %s", ctime(&t));
515 t = _time32_to_time(spcl.c_ddate);
516 fprintf(stdout, "Dumped from: %s",
517 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t));
518 if (spcl.c_host[0] == '\0')
519 return;
520 fprintf(stderr, "Level %ld dump of %s on %s:%s\n",
521 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
522 fprintf(stderr, "Label: %s\n", spcl.c_label);
523}
524
525int
526extractfile(name)
527 char *name;
528{
529 int flags;
530 mode_t mode;
531 struct timeval timep[2];
532 struct entry *ep;
533
534 curfile.name = name;
535 curfile.action = USING;
536 timep[0].tv_sec = curfile.dip->di_atime;
537 timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
538 timep[1].tv_sec = curfile.dip->di_mtime;
539 timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
540 mode = curfile.dip->di_mode;
541 flags = curfile.dip->di_flags;
542 switch (mode & IFMT) {
543
544 default:
545 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
546 skipfile();
547 return (FAIL);
548
549 case IFSOCK:
550 vprintf(stdout, "skipped socket %s\n", name);
551 skipfile();
552 return (GOOD);
553
554 case IFDIR:
555 if (mflag) {
556 ep = lookupname(name);
557 if (ep == NULL || ep->e_flags & EXTRACT)
558 panic("unextracted directory %s\n", name);
559 skipfile();
560 return (GOOD);
561 }
562 vprintf(stdout, "extract file %s\n", name);
563 return (genliteraldir(name, curfile.ino));
564
565 case IFLNK:
566 lnkbuf[0] = '\0';
567 pathlen = 0;
568 getfile(xtrlnkfile, xtrlnkskip);
569 if (pathlen == 0) {
570 vprintf(stdout,
571 "%s: zero length symbolic link (ignored)\n", name);
572 return (GOOD);
573 }
574 return (linkit(lnkbuf, name, SYMLINK));
575
576 case IFIFO:
577 vprintf(stdout, "extract fifo %s\n", name);
578 if (Nflag) {
579 skipfile();
580 return (GOOD);
581 }
582 if (uflag && !Nflag)
583 (void)unlink(name);
584 if (mkfifo(name, mode) < 0) {
585 fprintf(stderr, "%s: cannot create fifo: %s\n",
586 name, strerror(errno));
587 skipfile();
588 return (FAIL);
589 }
590 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
591 (void) chmod(name, mode);
592 utimes(name, timep);
593 (void) chflags(name, flags);
594 skipfile();
595 return (GOOD);
596
597 case IFCHR:
598 case IFBLK:
599 vprintf(stdout, "extract special file %s\n", name);
600 if (Nflag) {
601 skipfile();
602 return (GOOD);
603 }
604 if (uflag)
605 (void)unlink(name);
606 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
607 fprintf(stderr, "%s: cannot create special file: %s\n",
608 name, strerror(errno));
609 skipfile();
610 return (FAIL);
611 }
612 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
613 (void) chmod(name, mode);
614 utimes(name, timep);
615 (void) chflags(name, flags);
616 skipfile();
617 return (GOOD);
618
619 case IFREG:
620 vprintf(stdout, "extract file %s\n", name);
621 if (Nflag) {
622 skipfile();
623 return (GOOD);
624 }
625 if (uflag)
626 (void)unlink(name);
627 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
628 0666)) < 0) {
629 fprintf(stderr, "%s: cannot create file: %s\n",
630 name, strerror(errno));
631 skipfile();
632 return (FAIL);
633 }
634 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
635 (void) fchmod(ofile, mode);
636 getfile(xtrfile, xtrskip);
637 (void) close(ofile);
638 utimes(name, timep);
639 (void) chflags(name, flags);
640 return (GOOD);
641 }
642 /* NOTREACHED */
643}
644
645/*
646 * skip over bit maps on the tape
647 */
648void
649skipmaps()
650{
651
652 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
653 skipfile();
654}
655
656/*
657 * skip over a file on the tape
658 */
659void
660skipfile()
661{
662
663 curfile.action = SKIP;
664 getfile(xtrnull, xtrnull);
665}
666
667/*
668 * Extract a file from the tape.
669 * When an allocated block is found it is passed to the fill function;
670 * when an unallocated block (hole) is found, a zeroed buffer is passed
671 * to the skip function.
672 */
673void
674getfile(fill, skip)
675 void (*fill) __P((char *, long));
676 void (*skip) __P((char *, long));
677{
678 register int i;
679 int curblk = 0;
680 quad_t size = spcl.c_dinode.di_size;
681 static char clearedbuf[MAXBSIZE];
682 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
683 char junk[TP_BSIZE];
684
685 if (spcl.c_type == TS_END)
686 panic("ran off end of tape\n");
687 if (spcl.c_magic != NFS_MAGIC)
688 panic("not at beginning of a file\n");
689 if (!gettingfile && setjmp(restart) != 0)
690 return;
691 gettingfile++;
692loop:
693 for (i = 0; i < spcl.c_count; i++) {
694 if (readmapflag || spcl.c_addr[i]) {
695 readtape(&buf[curblk++][0]);
696 if (curblk == fssize / TP_BSIZE) {
697 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
698 fssize : (curblk - 1) * TP_BSIZE + size));
699 curblk = 0;
700 }
701 } else {
702 if (curblk > 0) {
703 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
704 curblk * TP_BSIZE :
705 (curblk - 1) * TP_BSIZE + size));
706 curblk = 0;
707 }
708 (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
709 TP_BSIZE : size));
710 }
711 if ((size -= TP_BSIZE) <= 0) {
712 for (i++; i < spcl.c_count; i++)
713 if (readmapflag || spcl.c_addr[i])
714 readtape(junk);
715 break;
716 }
717 }
718 if (gethead(&spcl) == GOOD && size > 0) {
719 if (spcl.c_type == TS_ADDR)
720 goto loop;
721 dprintf(stdout,
722 "Missing address (header) block for %s at %ld blocks\n",
723 curfile.name, blksread);
724 }
725 if (curblk > 0)
726 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
727 findinode(&spcl);
728 gettingfile = 0;
729}
730
731/*
732 * Write out the next block of a file.
733 */
734static void
735xtrfile(buf, size)
736 char *buf;
737 long size;
738{
739
740 if (Nflag)
741 return;
742 if (write(ofile, buf, (int) size) == -1) {
743 fprintf(stderr,
744 "write error extracting inode %d, name %s\nwrite: %s\n",
745 curfile.ino, curfile.name, strerror(errno));
746 }
747}
748
749/*
750 * Skip over a hole in a file.
751 */
752/* ARGSUSED */
753static void
754xtrskip(buf, size)
755 char *buf;
756 long size;
757{
758
759 if (lseek(ofile, size, SEEK_CUR) == -1) {
760 fprintf(stderr,
761 "seek error extracting inode %d, name %s\nlseek: %s\n",
762 curfile.ino, curfile.name, strerror(errno));
763 done(1);
764 }
765}
766
767/*
768 * Collect the next block of a symbolic link.
769 */
770static void
771xtrlnkfile(buf, size)
772 char *buf;
773 long size;
774{
775
776 pathlen += size;
777 if (pathlen > MAXPATHLEN) {
778 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
779 curfile.name, lnkbuf, buf, pathlen);
780 done(1);
781 }
782 (void) strcat(lnkbuf, buf);
783}
784
785/*
786 * Skip over a hole in a symbolic link (should never happen).
787 */
788/* ARGSUSED */
789static void
790xtrlnkskip(buf, size)
791 char *buf;
792 long size;
793{
794
795 fprintf(stderr, "unallocated block in symbolic link %s\n",
796 curfile.name);
797 done(1);
798}
799
800/*
801 * Collect the next block of a bit map.
802 */
803static void
804xtrmap(buf, size)
805 char *buf;
806 long size;
807{
808
809 memmove(map, buf, size);
810 map += size;
811}
812
813/*
814 * Skip over a hole in a bit map (should never happen).
815 */
816/* ARGSUSED */
817static void
818xtrmapskip(buf, size)
819 char *buf;
820 long size;
821{
822
823 panic("hole in map\n");
824 map += size;
825}
826
827/*
828 * Noop, when an extraction function is not needed.
829 */
830/* ARGSUSED */
831void
832xtrnull(buf, size)
833 char *buf;
834 long size;
835{
836
837 return;
838}
839
840/*
841 * Read TP_BSIZE blocks from the input.
842 * Handle read errors, and end of media.
843 */
844static void
845readtape(buf)
846 char *buf;
847{
848 long rd, newvol, i;
849 int cnt, seek_failed;
850
851 if (blkcnt < numtrec) {
852 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
853 blksread++;
854 tpblksread++;
855 return;
856 }
857 for (i = 0; i < ntrec; i++)
858 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
859 if (numtrec == 0)
860 numtrec = ntrec;
861 cnt = ntrec * TP_BSIZE;
862 rd = 0;
863getmore:
864#ifdef RRESTORE
865 if (host)
866 i = rmtread(&tapebuf[rd], cnt);
867 else
868#endif
869 i = read(mt, &tapebuf[rd], cnt);
870 /*
871 * Check for mid-tape short read error.
872 * If found, skip rest of buffer and start with the next.
873 */
874 if (!pipein && numtrec < ntrec && i > 0) {
875 dprintf(stdout, "mid-media short read error.\n");
876 numtrec = ntrec;
877 }
878 /*
879 * Handle partial block read.
880 */
881 if (pipein && i == 0 && rd > 0)
882 i = rd;
883 else if (i > 0 && i != ntrec * TP_BSIZE) {
884 if (pipein) {
885 rd += i;
886 cnt -= i;
887 if (cnt > 0)
888 goto getmore;
889 i = rd;
890 } else {
891 /*
892 * Short read. Process the blocks read.
893 */
894 if (i % TP_BSIZE != 0)
895 vprintf(stdout,
896 "partial block read: %ld should be %ld\n",
897 i, ntrec * TP_BSIZE);
898 numtrec = i / TP_BSIZE;
899 }
900 }
901 /*
902 * Handle read error.
903 */
904 if (i < 0) {
905 fprintf(stderr, "Tape read error while ");
906 switch (curfile.action) {
907 default:
908 fprintf(stderr, "trying to set up tape\n");
909 break;
910 case UNKNOWN:
911 fprintf(stderr, "trying to resynchronize\n");
912 break;
913 case USING:
914 fprintf(stderr, "restoring %s\n", curfile.name);
915 break;
916 case SKIP:
917 fprintf(stderr, "skipping over inode %d\n",
918 curfile.ino);
919 break;
920 }
921 if (!yflag && !reply("continue"))
922 done(1);
923 i = ntrec * TP_BSIZE;
924 memset(tapebuf, 0, i);
925#ifdef RRESTORE
926 if (host)
927 seek_failed = (rmtseek(i, 1) < 0);
928 else
929#endif
930 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
931
932 if (seek_failed) {
933 fprintf(stderr,
934 "continuation failed: %s\n", strerror(errno));
935 done(1);
936 }
937 }
938 /*
939 * Handle end of tape.
940 */
941 if (i == 0) {
942 vprintf(stdout, "End-of-tape encountered\n");
943 if (!pipein) {
944 newvol = volno + 1;
945 volno = 0;
946 numtrec = 0;
947 getvol(newvol);
948 readtape(buf);
949 return;
950 }
951 if (rd % TP_BSIZE != 0)
952 panic("partial block read: %d should be %d\n",
953 rd, ntrec * TP_BSIZE);
954 terminateinput();
955 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
956 }
957 blkcnt = 0;
958 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
959 blksread++;
960 tpblksread++;
961}
962
963static void
964findtapeblksize()
965{
966 register long i;
967
968 for (i = 0; i < ntrec; i++)
969 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
970 blkcnt = 0;
971#ifdef RRESTORE
972 if (host)
973 i = rmtread(tapebuf, ntrec * TP_BSIZE);
974 else
975#endif
976 i = read(mt, tapebuf, ntrec * TP_BSIZE);
977
978 if (i <= 0) {
979 fprintf(stderr, "tape read error: %s\n", strerror(errno));
980 done(1);
981 }
982 if (i % TP_BSIZE != 0) {
983 fprintf(stderr, "Tape block size (%ld) %s (%d)\n",
984 i, "is not a multiple of dump block size", TP_BSIZE);
985 done(1);
986 }
987 ntrec = i / TP_BSIZE;
988 numtrec = ntrec;
989 vprintf(stdout, "Tape block size is %ld\n", ntrec);
990}
991
992void
993closemt()
994{
995
996 if (mt < 0)
997 return;
998#ifdef RRESTORE
999 if (host)
1000 rmtclose();
1001 else
1002#endif
1003 (void) close(mt);
1004}
1005
1006/*
1007 * Read the next block from the tape.
1008 * Check to see if it is one of several vintage headers.
1009 * If it is an old style header, convert it to a new style header.
1010 * If it is not any valid header, return an error.
1011 */
1012static int
1013gethead(buf)
1014 struct s_spcl *buf;
1015{
1016 long i;
1017 union {
1018 quad_t qval;
1019 int32_t val[2];
1020 } qcvt;
1021 union u_ospcl {
1022 char dummy[TP_BSIZE];
1023 struct s_ospcl {
1024 int32_t c_type;
1025 int32_t c_date;
1026 int32_t c_ddate;
1027 int32_t c_volume;
1028 int32_t c_tapea;
1029 u_short c_inumber;
1030 int32_t c_magic;
1031 int32_t c_checksum;
1032 struct odinode {
1033 unsigned short odi_mode;
1034 u_short odi_nlink;
1035 u_short odi_uid;
1036 u_short odi_gid;
1037 int32_t odi_size;
1038 int32_t odi_rdev;
1039 char odi_addr[36];
1040 int32_t odi_atime;
1041 int32_t odi_mtime;
1042 int32_t odi_ctime;
1043 } c_dinode;
1044 int32_t c_count;
1045 char c_addr[256];
1046 } s_ospcl;
1047 } u_ospcl;
1048
1049 if (!cvtflag) {
1050 readtape((char *)buf);
1051 if (buf->c_magic != NFS_MAGIC) {
1052 if (swabl(buf->c_magic) != NFS_MAGIC)
1053 return (FAIL);
1054 if (!Bcvt) {
1055 vprintf(stdout, "Note: Doing Byte swapping\n");
1056 Bcvt = 1;
1057 }
1058 }
1059 if (checksum((int *)buf) == FAIL)
1060 return (FAIL);
1061 if (Bcvt) {
1062 swabst((u_char *)"8l4s31l", (u_char *)buf);
1063 swabst((u_char *)"l",(u_char *) &buf->c_level);
1064 swabst((u_char *)"2l",(u_char *) &buf->c_flags);
1065 }
1066 goto good;
1067 }
1068 readtape((char *)(&u_ospcl.s_ospcl));
1069 memset(buf, 0, (long)TP_BSIZE);
1070 buf->c_type = u_ospcl.s_ospcl.c_type;
1071 buf->c_date = u_ospcl.s_ospcl.c_date;
1072 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1073 buf->c_volume = u_ospcl.s_ospcl.c_volume;
1074 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1075 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1076 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1077 buf->c_magic = u_ospcl.s_ospcl.c_magic;
1078 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1079 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1080 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1081 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1082 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1083 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1084 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1085 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1086 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1087 buf->c_count = u_ospcl.s_ospcl.c_count;
1088 memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1089 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1090 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1091 return(FAIL);
1092 buf->c_magic = NFS_MAGIC;
1093
1094good:
1095 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1096 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1097 qcvt.qval = buf->c_dinode.di_size;
1098 if (qcvt.val[0] || qcvt.val[1]) {
1099 printf("Note: Doing Quad swapping\n");
1100 Qcvt = 1;
1101 }
1102 }
1103 if (Qcvt) {
1104 qcvt.qval = buf->c_dinode.di_size;
1105 i = qcvt.val[1];
1106 qcvt.val[1] = qcvt.val[0];
1107 qcvt.val[0] = i;
1108 buf->c_dinode.di_size = qcvt.qval;
1109 }
1110 readmapflag = 0;
1111
1112 switch (buf->c_type) {
1113
1114 case TS_CLRI:
1115 case TS_BITS:
1116 /*
1117 * Have to patch up missing information in bit map headers
1118 */
1119 buf->c_inumber = 0;
1120 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1121 if (buf->c_count > TP_NINDIR)
1122 readmapflag = 1;
1123 else
1124 for (i = 0; i < buf->c_count; i++)
1125 buf->c_addr[i]++;
1126 break;
1127
1128 case TS_TAPE:
1129 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1130 oldinofmt = 1;
1131 /* fall through */
1132 case TS_END:
1133 buf->c_inumber = 0;
1134 break;
1135
1136 case TS_INODE:
1137 case TS_ADDR:
1138 break;
1139
1140 default:
1141 panic("gethead: unknown inode type %d\n", buf->c_type);
1142 break;
1143 }
1144 /*
1145 * If we are restoring a filesystem with old format inodes,
1146 * copy the uid/gid to the new location.
1147 */
1148 if (oldinofmt) {
1149 buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1150 buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1151 }
1152 if (dflag)
1153 accthdr(buf);
1154 return(GOOD);
1155}
1156
1157/*
1158 * Check that a header is where it belongs and predict the next header
1159 */
1160static void
1161accthdr(header)
1162 struct s_spcl *header;
1163{
1164 static ino_t previno = 0x7fffffff;
1165 static int prevtype;
1166 static long predict;
1167 long blks, i;
1168
1169 if (header->c_type == TS_TAPE) {
1170 fprintf(stderr, "Volume header (%s inode format) ",
1171 oldinofmt ? "old" : "new");
1172 if (header->c_firstrec)
1173 fprintf(stderr, "begins with record %ld",
1174 header->c_firstrec);
1175 fprintf(stderr, "\n");
1176 previno = 0x7fffffff;
1177 return;
1178 }
1179 if (previno == 0x7fffffff)
1180 goto newcalc;
1181 switch (prevtype) {
1182 case TS_BITS:
1183 fprintf(stderr, "Dumped inodes map header");
1184 break;
1185 case TS_CLRI:
1186 fprintf(stderr, "Used inodes map header");
1187 break;
1188 case TS_INODE:
1189 fprintf(stderr, "File header, ino %d", previno);
1190 break;
1191 case TS_ADDR:
1192 fprintf(stderr, "File continuation header, ino %d", previno);
1193 break;
1194 case TS_END:
1195 fprintf(stderr, "End of tape header");
1196 break;
1197 }
1198 if (predict != blksread - 1)
1199 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1200 predict, blksread - 1);
1201 fprintf(stderr, "\n");
1202newcalc:
1203 blks = 0;
1204 if (header->c_type != TS_END)
1205 for (i = 0; i < header->c_count; i++)
1206 if (readmapflag || header->c_addr[i] != 0)
1207 blks++;
1208 predict = blks;
1209 blksread = 0;
1210 prevtype = header->c_type;
1211 previno = header->c_inumber;
1212}
1213
1214/*
1215 * Find an inode header.
1216 * Complain if had to skip.
1217 */
1218static void
1219findinode(header)
1220 struct s_spcl *header;
1221{
1222 static long skipcnt = 0;
1223 long i;
1224 char buf[TP_BSIZE];
453 (void) gethead(&spcl);
454 findinode(&spcl);
455 if (gettingfile) {
456 gettingfile = 0;
457 longjmp(restart, 1);
458 }
459}
460
461/*
462 * Handle unexpected EOF.
463 */
464static void
465terminateinput()
466{
467
468 if (gettingfile && curfile.action == USING) {
469 printf("Warning: %s %s\n",
470 "End-of-input encountered while extracting", curfile.name);
471 }
472 curfile.name = "<name unknown>";
473 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 time_t t;
512 t = _time32_to_time(spcl.c_date);
513 fprintf(stdout, "Dump date: %s", ctime(&t));
514 t = _time32_to_time(spcl.c_ddate);
515 fprintf(stdout, "Dumped from: %s",
516 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t));
517 if (spcl.c_host[0] == '\0')
518 return;
519 fprintf(stderr, "Level %ld dump of %s on %s:%s\n",
520 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
521 fprintf(stderr, "Label: %s\n", spcl.c_label);
522}
523
524int
525extractfile(name)
526 char *name;
527{
528 int flags;
529 mode_t mode;
530 struct timeval timep[2];
531 struct entry *ep;
532
533 curfile.name = name;
534 curfile.action = USING;
535 timep[0].tv_sec = curfile.dip->di_atime;
536 timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
537 timep[1].tv_sec = curfile.dip->di_mtime;
538 timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
539 mode = curfile.dip->di_mode;
540 flags = curfile.dip->di_flags;
541 switch (mode & IFMT) {
542
543 default:
544 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
545 skipfile();
546 return (FAIL);
547
548 case IFSOCK:
549 vprintf(stdout, "skipped socket %s\n", name);
550 skipfile();
551 return (GOOD);
552
553 case IFDIR:
554 if (mflag) {
555 ep = lookupname(name);
556 if (ep == NULL || ep->e_flags & EXTRACT)
557 panic("unextracted directory %s\n", name);
558 skipfile();
559 return (GOOD);
560 }
561 vprintf(stdout, "extract file %s\n", name);
562 return (genliteraldir(name, curfile.ino));
563
564 case IFLNK:
565 lnkbuf[0] = '\0';
566 pathlen = 0;
567 getfile(xtrlnkfile, xtrlnkskip);
568 if (pathlen == 0) {
569 vprintf(stdout,
570 "%s: zero length symbolic link (ignored)\n", name);
571 return (GOOD);
572 }
573 return (linkit(lnkbuf, name, SYMLINK));
574
575 case IFIFO:
576 vprintf(stdout, "extract fifo %s\n", name);
577 if (Nflag) {
578 skipfile();
579 return (GOOD);
580 }
581 if (uflag && !Nflag)
582 (void)unlink(name);
583 if (mkfifo(name, mode) < 0) {
584 fprintf(stderr, "%s: cannot create fifo: %s\n",
585 name, strerror(errno));
586 skipfile();
587 return (FAIL);
588 }
589 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
590 (void) chmod(name, mode);
591 utimes(name, timep);
592 (void) chflags(name, flags);
593 skipfile();
594 return (GOOD);
595
596 case IFCHR:
597 case IFBLK:
598 vprintf(stdout, "extract special file %s\n", name);
599 if (Nflag) {
600 skipfile();
601 return (GOOD);
602 }
603 if (uflag)
604 (void)unlink(name);
605 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
606 fprintf(stderr, "%s: cannot create special file: %s\n",
607 name, strerror(errno));
608 skipfile();
609 return (FAIL);
610 }
611 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
612 (void) chmod(name, mode);
613 utimes(name, timep);
614 (void) chflags(name, flags);
615 skipfile();
616 return (GOOD);
617
618 case IFREG:
619 vprintf(stdout, "extract file %s\n", name);
620 if (Nflag) {
621 skipfile();
622 return (GOOD);
623 }
624 if (uflag)
625 (void)unlink(name);
626 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
627 0666)) < 0) {
628 fprintf(stderr, "%s: cannot create file: %s\n",
629 name, strerror(errno));
630 skipfile();
631 return (FAIL);
632 }
633 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
634 (void) fchmod(ofile, mode);
635 getfile(xtrfile, xtrskip);
636 (void) close(ofile);
637 utimes(name, timep);
638 (void) chflags(name, flags);
639 return (GOOD);
640 }
641 /* NOTREACHED */
642}
643
644/*
645 * skip over bit maps on the tape
646 */
647void
648skipmaps()
649{
650
651 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
652 skipfile();
653}
654
655/*
656 * skip over a file on the tape
657 */
658void
659skipfile()
660{
661
662 curfile.action = SKIP;
663 getfile(xtrnull, xtrnull);
664}
665
666/*
667 * Extract a file from the tape.
668 * When an allocated block is found it is passed to the fill function;
669 * when an unallocated block (hole) is found, a zeroed buffer is passed
670 * to the skip function.
671 */
672void
673getfile(fill, skip)
674 void (*fill) __P((char *, long));
675 void (*skip) __P((char *, long));
676{
677 register int i;
678 int curblk = 0;
679 quad_t size = spcl.c_dinode.di_size;
680 static char clearedbuf[MAXBSIZE];
681 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
682 char junk[TP_BSIZE];
683
684 if (spcl.c_type == TS_END)
685 panic("ran off end of tape\n");
686 if (spcl.c_magic != NFS_MAGIC)
687 panic("not at beginning of a file\n");
688 if (!gettingfile && setjmp(restart) != 0)
689 return;
690 gettingfile++;
691loop:
692 for (i = 0; i < spcl.c_count; i++) {
693 if (readmapflag || spcl.c_addr[i]) {
694 readtape(&buf[curblk++][0]);
695 if (curblk == fssize / TP_BSIZE) {
696 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
697 fssize : (curblk - 1) * TP_BSIZE + size));
698 curblk = 0;
699 }
700 } else {
701 if (curblk > 0) {
702 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
703 curblk * TP_BSIZE :
704 (curblk - 1) * TP_BSIZE + size));
705 curblk = 0;
706 }
707 (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
708 TP_BSIZE : size));
709 }
710 if ((size -= TP_BSIZE) <= 0) {
711 for (i++; i < spcl.c_count; i++)
712 if (readmapflag || spcl.c_addr[i])
713 readtape(junk);
714 break;
715 }
716 }
717 if (gethead(&spcl) == GOOD && size > 0) {
718 if (spcl.c_type == TS_ADDR)
719 goto loop;
720 dprintf(stdout,
721 "Missing address (header) block for %s at %ld blocks\n",
722 curfile.name, blksread);
723 }
724 if (curblk > 0)
725 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
726 findinode(&spcl);
727 gettingfile = 0;
728}
729
730/*
731 * Write out the next block of a file.
732 */
733static void
734xtrfile(buf, size)
735 char *buf;
736 long size;
737{
738
739 if (Nflag)
740 return;
741 if (write(ofile, buf, (int) size) == -1) {
742 fprintf(stderr,
743 "write error extracting inode %d, name %s\nwrite: %s\n",
744 curfile.ino, curfile.name, strerror(errno));
745 }
746}
747
748/*
749 * Skip over a hole in a file.
750 */
751/* ARGSUSED */
752static void
753xtrskip(buf, size)
754 char *buf;
755 long size;
756{
757
758 if (lseek(ofile, size, SEEK_CUR) == -1) {
759 fprintf(stderr,
760 "seek error extracting inode %d, name %s\nlseek: %s\n",
761 curfile.ino, curfile.name, strerror(errno));
762 done(1);
763 }
764}
765
766/*
767 * Collect the next block of a symbolic link.
768 */
769static void
770xtrlnkfile(buf, size)
771 char *buf;
772 long size;
773{
774
775 pathlen += size;
776 if (pathlen > MAXPATHLEN) {
777 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
778 curfile.name, lnkbuf, buf, pathlen);
779 done(1);
780 }
781 (void) strcat(lnkbuf, buf);
782}
783
784/*
785 * Skip over a hole in a symbolic link (should never happen).
786 */
787/* ARGSUSED */
788static void
789xtrlnkskip(buf, size)
790 char *buf;
791 long size;
792{
793
794 fprintf(stderr, "unallocated block in symbolic link %s\n",
795 curfile.name);
796 done(1);
797}
798
799/*
800 * Collect the next block of a bit map.
801 */
802static void
803xtrmap(buf, size)
804 char *buf;
805 long size;
806{
807
808 memmove(map, buf, size);
809 map += size;
810}
811
812/*
813 * Skip over a hole in a bit map (should never happen).
814 */
815/* ARGSUSED */
816static void
817xtrmapskip(buf, size)
818 char *buf;
819 long size;
820{
821
822 panic("hole in map\n");
823 map += size;
824}
825
826/*
827 * Noop, when an extraction function is not needed.
828 */
829/* ARGSUSED */
830void
831xtrnull(buf, size)
832 char *buf;
833 long size;
834{
835
836 return;
837}
838
839/*
840 * Read TP_BSIZE blocks from the input.
841 * Handle read errors, and end of media.
842 */
843static void
844readtape(buf)
845 char *buf;
846{
847 long rd, newvol, i;
848 int cnt, seek_failed;
849
850 if (blkcnt < numtrec) {
851 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
852 blksread++;
853 tpblksread++;
854 return;
855 }
856 for (i = 0; i < ntrec; i++)
857 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
858 if (numtrec == 0)
859 numtrec = ntrec;
860 cnt = ntrec * TP_BSIZE;
861 rd = 0;
862getmore:
863#ifdef RRESTORE
864 if (host)
865 i = rmtread(&tapebuf[rd], cnt);
866 else
867#endif
868 i = read(mt, &tapebuf[rd], cnt);
869 /*
870 * Check for mid-tape short read error.
871 * If found, skip rest of buffer and start with the next.
872 */
873 if (!pipein && numtrec < ntrec && i > 0) {
874 dprintf(stdout, "mid-media short read error.\n");
875 numtrec = ntrec;
876 }
877 /*
878 * Handle partial block read.
879 */
880 if (pipein && i == 0 && rd > 0)
881 i = rd;
882 else if (i > 0 && i != ntrec * TP_BSIZE) {
883 if (pipein) {
884 rd += i;
885 cnt -= i;
886 if (cnt > 0)
887 goto getmore;
888 i = rd;
889 } else {
890 /*
891 * Short read. Process the blocks read.
892 */
893 if (i % TP_BSIZE != 0)
894 vprintf(stdout,
895 "partial block read: %ld should be %ld\n",
896 i, ntrec * TP_BSIZE);
897 numtrec = i / TP_BSIZE;
898 }
899 }
900 /*
901 * Handle read error.
902 */
903 if (i < 0) {
904 fprintf(stderr, "Tape read error while ");
905 switch (curfile.action) {
906 default:
907 fprintf(stderr, "trying to set up tape\n");
908 break;
909 case UNKNOWN:
910 fprintf(stderr, "trying to resynchronize\n");
911 break;
912 case USING:
913 fprintf(stderr, "restoring %s\n", curfile.name);
914 break;
915 case SKIP:
916 fprintf(stderr, "skipping over inode %d\n",
917 curfile.ino);
918 break;
919 }
920 if (!yflag && !reply("continue"))
921 done(1);
922 i = ntrec * TP_BSIZE;
923 memset(tapebuf, 0, i);
924#ifdef RRESTORE
925 if (host)
926 seek_failed = (rmtseek(i, 1) < 0);
927 else
928#endif
929 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
930
931 if (seek_failed) {
932 fprintf(stderr,
933 "continuation failed: %s\n", strerror(errno));
934 done(1);
935 }
936 }
937 /*
938 * Handle end of tape.
939 */
940 if (i == 0) {
941 vprintf(stdout, "End-of-tape encountered\n");
942 if (!pipein) {
943 newvol = volno + 1;
944 volno = 0;
945 numtrec = 0;
946 getvol(newvol);
947 readtape(buf);
948 return;
949 }
950 if (rd % TP_BSIZE != 0)
951 panic("partial block read: %d should be %d\n",
952 rd, ntrec * TP_BSIZE);
953 terminateinput();
954 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
955 }
956 blkcnt = 0;
957 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
958 blksread++;
959 tpblksread++;
960}
961
962static void
963findtapeblksize()
964{
965 register long i;
966
967 for (i = 0; i < ntrec; i++)
968 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
969 blkcnt = 0;
970#ifdef RRESTORE
971 if (host)
972 i = rmtread(tapebuf, ntrec * TP_BSIZE);
973 else
974#endif
975 i = read(mt, tapebuf, ntrec * TP_BSIZE);
976
977 if (i <= 0) {
978 fprintf(stderr, "tape read error: %s\n", strerror(errno));
979 done(1);
980 }
981 if (i % TP_BSIZE != 0) {
982 fprintf(stderr, "Tape block size (%ld) %s (%d)\n",
983 i, "is not a multiple of dump block size", TP_BSIZE);
984 done(1);
985 }
986 ntrec = i / TP_BSIZE;
987 numtrec = ntrec;
988 vprintf(stdout, "Tape block size is %ld\n", ntrec);
989}
990
991void
992closemt()
993{
994
995 if (mt < 0)
996 return;
997#ifdef RRESTORE
998 if (host)
999 rmtclose();
1000 else
1001#endif
1002 (void) close(mt);
1003}
1004
1005/*
1006 * Read the next block from the tape.
1007 * Check to see if it is one of several vintage headers.
1008 * If it is an old style header, convert it to a new style header.
1009 * If it is not any valid header, return an error.
1010 */
1011static int
1012gethead(buf)
1013 struct s_spcl *buf;
1014{
1015 long i;
1016 union {
1017 quad_t qval;
1018 int32_t val[2];
1019 } qcvt;
1020 union u_ospcl {
1021 char dummy[TP_BSIZE];
1022 struct s_ospcl {
1023 int32_t c_type;
1024 int32_t c_date;
1025 int32_t c_ddate;
1026 int32_t c_volume;
1027 int32_t c_tapea;
1028 u_short c_inumber;
1029 int32_t c_magic;
1030 int32_t c_checksum;
1031 struct odinode {
1032 unsigned short odi_mode;
1033 u_short odi_nlink;
1034 u_short odi_uid;
1035 u_short odi_gid;
1036 int32_t odi_size;
1037 int32_t odi_rdev;
1038 char odi_addr[36];
1039 int32_t odi_atime;
1040 int32_t odi_mtime;
1041 int32_t odi_ctime;
1042 } c_dinode;
1043 int32_t c_count;
1044 char c_addr[256];
1045 } s_ospcl;
1046 } u_ospcl;
1047
1048 if (!cvtflag) {
1049 readtape((char *)buf);
1050 if (buf->c_magic != NFS_MAGIC) {
1051 if (swabl(buf->c_magic) != NFS_MAGIC)
1052 return (FAIL);
1053 if (!Bcvt) {
1054 vprintf(stdout, "Note: Doing Byte swapping\n");
1055 Bcvt = 1;
1056 }
1057 }
1058 if (checksum((int *)buf) == FAIL)
1059 return (FAIL);
1060 if (Bcvt) {
1061 swabst((u_char *)"8l4s31l", (u_char *)buf);
1062 swabst((u_char *)"l",(u_char *) &buf->c_level);
1063 swabst((u_char *)"2l",(u_char *) &buf->c_flags);
1064 }
1065 goto good;
1066 }
1067 readtape((char *)(&u_ospcl.s_ospcl));
1068 memset(buf, 0, (long)TP_BSIZE);
1069 buf->c_type = u_ospcl.s_ospcl.c_type;
1070 buf->c_date = u_ospcl.s_ospcl.c_date;
1071 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1072 buf->c_volume = u_ospcl.s_ospcl.c_volume;
1073 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1074 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1075 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1076 buf->c_magic = u_ospcl.s_ospcl.c_magic;
1077 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1078 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1079 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1080 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1081 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1082 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1083 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1084 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1085 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1086 buf->c_count = u_ospcl.s_ospcl.c_count;
1087 memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1088 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1089 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1090 return(FAIL);
1091 buf->c_magic = NFS_MAGIC;
1092
1093good:
1094 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1095 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1096 qcvt.qval = buf->c_dinode.di_size;
1097 if (qcvt.val[0] || qcvt.val[1]) {
1098 printf("Note: Doing Quad swapping\n");
1099 Qcvt = 1;
1100 }
1101 }
1102 if (Qcvt) {
1103 qcvt.qval = buf->c_dinode.di_size;
1104 i = qcvt.val[1];
1105 qcvt.val[1] = qcvt.val[0];
1106 qcvt.val[0] = i;
1107 buf->c_dinode.di_size = qcvt.qval;
1108 }
1109 readmapflag = 0;
1110
1111 switch (buf->c_type) {
1112
1113 case TS_CLRI:
1114 case TS_BITS:
1115 /*
1116 * Have to patch up missing information in bit map headers
1117 */
1118 buf->c_inumber = 0;
1119 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1120 if (buf->c_count > TP_NINDIR)
1121 readmapflag = 1;
1122 else
1123 for (i = 0; i < buf->c_count; i++)
1124 buf->c_addr[i]++;
1125 break;
1126
1127 case TS_TAPE:
1128 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1129 oldinofmt = 1;
1130 /* fall through */
1131 case TS_END:
1132 buf->c_inumber = 0;
1133 break;
1134
1135 case TS_INODE:
1136 case TS_ADDR:
1137 break;
1138
1139 default:
1140 panic("gethead: unknown inode type %d\n", buf->c_type);
1141 break;
1142 }
1143 /*
1144 * If we are restoring a filesystem with old format inodes,
1145 * copy the uid/gid to the new location.
1146 */
1147 if (oldinofmt) {
1148 buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1149 buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1150 }
1151 if (dflag)
1152 accthdr(buf);
1153 return(GOOD);
1154}
1155
1156/*
1157 * Check that a header is where it belongs and predict the next header
1158 */
1159static void
1160accthdr(header)
1161 struct s_spcl *header;
1162{
1163 static ino_t previno = 0x7fffffff;
1164 static int prevtype;
1165 static long predict;
1166 long blks, i;
1167
1168 if (header->c_type == TS_TAPE) {
1169 fprintf(stderr, "Volume header (%s inode format) ",
1170 oldinofmt ? "old" : "new");
1171 if (header->c_firstrec)
1172 fprintf(stderr, "begins with record %ld",
1173 header->c_firstrec);
1174 fprintf(stderr, "\n");
1175 previno = 0x7fffffff;
1176 return;
1177 }
1178 if (previno == 0x7fffffff)
1179 goto newcalc;
1180 switch (prevtype) {
1181 case TS_BITS:
1182 fprintf(stderr, "Dumped inodes map header");
1183 break;
1184 case TS_CLRI:
1185 fprintf(stderr, "Used inodes map header");
1186 break;
1187 case TS_INODE:
1188 fprintf(stderr, "File header, ino %d", previno);
1189 break;
1190 case TS_ADDR:
1191 fprintf(stderr, "File continuation header, ino %d", previno);
1192 break;
1193 case TS_END:
1194 fprintf(stderr, "End of tape header");
1195 break;
1196 }
1197 if (predict != blksread - 1)
1198 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1199 predict, blksread - 1);
1200 fprintf(stderr, "\n");
1201newcalc:
1202 blks = 0;
1203 if (header->c_type != TS_END)
1204 for (i = 0; i < header->c_count; i++)
1205 if (readmapflag || header->c_addr[i] != 0)
1206 blks++;
1207 predict = blks;
1208 blksread = 0;
1209 prevtype = header->c_type;
1210 previno = header->c_inumber;
1211}
1212
1213/*
1214 * Find an inode header.
1215 * Complain if had to skip.
1216 */
1217static void
1218findinode(header)
1219 struct s_spcl *header;
1220{
1221 static long skipcnt = 0;
1222 long i;
1223 char buf[TP_BSIZE];
1224 int htype;
1225
1226 curfile.name = "<name unknown>";
1227 curfile.action = UNKNOWN;
1228 curfile.dip = NULL;
1229 curfile.ino = 0;
1230 do {
1231 if (header->c_magic != NFS_MAGIC) {
1232 skipcnt++;
1233 while (gethead(header) == FAIL ||
1234 _time32_to_time(header->c_date) != dumpdate)
1235 skipcnt++;
1236 }
1225
1226 curfile.name = "<name unknown>";
1227 curfile.action = UNKNOWN;
1228 curfile.dip = NULL;
1229 curfile.ino = 0;
1230 do {
1231 if (header->c_magic != NFS_MAGIC) {
1232 skipcnt++;
1233 while (gethead(header) == FAIL ||
1234 _time32_to_time(header->c_date) != dumpdate)
1235 skipcnt++;
1236 }
1237 switch (header->c_type) {
1237 htype = header->c_type;
1238 switch (htype) {
1238
1239 case TS_ADDR:
1240 /*
1241 * Skip up to the beginning of the next record
1242 */
1243 for (i = 0; i < header->c_count; i++)
1244 if (header->c_addr[i])
1245 readtape(buf);
1246 while (gethead(header) == FAIL ||
1247 _time32_to_time(header->c_date) != dumpdate)
1248 skipcnt++;
1249 break;
1250
1251 case TS_INODE:
1252 curfile.dip = &header->c_dinode;
1253 curfile.ino = header->c_inumber;
1254 break;
1255
1256 case TS_END:
1257 curfile.ino = maxino;
1258 break;
1259
1260 case TS_CLRI:
1261 curfile.name = "<file removal list>";
1262 break;
1263
1264 case TS_BITS:
1265 curfile.name = "<file dump list>";
1266 break;
1267
1268 case TS_TAPE:
1269 panic("unexpected tape header\n");
1270 /* NOTREACHED */
1271
1272 default:
1273 panic("unknown tape header type %d\n", spcl.c_type);
1274 /* NOTREACHED */
1275
1276 }
1239
1240 case TS_ADDR:
1241 /*
1242 * Skip up to the beginning of the next record
1243 */
1244 for (i = 0; i < header->c_count; i++)
1245 if (header->c_addr[i])
1246 readtape(buf);
1247 while (gethead(header) == FAIL ||
1248 _time32_to_time(header->c_date) != dumpdate)
1249 skipcnt++;
1250 break;
1251
1252 case TS_INODE:
1253 curfile.dip = &header->c_dinode;
1254 curfile.ino = header->c_inumber;
1255 break;
1256
1257 case TS_END:
1258 curfile.ino = maxino;
1259 break;
1260
1261 case TS_CLRI:
1262 curfile.name = "<file removal list>";
1263 break;
1264
1265 case TS_BITS:
1266 curfile.name = "<file dump list>";
1267 break;
1268
1269 case TS_TAPE:
1270 panic("unexpected tape header\n");
1271 /* NOTREACHED */
1272
1273 default:
1274 panic("unknown tape header type %d\n", spcl.c_type);
1275 /* NOTREACHED */
1276
1277 }
1277 } while (header->c_type == TS_ADDR);
1278 } while (htype == TS_ADDR);
1278 if (skipcnt > 0)
1279 fprintf(stderr, "resync restore, skipped %ld blocks\n",
1280 skipcnt);
1281 skipcnt = 0;
1282}
1283
1284static int
1285checksum(buf)
1286 register int *buf;
1287{
1288 register int i, j;
1289
1290 j = sizeof(union u_spcl) / sizeof(int);
1291 i = 0;
1292 if(!Bcvt) {
1293 do
1294 i += *buf++;
1295 while (--j);
1296 } else {
1297 /* What happens if we want to read restore tapes
1298 for a 16bit int machine??? */
1299 do
1300 i += swabl(*buf++);
1301 while (--j);
1302 }
1303
1304 if (i != CHECKSUM) {
1305 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1306 curfile.ino, curfile.name);
1307 return(FAIL);
1308 }
1309 return(GOOD);
1310}
1311
1312#ifdef RRESTORE
1313#if __STDC__
1314#include <stdarg.h>
1315#else
1316#include <varargs.h>
1317#endif
1318
1319void
1320#if __STDC__
1321msg(const char *fmt, ...)
1322#else
1323msg(fmt, va_alist)
1324 char *fmt;
1325 va_dcl
1326#endif
1327{
1328 va_list ap;
1329#if __STDC__
1330 va_start(ap, fmt);
1331#else
1332 va_start(ap);
1333#endif
1334 (void)vfprintf(stderr, fmt, ap);
1335 va_end(ap);
1336}
1337#endif /* RRESTORE */
1338
1339static u_char *
1340swabshort(sp, n)
1341 register u_char *sp;
1342 register int n;
1343{
1344 char c;
1345
1346 while (--n >= 0) {
1347 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1348 sp += 2;
1349 }
1350 return (sp);
1351}
1352
1353static u_char *
1354swablong(sp, n)
1355 register u_char *sp;
1356 register int n;
1357{
1358 char c;
1359
1360 while (--n >= 0) {
1361 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1362 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1363 sp += 4;
1364 }
1365 return (sp);
1366}
1367
1368void
1369swabst(cp, sp)
1370 register u_char *cp, *sp;
1371{
1372 int n = 0;
1373
1374 while (*cp) {
1375 switch (*cp) {
1376 case '0': case '1': case '2': case '3': case '4':
1377 case '5': case '6': case '7': case '8': case '9':
1378 n = (n * 10) + (*cp++ - '0');
1379 continue;
1380
1381 case 's': case 'w': case 'h':
1382 if (n == 0)
1383 n = 1;
1384 sp = swabshort(sp, n);
1385 break;
1386
1387 case 'l':
1388 if (n == 0)
1389 n = 1;
1390 sp = swablong(sp, n);
1391 break;
1392
1393 default: /* Any other character, like 'b' counts as byte. */
1394 if (n == 0)
1395 n = 1;
1396 sp += n;
1397 break;
1398 }
1399 cp++;
1400 n = 0;
1401 }
1402}
1403
1404static u_long
1405swabl(x)
1406 u_long x;
1407{
1408 swabst((u_char *)"l", (u_char *)&x);
1409 return (x);
1410}
1279 if (skipcnt > 0)
1280 fprintf(stderr, "resync restore, skipped %ld blocks\n",
1281 skipcnt);
1282 skipcnt = 0;
1283}
1284
1285static int
1286checksum(buf)
1287 register int *buf;
1288{
1289 register int i, j;
1290
1291 j = sizeof(union u_spcl) / sizeof(int);
1292 i = 0;
1293 if(!Bcvt) {
1294 do
1295 i += *buf++;
1296 while (--j);
1297 } else {
1298 /* What happens if we want to read restore tapes
1299 for a 16bit int machine??? */
1300 do
1301 i += swabl(*buf++);
1302 while (--j);
1303 }
1304
1305 if (i != CHECKSUM) {
1306 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1307 curfile.ino, curfile.name);
1308 return(FAIL);
1309 }
1310 return(GOOD);
1311}
1312
1313#ifdef RRESTORE
1314#if __STDC__
1315#include <stdarg.h>
1316#else
1317#include <varargs.h>
1318#endif
1319
1320void
1321#if __STDC__
1322msg(const char *fmt, ...)
1323#else
1324msg(fmt, va_alist)
1325 char *fmt;
1326 va_dcl
1327#endif
1328{
1329 va_list ap;
1330#if __STDC__
1331 va_start(ap, fmt);
1332#else
1333 va_start(ap);
1334#endif
1335 (void)vfprintf(stderr, fmt, ap);
1336 va_end(ap);
1337}
1338#endif /* RRESTORE */
1339
1340static u_char *
1341swabshort(sp, n)
1342 register u_char *sp;
1343 register int n;
1344{
1345 char c;
1346
1347 while (--n >= 0) {
1348 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1349 sp += 2;
1350 }
1351 return (sp);
1352}
1353
1354static u_char *
1355swablong(sp, n)
1356 register u_char *sp;
1357 register int n;
1358{
1359 char c;
1360
1361 while (--n >= 0) {
1362 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1363 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1364 sp += 4;
1365 }
1366 return (sp);
1367}
1368
1369void
1370swabst(cp, sp)
1371 register u_char *cp, *sp;
1372{
1373 int n = 0;
1374
1375 while (*cp) {
1376 switch (*cp) {
1377 case '0': case '1': case '2': case '3': case '4':
1378 case '5': case '6': case '7': case '8': case '9':
1379 n = (n * 10) + (*cp++ - '0');
1380 continue;
1381
1382 case 's': case 'w': case 'h':
1383 if (n == 0)
1384 n = 1;
1385 sp = swabshort(sp, n);
1386 break;
1387
1388 case 'l':
1389 if (n == 0)
1390 n = 1;
1391 sp = swablong(sp, n);
1392 break;
1393
1394 default: /* Any other character, like 'b' counts as byte. */
1395 if (n == 0)
1396 n = 1;
1397 sp += n;
1398 break;
1399 }
1400 cp++;
1401 n = 0;
1402 }
1403}
1404
1405static u_long
1406swabl(x)
1407 u_long x;
1408{
1409 swabst((u_char *)"l", (u_char *)&x);
1410 return (x);
1411}