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