]> git.wh0rd.org Git - dump.git/blob - restore/tape.c
4ac6a25d68c70aaaadc412fc6ecad3e35dc4f778
[dump.git] / restore / tape.c
1 /*
2  *      Ported to Linux's Second Extended File System as part of the
3  *      dump and restore backup suit
4  *      Remy Card <card@Linux.EU.Org>, 1994-1997
5  *      Stelian Pop <pop@cybercable.fr>, 1999 
6  *
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 #if 0
49 static char sccsid[] = "@(#)tape.c      8.9 (Berkeley) 5/1/95";
50 #endif
51 static const char rcsid[] =
52         "$Id: tape.c,v 1.2 1999/10/11 12:53:24 stelian Exp $";
53 #endif /* not lint */
54
55 #include <sys/param.h>
56 #include <sys/file.h>
57 #include <sys/mtio.h>
58 #include <sys/stat.h>
59
60 #ifdef  __linux__
61 #include <sys/time.h>
62 #include <linux/ext2_fs.h>
63 #include <bsdcompat.h>
64 #else   /* __linux__ */
65 #include <ufs/ufs/dinode.h>
66 #endif  /* __linux__ */
67 #include <protocols/dumprestore.h>
68
69 #include <errno.h>
70 #include <setjmp.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <unistd.h>
75
76 #ifdef  __linux__
77 #include <ext2fs/ext2fs.h>
78 #endif
79
80 #include "restore.h"
81 #include "extern.h"
82 #include "pathnames.h"
83
84 static long     fssize = MAXBSIZE;
85 static int      mt = -1;
86 static int      pipein = 0;
87 static char     *magtape;
88 static int      blkcnt;
89 static int      numtrec;
90 static char     *tapebuf;
91 static union    u_spcl endoftapemark;
92 static long     blksread;               /* blocks read since last header */
93 static long     tpblksread = 0;         /* TP_BSIZE blocks read */
94 static long     tapesread;
95 static jmp_buf  restart;
96 static int      gettingfile = 0;        /* restart has a valid frame */
97 static char     *host = NULL;
98
99 static int      ofile;
100 static char     *map;
101 static char     lnkbuf[MAXPATHLEN + 1];
102 static int      pathlen;
103
104 int             oldinofmt;      /* old inode format conversion required */
105 int             Bcvt;           /* Swap Bytes (for CCI or sun) */
106 static int      Qcvt;           /* Swap quads (for sun) */
107
108 #define FLUSHTAPEBUF()  blkcnt = ntrec + 1
109
110 static void      accthdr __P((struct s_spcl *));
111 static int       checksum __P((int *));
112 static void      findinode __P((struct s_spcl *));
113 static void      findtapeblksize __P((void));
114 static int       gethead __P((struct s_spcl *));
115 static void      readtape __P((char *));
116 static void      setdumpnum __P((void));
117 static u_long    swabl __P((u_long));
118 static u_char   *swablong __P((u_char *, int));
119 static u_char   *swabshort __P((u_char *, int));
120 static void      terminateinput __P((void));
121 static void      xtrfile __P((char *, long));
122 static void      xtrlnkfile __P((char *, long));
123 static void      xtrlnkskip __P((char *, long));
124 static void      xtrmap __P((char *, long));
125 static void      xtrmapskip __P((char *, long));
126 static void      xtrskip __P((char *, long));
127
128 static int readmapflag;
129
130 /*
131  * Set up an input source
132  */
133 void
134 setinput(source)
135         char *source;
136 {
137         FLUSHTAPEBUF();
138         if (bflag)
139                 newtapebuf(ntrec);
140         else
141                 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
142         terminal = stdin;
143
144 #ifdef RRESTORE
145         if (strchr(source, ':')) {
146                 host = source;
147                 source = strchr(host, ':');
148                 *source++ = '\0';
149                 if (rmthost(host) == 0)
150                         done(1);
151         } else
152 #endif
153         if (strcmp(source, "-") == 0) {
154                 /*
155                  * Since input is coming from a pipe we must establish
156                  * our own connection to the terminal.
157                  */
158                 terminal = fopen(_PATH_TTY, "r");
159                 if (terminal == NULL) {
160                         (void)fprintf(stderr, "cannot open %s: %s\n",
161                             _PATH_TTY, strerror(errno));
162                         terminal = fopen(_PATH_DEVNULL, "r");
163                         if (terminal == NULL) {
164                                 (void)fprintf(stderr, "cannot open %s: %s\n",
165                                     _PATH_DEVNULL, strerror(errno));
166                                 done(1);
167                         }
168                 }
169                 pipein++;
170         }
171         setuid(getuid());       /* no longer need or want root privileges */
172         magtape = strdup(source);
173         if (magtape == NULL) {
174                 fprintf(stderr, "Cannot allocate space for magtape buffer\n");
175                 done(1);
176         }
177 }
178
179 void
180 newtapebuf(size)
181         long size;
182 {
183         static tapebufsize = -1;
184
185         ntrec = size;
186         if (size <= tapebufsize)
187                 return;
188         if (tapebuf != NULL)
189                 free(tapebuf);
190         tapebuf = malloc(size * TP_BSIZE);
191         if (tapebuf == NULL) {
192                 fprintf(stderr, "Cannot allocate space for tape buffer\n");
193                 done(1);
194         }
195         tapebufsize = size;
196 }
197
198 /*
199  * Verify that the tape drive can be accessed and
200  * that it actually is a dump tape.
201  */
202 void
203 setup()
204 {
205         int i, j, *ip;
206         struct stat stbuf;
207
208         vprintf(stdout, "Verify tape and initialize maps\n");
209 #ifdef RRESTORE
210         if (host)
211                 mt = rmtopen(magtape, 0);
212         else
213 #endif
214         if (pipein)
215                 mt = 0;
216         else
217                 mt = open(magtape, O_RDONLY, 0);
218         if (mt < 0) {
219                 fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
220                 done(1);
221         }
222         volno = 1;
223         setdumpnum();
224         FLUSHTAPEBUF();
225         if (!pipein && !bflag)
226                 findtapeblksize();
227         if (gethead(&spcl) == FAIL) {
228                 blkcnt--; /* push back this block */
229                 blksread--;
230                 tpblksread--;
231                 cvtflag++;
232                 if (gethead(&spcl) == FAIL) {
233                         fprintf(stderr, "Tape is not a dump tape\n");
234                         done(1);
235                 }
236                 fprintf(stderr, "Converting to new file system format.\n");
237         }
238         if (pipein) {
239                 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
240                 endoftapemark.s_spcl.c_type = TS_END;
241                 ip = (int *)&endoftapemark;
242                 j = sizeof(union u_spcl) / sizeof(int);
243                 i = 0;
244                 do
245                         i += *ip++;
246                 while (--j);
247                 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
248         }
249         if (vflag || command == 't' || command == 'C')
250                 printdumpinfo();
251         if (filesys == NULL) {
252                 filesys = spcl.c_filesys;
253         }
254         dumptime = spcl.c_ddate;
255         dumpdate = spcl.c_date;
256         if (stat(".", &stbuf) < 0) {
257                 fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
258                 done(1);
259         }
260         if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
261                 fssize = TP_BSIZE;
262         if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
263                 fssize = stbuf.st_blksize;
264         if (((fssize - 1) & fssize) != 0) {
265                 fprintf(stderr, "bad block size %ld\n", fssize);
266                 done(1);
267         }
268         if (spcl.c_volume != 1) {
269                 fprintf(stderr, "Tape is not volume 1 of the dump\n");
270                 done(1);
271         }
272         if (gethead(&spcl) == FAIL) {
273                 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
274                 panic("no header after volume mark!\n");
275         }
276         findinode(&spcl);
277         if (spcl.c_type != TS_CLRI) {
278                 fprintf(stderr, "Cannot find file removal list\n");
279                 done(1);
280         }
281         maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
282         dprintf(stdout, "maxino = %ld\n", maxino);
283         map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
284         if (map == NULL)
285                 panic("no memory for active inode map\n");
286         usedinomap = map;
287         curfile.action = USING;
288         getfile(xtrmap, xtrmapskip);
289         if (spcl.c_type != TS_BITS) {
290                 fprintf(stderr, "Cannot find file dump list\n");
291                 done(1);
292         }
293         map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
294         if (map == (char *)NULL)
295                 panic("no memory for file dump list\n");
296         dumpmap = map;
297         curfile.action = USING;
298         getfile(xtrmap, xtrmapskip);
299         /*
300          * If there may be whiteout entries on the tape, pretend that the
301          * whiteout inode exists, so that the whiteout entries can be
302          * extracted.
303          */
304         if (oldinofmt == 0)
305                 SETINO(WINO, dumpmap);
306 }
307
308 /*
309  * Prompt user to load a new dump volume.
310  * "Nextvol" is the next suggested volume to use.
311  * This suggested volume is enforced when doing full
312  * or incremental restores, but can be overridden by
313  * the user when only extracting a subset of the files.
314  */
315 void
316 getvol(nextvol)
317         long nextvol;
318 {
319         long newvol=0, savecnt=0, wantnext=0, i;
320         union u_spcl tmpspcl;
321 #       define tmpbuf tmpspcl.s_spcl
322         char buf[TP_BSIZE];
323
324         if (nextvol == 1) {
325                 tapesread = 0;
326                 gettingfile = 0;
327         }
328         if (pipein) {
329                 if (nextvol != 1)
330                         panic("Changing volumes on pipe input?\n");
331                 if (volno == 1)
332                         return;
333                 goto gethdr;
334         }
335         savecnt = blksread;
336 again:
337         if (pipein)
338                 done(1); /* pipes do not get a second chance */
339         if (command == 'R' || command == 'r' || curfile.action != SKIP) {
340                 newvol = nextvol;
341                 wantnext = 1;
342         } else {
343                 newvol = 0;
344                 wantnext = 0;
345         }
346         while (newvol <= 0) {
347                 if (tapesread == 0) {
348                         fprintf(stderr, "%s%s%s%s%s",
349                             "You have not read any tapes yet.\n",
350                             "Unless you know which volume your",
351                             " file(s) are on you should start\n",
352                             "with the last volume and work",
353                             " towards the first.\n");
354                 } else {
355                         fprintf(stderr, "You have read volumes");
356                         strcpy(buf, ": ");
357                         for (i = 1; i < 32; i++)
358                                 if (tapesread & (1 << i)) {
359                                         fprintf(stderr, "%s%ld", buf, i);
360                                         strcpy(buf, ", ");
361                                 }
362                         fprintf(stderr, "\n");
363                 }
364                 do      {
365                         fprintf(stderr, "Specify next volume #: ");
366                         (void) fflush(stderr);
367                         (void) fgets(buf, BUFSIZ, terminal);
368                 } while (!feof(terminal) && buf[0] == '\n');
369                 if (feof(terminal))
370                         done(1);
371                 newvol = atoi(buf);
372                 if (newvol <= 0) {
373                         fprintf(stderr,
374                             "Volume numbers are positive numerics\n");
375                 }
376         }
377         if (newvol == volno) {
378                 tapesread |= 1 << volno;
379                 return;
380         }
381         closemt();
382         fprintf(stderr, "Mount tape volume %ld\n", newvol);
383         fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
384         fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
385         (void) fflush(stderr);
386         (void) fgets(buf, BUFSIZ, terminal);
387         if (feof(terminal))
388                 done(1);
389         if (!strcmp(buf, "none\n")) {
390                 terminateinput();
391                 return;
392         }
393         if (buf[0] != '\n') {
394                 (void) strcpy(magtape, buf);
395                 magtape[strlen(magtape) - 1] = '\0';
396         }
397 #ifdef RRESTORE
398         if (host)
399                 mt = rmtopen(magtape, 0);
400         else
401 #endif
402                 mt = open(magtape, O_RDONLY, 0);
403
404         if (mt == -1) {
405                 fprintf(stderr, "Cannot open %s\n", magtape);
406                 volno = -1;
407                 goto again;
408         }
409 gethdr:
410         volno = newvol;
411         setdumpnum();
412         FLUSHTAPEBUF();
413         if (gethead(&tmpbuf) == FAIL) {
414                 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
415                 fprintf(stderr, "tape is not dump tape\n");
416                 volno = 0;
417                 goto again;
418         }
419         if (tmpbuf.c_volume != volno) {
420                 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
421                 volno = 0;
422                 goto again;
423         }
424         if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
425 #ifdef  __linux__
426                 fprintf(stderr, "Wrong dump date\n\tgot: %s",
427                         ctime4(&tmpbuf.c_date));
428                 fprintf(stderr, "\twanted: %s", ctime4(&dumpdate));
429 #else
430                 fprintf(stderr, "Wrong dump date\n\tgot: %s",
431                         ctime(&tmpbuf.c_date));
432                 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
433 #endif
434                 volno = 0;
435                 goto again;
436         }
437         tapesread |= 1 << volno;
438         blksread = savecnt;
439         /*
440          * If continuing from the previous volume, skip over any
441          * blocks read already at the end of the previous volume.
442          *
443          * If coming to this volume at random, skip to the beginning
444          * of the next record.
445          */
446         dprintf(stdout, "read %ld recs, tape starts with %d\n",
447                 tpblksread, tmpbuf.c_firstrec);
448         if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
449                 if (!wantnext) {
450                         tpblksread = tmpbuf.c_firstrec;
451                         for (i = tmpbuf.c_count; i > 0; i--)
452                                 readtape(buf);
453                 } else if (tmpbuf.c_firstrec > 0 &&
454                            tmpbuf.c_firstrec < tpblksread - 1) {
455                         /*
456                          * -1 since we've read the volume header
457                          */
458                         i = tpblksread - tmpbuf.c_firstrec - 1;
459                         dprintf(stderr, "Skipping %ld duplicate record%s.\n",
460                                 i, i > 1 ? "s" : "");
461                         while (--i >= 0)
462                                 readtape(buf);
463                 }
464         }
465         if (curfile.action == USING) {
466                 if (volno == 1)
467                         panic("active file into volume 1\n");
468                 return;
469         }
470         /*
471          * Skip up to the beginning of the next record
472          */
473         if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
474                 for (i = tmpbuf.c_count; i > 0; i--)
475                         readtape(buf);
476         (void) gethead(&spcl);
477         findinode(&spcl);
478         if (gettingfile) {
479                 gettingfile = 0;
480                 longjmp(restart, 1);
481         }
482 }
483
484 /*
485  * Handle unexpected EOF.
486  */
487 static void
488 terminateinput()
489 {
490
491         if (gettingfile && curfile.action == USING) {
492                 printf("Warning: %s %s\n",
493                     "End-of-input encountered while extracting", curfile.name);
494         }
495         curfile.name = "<name unknown>";
496         curfile.action = UNKNOWN;
497         curfile.dip = NULL;
498         curfile.ino = maxino;
499         if (gettingfile) {
500                 gettingfile = 0;
501                 longjmp(restart, 1);
502         }
503 }
504
505 /*
506  * handle multiple dumps per tape by skipping forward to the
507  * appropriate one.
508  */
509 static void
510 setdumpnum()
511 {
512         struct mtop tcom;
513
514         if (dumpnum == 1 || volno != 1)
515                 return;
516         if (pipein) {
517                 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
518                 done(1);
519         }
520         tcom.mt_op = MTFSF;
521         tcom.mt_count = dumpnum - 1;
522 #ifdef RRESTORE
523         if (host)
524                 rmtioctl(MTFSF, dumpnum - 1);
525         else
526 #endif
527                 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
528                         fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
529 }
530
531 void
532 printdumpinfo()
533 {
534 #ifdef  __linux__
535         fprintf(stdout, "Dump   date: %s", ctime4(&spcl.c_date));
536         fprintf(stdout, "Dumped from: %s",
537             (spcl.c_ddate == 0) ? "the epoch\n" : ctime4(&spcl.c_ddate));
538 #else
539         fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
540         fprintf(stdout, "Dumped from: %s",
541             (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
542 #endif
543         if (spcl.c_host[0] == '\0')
544                 return;
545         fprintf(stderr, "Level %d dump of %s on %s:%s\n",
546                 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
547         fprintf(stderr, "Label: %s\n", spcl.c_label);
548 }
549
550 int
551 extractfile(name)
552         char *name;
553 {
554         int flags;
555         mode_t mode;
556         struct timeval timep[2];
557         struct entry *ep;
558 #ifdef  __linux__
559         int err;
560         uid_t uid;
561         gid_t gid;
562 #endif
563
564         curfile.name = name;
565         curfile.action = USING;
566 #ifdef  __linux__
567         timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
568         timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
569         timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
570         timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
571 #else   /* __linux__ */
572         timep[0].tv_sec = curfile.dip->di_atime;
573         timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
574         timep[1].tv_sec = curfile.dip->di_mtime;
575         timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
576 #endif  /* __linux__ */
577         mode = curfile.dip->di_mode;
578         flags = curfile.dip->di_flags;
579         switch (mode & IFMT) {
580
581         default:
582                 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
583                 skipfile();
584                 return (FAIL);
585
586         case IFSOCK:
587                 vprintf(stdout, "skipped socket %s\n", name);
588                 skipfile();
589                 return (GOOD);
590
591         case IFDIR:
592                 if (mflag) {
593                         ep = lookupname(name);
594                         if (ep == NULL || ep->e_flags & EXTRACT)
595                                 panic("unextracted directory %s\n", name);
596                         skipfile();
597                         return (GOOD);
598                 }
599                 vprintf(stdout, "extract file %s\n", name);
600                 return (genliteraldir(name, curfile.ino));
601
602         case IFLNK:
603                 lnkbuf[0] = '\0';
604                 pathlen = 0;
605 #ifdef  __linux__
606                 uid = curfile.dip->di_uid;
607                 gid = curfile.dip->di_gid;
608 #endif
609                 getfile(xtrlnkfile, xtrlnkskip);
610                 if (pathlen == 0) {
611                         vprintf(stdout,
612                             "%s: zero length symbolic link (ignored)\n", name);
613                         return (GOOD);
614                 }
615 #ifdef  __linux__
616                 err = linkit(lnkbuf, name, SYMLINK);
617                 if (err == GOOD)
618                         (void) chown(name, uid, gid);
619                 return (err);
620 #else
621                 return (linkit(lnkbuf, name, SYMLINK));
622 #endif
623
624         case IFIFO:
625                 vprintf(stdout, "extract fifo %s\n", name);
626                 if (Nflag) {
627                         skipfile();
628                         return (GOOD);
629                 }
630                 if (uflag && !Nflag)
631                         (void)unlink(name);
632                 if (mkfifo(name, mode) < 0) {
633                         fprintf(stderr, "%s: cannot create fifo: %s\n",
634                             name, strerror(errno));
635                         skipfile();
636                         return (FAIL);
637                 }
638                 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
639                 (void) chmod(name, mode);
640 #ifdef  __linux__
641                 (void) fsetflags(name, flags);
642 #else
643                 (void) chflags(name, flags);
644 #endif
645                 skipfile();
646                 utimes(name, timep);
647                 return (GOOD);
648
649         case IFCHR:
650         case IFBLK:
651                 vprintf(stdout, "extract special file %s\n", name);
652                 if (Nflag) {
653                         skipfile();
654                         return (GOOD);
655                 }
656                 if (uflag)
657                         (void)unlink(name);
658                 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
659                         fprintf(stderr, "%s: cannot create special file: %s\n",
660                             name, strerror(errno));
661                         skipfile();
662                         return (FAIL);
663                 }
664                 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
665                 (void) chmod(name, mode);
666 #ifdef  __linux__
667                 (void) fsetflags(name, flags);
668 #else
669                 (void) chflags(name, flags);
670 #endif
671                 skipfile();
672                 utimes(name, timep);
673                 return (GOOD);
674
675         case IFREG:
676                 vprintf(stdout, "extract file %s\n", name);
677                 if (Nflag) {
678                         skipfile();
679                         return (GOOD);
680                 }
681                 if (uflag)
682                         (void)unlink(name);
683                 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
684                     0666)) < 0) {
685                         fprintf(stderr, "%s: cannot create file: %s\n",
686                             name, strerror(errno));
687                         skipfile();
688                         return (FAIL);
689                 }
690                 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
691                 (void) fchmod(ofile, mode);
692 #ifdef  __linux__
693                 (void) fsetflags(ofile, flags);
694 #else
695                 (void) fchflags(ofile, flags);
696 #endif
697                 getfile(xtrfile, xtrskip);
698                 (void) close(ofile);
699                 utimes(name, timep);
700                 return (GOOD);
701         }
702         /* NOTREACHED */
703 }
704
705 /*
706  * skip over bit maps on the tape
707  */
708 void
709 skipmaps()
710 {
711
712         while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
713                 skipfile();
714 }
715
716 /*
717  * skip over a file on the tape
718  */
719 void
720 skipfile()
721 {
722
723         curfile.action = SKIP;
724         getfile(xtrnull, xtrnull);
725 }
726
727 /*
728  * Extract a file from the tape.
729  * When an allocated block is found it is passed to the fill function;
730  * when an unallocated block (hole) is found, a zeroed buffer is passed
731  * to the skip function.
732  */
733 void
734 getfile(fill, skip)
735         void    (*fill) __P((char *, long));
736         void    (*skip) __P((char *, long));
737 {
738         register int i;
739         int curblk = 0;
740         quad_t size = spcl.c_dinode.di_size;
741         int last_write_was_hole = 0;
742         long origsize = size;
743         static char clearedbuf[MAXBSIZE];
744         char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
745         char junk[TP_BSIZE];
746
747         if (spcl.c_type == TS_END)
748                 panic("ran off end of tape\n");
749         if (spcl.c_magic != NFS_MAGIC)
750                 panic("not at beginning of a file\n");
751         if (!gettingfile && setjmp(restart) != 0)
752                 return;
753         gettingfile++;
754 loop:
755         for (i = 0; i < spcl.c_count; i++) {
756                 if (readmapflag || spcl.c_addr[i]) {
757                         readtape(&buf[curblk++][0]);
758                         if (curblk == fssize / TP_BSIZE) {
759                                 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
760                                      fssize : (curblk - 1) * TP_BSIZE + size));
761                                 curblk = 0;
762                                 last_write_was_hole = 0;
763                         }
764                 } else {
765                         if (curblk > 0) {
766                                 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
767                                      curblk * TP_BSIZE :
768                                      (curblk - 1) * TP_BSIZE + size));
769                                 curblk = 0;
770                         }
771                         (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
772                                 TP_BSIZE : size));
773                         last_write_was_hole = 1;
774                 }
775                 if ((size -= TP_BSIZE) <= 0) {
776                         for (i++; i < spcl.c_count; i++)
777                                 if (readmapflag || spcl.c_addr[i])
778                                         readtape(junk);
779                         break;
780                 }
781         }
782         if (gethead(&spcl) == GOOD && size > 0) {
783                 if (spcl.c_type == TS_ADDR)
784                         goto loop;
785                 dprintf(stdout,
786                         "Missing address (header) block for %s at %ld blocks\n",
787                         curfile.name, blksread);
788         }
789         if (curblk > 0) {
790                 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
791                 last_write_was_hole = 0;
792         }
793         if (last_write_was_hole) {
794                 ftruncate(ofile, origsize);
795         }
796         findinode(&spcl);
797         gettingfile = 0;
798 }
799
800 /*
801  * Write out the next block of a file.
802  */
803 static void
804 xtrfile(buf, size)
805         char    *buf;
806         long    size;
807 {
808
809         if (Nflag)
810                 return;
811         if (write(ofile, buf, (int) size) == -1) {
812                 fprintf(stderr,
813                     "write error extracting inode %ld, name %s\nwrite: %s\n",
814                         curfile.ino, curfile.name, strerror(errno));
815                 done(1);
816         }
817 }
818
819 /*
820  * Skip over a hole in a file.
821  */
822 /* ARGSUSED */
823 static void
824 xtrskip(buf, size)
825         char *buf;
826         long size;
827 {
828
829         if (lseek(ofile, size, SEEK_CUR) == -1) {
830                 fprintf(stderr,
831                     "seek error extracting inode %ld, name %s\nlseek: %s\n",
832                         curfile.ino, curfile.name, strerror(errno));
833                 done(1);
834         }
835 }
836
837 /*
838  * Collect the next block of a symbolic link.
839  */
840 static void
841 xtrlnkfile(buf, size)
842         char    *buf;
843         long    size;
844 {
845
846         pathlen += size;
847         if (pathlen > MAXPATHLEN) {
848                 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
849                     curfile.name, lnkbuf, buf, pathlen);
850                 done(1);
851         }
852         (void) strcat(lnkbuf, buf);
853 }
854
855 /*
856  * Skip over a hole in a symbolic link (should never happen).
857  */
858 /* ARGSUSED */
859 static void
860 xtrlnkskip(buf, size)
861         char *buf;
862         long size;
863 {
864
865         fprintf(stderr, "unallocated block in symbolic link %s\n",
866                 curfile.name);
867         done(1);
868 }
869
870 /*
871  * Collect the next block of a bit map.
872  */
873 static void
874 xtrmap(buf, size)
875         char    *buf;
876         long    size;
877 {
878
879         memmove(map, buf, size);
880         map += size;
881 }
882
883 /*
884  * Skip over a hole in a bit map (should never happen).
885  */
886 /* ARGSUSED */
887 static void
888 xtrmapskip(buf, size)
889         char *buf;
890         long size;
891 {
892
893         panic("hole in map\n");
894         map += size;
895 }
896
897 /*
898  * Noop, when an extraction function is not needed.
899  */
900 /* ARGSUSED */
901 void
902 xtrnull(buf, size)
903         char *buf;
904         long size;
905 {
906
907         return;
908 }
909
910 int
911 do_cmpfiles(int fd_tape, int fd_disk, long size)
912 {
913 #ifndef BUFSIZE
914 #define BUFSIZE 1024
915 #endif
916         static char buf_tape[BUFSIZ];
917         static char buf_disk[BUFSIZ];
918         int n_tape;
919         int n_disk;
920
921         while (size > 0) {
922                 if ((n_tape = read(fd_tape, buf_tape, BUFSIZE)) < 1) {
923                         close(fd_tape), close(fd_disk);
924                         panic("do_cmpfiles: unexpected EOF[1]");
925                 }
926                 if ((n_disk = read(fd_disk, buf_disk, BUFSIZE)) < 1) {
927                         close(fd_tape), close(fd_disk);
928                         panic("do_cmpfiles: unexpected EOF[2]");
929                 }
930                 if (n_tape != n_disk) {
931                         close(fd_tape), close(fd_disk);
932                         panic("do_cmpfiles: sizes different!");
933                 }
934                 if (memcmp(buf_tape, buf_disk, n_tape) != 0) return (1);
935                 size -= n_tape;
936         }
937         return (0);
938 }
939
940 /* for debugging compare problems */
941 #undef COMPARE_FAIL_KEEP_FILE
942
943 #ifdef COMPARE_FAIL_KEEP_FILE
944 /* return true if tapefile should be unlinked after compare */
945 int
946 #else
947 void
948 #endif
949 cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk)
950 {
951         struct stat sbuf_tape;
952         int fd_tape, fd_disk;
953
954         if (stat(tapefile, &sbuf_tape) != 0) {
955                 panic("Can't lstat tmp file %s: %s\n", tapefile,
956                       strerror(errno));
957         }
958
959         if (sbuf_disk->st_size != sbuf_tape.st_size) {
960                 fprintf(stderr,
961                         "%s: size changed from %ld to %ld.\n",
962                         diskfile, sbuf_tape.st_size, sbuf_disk->st_size);
963 #ifdef COMPARE_FAIL_KEEP_FILE
964                 return (0);
965 #else
966                 return;
967 #endif
968         }
969
970         if ((fd_tape = open(tapefile, O_RDONLY)) < 0) {
971                 panic("Can't open %s: %s\n", tapefile, strerror(errno));
972         }
973         if ((fd_disk = open(diskfile, O_RDONLY)) < 0) {
974                 close(fd_tape);
975                 panic("Can't open %s: %s\n", diskfile, strerror(errno));
976         }
977
978         if (do_cmpfiles(fd_tape, fd_disk, sbuf_tape.st_size)) {
979                 fprintf(stderr, "%s: tape and disk copies are different\n",
980                         diskfile);
981                 close(fd_tape);
982                 close(fd_disk);
983 #ifdef COMPARE_FAIL_KEEP_FILE
984                 /* rename the file to live in /tmp */
985                 /* rename `tapefile' to /tmp/<basename of diskfile> */
986                 {
987                         char *p = strrchr(diskfile, '/');
988                         char newname[MAXPATHLEN];
989                         if (!p) {
990                                 panic("can't find / in %s\n", diskfile);
991                         }
992                         sprintf(newname, "%s/debug/%s", tmpdir, p + 1);
993                         if (rename(tapefile, newname)) {
994                                 panic("rename from %s to %s failed: %s\n",
995                                       tapefile, newname,
996                                       strerror(errno));
997                         } else {
998                                 fprintf(stderr, "*** %s saved to %s\n",
999                                         tapefile, newname);
1000                         }
1001                 }
1002                 
1003                 /* don't unlink the file (it's not there anymore */
1004                 /* anyway) */
1005                 return (0);
1006 #else
1007                 return;
1008 #endif
1009         }
1010         close(fd_tape);
1011         close(fd_disk);
1012 #ifdef COMPARE_FAIL_KEEP_FILE
1013         return (1);
1014 #endif
1015 }
1016
1017 static char tmpfilename[128];
1018
1019 void
1020 comparefile(name)
1021         char *name;
1022 {
1023         static char *tmpfile = NULL;
1024         int mode;
1025         struct stat sb, stemp;
1026         int r;
1027
1028         if ((r = lstat(name, &sb)) != 0) {
1029                 fprintf(stderr, "%s: does not exist (%d, %d).\n", name, r, errno);
1030                 skipfile();
1031                 return;
1032         }
1033
1034         curfile.name = name;
1035         curfile.action = USING;
1036         mode = curfile.dip->di_mode;
1037
1038         vprintf(stdout, "comparing %s (size: %ld, mode: 0%o)\n", name,
1039                 sb.st_size, mode);
1040
1041         if (sb.st_mode != mode) {
1042                 fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n",
1043                         name, mode & 07777, sb.st_mode & 07777);
1044         }
1045         switch (mode & IFMT) {
1046         default:
1047                 skipfile();
1048                 return;
1049
1050         case IFSOCK:
1051                 skipfile();
1052                 return;
1053
1054         case IFDIR:
1055                 skipfile();
1056                 return;
1057
1058         case IFLNK: {
1059                 char lbuf[MAXPATHLEN + 1];
1060                 int lsize;
1061
1062                 if (!(sb.st_mode & S_IFLNK)) {
1063                         fprintf(stderr, "%s: is no longer a symbolic link\n",
1064                                 name);
1065                         return;
1066                 }
1067                 lnkbuf[0] = '\0';
1068                 pathlen = 0;
1069                 getfile(xtrlnkfile, xtrlnkskip);
1070                 if (pathlen == 0) {
1071                         fprintf(stderr,
1072                                 "%s: zero length symbolic link (ignored)\n",
1073                                 name);
1074                         return;
1075                 }
1076                 if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) {
1077                         panic("readlink of %s failed: %s", name,
1078                               strerror(errno));
1079                 }
1080                 lbuf[lsize] = 0;
1081                 if (strcmp(lbuf, lnkbuf) != 0) {
1082                         fprintf(stderr,
1083                                 "%s: symbolic link changed from %s to %s.\n",
1084                                 name, lnkbuf, lbuf);
1085                         return;
1086                 }
1087                 return;
1088         }
1089
1090         case IFCHR:
1091         case IFBLK:
1092                 if (!(sb.st_mode & (S_IFCHR|S_IFBLK))) {
1093                         fprintf(stderr, "%s: no longer a special file\n",
1094                                 name);
1095                         skipfile();
1096                         return;
1097                 }
1098
1099                 if (sb.st_rdev != (int)curfile.dip->di_rdev) {
1100                         fprintf(stderr,
1101                                 "%s: device changed from %d,%d to %d,%d.\n",
1102                                 name,
1103                                 ((int)curfile.dip->di_rdev >> 8) & 0xf,
1104                                 (int)curfile.dip->di_rdev & 0xf,
1105                                 ((int)sb.st_rdev >> 8) & 0xf,
1106                                 (int)sb.st_rdev & 0xf);
1107                 }
1108                 skipfile();
1109                 return;
1110
1111         case IFREG:
1112                 if (tmpfile == NULL) {
1113                         /* argument to mktemp() must not be in RO space: */
1114                         sprintf(tmpfilename, "%s/restoreCXXXXXX", tmpdir);
1115                         tmpfile = mktemp(&tmpfilename[0]);
1116                 }
1117                 if ((stat(tmpfile, &stemp) == 0) && (unlink(tmpfile) != 0)) {
1118                         panic("cannot delete tmp file %s: %s\n",
1119                               tmpfile, strerror(errno));
1120                 }
1121                 if ((ofile = creat(tmpfile, 0600)) < 0) {
1122                         panic("cannot create file temp file %s: %s\n",
1123                               name, strerror(errno));
1124                 }
1125                 getfile(xtrfile, xtrskip);
1126                 (void) close(ofile);
1127 #ifdef COMPARE_FAIL_KEEP_FILE
1128                 if (cmpfiles(tmpfile, name, &sb))
1129                         unlink(tmpfile);
1130 #else
1131                 cmpfiles(tmpfile, name, &sb);
1132                 unlink(tmpfile);
1133 #endif
1134                 return;
1135         }
1136         /* NOTREACHED */
1137 }
1138
1139 /*
1140  * Read TP_BSIZE blocks from the input.
1141  * Handle read errors, and end of media.
1142  */
1143 static void
1144 readtape(buf)
1145         char *buf;
1146 {
1147         long rd, newvol, i;
1148         int cnt, seek_failed;
1149
1150         if (blkcnt < numtrec) {
1151                 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
1152                 blksread++;
1153                 tpblksread++;
1154                 return;
1155         }
1156         for (i = 0; i < ntrec; i++)
1157                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1158         if (numtrec == 0)
1159                 numtrec = ntrec;
1160         cnt = ntrec * TP_BSIZE;
1161         rd = 0;
1162 getmore:
1163 #ifdef RRESTORE
1164         if (host)
1165                 i = rmtread(&tapebuf[rd], cnt);
1166         else
1167 #endif
1168                 i = read(mt, &tapebuf[rd], cnt);
1169         /*
1170          * Check for mid-tape short read error.
1171          * If found, skip rest of buffer and start with the next.
1172          */
1173         if (!pipein && numtrec < ntrec && i > 0) {
1174                 dprintf(stdout, "mid-media short read error.\n");
1175                 numtrec = ntrec;
1176         }
1177         /*
1178          * Handle partial block read.
1179          */
1180         if (pipein && i == 0 && rd > 0)
1181                 i = rd;
1182         else if (i > 0 && i != ntrec * TP_BSIZE) {
1183                 if (pipein) {
1184                         rd += i;
1185                         cnt -= i;
1186                         if (cnt > 0)
1187                                 goto getmore;
1188                         i = rd;
1189                 } else {
1190                         /*
1191                          * Short read. Process the blocks read.
1192                          */
1193                         if (i % TP_BSIZE != 0)
1194                                 vprintf(stdout,
1195                                     "partial block read: %ld should be %ld\n",
1196                                     i, ntrec * TP_BSIZE);
1197                         numtrec = i / TP_BSIZE;
1198                 }
1199         }
1200         /*
1201          * Handle read error.
1202          */
1203         if (i < 0) {
1204                 fprintf(stderr, "Tape read error while ");
1205                 switch (curfile.action) {
1206                 default:
1207                         fprintf(stderr, "trying to set up tape\n");
1208                         break;
1209                 case UNKNOWN:
1210                         fprintf(stderr, "trying to resynchronize\n");
1211                         break;
1212                 case USING:
1213                         fprintf(stderr, "restoring %s\n", curfile.name);
1214                         break;
1215                 case SKIP:
1216                         fprintf(stderr, "skipping over inode %ld\n",
1217                                 curfile.ino);
1218                         break;
1219                 }
1220                 if (!yflag && !reply("continue"))
1221                         done(1);
1222                 i = ntrec * TP_BSIZE;
1223                 memset(tapebuf, 0, i);
1224 #ifdef RRESTORE
1225                 if (host)
1226                         seek_failed = (rmtseek(i, 1) < 0);
1227                 else
1228 #endif
1229                         seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
1230
1231                 if (seek_failed) {
1232                         fprintf(stderr,
1233                             "continuation failed: %s\n", strerror(errno));
1234                         done(1);
1235                 }
1236         }
1237         /*
1238          * Handle end of tape.
1239          */
1240         if (i == 0) {
1241                 vprintf(stdout, "End-of-tape encountered\n");
1242                 if (!pipein) {
1243                         newvol = volno + 1;
1244                         volno = 0;
1245                         numtrec = 0;
1246                         getvol(newvol);
1247                         readtape(buf);
1248                         return;
1249                 }
1250                 if (rd % TP_BSIZE != 0)
1251                         panic("partial block read: %d should be %d\n",
1252                                 rd, ntrec * TP_BSIZE);
1253                 terminateinput();
1254                 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
1255         }
1256         blkcnt = 0;
1257         memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
1258         blksread++;
1259         tpblksread++;
1260 }
1261
1262 static void
1263 findtapeblksize()
1264 {
1265         register long i;
1266
1267         for (i = 0; i < ntrec; i++)
1268                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1269         blkcnt = 0;
1270 #ifdef RRESTORE
1271         if (host)
1272                 i = rmtread(tapebuf, ntrec * TP_BSIZE);
1273         else
1274 #endif
1275                 i = read(mt, tapebuf, ntrec * TP_BSIZE);
1276
1277         if (i <= 0) {
1278                 fprintf(stderr, "tape read error: %s\n", strerror(errno));
1279                 done(1);
1280         }
1281         if (i % TP_BSIZE != 0) {
1282                 fprintf(stderr, "Tape block size (%ld) %s (%d)\n",
1283                         i, "is not a multiple of dump block size", TP_BSIZE);
1284                 done(1);
1285         }
1286         ntrec = i / TP_BSIZE;
1287         numtrec = ntrec;
1288         vprintf(stdout, "Tape block size is %ld\n", ntrec);
1289 }
1290
1291 void
1292 closemt()
1293 {
1294
1295         if (mt < 0)
1296                 return;
1297 #ifdef RRESTORE
1298         if (host)
1299                 rmtclose();
1300         else
1301 #endif
1302                 (void) close(mt);
1303 }
1304
1305 /*
1306  * Read the next block from the tape.
1307  * Check to see if it is one of several vintage headers.
1308  * If it is an old style header, convert it to a new style header.
1309  * If it is not any valid header, return an error.
1310  */
1311 static int
1312 gethead(buf)
1313         struct s_spcl *buf;
1314 {
1315         long i;
1316         union {
1317                 quad_t  qval;
1318                 int32_t val[2];
1319         } qcvt;
1320         union u_ospcl {
1321                 char dummy[TP_BSIZE];
1322                 struct  s_ospcl {
1323                         int32_t c_type;
1324                         int32_t c_date;
1325                         int32_t c_ddate;
1326                         int32_t c_volume;
1327                         int32_t c_tapea;
1328                         u_short c_inumber;
1329                         int32_t c_magic;
1330                         int32_t c_checksum;
1331                         struct odinode {
1332                                 unsigned short odi_mode;
1333                                 u_short odi_nlink;
1334                                 u_short odi_uid;
1335                                 u_short odi_gid;
1336                                 int32_t odi_size;
1337                                 int32_t odi_rdev;
1338                                 char    odi_addr[36];
1339                                 int32_t odi_atime;
1340                                 int32_t odi_mtime;
1341                                 int32_t odi_ctime;
1342                         } c_dinode;
1343                         int32_t c_count;
1344                         char    c_addr[256];
1345                 } s_ospcl;
1346         } u_ospcl;
1347
1348         if (!cvtflag) {
1349                 readtape((char *)buf);
1350                 if (buf->c_magic != NFS_MAGIC) {
1351                         if (swabl(buf->c_magic) != NFS_MAGIC)
1352                                 return (FAIL);
1353                         if (!Bcvt) {
1354                                 vprintf(stdout, "Note: Doing Byte swapping\n");
1355                                 Bcvt = 1;
1356                         }
1357                 }
1358                 if (checksum((int *)buf) == FAIL)
1359                         return (FAIL);
1360                 if (Bcvt) {
1361                         swabst((u_char *)"8l4s31l", (u_char *)buf);
1362                         swabst((u_char *)"l",(u_char *) &buf->c_level);
1363                         swabst((u_char *)"2l",(u_char *) &buf->c_flags);
1364                 }
1365                 goto good;
1366         }
1367         readtape((char *)(&u_ospcl.s_ospcl));
1368         memset(buf, 0, (long)TP_BSIZE);
1369         buf->c_type = u_ospcl.s_ospcl.c_type;
1370         buf->c_date = u_ospcl.s_ospcl.c_date;
1371         buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1372         buf->c_volume = u_ospcl.s_ospcl.c_volume;
1373         buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1374         buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1375         buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1376         buf->c_magic = u_ospcl.s_ospcl.c_magic;
1377         buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1378         buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1379         buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1380         buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1381         buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1382         buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1383 #ifdef  __linux__
1384         buf->c_dinode.di_atime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
1385         buf->c_dinode.di_mtime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1386         buf->c_dinode.di_ctime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1387 #else   /* __linux__ */
1388         buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1389         buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1390         buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1391 #endif  /* __linux__ */
1392         buf->c_count = u_ospcl.s_ospcl.c_count;
1393         memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1394         if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1395             checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1396                 return(FAIL);
1397         buf->c_magic = NFS_MAGIC;
1398
1399 good:
1400         if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1401             (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1402                 qcvt.qval = buf->c_dinode.di_size;
1403                 if (qcvt.val[0] || qcvt.val[1]) {
1404                         printf("Note: Doing Quad swapping\n");
1405                         Qcvt = 1;
1406                 }
1407         }
1408         if (Qcvt) {
1409                 qcvt.qval = buf->c_dinode.di_size;
1410                 i = qcvt.val[1];
1411                 qcvt.val[1] = qcvt.val[0];
1412                 qcvt.val[0] = i;
1413                 buf->c_dinode.di_size = qcvt.qval;
1414         }
1415         readmapflag = 0;
1416
1417         switch (buf->c_type) {
1418
1419         case TS_CLRI:
1420         case TS_BITS:
1421                 /*
1422                  * Have to patch up missing information in bit map headers
1423                  */
1424                 buf->c_inumber = 0;
1425                 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1426                 if (buf->c_count > TP_NINDIR)
1427                         readmapflag = 1;
1428                 else 
1429                         for (i = 0; i < buf->c_count; i++)
1430                                 buf->c_addr[i]++;
1431                 break;
1432
1433         case TS_TAPE:
1434                 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1435                         oldinofmt = 1;
1436                 /* fall through */
1437         case TS_END:
1438                 buf->c_inumber = 0;
1439                 break;
1440
1441         case TS_INODE:
1442         case TS_ADDR:
1443                 break;
1444
1445         default:
1446                 panic("gethead: unknown inode type %d\n", buf->c_type);
1447                 break;
1448         }
1449         /*
1450          * If we are restoring a filesystem with old format inodes,
1451          * copy the uid/gid to the new location.
1452          */
1453         if (oldinofmt) {
1454                 buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1455                 buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1456         }
1457         if (dflag)
1458                 accthdr(buf);
1459         return(GOOD);
1460 }
1461
1462 /*
1463  * Check that a header is where it belongs and predict the next header
1464  */
1465 static void
1466 accthdr(header)
1467         struct s_spcl *header;
1468 {
1469         static ino_t previno = 0x7fffffff;
1470         static int prevtype;
1471         static long predict;
1472         long blks, i;
1473
1474         if (header->c_type == TS_TAPE) {
1475                 fprintf(stderr, "Volume header (%s inode format) ",
1476                     oldinofmt ? "old" : "new");
1477                 if (header->c_firstrec)
1478                         fprintf(stderr, "begins with record %d",
1479                                 header->c_firstrec);
1480                 fprintf(stderr, "\n");
1481                 previno = 0x7fffffff;
1482                 return;
1483         }
1484         if (previno == 0x7fffffff)
1485                 goto newcalc;
1486         switch (prevtype) {
1487         case TS_BITS:
1488                 fprintf(stderr, "Dumped inodes map header");
1489                 break;
1490         case TS_CLRI:
1491                 fprintf(stderr, "Used inodes map header");
1492                 break;
1493         case TS_INODE:
1494                 fprintf(stderr, "File header, ino %ld", previno);
1495                 break;
1496         case TS_ADDR:
1497                 fprintf(stderr, "File continuation header, ino %ld", previno);
1498                 break;
1499         case TS_END:
1500                 fprintf(stderr, "End of tape header");
1501                 break;
1502         }
1503         if (predict != blksread - 1)
1504                 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1505                         predict, blksread - 1);
1506         fprintf(stderr, "\n");
1507 newcalc:
1508         blks = 0;
1509         if (header->c_type != TS_END)
1510                 for (i = 0; i < header->c_count; i++)
1511                         if (readmapflag || header->c_addr[i] != 0)
1512                                 blks++;
1513         predict = blks;
1514         blksread = 0;
1515         prevtype = header->c_type;
1516         previno = header->c_inumber;
1517 }
1518
1519 /*
1520  * Find an inode header.
1521  * Complain if had to skip, and complain is set.
1522  */
1523 static void
1524 findinode(header)
1525         struct s_spcl *header;
1526 {
1527         static long skipcnt = 0;
1528         long i;
1529         char buf[TP_BSIZE];
1530
1531         curfile.name = "<name unknown>";
1532         curfile.action = UNKNOWN;
1533         curfile.dip = NULL;
1534         curfile.ino = 0;
1535         do {
1536                 if (header->c_magic != NFS_MAGIC) {
1537                         skipcnt++;
1538                         while (gethead(header) == FAIL ||
1539                             header->c_date != dumpdate)
1540                                 skipcnt++;
1541                 }
1542                 switch (header->c_type) {
1543
1544                 case TS_ADDR:
1545                         /*
1546                          * Skip up to the beginning of the next record
1547                          */
1548                         for (i = 0; i < header->c_count; i++)
1549                                 if (header->c_addr[i])
1550                                         readtape(buf);
1551                         while (gethead(header) == FAIL ||
1552                             header->c_date != dumpdate)
1553                                 skipcnt++;
1554                         break;
1555
1556                 case TS_INODE:
1557                         curfile.dip = &header->c_dinode;
1558                         curfile.ino = header->c_inumber;
1559                         break;
1560
1561                 case TS_END:
1562                         curfile.ino = maxino;
1563                         break;
1564
1565                 case TS_CLRI:
1566                         curfile.name = "<file removal list>";
1567                         break;
1568
1569                 case TS_BITS:
1570                         curfile.name = "<file dump list>";
1571                         break;
1572
1573                 case TS_TAPE:
1574                         panic("unexpected tape header\n");
1575                         /* NOTREACHED */
1576
1577                 default:
1578                         panic("unknown tape header type %d\n", spcl.c_type);
1579                         /* NOTREACHED */
1580
1581                 }
1582         } while (header->c_type == TS_ADDR);
1583         if (skipcnt > 0)
1584                 fprintf(stderr, "resync restore, skipped %ld blocks\n",
1585                     skipcnt);
1586         skipcnt = 0;
1587 }
1588
1589 static int
1590 checksum(buf)
1591         register int *buf;
1592 {
1593         register int i, j;
1594
1595         j = sizeof(union u_spcl) / sizeof(int);
1596         i = 0;
1597         if(!Bcvt) {
1598                 do
1599                         i += *buf++;
1600                 while (--j);
1601         } else {
1602                 /* What happens if we want to read restore tapes
1603                         for a 16bit int machine??? */
1604                 do
1605                         i += swabl(*buf++);
1606                 while (--j);
1607         }
1608
1609         if (i != CHECKSUM) {
1610                 fprintf(stderr, "Checksum error %o, inode %ld file %s\n", i,
1611                         curfile.ino, curfile.name);
1612                 return(FAIL);
1613         }
1614         return(GOOD);
1615 }
1616
1617 #ifdef RRESTORE
1618 #if __STDC__
1619 #include <stdarg.h>
1620 #else
1621 #include <varargs.h>
1622 #endif
1623
1624 void
1625 #if __STDC__
1626 msg(const char *fmt, ...)
1627 #else
1628 msg(fmt, va_alist)
1629         char *fmt;
1630         va_dcl
1631 #endif
1632 {
1633         va_list ap;
1634 #if __STDC__
1635         va_start(ap, fmt);
1636 #else
1637         va_start(ap);
1638 #endif
1639         (void)vfprintf(stderr, fmt, ap);
1640         va_end(ap);
1641 }
1642 #endif /* RRESTORE */
1643
1644 static u_char *
1645 swabshort(sp, n)
1646         register u_char *sp;
1647         register int n;
1648 {
1649         char c;
1650
1651         while (--n >= 0) {
1652                 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1653                 sp += 2;
1654         }
1655         return (sp);
1656 }
1657
1658 static u_char *
1659 swablong(sp, n)
1660         register u_char *sp;
1661         register int n;
1662 {
1663         char c;
1664
1665         while (--n >= 0) {
1666                 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1667                 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1668                 sp += 4;
1669         }
1670         return (sp);
1671 }
1672
1673 void
1674 swabst(cp, sp)
1675         register u_char *cp, *sp;
1676 {
1677         int n = 0;
1678
1679         while (*cp) {
1680                 switch (*cp) {
1681                 case '0': case '1': case '2': case '3': case '4':
1682                 case '5': case '6': case '7': case '8': case '9':
1683                         n = (n * 10) + (*cp++ - '0');
1684                         continue;
1685
1686                 case 's': case 'w': case 'h':
1687                         if (n == 0)
1688                                 n = 1;
1689                         sp = swabshort(sp, n);
1690                         break;
1691
1692                 case 'l':
1693                         if (n == 0)
1694                                 n = 1;
1695                         sp = swablong(sp, n);
1696                         break;
1697
1698                 default: /* Any other character, like 'b' counts as byte. */
1699                         if (n == 0)
1700                                 n = 1;
1701                         sp += n;
1702                         break;
1703                 }
1704                 cp++;
1705                 n = 0;
1706         }
1707 }
1708
1709 static u_long
1710 swabl(x)
1711         u_long x;
1712 {
1713         swabst((u_char *)"l", (u_char *)&x);
1714         return (x);
1715 }