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