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