]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/restore/tape.c
This commit was generated by cvs2svn to compensate for changes in r167612,
[FreeBSD/FreeBSD.git] / sbin / restore / tape.c
1 /*
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)tape.c      8.9 (Berkeley) 5/1/95";
38 #endif
39 #endif /* not lint */
40
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 #include <sys/param.h>
45 #include <sys/file.h>
46 #include <sys/mtio.h>
47 #include <sys/stat.h>
48 #include <sys/time.h>
49 #include <sys/extattr.h>
50 #include <sys/acl.h>
51
52 #include <ufs/ufs/extattr.h>
53 #include <ufs/ufs/dinode.h>
54 #include <protocols/dumprestore.h>
55
56 #include <errno.h>
57 #include <limits.h>
58 #include <paths.h>
59 #include <setjmp.h>
60 #include <stdint.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <time.h>
65 #include <timeconv.h>
66 #include <unistd.h>
67
68 #include "restore.h"
69 #include "extern.h"
70
71 static long     fssize = MAXBSIZE;
72 static int      mt = -1;
73 static int      pipein = 0;
74 static int      pipecmdin = 0;
75 static FILE     *popenfp = NULL;
76 static char     *magtape;
77 static int      blkcnt;
78 static int      numtrec;
79 static char     *tapebuf;
80 static union    u_spcl endoftapemark;
81 static long     byteslide = 0;
82 static long     blksread;               /* blocks read since last header */
83 static int64_t  tapeaddr = 0;           /* current TP_BSIZE tape record */
84 static long     tapesread;
85 static jmp_buf  restart;
86 static int      gettingfile = 0;        /* restart has a valid frame */
87 static char     *host = NULL;
88 static int      readmapflag;
89
90 static int      ofile;
91 static char     *map;
92 static char     lnkbuf[MAXPATHLEN + 1];
93 static int      pathlen;
94
95 int             Bcvt;           /* Swap Bytes */
96 int             oldinofmt;      /* FreeBSD 1 inode format needs cvt */
97
98 #define FLUSHTAPEBUF()  blkcnt = ntrec + 1
99
100 char *namespace_names[] = EXTATTR_NAMESPACE_NAMES;
101
102 static void      accthdr(struct s_spcl *);
103 static int       checksum(int *);
104 static void      findinode(struct s_spcl *);
105 static void      findtapeblksize(void);
106 static char     *setupextattr(int);
107 static void      xtrattr(char *, long);
108 static void      set_extattr_link(char *, void *, int);
109 static void      set_extattr_fd(int, char *, void *, int);
110 static int       gethead(struct s_spcl *);
111 static void      readtape(char *);
112 static void      setdumpnum(void);
113 static u_long    swabl(u_long);
114 static u_char   *swablong(u_char *, int);
115 static u_char   *swabshort(u_char *, int);
116 static void      terminateinput(void);
117 static void      xtrfile(char *, long);
118 static void      xtrlnkfile(char *, long);
119 static void      xtrlnkskip(char *, long);
120 static void      xtrmap(char *, long);
121 static void      xtrmapskip(char *, long);
122 static void      xtrskip(char *, long);
123
124 /*
125  * Set up an input source
126  */
127 void
128 setinput(char *source, int ispipecommand)
129 {
130         FLUSHTAPEBUF();
131         if (bflag)
132                 newtapebuf(ntrec);
133         else
134                 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
135         terminal = stdin;
136
137         if (ispipecommand)
138                 pipecmdin++;
139         else
140 #ifdef RRESTORE
141         if (strchr(source, ':')) {
142                 host = source;
143                 source = strchr(host, ':');
144                 *source++ = '\0';
145                 if (rmthost(host) == 0)
146                         done(1);
147         } else
148 #endif
149         if (strcmp(source, "-") == 0) {
150                 /*
151                  * Since input is coming from a pipe we must establish
152                  * our own connection to the terminal.
153                  */
154                 terminal = fopen(_PATH_TTY, "r");
155                 if (terminal == NULL) {
156                         (void)fprintf(stderr, "cannot open %s: %s\n",
157                             _PATH_TTY, strerror(errno));
158                         terminal = fopen(_PATH_DEVNULL, "r");
159                         if (terminal == NULL) {
160                                 (void)fprintf(stderr, "cannot open %s: %s\n",
161                                     _PATH_DEVNULL, strerror(errno));
162                                 done(1);
163                         }
164                 }
165                 pipein++;
166         }
167         setuid(getuid());       /* no longer need or want root privileges */
168         magtape = strdup(source);
169         if (magtape == NULL) {
170                 fprintf(stderr, "Cannot allocate space for magtape buffer\n");
171                 done(1);
172         }
173 }
174
175 void
176 newtapebuf(long size)
177 {
178         static int tapebufsize = -1;
179
180         ntrec = size;
181         if (size <= tapebufsize)
182                 return;
183         if (tapebuf != NULL)
184                 free(tapebuf - TP_BSIZE);
185         tapebuf = malloc((size+1) * TP_BSIZE);
186         if (tapebuf == NULL) {
187                 fprintf(stderr, "Cannot allocate space for tape buffer\n");
188                 done(1);
189         }
190         tapebuf += TP_BSIZE;
191         tapebufsize = size;
192 }
193
194 /*
195  * Verify that the tape drive can be accessed and
196  * that it actually is a dump tape.
197  */
198 void
199 setup(void)
200 {
201         int i, j, *ip;
202         struct stat stbuf;
203
204         vprintf(stdout, "Verify tape and initialize maps\n");
205         if (pipecmdin) {
206                 if (setenv("RESTORE_VOLUME", "1", 1) == -1) {
207                         fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n",
208                             strerror(errno));
209                         done(1);
210                 }
211                 popenfp = popen(magtape, "r");
212                 mt = popenfp ? fileno(popenfp) : -1;
213         } else
214 #ifdef RRESTORE
215         if (host)
216                 mt = rmtopen(magtape, 0);
217         else
218 #endif
219         if (pipein)
220                 mt = 0;
221         else
222                 mt = open(magtape, O_RDONLY, 0);
223         if (mt < 0) {
224                 fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
225                 done(1);
226         }
227         volno = 1;
228         setdumpnum();
229         FLUSHTAPEBUF();
230         if (!pipein && !bflag)
231                 findtapeblksize();
232         if (gethead(&spcl) == FAIL) {
233                 fprintf(stderr, "Tape is not a dump tape\n");
234                 done(1);
235         }
236         if (pipein) {
237                 endoftapemark.s_spcl.c_magic = FS_UFS2_MAGIC;
238                 endoftapemark.s_spcl.c_type = TS_END;
239                 ip = (int *)&endoftapemark;
240                 j = sizeof(union u_spcl) / sizeof(int);
241                 i = 0;
242                 do
243                         i += *ip++;
244                 while (--j);
245                 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
246         }
247         if (vflag || command == 't')
248                 printdumpinfo();
249         dumptime = _time64_to_time(spcl.c_ddate);
250         dumpdate = _time64_to_time(spcl.c_date);
251         if (stat(".", &stbuf) < 0) {
252                 fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
253                 done(1);
254         }
255         if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
256                 fssize = TP_BSIZE;
257         if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
258                 fssize = stbuf.st_blksize;
259         if (((fssize - 1) & fssize) != 0) {
260                 fprintf(stderr, "bad block size %ld\n", fssize);
261                 done(1);
262         }
263         if (spcl.c_volume != 1) {
264                 fprintf(stderr, "Tape is not volume 1 of the dump\n");
265                 done(1);
266         }
267         if (gethead(&spcl) == FAIL) {
268                 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
269                 panic("no header after volume mark!\n");
270         }
271         findinode(&spcl);
272         if (spcl.c_type != TS_CLRI) {
273                 fprintf(stderr, "Cannot find file removal list\n");
274                 done(1);
275         }
276         maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
277         dprintf(stdout, "maxino = %d\n", maxino);
278         map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
279         if (map == NULL)
280                 panic("no memory for active inode map\n");
281         usedinomap = map;
282         curfile.action = USING;
283         getfile(xtrmap, xtrmapskip, xtrmapskip);
284         if (spcl.c_type != TS_BITS) {
285                 fprintf(stderr, "Cannot find file dump list\n");
286                 done(1);
287         }
288         map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
289         if (map == (char *)NULL)
290                 panic("no memory for file dump list\n");
291         dumpmap = map;
292         curfile.action = USING;
293         getfile(xtrmap, xtrmapskip, xtrmapskip);
294         /*
295          * If there may be whiteout entries on the tape, pretend that the
296          * whiteout inode exists, so that the whiteout entries can be
297          * extracted.
298          */
299         SETINO(WINO, dumpmap);
300         /* 'r' restores don't call getvol() for tape 1, so mark it as read. */
301         if (command == 'r')
302                 tapesread = 1;
303 }
304
305 /*
306  * Prompt user to load a new dump volume.
307  * "Nextvol" is the next suggested volume to use.
308  * This suggested volume is enforced when doing full
309  * or incremental restores, but can be overridden by
310  * the user when only extracting a subset of the files.
311  */
312 void
313 getvol(long nextvol)
314 {
315         int64_t prevtapea;
316         long i, newvol, savecnt;
317         union u_spcl tmpspcl;
318 #       define tmpbuf tmpspcl.s_spcl
319         char buf[TP_BSIZE];
320
321         if (nextvol == 1) {
322                 tapesread = 0;
323                 gettingfile = 0;
324         }
325         prevtapea = tapeaddr;
326         savecnt = blksread;
327         if (pipein) {
328                 if (nextvol != 1) {
329                         panic("Changing volumes on pipe input?\n");
330                         /* Avoid looping if we couldn't ask the user. */
331                         if (yflag || ferror(terminal) || feof(terminal))
332                                 done(1);
333                 }
334                 if (volno == 1)
335                         return;
336                 if (pipecmdin) {
337                         closemt();
338                         goto getpipecmdhdr;
339                 }
340                 goto gethdr;
341         }
342 again:
343         if (pipein)
344                 done(1); /* pipes do not get a second chance */
345         if (command == 'R' || command == 'r' || curfile.action != SKIP)
346                 newvol = nextvol;
347         else
348                 newvol = 0;
349         while (newvol <= 0) {
350                 if (tapesread == 0) {
351                         fprintf(stderr, "%s%s%s%s%s%s%s",
352                             "You have not read any tapes yet.\n",
353                             "If you are extracting just a few files,",
354                             " start with the last volume\n",
355                             "and work towards the first; restore",
356                             " can quickly skip tapes that\n",
357                             "have no further files to extract.",
358                             " Otherwise, begin with volume 1.\n");
359                 } else {
360                         fprintf(stderr, "You have read volumes");
361                         strcpy(buf, ": ");
362                         for (i = 0; i < 32; i++)
363                                 if (tapesread & (1 << i)) {
364                                         fprintf(stderr, "%s%ld", buf, i + 1);
365                                         strcpy(buf, ", ");
366                                 }
367                         fprintf(stderr, "\n");
368                 }
369                 do      {
370                         fprintf(stderr, "Specify next volume #: ");
371                         (void) fflush(stderr);
372                         if (fgets(buf, BUFSIZ, terminal) == NULL)
373                                 done(1);
374                 } while (buf[0] == '\n');
375                 newvol = atoi(buf);
376                 if (newvol <= 0) {
377                         fprintf(stderr,
378                             "Volume numbers are positive numerics\n");
379                 }
380         }
381         if (newvol == volno) {
382                 tapesread |= 1 << (volno - 1);
383                 return;
384         }
385         closemt();
386         fprintf(stderr, "Mount tape volume %ld\n", newvol);
387         fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
388         fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
389         (void) fflush(stderr);
390         if (fgets(buf, BUFSIZ, terminal) == NULL)
391                 done(1);
392         if (!strcmp(buf, "none\n")) {
393                 terminateinput();
394                 return;
395         }
396         if (buf[0] != '\n') {
397                 (void) strcpy(magtape, buf);
398                 magtape[strlen(magtape) - 1] = '\0';
399         }
400         if (pipecmdin) {
401                 char volno[sizeof("2147483647")];
402
403 getpipecmdhdr:
404                 (void)sprintf(volno, "%d", newvol);
405                 if (setenv("RESTORE_VOLUME", volno, 1) == -1) {
406                         fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n",
407                             strerror(errno));
408                         done(1);
409                 }
410                 popenfp = popen(magtape, "r");
411                 mt = popenfp ? fileno(popenfp) : -1;
412         } else
413 #ifdef RRESTORE
414         if (host)
415                 mt = rmtopen(magtape, 0);
416         else
417 #endif
418                 mt = open(magtape, O_RDONLY, 0);
419
420         if (mt == -1) {
421                 fprintf(stderr, "Cannot open %s\n", magtape);
422                 volno = -1;
423                 goto again;
424         }
425 gethdr:
426         volno = newvol;
427         setdumpnum();
428         FLUSHTAPEBUF();
429         if (gethead(&tmpbuf) == FAIL) {
430                 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
431                 fprintf(stderr, "tape is not dump tape\n");
432                 volno = 0;
433                 goto again;
434         }
435         if (tmpbuf.c_volume != volno) {
436                 fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume);
437                 volno = 0;
438                 goto again;
439         }
440         if (_time64_to_time(tmpbuf.c_date) != dumpdate ||
441             _time64_to_time(tmpbuf.c_ddate) != dumptime) {
442                 time_t t = _time64_to_time(tmpbuf.c_date);
443                 fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t));
444                 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
445                 volno = 0;
446                 goto again;
447         }
448         tapesread |= 1 << (volno - 1);
449         blksread = savecnt;
450         /*
451          * If continuing from the previous volume, skip over any
452          * blocks read already at the end of the previous volume.
453          *
454          * If coming to this volume at random, skip to the beginning
455          * of the next record.
456          */
457         dprintf(stdout, "last rec %qd, tape starts with %qd\n", prevtapea,
458             tmpbuf.c_tapea);
459         if (tmpbuf.c_type == TS_TAPE) {
460                 if (curfile.action != USING) {
461                         /*
462                          * XXX Dump incorrectly sets c_count to 1 in the
463                          * volume header of the first tape, so ignore
464                          * c_count when volno == 1.
465                          */
466                         if (volno != 1)
467                                 for (i = tmpbuf.c_count; i > 0; i--)
468                                         readtape(buf);
469                 } else if (tmpbuf.c_tapea <= prevtapea) {
470                         /*
471                          * Normally the value of c_tapea in the volume
472                          * header is the record number of the header itself.
473                          * However in the volume header following an EOT-
474                          * terminated tape, it is the record number of the
475                          * first continuation data block (dump bug?).
476                          *
477                          * The next record we want is `prevtapea + 1'.
478                          */
479                         i = prevtapea + 1 - tmpbuf.c_tapea;
480                         dprintf(stderr, "Skipping %ld duplicate record%s.\n",
481                                 i, i > 1 ? "s" : "");
482                         while (--i >= 0)
483                                 readtape(buf);
484                 }
485         }
486         if (curfile.action == USING) {
487                 if (volno == 1)
488                         panic("active file into volume 1\n");
489                 return;
490         }
491         (void) gethead(&spcl);
492         findinode(&spcl);
493         if (gettingfile) {
494                 gettingfile = 0;
495                 longjmp(restart, 1);
496         }
497 }
498
499 /*
500  * Handle unexpected EOF.
501  */
502 static void
503 terminateinput(void)
504 {
505
506         if (gettingfile && curfile.action == USING) {
507                 printf("Warning: %s %s\n",
508                     "End-of-input encountered while extracting", curfile.name);
509         }
510         curfile.name = "<name unknown>";
511         curfile.action = UNKNOWN;
512         curfile.mode = 0;
513         curfile.ino = maxino;
514         if (gettingfile) {
515                 gettingfile = 0;
516                 longjmp(restart, 1);
517         }
518 }
519
520 /*
521  * handle multiple dumps per tape by skipping forward to the
522  * appropriate one.
523  */
524 static void
525 setdumpnum(void)
526 {
527         struct mtop tcom;
528
529         if (dumpnum == 1 || volno != 1)
530                 return;
531         if (pipein) {
532                 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
533                 done(1);
534         }
535         tcom.mt_op = MTFSF;
536         tcom.mt_count = dumpnum - 1;
537 #ifdef RRESTORE
538         if (host)
539                 rmtioctl(MTFSF, dumpnum - 1);
540         else
541 #endif
542                 if (!pipecmdin && ioctl(mt, MTIOCTOP, (char *)&tcom) < 0)
543                         fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
544 }
545
546 void
547 printdumpinfo(void)
548 {
549         time_t t;
550         t = _time64_to_time(spcl.c_date);
551         fprintf(stdout, "Dump   date: %s", ctime(&t));
552         t = _time64_to_time(spcl.c_ddate);
553         fprintf(stdout, "Dumped from: %s",
554             (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t));
555         if (spcl.c_host[0] == '\0')
556                 return;
557         fprintf(stderr, "Level %ld dump of %s on %s:%s\n",
558                 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
559         fprintf(stderr, "Label: %s\n", spcl.c_label);
560 }
561
562 int
563 extractfile(char *name)
564 {
565         int flags;
566         uid_t uid;
567         gid_t gid;
568         mode_t mode;
569         int extsize;
570         struct timeval mtimep[2], ctimep[2];
571         struct entry *ep;
572         char *buf;
573
574         curfile.name = name;
575         curfile.action = USING;
576         mtimep[0].tv_sec = curfile.atime_sec;
577         mtimep[0].tv_usec = curfile.atime_nsec / 1000;
578         mtimep[1].tv_sec = curfile.mtime_sec;
579         mtimep[1].tv_usec = curfile.mtime_nsec / 1000;
580         ctimep[0].tv_sec = curfile.atime_sec;
581         ctimep[0].tv_usec = curfile.atime_nsec / 1000;
582         ctimep[1].tv_sec = curfile.birthtime_sec;
583         ctimep[1].tv_usec = curfile.birthtime_nsec / 1000;
584         extsize = curfile.extsize;
585         uid = curfile.uid;
586         gid = curfile.gid;
587         mode = curfile.mode;
588         flags = curfile.file_flags;
589         switch (mode & IFMT) {
590
591         default:
592                 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
593                 skipfile();
594                 return (FAIL);
595
596         case IFSOCK:
597                 vprintf(stdout, "skipped socket %s\n", name);
598                 skipfile();
599                 return (GOOD);
600
601         case IFDIR:
602                 if (mflag) {
603                         ep = lookupname(name);
604                         if (ep == NULL || ep->e_flags & EXTRACT)
605                                 panic("unextracted directory %s\n", name);
606                         skipfile();
607                         return (GOOD);
608                 }
609                 vprintf(stdout, "extract file %s\n", name);
610                 return (genliteraldir(name, curfile.ino));
611
612         case IFLNK:
613                 lnkbuf[0] = '\0';
614                 pathlen = 0;
615                 buf = setupextattr(extsize);
616                 getfile(xtrlnkfile, xtrattr, xtrlnkskip);
617                 if (pathlen == 0) {
618                         vprintf(stdout,
619                             "%s: zero length symbolic link (ignored)\n", name);
620                         return (GOOD);
621                 }
622                 if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
623                         if (extsize > 0)
624                                 set_extattr_link(name, buf, extsize);
625                         (void) lchown(name, uid, gid);
626                         (void) lchmod(name, mode);
627                         (void) lutimes(name, ctimep);
628                         (void) lutimes(name, mtimep);
629                         (void) lchflags(name, flags);
630                         return (GOOD);
631                 }
632                 return (FAIL);
633
634         case IFIFO:
635                 vprintf(stdout, "extract fifo %s\n", name);
636                 if (Nflag) {
637                         skipfile();
638                         return (GOOD);
639                 }
640                 if (uflag)
641                         (void) unlink(name);
642                 if (mkfifo(name, 0600) < 0) {
643                         fprintf(stderr, "%s: cannot create fifo: %s\n",
644                             name, strerror(errno));
645                         skipfile();
646                         return (FAIL);
647                 }
648                 if (extsize == 0) {
649                         skipfile();
650                 } else {
651                         buf = setupextattr(extsize);
652                         getfile(xtrnull, xtrattr, xtrnull);
653                         set_extattr_file(name, buf, extsize);
654                 }
655                 (void) chown(name, uid, gid);
656                 (void) chmod(name, mode);
657                 (void) utimes(name, ctimep);
658                 (void) utimes(name, mtimep);
659                 (void) chflags(name, flags);
660                 return (GOOD);
661
662         case IFCHR:
663         case IFBLK:
664                 vprintf(stdout, "extract special file %s\n", name);
665                 if (Nflag) {
666                         skipfile();
667                         return (GOOD);
668                 }
669                 if (uflag)
670                         (void) unlink(name);
671                 if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600,
672                     (int)curfile.rdev) < 0) {
673                         fprintf(stderr, "%s: cannot create special file: %s\n",
674                             name, strerror(errno));
675                         skipfile();
676                         return (FAIL);
677                 }
678                 if (extsize == 0) {
679                         skipfile();
680                 } else {
681                         buf = setupextattr(extsize);
682                         getfile(xtrnull, xtrattr, xtrnull);
683                         set_extattr_file(name, buf, extsize);
684                 }
685                 (void) chown(name, uid, gid);
686                 (void) chmod(name, mode);
687                 (void) utimes(name, ctimep);
688                 (void) utimes(name, mtimep);
689                 (void) chflags(name, flags);
690                 return (GOOD);
691
692         case IFREG:
693                 vprintf(stdout, "extract file %s\n", name);
694                 if (Nflag) {
695                         skipfile();
696                         return (GOOD);
697                 }
698                 if (uflag)
699                         (void) unlink(name);
700                 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
701                     0600)) < 0) {
702                         fprintf(stderr, "%s: cannot create file: %s\n",
703                             name, strerror(errno));
704                         skipfile();
705                         return (FAIL);
706                 }
707                 buf = setupextattr(extsize);
708                 getfile(xtrfile, xtrattr, xtrskip);
709                 if (extsize > 0)
710                         set_extattr_fd(ofile, name, buf, extsize);
711                 (void) fchown(ofile, uid, gid);
712                 (void) fchmod(ofile, mode);
713                 (void) futimes(ofile, ctimep);
714                 (void) futimes(ofile, mtimep);
715                 (void) fchflags(ofile, flags);
716                 (void) close(ofile);
717                 return (GOOD);
718         }
719         /* NOTREACHED */
720 }
721
722 /*
723  * Set attributes for a file.
724  */
725 void
726 set_extattr_file(char *name, void *buf, int size)
727 {
728         struct extattr *eap, *eaend;
729
730         vprintf(stdout, "Set attributes for %s:", name);
731         eaend = buf + size;
732         for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
733                 /*
734                  * Make sure this entry is complete.
735                  */
736                 if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
737                         dprintf(stdout, "\n\t%scorrupted",
738                                 eap == buf ? "" : "remainder ");
739                         break;
740                 }
741                 if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
742                         continue;
743                 vprintf(stdout, "\n\t%s, (%d bytes), %*s",
744                         namespace_names[eap->ea_namespace], eap->ea_length,
745                         eap->ea_namelength, eap->ea_name);
746                 /*
747                  * First we try the general attribute setting interface.
748                  * However, some attributes can only be set by root or
749                  * by using special interfaces (for example, ACLs).
750                  */
751                 if (extattr_set_file(name, eap->ea_namespace, eap->ea_name,
752                     EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
753                         dprintf(stdout, " (set using extattr_set_file)");
754                         continue;
755                 }
756                 /*
757                  * If the general interface refuses to set the attribute,
758                  * then we try all the specialized interfaces that we
759                  * know about.
760                  */
761                 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
762                     !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
763                         if (acl_set_file(name, ACL_TYPE_ACCESS,
764                             EXTATTR_CONTENT(eap)) != -1) {
765                                 dprintf(stdout, " (set using acl_set_file)");
766                                 continue;
767                         }
768                 }
769                 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
770                     !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
771                         if (acl_set_file(name, ACL_TYPE_DEFAULT,
772                             EXTATTR_CONTENT(eap)) != -1) {
773                                 dprintf(stdout, " (set using acl_set_file)");
774                                 continue;
775                         }
776                 }
777                 vprintf(stdout, " (unable to set)");
778         }
779         vprintf(stdout, "\n");
780 }
781
782 /*
783  * Set attributes for a symbolic link.
784  */
785 static void
786 set_extattr_link(char *name, void *buf, int size)
787 {
788         struct extattr *eap, *eaend;
789
790         vprintf(stdout, "Set attributes for %s:", name);
791         eaend = buf + size;
792         for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
793                 /*
794                  * Make sure this entry is complete.
795                  */
796                 if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
797                         dprintf(stdout, "\n\t%scorrupted",
798                                 eap == buf ? "" : "remainder ");
799                         break;
800                 }
801                 if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
802                         continue;
803                 vprintf(stdout, "\n\t%s, (%d bytes), %*s",
804                         namespace_names[eap->ea_namespace], eap->ea_length,
805                         eap->ea_namelength, eap->ea_name);
806                 /*
807                  * First we try the general attribute setting interface.
808                  * However, some attributes can only be set by root or
809                  * by using special interfaces (for example, ACLs).
810                  */
811                 if (extattr_set_link(name, eap->ea_namespace, eap->ea_name,
812                     EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
813                         dprintf(stdout, " (set using extattr_set_link)");
814                         continue;
815                 }
816                 /*
817                  * If the general interface refuses to set the attribute,
818                  * then we try all the specialized interfaces that we
819                  * know about.
820                  */
821                 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
822                     !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
823                         if (acl_set_link_np(name, ACL_TYPE_ACCESS,
824                             EXTATTR_CONTENT(eap)) != -1) {
825                                 dprintf(stdout, " (set using acl_set_link_np)");
826                                 continue;
827                         }
828                 }
829                 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
830                     !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
831                         if (acl_set_link_np(name, ACL_TYPE_DEFAULT,
832                             EXTATTR_CONTENT(eap)) != -1) {
833                                 dprintf(stdout, " (set using acl_set_link_np)");
834                                 continue;
835                         }
836                 }
837                 vprintf(stdout, " (unable to set)");
838         }
839         vprintf(stdout, "\n");
840 }
841
842 /*
843  * Set attributes on a file descriptor.
844  */
845 static void
846 set_extattr_fd(int fd, char *name, void *buf, int size)
847 {
848         struct extattr *eap, *eaend;
849
850         vprintf(stdout, "Set attributes for %s:", name);
851         eaend = buf + size;
852         for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
853                 /*
854                  * Make sure this entry is complete.
855                  */
856                 if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
857                         dprintf(stdout, "\n\t%scorrupted",
858                                 eap == buf ? "" : "remainder ");
859                         break;
860                 }
861                 if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
862                         continue;
863                 vprintf(stdout, "\n\t%s, (%d bytes), %*s",
864                         namespace_names[eap->ea_namespace], eap->ea_length,
865                         eap->ea_namelength, eap->ea_name);
866                 /*
867                  * First we try the general attribute setting interface.
868                  * However, some attributes can only be set by root or
869                  * by using special interfaces (for example, ACLs).
870                  */
871                 if (extattr_set_fd(fd, eap->ea_namespace, eap->ea_name,
872                     EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
873                         dprintf(stdout, " (set using extattr_set_fd)");
874                         continue;
875                 }
876                 /*
877                  * If the general interface refuses to set the attribute,
878                  * then we try all the specialized interfaces that we
879                  * know about.
880                  */
881                 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
882                     !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
883                         if (acl_set_fd(fd, EXTATTR_CONTENT(eap)) != -1) {
884                                 dprintf(stdout, " (set using acl_set_fd)");
885                                 continue;
886                         }
887                 }
888                 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
889                     !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
890                         if (acl_set_file(name, ACL_TYPE_DEFAULT,
891                             EXTATTR_CONTENT(eap)) != -1) {
892                                 dprintf(stdout, " (set using acl_set_file)");
893                                 continue;
894                         }
895                 }
896                 vprintf(stdout, " (unable to set)");
897         }
898         vprintf(stdout, "\n");
899 }
900
901 /*
902  * skip over bit maps on the tape
903  */
904 void
905 skipmaps(void)
906 {
907
908         while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
909                 skipfile();
910 }
911
912 /*
913  * skip over a file on the tape
914  */
915 void
916 skipfile(void)
917 {
918
919         curfile.action = SKIP;
920         getfile(xtrnull, xtrnull, xtrnull);
921 }
922
923 /*
924  * Extract a file from the tape.
925  * When an allocated block is found it is passed to the fill function;
926  * when an unallocated block (hole) is found, a zeroed buffer is passed
927  * to the skip function.
928  */
929 void
930 getfile(void (*datafill)(char *, long), void (*attrfill)(char *, long),
931         void (*skip)(char *, long))
932 {
933         int i;
934         off_t size;
935         int curblk, attrsize;
936         void (*fillit)(char *, long);
937         static char clearedbuf[MAXBSIZE];
938         char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
939         char junk[TP_BSIZE];
940
941         curblk = 0;
942         size = spcl.c_size;
943         attrsize = spcl.c_extsize;
944         if (spcl.c_type == TS_END)
945                 panic("ran off end of tape\n");
946         if (spcl.c_magic != FS_UFS2_MAGIC)
947                 panic("not at beginning of a file\n");
948         if (!gettingfile && setjmp(restart) != 0)
949                 return;
950         gettingfile++;
951         fillit = datafill;
952         if (size == 0 && attrsize > 0) {
953                 fillit = attrfill;
954                 size = attrsize;
955                 attrsize = 0;
956         }
957 loop:
958         for (i = 0; i < spcl.c_count; i++) {
959                 if (!readmapflag && i > TP_NINDIR) {
960                         if (Dflag) {
961                                 fprintf(stderr, "spcl.c_count = %jd\n",
962                                     (intmax_t)spcl.c_count);
963                                 break;
964                         } else
965                                 panic("spcl.c_count = %jd\n",
966                                     (intmax_t)spcl.c_count);
967                 }
968                 if (readmapflag || spcl.c_addr[i]) {
969                         readtape(&buf[curblk++][0]);
970                         if (curblk == fssize / TP_BSIZE) {
971                                 (*fillit)((char *)buf, (long)(size > TP_BSIZE ?
972                                      fssize : (curblk - 1) * TP_BSIZE + size));
973                                 curblk = 0;
974                         }
975                 } else {
976                         if (curblk > 0) {
977                                 (*fillit)((char *)buf, (long)(size > TP_BSIZE ?
978                                      curblk * TP_BSIZE :
979                                      (curblk - 1) * TP_BSIZE + size));
980                                 curblk = 0;
981                         }
982                         (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
983                                 TP_BSIZE : size));
984                 }
985                 if ((size -= TP_BSIZE) <= 0) {
986                         if (size > -TP_BSIZE && curblk > 0) {
987                                 (*fillit)((char *)buf,
988                                         (long)((curblk * TP_BSIZE) + size));
989                                 curblk = 0;
990                         }
991                         if (attrsize > 0) {
992                                 fillit = attrfill;
993                                 size = attrsize;
994                                 attrsize = 0;
995                                 continue;
996                         }
997                         if (spcl.c_count - i > 1)
998                                 dprintf(stdout, "skipping %d junk block(s)\n",
999                                         spcl.c_count - i - 1);
1000                         for (i++; i < spcl.c_count; i++) {
1001                                 if (!readmapflag && i > TP_NINDIR) {
1002                                         if (Dflag) {
1003                                                 fprintf(stderr,
1004                                                     "spcl.c_count = %jd\n",
1005                                                     (intmax_t)spcl.c_count);
1006                                                 break;
1007                                         } else 
1008                                                 panic("spcl.c_count = %jd\n",
1009                                                     (intmax_t)spcl.c_count);
1010                                 }
1011                                 if (readmapflag || spcl.c_addr[i])
1012                                         readtape(junk);
1013                         }
1014                         break;
1015                 }
1016         }
1017         if (gethead(&spcl) == GOOD && size > 0) {
1018                 if (spcl.c_type == TS_ADDR)
1019                         goto loop;
1020                 dprintf(stdout,
1021                         "Missing address (header) block for %s at %ld blocks\n",
1022                         curfile.name, blksread);
1023         }
1024         if (curblk > 0)
1025                 panic("getfile: lost data\n");
1026         findinode(&spcl);
1027         gettingfile = 0;
1028 }
1029
1030 /*
1031  * These variables are shared between the next two functions.
1032  */
1033 static int extbufsize = 0;
1034 static char *extbuf;
1035 static int extloc;
1036
1037 /*
1038  * Allocate a buffer into which to extract extended attributes.
1039  */
1040 static char *
1041 setupextattr(int extsize)
1042 {
1043
1044         extloc = 0;
1045         if (extsize <= extbufsize)
1046                 return (extbuf);
1047         if (extbufsize > 0)
1048                 free(extbuf);
1049         if ((extbuf = malloc(extsize)) != NULL) {
1050                 extbufsize = extsize;
1051                 return (extbuf);
1052         }
1053         extbufsize = 0;
1054         extbuf = NULL;
1055         fprintf(stderr, "Cannot extract %d bytes %s for inode %d, name %s\n",
1056             extsize, "of extended attributes", curfile.ino, curfile.name);
1057         return (NULL);
1058 }
1059
1060 /*
1061  * Extract the next block of extended attributes.
1062  */
1063 static void
1064 xtrattr(char *buf, long size)
1065 {
1066
1067         if (extloc + size > extbufsize)
1068                 panic("overrun attribute buffer\n");
1069         memmove(&extbuf[extloc], buf, size);
1070         extloc += size;
1071 }
1072
1073 /*
1074  * Write out the next block of a file.
1075  */
1076 static void
1077 xtrfile(char *buf, long size)
1078 {
1079
1080         if (Nflag)
1081                 return;
1082         if (write(ofile, buf, (int) size) == -1) {
1083                 fprintf(stderr,
1084                     "write error extracting inode %d, name %s\nwrite: %s\n",
1085                         curfile.ino, curfile.name, strerror(errno));
1086         }
1087 }
1088
1089 /*
1090  * Skip over a hole in a file.
1091  */
1092 /* ARGSUSED */
1093 static void
1094 xtrskip(char *buf, long size)
1095 {
1096
1097         if (lseek(ofile, size, SEEK_CUR) == -1) {
1098                 fprintf(stderr,
1099                     "seek error extracting inode %d, name %s\nlseek: %s\n",
1100                         curfile.ino, curfile.name, strerror(errno));
1101                 done(1);
1102         }
1103 }
1104
1105 /*
1106  * Collect the next block of a symbolic link.
1107  */
1108 static void
1109 xtrlnkfile(char *buf, long size)
1110 {
1111
1112         pathlen += size;
1113         if (pathlen > MAXPATHLEN) {
1114                 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
1115                     curfile.name, lnkbuf, buf, pathlen);
1116                 done(1);
1117         }
1118         (void) strcat(lnkbuf, buf);
1119 }
1120
1121 /*
1122  * Skip over a hole in a symbolic link (should never happen).
1123  */
1124 /* ARGSUSED */
1125 static void
1126 xtrlnkskip(char *buf, long size)
1127 {
1128
1129         fprintf(stderr, "unallocated block in symbolic link %s\n",
1130                 curfile.name);
1131         done(1);
1132 }
1133
1134 /*
1135  * Collect the next block of a bit map.
1136  */
1137 static void
1138 xtrmap(char *buf, long size)
1139 {
1140
1141         memmove(map, buf, size);
1142         map += size;
1143 }
1144
1145 /*
1146  * Skip over a hole in a bit map (should never happen).
1147  */
1148 /* ARGSUSED */
1149 static void
1150 xtrmapskip(char *buf, long size)
1151 {
1152
1153         panic("hole in map\n");
1154         map += size;
1155 }
1156
1157 /*
1158  * Noop, when an extraction function is not needed.
1159  */
1160 /* ARGSUSED */
1161 void
1162 xtrnull(char *buf, long size)
1163 {
1164
1165         return;
1166 }
1167
1168 /*
1169  * Read TP_BSIZE blocks from the input.
1170  * Handle read errors, and end of media.
1171  */
1172 static void
1173 readtape(char *buf)
1174 {
1175         long rd, newvol, i, oldnumtrec;
1176         int cnt, seek_failed;
1177
1178         if (blkcnt + (byteslide > 0) < numtrec) {
1179                 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE);
1180                 blksread++;
1181                 tapeaddr++;
1182                 return;
1183         }
1184         if (numtrec > 0)
1185                 memmove(&tapebuf[-TP_BSIZE],
1186                     &tapebuf[(numtrec-1) * TP_BSIZE], (long)TP_BSIZE);
1187         oldnumtrec = numtrec;
1188         for (i = 0; i < ntrec; i++)
1189                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1190         if (numtrec == 0)
1191                 numtrec = ntrec;
1192         cnt = ntrec * TP_BSIZE;
1193         rd = 0;
1194 getmore:
1195 #ifdef RRESTORE
1196         if (host)
1197                 i = rmtread(&tapebuf[rd], cnt);
1198         else
1199 #endif
1200                 i = read(mt, &tapebuf[rd], cnt);
1201         /*
1202          * Check for mid-tape short read error.
1203          * If found, skip rest of buffer and start with the next.
1204          */
1205         if (!pipein && numtrec < ntrec && i > 0) {
1206                 dprintf(stdout, "mid-media short read error.\n");
1207                 numtrec = ntrec;
1208         }
1209         /*
1210          * Handle partial block read.
1211          */
1212         if (pipein && i == 0 && rd > 0)
1213                 i = rd;
1214         else if (i > 0 && i != ntrec * TP_BSIZE) {
1215                 if (pipein) {
1216                         rd += i;
1217                         cnt -= i;
1218                         if (cnt > 0)
1219                                 goto getmore;
1220                         i = rd;
1221                 } else {
1222                         /*
1223                          * Short read. Process the blocks read.
1224                          */
1225                         if (i % TP_BSIZE != 0)
1226                                 vprintf(stdout,
1227                                     "partial block read: %ld should be %ld\n",
1228                                     i, ntrec * TP_BSIZE);
1229                         numtrec = i / TP_BSIZE;
1230                 }
1231         }
1232         /*
1233          * Handle read error.
1234          */
1235         if (i < 0) {
1236                 fprintf(stderr, "Tape read error while ");
1237                 switch (curfile.action) {
1238                 default:
1239                         fprintf(stderr, "trying to set up tape\n");
1240                         break;
1241                 case UNKNOWN:
1242                         fprintf(stderr, "trying to resynchronize\n");
1243                         break;
1244                 case USING:
1245                         fprintf(stderr, "restoring %s\n", curfile.name);
1246                         break;
1247                 case SKIP:
1248                         fprintf(stderr, "skipping over inode %d\n",
1249                                 curfile.ino);
1250                         break;
1251                 }
1252                 if (!yflag && !reply("continue"))
1253                         done(1);
1254                 i = ntrec * TP_BSIZE;
1255                 memset(tapebuf, 0, i);
1256 #ifdef RRESTORE
1257                 if (host)
1258                         seek_failed = (rmtseek(i, 1) < 0);
1259                 else
1260 #endif
1261                         seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
1262
1263                 if (seek_failed) {
1264                         fprintf(stderr,
1265                             "continuation failed: %s\n", strerror(errno));
1266                         done(1);
1267                 }
1268         }
1269         /*
1270          * Handle end of tape.
1271          */
1272         if (i == 0) {
1273                 vprintf(stdout, "End-of-tape encountered\n");
1274                 if (!pipein) {
1275                         newvol = volno + 1;
1276                         volno = 0;
1277                         numtrec = 0;
1278                         getvol(newvol);
1279                         readtape(buf);
1280                         return;
1281                 }
1282                 if (rd % TP_BSIZE != 0)
1283                         panic("partial block read: %d should be %d\n",
1284                                 rd, ntrec * TP_BSIZE);
1285                 terminateinput();
1286                 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
1287         }
1288         if (oldnumtrec == 0)
1289                 blkcnt = 0;
1290         else
1291                 blkcnt -= oldnumtrec;
1292         memmove(buf,
1293             &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE);
1294         blksread++;
1295         tapeaddr++;
1296 }
1297
1298 static void
1299 findtapeblksize(void)
1300 {
1301         long i;
1302
1303         for (i = 0; i < ntrec; i++)
1304                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1305         blkcnt = 0;
1306 #ifdef RRESTORE
1307         if (host)
1308                 i = rmtread(tapebuf, ntrec * TP_BSIZE);
1309         else
1310 #endif
1311                 i = read(mt, tapebuf, ntrec * TP_BSIZE);
1312
1313         if (i <= 0) {
1314                 fprintf(stderr, "tape read error: %s\n", strerror(errno));
1315                 done(1);
1316         }
1317         if (i % TP_BSIZE != 0) {
1318                 fprintf(stderr, "Tape block size (%ld) %s (%d)\n",
1319                         i, "is not a multiple of dump block size", TP_BSIZE);
1320                 done(1);
1321         }
1322         ntrec = i / TP_BSIZE;
1323         numtrec = ntrec;
1324         vprintf(stdout, "Tape block size is %ld\n", ntrec);
1325 }
1326
1327 void
1328 closemt(void)
1329 {
1330
1331         if (mt < 0)
1332                 return;
1333         if (pipecmdin) {
1334                 pclose(popenfp);
1335                 popenfp = NULL;
1336         } else
1337 #ifdef RRESTORE
1338         if (host)
1339                 rmtclose();
1340         else
1341 #endif
1342                 (void) close(mt);
1343 }
1344
1345 /*
1346  * Read the next block from the tape.
1347  * If it is not any valid header, return an error.
1348  */
1349 static int
1350 gethead(struct s_spcl *buf)
1351 {
1352         long i;
1353
1354         readtape((char *)buf);
1355         if (buf->c_magic != FS_UFS2_MAGIC && buf->c_magic != NFS_MAGIC) {
1356                 if (buf->c_magic == OFS_MAGIC) {
1357                         fprintf(stderr,
1358                             "Format of dump tape is too old. Must use\n");
1359                         fprintf(stderr,
1360                             "a version of restore from before 2002.\n");
1361                         return (FAIL);
1362                 }
1363                 if (swabl(buf->c_magic) != FS_UFS2_MAGIC &&
1364                     buf->c_magic != NFS_MAGIC) {
1365                         if (buf->c_magic == OFS_MAGIC) {
1366                                 fprintf(stderr,
1367                                   "Format of dump tape is too old. Must use\n");
1368                                 fprintf(stderr,
1369                                   "a version of restore from before 2002.\n");
1370                         }
1371                         return (FAIL);
1372                 }
1373                 if (!Bcvt) {
1374                         vprintf(stdout, "Note: Doing Byte swapping\n");
1375                         Bcvt = 1;
1376                 }
1377         }
1378         if (checksum((int *)buf) == FAIL)
1379                 return (FAIL);
1380         if (_time64_to_time(buf->c_date) != dumpdate)
1381                 fprintf(stderr, "Header with wrong dumpdate.\n");
1382         if (Bcvt) {
1383                 swabst((u_char *)"8l4s1q8l2q17l", (u_char *)buf);
1384                 swabst((u_char *)"l",(u_char *) &buf->c_level);
1385                 swabst((u_char *)"2l4q",(u_char *) &buf->c_flags);
1386         }
1387         readmapflag = 0;
1388
1389         switch (buf->c_type) {
1390
1391         case TS_CLRI:
1392         case TS_BITS:
1393                 /*
1394                  * Have to patch up missing information in bit map headers
1395                  */
1396                 buf->c_inumber = 0;
1397                 buf->c_size = buf->c_count * TP_BSIZE;
1398                 if (buf->c_count > TP_NINDIR)
1399                         readmapflag = 1;
1400                 else 
1401                         for (i = 0; i < buf->c_count; i++)
1402                                 buf->c_addr[i]++;
1403                 break;
1404
1405         case TS_TAPE:
1406                 if (buf->c_magic == NFS_MAGIC) {
1407                         if ((buf->c_flags & NFS_DR_NEWINODEFMT) == 0)
1408                                 oldinofmt = 1;
1409                         buf->c_date = _time32_to_time(buf->c_old_date);
1410                         buf->c_ddate = _time32_to_time(buf->c_old_ddate);
1411                         buf->c_tapea = buf->c_old_tapea;
1412                         buf->c_firstrec = buf->c_old_firstrec;
1413                 }
1414         case TS_END:
1415                 buf->c_inumber = 0;
1416                 break;
1417
1418         case TS_INODE:
1419                 /*
1420                  * For old dump tapes, have to copy up old fields to
1421                  * new locations.
1422                  */
1423                 if (buf->c_magic == NFS_MAGIC) {
1424                         buf->c_tapea = buf->c_old_tapea;
1425                         buf->c_firstrec = buf->c_old_firstrec;
1426                         buf->c_date = _time32_to_time(buf->c_old_date);
1427                         buf->c_ddate = _time32_to_time(buf->c_old_ddate);
1428                         buf->c_atime = _time32_to_time(buf->c_old_atime);
1429                         buf->c_mtime = _time32_to_time(buf->c_old_mtime);
1430                 }
1431                 break;
1432
1433         case TS_ADDR:
1434                 break;
1435
1436         default:
1437                 panic("gethead: unknown inode type %d\n", buf->c_type);
1438                 break;
1439         }
1440         /*
1441          * If we're restoring a filesystem with the old (FreeBSD 1)
1442          * format inodes, copy the uid/gid to the new location
1443          */
1444         if (oldinofmt) {
1445                 buf->c_uid = buf->c_spare1[1];
1446                 buf->c_gid = buf->c_spare1[2];
1447         }
1448         buf->c_magic = FS_UFS2_MAGIC;
1449         tapeaddr = buf->c_tapea;
1450         if (dflag)
1451                 accthdr(buf);
1452         return(GOOD);
1453 }
1454
1455 /*
1456  * Check that a header is where it belongs and predict the next header
1457  */
1458 static void
1459 accthdr(struct s_spcl *header)
1460 {
1461         static ino_t previno = 0x7fffffff;
1462         static int prevtype;
1463         static long predict;
1464         long blks, i;
1465
1466         if (header->c_type == TS_TAPE) {
1467                 fprintf(stderr, "Volume header ");
1468                 if (header->c_firstrec)
1469                         fprintf(stderr, "begins with record %qd",
1470                                 header->c_firstrec);
1471                 fprintf(stderr, "\n");
1472                 previno = 0x7fffffff;
1473                 return;
1474         }
1475         if (previno == 0x7fffffff)
1476                 goto newcalc;
1477         switch (prevtype) {
1478         case TS_BITS:
1479                 fprintf(stderr, "Dumped inodes map header");
1480                 break;
1481         case TS_CLRI:
1482                 fprintf(stderr, "Used inodes map header");
1483                 break;
1484         case TS_INODE:
1485                 fprintf(stderr, "File header, ino %d", previno);
1486                 break;
1487         case TS_ADDR:
1488                 fprintf(stderr, "File continuation header, ino %d", previno);
1489                 break;
1490         case TS_END:
1491                 fprintf(stderr, "End of tape header");
1492                 break;
1493         }
1494         if (predict != blksread - 1)
1495                 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1496                         predict, blksread - 1);
1497         fprintf(stderr, "\n");
1498 newcalc:
1499         blks = 0;
1500         if (header->c_type != TS_END)
1501                 for (i = 0; i < header->c_count; i++)
1502                         if (readmapflag || header->c_addr[i] != 0)
1503                                 blks++;
1504         predict = blks;
1505         blksread = 0;
1506         prevtype = header->c_type;
1507         previno = header->c_inumber;
1508 }
1509
1510 /*
1511  * Find an inode header.
1512  * Complain if had to skip.
1513  */
1514 static void
1515 findinode(struct s_spcl *header)
1516 {
1517         static long skipcnt = 0;
1518         long i;
1519         char buf[TP_BSIZE];
1520         int htype;
1521
1522         curfile.name = "<name unknown>";
1523         curfile.action = UNKNOWN;
1524         curfile.mode = 0;
1525         curfile.ino = 0;
1526         do {
1527                 htype = header->c_type;
1528                 switch (htype) {
1529
1530                 case TS_ADDR:
1531                         /*
1532                          * Skip up to the beginning of the next record
1533                          */
1534                         for (i = 0; i < header->c_count; i++)
1535                                 if (header->c_addr[i])
1536                                         readtape(buf);
1537                         while (gethead(header) == FAIL ||
1538                             _time64_to_time(header->c_date) != dumpdate) {
1539                                 skipcnt++;
1540                                 if (Dflag) {
1541                                         byteslide++;
1542                                         if (byteslide < TP_BSIZE) {
1543                                                 blkcnt--;
1544                                                 blksread--;
1545                                         } else 
1546                                                 byteslide = 0;
1547                                 }
1548                         }
1549                         break;
1550
1551                 case TS_INODE:
1552                         curfile.mode = header->c_mode;
1553                         curfile.uid = header->c_uid;
1554                         curfile.gid = header->c_gid;
1555                         curfile.file_flags = header->c_file_flags;
1556                         curfile.rdev = header->c_rdev;
1557                         curfile.atime_sec = header->c_atime;
1558                         curfile.atime_nsec = header->c_atimensec;
1559                         curfile.mtime_sec = header->c_mtime;
1560                         curfile.mtime_nsec = header->c_mtimensec;
1561                         curfile.birthtime_sec = header->c_birthtime;
1562                         curfile.birthtime_nsec = header->c_birthtimensec;
1563                         curfile.extsize = header->c_extsize;
1564                         curfile.size = header->c_size;
1565                         curfile.ino = header->c_inumber;
1566                         break;
1567
1568                 case TS_END:
1569                         /* If we missed some tapes, get another volume. */
1570                         if (tapesread & (tapesread + 1)) {
1571                                 getvol(0);
1572                                 continue;
1573                         }
1574                         curfile.ino = maxino;
1575                         break;
1576
1577                 case TS_CLRI:
1578                         curfile.name = "<file removal list>";
1579                         break;
1580
1581                 case TS_BITS:
1582                         curfile.name = "<file dump list>";
1583                         break;
1584
1585                 case TS_TAPE:
1586                         if (Dflag)
1587                                 fprintf(stderr, "unexpected tape header\n");
1588                         else
1589                                 panic("unexpected tape header\n");
1590
1591                 default:
1592                         if (Dflag)
1593                                 fprintf(stderr, "unknown tape header type %d\n",
1594                                     spcl.c_type);
1595                         else
1596                                 panic("unknown tape header type %d\n",
1597                                     spcl.c_type);
1598                         while (gethead(header) == FAIL ||
1599                             _time64_to_time(header->c_date) != dumpdate) {
1600                                 skipcnt++;
1601                                 if (Dflag) {
1602                                         byteslide++;
1603                                         if (byteslide < TP_BSIZE) {
1604                                                 blkcnt--;
1605                                                 blksread--;
1606                                         } else 
1607                                                 byteslide = 0;
1608                                 }
1609                         }
1610
1611                 }
1612         } while (htype == TS_ADDR);
1613         if (skipcnt > 0)
1614                 fprintf(stderr, "resync restore, skipped %ld %s\n",
1615                     skipcnt, Dflag ? "bytes" : "blocks");
1616         skipcnt = 0;
1617 }
1618
1619 static int
1620 checksum(int *buf)
1621 {
1622         int i, j;
1623
1624         j = sizeof(union u_spcl) / sizeof(int);
1625         i = 0;
1626         if (!Bcvt) {
1627                 do
1628                         i += *buf++;
1629                 while (--j);
1630         } else {
1631                 /* What happens if we want to read restore tapes
1632                         for a 16bit int machine??? */
1633                 do
1634                         i += swabl(*buf++);
1635                 while (--j);
1636         }
1637
1638         if (i != CHECKSUM) {
1639                 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1640                         curfile.ino, curfile.name);
1641                 return(FAIL);
1642         }
1643         return(GOOD);
1644 }
1645
1646 #ifdef RRESTORE
1647 #include <stdarg.h>
1648
1649 void
1650 msg(const char *fmt, ...)
1651 {
1652         va_list ap;
1653         va_start(ap, fmt);
1654         (void)vfprintf(stderr, fmt, ap);
1655         va_end(ap);
1656 }
1657 #endif /* RRESTORE */
1658
1659 static u_char *
1660 swabshort(u_char *sp, int n)
1661 {
1662         char c;
1663
1664         while (--n >= 0) {
1665                 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1666                 sp += 2;
1667         }
1668         return (sp);
1669 }
1670
1671 static u_char *
1672 swablong(u_char *sp, int n)
1673 {
1674         char c;
1675
1676         while (--n >= 0) {
1677                 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1678                 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1679                 sp += 4;
1680         }
1681         return (sp);
1682 }
1683
1684 static u_char *
1685 swabquad(u_char *sp, int n)
1686 {
1687         char c;
1688
1689         while (--n >= 0) {
1690                 c = sp[0]; sp[0] = sp[7]; sp[7] = c;
1691                 c = sp[1]; sp[1] = sp[6]; sp[6] = c;
1692                 c = sp[2]; sp[2] = sp[5]; sp[5] = c;
1693                 c = sp[3]; sp[3] = sp[4]; sp[4] = c;
1694                 sp += 8;
1695         }
1696         return (sp);
1697 }
1698
1699 void
1700 swabst(u_char *cp, u_char *sp)
1701 {
1702         int n = 0;
1703
1704         while (*cp) {
1705                 switch (*cp) {
1706                 case '0': case '1': case '2': case '3': case '4':
1707                 case '5': case '6': case '7': case '8': case '9':
1708                         n = (n * 10) + (*cp++ - '0');
1709                         continue;
1710
1711                 case 's': case 'w': case 'h':
1712                         if (n == 0)
1713                                 n = 1;
1714                         sp = swabshort(sp, n);
1715                         break;
1716
1717                 case 'l':
1718                         if (n == 0)
1719                                 n = 1;
1720                         sp = swablong(sp, n);
1721                         break;
1722
1723                 case 'q':
1724                         if (n == 0)
1725                                 n = 1;
1726                         sp = swabquad(sp, n);
1727                         break;
1728
1729                 case 'b':
1730                         if (n == 0)
1731                                 n = 1;
1732                         sp += n;
1733                         break;
1734
1735                 default:
1736                         fprintf(stderr, "Unknown conversion character: %c\n",
1737                             *cp);
1738                         done(0);
1739                         break;
1740                 }
1741                 cp++;
1742                 n = 0;
1743         }
1744 }
1745
1746 static u_long
1747 swabl(u_long x)
1748 {
1749         swabst((u_char *)"l", (u_char *)&x);
1750         return (x);
1751 }