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