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