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