]> git.wh0rd.org - dump.git/blob - restore/tape.c
Fixed compare of dumped socket files by ignoring them.
[dump.git] / restore / tape.c
1 /*
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
4 * Remy Card <card@Linux.EU.Org>, 1994-1997
5 * Stelian Pop <stelian@popies.net>, 1999-2000
6 * Stelian Pop <stelian@popies.net> - AlcĂ´ve <www.alcove.com>, 2000-2002
7 */
8
9 /*
10 * Copyright (c) 1983, 1993
11 * The Regents of the University of California. All rights reserved.
12 * (c) UNIX System Laboratories, Inc.
13 * All or some portions of this file are derived from material licensed
14 * to the University of California by American Telephone and Telegraph
15 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
16 * the permission of UNIX System Laboratories, Inc.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. All advertising materials mentioning features or use of this software
27 * must display the following acknowledgement:
28 * This product includes software developed by the University of
29 * California, Berkeley and its contributors.
30 * 4. Neither the name of the University nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
46
47 #ifndef lint
48 static const char rcsid[] =
49 "$Id: tape.c,v 1.68 2003/02/11 09:56:48 stelian Exp $";
50 #endif /* not lint */
51
52 #include <config.h>
53 #include <compatlfs.h>
54 #include <errno.h>
55 #include <compaterr.h>
56 #include <system.h>
57 #include <setjmp.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <unistd.h>
62
63 #include <sys/param.h>
64 #include <sys/file.h>
65 #include <sys/mtio.h>
66 #include <sys/stat.h>
67
68 #ifdef __linux__
69 #include <sys/time.h>
70 #include <time.h>
71 #ifdef HAVE_EXT2FS_EXT2_FS_H
72 #include <ext2fs/ext2_fs.h>
73 #else
74 #include <linux/ext2_fs.h>
75 #endif
76 #include <ext2fs/ext2fs.h>
77 #include <bsdcompat.h>
78 #else /* __linux__ */
79 #include <ufs/ufs/dinode.h>
80 #endif /* __linux__ */
81 #include <protocols/dumprestore.h>
82
83 #ifdef HAVE_ZLIB
84 #include <zlib.h>
85 #endif /* HAVE_ZLIB */
86
87 #ifdef HAVE_BZLIB
88 #include <bzlib.h>
89 #endif /* HAVE_BZLIB */
90
91 #include "restore.h"
92 #include "extern.h"
93 #include "pathnames.h"
94
95 #ifdef USE_QFA
96 int noresyncmesg = 0;
97 #endif /* USE_QFA */
98 static long fssize = MAXBSIZE;
99 static int mt = -1;
100 int pipein = 0;
101 static int magtapein = 0; /* input is from magtape */
102 static char magtape[MAXPATHLEN];
103 static char magtapeprefix[MAXPATHLEN];
104 static int blkcnt;
105 static int numtrec;
106 static char *tapebuf; /* input buffer for read */
107 static int bufsize; /* buffer size without prefix */
108 static char *tbufptr = NULL; /* active tape buffer */
109 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
110 static char *comprbuf; /* uncompress work buf */
111 static size_t comprlen; /* size including prefix */
112 #endif
113 static union u_spcl endoftapemark;
114 static long blksread; /* blocks read since last header */
115 static long tpblksread = 0; /* TP_BSIZE blocks read */
116 static long tapesread;
117 static sigjmp_buf restart;
118 static int gettingfile = 0; /* restart has a valid frame */
119 char *host = NULL;
120
121 static int ofile;
122 static char *map;
123 static char lnkbuf[MAXPATHLEN + 1];
124 static int pathlen;
125
126 int oldinofmt; /* old inode format conversion required */
127 int Bcvt; /* Swap Bytes (for CCI or sun) */
128 static int Qcvt; /* Swap quads (for sun) */
129
130 #define FLUSHTAPEBUF() blkcnt = ntrec + 1
131
132 static void accthdr __P((struct s_spcl *));
133 static int checksum __P((int *));
134 static void findinode __P((struct s_spcl *));
135 static void findtapeblksize __P((void));
136 static int gethead __P((struct s_spcl *));
137 static int converthead __P((struct s_spcl *));
138 static void converttapebuf __P((struct tapebuf *));
139 static void readtape __P((char *));
140 static void setdumpnum __P((void));
141 static u_int swabi __P((u_int));
142 #if 0
143 static u_long swabl __P((u_long));
144 #endif
145 static u_char *swab64 __P((u_char *, int));
146 static u_char *swab32 __P((u_char *, int));
147 static u_char *swab16 __P((u_char *, int));
148 static void terminateinput __P((void));
149 static void xtrfile __P((char *, size_t));
150 static void xtrlnkfile __P((char *, size_t));
151 static void xtrlnkskip __P((char *, size_t));
152 static void xtrmap __P((char *, size_t));
153 static void xtrmapskip __P((char *, size_t));
154 static void xtrskip __P((char *, size_t));
155 static void setmagtapein __P((void));
156
157 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
158 static void newcomprbuf __P((int));
159 static void (*readtape_func) __P((char *));
160 static void readtape_set __P((char *));
161 static void readtape_uncompr __P((char *));
162 static void readtape_comprfile __P((char *));
163 static void readtape_comprtape __P((char *));
164 static char *decompress_tapebuf __P((struct tapebuf *, int));
165 static void msg_read_error __P((char *));
166 #endif
167 static int read_a_block __P((int, char *, size_t, long *));
168 #define PREFIXSIZE sizeof(struct tapebuf)
169
170 #define COMPARE_ONTHEFLY 1
171
172 #if COMPARE_ONTHEFLY
173 static int ifile; /* input file for compare */
174 static int cmperror; /* compare error */
175 static void xtrcmpfile __P((char *, size_t));
176 static void xtrcmpskip __P((char *, size_t));
177 #endif
178
179 static int readmapflag;
180 static int readingmaps; /* set to 1 while reading the maps */
181
182 /*
183 * Set up an input source. This is called from main.c before setup() is.
184 */
185 void
186 setinput(char *source)
187 {
188 FLUSHTAPEBUF();
189 if (bflag)
190 newtapebuf(ntrec);
191 else
192 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
193 terminal = stdin;
194
195 #ifdef RRESTORE
196 if (strchr(source, ':')) {
197 host = source;
198 source = strchr(host, ':');
199 *source++ = '\0';
200 if (rmthost(host) == 0)
201 exit(1);
202 } else
203 #endif
204 if (strcmp(source, "-") == 0) {
205 /*
206 * Since input is coming from a pipe we must establish
207 * our own connection to the terminal.
208 */
209 terminal = fopen(_PATH_TTY, "r");
210 if (terminal == NULL) {
211 warn("cannot open %s", _PATH_TTY);
212 terminal = fopen(_PATH_DEVNULL, "r");
213 if (terminal == NULL)
214 err(1, "cannot open %s", _PATH_DEVNULL);
215 }
216 pipein++;
217 }
218 setuid(getuid()); /* no longer need or want root privileges */
219 if (Mflag) {
220 strncpy(magtapeprefix, source, MAXPATHLEN);
221 magtapeprefix[MAXPATHLEN-1] = '\0';
222 snprintf(magtape, MAXPATHLEN, "%s%03d", source, 1);
223 }
224 else
225 strncpy(magtape, source, MAXPATHLEN);
226 magtape[MAXPATHLEN - 1] = '\0';
227 }
228
229 void
230 newtapebuf(long size)
231 {
232 static int tapebufsize = -1;
233
234 ntrec = size;
235 bufsize = ntrec * TP_BSIZE;
236 if (size <= tapebufsize)
237 return;
238 if (tapebuf != NULL)
239 free(tapebuf);
240 tapebuf = malloc(size * TP_BSIZE + sizeof(struct tapebuf));
241 if (tapebuf == NULL)
242 errx(1, "Cannot allocate space for tape buffer");
243 tapebufsize = size;
244 }
245
246 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
247 static void
248 newcomprbuf(int size)
249 {
250 size_t buf_size = (size+1) * TP_BSIZE + sizeof(struct tapebuf);
251 if (buf_size <= comprlen)
252 return;
253 comprlen = buf_size;
254 if (comprbuf != NULL)
255 free(comprbuf);
256 comprbuf = malloc(comprlen);
257 if (comprbuf == NULL)
258 errx(1, "Cannot allocate space for decompress buffer");
259 }
260 #endif /* HAVE_ZLIB || HAVE_BZLIB */
261
262 /*
263 * Verify that the tape drive can be accessed and
264 * that it actually is a dump tape.
265 */
266 void
267 setup(void)
268 {
269 int i, j, *ip, bot_code;
270 struct STAT stbuf;
271 char *temptape;
272
273 Vprintf(stdout, "Verify tape and initialize maps\n");
274 if (Afile == NULL && bot_script) {
275 msg("Launching %s\n", bot_script);
276 bot_code = system_command(bot_script, magtape, 1);
277 if (bot_code != 0 && bot_code != 1) {
278 msg("Restore aborted by the beginning of tape script\n");
279 exit(1);
280 }
281 }
282
283 if (Afile)
284 temptape = Afile;
285 else
286 temptape = magtape;
287
288 #ifdef RRESTORE
289 if (host)
290 mt = rmtopen(temptape, O_RDONLY);
291 else
292 #endif
293 if (pipein)
294 mt = 0;
295 else
296 mt = OPEN(temptape, O_RDONLY, 0);
297 if (mt < 0)
298 err(1, "%s", magtape);
299 if (!Afile) {
300 volno = 1;
301 setmagtapein();
302 setdumpnum();
303 }
304 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
305 readtape_func = readtape_set;
306 #endif
307 FLUSHTAPEBUF();
308 findtapeblksize();
309 if (gethead(&spcl) == FAIL) {
310 blkcnt--; /* push back this block */
311 blksread--;
312 tpblksread--;
313 cvtflag++;
314 if (gethead(&spcl) == FAIL)
315 errx(1, "Tape is not a dump tape");
316 fprintf(stderr, "Converting to new file system format.\n");
317 }
318
319 if (zflag) {
320 fprintf(stderr, "Dump tape is compressed.\n");
321 #if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB)
322 errx(1,"This restore version doesn't support decompression");
323 #endif /* !HAVE_ZLIB && !HAVE_BZLIB */
324 }
325 if (pipein) {
326 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
327 endoftapemark.s_spcl.c_type = TS_END;
328 ip = (int *)&endoftapemark;
329 j = sizeof(union u_spcl) / sizeof(int);
330 i = 0;
331 do
332 i += *ip++;
333 while (--j);
334 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
335 }
336 if (vflag || command == 't' || command == 'C')
337 printdumpinfo();
338 #ifdef USE_QFA
339 if (tapeposflag && (unsigned long)spcl.c_date != qfadumpdate)
340 errx(1, "different QFA/dumpdates detected\n");
341 #endif
342 if (filesys[0] == '\0') {
343 char *dirptr;
344 strncpy(filesys, spcl.c_filesys, NAMELEN);
345 filesys[NAMELEN - 1] = '\0';
346 dirptr = strstr(filesys, " (dir");
347 if (dirptr != NULL)
348 *dirptr = '\0';
349 }
350 dumptime = spcl.c_ddate;
351 dumpdate = spcl.c_date;
352 if (STAT(".", &stbuf) < 0)
353 err(1, "cannot stat .");
354 if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
355 fssize = TP_BSIZE;
356 if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
357 fssize = stbuf.st_blksize;
358 if (((fssize - 1) & fssize) != 0)
359 errx(1, "bad block size %ld", fssize);
360 if (spcl.c_volume != 1)
361 errx(1, "Tape is not volume 1 of the dump");
362 if (gethead(&spcl) == FAIL) {
363 Dprintf(stdout, "header read failed at %ld blocks\n", (long)blksread);
364 panic("no header after volume mark!\n");
365 }
366 readingmaps = 1;
367 findinode(&spcl);
368 if (spcl.c_type != TS_CLRI)
369 errx(1, "Cannot find file removal list");
370 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
371 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
372 if (map == NULL)
373 errx(1, "no memory for active inode map");
374 usedinomap = map;
375 curfile.action = USING;
376 getfile(xtrmap, xtrmapskip);
377 while (spcl.c_type == TS_ADDR) {
378 /* Recompute maxino and the map */
379 dump_ino_t oldmaxino = maxino;
380 maxino += (spcl.c_count * TP_BSIZE * NBBY) + 1;
381 resizemaps(oldmaxino, maxino);
382
383 spcl.c_dinode.di_size = spcl.c_count * TP_BSIZE;
384 getfile(xtrmap, xtrmapskip);
385 }
386 Dprintf(stdout, "maxino = %lu\n", (unsigned long)maxino);
387 if (spcl.c_type != TS_BITS)
388 errx(1, "Cannot find file dump list");
389 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
390 if (map == (char *)NULL)
391 errx(1, "no memory for file dump list");
392 dumpmap = map;
393 curfile.action = USING;
394 getfile(xtrmap, xtrmapskip);
395 while (spcl.c_type == TS_ADDR) {
396 spcl.c_dinode.di_size = spcl.c_count * TP_BSIZE;
397 getfile(xtrmap, xtrmapskip);
398 }
399 /*
400 * If there may be whiteout entries on the tape, pretend that the
401 * whiteout inode exists, so that the whiteout entries can be
402 * extracted.
403 */
404 if (oldinofmt == 0)
405 SETINO(WINO, dumpmap);
406 readingmaps = 0;
407 findinode(&spcl);
408 }
409
410 /*
411 * Prompt user to load a new dump volume.
412 * "Nextvol" is the next suggested volume to use.
413 * This suggested volume is enforced when doing full
414 * or incremental restores, but can be overridden by
415 * the user when only extracting a subset of the files.
416 */
417 void
418 getvol(long nextvol)
419 {
420 long newvol = 0, wantnext = 0, i;
421 long saved_blksread = 0, saved_tpblksread = 0;
422 union u_spcl tmpspcl;
423 # define tmpbuf tmpspcl.s_spcl
424 char buf[TP_BSIZE];
425 int haderror = 0, bot_code = 1;
426
427 if (nextvol == 1) {
428 tapesread = 0;
429 gettingfile = 0;
430 tpblksread = 0;
431 blksread = 0;
432 }
433 if (pipein) {
434 if (nextvol != 1)
435 panic("Changing volumes on pipe input?\n");
436 if (volno == 1)
437 return;
438 goto gethdr;
439 }
440 saved_blksread = blksread;
441 saved_tpblksread = tpblksread;
442 #if defined(USE_QFA) && defined(sunos)
443 if (createtapeposflag || tapeposflag)
444 close(fdsmtc);
445 #endif
446 again:
447 if (pipein)
448 exit(1); /* pipes do not get a second chance */
449 if (aflag || curfile.action != SKIP) {
450 newvol = nextvol;
451 wantnext = 1;
452 } else {
453 newvol = 0;
454 wantnext = 0;
455 }
456 while (newvol <= 0) {
457 if (tapesread == 0) {
458 fprintf(stderr, "%s%s%s%s%s",
459 "You have not read any volumes yet.\n",
460 "Unless you know which volume your",
461 " file(s) are on you should start\n",
462 "with the last volume and work",
463 " towards the first.\n");
464 } else {
465 fprintf(stderr, "You have read volumes");
466 strcpy(buf, ": ");
467 for (i = 1; i < 32; i++)
468 if (tapesread & (1 << i)) {
469 fprintf(stderr, "%s%ld", buf, (long)i);
470 strcpy(buf, ", ");
471 }
472 fprintf(stderr, "\n");
473 }
474 do {
475 fprintf(stderr, "Specify next volume # (none if no more volumes): ");
476 (void) fflush(stderr);
477 (void) fgets(buf, TP_BSIZE, terminal);
478 } while (!feof(terminal) && buf[0] == '\n');
479 if (feof(terminal))
480 exit(1);
481 if (!strcmp(buf, "none\n")) {
482 terminateinput();
483 return;
484 }
485 newvol = atoi(buf);
486 if (newvol <= 0) {
487 fprintf(stderr,
488 "Volume numbers are positive numerics\n");
489 }
490 }
491 if (newvol == volno) {
492 tapesread |= 1 << volno;
493 #if defined(USE_QFA) && defined(sunos)
494 if (createtapeposflag || tapeposflag) {
495 if (OpenSMTCmt(magtape) < 0) {
496 volno = -1;
497 haderror = 1;
498 goto again;
499 }
500 }
501 #endif
502 return;
503 }
504 closemt();
505 if (Mflag) {
506 snprintf(magtape, MAXPATHLEN, "%s%03ld", magtapeprefix, newvol);
507 magtape[MAXPATHLEN - 1] = '\0';
508 }
509 if (bot_script && !haderror) {
510 msg("Launching %s\n", bot_script);
511 bot_code = system_command(bot_script, magtape, newvol);
512 if (bot_code != 0 && bot_code != 1) {
513 msg("Restore aborted by the beginning of tape script\n");
514 exit(1);
515 }
516 }
517 if (haderror || (bot_code && !Mflag)) {
518 haderror = 0;
519 fprintf(stderr, "Mount volume %ld\n", (long)newvol);
520 fprintf(stderr, "Enter ``none'' if there are no more volumes\n");
521 fprintf(stderr, "otherwise enter volume name (default: %s) ", magtape);
522 (void) fflush(stderr);
523 (void) fgets(buf, TP_BSIZE, terminal);
524 if (feof(terminal))
525 exit(1);
526 if (!strcmp(buf, "none\n")) {
527 terminateinput();
528 return;
529 }
530 if (buf[0] != '\n') {
531 char *pos;
532 (void) strncpy(magtape, buf, sizeof(magtape));
533 magtape[sizeof(magtape) - 1] = '\0';
534 if ((pos = strchr(magtape, '\n')))
535 magtape[pos - magtape] = '\0';
536 }
537 }
538 #ifdef RRESTORE
539 if (host)
540 mt = rmtopen(magtape, O_RDONLY);
541 else
542 #endif
543 mt = OPEN(magtape, O_RDONLY, 0);
544
545 if (mt == -1) {
546 fprintf(stderr, "Cannot open %s\n", magtape);
547 volno = -1;
548 haderror = 1;
549 goto again;
550 }
551 gethdr:
552 setmagtapein();
553 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
554 readtape_func = readtape_set;
555 #endif
556 volno = newvol;
557 setdumpnum();
558 FLUSHTAPEBUF();
559 findtapeblksize();
560 if (gethead(&tmpbuf) == FAIL) {
561 Dprintf(stdout, "header read failed at %ld blocks\n", (long)blksread);
562 fprintf(stderr, "tape is not dump tape\n");
563 volno = 0;
564 haderror = 1;
565 blksread = saved_blksread;
566 tpblksread = saved_tpblksread;
567 goto again;
568 }
569 if (tmpbuf.c_volume != volno) {
570 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
571 volno = 0;
572 haderror = 1;
573 blksread = saved_blksread;
574 tpblksread = saved_tpblksread;
575 goto again;
576 }
577 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
578 fprintf(stderr, "Wrong dump date\n\tgot: %s",
579 ctime4(&tmpbuf.c_date));
580 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
581 volno = 0;
582 haderror = 1;
583 blksread = saved_blksread;
584 tpblksread = saved_tpblksread;
585 goto again;
586 }
587 tapesread |= 1 << volno;
588 /*
589 * If continuing from the previous volume, skip over any
590 * blocks read already at the end of the previous volume.
591 *
592 * If coming to this volume at random, skip to the beginning
593 * of the next record.
594 */
595 if (zflag) {
596 fprintf(stderr, "Dump tape is compressed.\n");
597 #if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB)
598 errx(1,"This restore version doesn't support decompression");
599 #endif /* !HAVE_ZLIB && !HAVE_BZLIB */
600 }
601 Dprintf(stdout, "read %ld recs, tape starts with %ld\n",
602 tpblksread - 1, (long)tmpbuf.c_firstrec);
603 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
604 if (!wantnext) {
605 tpblksread = tmpbuf.c_firstrec + 1;
606 for (i = tmpbuf.c_count; i > 0; i--)
607 readtape(buf);
608 } else if (tmpbuf.c_firstrec > 0 &&
609 tmpbuf.c_firstrec < tpblksread - 1) {
610 /*
611 * -1 since we've read the volume header
612 */
613 i = tpblksread - tmpbuf.c_firstrec - 1;
614 Dprintf(stderr, "Skipping %ld duplicate record%s.\n",
615 (long)i, i > 1 ? "s" : "");
616 while (--i >= 0)
617 readtape(buf);
618 }
619 }
620 if (curfile.action == USING) {
621 if (volno == 1)
622 panic("active file into volume 1\n");
623 return;
624 }
625 /*
626 * Skip up to the beginning of the next record
627 */
628 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
629 for (i = tmpbuf.c_count; i > 0; i--)
630 readtape(buf);
631 (void) gethead(&spcl);
632 findinode(&spcl);
633 if (gettingfile) {
634 gettingfile = 0;
635 siglongjmp(restart, 1);
636 }
637 }
638
639 /*
640 * Handle unexpected EOF.
641 */
642 static void
643 terminateinput(void)
644 {
645
646 if (gettingfile && curfile.action == USING) {
647 printf("Warning: %s %s\n",
648 "End-of-input encountered while extracting", curfile.name);
649 }
650 curfile.name = "<name unknown>";
651 curfile.action = UNKNOWN;
652 curfile.dip = NULL;
653 curfile.ino = maxino;
654 if (gettingfile) {
655 gettingfile = 0;
656 siglongjmp(restart, 1);
657 }
658 }
659
660 /*
661 * handle multiple dumps per tape by skipping forward to the
662 * appropriate one.
663 */
664 static void
665 setdumpnum(void)
666 {
667 struct mtop tcom;
668
669 if (dumpnum == 1 || volno != 1)
670 return;
671 if (pipein)
672 errx(1, "Cannot have multiple dumps on pipe input");
673 tcom.mt_op = MTFSF;
674 tcom.mt_count = dumpnum - 1;
675 #ifdef RRESTORE
676 if (host)
677 rmtioctl(MTFSF, dumpnum - 1);
678 else
679 #endif
680 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
681 warn("ioctl MTFSF");
682 }
683
684 void
685 printdumpinfo(void)
686 {
687 fprintf(stdout, "Dump date: %s", ctime4(&spcl.c_date));
688 fprintf(stdout, "Dumped from: %s",
689 (spcl.c_ddate == 0) ? "the epoch\n" : ctime4(&spcl.c_ddate));
690 if (spcl.c_host[0] == '\0')
691 return;
692 fprintf(stdout, "Level %d dump of %s on %s:%s\n",
693 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
694 fprintf(stdout, "Label: %s\n", spcl.c_label);
695 }
696
697 void
698 printvolinfo(void)
699 {
700 int i;
701
702 if (volinfo[1] == ROOTINO) {
703 printf("Starting inode numbers by volume:\n");
704 for (i = 1; i < (int)TP_NINOS && volinfo[i] != 0; ++i)
705 printf("\tVolume %d: %lu\n", i, (unsigned long)volinfo[i]);
706 }
707 }
708
709 #ifdef sunos
710 struct timeval
711 time_t tv_sec; /* seconds */
712 suseconds_t tv_usec; /* and microseconds */
713 };
714 #endif
715
716 int
717 extractfile(struct entry *ep, int doremove)
718 {
719 unsigned int flags;
720 mode_t mode;
721 struct timeval timep[2];
722 char *name = myname(ep);
723
724 /* If removal is requested (-r mode) do remove it unless
725 * we are extracting a metadata only inode */
726 if (spcl.c_flags & DR_METAONLY) {
727 Vprintf(stdout, "file %s is metadata only\n", name);
728 }
729 else {
730 if (doremove) {
731 removeleaf(ep);
732 ep->e_flags &= ~REMOVED;
733 }
734 }
735
736 curfile.name = name;
737 curfile.action = USING;
738 #if defined(__linux__) || defined(sunos)
739 timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
740 timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
741 timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
742 timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
743 #else /* __linux__ || sunos */
744 timep[0].tv_sec = curfile.dip->di_atime;
745 timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
746 timep[1].tv_sec = curfile.dip->di_mtime;
747 timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
748 #endif /* __linux__ */
749 mode = curfile.dip->di_mode;
750 flags = curfile.dip->di_flags;
751 switch (mode & IFMT) {
752
753 default:
754 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
755 skipfile();
756 return (FAIL);
757
758 case IFSOCK:
759 Vprintf(stdout, "skipped socket %s\n", name);
760 skipfile();
761 return (GOOD);
762
763 case IFDIR:
764 if (mflag) {
765 if (ep == NULL || ep->e_flags & EXTRACT)
766 panic("unextracted directory %s\n", name);
767 skipfile();
768 return (GOOD);
769 }
770 Vprintf(stdout, "extract file %s\n", name);
771 return (genliteraldir(name, curfile.ino));
772
773 case IFLNK:
774 {
775 #ifdef HAVE_LCHOWN
776 uid_t luid = curfile.dip->di_uid;
777 gid_t lgid = curfile.dip->di_gid;
778 #endif
779 if (! (spcl.c_flags & DR_METAONLY)) {
780 lnkbuf[0] = '\0';
781 pathlen = 0;
782 getfile(xtrlnkfile, xtrlnkskip);
783 if (pathlen == 0) {
784 Vprintf(stdout,
785 "%s: zero length symbolic link (ignored)\n", name);
786 return (GOOD);
787 }
788 if (linkit(lnkbuf, name, SYMLINK) == FAIL)
789 return (FAIL);
790 }
791 else
792 skipfile();
793
794 #ifdef HAVE_LCHOWN
795 (void) lchown(name, luid, lgid);
796 #endif
797 return (GOOD);
798 }
799
800 case IFIFO:
801 Vprintf(stdout, "extract fifo %s\n", name);
802 if (Nflag) {
803 skipfile();
804 return (GOOD);
805 }
806 if (! (spcl.c_flags & DR_METAONLY)) {
807 if (uflag && !Nflag)
808 (void)unlink(name);
809 if (mkfifo(name, mode) < 0) {
810 warn("%s: cannot create fifo", name);
811 skipfile();
812 return (FAIL);
813 }
814 }
815 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
816 (void) chmod(name, mode);
817 if (flags)
818 #ifdef __linux__
819 (void) fsetflags(name, flags);
820 #else
821 (void) chflags(name, flags);
822 #endif
823 skipfile();
824 utimes(name, timep);
825 return (GOOD);
826
827 case IFCHR:
828 case IFBLK:
829 Vprintf(stdout, "extract special file %s\n", name);
830 if (Nflag) {
831 skipfile();
832 return (GOOD);
833 }
834 if (! (spcl.c_flags & DR_METAONLY)) {
835 if (uflag)
836 (void)unlink(name);
837 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
838 warn("%s: cannot create special file", name);
839 skipfile();
840 return (FAIL);
841 }
842 }
843 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
844 (void) chmod(name, mode);
845 if (flags)
846 #ifdef __linux__
847 {
848 warn("%s: fsetflags called on a special file", name);
849 (void) fsetflags(name, flags);
850 }
851 #else
852 (void) chflags(name, flags);
853 #endif
854 skipfile();
855 utimes(name, timep);
856 return (GOOD);
857
858 case IFREG:
859 {
860 uid_t luid = curfile.dip->di_uid;
861 gid_t lgid = curfile.dip->di_gid;
862
863 Vprintf(stdout, "extract file %s\n", name);
864 if (Nflag) {
865 skipfile();
866 return (GOOD);
867 }
868 if (! (spcl.c_flags & DR_METAONLY)) {
869 if (uflag)
870 (void)unlink(name);
871 if ((ofile = OPEN(name, O_WRONLY | O_CREAT | O_TRUNC,
872 0666)) < 0) {
873 warn("%s: cannot create file", name);
874 skipfile();
875 return (FAIL);
876 }
877 getfile(xtrfile, xtrskip);
878 (void) close(ofile);
879 }
880 else
881 skipfile();
882 (void) chown(name, luid, lgid);
883 (void) chmod(name, mode);
884 if (flags)
885 #ifdef __linux__
886 (void) fsetflags(name, flags);
887 #else
888 (void) chflags(name, flags);
889 #endif
890 utimes(name, timep);
891 return (GOOD);
892 }
893 }
894 /* NOTREACHED */
895 }
896
897 /*
898 * skip over bit maps on the tape
899 */
900 void
901 skipmaps(void)
902 {
903
904 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
905 skipfile();
906 }
907
908 /*
909 * skip over a file on the tape
910 */
911 void
912 skipfile(void)
913 {
914
915 curfile.action = SKIP;
916 getfile(xtrnull, xtrnull);
917 }
918
919 /*
920 * Extract a file from the tape.
921 * When an allocated block is found it is passed to the fill function;
922 * when an unallocated block (hole) is found, a zeroed buffer is passed
923 * to the skip function.
924 */
925 void
926 getfile(void (*fill) __P((char *, size_t)), void (*skip) __P((char *, size_t)))
927 {
928 int i;
929 volatile int curblk = 0;
930 volatile quad_t size = spcl.c_dinode.di_size;
931 volatile int last_write_was_hole = 0;
932 quad_t origsize = size;
933 static char clearedbuf[MAXBSIZE];
934 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
935 char junk[TP_BSIZE];
936
937 if (spcl.c_type == TS_END)
938 panic("ran off end of tape\n");
939 if (spcl.c_magic != NFS_MAGIC)
940 panic("not at beginning of a file\n");
941 if (!gettingfile && setjmp(restart) != 0)
942 return;
943 gettingfile++;
944 loop:
945 for (i = 0; i < spcl.c_count; i++) {
946 if (readmapflag || spcl.c_addr[i]) {
947 readtape(&buf[curblk++][0]);
948 if (curblk == fssize / TP_BSIZE) {
949 (*fill)((char *)buf, (size_t)(size > TP_BSIZE ?
950 fssize : (curblk - 1) * TP_BSIZE + size));
951 curblk = 0;
952 last_write_was_hole = 0;
953 }
954 } else {
955 if (curblk > 0) {
956 (*fill)((char *)buf, (size_t)(size > TP_BSIZE ?
957 curblk * TP_BSIZE :
958 (curblk - 1) * TP_BSIZE + size));
959 curblk = 0;
960 }
961 (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
962 TP_BSIZE : size));
963 last_write_was_hole = 1;
964 }
965 if ((size -= TP_BSIZE) <= 0) {
966 for (i++; i < spcl.c_count; i++)
967 if (readmapflag || spcl.c_addr[i])
968 readtape(junk);
969 break;
970 }
971 }
972 if (gethead(&spcl) == GOOD && size > 0) {
973 if (spcl.c_type == TS_ADDR)
974 goto loop;
975 Dprintf(stdout,
976 "Missing address (header) block for %s at %ld blocks\n",
977 curfile.name, (long)blksread);
978 }
979 if (curblk > 0) {
980 (*fill)((char *)buf, (size_t)((curblk * TP_BSIZE) + size));
981 last_write_was_hole = 0;
982 }
983 if (size > 0) {
984 fprintf(stderr, "Missing blocks at the end of %s, assuming hole\n", curfile.name);
985 while (size > 0) {
986 size_t skp = size > TP_BSIZE ? TP_BSIZE : size;
987 (*skip)(clearedbuf, skp);
988 size -= skp;
989 }
990 last_write_was_hole = 1;
991 }
992 if (last_write_was_hole) {
993 FTRUNCATE(ofile, origsize);
994 }
995 if (!readingmaps)
996 findinode(&spcl);
997 gettingfile = 0;
998 }
999
1000 /*
1001 * Write out the next block of a file.
1002 */
1003 static void
1004 xtrfile(char *buf, size_t size)
1005 {
1006
1007 if (Nflag)
1008 return;
1009 if (write(ofile, buf, (int) size) == -1)
1010 err(1, "write error extracting inode %lu, name %s\nwrite",
1011 (unsigned long)curfile.ino, curfile.name);
1012 }
1013
1014 /*
1015 * Skip over a hole in a file.
1016 */
1017 /* ARGSUSED */
1018 static void
1019 xtrskip(UNUSED(char *buf), size_t size)
1020 {
1021
1022 if (LSEEK(ofile, (OFF_T)size, SEEK_CUR) == -1)
1023 err(1, "seek error extracting inode %lu, name %s\nlseek",
1024 (unsigned long)curfile.ino, curfile.name);
1025 }
1026
1027 /*
1028 * Collect the next block of a symbolic link.
1029 */
1030 static void
1031 xtrlnkfile(char *buf, size_t size)
1032 {
1033
1034 pathlen += size;
1035 if (pathlen > MAXPATHLEN)
1036 errx(1, "symbolic link name: %s->%s%s; too long %d",
1037 curfile.name, lnkbuf, buf, pathlen);
1038 (void) strcat(lnkbuf, buf);
1039 }
1040
1041 /*
1042 * Skip over a hole in a symbolic link (should never happen).
1043 */
1044 /* ARGSUSED */
1045 static void
1046 xtrlnkskip(UNUSED(char *buf), UNUSED(size_t size))
1047 {
1048
1049 errx(1, "unallocated block in symbolic link %s", curfile.name);
1050 }
1051
1052 /*
1053 * Collect the next block of a bit map.
1054 */
1055 static void
1056 xtrmap(char *buf, size_t size)
1057 {
1058
1059 memmove(map, buf, size);
1060 map += size;
1061 }
1062
1063 /*
1064 * Skip over a hole in a bit map (should never happen).
1065 */
1066 /* ARGSUSED */
1067 static void
1068 xtrmapskip(UNUSED(char *buf), size_t size)
1069 {
1070
1071 panic("hole in map\n");
1072 map += size;
1073 }
1074
1075 /*
1076 * Noop, when an extraction function is not needed.
1077 */
1078 /* ARGSUSED */
1079 void
1080 xtrnull(UNUSED(char *buf), UNUSED(size_t size))
1081 {
1082
1083 return;
1084 }
1085
1086 #if COMPARE_ONTHEFLY
1087 /*
1088 * Compare the next block of a file.
1089 */
1090 static void
1091 xtrcmpfile(char *buf, size_t size)
1092 {
1093 static char cmpbuf[MAXBSIZE];
1094
1095 if (cmperror)
1096 return;
1097
1098 if (read(ifile, cmpbuf, size) != (ssize_t)size) {
1099 fprintf(stderr, "%s: size has changed.\n",
1100 curfile.name);
1101 cmperror = 1;
1102 return;
1103 }
1104
1105 if (memcmp(buf, cmpbuf, size) != 0) {
1106 fprintf(stderr, "%s: tape and disk copies are different\n",
1107 curfile.name);
1108 cmperror = 1;
1109 return;
1110 }
1111 }
1112
1113 /*
1114 * Skip over a hole in a file.
1115 */
1116 static void
1117 xtrcmpskip(UNUSED(char *buf), size_t size)
1118 {
1119 static char cmpbuf[MAXBSIZE];
1120 int i;
1121
1122 if (cmperror)
1123 return;
1124
1125 if (read(ifile, cmpbuf, size) != (ssize_t)size) {
1126 fprintf(stderr, "%s: size has changed.\n",
1127 curfile.name);
1128 cmperror = 1;
1129 return;
1130 }
1131
1132 for (i = 0; i < (int)size; ++i)
1133 if (cmpbuf[i] != '\0') {
1134 fprintf(stderr, "%s: tape and disk copies are different\n",
1135 curfile.name);
1136 cmperror = 1;
1137 return;
1138 }
1139 }
1140 #endif /* COMPARE_ONTHEFLY */
1141
1142 #if !COMPARE_ONTHEFLY
1143 static int
1144 do_cmpfiles(int fd_tape, int fd_disk, long size)
1145 {
1146 static char buf_tape[BUFSIZ];
1147 static char buf_disk[BUFSIZ];
1148 ssize_t n_tape;
1149 ssize_t n_disk;
1150
1151 while (size > 0) {
1152 if ((n_tape = read(fd_tape, buf_tape, sizeof(buf_tape))) < 1) {
1153 close(fd_tape), close(fd_disk);
1154 panic("do_cmpfiles: unexpected EOF[1]");
1155 }
1156 if ((n_disk = read(fd_disk, buf_disk, sizeof(buf_tape))) < 1) {
1157 close(fd_tape), close(fd_disk);
1158 panic("do_cmpfiles: unexpected EOF[2]");
1159 }
1160 if (n_tape != n_disk) {
1161 close(fd_tape), close(fd_disk);
1162 panic("do_cmpfiles: sizes different!");
1163 }
1164 if (memcmp(buf_tape, buf_disk, (size_t)n_tape) != 0) return (1);
1165 size -= n_tape;
1166 }
1167 return (0);
1168 }
1169
1170 /* for debugging compare problems */
1171 #undef COMPARE_FAIL_KEEP_FILE
1172
1173 static
1174 #ifdef COMPARE_FAIL_KEEP_FILE
1175 /* return true if tapefile should be unlinked after compare */
1176 int
1177 #else
1178 void
1179 #endif
1180 cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk)
1181 {
1182 struct STAT sbuf_tape;
1183 int fd_tape, fd_disk;
1184
1185 if (STAT(tapefile, &sbuf_tape) != 0) {
1186 panic("Can't lstat tmp file %s: %s\n", tapefile,
1187 strerror(errno));
1188 do_compare_error;
1189 }
1190
1191 if (sbuf_disk->st_size != sbuf_tape.st_size) {
1192 fprintf(stderr,
1193 "%s: size changed from %ld to %ld.\n",
1194 diskfile, (long)sbuf_tape.st_size, (long)sbuf_disk->st_size);
1195 do_compare_error;
1196 #ifdef COMPARE_FAIL_KEEP_FILE
1197 return (0);
1198 #else
1199 return;
1200 #endif
1201 }
1202
1203 if ((fd_tape = OPEN(tapefile, O_RDONLY)) < 0) {
1204 panic("Can't open %s: %s\n", tapefile, strerror(errno));
1205 do_compare_error;
1206 }
1207 if ((fd_disk = OPEN(diskfile, O_RDONLY)) < 0) {
1208 close(fd_tape);
1209 panic("Can't open %s: %s\n", diskfile, strerror(errno));
1210 do_compare_error;
1211 }
1212
1213 if (do_cmpfiles(fd_tape, fd_disk, sbuf_tape.st_size)) {
1214 fprintf(stderr, "%s: tape and disk copies are different\n",
1215 diskfile);
1216 close(fd_tape);
1217 close(fd_disk);
1218 do_compare_error;
1219 #ifdef COMPARE_FAIL_KEEP_FILE
1220 /* rename the file to live in /tmp */
1221 /* rename `tapefile' to /tmp/<basename of diskfile> */
1222 {
1223 char *p = strrchr(diskfile, '/');
1224 char newname[MAXPATHLEN];
1225 if (!p) {
1226 panic("can't find / in %s\n", diskfile);
1227 }
1228 snprintf(newname, sizeof(newname), "%s/debug/%s", tmpdir, p + 1);
1229 if (rename(tapefile, newname)) {
1230 panic("rename from %s to %s failed: %s\n",
1231 tapefile, newname,
1232 strerror(errno));
1233 } else {
1234 fprintf(stderr, "*** %s saved to %s\n",
1235 tapefile, newname);
1236 }
1237 }
1238
1239 /* don't unlink the file (it's not there anymore */
1240 /* anyway) */
1241 return (0);
1242 #else
1243 return;
1244 #endif
1245 }
1246 close(fd_tape);
1247 close(fd_disk);
1248 #ifdef COMPARE_FAIL_KEEP_FILE
1249 return (1);
1250 #endif
1251 }
1252 #endif /* !COMPARE_ONTHEFLY */
1253
1254 #if !COMPARE_ONTHEFLY
1255 static char tmpfilename[MAXPATHLEN];
1256 #endif
1257
1258 void
1259 comparefile(char *name)
1260 {
1261 unsigned int mode;
1262 struct STAT sb;
1263 int r;
1264 #if !COMPARE_ONTHEFLY
1265 static char *tmpfile = NULL;
1266 struct STAT stemp;
1267 #endif
1268
1269 curfile.name = name;
1270 curfile.action = USING;
1271 mode = curfile.dip->di_mode;
1272
1273 if ((mode & IFMT) == IFSOCK) {
1274 Vprintf(stdout, "skipped socket %s\n", name);
1275 skipfile();
1276 return;
1277 }
1278
1279 if ((r = LSTAT(name, &sb)) != 0) {
1280 warn("%s: does not exist (%d)", name, r);
1281 do_compare_error;
1282 skipfile();
1283 return;
1284 }
1285
1286 Vprintf(stdout, "comparing %s (size: %ld, mode: 0%o)\n", name,
1287 (long)sb.st_size, mode);
1288
1289 if (sb.st_mode != mode) {
1290 fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n",
1291 name, mode & 07777, sb.st_mode & 07777);
1292 do_compare_error;
1293 }
1294 if (spcl.c_flags & DR_METAONLY) {
1295 skipfile();
1296 return;
1297 }
1298 switch (mode & IFMT) {
1299 default:
1300 skipfile();
1301 return;
1302
1303 case IFSOCK:
1304 skipfile();
1305 return;
1306
1307 case IFDIR:
1308 skipfile();
1309 return;
1310
1311 case IFLNK: {
1312 char lbuf[MAXPATHLEN + 1];
1313 int lsize;
1314
1315 if (!(sb.st_mode & S_IFLNK)) {
1316 fprintf(stderr, "%s: is no longer a symbolic link\n",
1317 name);
1318 do_compare_error;
1319 return;
1320 }
1321 lnkbuf[0] = '\0';
1322 pathlen = 0;
1323 getfile(xtrlnkfile, xtrlnkskip);
1324 if (pathlen == 0) {
1325 fprintf(stderr,
1326 "%s: zero length symbolic link (ignored)\n",
1327 name);
1328 do_compare_error;
1329 return;
1330 }
1331 if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) {
1332 panic("readlink of %s failed: %s", name,
1333 strerror(errno));
1334 do_compare_error;
1335 }
1336 lbuf[lsize] = 0;
1337 if (strcmp(lbuf, lnkbuf) != 0) {
1338 fprintf(stderr,
1339 "%s: symbolic link changed from %s to %s.\n",
1340 name, lnkbuf, lbuf);
1341 do_compare_error;
1342 return;
1343 }
1344 return;
1345 }
1346
1347 case IFCHR:
1348 case IFBLK:
1349 if (!(sb.st_mode & (S_IFCHR|S_IFBLK))) {
1350 fprintf(stderr, "%s: no longer a special file\n",
1351 name);
1352 do_compare_error;
1353 skipfile();
1354 return;
1355 }
1356
1357 if (sb.st_rdev != (dev_t)curfile.dip->di_rdev) {
1358 fprintf(stderr,
1359 "%s: device changed from %d,%d to %d,%d.\n",
1360 name,
1361 ((int)curfile.dip->di_rdev >> 8) & 0xff,
1362 (int)curfile.dip->di_rdev & 0xff,
1363 ((int)sb.st_rdev >> 8) & 0xff,
1364 (int)sb.st_rdev & 0xff);
1365 do_compare_error;
1366 }
1367 skipfile();
1368 return;
1369
1370 case IFREG:
1371 #if COMPARE_ONTHEFLY
1372 if ((ifile = OPEN(name, O_RDONLY)) < 0) {
1373 panic("Can't open %s: %s\n", name, strerror(errno));
1374 skipfile();
1375 do_compare_error;
1376 }
1377 else {
1378 cmperror = 0;
1379 getfile(xtrcmpfile, xtrcmpskip);
1380 if (!cmperror) {
1381 char c;
1382 if (read(ifile, &c, 1) != 0) {
1383 fprintf(stderr, "%s: size has changed.\n",
1384 name);
1385 cmperror = 1;
1386 }
1387 }
1388 if (cmperror)
1389 do_compare_error;
1390 close(ifile);
1391 }
1392 #else
1393 if (tmpfile == NULL) {
1394 /* argument to mktemp() must not be in RO space: */
1395 snprintf(tmpfilename, sizeof(tmpfilename), "%s/restoreCXXXXXX", tmpdir);
1396 tmpfile = mktemp(&tmpfilename[0]);
1397 }
1398 if ((STAT(tmpfile, &stemp) == 0) && (unlink(tmpfile) != 0)) {
1399 panic("cannot delete tmp file %s: %s\n",
1400 tmpfile, strerror(errno));
1401 }
1402 if ((ofile = OPEN(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
1403 panic("cannot create file temp file %s: %s\n",
1404 name, strerror(errno));
1405 }
1406 getfile(xtrfile, xtrskip);
1407 (void) close(ofile);
1408 #ifdef COMPARE_FAIL_KEEP_FILE
1409 if (cmpfiles(tmpfile, name, &sb))
1410 unlink(tmpfile);
1411 #else
1412 cmpfiles(tmpfile, name, &sb);
1413 unlink(tmpfile);
1414 #endif
1415 #endif /* COMPARE_ONTHEFLY */
1416 return;
1417 }
1418 /* NOTREACHED */
1419 }
1420
1421 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
1422 static void (*readtape_func)(char *) = readtape_set;
1423
1424 /*
1425 * Read TP_BSIZE blocks from the input.
1426 * Handle read errors, and end of media.
1427 * Decompress compressed blocks.
1428 */
1429 static void
1430 readtape(char *buf)
1431 {
1432 (*readtape_func)(buf); /* call the actual processing routine */
1433 }
1434
1435 /*
1436 * Set function pointer for readtape() routine. zflag and magtapein must
1437 * be correctly set before the first call to readtape().
1438 */
1439 static void
1440 readtape_set(char *buf)
1441 {
1442 if (!zflag)
1443 readtape_func = readtape_uncompr;
1444 else {
1445 newcomprbuf(ntrec);
1446 if (magtapein)
1447 readtape_func = readtape_comprtape;
1448 else
1449 readtape_func = readtape_comprfile;
1450 }
1451 readtape(buf);
1452 }
1453
1454 #endif /* HAVE_ZLIB || HAVE_BZLIB */
1455
1456 /*
1457 * This is the original readtape(), it's used for reading uncompressed input.
1458 * Read TP_BSIZE blocks from the input.
1459 * Handle read errors, and end of media.
1460 */
1461 static void
1462 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
1463 readtape_uncompr(char *buf)
1464 #else
1465 readtape(char *buf)
1466 #endif
1467 {
1468 ssize_t rd, newvol, i;
1469 int cnt, seek_failed;
1470
1471 if (blkcnt < numtrec) {
1472 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1473 blksread++;
1474 tpblksread++;
1475 return;
1476 }
1477 tbufptr = tapebuf;
1478 for (i = 0; i < ntrec; i++)
1479 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1480 if (numtrec == 0)
1481 numtrec = ntrec;
1482 cnt = ntrec * TP_BSIZE;
1483 rd = 0;
1484 #ifdef USE_QFA
1485 if (createtapeposflag)
1486 (void)GetTapePos(&curtapepos);
1487 #endif
1488 getmore:
1489 #ifdef RRESTORE
1490 if (host)
1491 i = rmtread(&tapebuf[rd], cnt);
1492 else
1493 #endif
1494 i = read(mt, &tapebuf[rd], cnt);
1495
1496 /*
1497 * Check for mid-tape short read error.
1498 * If found, skip rest of buffer and start with the next.
1499 */
1500 if (!pipein && numtrec < ntrec && i > 0) {
1501 Dprintf(stdout, "mid-media short read error.\n");
1502 numtrec = ntrec;
1503 }
1504 /*
1505 * Handle partial block read.
1506 */
1507 if (pipein && i == 0 && rd > 0)
1508 i = rd;
1509 else if (i > 0 && i != ntrec * TP_BSIZE) {
1510 if (pipein) {
1511 rd += i;
1512 cnt -= i;
1513 if (cnt > 0)
1514 goto getmore;
1515 i = rd;
1516 } else {
1517 /*
1518 * Short read. Process the blocks read.
1519 */
1520 if (i % TP_BSIZE != 0)
1521 Vprintf(stdout,
1522 "partial block read: %ld should be %ld\n",
1523 (long)i, ntrec * TP_BSIZE);
1524 numtrec = i / TP_BSIZE;
1525 }
1526 }
1527 /*
1528 * Handle read error.
1529 */
1530 if (i < 0) {
1531 fprintf(stderr, "Tape read error while ");
1532 switch (curfile.action) {
1533 default:
1534 fprintf(stderr, "trying to set up tape\n");
1535 break;
1536 case UNKNOWN:
1537 fprintf(stderr, "trying to resynchronize\n");
1538 break;
1539 case USING:
1540 fprintf(stderr, "restoring %s\n", curfile.name);
1541 break;
1542 case SKIP:
1543 fprintf(stderr, "skipping over inode %lu\n",
1544 (unsigned long)curfile.ino);
1545 break;
1546 }
1547 if (!yflag && !reply("continue"))
1548 exit(1);
1549 i = ntrec * TP_BSIZE;
1550 memset(tapebuf, 0, (size_t)i);
1551 #ifdef RRESTORE
1552 if (host)
1553 seek_failed = (rmtseek(i, 1) < 0);
1554 else
1555 #endif
1556 seek_failed = (LSEEK(mt, i, SEEK_CUR) == (OFF_T)-1);
1557
1558 if (seek_failed) {
1559 warn("continuation failed");
1560 if (!yflag && !reply("assume end-of-tape and continue"))
1561 exit(1);
1562 i = 0;
1563 }
1564 }
1565 /*
1566 * Handle end of tape.
1567 */
1568 if (i == 0) {
1569 Vprintf(stdout, "End-of-tape encountered\n");
1570 if (!pipein) {
1571 newvol = volno + 1;
1572 volno = 0;
1573 numtrec = 0;
1574 getvol(newvol);
1575 readtape(buf);
1576 return;
1577 }
1578 if (rd % TP_BSIZE != 0)
1579 panic("partial block read: %d should be %d\n",
1580 rd, ntrec * TP_BSIZE);
1581 terminateinput();
1582 memmove(&tapebuf[rd], &endoftapemark, TP_BSIZE);
1583 }
1584 blkcnt = 0;
1585 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1586 blksread++;
1587 tpblksread++;
1588 }
1589
1590 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB)
1591
1592 /*
1593 * Read a compressed format block from a file or pipe and uncompress it.
1594 * Attempt to handle read errors, and end of file.
1595 */
1596 static void
1597 readtape_comprfile(char *buf)
1598 {
1599 long rl, size, i, ret;
1600 int newvol;
1601 struct tapebuf *tpb;
1602
1603 if (blkcnt < numtrec) {
1604 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1605 blksread++;
1606 tpblksread++;
1607 return;
1608 }
1609 /* need to read the next block */
1610 tbufptr = tapebuf;
1611 for (i = 0; i < ntrec; i++)
1612 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1613 numtrec = ntrec;
1614 tpb = (struct tapebuf *) tapebuf;
1615
1616 /* read the block prefix */
1617 ret = read_a_block(mt, tapebuf, PREFIXSIZE, &rl);
1618 converttapebuf(tpb);
1619
1620 if (Vflag && (ret == 0 || rl < (int)PREFIXSIZE || tpb->length == 0))
1621 ret = 0;
1622 if (ret <= 0)
1623 goto readerr;
1624
1625 /* read the data */
1626 size = tpb->length;
1627 if (size > bufsize) {
1628 /* something's wrong */
1629 Vprintf(stdout, "Prefix size error, max size %d, got %ld\n",
1630 bufsize, size);
1631 size = bufsize;
1632 tpb->length = bufsize;
1633 }
1634 ret = read_a_block(mt, tpb->buf, size, &rl);
1635 if (ret <= 0)
1636 goto readerr;
1637
1638 tbufptr = decompress_tapebuf(tpb, rl + PREFIXSIZE);
1639 if (tbufptr == NULL) {
1640 msg_read_error("File decompression error while");
1641 if (!yflag && !reply("continue"))
1642 exit(1);
1643 memset(tapebuf, 0, bufsize);
1644 tbufptr = tapebuf;
1645 }
1646
1647 blkcnt = 0;
1648 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1649 blksread++;
1650 tpblksread++;
1651 return;
1652
1653 readerr:
1654 /* Errors while reading from a file or pipe are catastrophic. Since
1655 * there are no block boundaries, it's impossible to bypass the
1656 * block in error and find the start of the next block.
1657 */
1658 if (ret == 0) {
1659 /* It's possible to have multiple input files using -M
1660 * and -f file1,file2...
1661 */
1662 Vprintf(stdout, "End-of-File encountered\n");
1663 if (!pipein) {
1664 newvol = volno + 1;
1665 volno = 0;
1666 numtrec = 0;
1667 getvol(newvol);
1668 readtape(buf);
1669 return;
1670 }
1671 }
1672 msg_read_error("Read error while");
1673 /* if (!yflag && !reply("continue")) */
1674 exit(1);
1675 }
1676
1677 /*
1678 * Read compressed data from a tape and uncompress it.
1679 * Handle read errors, and end of media.
1680 * Since a tape consists of separate physical blocks, we try
1681 * to recover from errors by repositioning the tape to the next
1682 * block.
1683 */
1684 static void
1685 readtape_comprtape(char *buf)
1686 {
1687 long rl, size, i;
1688 int ret, newvol;
1689 struct tapebuf *tpb;
1690 struct mtop tcom;
1691
1692 if (blkcnt < numtrec) {
1693 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1694 blksread++;
1695 tpblksread++;
1696 return;
1697 }
1698 /* need to read the next block */
1699 tbufptr = tapebuf;
1700 for (i = 0; i < ntrec; i++)
1701 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1702 numtrec = ntrec;
1703 tpb = (struct tapebuf *) tapebuf;
1704
1705 /* read the block */
1706 size = bufsize + PREFIXSIZE;
1707 ret = read_a_block(mt, tapebuf, size, &rl);
1708 if (ret <= 0)
1709 goto readerr;
1710
1711 converttapebuf(tpb);
1712 tbufptr = decompress_tapebuf(tpb, rl);
1713 if (tbufptr == NULL) {
1714 msg_read_error("Tape decompression error while");
1715 if (!yflag && !reply("continue"))
1716 exit(1);
1717 memset(tapebuf, 0, PREFIXSIZE + bufsize);
1718 tbufptr = tapebuf;
1719 }
1720 goto moverecord;
1721
1722 readerr:
1723 /* Handle errors: EOT switches to the next volume, other errors
1724 * attempt to position the tape to the next block.
1725 */
1726 if (ret == 0) {
1727 Vprintf(stdout, "End-of-tape encountered\n");
1728 newvol = volno + 1;
1729 volno = 0;
1730 numtrec = 0;
1731 getvol(newvol);
1732 readtape(buf);
1733 return;
1734 }
1735
1736 msg_read_error("Tape read error while");
1737 if (!yflag && !reply("continue"))
1738 exit(1);
1739 memset(tapebuf, 0, PREFIXSIZE + bufsize);
1740 tbufptr = tapebuf;
1741
1742 #ifdef RRESTORE
1743 if (host)
1744 rl = rmtioctl(MTFSR, 1);
1745 else
1746 #endif
1747 {
1748 tcom.mt_op = MTFSR;
1749 tcom.mt_count = 1;
1750 rl = ioctl(mt, MTIOCTOP, &tcom);
1751 }
1752
1753 if (rl < 0) {
1754 warn("continuation failed");
1755 if (!yflag && !reply("assume end-of-tape and continue"))
1756 exit(1);
1757 ret = 0; /* end of tape */
1758 goto readerr;
1759 }
1760
1761 moverecord:
1762 blkcnt = 0;
1763 memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
1764 blksread++;
1765 tpblksread++;
1766 }
1767
1768 /*
1769 * Decompress a struct tapebuf into a buffer. readsize is the size read
1770 * from the tape/file and is used for error messages. Returns a pointer
1771 * to the location of the uncompressed buffer or NULL on errors.
1772 * Adjust numtrec and complain for a short block.
1773 */
1774 static char *
1775 decompress_tapebuf(struct tapebuf *tpbin, int readsize)
1776 {
1777 /* If zflag is on, all blocks have a struct tapebuf prefix */
1778 /* zflag gets set in setup() from the dump header */
1779 int cresult, blocklen;
1780 unsigned long worklen;
1781 #ifdef HAVE_BZLIB
1782 unsigned int worklen2;
1783 #endif
1784 char *output = NULL,*reason = NULL, *lengtherr = NULL;
1785
1786 /* build a length error message */
1787 blocklen = tpbin->length;
1788 if (readsize < blocklen + (int)PREFIXSIZE)
1789 lengtherr = "short";
1790 else
1791 if (readsize > blocklen + (int)PREFIXSIZE)
1792 lengtherr = "long";
1793
1794 worklen = comprlen;
1795 cresult = 1;
1796 if (tpbin->compressed) {
1797 /* uncompress whatever we read, if it fails, complain later */
1798 if (tpbin->flags == COMPRESS_ZLIB) {
1799 #ifndef HAVE_ZLIB
1800 errx(1,"This restore version doesn't support zlib decompression");
1801 #else
1802 cresult = uncompress(comprbuf, &worklen,
1803 tpbin->buf, blocklen);
1804 output = comprbuf;
1805 switch (cresult) {
1806 case Z_OK:
1807 break;
1808 case Z_MEM_ERROR:
1809 reason = "not enough memory";
1810 break;
1811 case Z_BUF_ERROR:
1812 reason = "buffer too small";
1813 break;
1814 case Z_DATA_ERROR:
1815 reason = "data error";
1816 break;
1817 default:
1818 reason = "unknown";
1819 }
1820 if (cresult == Z_OK)
1821 cresult = 1;
1822 else
1823 cresult = 0;
1824 #endif /* HAVE_ZLIB */
1825 }
1826 if (tpbin->flags == COMPRESS_BZLIB) {
1827 #ifndef HAVE_BZLIB
1828 errx(1,"This restore version doesn't support bzlib decompression");
1829 #else
1830 worklen2 = worklen;
1831 cresult = BZ2_bzBuffToBuffDecompress(
1832 comprbuf, &worklen2,
1833 tpbin->buf, blocklen, 0, 0);
1834 worklen = worklen2;
1835 output = comprbuf;
1836 switch (cresult) {
1837 case BZ_OK:
1838 break;
1839 case BZ_MEM_ERROR:
1840 reason = "not enough memory";
1841 break;
1842 case BZ_OUTBUFF_FULL:
1843 reason = "buffer too small";
1844 break;
1845 case BZ_DATA_ERROR:
1846 case BZ_DATA_ERROR_MAGIC:
1847 case BZ_UNEXPECTED_EOF:
1848 reason = "data error";
1849 break;
1850 default:
1851 reason = "unknown";
1852 }
1853 if (cresult == BZ_OK)
1854 cresult = 1;
1855 else
1856 cresult = 0;
1857 #endif /* HAVE_BZLIB */
1858 }
1859 }
1860 else {
1861 output = tpbin->buf;
1862 worklen = blocklen;
1863 }
1864 if (cresult) {
1865 numtrec = worklen / TP_BSIZE;
1866 if (worklen % TP_BSIZE != 0)
1867 reason = "length mismatch";
1868 }
1869 if (reason) {
1870 if (lengtherr)
1871 fprintf(stderr, "%s compressed block: %d expected: %d\n",
1872 lengtherr, readsize, tpbin->length + PREFIXSIZE);
1873 fprintf(stderr, "decompression error, block %ld: %s\n",
1874 tpblksread+1, reason);
1875 if (!cresult)
1876 output = NULL;
1877 }
1878 return output;
1879 }
1880
1881 /*
1882 * Print an error message for a read error.
1883 * This was exteracted from the original readtape().
1884 */
1885 static void
1886 msg_read_error(char *m)
1887 {
1888 switch (curfile.action) {
1889 default:
1890 fprintf(stderr, "%s trying to set up tape\n", m);
1891 break;
1892 case UNKNOWN:
1893 fprintf(stderr, "%s trying to resynchronize\n", m);
1894 break;
1895 case USING:
1896 fprintf(stderr, "%s restoring %s\n", m, curfile.name);
1897 break;
1898 case SKIP:
1899 fprintf(stderr, "%s skipping over inode %lu\n", m,
1900 (unsigned long)curfile.ino);
1901 break;
1902 }
1903 }
1904 #endif /* HAVE_ZLIB || HAVE_BZLIB */
1905
1906 /*
1907 * Read the first block and get the blocksize from it. Test
1908 * for a compressed dump tape/file. setup() will make the final
1909 * determination by checking the compressed flag if gethead()
1910 * finds a valid header. The test here is necessary to offset the buffer
1911 * by the size of the compressed prefix. zflag is set here so that
1912 * readtape_set can set the correct function pointer for readtape().
1913 * Note that the first block of each tape/file is not compressed
1914 * and does not have a prefix.
1915 */
1916 static void
1917 findtapeblksize(void)
1918 {
1919 long i;
1920 size_t len;
1921 struct tapebuf *tpb = (struct tapebuf *) tapebuf;
1922 struct s_spcl spclpt;
1923
1924 for (i = 0; i < ntrec; i++)
1925 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1926 blkcnt = 0;
1927 tbufptr = tapebuf;
1928 /*
1929 * For a pipe or file, read in the first record. For a tape, read
1930 * the first block.
1931 */
1932 len = magtapein ? ntrec * TP_BSIZE : TP_BSIZE;
1933
1934 if (read_a_block(mt, tapebuf, len, &i) <= 0)
1935 errx(1, "Tape read error on first record");
1936
1937 memcpy(&spclpt, tapebuf, TP_BSIZE);
1938 if (converthead(&spclpt) == FAIL) {
1939 cvtflag++;
1940 if (converthead(&spclpt) == FAIL) {
1941 /* Special case for old compressed tapes with prefix */
1942 if (magtapein && (i % TP_BSIZE != 0))
1943 goto oldformat;
1944 errx(1, "Tape is not a dump tape");
1945 }
1946 fprintf(stderr, "Converting to new file system format.\n");
1947 }
1948 /*
1949 * If the input is from a file or a pipe, we read TP_BSIZE
1950 * bytes looking for a dump header. If the dump is compressed
1951 * we need to read in the rest of the block, as determined
1952 * by c_ntrec in the dump header. The first block of the
1953 * dump is not compressed and does not have a prefix.
1954 */
1955 if (!magtapein) {
1956 if (spclpt.c_type == TS_TAPE
1957 && spclpt.c_flags & DR_COMPRESSED) {
1958 /* It's a compressed dump file, read in the */
1959 /* rest of the block based on spclpt.c_ntrec. */
1960 if (spclpt.c_ntrec > ntrec)
1961 errx(1, "Tape blocksize is too large, use "
1962 "\'-b %d\' ", spclpt.c_ntrec);
1963 ntrec = spclpt.c_ntrec;
1964 len = (ntrec - 1) * TP_BSIZE;
1965 zflag = 1;
1966 }
1967 else {
1968 /* read in the rest of the block based on bufsize */
1969 len = bufsize - TP_BSIZE;
1970 }
1971 if (read_a_block(mt, tapebuf+TP_BSIZE, len, &i) < 0
1972 || (i != (long)len && i % TP_BSIZE != 0))
1973 errx(1,"Error reading dump file header");
1974 tbufptr = tapebuf;
1975 numtrec = ntrec;
1976 Vprintf(stdout, "Input block size is %ld\n", ntrec);
1977 return;
1978 } /* if (!magtapein) */
1979
1980 /*
1981 * If the input is a tape, we tried to read ntrec * TP_BSIZE bytes.
1982 * If the value of ntrec is too large, we read less than
1983 * what we asked for; adjust the value of ntrec and test for
1984 * a compressed dump tape.
1985 */
1986 if (i % TP_BSIZE != 0) {
1987 oldformat:
1988 /* may be old format compressed dump tape with a prefix */
1989 memcpy(&spclpt, tpb->buf, TP_BSIZE);
1990 cvtflag = 0;
1991 if (converthead(&spclpt) == FAIL) {
1992 cvtflag++;
1993 if (converthead(&spclpt) == FAIL)
1994 errx(1, "Tape is not a dump tape");
1995 fprintf(stderr, "Converting to new file system format.\n");
1996 }
1997 if (i % TP_BSIZE == PREFIXSIZE
1998 && tpb->compressed == 0
1999 && spclpt.c_type == TS_TAPE
2000 && spclpt.c_flags & DR_COMPRESSED) {
2001 zflag = 1;
2002 tbufptr = tpb->buf;
2003 if (tpb->length > bufsize)
2004 errx(1, "Tape blocksize is too large, use "
2005 "\'-b %d\' ", tpb->length / TP_BSIZE);
2006 }
2007 else
2008 errx(1, "Tape block size (%ld) is not a multiple of dump block size (%d)",
2009 i, TP_BSIZE);
2010 }
2011 ntrec = i / TP_BSIZE;
2012 if (spclpt.c_type == TS_TAPE) {
2013 if (spclpt.c_flags & DR_COMPRESSED)
2014 zflag = 1;
2015 if (spclpt.c_ntrec > ntrec)
2016 errx(1, "Tape blocksize is too large, use "
2017 "\'-b %d\' ", spclpt.c_ntrec);
2018 }
2019 numtrec = ntrec;
2020 Vprintf(stdout, "Tape block size is %ld\n", ntrec);
2021 }
2022
2023 /*
2024 * Read a block of data handling all of the messy details.
2025 */
2026 static int read_a_block(int fd, char *buf, size_t len, long *lengthread)
2027 {
2028 long i = 1, size;
2029
2030 size = len;
2031 while (size > 0) {
2032 #ifdef RRESTORE
2033 if (host)
2034 i = rmtread(buf, size);
2035 else
2036 #endif
2037 i = read(fd, buf, size);
2038
2039 if (i <= 0)
2040 break; /* EOD or error */
2041 size -= i;
2042 if (magtapein)
2043 break; /* block at a time for mt */
2044 buf += i;
2045 }
2046 *lengthread = len - size;
2047 return i;
2048 }
2049
2050 void
2051 closemt(void)
2052 {
2053
2054 if (mt < 0)
2055 return;
2056 #ifdef RRESTORE
2057 if (host)
2058 rmtclose();
2059 else
2060 #endif
2061 (void) close(mt);
2062 }
2063
2064 static void
2065 setmagtapein(void) {
2066 struct mtget mt_stat;
2067 static int done = 0;
2068 if (done)
2069 return;
2070 done = 1;
2071 if (!pipein) {
2072 /* need to know if input is really from a tape */
2073 #ifdef RRESTORE
2074 if (host)
2075 magtapein = !lflag;
2076 else
2077 #endif
2078 magtapein = ioctl(mt, MTIOCGET, (char *)&mt_stat) == 0;
2079 }
2080
2081 Vprintf(stdout,"Input is from %s\n",
2082 magtapein ? "tape" :
2083 Vflag ? "multi-volume (no tape)" : "file/pipe");
2084 }
2085
2086 /*
2087 * Read the next block from the tape.
2088 * Check to see if it is one of several vintage headers.
2089 * If it is an old style header, convert it to a new style header.
2090 * If it is not any valid header, return an error.
2091 */
2092 static int
2093 gethead(struct s_spcl *buf)
2094 {
2095 readtape((char *)buf);
2096 return converthead(buf);
2097 }
2098
2099 static int
2100 converthead(struct s_spcl *buf)
2101 {
2102 int32_t i;
2103 union {
2104 quad_t qval;
2105 int32_t val[2];
2106 } qcvt;
2107 union u_ospcl {
2108 char dummy[TP_BSIZE];
2109 struct s_ospcl {
2110 int32_t c_type;
2111 int32_t c_date;
2112 int32_t c_ddate;
2113 int32_t c_volume;
2114 int32_t c_tapea;
2115 u_int16_t c_inumber;
2116 int32_t c_magic;
2117 int32_t c_checksum;
2118 struct odinode {
2119 u_int16_t odi_mode;
2120 u_int16_t odi_nlink;
2121 u_int16_t odi_uid;
2122 u_int16_t odi_gid;
2123 int32_t odi_size;
2124 int32_t odi_rdev;
2125 char odi_addr[36];
2126 int32_t odi_atime;
2127 int32_t odi_mtime;
2128 int32_t odi_ctime;
2129 } c_dinode;
2130 int32_t c_count;
2131 char c_fill[256];
2132 } s_ospcl;
2133 } u_ospcl;
2134
2135 if (!cvtflag) {
2136 if (buf->c_magic != NFS_MAGIC) {
2137 if (swabi(buf->c_magic) != NFS_MAGIC)
2138 return (FAIL);
2139 if (!Bcvt) {
2140 Vprintf(stdout, "Note: Doing Byte swapping\n");
2141 Bcvt = 1;
2142 }
2143 }
2144 if (checksum((int *)buf) == FAIL)
2145 return (FAIL);
2146 if (Bcvt)
2147 swabst((u_char *)"8i4s31i528bi192b3i", (u_char *)buf);
2148 goto good;
2149 }
2150 memcpy(&u_ospcl.s_ospcl, buf, TP_BSIZE);
2151 memset((char *)buf, 0, (long)TP_BSIZE);
2152 buf->c_type = u_ospcl.s_ospcl.c_type;
2153 buf->c_date = u_ospcl.s_ospcl.c_date;
2154 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
2155 buf->c_volume = u_ospcl.s_ospcl.c_volume;
2156 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
2157 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
2158 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
2159 buf->c_magic = u_ospcl.s_ospcl.c_magic;
2160 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
2161 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
2162 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
2163 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
2164 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
2165 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
2166 #if defined(__linux__) || defined(sunos)
2167 buf->c_dinode.di_atime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
2168 buf->c_dinode.di_mtime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
2169 buf->c_dinode.di_ctime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
2170 #else /* __linux__ || sunos */
2171 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
2172 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
2173 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
2174 #endif /* __linux__ || sunos */
2175 buf->c_count = u_ospcl.s_ospcl.c_count;
2176 memmove(buf->c_addr, u_ospcl.s_ospcl.c_fill, (long)256);
2177 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
2178 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
2179 return(FAIL);
2180 buf->c_magic = NFS_MAGIC;
2181
2182 good:
2183 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
2184 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
2185 qcvt.qval = buf->c_dinode.di_size;
2186 if (qcvt.val[0] || qcvt.val[1]) {
2187 Vprintf(stdout, "Note: Doing Quad swapping\n");
2188 Qcvt = 1;
2189 }
2190 }
2191 if (Qcvt) {
2192 qcvt.qval = buf->c_dinode.di_size;
2193 i = qcvt.val[1];
2194 qcvt.val[1] = qcvt.val[0];
2195 qcvt.val[0] = i;
2196 buf->c_dinode.di_size = qcvt.qval;
2197 }
2198 readmapflag = 0;
2199
2200 switch (buf->c_type) {
2201
2202 case TS_CLRI:
2203 case TS_BITS:
2204 /*
2205 * Have to patch up missing information in bit map headers
2206 */
2207 buf->c_inumber = 0;
2208 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
2209 if (buf->c_count > TP_NINDIR)
2210 readmapflag = 1;
2211 else
2212 for (i = 0; i < buf->c_count; i++)
2213 buf->c_addr[i]++;
2214 break;
2215
2216 case TS_TAPE:
2217 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
2218 oldinofmt = 1;
2219 /* fall through */
2220 case TS_END:
2221 buf->c_inumber = 0;
2222 if (buf->c_flags & DR_INODEINFO) {
2223 memcpy(volinfo, buf->c_inos, TP_NINOS * sizeof(dump_ino_t));
2224 if (Bcvt)
2225 swabst((u_char *)"128i", (u_char *)volinfo);
2226 }
2227 break;
2228
2229 case TS_INODE:
2230 case TS_ADDR:
2231 break;
2232
2233 default:
2234 panic("gethead: unknown inode type %d\n", buf->c_type);
2235 break;
2236 }
2237 /*
2238 * If we are restoring a filesystem with old format inodes,
2239 * copy the uid/gid to the new location.
2240 */
2241 if (oldinofmt) {
2242 buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
2243 buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
2244 }
2245 if (dflag)
2246 accthdr(buf);
2247 return(GOOD);
2248 }
2249
2250 static void
2251 converttapebuf(struct tapebuf *tpb)
2252 {
2253 if (Bcvt) {
2254 struct tb {
2255 unsigned int length:28;
2256 unsigned int flags:3;
2257 unsigned int compressed:1;
2258 } tb;
2259 swabst((u_char *)"i", (u_char *)tpb);
2260 memcpy(&tb, tpb, 4);
2261 tpb->length = tb.length;
2262 tpb->flags = tb.flags;
2263 tpb->compressed = tb.compressed;
2264 }
2265 }
2266
2267 /*
2268 * Check that a header is where it belongs and predict the next header
2269 */
2270 static void
2271 accthdr(struct s_spcl *header)
2272 {
2273 static dump_ino_t previno = 0x7fffffff;
2274 static int prevtype;
2275 static long predict;
2276 long blks, i;
2277
2278 if (header->c_type == TS_TAPE) {
2279 fprintf(stderr, "Volume header (%s inode format) ",
2280 oldinofmt ? "old" : "new");
2281 if (header->c_firstrec)
2282 fprintf(stderr, "begins with record %d",
2283 header->c_firstrec);
2284 fprintf(stderr, "\n");
2285 previno = 0x7fffffff;
2286 return;
2287 }
2288 if (previno == 0x7fffffff)
2289 goto newcalc;
2290 switch (prevtype) {
2291 case TS_BITS:
2292 fprintf(stderr, "Dumped inodes map header");
2293 break;
2294 case TS_CLRI:
2295 fprintf(stderr, "Used inodes map header");
2296 break;
2297 case TS_INODE:
2298 fprintf(stderr, "File header, ino %lu", (unsigned long)previno);
2299 break;
2300 case TS_ADDR:
2301 fprintf(stderr, "File continuation header, ino %ld", (long)previno);
2302 break;
2303 case TS_END:
2304 fprintf(stderr, "End of tape header");
2305 break;
2306 }
2307 if (predict != blksread - 1)
2308 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
2309 predict, blksread - 1);
2310 fprintf(stderr, "\n");
2311 newcalc:
2312 blks = 0;
2313 if (header->c_type != TS_END)
2314 for (i = 0; i < header->c_count; i++)
2315 if (readmapflag || header->c_addr[i] != 0)
2316 blks++;
2317 predict = blks;
2318 blksread = 0;
2319 prevtype = header->c_type;
2320 previno = header->c_inumber;
2321 }
2322
2323 /*
2324 * Find an inode header.
2325 * Complain if had to skip, and complain is set.
2326 */
2327 static void
2328 findinode(struct s_spcl *header)
2329 {
2330 static long skipcnt = 0;
2331 long i;
2332 char buf[TP_BSIZE];
2333
2334 curfile.name = "<name unknown>";
2335 curfile.action = UNKNOWN;
2336 curfile.dip = NULL;
2337 curfile.ino = 0;
2338 do {
2339 if (header->c_magic != NFS_MAGIC) {
2340 skipcnt++;
2341 while (gethead(header) == FAIL ||
2342 header->c_date != dumpdate)
2343 skipcnt++;
2344 }
2345 switch (header->c_type) {
2346
2347 case TS_ADDR:
2348 /*
2349 * Skip up to the beginning of the next record
2350 */
2351 for (i = 0; i < header->c_count; i++)
2352 if (header->c_addr[i])
2353 readtape(buf);
2354 while (gethead(header) == FAIL ||
2355 header->c_date != dumpdate)
2356 skipcnt++;
2357 break;
2358
2359 case TS_INODE:
2360 curfile.dip = &header->c_dinode;
2361 curfile.ino = header->c_inumber;
2362 break;
2363
2364 case TS_END:
2365 curfile.ino = maxino;
2366 break;
2367
2368 case TS_CLRI:
2369 curfile.name = "<file removal list>";
2370 break;
2371
2372 case TS_BITS:
2373 curfile.name = "<file dump list>";
2374 break;
2375
2376 case TS_TAPE:
2377 panic("unexpected tape header\n");
2378 /* NOTREACHED */
2379
2380 default:
2381 panic("unknown tape header type %d\n", spcl.c_type);
2382 /* NOTREACHED */
2383
2384 }
2385 } while (header->c_type == TS_ADDR);
2386 if (skipcnt > 0)
2387 #ifdef USE_QFA
2388 if (!noresyncmesg)
2389 #endif
2390 fprintf(stderr, "resync restore, skipped %ld blocks\n",
2391 skipcnt);
2392 skipcnt = 0;
2393 }
2394
2395 static int
2396 checksum(int *buf)
2397 {
2398 int i, j;
2399
2400 j = sizeof(union u_spcl) / sizeof(int);
2401 i = 0;
2402 if(!Bcvt) {
2403 do
2404 i += *buf++;
2405 while (--j);
2406 } else {
2407 /* What happens if we want to read restore tapes
2408 for a 16bit int machine??? */
2409 do
2410 i += swabi(*buf++);
2411 while (--j);
2412 }
2413
2414 if (i != CHECKSUM) {
2415 fprintf(stderr, "Checksum error %o, inode %lu file %s\n", i,
2416 (unsigned long)curfile.ino, curfile.name);
2417 return(FAIL);
2418 }
2419 return(GOOD);
2420 }
2421
2422 #ifdef RRESTORE
2423 #ifdef __STDC__
2424 #include <stdarg.h>
2425 #else
2426 #include <varargs.h>
2427 #endif
2428
2429 void
2430 #ifdef __STDC__
2431 msg(const char *fmt, ...)
2432 #else
2433 msg(fmt, va_alist)
2434 char *fmt;
2435 va_dcl
2436 #endif
2437 {
2438 va_list ap;
2439 #ifdef __STDC__
2440 va_start(ap, fmt);
2441 #else
2442 va_start(ap);
2443 #endif
2444 (void)vfprintf(stderr, fmt, ap);
2445 va_end(ap);
2446 }
2447 #endif /* RRESTORE */
2448
2449 static u_char *
2450 swab16(u_char *sp, int n)
2451 {
2452 char c;
2453
2454 while (--n >= 0) {
2455 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
2456 sp += 2;
2457 }
2458 return (sp);
2459 }
2460
2461 static u_char *
2462 swab32(u_char *sp, int n)
2463 {
2464 char c;
2465
2466 while (--n >= 0) {
2467 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
2468 c = sp[1]; sp[1] = sp[2]; sp[2] = c;
2469 sp += 4;
2470 }
2471 return (sp);
2472 }
2473
2474 static u_char *
2475 swab64(u_char *sp, int n)
2476 {
2477 char c;
2478
2479 while (--n >= 0) {
2480 c = sp[0]; sp[0] = sp[7]; sp[7] = c;
2481 c = sp[1]; sp[1] = sp[6]; sp[6] = c;
2482 c = sp[2]; sp[2] = sp[5]; sp[5] = c;
2483 c = sp[3]; sp[3] = sp[4]; sp[4] = c;
2484 sp += 8;
2485 }
2486 return (sp);
2487 }
2488
2489 void
2490 swabst(u_char *cp, u_char *sp)
2491 {
2492 int n = 0;
2493
2494 while (*cp) {
2495 switch (*cp) {
2496 case '0': case '1': case '2': case '3': case '4':
2497 case '5': case '6': case '7': case '8': case '9':
2498 n = (n * 10) + (*cp++ - '0');
2499 continue;
2500
2501 case 's': case 'w': case 'h':
2502 if (n == 0)
2503 n = 1;
2504 sp = swab16(sp, n);
2505 break;
2506
2507 case 'i':
2508 if (n == 0)
2509 n = 1;
2510 sp = swab32(sp, n);
2511 break;
2512
2513 case 'l':
2514 if (n == 0)
2515 n = 1;
2516 sp = swab64(sp, n);
2517 break;
2518
2519 default: /* Any other character, like 'b' counts as byte. */
2520 if (n == 0)
2521 n = 1;
2522 sp += n;
2523 break;
2524 }
2525 cp++;
2526 n = 0;
2527 }
2528 }
2529
2530 static u_int
2531 swabi(u_int x)
2532 {
2533 swabst((u_char *)"i", (u_char *)&x);
2534 return (x);
2535 }
2536
2537 #if 0
2538 static u_long
2539 swabl(u_long x)
2540 {
2541 swabst((u_char *)"l", (u_char *)&x);
2542 return (x);
2543 }
2544 #endif
2545
2546 #ifdef USE_QFA
2547 /*
2548 * get the current position of the tape
2549 */
2550 int
2551 GetTapePos(long long *pos)
2552 {
2553 int err = 0;
2554
2555 #ifdef RDUMP
2556 if (host) {
2557 *pos = (long long) rmtseek(0, SEEK_CUR);
2558 err = *pos < 0;
2559 }
2560 else
2561 #endif
2562 {
2563 if (magtapein) {
2564 long mtpos;
2565 *pos = 0;
2566 err = (ioctl(mt, MTIOCPOS, &mtpos) < 0);
2567 *pos = (long long)mtpos;
2568 }
2569 else {
2570 *pos = LSEEK(mt, 0, SEEK_CUR);
2571 err = (*pos < 0);
2572 }
2573 }
2574 if (err) {
2575 err = errno;
2576 fprintf(stdout, "[%ld] error: %d (getting tapepos: %lld)\n",
2577 (unsigned long)getpid(), err, *pos);
2578 return err;
2579 }
2580 return err;
2581 }
2582
2583 typedef struct mt_pos {
2584 short mt_op;
2585 int mt_count;
2586 } MTPosRec, *MTPosPtr;
2587
2588 /*
2589 * go to specified position on tape
2590 */
2591 int
2592 GotoTapePos(long long pos)
2593 {
2594 int err = 0;
2595
2596 #ifdef RDUMP
2597 if (host)
2598 err = (rmtseek(pos, SEEK_SET) < 0);
2599 else
2600 #endif
2601 {
2602 if (magtapein) {
2603 struct mt_pos buf;
2604 buf.mt_op = MTSEEK;
2605 buf.mt_count = (int) pos;
2606 err = (ioctl(mt, MTIOCTOP, &buf) < 0);
2607 }
2608 else {
2609 pos = LSEEK(mt, pos, SEEK_SET);
2610 err = (pos < 0);
2611 }
2612 }
2613 if (err) {
2614 err = errno;
2615 fprintf(stdout, "[%ld] error: %d (setting tapepos: %lld)\n",
2616 (unsigned long)getpid(), err, pos);
2617 return err;
2618 }
2619 return err;
2620 }
2621
2622 /*
2623 * read next data from tape to re-sync
2624 */
2625 void
2626 ReReadFromTape(void)
2627 {
2628 FLUSHTAPEBUF();
2629 noresyncmesg = 1;
2630 if (gethead(&spcl) == FAIL) {
2631 #ifdef DEBUG_QFA
2632 fprintf(stdout, "DEBUG 1 gethead failed\n");
2633 #endif
2634 }
2635 findinode(&spcl);
2636 noresyncmesg = 0;
2637 }
2638
2639 void
2640 ReReadInodeFromTape(dump_ino_t theino)
2641 {
2642 long cntloop = 0;
2643
2644 FLUSHTAPEBUF();
2645 noresyncmesg = 1;
2646 do {
2647 cntloop++;
2648 gethead(&spcl);
2649 } while (!(spcl.c_inumber == theino && spcl.c_type == TS_INODE && spcl.c_date == dumpdate) && (cntloop < 32));
2650 #ifdef DEBUG_QFA
2651 fprintf(stderr, "%ld reads\n", cntloop);
2652 if (cntloop == 32) {
2653 fprintf(stderr, "DEBUG: bufsize %d\n", bufsize);
2654 fprintf(stderr, "DEBUG: ntrec %ld\n", ntrec);
2655 fprintf(stderr, "DEBUG: %ld reads\n", cntloop);
2656 }
2657 #endif
2658 findinode(&spcl);
2659 noresyncmesg = 0;
2660 }
2661 #endif /* USE_QFA */
2662
2663 void
2664 RequestVol(long tnum)
2665 {
2666 FLUSHTAPEBUF();
2667 getvol(tnum);
2668 }