]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/restore/tape.c
This commit was generated by cvs2svn to compensate for changes in r132720,
[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 static const char rcsid[] =
40   "$FreeBSD$";
41 #endif /* not lint */
42
43 #include <sys/param.h>
44 #include <sys/file.h>
45 #include <sys/mtio.h>
46 #include <sys/stat.h>
47 #include <sys/time.h>
48
49 #include <ufs/ufs/dinode.h>
50 #include <protocols/dumprestore.h>
51
52 #include <errno.h>
53 #include <limits.h>
54 #include <paths.h>
55 #include <setjmp.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <time.h>
60 #include <timeconv.h>
61 #include <unistd.h>
62
63 #include "restore.h"
64 #include "extern.h"
65
66 static long     fssize = MAXBSIZE;
67 static int      mt = -1;
68 static int      pipein = 0;
69 static int      pipecmdin = 0;
70 static FILE     *popenfp = NULL;
71 static char     *magtape;
72 static int      blkcnt;
73 static int      numtrec;
74 static char     *tapebuf;
75 static union    u_spcl endoftapemark;
76 static long     blksread;               /* blocks read since last header */
77 static int64_t  tapeaddr = 0;           /* current TP_BSIZE tape record */
78 static long     tapesread;
79 static jmp_buf  restart;
80 static int      gettingfile = 0;        /* restart has a valid frame */
81 static char     *host = NULL;
82 static int      readmapflag;
83
84 static int      ofile;
85 static char     *map;
86 static char     lnkbuf[MAXPATHLEN + 1];
87 static int      pathlen;
88
89 int             Bcvt;           /* Swap Bytes */
90
91 #define FLUSHTAPEBUF()  blkcnt = ntrec + 1
92
93 static void      accthdr(struct s_spcl *);
94 static int       checksum(int *);
95 static void      findinode(struct s_spcl *);
96 static void      findtapeblksize(void);
97 static int       gethead(struct s_spcl *);
98 static void      readtape(char *);
99 static void      setdumpnum(void);
100 static u_long    swabl(u_long);
101 static u_char   *swablong(u_char *, int);
102 static u_char   *swabshort(u_char *, int);
103 static void      terminateinput(void);
104 static void      xtrfile(char *, long);
105 static void      xtrlnkfile(char *, long);
106 static void      xtrlnkskip(char *, long);
107 static void      xtrmap(char *, long);
108 static void      xtrmapskip(char *, long);
109 static void      xtrskip(char *, long);
110
111 /*
112  * Set up an input source
113  */
114 void
115 setinput(char *source, int ispipecommand)
116 {
117         FLUSHTAPEBUF();
118         if (bflag)
119                 newtapebuf(ntrec);
120         else
121                 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
122         terminal = stdin;
123
124         if (ispipecommand)
125                 pipecmdin++;
126         else
127 #ifdef RRESTORE
128         if (strchr(source, ':')) {
129                 host = source;
130                 source = strchr(host, ':');
131                 *source++ = '\0';
132                 if (rmthost(host) == 0)
133                         done(1);
134         } else
135 #endif
136         if (strcmp(source, "-") == 0) {
137                 /*
138                  * Since input is coming from a pipe we must establish
139                  * our own connection to the terminal.
140                  */
141                 terminal = fopen(_PATH_TTY, "r");
142                 if (terminal == NULL) {
143                         (void)fprintf(stderr, "cannot open %s: %s\n",
144                             _PATH_TTY, strerror(errno));
145                         terminal = fopen(_PATH_DEVNULL, "r");
146                         if (terminal == NULL) {
147                                 (void)fprintf(stderr, "cannot open %s: %s\n",
148                                     _PATH_DEVNULL, strerror(errno));
149                                 done(1);
150                         }
151                 }
152                 pipein++;
153         }
154         setuid(getuid());       /* no longer need or want root privileges */
155         magtape = strdup(source);
156         if (magtape == NULL) {
157                 fprintf(stderr, "Cannot allocate space for magtape buffer\n");
158                 done(1);
159         }
160 }
161
162 void
163 newtapebuf(long size)
164 {
165         static int tapebufsize = -1;
166
167         ntrec = size;
168         if (size <= tapebufsize)
169                 return;
170         if (tapebuf != NULL)
171                 free(tapebuf);
172         tapebuf = malloc(size * TP_BSIZE);
173         if (tapebuf == NULL) {
174                 fprintf(stderr, "Cannot allocate space for tape buffer\n");
175                 done(1);
176         }
177         tapebufsize = size;
178 }
179
180 /*
181  * Verify that the tape drive can be accessed and
182  * that it actually is a dump tape.
183  */
184 void
185 setup(void)
186 {
187         int i, j, *ip;
188         struct stat stbuf;
189
190         vprintf(stdout, "Verify tape and initialize maps\n");
191         if (pipecmdin) {
192                 if (setenv("RESTORE_VOLUME", "1", 1) == -1) {
193                         fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n",
194                             strerror(errno));
195                         done(1);
196                 }
197                 popenfp = popen(magtape, "r");
198                 mt = popenfp ? fileno(popenfp) : -1;
199         } else
200 #ifdef RRESTORE
201         if (host)
202                 mt = rmtopen(magtape, 0);
203         else
204 #endif
205         if (pipein)
206                 mt = 0;
207         else
208                 mt = open(magtape, O_RDONLY, 0);
209         if (mt < 0) {
210                 fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
211                 done(1);
212         }
213         volno = 1;
214         setdumpnum();
215         FLUSHTAPEBUF();
216         if (!pipein && !bflag)
217                 findtapeblksize();
218         if (gethead(&spcl) == FAIL) {
219                 fprintf(stderr, "Tape is not a dump tape\n");
220                 done(1);
221         }
222         if (pipein) {
223                 endoftapemark.s_spcl.c_magic = FS_UFS2_MAGIC;
224                 endoftapemark.s_spcl.c_type = TS_END;
225                 ip = (int *)&endoftapemark;
226                 j = sizeof(union u_spcl) / sizeof(int);
227                 i = 0;
228                 do
229                         i += *ip++;
230                 while (--j);
231                 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
232         }
233         if (vflag || command == 't')
234                 printdumpinfo();
235         dumptime = _time64_to_time(spcl.c_ddate);
236         dumpdate = _time64_to_time(spcl.c_date);
237         if (stat(".", &stbuf) < 0) {
238                 fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
239                 done(1);
240         }
241         if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
242                 fssize = TP_BSIZE;
243         if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
244                 fssize = stbuf.st_blksize;
245         if (((fssize - 1) & fssize) != 0) {
246                 fprintf(stderr, "bad block size %ld\n", fssize);
247                 done(1);
248         }
249         if (spcl.c_volume != 1) {
250                 fprintf(stderr, "Tape is not volume 1 of the dump\n");
251                 done(1);
252         }
253         if (gethead(&spcl) == FAIL) {
254                 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
255                 panic("no header after volume mark!\n");
256         }
257         findinode(&spcl);
258         if (spcl.c_type != TS_CLRI) {
259                 fprintf(stderr, "Cannot find file removal list\n");
260                 done(1);
261         }
262         maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
263         dprintf(stdout, "maxino = %d\n", maxino);
264         map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
265         if (map == NULL)
266                 panic("no memory for active inode map\n");
267         usedinomap = map;
268         curfile.action = USING;
269         getfile(xtrmap, xtrmapskip);
270         if (spcl.c_type != TS_BITS) {
271                 fprintf(stderr, "Cannot find file dump list\n");
272                 done(1);
273         }
274         map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
275         if (map == (char *)NULL)
276                 panic("no memory for file dump list\n");
277         dumpmap = map;
278         curfile.action = USING;
279         getfile(xtrmap, xtrmapskip);
280         /*
281          * If there may be whiteout entries on the tape, pretend that the
282          * whiteout inode exists, so that the whiteout entries can be
283          * extracted.
284          */
285         SETINO(WINO, dumpmap);
286         /* 'r' restores don't call getvol() for tape 1, so mark it as read. */
287         if (command == 'r')
288                 tapesread = 1;
289 }
290
291 /*
292  * Prompt user to load a new dump volume.
293  * "Nextvol" is the next suggested volume to use.
294  * This suggested volume is enforced when doing full
295  * or incremental restores, but can be overridden by
296  * the user when only extracting a subset of the files.
297  */
298 void
299 getvol(long nextvol)
300 {
301         int64_t prevtapea;
302         long i, newvol, savecnt;
303         union u_spcl tmpspcl;
304 #       define tmpbuf tmpspcl.s_spcl
305         char buf[TP_BSIZE];
306
307         if (nextvol == 1) {
308                 tapesread = 0;
309                 gettingfile = 0;
310         }
311         prevtapea = tapeaddr;
312         savecnt = blksread;
313         if (pipein) {
314                 if (nextvol != 1) {
315                         panic("Changing volumes on pipe input?\n");
316                         /* Avoid looping if we couldn't ask the user. */
317                         if (yflag || ferror(terminal) || feof(terminal))
318                                 done(1);
319                 }
320                 if (volno == 1)
321                         return;
322                 if (pipecmdin) {
323                         closemt();
324                         goto getpipecmdhdr;
325                 }
326                 goto gethdr;
327         }
328 again:
329         if (pipein)
330                 done(1); /* pipes do not get a second chance */
331         if (command == 'R' || command == 'r' || curfile.action != SKIP)
332                 newvol = nextvol;
333         else
334                 newvol = 0;
335         while (newvol <= 0) {
336                 if (tapesread == 0) {
337                         fprintf(stderr, "%s%s%s%s%s%s%s",
338                             "You have not read any tapes yet.\n",
339                             "If you are extracting just a few files,",
340                             " start with the last volume\n",
341                             "and work towards the first; restore",
342                             " can quickly skip tapes that\n",
343                             "have no further files to extract.",
344                             " Otherwise, begin with volume 1.\n");
345                 } else {
346                         fprintf(stderr, "You have read volumes");
347                         strcpy(buf, ": ");
348                         for (i = 0; i < 32; i++)
349                                 if (tapesread & (1 << i)) {
350                                         fprintf(stderr, "%s%ld", buf, i + 1);
351                                         strcpy(buf, ", ");
352                                 }
353                         fprintf(stderr, "\n");
354                 }
355                 do      {
356                         fprintf(stderr, "Specify next volume #: ");
357                         (void) fflush(stderr);
358                         if (fgets(buf, BUFSIZ, terminal) == NULL)
359                                 done(1);
360                 } while (buf[0] == '\n');
361                 newvol = atoi(buf);
362                 if (newvol <= 0) {
363                         fprintf(stderr,
364                             "Volume numbers are positive numerics\n");
365                 }
366         }
367         if (newvol == volno) {
368                 tapesread |= 1 << (volno - 1);
369                 return;
370         }
371         closemt();
372         fprintf(stderr, "Mount tape volume %ld\n", newvol);
373         fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
374         fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
375         (void) fflush(stderr);
376         if (fgets(buf, BUFSIZ, terminal) == NULL)
377                 done(1);
378         if (!strcmp(buf, "none\n")) {
379                 terminateinput();
380                 return;
381         }
382         if (buf[0] != '\n') {
383                 (void) strcpy(magtape, buf);
384                 magtape[strlen(magtape) - 1] = '\0';
385         }
386         if (pipecmdin) {
387                 char volno[sizeof("2147483647")];
388
389 getpipecmdhdr:
390                 (void)sprintf(volno, "%d", newvol);
391                 if (setenv("RESTORE_VOLUME", volno, 1) == -1) {
392                         fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n",
393                             strerror(errno));
394                         done(1);
395                 }
396                 popenfp = popen(magtape, "r");
397                 mt = popenfp ? fileno(popenfp) : -1;
398         } else
399 #ifdef RRESTORE
400         if (host)
401                 mt = rmtopen(magtape, 0);
402         else
403 #endif
404                 mt = open(magtape, O_RDONLY, 0);
405
406         if (mt == -1) {
407                 fprintf(stderr, "Cannot open %s\n", magtape);
408                 volno = -1;
409                 goto again;
410         }
411 gethdr:
412         volno = newvol;
413         setdumpnum();
414         FLUSHTAPEBUF();
415         if (gethead(&tmpbuf) == FAIL) {
416                 dprintf(stdout, "header read failed at %ld blocks\n", blksread);
417                 fprintf(stderr, "tape is not dump tape\n");
418                 volno = 0;
419                 goto again;
420         }
421         if (tmpbuf.c_volume != volno) {
422                 fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume);
423                 volno = 0;
424                 goto again;
425         }
426         if (_time64_to_time(tmpbuf.c_date) != dumpdate ||
427             _time64_to_time(tmpbuf.c_ddate) != dumptime) {
428                 time_t t = _time64_to_time(tmpbuf.c_date);
429                 fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t));
430                 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
431                 volno = 0;
432                 goto again;
433         }
434         tapesread |= 1 << (volno - 1);
435         blksread = savecnt;
436         /*
437          * If continuing from the previous volume, skip over any
438          * blocks read already at the end of the previous volume.
439          *
440          * If coming to this volume at random, skip to the beginning
441          * of the next record.
442          */
443         dprintf(stdout, "last rec %qd, tape starts with %qd\n", prevtapea,
444             tmpbuf.c_tapea);
445         if (tmpbuf.c_type == TS_TAPE) {
446                 if (curfile.action != USING) {
447                         /*
448                          * XXX Dump incorrectly sets c_count to 1 in the
449                          * volume header of the first tape, so ignore
450                          * c_count when volno == 1.
451                          */
452                         if (volno != 1)
453                                 for (i = tmpbuf.c_count; i > 0; i--)
454                                         readtape(buf);
455                 } else if (tmpbuf.c_tapea <= prevtapea) {
456                         /*
457                          * Normally the value of c_tapea in the volume
458                          * header is the record number of the header itself.
459                          * However in the volume header following an EOT-
460                          * terminated tape, it is the record number of the
461                          * first continuation data block (dump bug?).
462                          *
463                          * The next record we want is `prevtapea + 1'.
464                          */
465                         i = prevtapea + 1 - tmpbuf.c_tapea;
466                         dprintf(stderr, "Skipping %ld duplicate record%s.\n",
467                                 i, i > 1 ? "s" : "");
468                         while (--i >= 0)
469                                 readtape(buf);
470                 }
471         }
472         if (curfile.action == USING) {
473                 if (volno == 1)
474                         panic("active file into volume 1\n");
475                 return;
476         }
477         (void) gethead(&spcl);
478         findinode(&spcl);
479         if (gettingfile) {
480                 gettingfile = 0;
481                 longjmp(restart, 1);
482         }
483 }
484
485 /*
486  * Handle unexpected EOF.
487  */
488 static void
489 terminateinput(void)
490 {
491
492         if (gettingfile && curfile.action == USING) {
493                 printf("Warning: %s %s\n",
494                     "End-of-input encountered while extracting", curfile.name);
495         }
496         curfile.name = "<name unknown>";
497         curfile.action = UNKNOWN;
498         curfile.mode = 0;
499         curfile.ino = maxino;
500         if (gettingfile) {
501                 gettingfile = 0;
502                 longjmp(restart, 1);
503         }
504 }
505
506 /*
507  * handle multiple dumps per tape by skipping forward to the
508  * appropriate one.
509  */
510 static void
511 setdumpnum(void)
512 {
513         struct mtop tcom;
514
515         if (dumpnum == 1 || volno != 1)
516                 return;
517         if (pipein) {
518                 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
519                 done(1);
520         }
521         tcom.mt_op = MTFSF;
522         tcom.mt_count = dumpnum - 1;
523 #ifdef RRESTORE
524         if (host)
525                 rmtioctl(MTFSF, dumpnum - 1);
526         else
527 #endif
528                 if (!pipecmdin && ioctl(mt, MTIOCTOP, (char *)&tcom) < 0)
529                         fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
530 }
531
532 void
533 printdumpinfo(void)
534 {
535         time_t t;
536         t = _time64_to_time(spcl.c_date);
537         fprintf(stdout, "Dump   date: %s", ctime(&t));
538         t = _time64_to_time(spcl.c_ddate);
539         fprintf(stdout, "Dumped from: %s",
540             (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t));
541         if (spcl.c_host[0] == '\0')
542                 return;
543         fprintf(stderr, "Level %ld dump of %s on %s:%s\n",
544                 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
545         fprintf(stderr, "Label: %s\n", spcl.c_label);
546 }
547
548 int
549 extractfile(char *name)
550 {
551         int flags;
552         mode_t mode;
553         struct timeval mtimep[2], ctimep[2];
554         struct entry *ep;
555
556         curfile.name = name;
557         curfile.action = USING;
558         mtimep[0].tv_sec = curfile.atime_sec;
559         mtimep[0].tv_usec = curfile.atime_nsec / 1000;
560         mtimep[1].tv_sec = curfile.mtime_sec;
561         mtimep[1].tv_usec = curfile.mtime_nsec / 1000;
562         ctimep[0].tv_sec = curfile.atime_sec;
563         ctimep[0].tv_usec = curfile.atime_nsec / 1000;
564         ctimep[1].tv_sec = curfile.birthtime_sec;
565         ctimep[1].tv_usec = curfile.birthtime_nsec / 1000;
566         mode = curfile.mode;
567         flags = curfile.file_flags;
568         switch (mode & IFMT) {
569
570         default:
571                 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
572                 skipfile();
573                 return (FAIL);
574
575         case IFSOCK:
576                 vprintf(stdout, "skipped socket %s\n", name);
577                 skipfile();
578                 return (GOOD);
579
580         case IFDIR:
581                 if (mflag) {
582                         ep = lookupname(name);
583                         if (ep == NULL || ep->e_flags & EXTRACT)
584                                 panic("unextracted directory %s\n", name);
585                         skipfile();
586                         return (GOOD);
587                 }
588                 vprintf(stdout, "extract file %s\n", name);
589                 return (genliteraldir(name, curfile.ino));
590
591         case IFLNK:
592                 lnkbuf[0] = '\0';
593                 pathlen = 0;
594                 getfile(xtrlnkfile, xtrlnkskip);
595                 if (pathlen == 0) {
596                         vprintf(stdout,
597                             "%s: zero length symbolic link (ignored)\n", name);
598                         return (GOOD);
599                 }
600                 if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
601                         (void) lchown(name, curfile.uid, curfile.gid);
602                         (void) lchmod(name, mode);
603                         (void) lutimes(name, ctimep);
604                         (void) lutimes(name, mtimep);
605                         return (GOOD);
606                 }
607                 return (FAIL);
608
609         case IFIFO:
610                 vprintf(stdout, "extract fifo %s\n", name);
611                 if (Nflag) {
612                         skipfile();
613                         return (GOOD);
614                 }
615                 if (uflag && !Nflag)
616                         (void)unlink(name);
617                 if (mkfifo(name, mode) < 0) {
618                         fprintf(stderr, "%s: cannot create fifo: %s\n",
619                             name, strerror(errno));
620                         skipfile();
621                         return (FAIL);
622                 }
623                 (void) chown(name, curfile.uid, curfile.gid);
624                 (void) chmod(name, mode);
625                 (void) utimes(name, ctimep);
626                 (void) utimes(name, mtimep);
627                 (void) chflags(name, flags);
628                 skipfile();
629                 return (GOOD);
630
631         case IFCHR:
632         case IFBLK:
633                 vprintf(stdout, "extract special file %s\n", name);
634                 if (Nflag) {
635                         skipfile();
636                         return (GOOD);
637                 }
638                 if (uflag)
639                         (void)unlink(name);
640                 if (mknod(name, mode, (int)curfile.rdev) < 0) {
641                         fprintf(stderr, "%s: cannot create special file: %s\n",
642                             name, strerror(errno));
643                         skipfile();
644                         return (FAIL);
645                 }
646                 (void) chown(name, curfile.uid, curfile.gid);
647                 (void) chmod(name, mode);
648                 (void) utimes(name, ctimep);
649                 (void) utimes(name, mtimep);
650                 (void) chflags(name, flags);
651                 skipfile();
652                 return (GOOD);
653
654         case IFREG:
655                 vprintf(stdout, "extract file %s\n", name);
656                 if (Nflag) {
657                         skipfile();
658                         return (GOOD);
659                 }
660                 if (uflag)
661                         (void)unlink(name);
662                 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
663                     0666)) < 0) {
664                         fprintf(stderr, "%s: cannot create file: %s\n",
665                             name, strerror(errno));
666                         skipfile();
667                         return (FAIL);
668                 }
669                 (void) fchown(ofile, curfile.uid, curfile.gid);
670                 (void) fchmod(ofile, mode);
671                 getfile(xtrfile, xtrskip);
672                 (void) close(ofile);
673                 (void) utimes(name, ctimep);
674                 (void) utimes(name, mtimep);
675                 (void) chflags(name, flags);
676                 return (GOOD);
677         }
678         /* NOTREACHED */
679 }
680
681 /*
682  * skip over bit maps on the tape
683  */
684 void
685 skipmaps(void)
686 {
687
688         while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
689                 skipfile();
690 }
691
692 /*
693  * skip over a file on the tape
694  */
695 void
696 skipfile(void)
697 {
698
699         curfile.action = SKIP;
700         getfile(xtrnull, xtrnull);
701 }
702
703 /*
704  * Extract a file from the tape.
705  * When an allocated block is found it is passed to the fill function;
706  * when an unallocated block (hole) is found, a zeroed buffer is passed
707  * to the skip function.
708  */
709 void
710 getfile(void (*fill)(char *, long), void (*skip)(char *, long))
711 {
712         int i;
713         int curblk = 0;
714         quad_t size = spcl.c_size;
715         static char clearedbuf[MAXBSIZE];
716         char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
717         char junk[TP_BSIZE];
718
719         if (spcl.c_type == TS_END)
720                 panic("ran off end of tape\n");
721         if (spcl.c_magic != FS_UFS2_MAGIC)
722                 panic("not at beginning of a file\n");
723         if (!gettingfile && setjmp(restart) != 0)
724                 return;
725         gettingfile++;
726 loop:
727         for (i = 0; i < spcl.c_count; i++) {
728                 if (readmapflag || spcl.c_addr[i]) {
729                         readtape(&buf[curblk++][0]);
730                         if (curblk == fssize / TP_BSIZE) {
731                                 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
732                                      fssize : (curblk - 1) * TP_BSIZE + size));
733                                 curblk = 0;
734                         }
735                 } else {
736                         if (curblk > 0) {
737                                 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
738                                      curblk * TP_BSIZE :
739                                      (curblk - 1) * TP_BSIZE + size));
740                                 curblk = 0;
741                         }
742                         (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
743                                 TP_BSIZE : size));
744                 }
745                 if ((size -= TP_BSIZE) <= 0) {
746                         for (i++; i < spcl.c_count; i++)
747                                 if (readmapflag || spcl.c_addr[i])
748                                         readtape(junk);
749                         break;
750                 }
751         }
752         if (gethead(&spcl) == GOOD && size > 0) {
753                 if (spcl.c_type == TS_ADDR)
754                         goto loop;
755                 dprintf(stdout,
756                         "Missing address (header) block for %s at %ld blocks\n",
757                         curfile.name, blksread);
758         }
759         if (curblk > 0)
760                 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
761         findinode(&spcl);
762         gettingfile = 0;
763 }
764
765 /*
766  * Write out the next block of a file.
767  */
768 static void
769 xtrfile(char *buf, long size)
770 {
771
772         if (Nflag)
773                 return;
774         if (write(ofile, buf, (int) size) == -1) {
775                 fprintf(stderr,
776                     "write error extracting inode %d, name %s\nwrite: %s\n",
777                         curfile.ino, curfile.name, strerror(errno));
778         }
779 }
780
781 /*
782  * Skip over a hole in a file.
783  */
784 /* ARGSUSED */
785 static void
786 xtrskip(char *buf, long size)
787 {
788
789         if (lseek(ofile, size, SEEK_CUR) == -1) {
790                 fprintf(stderr,
791                     "seek error extracting inode %d, name %s\nlseek: %s\n",
792                         curfile.ino, curfile.name, strerror(errno));
793                 done(1);
794         }
795 }
796
797 /*
798  * Collect the next block of a symbolic link.
799  */
800 static void
801 xtrlnkfile(char *buf, long size)
802 {
803
804         pathlen += size;
805         if (pathlen > MAXPATHLEN) {
806                 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
807                     curfile.name, lnkbuf, buf, pathlen);
808                 done(1);
809         }
810         (void) strcat(lnkbuf, buf);
811 }
812
813 /*
814  * Skip over a hole in a symbolic link (should never happen).
815  */
816 /* ARGSUSED */
817 static void
818 xtrlnkskip(char *buf, long size)
819 {
820
821         fprintf(stderr, "unallocated block in symbolic link %s\n",
822                 curfile.name);
823         done(1);
824 }
825
826 /*
827  * Collect the next block of a bit map.
828  */
829 static void
830 xtrmap(char *buf, long size)
831 {
832
833         memmove(map, buf, size);
834         map += size;
835 }
836
837 /*
838  * Skip over a hole in a bit map (should never happen).
839  */
840 /* ARGSUSED */
841 static void
842 xtrmapskip(char *buf, long size)
843 {
844
845         panic("hole in map\n");
846         map += size;
847 }
848
849 /*
850  * Noop, when an extraction function is not needed.
851  */
852 /* ARGSUSED */
853 void
854 xtrnull(char *buf, long size)
855 {
856
857         return;
858 }
859
860 /*
861  * Read TP_BSIZE blocks from the input.
862  * Handle read errors, and end of media.
863  */
864 static void
865 readtape(char *buf)
866 {
867         long rd, newvol, i;
868         int cnt, seek_failed;
869
870         if (blkcnt < numtrec) {
871                 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
872                 blksread++;
873                 tapeaddr++;
874                 return;
875         }
876         for (i = 0; i < ntrec; i++)
877                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
878         if (numtrec == 0)
879                 numtrec = ntrec;
880         cnt = ntrec * TP_BSIZE;
881         rd = 0;
882 getmore:
883 #ifdef RRESTORE
884         if (host)
885                 i = rmtread(&tapebuf[rd], cnt);
886         else
887 #endif
888                 i = read(mt, &tapebuf[rd], cnt);
889         /*
890          * Check for mid-tape short read error.
891          * If found, skip rest of buffer and start with the next.
892          */
893         if (!pipein && numtrec < ntrec && i > 0) {
894                 dprintf(stdout, "mid-media short read error.\n");
895                 numtrec = ntrec;
896         }
897         /*
898          * Handle partial block read.
899          */
900         if (pipein && i == 0 && rd > 0)
901                 i = rd;
902         else if (i > 0 && i != ntrec * TP_BSIZE) {
903                 if (pipein) {
904                         rd += i;
905                         cnt -= i;
906                         if (cnt > 0)
907                                 goto getmore;
908                         i = rd;
909                 } else {
910                         /*
911                          * Short read. Process the blocks read.
912                          */
913                         if (i % TP_BSIZE != 0)
914                                 vprintf(stdout,
915                                     "partial block read: %ld should be %ld\n",
916                                     i, ntrec * TP_BSIZE);
917                         numtrec = i / TP_BSIZE;
918                 }
919         }
920         /*
921          * Handle read error.
922          */
923         if (i < 0) {
924                 fprintf(stderr, "Tape read error while ");
925                 switch (curfile.action) {
926                 default:
927                         fprintf(stderr, "trying to set up tape\n");
928                         break;
929                 case UNKNOWN:
930                         fprintf(stderr, "trying to resynchronize\n");
931                         break;
932                 case USING:
933                         fprintf(stderr, "restoring %s\n", curfile.name);
934                         break;
935                 case SKIP:
936                         fprintf(stderr, "skipping over inode %d\n",
937                                 curfile.ino);
938                         break;
939                 }
940                 if (!yflag && !reply("continue"))
941                         done(1);
942                 i = ntrec * TP_BSIZE;
943                 memset(tapebuf, 0, i);
944 #ifdef RRESTORE
945                 if (host)
946                         seek_failed = (rmtseek(i, 1) < 0);
947                 else
948 #endif
949                         seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
950
951                 if (seek_failed) {
952                         fprintf(stderr,
953                             "continuation failed: %s\n", strerror(errno));
954                         done(1);
955                 }
956         }
957         /*
958          * Handle end of tape.
959          */
960         if (i == 0) {
961                 vprintf(stdout, "End-of-tape encountered\n");
962                 if (!pipein) {
963                         newvol = volno + 1;
964                         volno = 0;
965                         numtrec = 0;
966                         getvol(newvol);
967                         readtape(buf);
968                         return;
969                 }
970                 if (rd % TP_BSIZE != 0)
971                         panic("partial block read: %d should be %d\n",
972                                 rd, ntrec * TP_BSIZE);
973                 terminateinput();
974                 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
975         }
976         blkcnt = 0;
977         memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
978         blksread++;
979         tapeaddr++;
980 }
981
982 static void
983 findtapeblksize(void)
984 {
985         long i;
986
987         for (i = 0; i < ntrec; i++)
988                 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
989         blkcnt = 0;
990 #ifdef RRESTORE
991         if (host)
992                 i = rmtread(tapebuf, ntrec * TP_BSIZE);
993         else
994 #endif
995                 i = read(mt, tapebuf, ntrec * TP_BSIZE);
996
997         if (i <= 0) {
998                 fprintf(stderr, "tape read error: %s\n", strerror(errno));
999                 done(1);
1000         }
1001         if (i % TP_BSIZE != 0) {
1002                 fprintf(stderr, "Tape block size (%ld) %s (%d)\n",
1003                         i, "is not a multiple of dump block size", TP_BSIZE);
1004                 done(1);
1005         }
1006         ntrec = i / TP_BSIZE;
1007         numtrec = ntrec;
1008         vprintf(stdout, "Tape block size is %ld\n", ntrec);
1009 }
1010
1011 void
1012 closemt(void)
1013 {
1014
1015         if (mt < 0)
1016                 return;
1017         if (pipecmdin) {
1018                 pclose(popenfp);
1019                 popenfp = NULL;
1020         } else
1021 #ifdef RRESTORE
1022         if (host)
1023                 rmtclose();
1024         else
1025 #endif
1026                 (void) close(mt);
1027 }
1028
1029 /*
1030  * Read the next block from the tape.
1031  * If it is not any valid header, return an error.
1032  */
1033 static int
1034 gethead(struct s_spcl *buf)
1035 {
1036         long i;
1037
1038         readtape((char *)buf);
1039         if (buf->c_magic != FS_UFS2_MAGIC && buf->c_magic != NFS_MAGIC) {
1040                 if (buf->c_magic == OFS_MAGIC) {
1041                         fprintf(stderr,
1042                             "Format of dump tape is too old. Must use\n");
1043                         fprintf(stderr,
1044                             "a version of restore from before 2002.\n");
1045                         return (FAIL);
1046                 }
1047                 if (swabl(buf->c_magic) != FS_UFS2_MAGIC &&
1048                     buf->c_magic != NFS_MAGIC) {
1049                         if (buf->c_magic == OFS_MAGIC) {
1050                                 fprintf(stderr,
1051                                   "Format of dump tape is too old. Must use\n");
1052                                 fprintf(stderr,
1053                                   "a version of restore from before 2002.\n");
1054                         }
1055                         return (FAIL);
1056                 }
1057                 if (!Bcvt) {
1058                         vprintf(stdout, "Note: Doing Byte swapping\n");
1059                         Bcvt = 1;
1060                 }
1061         }
1062         if (checksum((int *)buf) == FAIL)
1063                 return (FAIL);
1064         if (Bcvt) {
1065                 swabst((u_char *)"8l4s1q8l2q17l", (u_char *)buf);
1066                 swabst((u_char *)"l",(u_char *) &buf->c_level);
1067                 swabst((u_char *)"2l4q",(u_char *) &buf->c_flags);
1068         }
1069         readmapflag = 0;
1070
1071         switch (buf->c_type) {
1072
1073         case TS_CLRI:
1074         case TS_BITS:
1075                 /*
1076                  * Have to patch up missing information in bit map headers
1077                  */
1078                 buf->c_inumber = 0;
1079                 buf->c_size = buf->c_count * TP_BSIZE;
1080                 if (buf->c_count > TP_NINDIR)
1081                         readmapflag = 1;
1082                 else 
1083                         for (i = 0; i < buf->c_count; i++)
1084                                 buf->c_addr[i]++;
1085                 break;
1086
1087         case TS_TAPE:
1088         case TS_END:
1089                 buf->c_inumber = 0;
1090                 break;
1091
1092         case TS_INODE:
1093                 /*
1094                  * For old dump tapes, have to copy up old fields to
1095                  * new locations.
1096                  */
1097                 if (buf->c_magic == NFS_MAGIC) {
1098                         buf->c_tapea = buf->c_old_tapea;
1099                         buf->c_firstrec = buf->c_old_firstrec;
1100                         buf->c_date = _time32_to_time(buf->c_old_date);
1101                         buf->c_ddate = _time32_to_time(buf->c_old_ddate);
1102                         buf->c_atime = _time32_to_time(buf->c_old_atime);
1103                         buf->c_mtime = _time32_to_time(buf->c_old_mtime);
1104                 }
1105                 break;
1106
1107         case TS_ADDR:
1108                 break;
1109
1110         default:
1111                 panic("gethead: unknown inode type %d\n", buf->c_type);
1112                 break;
1113         }
1114         buf->c_magic = FS_UFS2_MAGIC;
1115         tapeaddr = buf->c_tapea;
1116         if (dflag)
1117                 accthdr(buf);
1118         return(GOOD);
1119 }
1120
1121 /*
1122  * Check that a header is where it belongs and predict the next header
1123  */
1124 static void
1125 accthdr(struct s_spcl *header)
1126 {
1127         static ino_t previno = 0x7fffffff;
1128         static int prevtype;
1129         static long predict;
1130         long blks, i;
1131
1132         if (header->c_type == TS_TAPE) {
1133                 fprintf(stderr, "Volume header ");
1134                 if (header->c_firstrec)
1135                         fprintf(stderr, "begins with record %qd",
1136                                 header->c_firstrec);
1137                 fprintf(stderr, "\n");
1138                 previno = 0x7fffffff;
1139                 return;
1140         }
1141         if (previno == 0x7fffffff)
1142                 goto newcalc;
1143         switch (prevtype) {
1144         case TS_BITS:
1145                 fprintf(stderr, "Dumped inodes map header");
1146                 break;
1147         case TS_CLRI:
1148                 fprintf(stderr, "Used inodes map header");
1149                 break;
1150         case TS_INODE:
1151                 fprintf(stderr, "File header, ino %d", previno);
1152                 break;
1153         case TS_ADDR:
1154                 fprintf(stderr, "File continuation header, ino %d", previno);
1155                 break;
1156         case TS_END:
1157                 fprintf(stderr, "End of tape header");
1158                 break;
1159         }
1160         if (predict != blksread - 1)
1161                 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1162                         predict, blksread - 1);
1163         fprintf(stderr, "\n");
1164 newcalc:
1165         blks = 0;
1166         if (header->c_type != TS_END)
1167                 for (i = 0; i < header->c_count; i++)
1168                         if (readmapflag || header->c_addr[i] != 0)
1169                                 blks++;
1170         predict = blks;
1171         blksread = 0;
1172         prevtype = header->c_type;
1173         previno = header->c_inumber;
1174 }
1175
1176 /*
1177  * Find an inode header.
1178  * Complain if had to skip.
1179  */
1180 static void
1181 findinode(struct s_spcl *header)
1182 {
1183         static long skipcnt = 0;
1184         long i;
1185         char buf[TP_BSIZE];
1186         int htype;
1187
1188         curfile.name = "<name unknown>";
1189         curfile.action = UNKNOWN;
1190         curfile.mode = 0;
1191         curfile.ino = 0;
1192         do {
1193                 htype = header->c_type;
1194                 switch (htype) {
1195
1196                 case TS_ADDR:
1197                         /*
1198                          * Skip up to the beginning of the next record
1199                          */
1200                         for (i = 0; i < header->c_count; i++)
1201                                 if (header->c_addr[i])
1202                                         readtape(buf);
1203                         while (gethead(header) == FAIL ||
1204                             _time64_to_time(header->c_date) != dumpdate)
1205                                 skipcnt++;
1206                         break;
1207
1208                 case TS_INODE:
1209                         curfile.mode = header->c_mode;
1210                         curfile.uid = header->c_uid;
1211                         curfile.gid = header->c_gid;
1212                         curfile.file_flags = header->c_file_flags;
1213                         curfile.rdev = header->c_rdev;
1214                         curfile.atime_sec = header->c_atime;
1215                         curfile.atime_nsec = header->c_atimensec;
1216                         curfile.mtime_sec = header->c_mtime;
1217                         curfile.mtime_nsec = header->c_mtimensec;
1218                         curfile.birthtime_sec = header->c_birthtime;
1219                         curfile.birthtime_nsec = header->c_birthtimensec;
1220                         curfile.size = header->c_size;
1221                         curfile.ino = header->c_inumber;
1222                         break;
1223
1224                 case TS_END:
1225                         /* If we missed some tapes, get another volume. */
1226                         if (tapesread & (tapesread + 1)) {
1227                                 getvol(0);
1228                                 continue;
1229                         }
1230                         curfile.ino = maxino;
1231                         break;
1232
1233                 case TS_CLRI:
1234                         curfile.name = "<file removal list>";
1235                         break;
1236
1237                 case TS_BITS:
1238                         curfile.name = "<file dump list>";
1239                         break;
1240
1241                 case TS_TAPE:
1242                         panic("unexpected tape header\n");
1243                         /* NOTREACHED */
1244
1245                 default:
1246                         panic("unknown tape header type %d\n", spcl.c_type);
1247                         /* NOTREACHED */
1248
1249                 }
1250         } while (htype == TS_ADDR);
1251         if (skipcnt > 0)
1252                 fprintf(stderr, "resync restore, skipped %ld blocks\n",
1253                     skipcnt);
1254         skipcnt = 0;
1255 }
1256
1257 static int
1258 checksum(int *buf)
1259 {
1260         int i, j;
1261
1262         j = sizeof(union u_spcl) / sizeof(int);
1263         i = 0;
1264         if (!Bcvt) {
1265                 do
1266                         i += *buf++;
1267                 while (--j);
1268         } else {
1269                 /* What happens if we want to read restore tapes
1270                         for a 16bit int machine??? */
1271                 do
1272                         i += swabl(*buf++);
1273                 while (--j);
1274         }
1275
1276         if (i != CHECKSUM) {
1277                 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1278                         curfile.ino, curfile.name);
1279                 return(FAIL);
1280         }
1281         return(GOOD);
1282 }
1283
1284 #ifdef RRESTORE
1285 #include <stdarg.h>
1286
1287 void
1288 msg(const char *fmt, ...)
1289 {
1290         va_list ap;
1291         va_start(ap, fmt);
1292         (void)vfprintf(stderr, fmt, ap);
1293         va_end(ap);
1294 }
1295 #endif /* RRESTORE */
1296
1297 static u_char *
1298 swabshort(u_char *sp, int n)
1299 {
1300         char c;
1301
1302         while (--n >= 0) {
1303                 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1304                 sp += 2;
1305         }
1306         return (sp);
1307 }
1308
1309 static u_char *
1310 swablong(u_char *sp, int n)
1311 {
1312         char c;
1313
1314         while (--n >= 0) {
1315                 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1316                 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1317                 sp += 4;
1318         }
1319         return (sp);
1320 }
1321
1322 static u_char *
1323 swabquad(u_char *sp, int n)
1324 {
1325         char c;
1326
1327         while (--n >= 0) {
1328                 c = sp[0]; sp[0] = sp[7]; sp[7] = c;
1329                 c = sp[1]; sp[1] = sp[6]; sp[6] = c;
1330                 c = sp[2]; sp[2] = sp[5]; sp[5] = c;
1331                 c = sp[3]; sp[3] = sp[4]; sp[4] = c;
1332                 sp += 8;
1333         }
1334         return (sp);
1335 }
1336
1337 void
1338 swabst(u_char *cp, u_char *sp)
1339 {
1340         int n = 0;
1341
1342         while (*cp) {
1343                 switch (*cp) {
1344                 case '0': case '1': case '2': case '3': case '4':
1345                 case '5': case '6': case '7': case '8': case '9':
1346                         n = (n * 10) + (*cp++ - '0');
1347                         continue;
1348
1349                 case 's': case 'w': case 'h':
1350                         if (n == 0)
1351                                 n = 1;
1352                         sp = swabshort(sp, n);
1353                         break;
1354
1355                 case 'l':
1356                         if (n == 0)
1357                                 n = 1;
1358                         sp = swablong(sp, n);
1359                         break;
1360
1361                 case 'q':
1362                         if (n == 0)
1363                                 n = 1;
1364                         sp = swabquad(sp, n);
1365                         break;
1366
1367                 case 'b':
1368                         if (n == 0)
1369                                 n = 1;
1370                         sp += n;
1371                         break;
1372
1373                 default:
1374                         fprintf(stderr, "Unknown conversion character: %c\n",
1375                             *cp);
1376                         done(0);
1377                         break;
1378                 }
1379                 cp++;
1380                 n = 0;
1381         }
1382 }
1383
1384 static u_long
1385 swabl(u_long x)
1386 {
1387         swabst((u_char *)"l", (u_char *)&x);
1388         return (x);
1389 }